Files
im_server/docker/tinode/entrypoint.sh
T
Your NameandClaude Sonnet 5 b30cce950a fix(docker): mirror tinode's own log output to stdout
Confirmed live: /var/log/tinode.log-only redirection meant Loki never
received a single real tinode runtime log line (election, rehash,
connection, error output) since the container started -- Promtail
collects standard container stdout/stderr, not files written inside
the container. Every Pod's collected log was just this script's own
"NO_DB_INIT=true: skipping..." init line, nothing from tinode itself.

Now more consequential with native Cluster enabled: failover/rehash
state transitions were completely invisible to the normal Grafana/Loki
monitoring path, visible only via manual kubectl exec.

tee mirrors to both stdout (collected) and the file (still readable via
kubectl exec). PIPESTATUS[0] is required since a bare $? after a pipe
would report tee's exit status, not tinode's -- which also let this
drop the now-redundant "tail last 200 lines to stderr on crash" block,
since the full live stream already went to stdout throughout the run.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 20:23:25 +08:00

200 lines
5.4 KiB
Bash

#!/bin/bash
# If EXT_CONFIG is set, use it as a config file.
if [ ! -z "$EXT_CONFIG" ] ; then
CONFIG="$EXT_CONFIG"
# Enable push notifications.
if [ ! -z "$FCM_SENDER_ID" ] ; then
FCM_PUSH_ENABLED=true
fi
else
CONFIG=working.config
: "${REDIS_KEY_PREFIX:=im}"
if [ -z "$CLUSTER_NODES_JSON" ] ; then
CLUSTER_NODES_JSON='[{"name":"tinode-0","addr":"tinode-0:12000"},{"name":"tinode-1","addr":"tinode-1:12001"},{"name":"tinode-2","addr":"tinode-2:12002"}]'
fi
# Remove the old config.
rm -f working.config
# The 'alldbs' is not a valid adapter name.
if [ "$TARGET_DB" = "alldbs" ] ; then
TARGET_DB=
fi
# Enable email verification if $SMTP_SERVER is defined.
if [ ! -z "$SMTP_SERVER" ] ; then
EMAIL_VERIFICATION_REQUIRED='"auth"'
fi
# Enable TLS (httpS).
if [ ! -z "$TLS_DOMAIN_NAME" ] ; then
TLS_ENABLED=true
fi
# Enable push notifications.
if [ ! -z "$FCM_CRED_FILE" ] ; then
FCM_PUSH_ENABLED=true
fi
if [ ! -z "$TNPG_AUTH_TOKEN" ] ; then
TNPG_PUSH_ENABLED=true
fi
if [ ! -z "$ICE_SERVERS_FILE" ] ; then
WEBRTC_ENABLED=true
fi
# Generate a new 'working.config' from template and environment
while IFS='' read -r line || [[ -n $line ]] ; do
while [[ "$line" =~ (\$[A-Z_][A-Z_0-9]*) ]] ; do
LHS=${BASH_REMATCH[1]}
RHS="$(eval echo "\"$LHS\"")"
line=${line//$LHS/"$RHS"}
done
echo "$line" >> working.config
done < config.template
fi
# If external static dir is defined, use it.
# Otherwise, fall back to "./static".
if [ ! -z "$EXT_STATIC_DIR" ] ; then
STATIC_DIR=$EXT_STATIC_DIR
else
STATIC_DIR="./static"
fi
# Do not load data when upgrading database.
if [ "$UPGRADE_DB" = "true" ] ; then
SAMPLE_DATA=
fi
# If push notifications are enabled, generate client-side firebase config file.
if [ ! -z "$FCM_PUSH_ENABLED" ] || [ ! -z "$TNPG_PUSH_ENABLED" ] ; then
# Write client config to $STATIC_DIR/firebase-init.js
cat > $STATIC_DIR/firebase-init.js <<- EOM
const FIREBASE_INIT = {
apiKey: "$FCM_API_KEY",
appId: "$FCM_APP_ID",
messagingSenderId: "$FCM_SENDER_ID",
projectId: "$FCM_PROJECT_ID",
messagingVapidKey: "$FCM_VAPID_KEY",
measurementId: "$FCM_MEASUREMENT_ID"
};
EOM
else
# Create an empty firebase-init.js
echo "" > $STATIC_DIR/firebase-init.js
fi
if [ ! -z "$IOS_UNIV_LINKS_APP_ID" ] ; then
# Write config to $STATIC_DIR/apple-app-site-association config file.
# See https://developer.apple.com/library/archive/documentation/General/Conceptual/AppSearch/UniversalLinks.html for details.
cat > $STATIC_DIR/apple-app-site-association <<- EOM
{
"applinks": {
"apps": [],
"details": [
{
"appID": "$IOS_UNIV_LINKS_APP_ID",
"paths": [ "*" ]
}
]
}
}
EOM
fi
# Wait for database if needed.
if [ ! -z "$WAIT_FOR" ] ; then
IFS=':' read -ra DB <<< "$WAIT_FOR"
if [ ${#DB[@]} -ne 2 ]; then
echo "\$WAIT_FOR (${WAIT_FOR}) env var should be in form HOST:PORT"
exit 1
fi
until nc -z -v -w5 ${DB[0]} ${DB[1]}; do echo "waiting for ${WAIT_FOR}..."; sleep 3; done
fi
run_with_retries() {
local name="$1"
shift
local attempts="${STARTUP_RETRY_ATTEMPTS:-10}"
local delay="${STARTUP_RETRY_DELAY_SECONDS:-3}"
local i=1
while [ "$i" -le "$attempts" ]; do
"$@"
local status=$?
if [ "$status" -eq 0 ]; then
return 0
fi
echo "$name failed with status $status (attempt $i/$attempts)."
if [ "$i" -eq "$attempts" ]; then
return "$status"
fi
sleep "$delay"
i=$((i + 1))
done
}
init_db_once() {
./init-db \
--reset=${RESET_DB} \
--upgrade=${UPGRADE_DB} \
--config=${CONFIG} \
--data=${SAMPLE_DATA} \
--no_init=${NO_DB_INIT} \
1>${init_stdout}
}
apply_hotgo_tenant_db_once() {
IM_MYSQL_DSN="${MYSQL_DSN}" ./apply-hotgo-tenant-db
}
init_stdout=./init-db-stdout.txt
if [ "$NO_DB_INIT" = "true" ] ; then
echo "NO_DB_INIT=true: skipping init-db and apply-hotgo-tenant-db."
else
# Initialize the database if it has not been initialized yet or if data reset/upgrade has been requested.
run_with_retries "init-db" init_db_once
if [ $? -ne 0 ]; then
echo "./init-db failed. Quitting."
exit 1
fi
# Create/upgrade the hotgo tenant registry and the workbench/org/meetings/
# reports/mailbox/etc. tables that init-db above does not manage.
run_with_retries "apply-hotgo-tenant-db" apply_hotgo_tenant_db_once
if [ $? -ne 0 ]; then
echo "./apply-hotgo-tenant-db failed. Quitting."
exit 1
fi
fi
# If sample data was provided, try to find Tino password.
if [ ! -z "$SAMPLE_DATA" ] ; then
grep "usr;tino;" $init_stdout > /botdata/tino-password
fi
if [ -s /botdata/tino-password ] ; then
# Convert Tino's authentication credentials into a cookie file.
# /botdata/tino-password could be empty if DB was not updated. In such a case the
# /botdata/.tn-cookie will not be modified.
./credentials.sh /botdata/.tn-cookie < /botdata/tino-password
fi
args=("--config=${CONFIG}" "--static_data=$STATIC_DIR" "--cluster_self=$CLUSTER_SELF" "--pprof_url=$PPROF_URL")
# Run the tinode server, mirroring output to both stdout (so kubectl logs/Promtail's
# standard container-log collection actually sees it -- confirmed live that the old
# file-only redirect meant Loki never received a single real tinode log line, only
# this script's own earlier init-db output) and the log file (kept for exec-based
# inspection, e.g. `kubectl exec ... -- cat /var/log/tinode.log`). PIPESTATUS[0] is
# required here: with output piped through tee, a bare $? would report tee's exit
# status (almost always 0) instead of tinode's.
./tinode "${args[@]}" 2>&1 | tee -a /var/log/tinode.log
exit "${PIPESTATUS[0]}"