#!/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

#
# В к8 выделен блок общей инициализации k8s_init() (тома /mnt/shared и БД),
#   который запускается отдельно разово,
#   и повторно при необходимости изменить конфигурацию.
#   При запусках pod-ов /mnt/shared стараемся не трогать,
#   чтобы исключить возможные конфликты подов.
#   todo: привести к деплою appfarm, чтобы не использовать nfs.
#
# В appfarm деплое - нет маунтов, томов, и общей fs,
#   поэтому каждый раз требуется полная настройка /mnt/shared,
#   и передача всех параметров(и ключей/конфигов) через env
#   в т.ч. init_custom_fields
#
# Инициализация AppFarm(init_db):
#   main
#   init_db
#   flush_cache
#
# В коробке инициализация уже выполнена.
# TODO поддержка внешней БД для коробки,
#   сейчас настраивают руками по инструкции.
#
# В Cloud почти все конфиги дефолтные, трогать ничего не надо.
#
# Общий алгоритм.
# - инициализация /mnt/shared [только k8]
#   # TODO: конфиги монтировать в deploy, сразу по месту.
#   k8s_init_shared_init
#   k8s_init_shared_patch
#   k8s_init_config_create
#   /mnt/configs/corp_rootCA.pem -> /mnt/shared/config/etc/nginx/ssl/  # mount?
#   /mnt/tls/{tls.key,tls.crt} -> /mnt/shared/config/etc/nginx/ssl/{$DOMAIN.key,$DOMAIN.crt}
#      mount?
#   /mnt/redis-tls/{tls.key,tls.crt} -> /mnt/shared/config/eva-app/{redis.key,redis.crt}
#      mount ?
#   init /mnt/shared/config/etc/nginx/dh4096.pem
#   gen_ssl_keys
#   gen_jwt_keys
#   gen_crypt_keys
#   gen_evagit_ssh_keys
#   k8s_init_pod_fs
#   configure_eva_app
#   configure_rdisk
#   patch_all_config_py
#   configure_data_sources
#   configure_external_redis
#   configure_wsgidav
#   do_autogen
#   init_db
#   flush_cache
#
# Общая инициализация контейнера(main)
# - config_init init from template -> /mnt/shared/config/CONFIG,
#     set EVA_DEPLOY_TYPE, NGINX_ENABLED, EVA_CONFIG__@ -> /mnt/shared/config/CONFIG
# - set_data_location
#     create_links
#     init from skelet
#     patch from skelet
# - /opt/bin/eva_init_access.sh -> set files perms for postgres and git-ssh
# - sync_custom_skelet
#     /opt/fox_utils/crab_skelet_init /mnt/shared/config/os_skelet/ /
# - gen_jwt_keys
# - set_jwt_links
# - /opt/bin/_uwsgi_configure.sh  gen uwsgi configs
# - /opt/bin/_nginx_configure
#     gen dh4096.pem
#     gen nginx/conf.d/eva-app.conf
#     use_certbot
# - configure_common_deploy(configure_cloud_deploy)
#   - check_config():  DOMAIN, ADMIN_EMAIL
#   - gen_ssl_keys()
#       write crt, corp_ca
#         or gen root_ca, crt
#       patch os, py bundles: root_ca, corp_ca
#   - fix_converter_scripts()
#   - gen_evagit_ssh_keys()
#   - gen_crypt_keys() EVA_INSTANCE_KEY
#   - configure_eva_app()
#     - configure_domain()
#     - configure_email_server()
#     - EVA_ACCOUNT_USE, IS_BOX_VERSION
#     - WHATSAPP_MESSENGER_URL, CONVERTER_PLANTUML_URL
#   - configure_rdisk(): CONVERTER_URL
#   - patch_all_config_py() write env to */custom/config.py
#   - if [[ $EVA_DEPLOY_TYPE == appfarm ]]; then  # TODO if ext_pg ...
#       - configure_data_sources()
#       - configure_external_redis()
#   - configure_wsgidav(): (!!! from config.py) AUTH_SERVER_URL, org_name, redis
# - optionally config and run local pg/redis
#   - /opt/fox_acrm/deploy/provision.py --redis --postgres
#   - patch_postgres_cluster
#       NSS_WRAPPER_PASSWD, NSS_WRAPPER_GROUP, LD_PRELOAD
#       -> /etc/postgresql/$PG_VER/main/environment
# - do_autogen
#     init_custom_fields
#     autogen

