Skip to content
Snippets Groups Projects
cron-callback.sh 4.49 KiB
Newer Older
Recolic's avatar
.  
Recolic committed
#!/bin/bash
# pacman -S cdrkit qemu-base
Recolic's avatar
Recolic committed

Recolic's avatar
.  
Recolic committed
workdir=./data
mkdir -p "$workdir"
Recolic's avatar
Recolic committed
cd "$workdir" || exit $?
Recolic's avatar
.  
Recolic committed
mkdir -p base vm tmp
Recolic's avatar
Recolic committed

Recolic's avatar
Recolic committed
function echo2 () {
    echo "$@" 1>&2
}
Recolic's avatar
Recolic committed
function generate_metadata () {
    local name=$1
    echo "local-hostname: $name"
}
function generate_userdata () {
    local username=$1
    local password=$2
    local name=$3
    # TODO: allow public key?
    echo "#cloud-config
system_info:
  default_user:
    name: $username
    home: /home/$username

password: $password
chpasswd: { expire: False }
hostname: $name

# configure sshd to allow users logging in using password 
# rather than just keys
ssh_pwauth: True
"
}

Recolic's avatar
Recolic committed
function download_cloud_img_if_not_exist () {
    local cloudimg="$1"
Recolic's avatar
Recolic committed
    [[ "$1" != "focal-server-cloudimg-amd64.img" ]] && echo2 "ERROR: cloudimg not supported"
    [[ -f "base/$cloudimg" ]] || aria2c -o "base/$cloudimg" https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img || ! echo2 "Failed to download ubuntu cloudimg" || return $?
Recolic's avatar
Recolic committed
}

function create_vm_if_not_exist () {
Recolic's avatar
Recolic committed
    # TODO: support create VM from existing qcow2 snapshot
Recolic's avatar
Recolic committed
    local name=$1
Recolic's avatar
Recolic committed
    local cloudimg=$2
    local disk=$3
    local username=$4
    local password="$5"
Recolic's avatar
Recolic committed

Recolic's avatar
.  
Recolic committed
    if [[ -f "vm/$name/disk.img" ]]; then
Recolic's avatar
Recolic committed
        # already exists
Recolic's avatar
.  
Recolic committed
        :
Recolic's avatar
Recolic committed
    else
Recolic's avatar
Recolic committed
        download_cloud_img_if_not_exist "$cloudimg" || return $?
Recolic's avatar
.  
Recolic committed
        rm -rf "vm/$name" ; mkdir -p "vm/$name"
Recolic's avatar
Recolic committed
        # create it
Recolic's avatar
.  
Recolic committed
        generate_metadata "$name" > "vm/$name/meta-data" || return $?
        generate_userdata "$username" "$password" "$name" > "vm/$name/user-data" || return $?
        ( cd "vm/$name" ; genisoimage  -output initimg.iso -volid cidata -joliet -rock user-data meta-data ) || return $?
        qemu-img create -f qcow2 -F qcow2 -o backing_file="../../base/focal-server-cloudimg-amd64.img" "vm/$name/disk.img" || return $?
        qemu-img resize "vm/$name/disk.img" "$disk" || return $?
Recolic's avatar
Recolic committed
    fi
Recolic's avatar
Recolic committed
}

function start_vm_if_not_running () {
    local name=$1
Recolic's avatar
Recolic committed
    local options_txt="$2"
    read -a options <<< "$options_txt"
Recolic's avatar
Recolic committed

Recolic's avatar
Recolic committed
    # For tracking started instance
    local uuid=`uuidgen --namespace @oid --name "qemu.$name" --sha1`

    # Check if qemu already running for this instance.
    ps aux | grep -F "--uuid $uuid" | grep qemu && return 0

Recolic's avatar
.  
Recolic committed
    # start it
Recolic's avatar
Recolic committed
    [[ ! -f "vm/$name/disk.img" ]] && echo2 "In start_vm, disk image vm/$name/disk.img doesn't exist. Did init_vm fail?" && return 1
Recolic's avatar
Recolic committed
    nohup qemu-system-x86_64 --uuid "$uuid" -drive file="vm/$name/disk.img",if=virtio -cdrom "vm/$name/initimg.iso" -cpu host --enable-kvm -bios /usr/share/edk2-ovmf/x64/OVMF.fd -net nic,model=rtl8139 "${options[@]}" & disown
Recolic's avatar
Recolic committed
}

Recolic's avatar
Recolic committed
function do_init () {
    while IFS= read -r line; do
Recolic's avatar
Recolic committed
        # Ignore lines starting with #
        if [[ "$line" =~ ^\# ]]; then
            continue
        fi
        # Trim leading and trailing whitespaces
        line=$(echo "$line" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
Recolic's avatar
Recolic committed
        # Check if the line is non-empty
        if [ -n "$line" ]; then
            # Parse the line as "name;cloudimg;disk;username;password", trim space
            IFS=';' read -r name cloudimg disk username password <<< "$(echo "$line" | tr -s '[:space:]' ';')"

            # Check if all fields are non-empty
            if [ -n "$name" ] && [ -n "$cloudimg" ] && [ -n "$disk" ] && [ -n "$username" ] && [ -n "$password" ]; then
                create_vm_if_not_exist "$name" "$cloudimg" "$disk" "$username" "$password" || echo2 "Failed to create_vm_if_not_exist. $?"
            else
                echo2 "Error: Bad configuration line: $line"
            fi
        fi
    done < ../init.settings
}
Recolic's avatar
Recolic committed

Recolic's avatar
Recolic committed
function do_start () {
    while IFS= read -r line; do
        # Ignore lines starting with #
        if [[ "$line" =~ ^\# ]]; then
            continue
        fi
        # Trim leading and trailing whitespaces
        line=$(echo "$line" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
        # Check if the line is non-empty
        if [ -n "$line" ]; then
            # Parse the line as "name;options", only trim space in name, options can contain ;
            name=$(echo "$line" | sed -e 's/[[:space:]]*;.*$//' -e 's/^[[:space:]]*//')
Recolic's avatar
Recolic committed
            options=$(echo "$line" | sed 's/^[^;]*;//')
Recolic's avatar
Recolic committed
    
            # Check if the name is empty
            if [ -n "$name" ]; then
Recolic's avatar
Recolic committed
                start_vm_if_not_running "$name" "$options" || echo2 "Failed to start_vm_if_not_running. $?"
Recolic's avatar
Recolic committed
            else
Recolic's avatar
Recolic committed
                echo2 "Error: Bad configuration line: $line"
Recolic's avatar
Recolic committed
            fi
        fi
    done < ../runtime.settings
}
Recolic's avatar
Recolic committed

Recolic's avatar
Recolic committed
do_init
do_start