#!/bin/bash
set -eu
### --help Info: инициализация конфигурации и данных контейнера.
### --help Usage: /opt/bin/eva_init.sh
### --help Example: /opt/bin/eva_init.sh
. /opt/fox_utils/crab_sys.sh

declare RANDOM

# Container environment
declare EVA_DEPLOY_TYPE

# sys::arg_parse "$@"
# /mnt/shared/config/CONFIG
declare DOMAIN
declare EMAIL_HOST_ADDR
declare EMAIL_PORT
declare EMAIL_USER
declare EMAIL_LOGIN
declare EMAIL_PASSWORD
declare EMAIL_USE_SSL
declare DNS_SERVER1
declare DNS_SERVER2
declare EVA_DEPLOY_TYPE SLA
declare EVA_INSTANCE_KEY
declare ACCOUNT_FQDN

declare POSTGRESQL_ENABLED REDIS_SERVER_ENABLED MEMORY_LIMIT_GB
declare NGINX_ENABLED
declare MANUAL_CONFIGURATION=
declare DB_URL DB_PRE_PING
declare REDIS_HOST REDIS_PORT REDIS_DB REDIS_USERNAME REDIS_PASSWORD REDIS_TLS


set_data_location() {
	# для k8s реализовали отдельно, так проще
	local hostname dir loc dir_loc

	hostname="$(hostname)"

	case "$EVA_DEPLOY_TYPE" in
	box|box-lxc|cloud-lxc)
		# Single container используем /mnt/shared вместо /mnt/shared/hosts/$hostname
		loc=/mnt/shared
		;;
	*)
		# Многоконтейнерый деплой,
		#   используем /mnt/shared/hosts/$hostname для приватных персистентных данных
		# TODO уточнить типы
		set -o pipefail
		hostname=$(ip route get 1 | sed -Ee 's/.* src ([0-9.]+) .*/\1/;t;d')
		set +o pipefail
		loc="/mnt/shared/hosts/$hostname"
		if [[ ! -d $loc ]]; then
			mkdir "$loc"
		fi
		;;
	esac

	for dir in root var/log var/lib/postgresql; do
		if [[ $loc == /mnt/shared ]]; then
			# Сохраняем в корень для удобства.
			dir_loc="$loc/${dir##*/}"
		else
			dir_loc="$loc/$dir"
		fi
		# инициализация из скелета
		if [[ ! -d $dir_loc ]]; then
			if [[ $(id -u) = 0 ]]; then
				rsync -rlogp "/skelet/$dir/" "$dir_loc"
			else
				rsync -rlp "/skelet/$dir/" "$dir_loc"
			fi
		fi
		# Правим линк в /mnt/tmp
		ln -sf --no-target-directory "$dir_loc" "/mnt/tmp/$dir"
	done
	# patch mnt/shared from skelet, absent dir only
	for dir in /skelet/config/* /skelet/config/etc/*; do
		dir="${dir#/skelet/config/}"
		if [[ -d /skelet/config/$dir && ! -d /mnt/shared/config/$dir ]]; then
			echo "Init absent conf dir /mnt/shared/config/$dir from /skelet/config/$dir" >&2
			rsync -rl "/skelet/config/$dir/" "/mnt/shared/config/$dir"
		fi
	done
	# Кладем rw-данные из skelet в tmp
	# mkdir -p /mnt/tmp/etc/ssl/certs/
	# cp -a /skelet/etc/ssl/certs/ca-certificates.crt /mnt/tmp/etc/ssl/certs/ca-certificates.crt
	# mkdir -p /mnt/tmp/usr/local/lib/python3.8/dist-packages/certifi/
	# cp -a /skelet/usr/local/lib/python3.8/dist-packages/certifi/cacert.pem \
	#	/mnt/tmp/usr/local/lib/python3.8/dist-packages/certifi/cacert.pem
	# recreate apps tmp dirs
	mkdir -p /var/tmp/eva-app /var/tmp/eva-converter
	mkdir -p /mnt/shared/tmp/rdisk/{sessions,tokens}
	mkdir -p /mnt/shared/mail
	return 0
}




check_config(){
	echo "Проверяем файл конфигурации на наличие ошибок..."
	# DOMAIN
	if [[ "$DOMAIN" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
		echo "Ошибка в файле конфигурации /opt/CONFIG!"
		echo "Вы ввели в опцию DOMAIN ip адрес, нужно ввести доменное имя"
		echo "Отредактируйте файл /opt/CONFIG и запустите повторно /opt/bin/eva_configure"
		return 1
	fi
	if ! python3 -c \
		"import validators; exit(0) if validators.domain('${DOMAIN}') else exit(1)"; then
		echo "Ошибка в файле конфигурации /opt/CONFIG!"
		echo "Введите в опцию DOMAIN корректное доменное имя. Не вводите префикс https://"
		echo "Пример: eva.example.com или my-eva-domain.ru"
		echo "Отредактируйте файл /opt/CONFIG и запустите повторно."
		return 1
	fi
	if ! python3 -c \
		"import validators; exit(0) if validators.email('${ADMIN_EMAIL}') else exit(1)"; then
		echo "Ошибка в файле конфигурации /opt/CONFIG!"
		echo "Введите в опцию ADMIN_EMAIL корректный email администратора."
		echo "Пример: admin@example.com"
		echo "Отредактируйте файл /opt/CONFIG и запустите повторно."
		return 1
	fi
	return 0
}


configure_email_server(){
	# TODO: единообразный конфиг
	/opt/fox_utils/crab_conf set SMTP_SERVER "$EMAIL_HOST_ADDR" /opt/eva-app/custom/config.py
	sed "s/SMTP_PORT.*/SMTP_PORT=${EMAIL_PORT}/g" -i /opt/eva-app/custom/config.py

	/opt/fox_utils/crab_conf set EMAIL_HOST_ADDR "$EMAIL_HOST_ADDR" /opt/eva-app/custom/config.py
	/opt/fox_utils/crab_conf set EMAIL_PORT "$EMAIL_PORT" /opt/eva-app/custom/config.py
	# crab_conf устанавливает значение с кавычками, уберем для python, чтобы был int
	sed "s/EMAIL_PORT.*/EMAIL_PORT=${EMAIL_PORT}/g" -i /opt/eva-app/custom/config.py
	/opt/fox_utils/crab_conf set EMAIL_USER "$EMAIL_USER" /opt/eva-app/custom/config.py
	/opt/fox_utils/crab_conf set EMAIL_LOGIN "$EMAIL_LOGIN" /opt/eva-app/custom/config.py
	/opt/fox_utils/crab_conf set EMAIL_PASSWORD "$EMAIL_PASSWORD" /opt/eva-app/custom/config.py
	/opt/fox_utils/crab_conf set EMAIL_USE_SSL True /opt/eva-app/custom/config.py

	if [ "$EMAIL_USE_SSL" = "1" ]; then
		sed 's/EMAIL_USE_SSL.*/EMAIL_USE_SSL=True/g' -i /opt/eva-app/custom/config.py
	elif [ "$EMAIL_USE_SSL" = "0" ]; then
		sed 's/EMAIL_USE_SSL.*/EMAIL_USE_SSL=False/g' -i /opt/eva-app/custom/config.py
	else
		echo "ERROR! Опция EMAIL_USE_SSL должна быть 1 или 0"
	fi

	return 0
}


