add rpm packaging; dnf and firewalld support

- packaging/rpm/terraria-server-manager.spec.in: installs via make
  install, plain scriptlets (no Fedora-only macros) mirroring the deb
  maintainer scripts; removal stops servers, disables boot/backups/
  daemon and removes only terractl's own drop-ins.
- make rpm (rpmbuild --nodeps, works on Debian/Ubuntu); make check
  parses the spec when rpmspec is installed.
- Release workflow builds deb and rpm, attaches both, publishes the rpm
  to Gitea's RPM registry. Job renamed to 'packages'.
- pkg_install: install hints use dnf or apt with the right package
  names (doctor, fetch, python3/openssl checks).
- firewalld: new prints the firewall-cmd command for its port; doctor
  lists instance and daemon ports firewalld doesn't allow.
- Docs, README, AGENTS.md and changelog; VERSION 0.0.13.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adamandClaude Opus 5.5 committed 2026-10-02 22:54:39 +00:00
1 parent 3a3b4b8eb9
commit 85da15a26f
10 files changed
+332 -38

No files matched your search

+51 -7
View File
@@ -53,6 +53,30 @@ join_by() {
}
log() { echo "terractl: $*" >&2; }
# The command that installs <what> (unzip, curl, python3, openssl, icu, polkit)
# with this system's package manager: pkg_install <sudo prefix> <what>
pkg_install() {
local sudo=$1 what=$2
if command -v apt-get >/dev/null; then
case $what in icu) what=libicu-dev ;; polkit) what=polkitd ;; esac
echo "${sudo}apt install $what"
elif command -v dnf >/dev/null; then
case $what in icu) what=libicu ;; esac
echo "${sudo}dnf install $what"
else
case $what in icu) what=ICU ;; esac
echo "install $what with your package manager"
fi
}
# firewalld is on by default on Fedora and RHEL, and blocks new ports until
# they're opened. Both need root (or polkit's permission) to ask.
firewalld_running() { command -v firewall-cmd >/dev/null && firewall-cmd --state >/dev/null 2>&1; }
firewalld_allows() { firewall-cmd --query-port="$1/tcp" >/dev/null 2>&1; }
firewalld_open_cmd() { # firewalld_open_cmd <sudo prefix> <port>
echo "${1}firewall-cmd --permanent --add-port=$2/tcp && ${1}firewall-cmd --reload"
}
# Is <user> (default: whoever runs this) in the terraria group?
in_group() {
[[ " $(id -nG "${1:-$(id -un)}" 2>/dev/null) " == *" $SVC_USER "* ]]
@@ -1054,6 +1078,10 @@ EOF
$(hint root enable "$name" --now)
$(hint group attach "$name")
EOF
if firewalld_running && ! firewalld_allows "$(inst_port "$name")"; then
echo "firewalld is on; to let players connect, open its port:"
echo " $(firewalld_open_cmd "$(if [[ $EUID -ne 0 ]]; then echo "sudo "; fi)" "$(inst_port "$name")")"
fi
location_warnings
}
@@ -1839,16 +1867,16 @@ doctor_system() {
# Programs
before=$(doc_problems_so_far)
command -v unzip >/dev/null || doc_problem FAIL "unzip isn't installed, so servers can't be unpacked" "${DOC_SUDO}apt install unzip"
command -v unzip >/dev/null || doc_problem FAIL "unzip isn't installed, so servers can't be unpacked" "$(pkg_install "$DOC_SUDO" unzip)"
mapfile -t tml_confs < <(grep -l '^TYPE=tmodloader' "$BASE_DIR"/*/instance.conf 2>/dev/null || true)
tml=${#tml_confs[@]}
if [[ $tml -gt 0 ]]; then
ldconfig=$(command -v ldconfig || echo /sbin/ldconfig)
if ! "$ldconfig" -p 2>/dev/null | grep -q 'libicuuc\.so'; then
doc_problem FAIL "ICU isn't installed; tModLoader servers stop with 'Aborted' without it" "${DOC_SUDO}apt install libicu-dev"
doc_problem FAIL "ICU isn't installed; tModLoader servers stop with 'Aborted' without it" "$(pkg_install "$DOC_SUDO" icu)"
fi
command -v curl >/dev/null ||
doc_problem FAIL "curl isn't installed; tModLoader servers need it to download .NET on their first start" "${DOC_SUDO}apt install curl"
doc_problem FAIL "curl isn't installed; tModLoader servers need it to download .NET on their first start" "$(pkg_install "$DOC_SUDO" curl)"
fi
if [[ $(doc_problems_so_far) -eq $before ]]; then
doc_ok "programs$(if [[ $tml -gt 0 ]]; then echo " (including ICU and curl for tModLoader)"; fi)"
@@ -1938,12 +1966,17 @@ doctor_system() {
if [[ $(systemctl show -p LoadState --value polkit.service 2>/dev/null) != loaded ]]; then
doc_problem warn "polkit isn't installed, so members of the '$SVC_USER' group need sudo to start and stop servers" \
"${DOC_SUDO}apt install polkitd"
"$(pkg_install "$DOC_SUDO" polkit)"
fi
if systemctl is-enabled --quiet terractld.service 2>/dev/null; then
if systemctl is-active --quiet terractld.service; then
doc_ok "the daemon for other hosts (terractld) is running"
d=${TERRACTL_LISTEN:-7776}; d=${d##*:}
if [[ $EUID -eq 0 ]] && firewalld_running && ! firewalld_allows "$d"; then
doc_problem warn "firewalld doesn't allow port $d/tcp, so other hosts can't reach the daemon" \
"$(firewalld_open_cmd "$DOC_SUDO" "$d") (or allow it only from the hosts that manage this one)"
fi
else
doc_problem FAIL "the daemon for other hosts (terractld) is enabled but not running" \
"${DOC_SUDO}systemctl restart terractld; if it stops again: journalctl -u terractld" \
@@ -2101,6 +2134,17 @@ doctor_instances() {
doc_problem warn "$list use port $p, so only one of them can run at a time" \
"change port= in the serverconfig.txt of all but one"
done
# Opening ports is left to a person: it's a decision about who can connect
if [[ $EUID -eq 0 ]] && firewalld_running; then
for p in "${!by_port[@]}"; do
list=${by_port[$p]}
if [[ -n $only && " $list " != *" $only "* ]]; then continue; fi
if ! firewalld_allows "$p"; then
doc_problem warn "firewalld doesn't allow port $p/tcp, so players can't connect to ${list// /, }" \
"$(firewalld_open_cmd "$DOC_SUDO" "$p")"
fi
done
fi
}
# Each instance is checked in a subshell (load_conf sets globals), so its
@@ -2256,8 +2300,8 @@ cmd_fetch() {
"") die "usage: terractl fetch vanilla|tmodloader [<version>|latest] [--upgrade <name>], or: terractl fetch vanilla|tmodloader --list" ;;
*) die "unknown server type '$type' (vanilla or tmodloader)" ;;
esac
command -v curl >/dev/null || die "fetch needs curl: sudo apt install curl"
command -v python3 >/dev/null || die "fetch needs python3: sudo apt install python3"
command -v curl >/dev/null || die "fetch needs curl: $(pkg_install "sudo " curl)"
command -v python3 >/dev/null || die "fetch needs python3: $(pkg_install "sudo " python3)"
if [[ $list -eq 1 ]]; then
[[ -z $version && -z $upgrade ]] || die "--list doesn't take a version or --upgrade"
fetch_list "$type"
@@ -2368,7 +2412,7 @@ run_remote_helper() {
# A development copy uses the helper from its source tree
if [[ $helper == *@* ]]; then helper="$(dirname "$self")/../lib/terractl-remote"; fi
if [[ $ver == *@* ]]; then ver=development; fi
command -v python3 >/dev/null || die "this needs python3 (sudo apt install python3)"
command -v python3 >/dev/null || die "this needs python3: $(pkg_install "sudo " python3)"
TERRACTL_BIN=$self TERRACTL_VERSION=$ver TERRACTL_CALLER_PWD=$CALLER_PWD \
TERRACTL_LISTEN=${TERRACTL_LISTEN:-} exec python3 "$helper" "$@"
}