# 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 EMAIL_USE_TLS
declare DNS_SERVER1
declare DNS_SERVER2
declare EVA_DEPLOY_TYPE SLA
declare EVA_INSTANCE_KEY
declare EVA_RSA_PRV_KEY
declare EVA_RSA_PUB_KEY
declare ACCOUNT_FQDN
declare CONVERTER_URL

declare HA_COMPANION
declare HA_ROLE
declare HA_COMPANION_IP
declare HA_FILE_MARKERS

declare POSTGRESQL_ENABLED REDIS_SERVER_ENABLED MEMORY_LIMIT_GB
declare NGINX_ENABLED
declare EVA_GIT_SSHD_ENABLED
declare MANUAL_CONFIGURATION=
declare DB_URL DB_PRE_PING
declare NO_SHARED
declare S3_ENDPOINT S3_FALLBACK S3_AWS_ACCESS_KEY_ID S3_AWS_SECRET_ACCESS_KEY S3_BUCKET_NAME
declare REDIS_HOST REDIS_PORT REDIS_DB REDIS_USERNAME REDIS_PASSWORD REDIS_TLS

declare PY_APP_CFG__APP_FQDN
declare PY_APP_CFG__ORG_DOMAIN
declare PY_APP_CFG__APP_NAME
declare PY_APP_CFG__AUTH_SERVER_URL
declare PY_APP_CFG__AUTH_SESSION_COOKIE_DOMAIN
declare PY_APP_CFG__HOSTNAME_FQDN
declare PY_APP_CFG__ORG_NAME
declare PY_APP_CFG__EXTERNAL_PORT_HTTPS
declare PY_APP_CFG__BASE_HREF
declare PY_APP_CFG__EVA_INSTANCE_KEY
declare PY_APP_CFG__WHATSAPP_MESSENGER_URL
declare PY_APP_CFG__SMTP_SERVER
declare PY_APP_CFG__SMTP_PORT
declare PY_APP_CFG__EMAIL_HOST_ADDR
declare PY_APP_CFG__EMAIL_PORT
declare PY_APP_CFG__EMAIL_USER
declare PY_APP_CFG__EMAIL_LOGIN
declare PY_APP_CFG__EMAIL_PASSWORD
declare PY_APP_CFG__EMAIL_USE_SSL
declare PY_APP_CFG__EMAIL_USE_TLS
declare PY_APP_CFG__IS_BOX_VERSION
declare PY_APP_CFG__EVA_ACCOUNT_USE
declare PY_APP_CFG__CONVERTER_PLANTUML_URL

declare PY_GIT_CFG__APP_FQDN

declare PY_RDISK_CFG__CONVERTER_URL


declare INIT_DB=
declare PG_VER=13

if [[ -d /etc/postgresql/14 ]]; then
	PG_VER=14
fi

# $$ - в контейнерах не надёжно, может совпадать. Добавим хост.
declare E="$(hostname).$$"


debug_time() {
	echo "DEBUG_TIME $(date +"%Y-%m-%d %H:%M:%S %s") $1" >&2
	return 0
}


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

	hostname="$(hostname)"

	case "$EVA_DEPLOY_TYPE" in
	box|box-lxc|cloud-lxc|appfarm)
		# 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() {
	debug_time "start 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
}


update_config_from_env() {
	local container_var config_var

	/opt/fox_utils/crab_conf set EVA_DEPLOY_TYPE "$EVA_DEPLOY_TYPE" \
		/mnt/shared/config/CONFIG

	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
}


config_init() {
	debug_time "start config_init"
	local config_template="${1:-/opt/bin/templates/CONFIG}" overwrite="${2:-}"
	# Init /mnt/shared/config/CONFIG
	if [[ $overwrite || ! -f /mnt/shared/config/CONFIG ]]; then
		cp "$config_template" /mnt/shared/config/CONFIG.$$
		# Проставим дефолты для деплоя
		case "$EVA_DEPLOY_TYPE" in
		cloud*)
			/opt/fox_utils/crab_conf set NGINX_ENABLED FALSE /mnt/shared/config/CONFIG.$$
			;;
		appfarm)
			# Патчим стандартный шаблон
			/opt/fox_utils/crab_conf set NGINX_ENABLED FALSE /mnt/shared/config/CONFIG.$$
			/opt/fox_utils/crab_conf set POSTGRESQL_ENABLED FALSE /mnt/shared/config/CONFIG.$$
			/opt/fox_utils/crab_conf set REDIS_SERVER_ENABLED FALSE /mnt/shared/config/CONFIG.$$
			/opt/fox_utils/crab_conf set NO_SHARED TRUE /mnt/shared/config/CONFIG.$$
			;;
		esac
		mv /mnt/shared/config/CONFIG.$$ /mnt/shared/config/CONFIG
	fi
	# Set CONFIG by container env,
	update_config_from_env
	return 0
}