configure_resolv_conf(){
	# может использовать файл образа и перезатирать, только если указан.
	if [ "${EVA_DEPLOY_TYPE}" != "box-lxc" -a "${EVA_DEPLOY_TYPE}" != "cloud-lxc" ]; then
		# Только для деплоя lxc
		# Деплой докера возьмет DNS-сервера с хоста
		return 0
	fi
	if [[ ${DNS_SERVER1:-} ]]; then
		echo "options rotate" > /etc/resolv.conf
		echo "nameserver ${DNS_SERVER1:-8.8.8.8}" >> /etc/resolv.conf
		if [ -n "${DNS_SERVER2:-}" ]; then
			echo "nameserver ${DNS_SERVER2}" >> /etc/resolv.conf
		fi
	fi
	return 0
}


configure_eva_app() {
	# WHATSAPP_MESSENGER_URL = 'https://whatsapp.evacrm.ru'
	# WHATSAPP_PROXY_URL = 'http://localhost:8080'
	if [[ ${ACCOUNT_FQDN:-} ]]; then
		sed -i -Ee 's/^IS_BOX_VERSION[ ]*=.*//;T;d' /mnt/shared/config/eva-app/config.py
		sed -i -Ee 's/^EVA_ACCOUNT_USE[ ]*=.*//;T;d' /mnt/shared/config/eva-app/config.py
	else
		# fixme: crab_conf set True and False as str!!!
		/opt/fox_utils/crab_conf set IS_BOX_VERSION True /opt/eva-app/custom/config.py
		/opt/fox_utils/crab_conf set EVA_ACCOUNT_USE False /opt/eva-app/custom/config.py
	fi
	/opt/fox_utils/crab_conf set CONVERTER_PLANTUML_URL "http://127.0.0.1:8083/plantuml/" \
		/opt/eva-app/custom/config.py
	return 0
}


