BraveCrow

proxmox_hassos_install.sh

Jun 13th, 2021
752
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/bin/env bash
  2.  
  3. # Setup script environment
  4. set -o errexit  #Exit immediately if a pipeline returns a non-zero status
  5. set -o errtrace #Trap ERR from shell functions, command substitutions, and commands from subshell
  6. set -o nounset  #Treat unset variables as an error
  7. set -o pipefail #Pipe will exit with last non-zero status if applicable
  8. shopt -s expand_aliases
  9. alias die='EXIT=$? LINE=$LINENO error_exit'
  10. trap die ERR
  11. trap cleanup EXIT
  12.  
  13. function error_exit() {
  14.   trap - ERR
  15.   local DEFAULT='Unknown failure occured.'
  16.   local REASON="\e[97m${1:-$DEFAULT}\e[39m"
  17.   local FLAG="\e[91m[ERROR] \e[93m$EXIT@$LINE"
  18.   msg "$FLAG $REASON"
  19.   [ ! -z ${VMID-} ] && cleanup_vmid
  20.   exit $EXIT
  21. }
  22. function warn() {
  23.   local REASON="\e[97m$1\e[39m"
  24.   local FLAG="\e[93m[WARNING]\e[39m"
  25.   msg "$FLAG $REASON"
  26. }
  27. function info() {
  28.   local REASON="$1"
  29.   local FLAG="\e[36m[INFO]\e[39m"
  30.   msg "$FLAG $REASON"
  31. }
  32. function msg() {
  33.   local TEXT="$1"
  34.   echo -e "$TEXT"
  35. }
  36. function cleanup_vmid() {
  37.   if $(qm status $VMID &>/dev/null); then
  38.     if [ "$(qm status $VMID | awk '{print $2}')" == "running" ]; then
  39.       qm stop $VMID
  40.     fi
  41.     qm destroy $VMID
  42.   fi
  43. }
  44. function cleanup() {
  45.   popd >/dev/null
  46.   rm -rf $TEMP_DIR
  47. }
  48. TEMP_DIR=$(mktemp -d)
  49. pushd $TEMP_DIR >/dev/null
  50.  
  51. # Select storage location
  52. while read -r line; do
  53.   TAG=$(echo $line | awk '{print $1}')
  54.   TYPE=$(echo $line | awk '{printf "%-10s", $2}')
  55.   FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}')
  56.   ITEM="  Type: $TYPE Free: $FREE "
  57.   OFFSET=2
  58.   if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
  59.     MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
  60.   fi
  61.   STORAGE_MENU+=( "$TAG" "$ITEM" "OFF" )
  62. done < <(pvesm status -content images | awk 'NR>1')
  63. if [ $((${#STORAGE_MENU[@]}/3)) -eq 0 ]; then
  64.   warn "'Disk image' needs to be selected for at least one storage location."
  65.   die "Unable to detect valid storage location."
  66. elif [ $((${#STORAGE_MENU[@]}/3)) -eq 1 ]; then
  67.   STORAGE=${STORAGE_MENU[0]}
  68. else
  69.   while [ -z "${STORAGE:+x}" ]; do
  70.     STORAGE=$(whiptail --title "Storage Pools" --radiolist \
  71.     "Which storage pool you would like to use for the container?\n\n" \
  72.     16 $(($MSG_MAX_LENGTH + 23)) 6 \
  73.     "${STORAGE_MENU[@]}" 3>&1 1>&2 2>&3) || exit
  74.   done
  75. fi
  76. info "Using '$STORAGE' for storage location."
  77.  
  78. # Get the next guest VM/LXC ID
  79. VMID=$(pvesh get /cluster/nextid)
  80. info "Container ID is $VMID."
  81.  
  82. # Get latest Home Assistant disk image archive URL
  83. msg "Getting URL for latest Home Assistant disk image..."
  84. RELEASE_TYPE=vmdk
  85. URL=$(cat<<EOF | python3
  86. import requests
  87. url = "https://api.github.com/repos/home-assistant/operating-system/releases"
  88. r = requests.get(url).json()
  89. if "message" in r:
  90.     exit()
  91. for release in r:
  92.     if release["prerelease"]:
  93.         continue
  94.     for asset in release["assets"]:
  95.         if asset["name"].find("$RELEASE_TYPE") != -1:
  96.             image_url = asset["browser_download_url"]
  97.             print(image_url)
  98.             exit()
  99. EOF
  100. )
  101. if [ -z "$URL" ]; then
  102.   die "Github has returned an error. A rate limit may have been applied to your connection."
  103. fi
  104.  
  105. # Download Home Assistant disk image archive
  106. msg "Downloading disk image..."
  107. wget -q --show-progress $URL
  108. echo -en "\e[1A\e[0K" #Overwrite output from wget
  109. FILE=$(basename $URL)
  110.  
  111. # Extract Home Assistant disk image
  112. msg "Extracting disk image..."
  113. case $FILE in
  114.   *"gz") gunzip -f $FILE;;
  115.   *"xz") xz -d $FILE;;
  116.   *) die "Unable to handle file extension '${FILE##*.}'.";;
  117. esac
  118.  
  119. # Create variables for container disk
  120. STORAGE_TYPE=$(pvesm status -storage $STORAGE | awk 'NR>1 {print $2}')
  121. if [ "$STORAGE_TYPE" = "dir" ]; then
  122.   DISK_EXT=".qcow2"
  123.   DISK_REF="$VMID/"
  124.   IMPORT_OPT="-format qcow2"
  125. fi
  126. for i in {0,1}; do
  127.   disk="DISK$i"
  128.   eval DISK${i}=vm-${VMID}-disk-${i}${DISK_EXT:-}
  129.   eval DISK${i}_REF=${STORAGE}:${DISK_REF:-}${!disk}
  130. done
  131.  
  132. # Create VM
  133. msg "Creating VM..."
  134. VM_NAME=$(sed -e "s/\_//g" -e "s/.${RELEASE_TYPE}.*$//" <<< $FILE)
  135. qm create $VMID -agent 1 -bios ovmf -name $VM_NAME -net0 virtio,bridge=vmbr0 \
  136.   -onboot 1 -ostype l26 -scsihw virtio-scsi-pci
  137. pvesm alloc $STORAGE $VMID $DISK0 128 1>&/dev/null
  138. qm importdisk $VMID ${FILE%.*} $STORAGE ${IMPORT_OPT:-} 1>&/dev/null
  139. qm set $VMID \
  140.   -efidisk0 ${DISK0_REF},size=128K \
  141.   -sata0 ${DISK1_REF},size=120G > /dev/null
  142. qm set $VMID \
  143.   -boot order=sata0 > /dev/null
  144.  
  145. # Add serial port and enable console output
  146. set +o errtrace
  147. (
  148.   msg "Adding serial port and configuring console..."
  149.   trap '
  150.    warn "Unable to configure serial port. VM is still functional."
  151.    if [ "$(qm config $VMID | sed -n ''/serial0/p'')" != "" ]; then
  152.      qm set $VMID --delete serial0 >/dev/null
  153.    fi
  154.    exit
  155.  ' ERR
  156.   if [ "$(command -v kpartx)" = "" ]; then
  157.     msg "Installing 'kpartx'..."
  158.     apt-get update >/dev/null
  159.     apt-get -qqy install kpartx &>/dev/null
  160.   fi
  161.   DISK1_PATH="$(pvesm path $DISK1_REF)"
  162.   DISK1_PART1="$(kpartx -al $DISK1_PATH | awk 'NR==1 {print $1}')"
  163.   DISK1_PART1_PATH="/dev/mapper/$DISK1_PART1"
  164.   TEMP_MOUNT="${TEMP_DIR}/mnt"
  165.   trap '
  166.    findmnt $TEMP_MOUNT >/dev/null && umount $TEMP_MOUNT
  167.    command -v kpartx >/dev/null && kpartx -d $DISK1_PATH
  168.  ' EXIT
  169.   kpartx -a $DISK1_PATH
  170.   mkdir $TEMP_MOUNT
  171.   mount $DISK1_PART1_PATH $TEMP_MOUNT
  172.   sed -i 's/$/ console=ttyS0/' ${TEMP_MOUNT}/cmdline.txt
  173.   qm set $VMID -serial0 socket >/dev/null
  174. )
  175.  
  176. info "Completed Successfully! New VM ID is \e[1m$VMID\e[0m."
RAW Paste Data