#!/bin/sh

set -e
set -x

usage () {
	echo "Usage: $0 /dev/<DEVICE>"
	echo "Example: $0 /dev/sdb"
	exit 1
}

if [ -z "${1}" ] ; then
	usage
fi

MY_ROLE=$(cat /etc/oci/my-role)
case "${MY_ROLE}" in
"controller")	SHORT_ROLE="ctrl"	;;
"compute")	SHORT_ROLE="com"	;;
"messaging")	SHORT_ROLE="msg"	;;
"sql")		SHORT_ROLE="sql"	;;
"sqlmsg")	SHORT_ROLE="sqlmsg"	;;
*)		echo "Unknown role: exiting." ; exit 1 ;;
esac

VG_DEVICE_NAME=${1}

# Default for LV name is here:
LV_NAME=data

# Destination mount point for the VG is here:
DATA_MOUNT_POINT=/srv/data

# See if we have a matching /dev/disk/oci-sort/
BASENAME_VG_DEVICE_NAME=$(basename ${VG_DEVICE_NAME})
if [ -e /dev/disk/oci-sort/${BASENAME_VG_DEVICE_NAME} ] ; then
	# We have a match: swap with the real device name
	VG_DEVICE_NAME=$(realpath /dev/disk/oci-sort/${BASENAME_VG_DEVICE_NAME})
fi

if ! [ -e ${VG_DEVICE_NAME} ] ; then
	echo "Device ${VG_DEVICE_NAME} does not exist"
	exit 1
fi

# This is the "9" in cloud1-compute-9 ...
COMP_NN=$(hostname | cut -d. -f1 | cut -d- -f3)
# This is the "cloud1" in cloud1-compute-9 ...
CLUST=$(hostname | cut -d. -f1 | cut -d- -f1)

VG_NAME=${CLUST}${SHORT_ROLE}${COMP_NN}vg0

# Make the PV if it's possible
if pvcreate -t ${VG_DEVICE_NAME} ; then
	pvcreate ${VG_DEVICE_NAME}
fi
# Make VG
if ! [ -d /dev/${VG_NAME} ] ; then
	vgcreate -f ${VG_NAME} ${VG_DEVICE_NAME}
	vgchange -a y ${VG_NAME}
fi
# Make LV
if ! [ -h /dev/mapper/${VG_NAME}-${LV_NAME} ] ; then
	FREE_SPACE=$(vgs --units m -o vg_free | tail -n 1 | awk '{print $1}' | cut -d. -f1)
	# For messaging nodes, only provision 1/4 of the
	# free space, leaving enough to make another LV for MySQL.
	if [ "${MY_ROLE}" = "messaging" ] ; then
		LVCRE_SIZE=$(( ${FREE_SPACE} / 4 ))
	else
		LVCRE_SIZE=${FREE_SPACE}
	fi
	lvcreate -L${LVCRE_SIZE}M -n ${LV_NAME} ${VG_NAME}
fi

if [ "${MY_ROLE}" = "messaging" ] && ! [ -h /dev/mapper/${VG_NAME}-mysql ]; then
	if [ -z LVCRE_SIZE ] ; then
		FREE_SPACE=$(vgs --units m -o vg_free | tail -n 1 | awk '{print $1}' | cut -d. -f1)
		LVCRE_SIZE=$(( ${FREE_SPACE} / 3 ))
	fi
	lvcreate -L${LVCRE_SIZE}M -n mysql ${VG_NAME}
fi

# Make the partition
if ! blkid | grep -q ${VG_NAME}-${LV_NAME} ; then
	mkfs.xfs /dev/${VG_NAME}/${LV_NAME}
fi

if [ "${MY_ROLE}" = "messaging" ] ; then
	if ! blkid | grep -q ${VG_NAME}-mysql ; then
		mkfs.xfs /dev/${VG_NAME}/mysql
	fi
fi

# Insert the data partition in /etc/fstab
eval $(blkid | grep ${VG_NAME}-${LV_NAME} | awk '{print $2}')
if [ -z "${UUID}" ] ; then
	echo "Could not find the partition UUID"
	exit 1
else
	DATA_UUID=${UUID}
fi