configure_wsgidav() {
	local account_auth_url org_name
	account_auth_url="$(
	sed -E "s/^AUTH_SERVER_URL\s*=\s*[\"'](.*)[\"']\s*$/\1/;t;d" /opt/eva-app/custom/config.py)"
	org_name="$(sed -E "s/^ORG_NAME\s*=\s*[\"'](.*)[\"']\s*$/\1/;t;d" /opt/eva-app/custom/config.py)"
	# fixme в облаке не заполнен custom/config.py, а /opt/eva-app/custom/org_name depricated
	if [[ ! "$org_name" && -f /opt/eva-app/custom/org_name ]]; then
		org_name="$(cat /opt/eva-app/custom/org_name)"
		# fixme mv to configure_crm
		/opt/fox_utils/crab_conf set ORG_NAME "$org_name" /opt/eva-app/custom/config.py
	fi
	if [[ ! "$org_name" ]]; then
		# Fallback, до регистрации, org_name может не быть.
		org_name="$(hostname)"
		echo "Warning! Use hostname($org_name) as org_name" >&2
	fi
	if [ -z "$account_auth_url" ]; then
		account_auth_url="https://account.evateam.ru"
	fi
	sed -E "s|(^\s{4}org_name: )(.*)|\1$org_name|; \
		s|(^\s{4}endpoint: )(.*)|\1\"$account_auth_url\"|;" \
		-i /mnt/shared/config/wsgidav/wsgidav.yaml
	# configure lock manager
	if grep -qE '^lock_storage_params:' /mnt/shared/config/wsgidav/wsgidav.yaml \
		&& ! grep -qE '^lock_storage_params:[ ]*\{.*}' \
		/mnt/shared/config/wsgidav/wsgidav.yaml; then
		echo "configure_wsgidav(): detect multiline lock_storage_params in config," \
			"skip automatic update" >&2
	else
		sed -i -Ee 's/^lock_storage_params:[ ]*\{.*}//;T;d' \
			/mnt/shared/config/wsgidav/wsgidav.yaml
		local redis_settings
		redis_settings="$(redis_settings_json)"
		if [[ $redis_settings ]]; then
			echo "lock_storage_params: $redis_settings" \
				>> /mnt/shared/config/wsgidav/wsgidav.yaml
		fi
	fi
	return 0
}


configure_rdisk() {
	/opt/fox_utils/crab_conf set CONVERTER_URL "http://127.0.0.1:8083/converter/" \
		/opt/rdisk/rdisk/custom/config.py
	return 0
}


fix_converter_scripts() {
	# Т.к. /root/ - персистентный и сам не обновляется, то скопируем скрипты в профиль здесь.
	mkdir -p /root/.config/libreoffice/4/user/basic/
	rsync -rl --delete /opt/eva-converter/libreoffice_scripts/ /root/.config/libreoffice/4/user/basic/
	return 0
}


configure_messenger() {
	/opt/fox_utils/crab_conf set WHATSAPP_MESSENGER_URL "" \
		/opt/eva-app/custom/config.py
	return 0
}


