Skip to content

tashikomaaa/palpatine

Repository files navigation

PALPATINE — Galactic Server Control

Version: v1 (core-only)

License: GPL v3

Palapatine is an open-source project built and maintained by Moutarlier Aldwin aka (tashikomaaa or corvus).
Licensed under the GNU General Public License v3.0.

Palpatine is a terminal-based fleet manager written in Bash. It provides a small, auditable, and extensible tool to run commands and manage services across many servers via SSH.

Design goals: simple, auditable, minimal dependencies (ssh, coreutils), friendly for ops engineers and open-source collaboration.


Table of contents


What is Palpatine?

Palpatine is a terminal-based fleet manager written in Bash. It provides:

  • a TUI-like main menu for common fleet tasks (scan, run command, reboot, shutdown);
  • a focus mode to control a single server interactively (run commands, SSH, reboot/shutdown);
  • robust SSH handling: non-interactive first (good for automation), and optional interactive retry when a host requires a password;
  • optional JSON scan output for integration with other tools;
  • simple configuration via /etc/palpatine.conf, ~/.palpatine.conf, or ./.palpatine.conf;
  • minimal i18n support (UI_LANG=fr|en).

Palpatine intentionally keeps dependencies tiny so it runs on most Linux and macOS hosts with ssh installed.


Installation

Clone the repository and make the main script executable:

git clone https://github.com/tashikomaaa/palpatine.git palpatine
cd palpatine
chmod +x palpatine

Optional — install Palpatine system-wide so palpatine is on your PATH:

sudo ./install.sh --prefix /usr/local

Create your server list files in the repository root. By default Palpatine uses servers.txt. You can also use servers-<group>.txt and set GROUP in config.

Example servers-prod.txt:

root@192.168.1.10
admin@192.168.1.11
web-01.example.com

Project layout

palpatine/                # repo root
├── palpatine             # main launcher (executable)
└── lib/
    ├── core.sh          # core helpers, SSH wrapper, server loading
    ├── ui.sh            # UI + i18n helpers
    ├── actions.sh       # status/scan, run, reboot, shutdown
    ├── focus.sh         # focus mode & server selection helpers
    ├── plugins.sh       # plugin registry + loader
    └── plugins/         # optional plugins (auto-loaded)
~/.palpatine.conf        # optional per-user config (not in repo)

All code is pure Bash and intended to be easy to inspect and modify.


Quick start

  1. Create or edit ~/.palpatine.conf (see configuration section below).
  2. Create your servers.txt or servers-<group>.txt.
  3. Run:
./palpatine

Use the TUI menu to scan your fleet, run commands, or focus on an individual server.

You can also run non-interactive actions from CLI:

./palpatine --group prod --action status
./palpatine --action run --cmd "df -h"
./palpatine --focus "root@web-01"
./palpatine --action reboot --dry-run

Configuration

Palpatine reads these config files (in order), where later files override earlier ones:

  1. /etc/palpatine.conf
  2. ~/.palpatine.conf
  3. ./.palpatine.conf (project-local)

A sample ~/.palpatine.conf:

# ~/.palpatine.conf
GROUP="prod"
SSH_USER="root"
MAX_JOBS=8
SSH_TIMEOUT=5
UI_LANG="en"               # supports en, fr, de, es, pt, it, ru, uk, pl, ja, ko, zh
DRY_RUN=false

# Scan output options
SCAN_OUTPUT_JSON=true
SCAN_OUTPUT_DIR="$HOME/palpatine_scans"   # optional
SCAN_OUTPUT_FILE=""                       # optional (overrides DIR)

# Playbook / automation helpers
SCAN_INTERACTIVE_RETRY=true
# DISABLE_UPDATE_CHECK=true            # uncomment to opt-out of git update checks
# UPDATE_CHECK_INTERVAL=86400          # seconds between update checks
# UPDATE_REMOTE=origin
# UPDATE_BRANCH=main

