#!/bin/sh

set -e

# This script preseeds all of the debconf values needed to install an
# OpenStack cloud without any manual intervention, then installs it. It
# relies on the preseed-lib library, which knows about the debconf
# templates of every OpenStack service.
#
# The INSTALL_TYPE variable selects what gets installed at the end:
#   single-node:  openstack-toaster (everything on one machine)
#   proxy-node:   openstack-proxy-node (API / management node, which also
#                 holds the MySQL and RabbitMQ servers)
#   compute-node: openstack-compute-node (hypervisor node, using the MySQL,
#                 RabbitMQ and Keystone servers of a proxy node)
#
# Single-node and proxy-node are fully automatic: the MySQL and RabbitMQ
# servers are local, and the Keystone endpoint IP is auto-detected. Their
# values are saved in /root/osinstallrc (the same file that
# openstack-deploy, openstack-deploy-tempest and openstack-deploy-fix-*
# use), so that deploying a compute node is fully automated too: copy that
# file to the compute node, then run this script. Compute-node reads
# /root/osinstallrc, and only prompts for values which are missing,
# remembering the answers in the same file so they are never asked again.

if [ -r /usr/share/openstack-deploy/preseed-lib ] ; then
	. /usr/share/openstack-deploy/preseed-lib
else
	echo "Can't find /usr/share/openstack-deploy/preseed-lib: exiting"
	exit 1
fi

if [ -z "${APTGET:-}" ] ; then
	APTGET="apt-get -o Dpkg::Options::=--force-confnew --allow-downgrades --allow-change-held-packages -fuy"
fi

# Install type possible values: single-node, proxy-node or compute-node
if [ -z "${INSTALL_TYPE:-}" ] ; then
	INSTALL_TYPE=single-node
fi

# The controller's values are stored here, and a compute node gets its
# values from a copy of this file.
OSINSTALL_RC=/root/osinstallrc
if [ -r ${OSINSTALL_RC} ] ; then
	. ${OSINSTALL_RC}
fi

# Usage: osinstall_rcsave <VARNAME>
# Save the value of <VARNAME> in ${OSINSTALL_RC}, unless it is already
# there (the first value always wins).
osinstall_rcsave () {
	local VARNAME VALUE
	VARNAME=${1}
	VALUE=$(eval "echo \${${VARNAME}:-}")
	if ! grep -q "^${VARNAME}=" ${OSINSTALL_RC} 2>/dev/null ; then
		printf '%s="%s"\n' "${VARNAME}" "${VALUE}" >>${OSINSTALL_RC}
	fi
}

# Usage: osinstall_rcvalue <VARNAME> <prompt>
# Do nothing if <VARNAME> is already set (by ${OSINSTALL_RC} or by the
# environment), otherwise prompt for it and save it in ${OSINSTALL_RC} so
# that it is never asked again. Note that an empty value is a valid value
# (eg: the MariaDB root password when using unix_socket authentication),
# which is why ${VAR+set} is used instead of ${VAR:-}.
osinstall_rcvalue () {
	local VARNAME CUR VALUE
	VARNAME=${1}
	CUR=$(eval "echo \${${VARNAME}+x}")
	if [ -z "${CUR}" ] ; then
		printf '%s' "${2}"
		read VALUE
		eval "${VARNAME}=\"\${VALUE}\""
		osinstall_rcsave ${VARNAME}
	fi
}