fix_jwt_keys() {
	# Изначально ключи приходят со сборщика, нам нужно их заменить своими кастомными.
	# rm -f /opt/account/jwt_rsa{,.pub,.pub.orig}
	# if [[ ! -f /opt/account/custom/jwt_rsa ]]; then
	# 	(
	# 		cd /opt/account
	# 		python3 manage.py generate_rsa_keypair
	# 	)
	# 	mv /opt/account/jwt_rsa{,.pub} /opt/account/custom/
	# fi
	# ln -s custom/jwt_rsa /opt/account/
	# ln -s custom/jwt_rsa.pub /opt/account/

	# skip strongbash010
	rm -f /opt/eva-app/tmp/jwt_rsa{,.pub,.pub.orig}
	if [[ ! -f /opt/eva-app/custom/jwt_rsa ]]; then
		(
			cd /opt/eva-app
			python3 manage.py generate_rsa_keypair
		)
		mv /opt/eva-app/tmp/jwt_rsa{,.pub} /opt/eva-app/custom/
	fi
	# Ссылки абсолютные, т.к. многоуровневые.
	ln -s /opt/eva-app/custom/jwt_rsa /opt/eva-app/tmp/
	# Здесь нужен открытый ключ аккаунта.
	if [[ $EVA_DEPLOY_TYPE = cloud* ]]; then
		ln -s /opt/eva-app/custom/jwt_rsa.account.pub /opt/eva-app/tmp/jwt_rsa.pub
	else
		ln -s /opt/eva-app/custom/jwt_rsa.pub /opt/eva-app/tmp/jwt_rsa.pub
	fi
	# Для работы приглашений
	# /opt/fox_utils/crab_conf set VM_TYPE devel /opt/account/custom/config.py
	# /opt/fox_utils/crab_conf set CRM_PUB_KEY "" /opt/account/custom/config.py
	# local key
	# key="$(sed ':a;N;$!ba;s/\n/\\\\n/g' </opt/eva-app/custom/jwt_rsa.pub)"
	# sed "s#CRM_PUB_KEY.*#CRM_PUB_KEY=\"$key\"#g" -i /opt/account/custom/config.py
	return 0
}


gen_crypt_keys(){
	if grep -q "SESSION_CRYPT_KEY" /opt/eva-app/custom/config.py; then
		sed -i 's/SESSION_CRYPT_KEY/EVA_INSTANCE_KEY/g' /opt/eva-app/custom/config.py
	fi
	if ! grep -q "EVA_INSTANCE_KEY" /opt/eva-app/custom/config.py; then
		if [[ ! ${EVA_INSTANCE_KEY:-} ]]; then
			EVA_INSTANCE_KEY="AES:$(openssl rand -hex 16):$(openssl rand -hex 32)"
		fi
		/opt/fox_utils/crab_conf set EVA_INSTANCE_KEY "$EVA_INSTANCE_KEY" \
			/opt/eva-app/custom/config.py
	fi
	return 0
}


do_autogen() {
	(
		cd /opt/eva-app
		python3 manage.py autogen
	)
	return 0
}


sync_custom_skelet() {
	# TODO: Check!
	if [ -d /mnt/shared/config/os_skelet ]; then
		# Init skelet from /mnt/shared/config/os_skelet
		/opt/fox_utils/crab_skelet_init /mnt/shared/config/os_skelet/ /
	fi
	return 0
}


patch_postgres_cluster() {
	if [[ ${POSTGRESQL_ENABLED:-TRUE} != TRUE ]]; then
		return 0
	fi
	# /etc/postgresql/13/main/environment
	local var
	for var in NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP LD_PRELOAD; do
		if [[ ${!var:-} ]]; then
			echo "$var = '${!var}'" >> /etc/postgresql/13/main/environment
		else
			sed -i -Ee "/^$var / d" /etc/postgresql/13/main/environment
		fi
	done
	return 0
}