# Insert the mysql partition in /etc/fstab
if [ "${MY_ROLE}" = "messaging" ] ; then
	eval $(blkid | grep ${VG_NAME}-mysql | awk '{print $2}')
	if [ -z "${UUID}" ] ; then
		echo "Could not find the partition UUID"
		exit 1
	else
		MYSQL_UUID=${UUID}
	fi
fi

# Make the fstab entry for the VG
if ! grep -q ${DATA_UUID} /etc/fstab ; then
	echo "UUID=${DATA_UUID}\t${DATA_MOUNT_POINT}\txfs\trw,relatime,attr2,inode64,noquota\t0\t2" >>/etc/fstab
fi
if [ "${MY_ROLE}" = "messaging" ] ; then
	if ! grep -q ${MYSQL_UUID} /etc/fstab ; then
		echo "UUID=${MYSQL_UUID}\t/var/lib/mysql\txfs\trw,relatime,attr2,inode64,noquota\t0\t2" >>/etc/fstab
	fi
	mkdir -p /var/lib/mysql
fi

mkdir -p ${DATA_MOUNT_POINT}
# Mount the partition if it's needed (ie: not mounted yet)
if ! cat /proc/mounts | grep -q -E '^/dev/[-a-zAZ0-9/]* '${DATA_MOUNT_POINT} ; then
	mount ${DATA_MOUNT_POINT}
fi
if [ "${MY_ROLE}" = "messaging" ] ; then
	if ! cat /proc/mounts | grep -q -E '^/dev/[-a-zAZ0-9/]* '/var/lib/mysql ; then
		mount /var/lib/mysql
	fi
	chown mysql:mysql /var/lib/mysql
fi

# Note that UIDs / GIDs for system users/groups for nova, cinder and libvirt-qemu
# are hardcoded, because reserved in Debian (by policy and through the relevant
# bug report) for this usage.

