diff --git a/package/shared/update-xrpld.service b/package/shared/update-xrpld.service new file mode 100644 index 0000000000..28bbdf5577 --- /dev/null +++ b/package/shared/update-xrpld.service @@ -0,0 +1,16 @@ +[Unit] +Description=Check for and install xrpld package updates +Documentation=man:systemd.service(5) +Wants=network-online.target +After=network-online.target +ConditionPathExists=/opt/xrpld/bin/update-xrpld.sh +ConditionPathExists=/opt/xrpld/bin/xrpld + +[Service] +Type=oneshot +ExecStart=/usr/bin/flock -n /run/lock/xrpld-update.lock /opt/xrpld/bin/update-xrpld.sh +StandardOutput=journal +StandardError=journal +SyslogIdentifier=update-xrpld +TimeoutStartSec=30min +PrivateTmp=true diff --git a/package/shared/update-xrpld.sh b/package/shared/update-xrpld.sh index cf5cef6ffb..f9dc423afa 100755 --- a/package/shared/update-xrpld.sh +++ b/package/shared/update-xrpld.sh @@ -1,74 +1,134 @@ #!/usr/bin/env bash +set -euo pipefail -# auto-update script for xrpld daemon +# Optional: also write logs to a legacy file in addition to journald. +# By default, this script logs to systemd/journald, viewable via: +# journalctl -t update-xrpld +# +# Uncomment the line below if you need a flat file for compatibility with +# external tooling, manual inspection, or environments where journald logs +# are not persisted or easily accessible. +# +# Note: This duplicates all output (stdout/stderr) to both journald and the file. +# It is generally not needed on modern systems and may cause log file growth +# if left enabled long-term. +# +# Requires /var/log/xrpld/ to exist and be writable by the service (root). +# +# exec > >(tee -a /var/log/xrpld/update.log) 2>&1 -# Check for sudo/root permissions -if [[ $(id -u) -ne 0 ]] ; then - echo "This update script must be run as root or sudo" - exit 1 -fi +PATH=/usr/sbin:/usr/bin:/sbin:/bin -LOCKDIR=/run/lock/xrpld-update.lock -UPDATELOG=/var/log/xrpld/update.log +PKG_NAME=${PKG_NAME:-xrpld} -function cleanup { - # If this directory isn't removed, future updates will fail. - rmdir "$LOCKDIR" +log() { + # If running under systemd/journald, let it handle timestamps. + if [[ -n "${JOURNAL_STREAM:-}" ]]; then + printf '%s\n' "$*" + else + printf '%s %s\n' "$(date -u +'%Y-%m-%dT%H:%M:%SZ')" "$*" + fi } -# Use mkdir to check if process is already running. mkdir is atomic, as against file create. -if ! mkdir "$LOCKDIR" 2>/dev/null; then - echo "$(date -u) lockdir exists - won't proceed." >> "$UPDATELOG" - exit 1 -fi -trap cleanup EXIT +require_root() { + if [[ ${EUID:-$(id -u)} -ne 0 ]]; then + log "This update script must be run as root" + exit 1 + fi +} -can_update=false - -if command -v apt-get &>/dev/null; then +apt_can_update() { apt-get update -qq + apt-get -s --only-upgrade install "$PKG_NAME" 2>/dev/null | grep -q "^Inst ${PKG_NAME}\b" +} - if apt-get -s --only-upgrade install xrpld 2>/dev/null | grep -q '^Inst xrpld'; then - can_update=true +apt_apply_update() { + DEBIAN_FRONTEND=noninteractive apt-get install -y -qq "$PKG_NAME" +} + +get_rpm_pm() { + if command -v dnf >/dev/null 2>&1; then + printf 'dnf\n' + elif command -v yum >/dev/null 2>&1; then + printf 'yum\n' + else + return 1 fi +} - function apply_update { - DEBIAN_FRONTEND=noninteractive apt-get install -y -qq xrpld - } -elif command -v yum &>/dev/null; then - REPO=${REPO:-stable} - if [[ ! "$REPO" =~ ^(stable|unstable|nightly|develop)$ ]]; then - echo "Invalid REPO value: ${REPO}" >&2 - exit 1 +rpm_refresh_metadata() { + local pm=$1 + + if [[ "$pm" == "dnf" ]]; then + dnf makecache --refresh -q >/dev/null + else + yum clean expire-cache -q >/dev/null fi - yum --disablerepo=* --enablerepo="ripple-${REPO}" clean expire-cache +} - # yum check-update exits 100 when updates are available, 0 for none, 1 for errors. - yum check-update -q --enablerepo="ripple-${REPO}" xrpld +rpm_can_update() { + local pm=$1 + + rpm_refresh_metadata "$pm" + + local rc=0 + set +e + "$pm" check-update -q "$PKG_NAME" >/dev/null 2>&1 rc=$? - if [ $rc -eq 100 ]; then - can_update=true - elif [ $rc -ne 0 ]; then - echo "yum check-update failed with exit code $rc" + set -e + + if [[ $rc -eq 100 ]]; then + return 0 + elif [[ $rc -eq 0 ]]; then + return 1 + else + log "$pm check-update failed with exit code $rc" exit 1 fi +} - function apply_update { - yum update -y --enablerepo="ripple-${REPO}" xrpld - } -else - echo "No supported package manager found (apt-get or yum)" +rpm_apply_update() { + local pm=$1 + "$pm" update -y "$PKG_NAME" +} + +restart_service() { + systemctl restart "${PKG_NAME}.service" + log "${PKG_NAME} service restarted successfully" +} + +main() { + require_root + + if command -v apt-get >/dev/null 2>&1; then + log "Checking for ${PKG_NAME} updates via apt" + if apt_can_update; then + log "Update available; installing" + apt_apply_update + restart_service + log "${PKG_NAME} updated successfully" + else + log "No updates available" + fi + return + fi + + local rpm_pm="" + if rpm_pm="$(get_rpm_pm)"; then + log "Checking for ${PKG_NAME} updates via ${rpm_pm}" + if rpm_can_update "$rpm_pm"; then + log "Update available; installing" + rpm_apply_update "$rpm_pm" + restart_service + log "${PKG_NAME} updated successfully" + else + log "No updates available" + fi + return + fi + + log "No supported package manager found (apt-get, dnf, or yum)" exit 1 -fi +} -# Do the actual update and restart the service after reloading systemctl daemon. -if [ "$can_update" = true ] ; then - exec >>"${UPDATELOG}" 2>&1 - set -e - apply_update - systemctl daemon-reload - systemctl restart xrpld.service || { echo "$(date -u) xrpld daemon restart FAILED"; exit 1; } - echo "$(date -u) xrpld daemon updated." -else - echo "$(date -u) no updates available" >> "$UPDATELOG" -fi +main "$@" diff --git a/package/shared/update-xrpld.timer b/package/shared/update-xrpld.timer new file mode 100644 index 0000000000..d4fe36e64b --- /dev/null +++ b/package/shared/update-xrpld.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Daily xrpld update check + +[Timer] +OnCalendar=*-*-* 00:00:00 +RandomizedDelaySec=1h +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/package/shared/xrpld.logrotate b/package/shared/xrpld.logrotate index f27d493bc8..7818c1b44c 100644 --- a/package/shared/xrpld.logrotate +++ b/package/shared/xrpld.logrotate @@ -6,8 +6,7 @@ missingok notifempty compress - compresscmd /usr/bin/nice - compressoptions -n19 ionice -c3 gzip + compresscmd /usr/bin/gzip compressext .gz postrotate /opt/xrpld/bin/xrpld --conf /etc/opt/xrpld/xrpld.cfg logrotate diff --git a/package/shared/xrpld.service b/package/shared/xrpld.service index 64f236dd45..a785e05bf6 100644 --- a/package/shared/xrpld.service +++ b/package/shared/xrpld.service @@ -2,16 +2,17 @@ Description=XRP Ledger Daemon After=network-online.target Wants=network-online.target -StartLimitIntervalSec=60 -StartLimitBurst=3 +StartLimitIntervalSec=300 +StartLimitBurst=5 [Service] Type=simple ExecStart=/opt/xrpld/bin/xrpld --net --silent --conf /etc/opt/xrpld/xrpld.cfg -Restart=on-failure -RestartSec=5 +Restart=always +RestartSec=5s NoNewPrivileges=true ProtectSystem=full +ProtectHome=true PrivateTmp=true User=xrpld Group=xrpld