main() {
	set_data_location
	/opt/bin/eva_init_access.sh
	patch_postgres_cluster
	sync_custom_skelet
	gen_crypt_keys

	if [[ $MANUAL_CONFIGURATION ]]; then
		echo "MANUAL_CONFIGURATION in /opt/CONFIG, skip auto config" >&2
	elif [[ $EVA_DEPLOY_TYPE = cloud* ]]; then
		# TODO: ??? Надо ли какую-то доп настройку под облако?
		# install -d /opt/eva-app/custom
		# touch /opt/eva-app/custom/config.py
		# # ??
		# echo evateam.ru > /opt/eva-app/custom/cloud_name
		if [[ ${SLA:-} ]]; then
			# TODO: выпилить fox_acrm
			echo "configure SLA $SLA" >&2
			/opt/fox_acrm/deploy/provision.py --sla "$SLA" --redis --postgres
			/opt/bin/_uwsgi_configure.sh
			# Чтобы постоянные синки не клали ноду отключаем их у pg в облаке.
			echo "fsync = 0" >> /etc/postgresql/13/main/postgresql.conf
		fi
		configure_wsgidav
	elif [[ $EVA_DEPLOY_TYPE = box* ]]; then
		check_config
		/opt/fox_acrm/deploy/provision.py --memory-limit-gb "${MEMORY_LIMIT_GB:-8}" \
			--redis --postgres
		/opt/bin/_uwsgi_configure.sh
		/opt/bin/_nginx_configure
		configure_email_server
		configure_resolv_conf
		configure_eva_app
		configure_wsgidav
		configure_rdisk
		fix_converter_scripts
		configure_messenger
	else
		echo "Unsupported EVA_DEPLOY_TYPE=$EVA_DEPLOY_TYPE in /opt/CONFIG" >&2
		return 1
	fi
	# fixme зачем-то manage.py(автогену, keygen) нужны редис и постгрес
	#   у кубера будут проблемы со стартом, если БД будет не доступна.
	if [ "${REDIS_SERVER_ENABLED:-TRUE}" = 'TRUE' ]; then
		/etc/init.d/redis-server start
	fi
	if [ "${POSTGRESQL_ENABLED:-TRUE}" = 'TRUE' ]; then
		/etc/init.d/postgresql start
	fi
	do_autogen
	fix_jwt_keys
	return 0
}


shared_lock() {
	# get shared lock
	local my_id="$RANDOM" lock_ts
	while true; do
		# Поды стартуют параллельно, важно не законфликтовать.
		lock_ts=$(stat -c %Y /mnt/shared/.lock) || true
		if [[ $lock_ts ]] && (( $(date +%s) - lock_ts > 30)); then
			rm -f /mnt/shared/.lock
			sleep 2  # avoid race
		fi
		if (set -o noclobber; echo "$my_id" > /mnt/shared/.lock); then
			break
		elif [[ ! -f /mnt/shared/.lock ]]; then
			# may be race!
			echo "!!! Init Config: Cannot create lock on /mnt/tmp/shared-real/.lock" >&2
			return 1
		else
			echo "Init Config: Already locked /mnt/tmp/shared-real/.lock, waiting for config" >&2
			sleep 5
		fi
	done
	return 0
}


shared_unlock() {
	rm -f /mnt/shared/.lock
	return 0
}


k8s_main() {
	# здесь патчим /mnt/tmp, shared по возможности не трогаем.
	# set_data_location
	local hostname loc dir dir_loc

	set -o pipefail
	hostname=$(ip route get 1 | sed -Ee 's/.* src ([0-9.]+) .*/\1/;t;d')
	set +o pipefail
	loc="/mnt/shared/hosts/$hostname"
	if [[ ! -d $loc ]]; then
		mkdir "$loc"
	fi

	for dir in root var/log; do
		dir_loc="$loc/$dir"
		# инициализация из скелета
		if [[ ! -d $dir_loc ]]; then
			mkdir -p "$dir_loc"
			if [[ $(id -u) = 0 ]]; then
				rsync -rlogp "/skelet/$dir/" "$dir_loc"
			else
				rsync -rlp "/skelet/$dir/" "$dir_loc"
			fi
		fi
		# Правим линк в /mnt/tmp
		ln -sf --no-target-directory "$dir_loc" "/mnt/tmp/$dir"
	done
	# # инициализация из скелета
	# if [[ ! -d $loc/var/log ]]; then
	# 	mkdir -p "$loc/var/log"
	# 	rsync -a "/skelet/var/log/" "$loc/var/log"
	# fi
	# # Правим линк в /mnt/tmp
	# ln -sf --no-target-directory "$loc/var/log" "/mnt/tmp/var/log"
	#
	# # Общий /root - удобней, но там есть код зависящий от версии..(скрипты libreoffice...)
	# if [[ ! -d /mnt/shared/root ]]; then
	# 	rsync -a /skelet/root/ /mnt/shared/root
	# fi
	#
	# ln -sf --no-target-directory "/mnt/shared/root" "/mnt/tmp/root"

	mkdir -p /var/tmp/eva-app /var/tmp/eva-converter

	# from _nginx_configure
	if [[ -f /mnt/shared/config/etc/nginx/dh4096.pem ]]; then
		mkdir -p /mnt/tmp/config/etc/nginx
		ln -sf /mnt/shared/config/etc/nginx/dh4096.pem /mnt/tmp/etc/nginx/dh4096.pem
	fi

	/opt/bin/eva_init_access.sh

	# patch image if rw
	sync_custom_skelet

	/opt/bin/_uwsgi_configure.sh
	/opt/bin/_nginx_configure
	# Тут копируем скрипты в ~root/, а он у каждого пода свой.
	fix_converter_scripts
	fix_jwt_keys

	do_autogen

	return 0
}