# Function profile:
# do_the_bindmount /source/path       /dest/path       username     UUID  /path-to-shell    /path/to/home     home-username service,list
# Example calls:
# do_the_bindmount /srv/data/nova    /var/lib/nova     nova         64060 /bin/sh           /var/lib/nova     nova          nova-compute.service
# do_the_bindmount /srv/data/cinder  /var/lib/cinder   cinder       64061 /bin/false        /var/lib/cinder   cinder        cinder-volume.service,cinder-backup.service"
# do_the_bindmount /srv/data/libvirt /var/lib/libvirt  libvirt-qemu 64055 /usr/sbin/nologin /var/lib/libvirt  root          libvirtd.service
do_the_bindmount () {
	local BIND_MOUNTED_PATH SOURCE_PATH USERNAME SERVICE_LIST
	local SERVICE_WAS_STARTED
	SOURCE_PATH=${1}
	BIND_MOUNTED_PATH=${2}
	USERNAME=${3}
	PROJECT_UUID=${4}
	PROJECT_SHELL=${5}
	PROJECT_HOME=${6}
	PROJECT_HOME_OWNER=${7}
	SERVICES_LIST=${8}

	# Make sure we have a nova user and group
	if ! getent group ${USERNAME} > /dev/null 2>&1 ; then
		addgroup --quiet --system ${USERNAME} --gid ${PROJECT_UUID}
	fi

	if ! getent passwd ${USERNAME} > /dev/null 2>&1 ; then
		# Note that nova needs a shell.
		adduser --system \
			--home /var/lib/${USERNAME} \
			--no-create-home \
			--quiet \
			--disabled-password \
			--shell ${PROJECT_SHELL} \
			--group ${USERNAME} --uid ${PROJECT_UUID}
	fi

	# Make sure /var/lib/nova exists
	if [ "${PROJECT_HOME}" != "/nonexistent" ] && [ ! -d ${PROJECT_HOME} ] ; then
		mkdir -p ${PROJECT_HOME}
		chown ${PROJECT_HOME_OWNER}:${PROJECT_HOME_OWNER} ${PROJECT_HOME}
	fi

	# Make the bind mount fstab entries
	if ! cat /etc/fstab | grep -q -E "^${SOURCE_PATH}[[:space:]]*${BIND_MOUNTED_PATH}[[:space:]]none" ; then
		echo "${SOURCE_PATH}\t${BIND_MOUNTED_PATH}\tnone\trw,bind,nofail\t0\t0" >>/etc/fstab
	fi

	if ! cat /proc/mounts | grep -q -E '^/dev/[-a-zAZ0-9/]* '${BIND_MOUNTED_PATH} ; then
		if ! [ -d ${BIND_MOUNTED_PATH} ] ; then
			mkdir -p ${BIND_MOUNTED_PATH}
		fi

		if ! [ -d ${SOURCE_PATH} ] ; then
			mkdir -p ${SOURCE_PATH}
		fi

		SERVICES_NEEDS_START=no
		for DAEMON in $(echo ${SERVICES_LIST} | tr 'n' ' ') ; do
			if systemctl -q is-active ${DAEMON} ; then
				systemctl stop ${DAEMON}
				SERVICES_NEEDS_START=yes
			fi
		done

		# If folder isn't empty
		if ! find ${BIND_MOUNTED_PATH} -type d -empty >/dev/null ; then
			OLD_FOLDER_MIGRATION=yes
			mv ${BIND_MOUNTED_PATH} ${BIND_MOUNTED_PATH}-old
			mkdir -p ${BIND_MOUNTED_PATH}
		else
			OLD_FOLDER_MIGRATION=no
		fi

		mount ${BIND_MOUNTED_PATH}
		chown ${PROJECT_HOME_OWNER}:${PROJECT_HOME_OWNER} ${BIND_MOUNTED_PATH}

		if [ "${OLD_FOLDER_MIGRATION}" = "yes" ] ; then
			mv ${BIND_MOUNTED_PATH}-old/* ${BIND_MOUNTED_PATH}/
			# Also copy hidden files / folders
			if ! find ${BIND_MOUNTED_PATH}-old -type d -empty >/dev/null ; then
				for i in $(ls -A ${BIND_MOUNTED_PATH}-old) ; do
					mv ${BIND_MOUNTED_PATH}-old/$i ${BIND_MOUNTED_PATH}/
				done
			fi
			rm -rf ${BIND_MOUNTED_PATH}-old
		fi

		if [ "${SERVICES_NEEDS_START}" = "yes" ] ; then
			for DAEMON in $(echo ${SERVICES_LIST} | tr 'n' ' ') ; do
				systemctl start ${DAEMON} || true
			done
		fi
	fi
}

case "${MY_ROLE}" in
"compute")
	# Previously, OCI was setting-up only /var/lib/nova/instances.
	# Let's keep it this way if it was setup before. Users can manually
	# migrate to the new style if they want to.
	if ! cat /proc/mounts | grep -q -E '^/dev/[-a-zAZ0-9/]*[[:space:]]*'/var/lib/nova/instances ; then
		do_the_bindmount ${DATA_MOUNT_POINT}/nova    /var/lib/nova     nova         64060 /bin/sh    /var/lib/nova     nova          nova-compute.service
		do_the_bindmount ${DATA_MOUNT_POINT}/cinder  /var/lib/cinder   cinder       64061 /bin/false        /var/lib/cinder   cinder        cinder-volume.service,cinder-backup.service
		do_the_bindmount ${DATA_MOUNT_POINT}/libvirt /var/lib/libvirt  libvirt-qemu 64055 /usr/sbin/nologin /var/lib/libvirt  root          libvirtd.service
	fi
;;
"controller")
	do_the_bindmount ${DATA_MOUNT_POINT}/mysql	/var/lib/mysql mysql	120	/bin/false	/nonexistent	mysql	mysql.service
	do_the_bindmount ${DATA_MOUNT_POINT}/openstack-dashboard /var/lib/openstack-dashboard www-data 33 /usr/sbin/nologin /var/www root apache2.service
	mkdir -p ${DATA_MOUNT_POINT}/openstack-dashboard/upload_tmp
	chown www-data:www-data ${DATA_MOUNT_POINT}/openstack-dashboard/upload_tmp
;;
"messaging")
	do_the_bindmount ${DATA_MOUNT_POINT}/log	/var/log     root         0 /bin/bash	/root	root	''
	do_the_bindmount ${DATA_MOUNT_POINT}/automysqlbackup /var/lib/automysqlbackup root 0 /bin/bash /root root ''
;;
"sql"|"sqlmsg")
	do_the_bindmount ${DATA_MOUNT_POINT}/mysql	/var/lib/mysql mysql	120	/bin/false	/nonexistent	mysql	mysql.service
;;
*)
	echo "Unknown role: exiting."
	exit 1
;;
esac
