#!/bin/sh
### Copyright 1999-2024. WebPros International GmbH. All rights reserved.

# If env variable PLESK_INSTALLER_ERROR_REPORT=path_to_file is specified then in case of error
# free_ram_check.sh writes single line json report into it with the following fields:
# - "stage": "ramcheck"
# - "level": "error"
# - "errtype": "notenoughfreeram"
# - "required": required RAM, human readable (e.g. "600 MB")
# - "available": available RAM, human readable (e.g. "255 MB")
# - "needtofree": amount of RAM which should be added or freed, human readable (e.g. "345 MB")
# - "date": time of error occurance ("2020-03-24T06:59:43,127545441+0000")
# - "error": human readable error message ("There is not enough RAM available.")

human_readable_size()
{
	echo "$1" | awk '
		function human(x) {
			s = "MGTEPYZ";
			while (x >= 1000 && length(s) > 1) {
				x /= 1024; s = substr(s, 2);
			}
			# 0.05 below will make sure the value is rounded up
			return sprintf("%.1f %sB", x + 0.05, substr(s, 1, 1));
		}
		{ print human($1); }'
}


# @params are tags in format "key=value"
# Report body (human readable information) is read from stdin
# and copied to stderr.
make_error_report()
{
	local report_file="${PLESK_INSTALLER_ERROR_REPORT:-}"

	local python_bin=
	for bin in "/opt/psa/bin/python" "/usr/local/psa/bin/python" "/usr/bin/python2" "/opt/psa/bin/py3-python" "/usr/local/psa/bin/py3-python" "/usr/libexec/platform-python" "/usr/bin/python3"; do
		if [ -x "$bin" ]; then
			python_bin="$bin"
			break
		fi
	done

	if [ -n "$report_file" -a -x "$python_bin" ]; then
		"$python_bin" -c 'import sys, json
report_file = sys.argv[1]
error = sys.stdin.read()

sys.stderr.write(error)

data = {
    "error": error,
}

for tag in sys.argv[2:]:
    k, v = tag.split("=", 1)
    data[k] = v

with open(report_file, "a") as f:
    json.dump(data, f)
    f.write("\n")
' "$report_file" "date=$(date --utc --iso-8601=ns)" "$@"
	else
		cat - >&2
	fi
}

check_free_ram()
{
	local required="$1"
	local available_mem
	available_mem=$(free -m | awk '/^Mem:/ {print $7}')

	if [ "$available_mem" -lt "$required" ] ; then
		local needtofree
		needtofree="`human_readable_size $((required - available_mem))`"
		make_error_report 'stage=ramcheck' 'level=error' 'errtype=notenoughfreeram' \
			"required=$required MB" "available=$available_mem MB" "needtofree=$needtofree" <<-EOL
				There is not enough RAM available. You need to free up $needtofree.
		EOL
		exit 2
	fi
}

check_free_ram "$@"