patch_config_py() {
	local prefix="$1" file_loc="$2"
	local env_names env_name config_name file_path="/opt/$file_loc/custom/config.py"

	echo "Setup $file_path" >&2
	# TODO: optimize with single edit command
	eval "env_names=(\"\${!${prefix}__@}\")"
	for env_name in "${env_names[@]}"; do
		config_name="${env_name#${prefix}__}"
		if [[ $config_name =~ PASS|URL|KEY ]]; then
			echo "  Set $config_name" >&2
		else
			echo "  Set $config_name=${!env_name}" >&2
		fi
		if [[ ${!env_name} =~ ^(True|False|None|-?[0-9]+(.[0-9]+)?)$ ]]; then
			if ! grep -qEe "^$config_name *= *.*" "$file_path"; then
				echo "$config_name = ${!env_name}" >>"$file_path"
			fi

			if grep -qEe "^$config_name = ${!env_name}\$" "$file_path"; then
				continue
			fi
			sed "s/^$config_name *=.*/$config_name = ${!env_name}/g" \
				-i "$file_path"
		else
			/opt/fox_utils/crab_conf set "$config_name" "${!env_name}" "$file_path"
		fi
	done
	return 0
}


patch_all_config_py() {
	debug_time "start patch_all_config_py"
	# patch */custom/config.py
	patch_config_py PY_APP_CFG eva-app
	patch_config_py PY_GIT_CFG eva_git
	# patch_config_py PY_CONVERTER eva-converter  # only_redis settings
	patch_config_py PY_RDISK_CFG rdisk/rdisk  # converter_url
	return 0
}


configure_domains() {
	local org_domain cookie_domain app_name account_url='' app_fqdn base_href=''

	echo "Настраиваем работу на домене ${DOMAIN} ..." >&2
	# DOMAIN == APP_FQDN
	# ORG_DOMAIN == AUTH_SESSION_COOKIE_DOMAIN or APP_FQDN
	# ACCOUNT_FQDN
	app_fqdn="$DOMAIN"
	app_name="${DOMAIN%%.*}"
	if [[ ${ORG_DOMAIN:-} ]]; then
		cookie_domain=".$ORG_DOMAIN"
	else
		ORG_DOMAIN="$DOMAIN"
		cookie_domain="$DOMAIN${EXTERNAL_PORT_HTTPS:+:$EXTERNAL_PORT_HTTPS}"
	fi
	org_domain="$ORG_DOMAIN"
	if [[ ${ACCOUNT_FQDN:-} ]]; then
		account_url="https://$ACCOUNT_FQDN"
	fi

	if [[ ${BASE_HREF:-} ]]; then
		base_href="$BASE_HREF"
		# Приведём к виду /prefix
		base_href="${base_href%/}"
		base_href="${base_href#/}"
		base_href="/$base_href"
	fi

	# Описание полей https://bcrm.carbonsoft.ru/project/Document/DOC-004285
	# Версия без SSO
	PY_APP_CFG__APP_FQDN="$app_fqdn"
	PY_APP_CFG__ORG_DOMAIN="$org_domain"
	PY_APP_CFG__APP_NAME="$app_name"
	PY_APP_CFG__AUTH_SERVER_URL="$account_url"
	PY_APP_CFG__AUTH_SESSION_COOKIE_DOMAIN="$cookie_domain"
	PY_APP_CFG__HOSTNAME_FQDN="$app_fqdn"
	PY_APP_CFG__ORG_NAME="$app_name"
	PY_APP_CFG__EXTERNAL_PORT_HTTPS="${EXTERNAL_PORT_HTTPS:-}"
	PY_APP_CFG__BASE_HREF="$base_href"

	PY_GIT_CFG__APP_FQDN="$app_fqdn"

	if [[
		! -f /opt/eva-app/custom/org_name
		|| $app_name != $(</opt/eva-app/custom/org_name)
		]]; then
		echo "$app_name" > /opt/eva-app/custom/org_name
	fi
	return 0
}


