Commit 52435d76 authored by Kroese's avatar Kroese Committed by GitHub
Browse files

build: Folder structure (#181)

* feat: Multi-disk support

* fix: Shellcheck

* build: Change folder structure

* fix: Entrypoint
parent 11ad461e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -11,4 +11,4 @@ jobs:
      - name: Run ShellCheck
        uses: ludeeus/action-shellcheck@master
env:
        SHELLCHECK_OPTS: -x -e SC2001 -e SC2002 -e SC2223 -e SC2034 -e SC2064  -e SC2317 -e SC2093
        SHELLCHECK_OPTS: -x --source-path=src -e SC2001 -e SC2002 -e SC2223 -e SC2034 -e SC2064  -e SC2317 -e SC2093 -e SC2153
+2 −2
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ RUN apt-get update && apt-get -y upgrade && \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

COPY run/*.sh /run/
COPY src/*.sh /run/
RUN chmod +x /run/*.sh

VOLUME /storage
@@ -44,4 +44,4 @@ LABEL org.opencontainers.image.url="https://hub.docker.com/r/qemux/qemu-docker/"
LABEL org.opencontainers.image.source="https://github.com/qemu-tools/qemu-docker/"
LABEL org.opencontainers.image.description="QEMU in a docker container using KVM acceleration"

ENTRYPOINT ["/usr/bin/tini", "-s", "/run/run.sh"]
ENTRYPOINT ["/usr/bin/tini", "-s", "/run/entry.sh"]

run/disk.sh

deleted100644 → 0
+0 −226
Original line number Diff line number Diff line
#!/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_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

BOOT="$STORAGE/boot.img"
DATA="${STORAGE}/data.img"
DISK_SIZE=$(echo "${DISK_SIZE}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
DATA_SIZE=$(numfmt --from=iec "${DISK_SIZE}")

if [ -f "${DATA}" ]; then

  OLD_SIZE=$(stat -c%s "${DATA}")

  if [ "$DATA_SIZE" -gt "$OLD_SIZE" ]; then

    info "Resizing data disk from $OLD_SIZE to $DATA_SIZE bytes.."

    if [[ "${ALLOCATE}" == [Nn]* ]]; then

      # Resize file by changing its length
      if ! truncate -s "${DATA_SIZE}" "${DATA}"; then
        error "Could not resize the file for the data disk." && exit 85
      fi

    else

      REQ=$((DATA_SIZE-OLD_SIZE))

      # Check free diskspace
      SPACE=$(df --output=avail -B 1 "${STORAGE}" | tail -n 1)

      if (( REQ > SPACE )); then
        error "Not enough free space to resize data disk to ${DISK_SIZE}."
        error "Specify a smaller size or disable preallocation with ALLOCATE=N." && exit 84
      fi

      # Resize file by allocating more space
      if ! fallocate -l "${DATA_SIZE}" "${DATA}"; then
        if ! truncate -s "${DATA_SIZE}" "${DATA}"; then
          error "Could not resize the file for the data disk." && exit 85
        fi
      fi

      if [[ "${ALLOCATE}" == [Zz]* ]]; then

        GB=$(( (REQ + 1073741823)/1073741824 ))

        info "Preallocating ${GB} GB of diskspace, please wait..."
        dd if=/dev/urandom of="${DATA}" seek="${OLD_SIZE}" count="${REQ}" bs=1M iflag=count_bytes oflag=seek_bytes status=none

      fi
    fi
  fi

  if [ "$DATA_SIZE" -lt "$OLD_SIZE" ]; then

    info "Shrinking existing disks is not supported yet!"
    info "Creating backup of old drive in storage folder..."

    mv -f "${DATA}" "${DATA}.bak"

  fi
fi

if [ ! -f "${DATA}" ]; then

  if [[ "${ALLOCATE}" == [Nn]* ]]; then

    # Create an empty file
    if ! truncate -s "${DATA_SIZE}" "${DATA}"; then
      rm -f "${DATA}"
      error "Could not create a file for the data disk." && exit 87
    fi

  else

    # Check free diskspace
    SPACE=$(df --output=avail -B 1 "${STORAGE}" | tail -n 1)

    if (( DATA_SIZE > SPACE )); then
      error "Not enough free space to create a data disk of ${DISK_SIZE}."
      error "Specify a smaller size or disable preallocation with ALLOCATE=N." && exit 86
    fi

    # Create an empty file
    if ! fallocate -l "${DATA_SIZE}" "${DATA}"; then
      if ! truncate -s "${DATA_SIZE}" "${DATA}"; then
        rm -f "${DATA}"
        error "Could not create a file for the data disk." && exit 87
      fi
    fi

    if [[ "${ALLOCATE}" == [Zz]* ]]; then

      info "Preallocating ${DISK_SIZE} of diskspace, please wait..."
      dd if=/dev/urandom of="${DATA}" count="${DATA_SIZE}" bs=1M iflag=count_bytes status=none

    fi
  fi

  # Check if file exists
  if [ ! -f "${DATA}" ]; then
    error "Data disk does not exist ($DATA)" && exit 88
  fi

fi

# Check the filesize
SIZE=$(stat -c%s "${DATA}")

if [[ SIZE -ne DATA_SIZE ]]; then
  error "Virtual disk has the wrong size: ${SIZE}" && exit 89
fi

DISK_OPTS=""

if [ -f "$BOOT" ]; then
  DISK_OPTS="${DISK_OPTS} \
    -drive id=cdrom0,if=none,format=raw,readonly=on,file=${BOOT} \
    -device virtio-scsi-pci,id=scsi0 \
    -device scsi-cd,bus=scsi0.0,drive=cdrom0,bootindex=9"
fi

DISK_OPTS="${DISK_OPTS} \
    -device virtio-scsi-pci,id=hw-userdata,bus=pcie.0,addr=0xa \
    -drive file=${DATA},if=none,id=drive-userdata,format=raw,cache=${DISK_CACHE},aio=${DISK_IO},discard=${DISK_DISCARD},detect-zeroes=on \
    -device scsi-hd,bus=hw-userdata.0,channel=0,scsi-id=0,lun=0,drive=drive-userdata,id=userdata0,rotation_rate=${DISK_ROTATION},bootindex=1"

: ${DISK2_SIZE:=''}
EXTRA_SIZE=DISK2_SIZE
EXTRA_DISK="/storage2/data.img"

if [ -d "$(dirname "${EXTRA_DISK}")" ]; then

  if [ ! -f "${EXTRA_DISK}" ]; then
    [ -z "$EXTRA_SIZE" ] && EXTRA_SIZE="16G"
    if ! truncate -s "${EXTRA_SIZE}" "${EXTRA_DISK}"; then
      error "Could not create the file for the second disk." && exit 53
    fi
  fi

  if [ -n "$EXTRA_SIZE" ]; then
    CUR_SIZE=$(stat -c%s "${EXTRA_DISK}")
    DATA_SIZE=$(numfmt --from=iec "${EXTRA_SIZE}")
    if [ "$DATA_SIZE" -gt "$CUR_SIZE" ]; then
      truncate -s "${EXTRA_SIZE}" "${EXTRA_DISK}"
    fi
  fi
  
  DISK_OPTS="${DISK_OPTS} \
    -device virtio-scsi-pci,id=hw-userdata2,bus=pcie.0,addr=0xd \
    -drive file=${EXTRA_DISK},if=none,id=drive-userdata2,format=raw,cache=${DISK_CACHE},aio=${DISK_IO},discard=${DISK_DISCARD},detect-zeroes=on \
    -device scsi-hd,bus=hw-userdata2.0,channel=0,scsi-id=0,lun=0,drive=drive-userdata2,id=userdata2,rotation_rate=${DISK_ROTATION},bootindex=4"

fi

: ${DISK3_SIZE:=''}
EXTRA_SIZE=DISK3_SIZE
EXTRA_DISK="/storage3/data.img"

if [ -d "$(dirname "${EXTRA_DISK}")" ]; then

  if [ ! -f "${EXTRA_DISK}" ]; then
    [ -z "$EXTRA_SIZE" ] && EXTRA_SIZE="16G"
    if ! truncate -s "${EXTRA_SIZE}" "${EXTRA_DISK}"; then
      error "Could not create the file for the third disk." && exit 54
    fi
  fi

  if [ -n "$EXTRA_SIZE" ]; then
    CUR_SIZE=$(stat -c%s "${EXTRA_DISK}")
    DATA_SIZE=$(numfmt --from=iec "${EXTRA_SIZE}")
    if [ "$DATA_SIZE" -gt "$CUR_SIZE" ]; then
      truncate -s "${EXTRA_SIZE}" "${EXTRA_DISK}"
    fi
  fi

  DISK_OPTS="${DISK_OPTS} \
    -device virtio-scsi-pci,id=hw-userdata3,bus=pcie.0,addr=0xe \
    -drive file=${EXTRA_DISK},if=none,id=drive-userdata3,format=raw,cache=${DISK_CACHE},aio=${DISK_IO},discard=${DISK_DISCARD},detect-zeroes=on \
    -device scsi-hd,bus=hw-userdata3.0,channel=0,scsi-id=0,lun=0,drive=drive-userdata3,id=userdata3,rotation_rate=${DISK_ROTATION},bootindex=5"

fi

: ${DEVICE:=''}        # Docker variable to passthrough a block device, like /dev/vdc1.
: ${DEVICE2:=''}
: ${DEVICE3:=''}

if [ -n "${DEVICE}" ]; then

  [ ! -b "${DEVICE}" ] && error "Device ${DEVICE} 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-userdata4,bus=pcie.0,addr=0xf \
    -drive file=${DEVICE},if=none,id=drive-userdata4,format=raw,cache=${DISK_CACHE},aio=${DISK_IO},discard=${DISK_DISCARD},detect-zeroes=on \
    -device scsi-hd,bus=hw-userdata4.0,channel=0,scsi-id=0,lun=0,drive=drive-userdata4,id=userdata4,rotation_rate=${DISK_ROTATION},bootindex=6"

fi

if [ -n "${DEVICE2}" ]; then

  [ ! -b "${DEVICE2}" ] && error "Device ${DEVICE2} cannot be found! Please add it to the 'devices' section of your compose file." && exit 56

  DISK_OPTS="${DISK_OPTS} \
    -device virtio-scsi-pci,id=hw-userdata5,bus=pcie.0,addr=0x5 \
    -drive file=${DEVICE2},if=none,id=drive-userdata5,format=raw,cache=${DISK_CACHE},aio=${DISK_IO},discard=${DISK_DISCARD},detect-zeroes=on \
    -device scsi-hd,bus=hw-userdata5.0,channel=0,scsi-id=0,lun=0,drive=drive-userdata5,id=userdata5,rotation_rate=${DISK_ROTATION},bootindex=7"

fi

if [ -n "${DEVICE3}" ]; then

  [ ! -b "${DEVICE3}" ] && error "Device ${DEVICE3} cannot be found! Please add it to the 'devices' section of your compose file." && exit 57

  DISK_OPTS="${DISK_OPTS} \
    -device virtio-scsi-pci,id=hw-userdata6,bus=pcie.0,addr=0x6 \
    -drive file=${DEVICE3},if=none,id=drive-userdata6,format=raw,cache=${DISK_CACHE},aio=${DISK_IO},discard=${DISK_DISCARD},detect-zeroes=on \
    -device scsi-hd,bus=hw-userdata6.0,channel=0,scsi-id=0,lun=0,drive=drive-userdata6,id=userdata6,rotation_rate=${DISK_ROTATION},bootindex=8"

fi

src/disk.sh

0 → 100644
+188 −0
Original line number Diff line number Diff line
#!/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_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=""
BOOT="$STORAGE/boot.img"

if [ -f "$BOOT" ]; then
  DISK_OPTS="${DISK_OPTS} \
    -device virtio-scsi-pci,id=scsi0 \
    -drive id=cdrom0,if=none,format=raw,readonly=on,file=${BOOT} \
    -device scsi-cd,bus=scsi0.0,drive=cdrom0,bootindex=10"
fi

addDisk () {

  local GB
  local DIR
  local REQ
  local SIZE
  local SPACE
  local MIN_SIZE
  local CUR_SIZE
  local DATA_SIZE
  local DISK_ID=$1
  local DISK_FILE=$2
  local DISK_DESC=$3
  local DISK_SPACE=$4
  local DISK_INDEX=$5
  local DISK_ADDRESS=$6

  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 [ -f "${DISK_FILE}" ]; then

    CUR_SIZE=$(stat -c%s "${DISK_FILE}")

    if [ "$DATA_SIZE" -gt "$CUR_SIZE" ]; then

      GB=$(( (CUR_SIZE + 1073741823)/1073741824 ))
      info "Resizing ${DISK_DESC} from ${GB}G to ${DISK_SPACE} .."

      if [[ "${ALLOCATE}" == [Nn]* ]]; then

        # Resize file by changing its length
        if ! truncate -s "${DISK_SPACE}" "${DISK_FILE}"; then
          error "Could not resize ${DISK_DESC} file (${DISK_FILE}) to ${DISK_SPACE} .." && exit 85
        fi

      else

        REQ=$((DATA_SIZE-CUR_SIZE))

        # Check free diskspace
        SPACE=$(df --output=avail -B 1 "${DIR}" | tail -n 1)

        if (( REQ > SPACE )); then
          error "Not enough free space to resize ${DISK_DESC} to ${DISK_SPACE} .."
          error "Specify a smaller size or disable preallocation with ALLOCATE=N." && exit 84
        fi

        # Resize file by allocating more space
        if ! fallocate -l "${DISK_SPACE}" "${DISK_FILE}"; then
          if ! truncate -s "${DISK_SPACE}" "${DISK_FILE}"; then
            error "Could not resize ${DISK_DESC} file (${DISK_FILE}) to ${DISK_SPACE} .." && exit 85
          fi
        fi

      fi
    fi
  fi

  if [ ! -f "${DISK_FILE}" ]; then

    if [[ "${ALLOCATE}" == [Nn]* ]]; then

      # Create an empty file
      if ! truncate -s "${DISK_SPACE}" "${DISK_FILE}"; then
        rm -f "${DISK_FILE}"
        error "Could not create a file for ${DISK_DESC} (${DISK_FILE})" && exit 87
      fi

    else

      # Check free diskspace
      SPACE=$(df --output=avail -B 1 "${DIR}" | tail -n 1)

      if (( DATA_SIZE > SPACE )); then
        error "Not enough free space to create ${DISK_DESC} of ${DISK_SPACE} .."
        error "Specify a smaller size or disable preallocation with ALLOCATE=N." && exit 86
      fi

      # Create an empty file
      if ! fallocate -l "${DISK_SPACE}" "${DISK_FILE}"; then
        if ! truncate -s "${DISK_SPACE}" "${DISK_FILE}"; then
          rm -f "${DISK_FILE}"
          error "Could not create a file for ${DISK_DESC} (${DISK_FILE}) of ${DISK_SPACE} .." && exit 87
        fi
      fi

    fi

    # Check if file exists
    if [ ! -f "${DISK_FILE}" ]; then
      error "File for ${DISK_DESC} ($DISK_FILE) does not exist!" && exit 88
    fi

  fi

  # Check the filesize
  SIZE=$(stat -c%s "${DISK_FILE}")

  if [[ SIZE -ne DATA_SIZE ]]; then
    error "File for ${DISK_DESC} (${DISK_FILE}) has the wrong size: ${SIZE} bytes" && exit 89
  fi

  DISK_OPTS="${DISK_OPTS} \
    -device virtio-scsi-pci,id=hw-${DISK_ID},bus=pcie.0,addr=${DISK_ADDRESS} \
    -drive file=${DISK_FILE},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
}

DISK1_FILE="${STORAGE}/data.img"
DISK2_FILE="/storage2/data2.img"
DISK3_FILE="/storage3/data3.img"
DISK4_FILE="/storage4/data4.img"
DISK5_FILE="/storage5/data5.img"
DISK6_FILE="/storage6/data6.img"

: ${DISK2_SIZE:=''}
: ${DISK3_SIZE:=''}
: ${DISK4_SIZE:=''}
: ${DISK5_SIZE:=''}
: ${DISK6_SIZE:=''}

addDisk "userdata" "${DISK1_FILE}" "disk" "${DISK_SIZE}" "1" "0xa"
addDisk "userdata2" "${DISK2_FILE}" "disk2" "${DISK2_SIZE}" "2" "0xb"
addDisk "userdata3" "${DISK3_FILE}" "disk3" "${DISK3_SIZE}" "3" "0xc"
addDisk "userdata4" "${DISK4_FILE}" "disk4" "${DISK4_SIZE}" "4" "0xd"
addDisk "userdata5" "${DISK5_FILE}" "disk5" "${DISK5_SIZE}" "5" "0xe"
addDisk "userdata6" "${DISK6_FILE}" "disk6" "${DISK6_SIZE}" "6" "0xf"

addDevice () {

  local DISK_ID=$1
  local DISK_DEV=$2
  local DISK_INDEX=$3
  local DISK_ADDRESS=$4

  [ -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},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
}

: ${DEVICE:=''}        # Docker variable to passthrough a block device, like /dev/vdc1.
: ${DEVICE2:=''}
: ${DEVICE3:=''}
: ${DEVICE4:=''}
: ${DEVICE5:=''}
: ${DEVICE6:=''}

addDevice "userdata7" "${DEVICE}" "7" "0x6"
addDevice "userdata8" "${DEVICE2}" "8" "0x7"
addDevice "userdata9" "${DEVICE3}" "9" "0x8"
addDevice "userdata4" "${DEVICE4}" "4" "0xd"
addDevice "userdata5" "${DEVICE5}" "5" "0xe"
addDevice "userdata6" "${DEVICE6}" "6" "0xf"

return 0
+7 −7
Original line number Diff line number Diff line
@@ -12,28 +12,28 @@ set -Eeuo pipefail
: ${RAM_SIZE:='512M'}   # Maximum RAM amount

echo "❯ Starting QEMU for Docker v${VERSION}..."
echo "❯ For support visit https://github.com/qemu-tools/qemu-docker/"

info () { echo -e "\E[1;34m❯ \E[1;36m$1\E[0m" ; }
error () { echo -e >&2 "\E[1;31m❯ ERROR: $1\E[0m" ; }
trap 'error "Status $? while: ${BASH_COMMAND} (line $LINENO/$BASH_LINENO)"' ERR

[ ! -f "/run/run.sh" ] && error "Script must run inside Docker container!" && exit 11
[ ! -f "/run/entry.sh" ] && error "Script must run inside Docker container!" && exit 11
[ "$(id -u)" -ne "0" ] && error "Script must be executed with root privileges." && exit 12

STORAGE="/storage"
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)

STORAGE="/storage"
[ ! -d "$STORAGE" ] && error "Storage folder (${STORAGE}) not found!" && exit 13

if [ ! -f "$STORAGE/boot.img" ]; then
  . /run/install.sh
fi
cd /run

. /run/disk.sh     # Initialize disks
. /run/network.sh  # Initialize network
. install.sh   # Get bootdisk
. disk.sh       # Initialize disks
. network.sh  # Initialize network

KVM_ERR=""
KVM_OPTS=""
Loading