RunUpdates is a deterministic, operator‑grade update orchestrator that runs on Linux and manages updates for any platform whose lifecycle is defined in YAML.
The orchestrator itself is Linux‑based, but the hosts it manages may be Linux, Windows, macOS, OS/2, or any other system with a command model defined in the inventory schema.
RunUpdates emphasizes:
- reproducible execution
- strict validation
- audit‑transparent logging
- schema‑aligned configuration
- machine‑readable summaries
- predictable operator‑grade behavior
A fixed, cross‑platform pipeline:
check → parse → refresh → update? → clean → reboot?
The pipeline is not distro‑defined.
All hosts follow the same lifecycle, with commands supplied by the inventory.
The inventory schema defines:
- OS families (linux, windows, macos, etc.)
- distros (sub‑families)
- commands for each lifecycle step
- stdout/exit‑code semantics
- reboot detection
- host definitions
- secrets merging
- connection parameters
RunUpdates does not assume Linux hosts — it assumes schema‑validated commands.
- Local execution via sudo_run
- Remote execution via SSH (keyfile preferred, password fallback)
- Any platform is supported if its lifecycle is defined in YAML
RunUpdates includes a universal parser that detects:
- updates available
- updates performed
- no updates needed
- repo broken
- reboot required
This works across all distros and OS families.
- schema validation
- header audit mode
- fix‑headers‑only mode
- family/distro/host cross‑validation
- host family mismatch detection
- structured JSON logs
- redacted secrets
- timestamped lifecycle events
- deterministic formatting
- per‑host JSON summaries
- aggregated final summary
- classification fields
- reboot indicators
- repo health
All paths (config, schema, inventory, logs, summaries) follow:
- CLI override
- Environment variable
- Development‑mode defaults
- Installed‑mode defaults
- Frozen‑bundle defaults (.env auto‑generated)
RunUpdates depends on PythonTools. Both must be installed in the same environment.
git clone https://github.com/Linktech-Engineering-LLC/PythonTools.git
cd PythonTools
python3 -m venv .venv
source .venv/bin/activate
pip install -e .git clone https://github.com/Linktech-Engineering-LLC/RunUpdates.git
cd RunUpdates
pip install -r requirements.txtRunUpdates is now ready to use.
If modifying both repositories:
- keep both repos checked out
- install both in editable mode
- RunUpdates will immediately see changes in PythonTools
RunUpdates is a consumer of PythonTools, not a bundler.
The inventory is a structured YAML document defining:
- OS families
- distros
- commands
- lifecycle semantics
- exit‑code or stdout rules
- hosts
- connection parameters
Secrets are not stored in the inventory.
They live only in the vault file (vault.yml).
family → vars → distro → vars → hosts
Example:
linux:
vars:
port: 2239
opensuse:
vars:
systemd: true
systemd_mode: wait # or: async
lifecycle:
- refresh
- check
- update
- clean
- reboot
commands:
refresh: "zypper refresh"
check: "zypper patch-check --with-optional"
update: "zypper --non-interactive up --auto-agree-with-licenses --recommends --replacefiles --allow-vendor-change"
clean: "zypper clean"
reboot: "zypper needs-rebooting"
orphans: "zypper packages --orphaned"
list: "zypper list-updates --all"
reboot_now: "systemctl reboot || shutdown -r now"
exit_codes:
refresh:
success: [0]
error: ["*"]
check:
up_to_date: [0]
patches_available: [100, 101]
error: ["*"]
update:
success: [0]
reboot_required: [102, 104]
restart_services: [103]
error: ["*"]
reboot:
no_reboot: [0]
reboot_required: [102]
restart_services: [103]
reboot_and_restart: [104]
error: ["*"]
hosts:
suse-node-01:
enabled: true
address: ["192.0.2.10"]address is always a list, even for a single address.
This ensures:
- predictable iteration
- consistent normalization
- multi‑address failover
Secrets are stored only in an encrypted vault file (e.g., vault.yml).
The inventory contains no secrets.
RunUpdates uses CLI arguments and environment variables only to locate:
- the vault file
- the vault password file (or inline password)
Secrets themselves are never supplied directly via environment variables or CLI.
Vault path resolution:
--vault-pathRUNUPDATES_VAULT_PATH- (no default — missing value is a validation error)
Vault password resolution:
--vault-password-fileor--vault-passwordRUNUPDATES_VAULT_PASSWORD_FILE- (no default — missing value is a validation error)
After decrypting the vault, RunUpdates merges secrets into the normalized host objects in memory.
Secrets are:
- never logged
- never written to disk
- redacted in summaries
RunUpdates uses a subcommand‑driven CLI:
| Command | Description |
|---|---|
version |
Show version information |
help |
Show help for a subcommand (help update, help inventory, etc.) |
inventory |
Inspect inventory families, distros, hosts, and metadata |
update |
Run updates on selected hosts |
summary |
Show run summary information |
runupdates inventory [options]
Code --list-families --list-distros --list-hosts --list-inventory --show-metadata
Code --family --distro --host
runupdates update [options]
Code --family linux --distro --host
Code --force --mode sequential|parallel|distro-parallel
runupdates summary [options]
Code --latest --list --host
RunUpdates executes a deterministic lifecycle:
check → parse → refresh → update? → clean → reboot?
- check — run the distro‑defined check command
- parse — classify stdout/exit codes into universal update states
- refresh — refresh package metadata (only if updates are needed)
- update — apply updates (conditional)
- clean — always run; remove stale metadata and temp files
- reboot — detect whether a reboot is required
Each step records:
- exit code
- stdout/stderr
- classification
- timestamps
Failures do not stop the overall run.
Each host produces:
Code .json
Containing:
- lifecycle status
- update status
- repo health
- reboot requirement
- exit codes
- stdout/stderr (or redacted indicators)
- timestamps
summary.json includes:
- run start/end
- duration
- totals (completed, failed, skipped, repo_broken, reboot_required, etc.)
- per‑host status map
main.py
└── UpdateOrchestrator
├── ConfigResolver
├── PathResolver
├── SchemaLoader
├── RunUpdatesInventoryLoader
├── VaultLoader
├── HostSelector
├── HostConnector
│ ├── sudo_run (local)
│ └── SSHSession (remote)
├── HostExecutor
├── UniversalCheckParser
├── RebootWaiter
└── SummaryAggregator
- ConfigResolver → resolves CLI/env/default paths
- SchemaLoader → loads and validates schema
- RunUpdatesInventoryLoader → loads, merges, normalizes inventory
- VaultLoader → locates, decrypts, and merges vault secrets
- HostSelector → applies CLI filters
- HostConnector → local vs remote execution
- HostExecutor → runs deterministic lifecycle
- UniversalCheckParser → stdout/exit‑code classification
- SummaryAggregator → builds final summary
RunUpdates uses a unified classification model:
- success
- warning
- error
- fatal
Mapped from:
- exit codes
- stdout patterns
- SSH failures
- PythonTools exceptions
- repo health indicators
- no dynamic code execution
- no YAML‑driven logic paths
- secrets only in vault.yml
- secrets never logged or written to disk
- SSH keyfile preferred
- deterministic logging
- strict schema validation
Planned enhancements:
- expanded OS family/distro examples
- richer structured check parsing
- improved reboot classification
- inventory diffing
- dashboard‑ready summary format
Pull requests are welcome.
Please ensure:
- deterministic behavior
- no breaking schema changes
- placeholder‑only examples
- documentation updates for new features
MIT License — see LICENSE for details.