configure_email_server() {
	PY_APP_CFG__SMTP_SERVER="$EMAIL_HOST_ADDR"  # !!! Not Used
	PY_APP_CFG__SMTP_PORT="$EMAIL_PORT"  # !!! Not Used

	PY_APP_CFG__EMAIL_HOST_ADDR="$EMAIL_HOST_ADDR"
	PY_APP_CFG__EMAIL_PORT="$EMAIL_PORT"
	PY_APP_CFG__EMAIL_USER="$EMAIL_USER"
	PY_APP_CFG__EMAIL_LOGIN="$EMAIL_LOGIN"
	PY_APP_CFG__EMAIL_PASSWORD="$EMAIL_PASSWORD"

	if [[ $EMAIL_USE_SSL = 1 ]]; then
		PY_APP_CFG__EMAIL_USE_SSL=True
	elif [[ $EMAIL_USE_SSL = 0 ]]; then
		PY_APP_CFG__EMAIL_USE_SSL=False
	else
		echo "ERROR! Опция EMAIL_USE_SSL должна быть 1 или 0"
	fi

	if [[ $EMAIL_USE_TLS = 1 ]]; then
		PY_APP_CFG__EMAIL_USE_TLS=True
	elif [[ $EMAIL_USE_TLS = 0 ]]; then
		PY_APP_CFG__EMAIL_USE_TLS=False
	else
		echo "ERROR! Опция EMAIL_USE_TLS должна быть 1 или 0"
	fi
	return 0
}


configure_eva_app() {
	debug_time "start configure_eva_app"

	configure_domains
	configure_email_server

	if [[ ${ACCOUNT_FQDN:-} ]]; then
		PY_APP_CFG__IS_BOX_VERSION=False
		PY_APP_CFG__EVA_ACCOUNT_USE=True
	else
		PY_APP_CFG__IS_BOX_VERSION=True
		PY_APP_CFG__EVA_ACCOUNT_USE=False
	fi

	PY_APP_CFG__WHATSAPP_MESSENGER_URL="${PY_APP_CFG__WHATSAPP_MESSENGER_URL:-}"
	PY_APP_CFG__CONVERTER_PLANTUML_URL="http://127.0.0.1:8083/plantuml/"
	return 0
}


configure_rdisk() {
	debug_time "start configure_rdisk"
	# default except cloud
	PY_RDISK_CFG__CONVERTER_URL="${CONVERTER_URL:-http://127.0.0.1:8083/converter/}"
	return 0
}


_enable_ha_cluster__ssh_hostkeys() {
	mkdir -p /mnt/shared/config/etc/ssh
	# Пересоздавать существующие ключи не будет, недостающие ключи - создаст
	ssh-keygen -A -f /mnt/shared/config
	# TODO: перенести в eva_deploy,
	#       переделать ключи в ссылки на /mnt/shared/config/etc/ssh/ssh_host_*
	rsync -avhP /mnt/shared/config/etc/ssh/ssh_host_* /etc/ssh/
	return 0
}


configure_ha_cluster() {
	if [[ ${HA_COMPANION:-} ]]; then
		if [[ ! ${HA_COMPANION_IP:-} ]]; then
			echo "ERROR Не задан HA_COMPANION_IP" >&2
			return 1
		fi
		if [[ ! ${HA_ROLE:-} ]]; then
			echo "ERROR Не задан HA_ROLE" >&2
			return 1
		fi

		echo "Configure HA: HA_COMPANION_IP=$HA_COMPANION_IP, HA_ROLE=$HA_ROLE" >&2

		HA_FILE_MARKERS="${HA_FILE_MARKERS:-}"
		mkdir -p "$HA_FILE_MARKERS"
		_enable_ha_cluster__ssh_hostkeys

		PY_APP_CFG__HA_COMPANION="$HA_COMPANION"
		PY_APP_CFG__HA_ROLE="$HA_ROLE"
		# PY_APP_CFG__HA_COMPANION_IP="$HA_COMPANION_IP"  # !!! not used
		PY_APP_CFG__HA_FILE_MARKERS="$HA_FILE_MARKERS"

	elif grep -q "^HA_COMPANION" /opt/eva-app/custom/config.py; then
		echo "Clear HA configuration" >&2
		# Если отключили реплику, перед стартом Евы нужно убедиться,
		# что параметры будут удалены из конфига
		PY_APP_CFG__HA_COMPANION=None
	fi
	return 0
}