configure_external_db() {
	# Для простоты, работаем только с однострочным значением в конфиге
	# TODO: Может апп сам будет конфиг из env?
	#   На питоне будет проще, и меньше багов со спец символами.
	#   + возможность использовать секреты
	# TODO: TLS options
	if grep -qE '^data_sources[ ]*=[ ]*' /mnt/shared/config/eva-app/config.py \
		&& ! grep -qE '^data_sources[ ]*=[ ]*\{.*}}' \
		/mnt/shared/config/eva-app/config.py; then
		echo "configure_external_db(): detect multiline data_sources config," \
			"skip automatic update" >&2
		return 0
	fi
	sed -i -Ee 's/^data_sources[ ]*=[ ]*\{.*}}//;T;d' /mnt/shared/config/eva-app/config.py
	if [[ ${DB_URL:-} ]]; then
		echo "data_sources = {" \
			"'default': {" \
			" 'type': 'sqlalchemy'," \
			" 'sqlalchemy.url': '$DB_URL'," \
			${DB_PRE_PING:+" 'sqlalchemy.pool_pre_ping': True,"} \
			" 'sqlalchemy.pool_size': 2, 'sqlalchemy.pool_recycle': 3600," \
			" 'sqlalchemy.poolclass': 'QueuePool', 'sqlalchemy.pool_use_lifo': True," \
			" 'sqlalchemy.max_overflow': 50, 'sqlalchemy.pool_timeout': 1200,}," \
			"'rdisk': {" \
			" 'class': 'modules.rdisk.data_driver.rdisk:RDiskDataDriver'," \
			" 'uri': 'file:///opt/eva-app/files/', }}" \
			>> /mnt/shared/config/eva-app/config.py
	fi
	return 0
}


redis_settings_json() {
	# output one line json, if settings is not default
	set -e
	if [[ ${REDIS_HOST:-} ]]; then
		# Fix k8s cluster service var
		! [[ $REDIS_PORT =~ ^[0-9]+$ ]] && REDIS_PORT=
		local ca_file=/etc/ssl/certs/ca-certificates.crt ssl_certfile='' ssl_keyfile=''
		if [[ -f /opt/eva-app/custom/redis-ca.crt ]]; then
			ca_file=/opt/eva-app/custom/redis-ca.crt
		fi
		# вероятно key должен быть secret и монтироваться в другое место.
		if [[ \
			${REDIS_TLS:-} \
			&& -f /opt/eva-app/custom/redis.crt \
			&& -f /opt/eva-app/custom/redis.key ]]; then
			ssl_certfile=/opt/eva-app/custom/redis.crt
			ssl_keyfile=/opt/eva-app/custom/redis.key
		fi
		# type - not redis param
		echo "{" \
			" 'type': 'redis'," \
			" 'host': '$REDIS_HOST'," \
			" 'port': '${REDIS_PORT:-6379}'," \
			" 'db': ${REDIS_DB:-7}," \
			" ${REDIS_PASSWORD:+"'password': '$REDIS_PASSWORD',"}" \
			" ${REDIS_USERNAME:+"'username': '$REDIS_USERNAME',"}" \
			" ${REDIS_TLS:+'ssl': True,}" \
			" 'ssl_ca_certs': '${ca_file}'," \
			" ${ssl_certfile:+"'ssl_certfile': '$ssl_certfile',"}" \
			" ${ssl_keyfile:+"'ssl_keyfile': '$ssl_keyfile',"}" \
			"}"
	fi
	return 0
}