# Auto-detect the IP address of the interface holding the default route
DEFROUTE_IF=$(LC_ALL=C ip route show default | awk '{print $5; exit}')
if [ -n "${DEFROUTE_IF}" ] ; then
	DEFROUTE_IP=$(LC_ALL=C ip addr show "${DEFROUTE_IF}" | grep inet | head -n 1 | awk '{print $2}' | cut -d/ -f1 | grep -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$')
fi

if [ "${INSTALL_TYPE}" = "compute-node" ] ; then
	# A compute node uses the MySQL, RabbitMQ and Keystone servers of its
	# proxy node: everything comes from ${OSINSTALL_RC}, which a copy of
	# the proxy node's file provides. Values which are missing are
	# prompted for and saved, so they are only ever asked once.
	osinstall_rcvalue RC_KEYSTONE_ENDPOINT_IP "Keystone endpoint IP address: "
	osinstall_rcvalue RC_KEYSTONE_REGION "Keystone region [regionOne]: "
	osinstall_rcvalue RC_KEYSTONE_ADMINPASS "Keystone admin password: "
	osinstall_rcvalue RC_MYSQL_SERVER_HOSTNAME "MySQL server hostname: "
	osinstall_rcvalue RC_MYSQL_PASSWORD "MySQL root password: "
	osinstall_rcvalue RC_RABIT_HOST "RabbitMQ server hostname: "
	osinstall_rcvalue RC_RABIT_USER "RabbitMQ user [openstack]: "
	osinstall_rcvalue RC_RABIT_PASS "RabbitMQ password: "
	osinstall_rcvalue RC_NEUTRON_SQL_PASS "Neutron MySQL password: "
	osinstall_rcvalue RC_NEUTRON_SERVICE_PASS "Neutron service password: "
	osinstall_rcvalue RC_NOVA_SQL_PASS "Nova MySQL password: "
	osinstall_rcvalue RC_NOVA_SERVICE_PASS "Nova service password: "
	osinstall_rcvalue RC_METADATA_SHARED_SECRET "Metadata proxy shared secret: "
	osinstall_rcvalue RC_PLACEMENT_SERVICE_PASS "Placement service password: "

	KEYSTONE_ENDPOINT_IP=${RC_KEYSTONE_ENDPOINT_IP}
	KEYSTONE_REGION=${RC_KEYSTONE_REGION:-regionOne}
	KEYSTONE_ADM_PASS=${RC_KEYSTONE_ADMINPASS}
	MYSQL_HOST=${RC_MYSQL_SERVER_HOSTNAME}
	MYSQL_PASSWORD=${RC_MYSQL_PASSWORD}
	RABIT_HOST=${RC_RABIT_HOST}
	RABIT_LOGIN=${RC_RABIT_USER:-openstack}
	RABIT_PASS=${RC_RABIT_PASS}
	NEUTRON_SQL_PASS=${RC_NEUTRON_SQL_PASS}
	NEUTRON_SERVICE_PASS=${RC_NEUTRON_SERVICE_PASS}
	NOVA_SQL_PASS=${RC_NOVA_SQL_PASS}
	NOVA_SERVICE_PASS=${RC_NOVA_SERVICE_PASS}
	METADATA_SHARED_SECRET=${RC_METADATA_SHARED_SECRET}
	PLACEMENT_SERVICE_PASS=${RC_PLACEMENT_SERVICE_PASS}
	# The nova-api database isn't used by a compute node, but the preseed
	# of os_preseed_nova needs a value.
	os_preseed_gen_pass
	NOVA_API_SQL_PASS=${GENERATED_PASSWORD}
else
	# Single-node and proxy-node hold the MySQL and RabbitMQ servers
	# locally: everything below is auto-detected, nothing is prompted.
	KEYSTONE_ENDPOINT_IP=${DEFROUTE_IP:-127.0.0.1}
	KEYSTONE_REGION=${RC_KEYSTONE_REGION:-regionOne}
	KEYSTONE_ADM_PASS=${RC_KEYSTONE_ADMINPASS:-${MASTER_PASS:-changeme}}

	# MariaDB on Debian authenticates root through unix_socket, so there's
	# no MySQL root password to preseed anymore.
	MYSQL_HOST=""
	MYSQL_PASSWORD=""
	RABIT_HOST="127.0.0.1"
	RABIT_LOGIN="guest"

	os_preseed_gen_pass
	RABIT_PASS=${RC_RABIT_PASS:-${GENERATED_PASSWORD}}
	os_preseed_gen_pass
	KEYSTONE_SQL_PASS=${GENERATED_PASSWORD}
	os_preseed_gen_pass
	GLANCE_SQL_PASS=${GENERATED_PASSWORD}
	os_preseed_gen_pass
	NOVA_SQL_PASS=${GENERATED_PASSWORD}
	os_preseed_gen_pass
	NOVA_API_SQL_PASS=${GENERATED_PASSWORD}
	os_preseed_gen_pass
	NEUTRON_SQL_PASS=${GENERATED_PASSWORD}
	os_preseed_gen_pass
	NEUTRON_SERVICE_PASS=${GENERATED_PASSWORD}
	os_preseed_gen_pass
	CINDER_SQL_PASS=${GENERATED_PASSWORD}
	os_preseed_gen_pass
	AODH_SQL_PASS=${GENERATED_PASSWORD}
	os_preseed_gen_pass
	HEAT_SQL_PASS=${GENERATED_PASSWORD}
	os_preseed_gen_pass
	GNOCCHI_SQL_PASS=${GENERATED_PASSWORD}
	os_preseed_gen_pass
	PLACEMENT_SQL_PASS=${GENERATED_PASSWORD}
	os_preseed_gen_pass
	NOVA_SERVICE_PASS=${GENERATED_PASSWORD}
	os_preseed_gen_pass
	METADATA_SHARED_SECRET=${GENERATED_PASSWORD}
	os_preseed_gen_pass
	PLACEMENT_SERVICE_PASS=${GENERATED_PASSWORD}
fi

os_pressed_misc

if [ "${INSTALL_TYPE}" = "compute-node" ] ; then
	os_preseed_nova "${NOVA_SQL_PASS}" "${NOVA_API_SQL_PASS}" "${MYSQL_PASSWORD}" "${MYSQL_HOST}" \
		"${KEYSTONE_ENDPOINT_IP}" "${KEYSTONE_REGION}" "${KEYSTONE_ADM_PASS}" \
		"" "${RABIT_HOST}" "${RABIT_LOGIN}" "${RABIT_PASS}" \
		"${METADATA_SHARED_SECRET}" "${NOVA_SERVICE_PASS}" "${PLACEMENT_SERVICE_PASS}"
	os_preseed_neutron "${NEUTRON_SQL_PASS}" "${MYSQL_PASSWORD}" "${MYSQL_HOST}" \
		"${KEYSTONE_ENDPOINT_IP}" "${KEYSTONE_REGION}" "${KEYSTONE_ADM_PASS}" \
		"" "${RABIT_HOST}" "${RABIT_LOGIN}" "${RABIT_PASS}" \
		"${METADATA_SHARED_SECRET}" "" "" "${NOVA_SERVICE_PASS}" "${NEUTRON_SERVICE_PASS}"
	os_preseed_ceilometer "${KEYSTONE_ENDPOINT_IP}" "${KEYSTONE_REGION}" "${KEYSTONE_ADM_PASS}" \
		"" "${RABIT_HOST}" "${RABIT_LOGIN}" "${RABIT_PASS}"

	# Unlike all the values above, which point to the proxy node, the
	# overlay IP of the OpenvSwitch agent is local to this compute node.
	if [ -n "${DEFROUTE_IP:-}" ] ; then
		echo "neutron-openvswitch-agent neutron-openvswitch-agent/overlay-int-ip-address string ${DEFROUTE_IP}
neutron-openvswitch-agent neutron-openvswitch-agent/overlay-int-ip-address seen true
" | debconf-set-selections
	fi
else
	# Install the MySQL and RabbitMQ servers first: the keystone postinst
	# needs them to create its database and bootstrap the admin user.
	${APTGET} install -y openstack-cloud-services

	# The services of this node use the guest account from localhost, but
	# RabbitMQ refuses guest connections from any other address: create a
	# real user for the compute nodes, and remember its credentials.
	rabbitmqctl change_password guest "${RABIT_PASS}"
	if ! rabbitmqctl list_users | grep -q "^openstack" ; then
		rabbitmqctl add_user openstack "${RABIT_PASS}"
	fi
	rabbitmqctl set_permissions -p / openstack ".*" ".*" ".*"

	os_install_keystone "" "${KEYSTONE_ADM_PASS}" "${KEYSTONE_ENDPOINT_IP}" "${KEYSTONE_REGION}" \
		"${KEYSTONE_SQL_PASS}" "${MYSQL_PASSWORD}" "${MYSQL_HOST}"
	${APTGET} install -y keystone

	os_preseed_glance "${GLANCE_SQL_PASS}" "${MYSQL_PASSWORD}" "${MYSQL_HOST}" \
		"${KEYSTONE_ENDPOINT_IP}" "${KEYSTONE_REGION}" "${KEYSTONE_ADM_PASS}" \
		"" "${RABIT_HOST}" "${RABIT_LOGIN}" "${RABIT_PASS}"
	os_preseed_nova "${NOVA_SQL_PASS}" "${NOVA_API_SQL_PASS}" "${MYSQL_PASSWORD}" "${MYSQL_HOST}" \
		"${KEYSTONE_ENDPOINT_IP}" "${KEYSTONE_REGION}" "${KEYSTONE_ADM_PASS}" \
		"" "${RABIT_HOST}" "${RABIT_LOGIN}" "${RABIT_PASS}" \
		"${METADATA_SHARED_SECRET}" "${NOVA_SERVICE_PASS}" "${PLACEMENT_SERVICE_PASS}"
	os_preseed_neutron "${NEUTRON_SQL_PASS}" "${MYSQL_PASSWORD}" "${MYSQL_HOST}" \
		"${KEYSTONE_ENDPOINT_IP}" "${KEYSTONE_REGION}" "${KEYSTONE_ADM_PASS}" \
		"" "${RABIT_HOST}" "${RABIT_LOGIN}" "${RABIT_PASS}" \
		"${METADATA_SHARED_SECRET}" "" "" "${NOVA_SERVICE_PASS}" "${NEUTRON_SERVICE_PASS}"
	os_preseed_cinder "${CINDER_SQL_PASS}" "${MYSQL_PASSWORD}" "${MYSQL_HOST}" \
		"${KEYSTONE_ENDPOINT_IP}" "${KEYSTONE_REGION}" "${KEYSTONE_ADM_PASS}" \
		"" "${RABIT_HOST}" "${RABIT_LOGIN}" "${RABIT_PASS}"
	os_preseed_ceilometer "${KEYSTONE_ENDPOINT_IP}" "${KEYSTONE_REGION}" "${KEYSTONE_ADM_PASS}" \
		"" "${RABIT_HOST}" "${RABIT_LOGIN}" "${RABIT_PASS}"
	os_preseed_aodh "${AODH_SQL_PASS}" "${MYSQL_PASSWORD}" "${MYSQL_HOST}" \
		"${KEYSTONE_ENDPOINT_IP}" "${KEYSTONE_REGION}" "${KEYSTONE_ADM_PASS}" \
		"" "${RABIT_HOST}" "${RABIT_LOGIN}" "${RABIT_PASS}"
	os_preseed_heat "${HEAT_SQL_PASS}" "${MYSQL_PASSWORD}" "${MYSQL_HOST}" \
		"${KEYSTONE_ENDPOINT_IP}" "${KEYSTONE_REGION}" "${KEYSTONE_ADM_PASS}" \
		"" "${RABIT_HOST}" "${RABIT_LOGIN}" "${RABIT_PASS}"
	os_preseed_gnocchi "${GNOCCHI_SQL_PASS}" "${MYSQL_PASSWORD}" "${MYSQL_HOST}" \
		"${KEYSTONE_ENDPOINT_IP}" "${KEYSTONE_REGION}" "${KEYSTONE_ADM_PASS}"
	os_preseed_placement "${PLACEMENT_SQL_PASS}" "${MYSQL_PASSWORD}" "${MYSQL_HOST}" \
		"${KEYSTONE_ENDPOINT_IP}" "${KEYSTONE_REGION}" "${KEYSTONE_ADM_PASS}" "${PLACEMENT_SERVICE_PASS}"
	os_pressed_horizon "*"

	# Remember everything which a compute node will need, so that
	# deploying one is just: copy ${OSINSTALL_RC} over, then run this
	# script with INSTALL_TYPE=compute-node.
	RC_KEYSTONE_ENDPOINT_IP=${KEYSTONE_ENDPOINT_IP}
	RC_KEYSTONE_REGION=${KEYSTONE_REGION}
	RC_KEYSTONE_ADMINPASS=${KEYSTONE_ADM_PASS}
	RC_MYSQL_SERVER_HOSTNAME=${KEYSTONE_ENDPOINT_IP}
	RC_MYSQL_PASSWORD=${MYSQL_PASSWORD}
	RC_RABIT_HOST=${KEYSTONE_ENDPOINT_IP}
	RC_RABIT_USER=openstack
	RC_RABIT_PASS=${RABIT_PASS}
	RC_NEUTRON_SQL_PASS=${NEUTRON_SQL_PASS}
	RC_NEUTRON_SERVICE_PASS=${NEUTRON_SERVICE_PASS}
	RC_NOVA_SQL_PASS=${NOVA_SQL_PASS}
	RC_NOVAAPI_SQL_PASS=${NOVA_API_SQL_PASS}
	RC_NOVA_SERVICE_PASS=${NOVA_SERVICE_PASS}
	RC_METADATA_SHARED_SECRET=${METADATA_SHARED_SECRET}
	RC_PLACEMENT_SERVICE_PASS=${PLACEMENT_SERVICE_PASS}
	RC_GLANCE_SQL_PASS=${GLANCE_SQL_PASS}
	RC_CINDER_SQL_PASS=${CINDER_SQL_PASS}
	RC_AODH_SQL_PASS=${AODH_SQL_PASS}
	RC_HEAT_SQL_PASS=${HEAT_SQL_PASS}
	RC_GNOCCHI_SQL_PASS=${GNOCCHI_SQL_PASS}
	osinstall_rcsave RC_KEYSTONE_ENDPOINT_IP
	osinstall_rcsave RC_KEYSTONE_REGION
	osinstall_rcsave RC_KEYSTONE_ADMINPASS
	osinstall_rcsave RC_MYSQL_SERVER_HOSTNAME
	osinstall_rcsave RC_MYSQL_PASSWORD
	osinstall_rcsave RC_RABIT_HOST
	osinstall_rcsave RC_RABIT_USER
	osinstall_rcsave RC_RABIT_PASS
	osinstall_rcsave RC_NEUTRON_SQL_PASS
	osinstall_rcsave RC_NEUTRON_SERVICE_PASS
	osinstall_rcsave RC_NOVA_SQL_PASS
	osinstall_rcsave RC_NOVAAPI_SQL_PASS
	osinstall_rcsave RC_NOVA_SERVICE_PASS
	osinstall_rcsave RC_METADATA_SHARED_SECRET
	osinstall_rcsave RC_PLACEMENT_SERVICE_PASS
	osinstall_rcsave RC_GLANCE_SQL_PASS
	osinstall_rcsave RC_CINDER_SQL_PASS
	osinstall_rcsave RC_AODH_SQL_PASS
	osinstall_rcsave RC_HEAT_SQL_PASS
	osinstall_rcsave RC_GNOCCHI_SQL_PASS
fi

case "${INSTALL_TYPE}" in
"single-node")
	DEBIAN_FRONTEND=noninteractive ${APTGET} install -y openstack-toaster
;;
"proxy-node")
	DEBIAN_FRONTEND=noninteractive ${APTGET} install -y openstack-proxy-node
;;
"compute-node")
	DEBIAN_FRONTEND=noninteractive ${APTGET} install -y openstack-compute-node
;;
esac

exit 0
