After...
Code: Select all
max_instance_count=$(jq -r ".system.max_instance_count | select( . != null )" "$SA_CONFIG")
if [ -n "$max_instance_count" ] && [ "$max_instance_count" -gt 0 ]; then
nofile_soft_limit=$((nofile_soft_limit / ( max_instance_count + 1 )))
echo "setting ulimit -n to $nofile_soft_limit"
else
echo "Error: max_instance_count is not valid or not found in $SA_CONFIG, defaulting ulimit to 55000"
nofile_soft_limit=55000
fi
Add following:
Code: Select all
###########################################################
# INSTANCE LIMIT / REPUTATION RESERVED SLOT CHECK
#
# IMPORTANT:
# Sashimono's sa.sqlite database is the source of truth.
# Do NOT count /home directories or Linux users.
#
# This code runs inside user-install.sh BEFORE Sashimono
# inserts the NEW instance into the database, so:
#
# allocated instances = instances already in use
# available slots = max - allocated
#
###########################################################
# ---------------------------------------------------------
# Existing nofile setup
# ---------------------------------------------------------
nofile_soft_limit=$(ulimit -n -S)
if [ "$nofile_soft_limit" -lt 250000 ]; then
ulimit -n 250000
nofile_soft_limit=250000
fi
# ---------------------------------------------------------
# Get configured max instance count
# ---------------------------------------------------------
max_instance_count=$(jq -r '.system.max_instance_count // empty' "$SA_CONFIG")
if [[ "$max_instance_count" =~ ^[0-9]+$ ]] &&
[ "$max_instance_count" -gt 0 ]; then
nofile_soft_limit=$((nofile_soft_limit / (max_instance_count + 1)))
echo "setting ulimit -n to $nofile_soft_limit"
else
echo "Error: max_instance_count is invalid or missing from $SA_CONFIG"
echo "INVALID_MAX_INSTANCE_COUNT,INST_ERR"
exit 1
fi
# ---------------------------------------------------------
# Sashimono instance database
# ---------------------------------------------------------
SA_DB="/etc/sashimono/sa.sqlite"
if [ ! -f "$SA_DB" ]; then
echo "Error: Sashimono database does not exist: $SA_DB"
echo "SA_DATABASE_NOT_FOUND,INST_ERR"
exit 1
fi
# ---------------------------------------------------------
# Read:
#
# 1. allocated instance count
# 2. whether a RUNNING reputation instance exists
#
# Directly from Sashimono's own database.
# ---------------------------------------------------------
if ! slot_db_result=$(
python3 - "$SA_DB" <<'PY'
import sqlite3
import sys
db_path = sys.argv[1]
try:
db = sqlite3.connect(
f"file:{db_path}?mode=ro",
uri=True,
timeout=5
)
# Same concept Sashimono itself uses for allocated
# instances: everything except destroyed instances.
allocated = db.execute("""
SELECT COUNT(name)
FROM instances
WHERE status != 'destroyed'
""").fetchone()[0]
# Reputation must actually be in RUNNING state and
# have "reputation" in its image name.
reputation = db.execute("""
SELECT COUNT(name)
FROM instances
WHERE LOWER(status) = 'running'
AND LOWER(image_name) LIKE '%reputation%'
""").fetchone()[0]
print(f"{int(allocated)}|{'true' if int(reputation) > 0 else 'false'}")
db.close()
except Exception as e:
print(f"ERROR:{e}", file=sys.stderr)
sys.exit(1)
PY
); then
echo "Error: failed reading Sashimono instance database."
echo "SA_DATABASE_READ_ERROR,INST_ERR"
exit 1
fi
# ---------------------------------------------------------
# Parse DB result
#
# Example:
#
# 2|true
# ---------------------------------------------------------
IFS='|' read -r current_instance_count reputation_running <<< "$slot_db_result"
# Validate returned instance count
if [[ ! "$current_instance_count" =~ ^[0-9]+$ ]]; then
echo "Error: invalid allocated instance count: $current_instance_count"
echo "SA_DATABASE_COUNT_INVALID,INST_ERR"
exit 1
fi
# Validate reputation result
if [[ "$reputation_running" != "true" ]] &&
[[ "$reputation_running" != "false" ]]; then
echo "Error: invalid reputation status: $reputation_running"
echo "SA_DATABASE_REPUTATION_INVALID,INST_ERR"
exit 1
fi
# ---------------------------------------------------------
# Calculate remaining slots
# ---------------------------------------------------------
available_instance_count=$((max_instance_count - current_instance_count))
if [ "$available_instance_count" -lt 0 ]; then
available_instance_count=0
fi
# ---------------------------------------------------------
# Normalize requested image and official reputation image
#
# docker_image may contain your custom:
#
# --setting--value
#
# suffix, so strip that for comparison.
# ---------------------------------------------------------
requested_base_image="${docker_image%%--*}"
configured_reputation_image="${REPUTATION_IMAGE:-}"
configured_reputation_image="${configured_reputation_image%%--*}"
# Strip optional @sha256 digest as well
requested_base_image="${requested_base_image%%@*}"
configured_reputation_image="${configured_reputation_image%%@*}"
# ---------------------------------------------------------
# Determine if THIS deployment is the official reputation
# image.
#
# We do NOT simply trust any arbitrary image containing
# "reputation" here.
# ---------------------------------------------------------
requested_is_reputation=false
if [ -n "$configured_reputation_image" ] &&
[ "$requested_base_image" = "$configured_reputation_image" ]; then
requested_is_reputation=true
fi
# ---------------------------------------------------------
# Log current state
# ---------------------------------------------------------
echo
echo "##########################################################"
echo "# Instance slot check"
echo "##########################################################"
echo "Maximum instances: $max_instance_count"
echo "Allocated instances: $current_instance_count"
echo "Available instances: $available_instance_count"
echo "Reputation running: $reputation_running"
echo "Requested image: $requested_base_image"
echo "Configured reputation image: $configured_reputation_image"
echo "Request is reputation: $requested_is_reputation"
echo
# ---------------------------------------------------------
# Absolutely no capacity
# ---------------------------------------------------------
if [ "$available_instance_count" -le 0 ]; then
echo "No Sashimono instance slots are available."
echo "MAX_INSTANCES_REACHED,INST_ERR"
# Do NOT rollback here.
#
# user-install.sh has not created the new $user yet.
exit 1
fi
# ---------------------------------------------------------
# RESERVE FINAL SLOT FOR REPUTATION
#
# RULE:
#
# If only ONE slot remains AND no reputation instance
# is currently running:
#
# normal image -> BLOCK
# reputation image -> ALLOW
#
# This means the final slot cannot accidentally be taken
# by another tenant when reputation is missing.
# ---------------------------------------------------------
if [ "$available_instance_count" -eq 1 ] &&
[ "$reputation_running" != "true" ]; then
echo "WARNING: Only one Sashimono instance slot remains."
echo "WARNING: No running reputation instance was found."
echo
if [ "$requested_is_reputation" = "true" ]; then
echo "Requested deployment is the configured reputation image."
echo "Allowing reputation to use the reserved final slot."
echo
else
echo "Final instance slot is reserved for reputation."
echo "Rejecting normal deployment."
echo
echo "LAST_SLOT_RESERVED_FOR_REPUTATION,INST_ERR"
# IMPORTANT:
# Do NOT call rollback here because $user has not
# been created yet.
exit 1
fi
else
# Helpful logging only
if [ "$reputation_running" = "true" ]; then
echo "Reputation is already running."
echo "Reserved-slot protection is not required."
else
echo "More than one instance slot remains."
echo "Reserved-slot protection is not required yet."
fi
echo
fi
###########################################################
# END INSTANCE LIMIT / REPUTATION RESERVED SLOT CHECK
###########################################################