Key variables explained

  • GROUP — default group name (uses servers-<GROUP>.txt if present).
  • SSH_USER — default SSH username used for bare hostnames.
  • MAX_JOBS — maximum parallel SSH jobs (concurrency).
  • SSH_TIMEOUT — seconds for ConnectTimeout in SSH options.
  • UI_LANG — UI language: en, fr, de, es, pt, it, ru, uk, pl, ja, ko, zh (aliases such as pt-br or zh-cn are also accepted).
  • DRY_RUN — if true, no SSH commands will be executed (useful for testing).
  • SCAN_OUTPUT_JSONtrue / false; controls whether action_status writes JSON file.
  • SCAN_OUTPUT_DIR — directory to write scan files (if not set, defaults to ./logs/scans).
  • SCAN_OUTPUT_FILE — exact file path for scan output (if set, overrides SCAN_OUTPUT_DIR).
  • SCAN_REPORTtrue / false; enables the Markdown scan report under logs/reports/.
  • SCAN_REPORT_DIR / SCAN_REPORT_FILE — override the default report destination.
  • SCAN_INTERACTIVE_RETRY — if true and TTY present, when a host reports auth failure during scan, the user is prompted to retry interactively for that host.
  • DISABLE_UPDATE_CHECK — set to true to skip the automatic git update prompt (defaults to false).
  • UPDATE_CHECK_INTERVAL — seconds between update checks (default 86400).
  • UPDATE_REMOTE / UPDATE_BRANCH — git remote/branch used to check for updates (defaults origin / main).

Usage — CLI & Interactive

CLI mode (non-interactive)

Examples:

# show status (ping + attempt uptime)
./palpatine --group prod --action status

# run a command across the fleet
./palpatine --action run --cmd "df -h"

# reboot all servers (use --dry-run to test)
./palpatine --action reboot --dry-run

# open focus on server #2 from servers.txt
./palpatine --focus 2

# add or remove entries from the active servers list
./palpatine --group prod --add-server "admin@web-04"
./palpatine --remove-server "legacy-host"

Interactive menu

Launch ./palpatine without args. The main menu offers:

  • Scan systems (ping + uptime)
  • Execute an order (enter a command to run in parallel)
  • Reboot the fleet
  • Shutdown the fleet
  • Focus on a server for per-host actions
  • Open the plugin bay (if plugins are installed)
  • Add or remove entries from the active servers list (removal accepts either the hostname or its menu number)

Focus mode

Choose a server and you'll have options:

  • uptime (runs uptime -p)
  • run a custom command
  • reboot / shutdown
  • open an interactive SSH shell

Plugins

Drop Bash scripts into lib/plugins/ and call register_plugin "id" "Label" handler_fn. Palpatine loads them automatically at startup and surfaces them under the Plugins menu item. Each plugin receives access to the shared helpers (run_ssh_cmd, draw_header, translations via L, etc.), so you can build custom workflows without touching the core menu.

The repository ships with two examples:

  • backup.sh — run fleet-wide tar backups of /etc or /var/www.
  • monitoring.sh — stream uptime, disk, and memory stats across the fleet.

Document your plugin labels with L 'plugin.<name>.label' if you want multilingual support.

Playbooks

Playbooks chain multiple fleet actions without manual prompts. Create a plain-text file (for example playbooks/sample.playbook) with one directive per line:

# comments are ignored
note: Starting nightly scan
scan
run: df -h
sleep: 5
note: Finished

Supported directives:

  • scan — run the fleet scan workflow.
  • run: <command> — execute a command across all servers (the playbook fails if any host reports an error or is unreachable).
  • reboot / shutdown — trigger fleet reboots or shutdowns without interactive confirmation (pair with DRY_RUN=true for rehearsals).
  • sleep: <seconds> — wait between steps.
  • note: <message> — log a message via the standard empire helper.

Execute with ./palpatine --playbook path/to/file. Playbooks are mutually exclusive with --action, --focus, or server list edits so you can run them unattended.

Automatic updates

When Palpatine is run from a git checkout it periodically checks the configured remote/branch (default origin/main) for new commits. If a newer revision is found, it offers to pull the update (git pull --ff-only). Set DISABLE_UPDATE_CHECK=true to skip this behaviour or adjust UPDATE_CHECK_INTERVAL for more/less frequent checks.


Scan JSON output format

When SCAN_OUTPUT_JSON=true, scans are written to a file named:

  • ${SCAN_OUTPUT_FILE} (if set), otherwise
  • ${SCAN_OUTPUT_DIR}/scan-YYYYMMDD_HHMMSS.json (where the default SCAN_OUTPUT_DIR is ./logs/scans).

Output is a single JSON array — each element is an object per host:

[
  {
    "host": "root@192.168.1.10",
    "ping": "ok",
    "ssh": "ok",
    "ssh_output": "up 2 days,  3:05",
    "ssh_exit_code": 0,
    "scanned_at": "2025-10-08T15:30:00Z"
  }
]