configure_data_sources() {
	local ds_conf
	debug_time "start configure_data_sources"
	# Для простоты, работаем только с однострочным значением в конфиге
	# 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_data_sources(): 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
	[[ -z ${DB_URL:-} && -z ${S3_ENDPOINT:-} ]] && return 0

	ds_conf="data_sources = {"

	ds_conf+="'default': {"
	if [[ ${DB_URL:-} ]]; then
		ds_conf+=" 'type': 'sqlalchemy',"
		ds_conf+=" 'sqlalchemy.url': '$DB_URL',"
		ds_conf+="${DB_PRE_PING:+ 'sqlalchemy.pool_pre_ping': True,}"
		ds_conf+=" 'sqlalchemy.pool_size': 2, 'sqlalchemy.pool_recycle': 3600,"
		ds_conf+=" 'sqlalchemy.poolclass': 'QueuePool', 'sqlalchemy.pool_use_lifo': True,"
		ds_conf+=" 'sqlalchemy.max_overflow': 50, 'sqlalchemy.pool_timeout': 1200,"
	else
		ds_conf+=" 'type': 'sqlalchemy',"
		ds_conf+=" 'sqlalchemy.url': 'postgresql+psycopg2://postgres@/evadb',"
		ds_conf+=" 'sqlalchemy.pool_size': 2,"
		ds_conf+=" 'sqlalchemy.pool_recycle': 3600,"
		ds_conf+=" 'sqlalchemy.poolclass': 'QueuePool',"
		ds_conf+=" 'sqlalchemy.pool_use_lifo': True,"
		ds_conf+=" 'sqlalchemy.max_overflow': 50,"
		ds_conf+=" 'sqlalchemy.pool_timeout': 1200,"
	fi
	ds_conf+="},"

	ds_conf+="'rdisk': {"
	if [[ ${S3_ENDPOINT:-} ]]; then
		ds_conf+=" 'class': 'modules.rdisk.data_driver.rdisk:RDiskDataDriver',"
		ds_conf+=" 'uri': 's3:///',"
		ds_conf+=" 'endpoint_url': '$S3_ENDPOINT',"
		ds_conf+=" 'aws_access_key_id': '$S3_AWS_ACCESS_KEY_ID',"
		ds_conf+=" 'aws_secret_access_key': '$S3_AWS_SECRET_ACCESS_KEY',"
		ds_conf+=" 'bucket_name': '$S3_BUCKET_NAME',"
		if [[ ${S3_FALLBACK:-} ]]; then
			ds_conf+=" 'fallback': {"
			ds_conf+=" 'class': 'modules.rdisk.data_driver.rdisk:RDiskDataDriver',"
			ds_conf+=" 'uri': 'file:///opt/eva-app/files/',"
			ds_conf+=" },"
		fi
	else
		ds_conf+=" 'class': 'modules.rdisk.data_driver.rdisk:RDiskDataDriver',"
		ds_conf+=" 'uri': 'file:///opt/eva-app/files/',"
	fi
	ds_conf+="}"

	ds_conf+="}"
	echo "$ds_conf" >>/mnt/shared/config/eva-app/config.py

	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
		if ! [[ ${REDIS_PORT:-6379} =~ ^[0-9]+$ ]]; then
			echo "WARNING: Invalid REDIS_PORT format: ${REDIS_PORT:-}," \
				" use default." >&2
			REDIS_PORT=
		fi
		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() {
	debug_time "start configure_external_redis"
	local app
	# wsgidav in configure_wsgidav
	for app in eva-app eva-converter; do
		configure_app_external_redis "$app"
	done
	return 0
}


configure_app_external_redis() {
	debug_time "start 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
}


configure_wsgidav() {
	debug_time "start 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)"
	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
		if [[ $EVA_DEPLOY_TYPE = cloud* ]]; then
			account_auth_url="https://account.evateam.ru"
		else
			account_auth_url="http://127.0.0.1:8080"
		fi
	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
}


sync_custom_skelet() {
	debug_time "start 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
}


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


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


write_file_from_env() {
	local file_name="$1" var_name="$2" force="${3:-}"


	if [[ ! -f "$file_name" || $force ]]; then
		# Это может быть клиентский сертификат, не имеем права его трогать
		if [[ ${!var_name:-} ]]; then
			cat >"$file_name.$E" <<<"${!var_name}"
			mv "$file_name.$E" "$file_name"
		fi
	fi
	return 0
}


ssl_gen_self_signed() {
	(
		# from self-signed-cert-ctl
		cd /etc/nginx/ssl
		echo "Не найден сертификат для домена $DOMAIN. Генерируем самоподписной"
		local subj="/C=RU/ST=Russia/L=Moscow/O=EvaTeam/OU=EvaTeam"

		if [[ ! -f rootCA.key ]]; then
			openssl genrsa -out rootCA.key 2048
		fi

		if [[ ! -f rootCA.pem ]]; then
			openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 9999 \
				-out rootCA.pem -subj "$subj/CN=CAKEY"
		fi

		openssl req -new -newkey rsa:2048 -sha256 -nodes -keyout "$DOMAIN.key" \
			-subj "$subj/CN=$DOMAIN" -out "$DOMAIN.csr"

		cat > "$DOMAIN.ext" <<EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment"
subjectAltName = @alt_names"

[alt_names]
DNS.1 = $DOMAIN
DNS.2 = *.$DOMAIN
EOF

		openssl x509 -req -in "$DOMAIN.csr" -extfile "$DOMAIN.ext" -out "$DOMAIN.crt" \
			-CA rootCA.pem -CAkey rootCA.key -sha256 -CAcreateserial -days 5000
	)
	return 0
}


ssl_bundles() {
	set -e
	local os_id_like os_py_pkg py_ver

	# 1)
	# ID_LIKE=debian # Ubuntu, Astra
	# ID_LIKE="rhel centos fedora" # RedOS
	# 2)
	# https://go.dev/src/crypto/x509/root_linux.go
	# 	"/etc/ssl/certs/ca-certificates.crt",                // Debian/Ubuntu/Gentoo etc.
	# 	"/etc/pki/tls/certs/ca-bundle.crt",                  // Fedora/RHEL 6
	# 	"/etc/ssl/ca-bundle.pem",                            // OpenSUSE
	# 	"/etc/pki/tls/cacert.pem",                           // OpenELEC
	# 	"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
	# 	"/etc/ssl/cert.pem",                                 // Alpine Linux
	os_id_like="$(
	declare ID_LIKE
	. /etc/os-release
	echo "$ID_LIKE")"
	if [[ ${os_id_like:-debian} =~ debian ]]; then
		echo /etc/ssl/certs/ca-certificates.crt
		os_py_pkg="dist-packages"
	elif [[ ${os_id_like:-debian} =~ rhel ]]; then
		echo /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
		os_py_pkg="site-packages"
	else
		echo "Unknown OS ${os_id_like}" >&2
		return 1
	fi

	py_ver="$(
	python3 -c \
		'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')"

	# fixme .../certifi/cacert.pem may be read-only!!! Move to tmp!
	echo "/usr/local/lib/python$py_ver/$os_py_pkg/certifi/cacert.pem"
	return 0
}


