#!/bin/bash
#
# storage creation: {{now}}
{%- if debug and debug == "yes" %} set -x {% endif %}

if  [ -z "$(type -P jq)" ] ; then
  echo 'debconf debconf/frontend select Noninteractive' | sudo debconf-set-selections
  sudo DEBIAN_FRONTEND=noninteractive apt-get update >/dev/null
  sudo DEBIAN_FRONTEND=noninteractive apt-get upgrade -y >/dev/null
  sudo DEBIAN_FRONTEND=noninteractive apt-get install jq -y >/dev/null
fi
[ -z "$(type -P jq)" ] && echo "jq not found" && exit  1

_get_part_name() {
  local device_name=$1
  local part_pos=$2

  if [ "/dev/$device_name${part_pos}" != "/dev/$device_name" ] && [ -e "/dev/$device_name${part_pos}" ] ; then
    echo "${device_name}${part_pos}"
  elif [ -e "/dev/${device_name}p${part_pos}" ] ; then
    echo "${device_name}p${part_pos}"
  else
    echo ""
  fi
}
_get_dev_children() {
  sudo lsblk -fA --j | jq -rc '.blockdevices[].children[] | select((.name == "'${1}${2}'") or (.name == "'${1}p${2}'"))' | sed 's/null//g'
}
_on_item() {
  local device_name=$1
  local part_name=$2
  local part_pos=$3
  local part_size=$4
  local part_type=$5

  local local already_created=""
  local item_pos=-1
  local mkfs_ops=""
  local device_data
  local dev_part_nanme
  local dev_part_path
  local child_data
  local device_blk_type
  local list_mounts
  local new_dev_children

  [ -r "$etc_disks_parts" ] && has_part="$(grep "^$part_name" "$etc_disks_parts")"
  [ -n "$has_part" ] && echo "$part_name already_created" && return
  device_data=$(lsblk -fA --j | jq -rc '.blockdevices[] | select(.name == "'$device_name'")')

  dev_part_name=$(_get_part_name $device_name $part_pos)
  if [ -n "$dev_part_name" ] ; then
    dev_part_path="/dev/$dev_part_name"
    child_data=$(echo "$device_data" | jq -cr '.children[] | select(.name == "'$dev_part_name'")')
  fi
  if [ -z "$child_data" ] ; then
    list_mounts=$(df | grep ^/dev/$device_name | grep -v " /$" | cut -f1 -d" ")
    [ -n "$list_mounts" ] && sudo umount $list_mounts
    {#case $(sudo fdisk -V | cut -f4 -d" ") in #}
    {# case "$SERVER_PROVIDER" in
      upcloud) fdisk_nl="" ;;
      aws) fdisk_nl="\n" ;;
      *) fdisk_nl="\n"
    esac
    #}
    local str_part_size
    [ "$total_storage_parts" != $part_pos ]  && str_part_size="+${part_size}G"
    echo -e "n\n\n\n${str_part_size}\nw\n" | sudo fdisk /dev/"$device_name" &>/dev/null
    #NOTE: sometimes it requires an extra newline. using command exit code ´?' did not work, lsblk it is more secure
    [ -z $(_get_dev_children $device_name $part_pos) ] && echo -e "n\n\n\n\n${str_part_size}\nw\n" | sudo fdisk /dev/"$device_name" &>/dev/null
    if [ -z $(_get_dev_children $device_name $part_pos) ] ; then
      echo "Error create $part_pos in $device_name"
      return 1
    fi
    sudo systemctl daemon-reload
    [ -n "$list_mounts" ] && sudo mount $list_mounts
    dev_part_name=$(_get_part_name $device_name $part_pos)
    [ -n "$dev_part_name" ] && dev_part_path="/dev/$dev_part_name"
  fi
  [ -z "$dev_part_path" ] && return 1
  device_blk_type=$(sudo blkid $dev_part_path | tr ' ' '\n' | grep ^TYPE | cut -f2 -d"=" | sed 's/"//g')
  [ -n "$child_data" ] && [ "$device_blk_type" == "$part_type" ] && return
  {#[ -n "$child_data" ] && [ "$(echo "$child_data" | jq -rc '.fstype')" == "$part_type" ] && return #}
  [ "$part_type" == "raw" ] && return
  if [ ! -r "/usr/sbin/fsck.${part_type}" ] ; then
    case "$part_type" in
      xfs)
        sudo DEBIAN_FRONTEND=noninteractive apt-get install xfsprogs -y >/dev/null
        ;;
    esac
  fi
  case "$part_type" in
    xfs)
      mkfs_ops="-f"
      ;;
  esac
  if [ -z "$dev_part_name" ] ; then
    echo "/dev/${device_name} ${part_pos} not found"
    return 1
  fi
  if [ ! -r "/usr/sbin/mkfs.${part_type}" ] ; then
    echo "mkfs.${part_type} not found to format $dev_part_path "
    exit 1
  else
    if ! sudo mkfs.${part_type} $mkfs_ops $dev_part_path >/dev/null ; then
      echo "Error mkfs.${part_type} format $dev_part_path "
      exit 1
    fi
  fi
}
_on_fs_item() {
  local device_name=$1
  local part_name=$2
  local part_pos=$3
  local part_size=$4
  local part_type=$5
  local part_mount_path=$6
  local part_fstab=$7

  local device_data
  local dev_path_name
  local dev_path_path

  device_data=$(lsblk -fA --j | jq -rc '.blockdevices[] | select(.name == "'$device_name'")')
  dev_part_name=$(_get_part_name $device_name $part_pos)
  if [ -z "$dev_part_name" ] ; then
    echo "/dev/${device_name} ${part_pos} not found"
    return 1
  fi
  dev_part_path="/dev/$dev_part_name"
  part_uuid=$(sudo blkid $dev_part_path | tr ' ' '\n' | grep ^UUID | cut -f2 -d"=" | sed 's/"//g')
  {# part_uuid=$(echo "$device_data" | jq -rc '.children[] | select(.name == "'$dev_part_name'") |.uuid' | sed 's/null//g' ) #}
  [ -r "$etc_disks_parts" ] && has_part="$(grep "^$part_name" "$etc_disks_parts")"
  if [ -n "$has_part" ] ; then
     sed -i /^$part_name/d $etc_disks_parts
  fi
  blkid_data=$(sudo blkid $dev_part_path | cut -f2 -d":" | sed 's/^ //g')
  echo "$part_name:${dev_part_path}:$part_size:$part_type:$part_uuid:2024_04_30_21_21_48:$blkid_data" | sudo tee -a "$etc_disks_parts" >/dev/null
  [ "$part_type" == "raw" ] && return
  [ "$part_type" != "xfs" ] && [ -n "$(type -P tune2fs)" ] && tune2fs -L "$part_name" "$dev_part_path" >/dev/null
  if [ -n "$part_mount_path" ] ; then
    [ ! -d "$part_mount_path" ] && sudo mkdir -p "$part_mount_path"
    has_mount=$(mount | grep "$dev_part_path")
    [ -z "$has_mount" ] && sudo mount "$dev_part_path" "$part_mount_path"
    if [ -n "$part_fstab" ] ; then
      local fstab_uuid
      if [ -n "$part_uuid" ] ; then
        fstab_uuid=$part_uuid
      else
        fstab_uuid=$dev_part_path
      fi
      [ -n "$(sudo grep "$part_mount_path" "$etc_fstab")" ] && grep -v " $part_mount_path " "$etc_fstab" > /tmp/fstab.$$ | sudo mv /tmp/fstab.$$ "$etc_fstab"
      case "$part_type" in
        xfs)
          echo "UUID=$fstab_uuid $part_mount_path  $part_type  rw,relatime,attr2,inode64,noquota 0 1" | sudo tee -a "$etc_fstab" >/dev/null
          ;;
        *) echo "UUID=$fstab_uuid $part_mount_path  $part_type  errors=remount-ro 0 1" | sudo tee -a "$etc_fstab" >/dev/null
      esac
      sudo systemctl daemon-reload
    fi
  fi
}

etc_disks_parts="/etc/.disks_parts"
etc_fstab="/etc/fstab"
server_pos={{server_pos}}

SERVER_PROVIDER={{server.provider}}
DEVICES_LIST=$(lsblk -d --j | jq -rc '.blockdevices[].name' | sort | tr "\n" " ")

{%- for storage in server.storages %}
# Storage {{loop.index}} {{storage.name}}
  storage_pos={{loop.index0}}
  device_name=$(echo "$DEVICES_LIST" | cut -f{{loop.index}} -d" ")
  if [ -n "$device_name" ] ; then
    device_children_len=$(lsblk -fA --j | jq -rc '.blockdevices[] | select(.name == "'$device_name'") | .children | length' 2>/dev/null)
    storage_parts={{storage.parts | length }}
    total_storage_parts=$(($device_children_len + $storage_parts))
    if [ "$(lsblk -fA --j | jq -rc '.blockdevices[].children[] | select(.mountpoints[] == "/") | .name | contains("'$device_name'")' 2>/dev/null)" == "true" ] ; then
      device_children_len=$(($device_children_len - 1))
      total_storage_parts=$(($total_storage_parts - 1))
    fi
    {%- if storage.parts %}
      {%- for part in storage.parts %}
        {%- if part.name == "root" or part.mount_path == "/" -%}{% continue %}{%- endif %}
    # Storage {{storage.name}} part {{loop.index}} {{part.name}}
    {#
    storage_name="{{part.name}}"
    storage_size={{part.size}}
    storage_total={{part.total}}
    storage_type="{{part.type}}"
    {% if part.mount %}storage_mount="true"{% endif %}
    {% if part.fstab %}storage_fstab="true"{% endif %}
    #}
    device_pos={{loop.index}}
    [ -n "{{part.mount_path}}" ] && has_part=$(lsblk -fA --j | jq -rc '.blockdevices[].children[] | select(.mountpoints[] == "{{part.mount_path}}")' 2>/dev/null)
    [ -z "$has_part" ] && [ -r "$etc_disks_parts" ] && has_part="$(grep "^{{part.name}}" "$etc_disks_parts")"
    if [ -z "$has_part" ] ; then
      device_pos=$(($device_children_len + $device_pos))
      if _on_item "$device_name" "{{part.name}}" "$device_pos" "{{part.size}}" "{{part.type}}" ; then
       _on_fs_item "$device_name" "{{part.name}}" "$device_pos" "{{part.size}}" "{{part.type}}" {% if part.mount_path %}"{{part.mount_path}}"{% else %}""{% endif %} {% if part.fstab %}"{{part.fstab}}"{% else %}""{% endif %}
      else
        echo "Error create $device_name {{part.name}} $device_pos {{part.size}}  {{part.type}}"
      fi
    else
      device_children_len=$(($device_children_len - 1))
      total_storage_parts=$(($total_storage_parts - 1))
    fi
      {%- endfor %}
    {%- else %}
        {%- if storage.name == "root" or storage.mount_path == "/" -%}{% continue %}{%- endif -%}
    {#
    storage_name="{{storage.name}}"
    storage_size={{storage.size}}
    storage_total={{storage.total}}
    storage_type="{{storage.type}}"
    {% if storage.mount %}storage_mount="true"{% endif %}
    {% if storage.fstab %}storage_fstab="true"{% endif %}
    #}
    device_pos={{loop.index}}
    [ -n "{{part.mount_path}}" ] && has_part=$(lsblk -fA --j | jq -rc '.blockdevices[].children[] | select(.mountpoints[] == "{{part.mount_path}}")' 2>/dev/null)
    [ -z "$has_part" ] && [ -r "$etc_disks_parts" ] && has_part="$(grep "^{{part.name}}" "$etc_disks_parts")"
    if [ -z "$has_part" ] ; then
      device_pos=$(($device_children_len + $device_pos))
      if _on_item "$device_name" "{{storage.name}}" "$device_pos" "{{storage.size}}" "{{storage.type}}" ; then
        _on_fs_item "$device_name" "{{storage.name}}" "$device_pos" "{{storage.size}}" "{{storage.type}}" {% if storage.mount_path %}"{{storage.mount_path}}"{% else %}""{% endif %} {% if storage.fstab %}"{{storage.fstab}}"{% else %}""{% endif %}
      else
        echo "Error create $device_name {{storage.name}} $device_pos {{storagesize}}  {{storage.type}}"
      fi
    else
      device_children_len=$(($device_children_len - 1))
      total_storage_parts=$(($total_storage_parts - 1))
    fi
    {%- endif %}
  fi
{%- endfor %}