configure_external_redis() {
	local app
	for app in eva-app eva-converter; do
		configure_app_external_redis "$app"
	done
	return 0
}


configure_app_external_redis() {
	local app="$1" config
	config="/mnt/shared/config/$app/config.py"
	# Для простоты, работаем только с однострочным значением в конфиге
	# TODO: Может апп сам будет конфиг из env?
	#   На питоне будет проще, и меньше багов со спец символами.
	#   + возможность использовать секреты
	# TODO: TLS options
	if grep -qE '^cache_settings[ ]*=[ ]*' "$config" \
		&& ! grep -qE '^cache_settings[ ]*=[ ]*\{.*}}' "$config"; then
		echo "configure_external_redis(): detect multiline cache_settings config," \
			"skip automatic update" >&2
		return 0
	fi
	sed -i -Ee 's/^cache_settings[ ]*=[ ]*\{.*}}//;T;d' "$config"
	local redis_settings
	redis_settings="$(redis_settings_json)"
	if [[ $redis_settings ]]; then
		echo "cache_settings = {'default': $redis_settings}" \
			>> "$config"
	fi
	return 0
}


init_db() {
	(
		cd /opt/eva-app
		echo "Check db initialization." >&2
		# TODO grep UndefinedTable
		if ! python3 manage.py shell "assert g.system_user"; then
			echo "Do init db!!!"
			# initdb
			run_pytest=1 python3 manage.py init_db
			/usr/local/bin/alembic stamp heads
			# Вызов патча сохраняет последний патч в БД, аналог alembic_tag
			python3 manage.py patch
			python3 -m bin.default_data
			# $SELECTED_PRODUCT \
			# && models.CmfLicense.landing_page2license(code=\"$SELECTED_PRODUCT\")
			/opt/bin/register.sh
		fi
		exit 0
	)
	return 0
}


k8s_init_shared_init() {
	if [[ ! -d /mnt/shared/config ]]; then
		# первый раз берём конфигурацию из образа
		# в non root режиме, у нас нет доступа к / маунта (
		rsync -rlpv --exclude /postgresql --exclude /eva_pg_backup \
			/skelet/shared/ /mnt/shared/
	fi
	return 0
}


k8s_init_shared_patch() {
	# copy from set_data_location
	local dir

	# patch mnt/shared from skelet, absent dir only
	for dir in /skelet/config/* /skelet/config/etc/*; do
		dir="${dir#/skelet/config/}"
		if [[ -d /skelet/config/$dir && ! -d /mnt/shared/config/$dir ]]; then
			echo "Init absent conf dir /mnt/shared/config/$dir from /skelet/config/$dir" >&2
			rsync -rl "/skelet/config/$dir/" "/mnt/shared/config/$dir"
		fi
	done
	# recreate apps tmp dirs
	mkdir -p /mnt/shared/tmp/rdisk/{sessions,tokens}
	mkdir -p /mnt/shared/mail
	return 0
}

k8s_init_config_create() {
	# Обновим конфигурацию
	cp /mnt/configs/CONFIG /mnt/shared/config/CONFIG
	# Patch from env
	local container_var config_var
	for container_var in "${!EVA_CONFIG__@}"; do
		config_var="${container_var#EVA_CONFIG__}"
		/opt/fox_utils/crab_conf set "$config_var" "${!container_var}" \
			/mnt/shared/config/CONFIG
	done
	return 0
}

k8s_init() {
	# todo !!! может это джоб eva_configure?
	EVA_DEPLOY_TYPE=k8s
	# Контейнер инициализации, разово заполним том /mnt/shared из скелета образа: /skelet/shared
	# /mnt/configs/ - ConfigMap, копируем поверх скелета в /mnt/shared/config
	shared_lock

	k8s_init_shared_init
	k8s_init_shared_patch
	k8s_init_config_create

	source /opt/CONFIG

	# /etc/nginx/ssl/corp_rootCA.pem
	if [[ -f /mnt/configs/corp_rootCA.pem ]]; then
		cp /mnt/configs/corp_rootCA.pem /mnt/shared/config/etc/nginx/ssl/
	fi
	# Копировать сертификаты nginx
	# /etc/nginx/ssl/${DOMAIN}.{crt,key}
	if [[ -f /mnt/tls/tls.crt ]]; then
		cp /mnt/tls/tls.crt /mnt/shared/config/etc/nginx/ssl/"${DOMAIN}.crt"
		cp /mnt/tls/tls.key /mnt/shared/config/etc/nginx/ssl/"${DOMAIN}.key"
	fi
	# todo-1
	#  postgres(/mnt/postgres-tls)
	if [[ -f /mnt/redis-tls/tls.crt ]]; then
		cp /mnt/redis-tls/tls.crt /mnt/shared/config/eva-app/redis.crt
		cp /mnt/redis-tls/tls.key /mnt/shared/config/eva-app/redis.key
	fi

	configure_external_db
	configure_external_redis

	# from _nginx_configure
	if [[ "${NGINX_ENABLED:-TRUE}" = 'TRUE' && ! -f /mnt/shared/config/etc/nginx/dh4096.pem ]]; then
		mkdir -p /mnt/shared/config/etc/nginx/
		openssl dhparam -dsaparam -out /mnt/shared/config/etc/nginx/dh4096.pem 4096
	fi

	k8s_main
	gen_crypt_keys

	configure_email_server
	configure_eva_app
	configure_wsgidav
	configure_rdisk
	configure_messenger

	init_db

	# release lock
	shared_unlock
	# Сбросим кеш
	(
		cd /opt/eva-app
		python3 manage.py cache_flushdb
	)
	touch /mnt/shared/.init_done
	return 0
}


config_init() {
	local container_var config_var
	# Init /mnt/shared/config/CONFIG
	if [[ ! -f /mnt/shared/config/CONFIG ]]; then
		case "$EVA_DEPLOY_TYPE" in
		box|box-lxc|cloud-lxc)
			cp /opt/bin/templates/CONFIG /mnt/shared/config/CONFIG.$$
			/opt/fox_utils/crab_conf set EVA_DEPLOY_TYPE "$EVA_DEPLOY_TYPE" \
				/mnt/shared/config/CONFIG.$$
			mv /mnt/shared/config/CONFIG.$$ /mnt/shared/config/CONFIG
			;;
		*)
			echo "Unsupported EVA_DEPLOY_TYPE = $EVA_DEPLOY_TYPE" >&2
			;;
		esac
	else
		/opt/fox_utils/crab_conf set EVA_DEPLOY_TYPE "$EVA_DEPLOY_TYPE" \
			/mnt/shared/config/CONFIG
	fi

	# Set CONFIG by container env,
	# Пока только для single варианта,
	# TODO Кластер по месту(т.к. конфиг в кластере общий и возможно RO):
	#   EVA_DEPLOY_TYPE = cluster-master|cluster-control|*-master|*-control
	case "$EVA_DEPLOY_TYPE" in
	box|box-lxc|cloud-lxc)
		for container_var in "${!EVA_CONFIG__@}"; do
			config_var="${container_var#EVA_CONFIG__}"
			/opt/fox_utils/crab_conf set "$config_var" "${!container_var}" \
				/mnt/shared/config/CONFIG
		done
		;;
	esac
	return 0
}


if [[ ${1:-} == k8s-init ]]; then
	set -x
	# Не очень удобно, что файлы, конфиги, логи и тп лежат в одном томе.
	# логи по хорошему надо переносить в кластер
	# конфиги лучше per-pod volume
	source /opt/bin/nss_wrapper.sh
	k8s_init
	exit 0
fi


if [[ ${EVA_DEPLOY_TYPE:-} = k8s ]]; then
	set -x
	source /opt/CONFIG
	k8s_main
else
	config_init
	source /opt/CONFIG
	main
fi

exit 0