ssl_install_root_crt() {
	local file_name="$1" bundle bundle_hash crt_hash crt_content

	if [[ ! -f $file_name ]]; then
		echo "Crt $file_name absent. Skip install." >&2
		return 0
	fi
	# strip CR
	crt_content="$(sed 's/\r$//' "$file_name")"

	if ! grep -Fxqe '-----BEGIN CERTIFICATE-----' <<<"$crt_content"; then
		echo "Invalid SSL Certificate format: $file_name" >&2
		return 1
	fi

	grep -v '^---' >"/tmp/eva_init_ssl_crt.$E" <<<"$crt_content"
	crt_hash="$(sort <"/tmp/eva_init_ssl_crt.$E" | uniq | wc -l )"

	for bundle in $(ssl_bundles); do
		# Проверяем, что root сертификат прописан в bundle
		bundle_hash="$(
		grep -F -x -f "/tmp/eva_init_ssl_crt.$E" "$bundle" \
			| sort | uniq | wc -l || true)"
		if [[ "$bundle_hash" != "$crt_hash" ]]; then
			echo "Добавляем сертификат $file_name в $bundle" >&2
			cat <<<"$crt_content" >> "$bundle"
		fi
	done
	rm "/tmp/eva_init_ssl_crt.$E"
	return 0
}


gen_ssl_keys() {
	local dir=/etc/nginx/ssl

	write_file_from_env "$dir/rootCA.key" EVA_SSL_CA_KEY
	write_file_from_env "$dir/rootCA.pem" EVA_SSL_CA_CRT

	write_file_from_env "$dir/corp_rootCA.pem" EVA_SSL_CORP_CRT

	write_file_from_env "$dir/$DOMAIN.crt" EVA_SSL_CRT
	write_file_from_env "$dir/$DOMAIN.key" EVA_SSL_KEY

	if ! [[ -f "$dir/$DOMAIN.key" && -f "$dir/$DOMAIN.crt" ]]; then
		echo "SSL keys not found. Generate self-signed."
		ssl_gen_self_signed
	fi
	return 0
}


gen_evagit_ssh_keys() {
	[[ ${EVA_GIT_SSHD_ENABLED:-} != TRUE ]] && return 0
	debug_time "start gen_evagit_ssh_keys"
	local server_conf type key
	server_conf="/mnt/shared/config/eva_git/sshd/"
	for type in ecdsa ed25519 rsa; do
		key="$server_conf/ssh_host_${type}_key"
		[[ -f $key ]] && continue
		ssh-keygen -t "$type" -f "$key" -C "git@$(hostname)" -N ""
	done
	return 0
}