Field meanings:

  • host: the host string used (user@host or host).
  • ping: "ok" or "failed".
  • ssh: one of "ok", "auth_failed", "failed", "failed_no_output", "not_attempted", or "skipped".
  • ssh_output: captured stdout/stderr from uptime -p (truncated if long).
  • ssh_exit_code: numeric exit status reported by the SSH command (null if the command was skipped).
  • scanned_at: ISO-8601 timestamp of the scan for that host.

You can easily pipe the file into jq for queries:

jq '.[] | {host, ping, ssh}' logs/scans/scan-20251008_153000.json

When SCAN_REPORT=true, Palpatine also writes a Markdown report alongside the JSON output (default ./logs/reports/). The report contains a table summarising ping/SSH results per host and a final counter recap, making it easy to share scan results with teammates.


Security & best practices

  • Prefer SSH keys (ed25519 or RSA). Use ssh-keygen and ssh-copy-id to install your public key on servers.
  • DRY_RUN=true is useful to test the script without making changes.
  • Palpatine uses ssh -o BatchMode=yes by default for non-interactive actions — this avoids blocking when running in automation/cron.
  • If SCAN_INTERACTIVE_RETRY=true, Palpatine may prompt for passwords interactively only if run in a TTY — it will never store passwords.
  • File permissions: keep ~/.ssh permissions strict (700 for .ssh, 600 for authorized_keys).
  • Avoid running Palpatine as root on your workstation — prefer a normal user with SSH keys.

Troubleshooting (common issues)

Permission denied (publickey,password)

  • You attempted SSH without a key available on server.

  • Quick checks:

    • ssh -vvv user@host — inspect auth methods attempted.
    • Ensure ~/.ssh/id_ed25519 (or id_rsa) exists.
    • Use ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host.

Script exits during scan (happens after first ping)

  • This is usually set -e behavior interacting with failing commands.
  • Palpatine wraps scan loops with set +e / set -e to avoid that; if you modified files and see early exit, ensure those guards exist.
  • Run bash -n lib/actions.sh (and other lib files) to syntax-check script files.

syntax error: unexpected end of file

  • Often caused by:

    • a truncated file (transfer interrupted),
    • missing fi, done, or } in a function,
    • CRLF (Windows) line endings.
  • Fixes:

    • Ensure the file is complete — wc -l lib/actions.sh.
    • Convert line endings: dos2unix lib/actions.sh or sed -i 's/\r$//' lib/actions.sh.
    • Run bash -n lib/actions.sh to pinpoint syntax errors.

local: can only be used in a function

  • local must appear only inside functions. Check you haven't used local at top-level.

Contributing

Palpatine aims to be simple and auditable. If you want to contribute:

  1. Fork the repo.
  2. Add a clear commit message and provide tests or manual test steps (run ./tests/run.sh).
  3. Open a PR with explanation and rationale.

Suggested improvements:

  • additional built-in plugins (backups, observability, remediation)
  • alternate visual themes (light mode, high contrast)
  • optional output formats: CSV, JSONL, Prometheus metrics
  • richer interactive UI (fzf integration or dialog)

Testing

Automated checks live in tests/. Run everything locally with:

./tests/run.sh

The script exercises the plugin registry/loader and ensures bundled plugins register correctly. Pair it with bash -n lib/*.sh lib/plugins/*.sh for quick syntax validation.


Development notes (for maintainers)

  • All code is intentionally plain Bash (POSIX-ish with Bashisms).
  • Keep comments and variable names English for wide collaboration.
  • Use bash -n for syntax checks and shellcheck when possible.
  • Keep set -euo pipefail at top-level but wrap tolerant sections with set +e / set -e.

Example ~/.palpatine.conf (copy/paste)

# ~/.palpatine.conf - Palpatine configuration
GROUP="prod"
SSH_USER="deploy"
MAX_JOBS=8
SSH_TIMEOUT=5
UI_LANG="en"
DRY_RUN=false

SCAN_OUTPUT_JSON=true
SCAN_OUTPUT_DIR="$HOME/palpatine_scans"
SCAN_OUTPUT_FILE=""
SCAN_INTERACTIVE_RETRY=true

About

Palpatine is a Bash-based fleet command tool for SSH-managed hosts. Scan systems, run scripted orders, log results (JSON/Markdown), and manage server lists from an interactive TUI—with multilingual UI support and plugin-friendly design.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages