diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..7d8a4e9 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,36 @@ +services: + - name: docker:dind + +default: + image: docker:latest + artifacts: + expire_in: 1 week + interruptible: true + retry: + max: 2 + when: runner_system_failure + tags: + - infra-docker-dind + +variables: + DOCKER_DRIVER: overlay2 + +stages: + - build + +build: + stage: build + variables: + IMAGE_NAME: "registry.digitalarsenal.net/low-level-hacks/third-party-build/dockur_windows" + rules: + - if: $CI_COMMIT_TAG + variables: + IMAGE_VERSION: "$CI_COMMIT_TAG" + - if: $CI_COMMIT_TAG == null + variables: + IMAGE_VERSION: "$CI_COMMIT_REF_SLUG" + before_script: + - apk add --no-cache docker-compose bash kmod + script: + - docker login -u "$CI_REGISTRY_USER" -p "$REGISTRY_PUSH_ACCESS_TOKEN" "$CI_REGISTRY" + - ./prepare_image.sh diff --git a/Dockerfile b/Dockerfile index b3eedfb..ba6997b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,6 +29,8 @@ RUN set -eu && \ COPY --chmod=755 ./src /run/ COPY --chmod=755 ./assets /run/assets +RUN mkdir /storage + ADD --chmod=664 https://github.com/qemus/virtiso-whql/releases/download/v1.9.44-0/virtio-win-1.9.44.tar.xz /drivers.txz FROM dockurr/windows-arm:${VERSION_ARG} AS build-arm64 @@ -37,7 +39,6 @@ FROM build-${TARGETARCH} ARG VERSION_ARG="0.00" RUN echo "$VERSION_ARG" > /run/version -VOLUME /storage EXPOSE 8006 3389 ENV VERSION="11" diff --git a/compose.yml b/compose.yml index 3735189..57ad009 100644 --- a/compose.yml +++ b/compose.yml @@ -1,20 +1,19 @@ services: - windows: + windows-build: build: . - container_name: windows + container_name: windows-build privileged: true healthcheck: - test: "[ -f /data/ready ] || exit 1" - interval: 60s - retries: 5 - start_period: 480s + test: "[ -f /data/prepared ] || exit 1" + interval: 30s + retries: 50 + start_period: 600s timeout: 2s environment: VERSION: "11" USERNAME: "bill" PASSWORD: "gates" - DEBUG: "y" - MANUAL: "n" + DISK_FMT: "qcow2" devices: - /dev/kvm - /dev/net/tun @@ -22,29 +21,31 @@ services: - NET_ADMIN ports: - 8006:8006 - - 3389:3389/tcp - - 3389:3389/udp stop_grace_period: 2m volumes: - ./scripts:/oem - - ./shared:/data - ./custom.xml:/custom.xml - networks: - vlan: - ipv4_address: 192.168.0.100 - vlan-1: - ipv4_address: 192.168.1.100 + - ./custom.iso:/custom.iso -networks: - vlan: - driver: bridge - ipam: - driver: default - config: - - subnet: 192.168.0.0/24 - vlan-1: - driver: bridge - ipam: - driver: default - config: - - subnet: 192.168.1.0/24 \ No newline at end of file + windows-installed: + image: $IMAGE_NAME:$IMAGE_VERSION + container_name: windows-installed + privileged: true + healthcheck: + test: "[ -f /storage/ready ] || exit 1" + interval: 30s + retries: 20 + start_period: 60s + timeout: 2s + environment: + VERSION: "11" + USERNAME: "bill" + PASSWORD: "gates" + devices: + - /dev/kvm + - /dev/net/tun + cap_add: + - NET_ADMIN + ports: + - 8006:8006 + stop_grace_period: 2m diff --git a/custom.xml b/custom.xml index 29729f9..d630612 100644 --- a/custom.xml +++ b/custom.xml @@ -105,6 +105,10 @@ 4 reg.exe add "HKLM\SYSTEM\Setup\MoSetup" /v AllowUpgradesWithUnsupportedTPMOrCPU /t REG_DWORD /d 1 /f + + 5 + reg.exe add "HKLM\SYSTEM\CurrentControlSet\Services\msiserver" /v Start /t REG_DWORD /d 2 /f + @@ -456,12 +460,12 @@ 24 - cmd /C if exist "C:\OEM\install.bat" start "Install" "cmd /C C:\OEM\install.bat" + cmd /C if exist "C:\OEM\install.bat" cmd /C C:\OEM\install.bat Execute custom script from the OEM folder if exists 25 - cmd /C "type nul > \\host.lan\Data\ready" + cmd /C "type nul > \\host.lan\Data\prepared" Let host known that all configuration is done diff --git a/env.sh b/env.sh new file mode 100755 index 0000000..64c21db --- /dev/null +++ b/env.sh @@ -0,0 +1,2 @@ +export IMAGE_NAME=${IMAGE_NAME:-"dockur_windows_installed"} +export IMAGE_VERSION=${IMAGE_VERSION:-"latest"} \ No newline at end of file diff --git a/prepare_image.sh b/prepare_image.sh new file mode 100755 index 0000000..19cde37 --- /dev/null +++ b/prepare_image.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +source env.sh + +echo "start to build and install windows" +docker compose up windows-build -d --wait --build + +echo "windows installed, now stop container" +docker stop windows-build + +echo "commit all the changes" +docker commit windows-build "$IMAGE_NAME:$IMAGE_VERSION" +docker images + +docker push "$IMAGE_NAME:$IMAGE_VERSION" + +echo "start container with windows installed" +docker compose up windows-installed -d --wait diff --git a/scripts/dependencies_windows.ps1 b/scripts/dependencies_windows.ps1 index 06a9101..568330d 100644 --- a/scripts/dependencies_windows.ps1 +++ b/scripts/dependencies_windows.ps1 @@ -109,6 +109,39 @@ function Install-WinDump() { Validate-FileHash $BinaryPath $Hash SHA1 } +function Install-QGA() { + # Define QEMU Guest Agent installer URL (change version if needed) + $QGA_URL = "https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso" + $QGA_ISO = "$env:TEMP\virtio-win.iso" + + # Download QEMU Guest Agent ISO + Write-Host "Downloading QEMU Guest Agent ISO..." + curl.exe -L $QGA_URL -o $QGA_ISO + + # Mount the ISO + Write-Host "Mounting ISO..." + $mount = Mount-DiskImage -ImagePath $QGA_ISO -PassThru | Get-Volume + $QGA_DRIVE = $mount.DriveLetter + ":" + + # Define installer path + $QGA_MSI = "$QGA_DRIVE\guest-agent\qemu-ga-x86_64.msi" + + # Install QEMU Guest Agent + Write-Host "Installing QEMU Guest Agent..." + Start-Process msiexec.exe -ArgumentList "/i `"$QGA_MSI`" /quiet /norestart" -Wait -NoNewWindow + + Get-Service QEMU-GA + + # Unmount the ISO + Write-Host "Unmounting ISO..." + Dismount-DiskImage -ImagePath $QGA_ISO + + # Cleanup + Remove-Item -Path $QGA_ISO -Force + + Write-Host "QEMU Guest Agent installation complete." +} + [System.IO.Directory]::CreateDirectory("C:\workspace") CheckStatus @@ -127,4 +160,7 @@ CheckStatus Install-WinDump CheckStatus +Install-QGA +CheckStatus + pip install Pyro5==5.15 diff --git a/scripts/install.bat b/scripts/install.bat index 2f430c2..cd0a3e2 100644 --- a/scripts/install.bat +++ b/scripts/install.bat @@ -5,5 +5,3 @@ powershell -ExecutionPolicy Bypass -File "optimize.ps1" powershell -ExecutionPolicy Bypass -File "disable_updates.ps1" popd - -shutdown /f /r /t 0 diff --git a/src/install.sh b/src/install.sh index e22b99e..54eebd5 100644 --- a/src/install.sh +++ b/src/install.sh @@ -1036,13 +1036,17 @@ if ! startInstall; then exit 68 fi +if [ -e /storage/*.qcow2 ]; then + html "Windows already installed, skipping image preparation..." + return 0 +fi + if [ ! -s "$ISO" ] || [ ! -f "$ISO" ]; then if ! downloadImage "$ISO" "$VERSION" "$LANGUAGE"; then rm -f "$ISO" 2> /dev/null || true exit 61 fi fi - if ! extractImage "$ISO" "$DIR" "$VERSION"; then rm -f "$ISO" 2> /dev/null || true exit 62 diff --git a/src/network.sh b/src/network.sh index 2f90705..da15ef0 100644 --- a/src/network.sh +++ b/src/network.sh @@ -4,24 +4,17 @@ set -Eeuo pipefail # Docker environment variables : "${MAC:=""}" -: "${MAC_2:=""}" : "${DHCP:="N"}" -: "${NETWORK:="bridge"}" +: "${NETWORK:="Y"}" : "${USER_PORTS:=""}" : "${HOST_PORTS:=""}" : "${ADAPTER:="virtio-net-pci"}" -: "${ADAPTER_2:="virtio-net-pci"}" -: "${VM_NET_DEV:="eth0"}" -: "${VM_NET_DEV_2:="eth1"}" +: "${VM_NET_DEV:=""}" : "${VM_NET_TAP:="qemu"}" -: "${VM_NET_TAP_2:="qemu_2"}" : "${VM_NET_MAC:="$MAC"}" -: "${VM_NET_MAC_2:="$MAC_2"}" : "${VM_NET_HOST:="QEMU"}" -: "${VM_NET_HOST_2:="QEMU_2"}" -: "${VM_NET_IP:="192.168.0.101"}" -: "${VM_NET_IP_2:="192.168.1.101"}" +: "${VM_NET_IP:="20.20.20.21"}" : "${DNSMASQ_OPTS:=""}" : "${DNSMASQ:="/usr/sbin/dnsmasq"}" @@ -33,28 +26,106 @@ ADD_ERR="Please add the following setting to your container:" # Functions # ###################################### +configureDHCP() { + + # Create the necessary file structure for /dev/vhost-net + if [ ! -c /dev/vhost-net ]; then + if mknod /dev/vhost-net c 10 238; then + chmod 660 /dev/vhost-net + fi + fi + + # Create a macvtap network for the VM guest + { + msg=$(ip link add link "$VM_NET_DEV" name "$VM_NET_TAP" address "$VM_NET_MAC" type macvtap mode bridge 2>&1) + rc=$? + } || : + + case "$msg" in + "RTNETLINK answers: File exists"*) + while ! ip link add link "$VM_NET_DEV" name "$VM_NET_TAP" address "$VM_NET_MAC" type macvtap mode bridge; do + info "Waiting for macvtap interface to become available.." + sleep 5 + done + ;; + "RTNETLINK answers: Invalid argument"*) + error "Cannot create macvtap interface. Please make sure that the network type of the container is 'macvlan' and not 'ipvlan'." + return 1 + ;; + "RTNETLINK answers: Operation not permitted"*) + error "No permission to create macvtap interface. Please make sure that your host kernel supports it and that the NET_ADMIN capability is set." + return 1 + ;; + *) + [ -n "$msg" ] && echo "$msg" >&2 + if ((rc != 0)); then + error "Cannot create macvtap interface." + return 1 + fi + ;; + esac + + while ! ip link set "$VM_NET_TAP" up; do + info "Waiting for MAC address $VM_NET_MAC to become available..." + sleep 2 + done + + local TAP_NR TAP_PATH MAJOR MINOR + TAP_NR=$(>"$TAP_PATH" + rc=$? + } 2>/dev/null || : + + if ((rc != 0)); then + error "Cannot create TAP interface ($rc). $ADD_ERR --device-cgroup-rule='c *:* rwm'" && return 1 + 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" && return 1 + fi + + NET_OPTS="-netdev tap,id=hostnet0,vhost=on,vhostfd=40,fd=30" + + return 0 +} + configureDNS() { - # 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 - echo "0 $VM_NET_MAC_2 $VM_NET_IP_2 $VM_NET_HOST_2 01:$VM_NET_MAC_2" >>/var/lib/misc/dnsmasq.leases - chmod 644 /var/lib/misc/dnsmasq.leases # dnsmasq configuration: - # eth0 - Provides both DNS and Default Gateway - DNSMASQ_OPTS+=" --dhcp-range=$VM_NET_IP,$VM_NET_IP" - DNSMASQ_OPTS+=" --dhcp-host=$VM_NET_MAC,,$VM_NET_IP,$VM_NET_HOST,infinite" - DNSMASQ_OPTS+=" --dhcp-option=option:netmask,255.255.255.0" - DNSMASQ_OPTS+=" --dhcp-option=option:dns-server,${VM_NET_IP%.*}.1" + 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+=" --dhcp-option=option:dns-server,${VM_NET_IP%.*}.1 --dhcp-option=option:router,${VM_NET_IP%.*}.1" + + # Add DNS entry for container DNSMASQ_OPTS+=" --address=/host.lan/${VM_NET_IP%.*}.1" - # eth1 - Provides only DNS, no default gateway - DNSMASQ_OPTS+=" --dhcp-range=$VM_NET_IP_2,$VM_NET_IP_2" - DNSMASQ_OPTS+=" --dhcp-host=$VM_NET_MAC_2,,$VM_NET_IP_2,$VM_NET_HOST_2,infinite" - DNSMASQ_OPTS+=" --dhcp-option=option:netmask,255.255.255.0" - DNSMASQ_OPTS+=" --dhcp-option=option:dns-server,${VM_NET_IP_2%.*}.1" - DNSMASQ_OPTS+=" --address=/host.lan/${VM_NET_IP_2%.*}.1" - - # Cleanup and start dnsmasq DNSMASQ_OPTS=$(echo "$DNSMASQ_OPTS" | sed 's/\t/ /g' | tr -s ' ' | sed 's/^ *//') if ! $DNSMASQ ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS}; then @@ -116,9 +187,6 @@ configureUser() { forward=$(getUserPorts "$USER_PORTS") [ -n "$forward" ] && NET_OPTS+=",$forward" - NET_OPTS+=" -netdev user,id=hostnet1,host=${VM_NET_IP_2%.*}.1,net=${VM_NET_IP_2%.*}.0/24,dhcpstart=$VM_NET_IP_2,hostname=$VM_NET_HOST_2" - [ -n "$forward" ] && NET_OPTS+=",$forward" - return 0 } @@ -161,14 +229,6 @@ configureNAT() { error "Failed to create bridge. $ADD_ERR --cap-add NET_ADMIN" && return 1 fi - { - ip link add dev dockerbridge_2 type bridge - rc=$? - } || : - if ((rc != 0)); then - error "Failed to create bridge. $ADD_ERR --cap-add NET_ADMIN" && return 1 - fi - if ! ip address add "${VM_NET_IP%.*}.1/24" broadcast "${VM_NET_IP%.*}.255" dev dockerbridge; then error "Failed to add IP address!" && return 1 fi @@ -178,15 +238,6 @@ configureNAT() { sleep 2 done - if ! ip address add "${VM_NET_IP_2%.*}.1/24" broadcast "${VM_NET_IP_2%.*}.255" dev dockerbridge_2; then - error "Failed to add IP address!" && return 1 - fi - - while ! ip link set dockerbridge_2 up; do - info "Waiting for IP address to become available..." - sleep 2 - done - # QEMU Works with taps, set tap to the bridge created if ! ip tuntap add dev "$VM_NET_TAP" mode tap; then error "$tuntap" && return 1 @@ -201,19 +252,6 @@ configureNAT() { error "Failed to set IP link!" && return 1 fi - if ! ip tuntap add dev "$VM_NET_TAP_2" mode tap; then - error "$tuntap" && return 1 - fi - - while ! ip link set "$VM_NET_TAP_2" up promisc on; do - info "Waiting for TAP to become available..." - sleep 2 - done - - if ! ip link set dev "$VM_NET_TAP_2" master dockerbridge_2; then - error "Failed to set IP link!" && return 1 - fi - # 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 @@ -233,19 +271,6 @@ configureNAT() { error "Failed to configure IP tables!" && return 1 fi - if ! iptables -t nat -A POSTROUTING -o "$VM_NET_DEV_2" -j MASQUERADE; then - error "$tables" && return 1 - fi - - # shellcheck disable=SC2086 - if ! iptables -t nat -A PREROUTING -i "$VM_NET_DEV_2" -d "$IP_2" -p tcp${exclude} -j DNAT --to "$VM_NET_IP_2"; then - error "Failed to configure IP tables!" && return 1 - fi - - if ! iptables -t nat -A PREROUTING -i "$VM_NET_DEV_2" -d "$IP_2" -p udp -j DNAT --to "$VM_NET_IP_2"; then - error "Failed to configure IP tables!" && return 1 - fi - 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 >/dev/null 2>&1 || true @@ -263,24 +288,11 @@ configureNAT() { NET_OPTS+=",script=no,downscript=no" - NET_OPTS+=" -netdev tap,id=hostnet1,ifname=$VM_NET_TAP_2" - - if [ -c /dev/vhost-net ]; then - { - exec 41>>/dev/vhost-net - rc=$? - } 2>/dev/null || : - ((rc == 0)) && NET_OPTS+=",vhost=on,vhostfd=41" - fi - - NET_OPTS+=",script=no,downscript=no" - configureDNS || return 1 - return 0/ + return 0 } - configureBridge() { local tuntap="TUN device is missing. $ADD_ERR --device /dev/net/tun" @@ -320,21 +332,21 @@ configureBridge() { error "Failed to create bridge. $ADD_ERR --cap-add NET_ADMIN" && return 1 fi - { - ip link add dev dockerbridge_2 type bridge - rc=$? - } || : - if ((rc != 0)); then - error "Failed to create bridge. $ADD_ERR --cap-add NET_ADMIN" && return 1 - fi + # { + # ip link add dev dockerbridge_2 type bridge + # rc=$? + # } || : + # if ((rc != 0)); then + # error "Failed to create bridge. $ADD_ERR --cap-add NET_ADMIN" && return 1 + # fi # We need freshly created bridge to have IP address of the container # For this reason we need to migrate IP from eth0 to dockerbridge. for addr in $(ip --json addr show dev $VM_NET_DEV | jq -c '.[0].addr_info[] | select(.family == "inet")'); do - cidr_addr=$(echo $addr | jq -r '[ .local, .prefixlen|tostring] | join("/")'); + cidr_addr=$(echo $addr | jq -r '[ .local, .prefixlen|tostring] | join("/")') if ! ip addr add dev dockerbridge $cidr_addr; then - error "Failed to add address for dockerbridge interface" - exit 30 + error "Failed to add address for dockerbridge interface" + exit 30 fi done if ! ip addr flush dev $VM_NET_DEV; then @@ -347,24 +359,24 @@ configureBridge() { sleep 2 done - # We need freshly created bridge to have IP address of the container - # For this reason we need to migrate IP from eth0 to dockerbridge. - for addr in $(ip --json addr show dev $VM_NET_DEV_2 | jq -c '.[0].addr_info[] | select(.family == "inet")'); do - cidr_addr=$(echo $addr | jq -r '[ .local, .prefixlen|tostring] | join("/")'); - if ! ip addr add dev dockerbridge_2 $cidr_addr; then - error "Failed to add address for dockerbridge_2 interface" - exit 30 - fi - done - if ! ip addr flush dev $VM_NET_DEV_2; then - error "Failed to clear $VM_NET_DEV_2 interface addresses" - exit 30 - fi + # # We need freshly created bridge to have IP address of the container + # # For this reason we need to migrate IP from eth0 to dockerbridge. + # for addr in $(ip --json addr show dev $VM_NET_DEV_2 | jq -c '.[0].addr_info[] | select(.family == "inet")'); do + # cidr_addr=$(echo $addr | jq -r '[ .local, .prefixlen|tostring] | join("/")') + # if ! ip addr add dev dockerbridge_2 $cidr_addr; then + # error "Failed to add address for dockerbridge_2 interface" + # exit 30 + # fi + # done + # if ! ip addr flush dev $VM_NET_DEV_2; then + # error "Failed to clear $VM_NET_DEV_2 interface addresses" + # exit 30 + # fi - while ! ip link set dockerbridge_2 up; do - info "Waiting for IP address to become available..." - sleep 2 - done + # while ! ip link set dockerbridge_2 up; do + # info "Waiting for IP address to become available..." + # sleep 2 + # done # QEMU Works with taps, set tap to the bridge created if ! ip tuntap add dev "$VM_NET_TAP" mode tap; then @@ -384,18 +396,18 @@ configureBridge() { error "Failed to attach docker interface to bridge" fi - if ! ip tuntap add dev "$VM_NET_TAP_2" mode tap; then - error "$tuntap" && return 1 - fi + # if ! ip tuntap add dev "$VM_NET_TAP_2" mode tap; then + # error "$tuntap" && return 1 + # fi - while ! ip link set "$VM_NET_TAP_2" up promisc on; do - info "Waiting for TAP to become available..." - sleep 2 - done + # while ! ip link set "$VM_NET_TAP_2" up promisc on; do + # info "Waiting for TAP to become available..." + # sleep 2 + # done - if ! ip link set dev "$VM_NET_TAP_2" master dockerbridge_2; then - error "Failed to set IP link!" && return 1 - fi + # if ! ip link set dev "$VM_NET_TAP_2" master dockerbridge_2; then + # error "Failed to set IP link!" && return 1 + # fi # add initial default route as well if ! ip route add default dev dockerbridge via ${VM_NET_IP%.*}.1; then @@ -414,17 +426,17 @@ configureBridge() { NET_OPTS+=",script=no,downscript=no" - NET_OPTS+=" -netdev tap,id=hostnet1,ifname=$VM_NET_TAP_2" + # NET_OPTS+=" -netdev tap,id=hostnet1,ifname=$VM_NET_TAP_2" - if [ -c /dev/vhost-net ]; then - { - exec 41>>/dev/vhost-net - rc=$? - } 2>/dev/null || : - ((rc == 0)) && NET_OPTS+=",vhost=on,vhostfd=41" - fi + # if [ -c /dev/vhost-net ]; then + # { + # exec 41>>/dev/vhost-net + # rc=$? + # } 2>/dev/null || : + # ((rc == 0)) && NET_OPTS+=",vhost=on,vhostfd=41" + # fi - NET_OPTS+=",script=no,downscript=no" + # NET_OPTS+=",script=no,downscript=no" return 0 @@ -438,15 +450,13 @@ closeNetwork() { [[ "$NETWORK" == [Nn]* ]] && return 0 + exec 30<&- || true exec 40<&- || true - exec 41<&- || true if [[ "$DHCP" == [Yy1]* ]]; then ip link set "$VM_NET_TAP" down || true ip link delete "$VM_NET_TAP" || true - ip link set "$VM_NET_TAP_2" down || true - ip link delete "$VM_NET_TAP_2" || true else @@ -457,13 +467,9 @@ closeNetwork() { ip link set "$VM_NET_TAP" down promisc off || true ip link delete "$VM_NET_TAP" || true - ip link set "$VM_NET_TAP_2" down promisc off || true - ip link delete "$VM_NET_TAP_2" || true ip link set dockerbridge down || true ip link delete dockerbridge || true - ip link set dockerbridge_2 down || true - ip link delete dockerbridge_2 || true fi @@ -494,22 +500,28 @@ checkOS() { getInfo() { + if [ -z "$VM_NET_DEV" ]; then + # Give Kubernetes priority over the default interface + [ -d "/sys/class/net/net0" ] && VM_NET_DEV="net0" + [ -d "/sys/class/net/net1" ] && VM_NET_DEV="net1" + [ -d "/sys/class/net/net2" ] && VM_NET_DEV="net2" + [ -d "/sys/class/net/net3" ] && VM_NET_DEV="net3" + # Automaticly detect the default network interface + [ -z "$VM_NET_DEV" ] && 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 - if [ ! -d "/sys/class/net/$VM_NET_DEV_2" ]; then - error "Network interface '$VM_NET_DEV_2' does not exist inside the container!" - error "$ADD_ERR -e \"VM_NET_DEV_2=NAME\" to specify another interface name." && exit 27 - fi - if [ -z "$MAC" ]; then local file="$STORAGE/$PROCESS.mac" + [ -s "$file" ] && MAC=$(<"$file") if [ -z "$MAC" ]; then # Generate MAC address based on Docker container ID in hostname - MAC=$(printf '02:%02x:%02x:%02x:%02x:%02x\n' \ - $((RANDOM % 256)) $((RANDOM % 256)) $((RANDOM % 256)) $((RANDOM % 256)) $((RANDOM % 256))) + MAC=$(echo "$HOST" | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/') echo "${MAC^^}" >"$file" fi fi @@ -526,34 +538,9 @@ getInfo() { error "Invalid MAC address: '$VM_NET_MAC', should be 12 or 17 digits long!" && exit 28 fi - if [ -z "$MAC_2" ]; then - local file="$STORAGE/$PROCESS.mac" - if [ -z "$MAC_2" ]; then - # Generate MAC address based on Docker container ID in hostname - MAC_2=$(printf '02:%02x:%02x:%02x:%02x:%02x\n' \ - $((RANDOM % 256)) $((RANDOM % 256)) $((RANDOM % 256)) $((RANDOM % 256)) $((RANDOM % 256))) - echo "${MAC_2^^}" >>"$file" - fi - fi - - VM_NET_MAC_2="${MAC_2^^}" - VM_NET_MAC_2="${VM_NET_MAC_2//-/:}" - - if [[ ${#VM_NET_MAC_2} == 12 ]]; then - m="$VM_NET_MAC_2" - VM_NET_MAC_2="${m:0:2}:${m:2:2}:${m:4:2}:${m:6:2}:${m:8:2}:${m:10:2}" - fi - - if [[ ${#VM_NET_MAC_2} != 17 ]]; then - error "Invalid MAC address: '$VM_NET_MAC_2', should be 12 or 17 digits long!" && exit 28 - fi - GATEWAY=$(ip route list dev "$VM_NET_DEV" | awk ' /^default/ {print $3}') IP=$(ip address show dev "$VM_NET_DEV" | grep inet | awk '/inet / { print $2 }' | cut -f1 -d/) - GATEWAY_2=$(ip route list dev "$VM_NET_DEV_2" | awk ' /^default/ {print $3}') - IP_2=$(ip address show dev "$VM_NET_DEV_2" | grep inet | awk '/inet / { print $2 }' | cut -f1 -d/) - return 0 } @@ -574,67 +561,83 @@ if [[ "$DEBUG" == [Yy1]* ]]; then [ -f /etc/resolv.conf ] && grep '^nameserver*' /etc/resolv.conf echo fi -if [[ "$DEBUG" == [Yy1]* ]]; then - info "Host: $HOST IP: $IP_2 Gateway: $GATEWAY_2 Interface: $VM_NET_DEV_2 MAC: $VM_NET_MAC_2" - [ -f /etc/resolv.conf ] && grep '^nameserver*' /etc/resolv.conf - echo -fi -if [[ "$IP" != "172."* ]] && [[ "$IP" != "10.8"* ]] && [[ "$IP" != "10.9"* ]]; then +if [[ "$DHCP" == [Yy1]* ]]; then + checkOS -fi -if [[ "${NETWORK,,}" == "user"* ]]; then - - # Configure for usermode networking (slirp) - configureUser || exit 24 - -elif [[ "${NETWORK,,}" == "bridge"* ]]; then - # CONFIGURE Bridge - html "Configuring bridged network" - - if ! configureBridge; then - - error "Failed to setup bridge networking" - - ip link set "$VM_NET_TAP" down promisc off &>null || true - ip link delete "$VM_NET_TAP" &>null || true - ip link set "$VM_NET_TAP_2" down promisc off &>null || true - ip link delete "$VM_NET_TAP_2" &>null || true - - ip link set dockerbridge down &>null || true - ip link delete dockerbridge &>null || true - ip link set dockerbridge_2 down &>null || true - ip link delete dockerbridge_2 &>null || true - - exit 25 + if [[ "$IP" == "172."* ]]; then + warn "container IP starts with 172.* which is often a sign that you are not on a macvlan network (required for DHCP)!" fi + # Configure for macvtap interface + configureDHCP || exit 20 + else - # Configure for tap interface - if ! configureNAT; then + if [[ "$IP" != "172."* ]] && [[ "$IP" != "10.8"* ]] && [[ "$IP" != "10.9"* ]]; then + checkOS + fi - error "Failed to setup NAT networking" + if [[ "${NETWORK,,}" == [Yy1]* ]]; then - ip link set "$VM_NET_TAP" down promisc off &>null || true - ip link delete "$VM_NET_TAP" &>null || true - ip link set "$VM_NET_TAP_2" down promisc off &>null || true - ip link delete "$VM_NET_TAP_2" &>null || true + # Configure for tap interface + if ! configureNAT; then - ip link set dockerbridge down &>null || true - ip link delete dockerbridge &>null || true - ip link set dockerbridge_2 down &>null || true - ip link delete dockerbridge_2 &>null || true + NETWORK="user" + warn "falling back to usermode networking! Performance will be bad and port mapping will not work." - exit 25 + ip link set "$VM_NET_TAP" down promisc off &>null || true + ip link delete "$VM_NET_TAP" &>null || true + + ip link set dockerbridge down &>null || true + ip link delete dockerbridge &>null || true + + fi + + fi + + if [[ "${NETWORK,,}" == "user"* ]]; then + + # Configure for usermode networking (slirp) + configureUser || exit 24 + + fi + + if [[ "${NETWORK,,}" == "bridge"* ]]; then + + # Configure for usermode networking (slirp) + # CONFIGURE Bridge + html "Configuring bridged network" + + if ! configureBridge; then + + error "Failed to setup bridge networking" + + ip link set "$VM_NET_TAP" down promisc off &>null || true + ip link delete "$VM_NET_TAP" &>null || true + # ip link set "$VM_NET_TAP_2" down promisc off &>null || true + # ip link delete "$VM_NET_TAP_2" &>null || true + + ip link set dockerbridge down &>null || true + ip link delete dockerbridge &>null || true + # ip link set dockerbridge_2 down &>null || true + # ip link delete dockerbridge_2 &>null || true + + exit 25 + fi fi fi NET_OPTS+=" -device $ADAPTER,romfile=,netdev=hostnet0,mac=$VM_NET_MAC,id=net0" -NET_OPTS+=" -device $ADAPTER_2,romfile=,netdev=hostnet1,mac=$VM_NET_MAC_2,id=net1" +# NET_OPTS+=" -device $ADAPTER_2,romfile=,netdev=hostnet1,mac=$VM_NET_MAC_2,id=net1" + +NET_OPTS+=" -device virtio-serial-pci,id=virtserial0,bus=pcie.0,addr=0x6" +NET_OPTS+=" -chardev socket,id=qga0,path=/tmp/qga.sock,server=on,wait=off" +NET_OPTS+=" -device virtio-serial" +NET_OPTS+=" -device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0" html "Initialized network successfully..." return 0 diff --git a/src/power.sh b/src/power.sh index e7ceaff..3e36701 100644 --- a/src/power.sh +++ b/src/power.sh @@ -36,6 +36,7 @@ boot() { fi if [ -z "$fail" ]; then info "Windows started succesfully, visit http://localhost:8006/ to view the screen..." + touch "$STORAGE/ready" return 0 fi fi @@ -161,6 +162,10 @@ _graceful_shutdown() { set +e + if [ -f "$STORAGE/ready" ]; then + rm $STORAGE/ready + fi + if [ -f "$QEMU_END" ]; then info "Received $1 while already shutting down..." return