gen_crypt_keys() {
	debug_time "start gen_crypt_keys"
	# Patch
	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
		local eva_instance_key="${EVA_INSTANCE_KEY:-}"
		if [[ ! $eva_instance_key ]]; then
			echo "!!! Generate EVA_INSTANCE_KEY!"
			eva_instance_key="AES:$(openssl rand -hex 16):$(openssl rand -hex 32)"
		fi
		PY_APP_CFG__EVA_INSTANCE_KEY="$eva_instance_key"
	fi
	return 0
}


gen_jwt_keys() {
	debug_time "start gen_jwt_keys"
	if [[ ! -f /opt/eva-app/custom/jwt_rsa ]]; then
		# Для appfarm - ключи из переменных, т.к. больше хранить их негде.
		# TODO:
		#   Совсем идеально - не записывать на диск. Брать из переменных внутри апп (!!! и wsgidav)
		#   Это касается и других ключей и паролей
		if [[ ${EVA_RSA_PRV_KEY:-} && ${EVA_RSA_PUB_KEY:-} ]]; then
			echo "Write JWT from Env" >&2
			cat >/opt/eva-app/custom/jwt_rsa.$E <<<"$EVA_RSA_PRV_KEY"
			cat >/opt/eva-app/custom/jwt_rsa.pub.$E <<<"$EVA_RSA_PUB_KEY"
		else
			echo "!!! Generate new JWT keys" >&2
			openssl genrsa -out /opt/eva-app/custom/jwt_rsa.$E 1024
			openssl rsa -in /opt/eva-app/custom/jwt_rsa.$E \
				-pubout -out /opt/eva-app/custom/jwt_rsa.pub.$E
		fi
		mv /opt/eva-app/custom/jwt_rsa.$E /opt/eva-app/custom/jwt_rsa
		mv /opt/eva-app/custom/jwt_rsa.pub.$E /opt/eva-app/custom/jwt_rsa.pub
	fi
	return 0
}


set_jwt_links() {
	debug_time "start set_jwt_links"
	# skip strongbash010
	rm -f /opt/eva-app/tmp/jwt_rsa{,.pub,.pub.orig}
	# Ссылки абсолютные, т.к. многоуровневые.
	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
	return 0
}


do_autogen() {
	debug_time "start do_autogen"
	(
		cd /opt/eva-app
		if [[ ${NO_SHARED:-} = TRUE || $INIT_DB ]]; then
			# Если нет персистентного хранилища,
			#  нужно создать файлы моделей с кастом полями.
			python3 manage.py init_custom_fields
		fi
		python3 manage.py autogen
	)
	return 0
}


configure_cloud_deploy() {
	# Почти все конфиги дефолтные, ничего трогать не надо.
	gen_crypt_keys
	configure_ha_cluster
	patch_all_config_py
	configure_wsgidav
	return 0
}


configure_common_deploy() {
	check_config

	# configure fs
	gen_ssl_keys
	fix_converter_scripts
	gen_evagit_ssh_keys
	ssl_install_root_crt /etc/nginx/ssl/rootCA.pem
	ssl_install_root_crt /etc/nginx/ssl/corp_rootCA.pem

	# configure PyApps
	gen_crypt_keys
	configure_ha_cluster
	configure_eva_app
	configure_rdisk

	patch_all_config_py

	if [[ $EVA_DEPLOY_TYPE == appfarm ]]; then
		# todo: allow for box too
		configure_data_sources
		configure_external_redis
	fi

	configure_wsgidav
	return 0
}


configure_local_redis() {
	if [[ $MANUAL_CONFIGURATION ]]; then
		echo "MANUAL_CONFIGURATION in /opt/CONFIG, skip redis config" >&2
	elif [[ $EVA_DEPLOY_TYPE = cloud* ]]; then
		if [[ ${SLA:-} ]]; then
			/opt/fox_acrm/deploy/provision.py --sla "$SLA" --redis
		fi
	else
		/opt/fox_acrm/deploy/provision.py \
			--memory-limit-gb "${MEMORY_LIMIT_GB:-8}" --redis
	fi
	return 0
}


configure_local_postgres() {
	patch_postgres_cluster
	if [[ $MANUAL_CONFIGURATION ]]; then
		echo "MANUAL_CONFIGURATION in /opt/CONFIG, skip postgres config" >&2
	elif [[ $EVA_DEPLOY_TYPE = cloud* ]]; then
		if [[ ${SLA:-} ]]; then
			/opt/fox_acrm/deploy/provision.py --sla "$SLA" --postgres
		fi
		# Чтобы постоянные синки не клали ноду отключаем их у pg в облаке.
		# fixme dups!
		echo "fsync = 0" >>"/etc/postgresql/$PG_VER/main/postgresql.conf"
	else
		/opt/fox_acrm/deploy/provision.py \
			--memory-limit-gb "${MEMORY_LIMIT_GB:-8}" --postgres
	fi
	return 0
}


main() {
	debug_time "start main"
	set_data_location
	/opt/bin/eva_init_access.sh
	sync_custom_skelet
	gen_jwt_keys
	set_jwt_links
	/opt/bin/_uwsgi_configure.sh
	/opt/bin/_nginx_configure

	if [[ $MANUAL_CONFIGURATION ]]; then
		echo "MANUAL_CONFIGURATION in /opt/CONFIG, skip auto config" >&2
	elif [[ $EVA_DEPLOY_TYPE = cloud* ]]; then
		configure_cloud_deploy
	elif [[ $EVA_DEPLOY_TYPE =~ ^(box.*)|appfarm$ ]]; then
		configure_common_deploy
	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
		configure_local_redis
		/etc/init.d/redis-server start
	fi
	if [ "${POSTGRESQL_ENABLED:-TRUE}" = 'TRUE' ]; then
		configure_local_postgres
		/etc/init.d/postgresql start
	fi
	do_autogen
	return 0
}


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


init_db() {
	debug_time "start init_db"
	local current_revision
	(
		cd /opt/eva-app
		echo "Check db initialization." >&2
		# Версии алембика пустая, если бд не создавалась.
		# fixme: !!!! maybe dirty output(cmf: print()), grep pattern!!!
		current_revision=$(/usr/local/bin/alembic current)
		if [[ "$current_revision" ]]; then
			echo "Db already initialized, version=$current_revision"
		else
			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
}


app_farm_init() {
	# Здесь только создание БД
	config_init
	source /opt/CONFIG

	INIT_DB=TRUE  # Skip write_custom_fields
	main

	init_db

	flush_cache
	return 0
}


shared_lock() {
	debug_time "start shared_lock"
	# get shared lock
	local my_id="$E" 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() {
	debug_time "start shared_unlock"
	rm -f /mnt/shared/.lock
	return 0
}


k8s_init_shared_init() {
	debug_time "start 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() {
	debug_time "start 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

	rsync -i -rl -v --ignore-existing \
		--exclude /config/etc --exclude /eva_pg_backup \
		/skelet/shared/* /mnt/shared/
	return 0
}


k8s_init() {
	debug_time "start k8s_init"
	EVA_DEPLOY_TYPE=k8s
	# Контейнер инициализации, разово заполним том /mnt/shared из скелета образа: /skelet/shared
	# /mnt/configs/ - ConfigMap, копируем поверх скелета в /mnt/shared/config
	shared_lock

	k8s_init_shared_init
	k8s_init_shared_patch
	# /mnt/configs - k8s configmaps
	config_init "/mnt/configs/CONFIG" overwrite

	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

	# 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

	gen_ssl_keys
	gen_jwt_keys
	gen_crypt_keys
	gen_evagit_ssh_keys

	k8s_init_pod_fs

	configure_eva_app
	configure_rdisk

	patch_all_config_py

	configure_data_sources
	configure_external_redis

	configure_wsgidav

	do_autogen
	init_db

	# release lock
	shared_unlock
	flush_cache
	touch /mnt/shared/.init_done
	return 0
}


k8s_init_pod_fs() {
	debug_time "start k8s_init_pod_fs"
	# здесь патчим /mnt/tmp, shared по возможности не трогаем.
	# set_data_location TODO переиспользовать
	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

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

	# patch image if rw
	sync_custom_skelet

	set_jwt_links
	return 0
}


k8s_main() {
	# Shared не трогаем, инициализируем только tmpfs
	debug_time "start k8s_main"

	k8s_init_pod_fs

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

	/opt/bin/_uwsgi_configure.sh
	/opt/bin/_nginx_configure
	ssl_install_root_crt /etc/nginx/ssl/rootCA.pem
	ssl_install_root_crt /etc/nginx/ssl/corp_rootCA.pem

	do_autogen
	return 0
}


subcommand() {
	if [[ ${1:-} == k8s-init ]]; then
		k8s_init
	elif [[ ${1:-} == appfarm-init ]]; then
		app_farm_init
	else
		echo "Unknown subcommand $@" >&2
		return 1
	fi
	return 0
}


if [[ ${1:-} ]]; then
	subcommand "$@"
	exit 0
fi


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

exit 0
