diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 2d563e0..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,65 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - ---- - -## [0.4.0] - 2026-03-18 - -### Added - -* Structured logging system with timestamps -* Log levels: INFO, OK, ERR -* Central log file: `/opt/update-manager/log/update-manager.log` -* Log submenu in UI -* Log viewing options: - - * Full log - * Live log (tail -f) - * Last 20 lines - * Log file location - -### Changed - -* Refactored UI to group log features into submenu -* Improved menu structure and usability - -### Improved - -* Better error visibility for SSH failures -* Consistent output across hosts -* README updated with UI screenshots and logging documentation - ---- - -## [0.3.0] - 2026-03-18 - -### Added - -* CLI menu (`update-manager-ui.sh`) -* Interactive host management -* Dialog-based UI navigation - -### Changed - -* Project renamed from `lanx-update` to `update-manager` -* Moved runtime files to `/opt/update-manager` - ---- - -## [0.2.0] - 2026-03-18 - -### Added - -* SSH-based update checking across multiple hosts -* Support for `hosts.conf` -* Config file support (`/etc/update-manager.conf`) - ---- - -## [0.1.0] - 2026-03-17 - -### Added - -* Initial version -* Basic apt update check functionality diff --git a/README.md b/README.md index dc3900b..36fcbfb 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,4 @@ -

- -

- +# 🖥️ Update Manager Simple CLI tool to check and manage updates across multiple Ubuntu systems over SSH. @@ -29,10 +26,10 @@ Built for Lanx environments – lightweight, fast and no unnecessary dependencie ## Features * Check updates on multiple hosts -* Run updates remotely over SSH -* Interactive CLI menu (dialog-based UI) -* Centralized logging +* Run checks remotely over SSH * Simple config files +* Built-in logging (file + terminal) +* Dialog-based UI menu * No agents required * Works with existing SSH setup @@ -40,20 +37,12 @@ Built for Lanx environments – lightweight, fast and no unnecessary dependencie ## Update Manager UI -### Main menu -

- Main menu -

- -### Log menu - -

- Log menu + Update Manager CLI UI

- Lightweight • No dependencies • Works over SSH + Lightweight • Terminal-based • Works over SSH

--- @@ -68,7 +57,7 @@ sudo apt update sudo apt install dialog openssh-client sudo mkdir -p /opt/update-manager -sudo cp update-manager.sh update-manager-ui.sh dialogrc /opt/update-manager/ +sudo cp update-manager.sh update-manager-ui.sh /opt/update-manager/ sudo chmod +x /opt/update-manager/update-manager.sh sudo chmod +x /opt/update-manager/update-manager-ui.sh @@ -145,12 +134,6 @@ server3 192.168.1.30 user ## Usage -### Check updates - -```bash -update-manager check -``` - ### Start UI ```bash @@ -159,25 +142,42 @@ update-manager-ui --- +### Check updates (CLI) + +```bash +update-manager check +``` + +--- + ## Logging -Log file location: +The tool logs both to terminal and file. + +### Primary location ```bash /opt/update-manager/log/update-manager.log ``` -View log: +### Fallback location ```bash -less /opt/update-manager/log/update-manager.log +~/update-manager/log/update-manager.log ``` -Follow log: +### Notes -```bash -tail -f /opt/update-manager/log/update-manager.log -``` +* Log directory is created automatically +* Log file is created automatically +* Output is written to both terminal and file +* Log levels: + + * INFO + * WARN + * ERROR + +Logs can be viewed directly from the UI. --- @@ -189,8 +189,8 @@ tail -f /opt/update-manager/log/update-manager.log ├── update-manager-ui.sh ├── update-manager.conf ├── hosts.conf -├── log/ -│ └── update-manager.log +└── log/ + └── update-manager.log ``` --- @@ -199,7 +199,6 @@ tail -f /opt/update-manager/log/update-manager.log * Uses SSH to connect to each host * Runs `apt` commands remotely -* Logs results locally * No agents or services needed * Designed for simple and efficient operations @@ -210,6 +209,7 @@ tail -f /opt/update-manager/log/update-manager.log * SSH access to all hosts * SSH keys recommended (no password prompts) * Ubuntu/Debian-based systems +* `dialog` (for UI) --- @@ -218,6 +218,7 @@ tail -f /opt/update-manager/log/update-manager.log * 🔔 Notifications (ntfy / push alerts) * 🌐 Web interface * 📧 Email reporting +* 📜 Advanced logging / audit trail * 📊 Basic monitoring (status, last check, pending updates) * 🧩 Plugin system (extensible modules) * 🔐 Security & compliance checks @@ -225,15 +226,6 @@ tail -f /opt/update-manager/log/update-manager.log --- -## ❤️ Credits - -Built with ❤️ for Lanx by [NodeFox 🦊](https://nodefox.lanx.dk) -Maintained by [Eddie Nielsen](https://lanx.dk) - -> Learn. Adopt. Survive. Share. - ---- - ## License This project is licensed under the GNU GPL v3 License. @@ -241,3 +233,10 @@ This project is licensed under the GNU GPL v3 License. See the LICENSE file for full details. --- + +## Author + +Built with ❤️ for [Lanx](https://lanx.dk) by **NodeFox** 🦊 + +Maintained by Eddie Nielsen +Feel free to contribute, suggest improvements or fork the project. diff --git a/dialogrc b/dialogrc deleted file mode 100644 index 250e64a..0000000 --- a/dialogrc +++ /dev/null @@ -1,32 +0,0 @@ -use_shadow = OFF -use_colors = ON - -screen_color = (WHITE,BLUE,OFF) -dialog_color = (WHITE,BLUE,OFF) -title_color = (YELLOW,BLUE,ON) -border_color = (WHITE,BLUE,OFF) - -button_active_color = (BLACK,WHITE,ON) -button_inactive_color = (WHITE,BLUE,OFF) - -button_key_active_color = (BLACK,WHITE,ON) -button_key_inactive_color = (WHITE,BLUE,OFF) - -button_label_active_color = (BLACK,WHITE,ON) -button_label_inactive_color = (WHITE,BLUE,OFF) - -menubox_color = (WHITE,BLUE,OFF) -menubox_border_color = (WHITE,BLUE,OFF) - -item_color = (WHITE,BLUE,OFF) -item_selected_color = (BLACK,WHITE,ON) - -tag_color = (WHITE,BLUE,OFF) -tag_selected_color = (BLACK,WHITE,ON) - -tag_key_color = (YELLOW,BLUE,OFF) -tag_key_selected_color = (BLACK,WHITE,ON) - -position_indicator_color = (WHITE,BLUE,OFF) -uarrow_color = (WHITE,BLUE,OFF) -darrow_color = (WHITE,BLUE,OFF) diff --git a/docs/architecture.md b/docs/architecture.md deleted file mode 100644 index 3c9771c..0000000 --- a/docs/architecture.md +++ /dev/null @@ -1,211 +0,0 @@ -

- Architecture Diagram -

- -# 🧠 Update Manager Architecture - -This document describes how Update Manager is structured internally and how data flows through the system. - ---- - -## Overview - -Update Manager is a lightweight, SSH-based system for managing updates across multiple Linux hosts. - -It consists of two main layers: - -* **UI layer** – interactive menu (`update-manager-ui.sh`) -* **Core engine** – update logic (`update-manager.sh`) - -The system is designed to be simple, transparent, and dependency-light. - ---- - -## High-Level Flow - -```text -User - ↓ -UI (update-manager-ui.sh) - ↓ -Core (update-manager.sh) - ↓ -SSH → Remote Hosts - ↓ -Results - ↓ -Logging (/opt/update-manager/log) - ↓ -UI / User -``` - ---- - -## Components - -### UI Layer (`update-manager-ui.sh`) - -Responsible for: - -* Displaying menu (via `dialog`) -* Handling user input -* Managing hosts (add/remove/edit) -* Providing access to logs -* Delegating actions to core engine - -The UI does **not perform updates directly**. - ---- - -### Core Engine (`update-manager.sh`) - -Responsible for: - -* Reading configuration -* Parsing hosts file -* Executing SSH commands -* Checking for updates (`apt list --upgradable`) -* Handling connection errors -* Writing structured logs - -This is the **execution layer** of the system. - ---- - -### Hosts Configuration - -File: - -```bash -/opt/update-manager/hosts.conf -``` - -Format: - -```text -name ip user -``` - -Example: - -```text -server1 192.168.1.10 user -server2 192.168.1.20 user -server3 192.168.1.30 user -``` - -Each line represents a target system accessed via SSH. - ---- - -### Logging System - -Log file: - -```bash -/opt/update-manager/log/update-manager.log -``` - -Log format: - -```text -YYYY-MM-DD HH:MM:SS [LEVEL] host - message -``` - -Example: - -```text -2026-03-18 20:45:01 [INFO] lanx-www - Checking updates -2026-03-18 20:45:03 [OK] lanx-www - 3 updates available -2026-03-18 20:45:05 [ERR] lanx-db - Connection failed -``` - -#### Log Levels - -* `INFO` – informational messages -* `OK` – successful operations -* `ERR` – errors or failures - -Logging is centralized and written locally. - ---- - -## Execution Flow - -For each host: - -1. Read host entry from `hosts.conf` -2. Establish SSH connection -3. Execute: - -```bash -apt list --upgradable -``` - -4. Parse output -5. Determine: - - * Up-to-date - * Updates available - * Connection failure -6. Write result to: - - * terminal output - * log file - ---- - -## Configuration - -Primary config: - -```bash -/etc/update-manager.conf -``` - -Fallback: - -```bash -./update-manager.conf -``` - -Supported options: - -* `HOSTS_FILE` -* `SSH_OPTIONS` - ---- - -## Design Principles - -* **No agents** – uses standard SSH only -* **Simple over complex** – minimal dependencies -* **Transparent behavior** – everything is visible/logged -* **CLI-first** – designed for terminal environments -* **Modular growth** – prepared for future extensions - ---- - -## Future Architecture Direction - -Planned extensions: - -* Plugin system (modular features) -* Web interface (optional UI layer) -* Notification system (alerts) -* Metrics / monitoring -* Integration with Lanx AI - ---- - -## Summary - -Update Manager follows a clean separation: - -* UI = interaction -* Core = execution -* Config = data -* Log = output - -This keeps the system predictable, debuggable, and easy to extend. - diff --git a/docs/images/architecture-diagram.png b/docs/images/architecture-diagram.png deleted file mode 100644 index d2b79f2..0000000 Binary files a/docs/images/architecture-diagram.png and /dev/null differ diff --git a/docs/images/menu-logs.png b/docs/images/menu-logs.png deleted file mode 100644 index 1bffefe..0000000 Binary files a/docs/images/menu-logs.png and /dev/null differ diff --git a/docs/images/menu-main.png b/docs/images/menu-main.png deleted file mode 100644 index 80e1e80..0000000 Binary files a/docs/images/menu-main.png and /dev/null differ diff --git a/docs/images/update-manager-ui.png b/docs/images/update-manager-ui.png deleted file mode 100644 index a9dd924..0000000 Binary files a/docs/images/update-manager-ui.png and /dev/null differ diff --git a/images/updatemanager-logo.png b/images/updatemanager-logo.png deleted file mode 100644 index bd5a27a..0000000 Binary files a/images/updatemanager-logo.png and /dev/null differ diff --git a/log/update-manager.sh b/log/update-manager.sh deleted file mode 100644 index d3e9635..0000000 --- a/log/update-manager.sh +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env bash - -UPDATE_MANAGER_SCRIPT="/opt/update-manager/update-manager.sh" - -get_log_file() { - local primary="/opt/update-manager/log/update-manager.log" - local fallback="$HOME/update-manager/log/update-manager.log" - - if [[ -f "$primary" ]]; then - echo "$primary" - else - echo "$fallback" - fi -} - -run_check() { - echo - bash "$UPDATE_MANAGER_SCRIPT" check - echo - read -rp "Press Enter to continue..." -} - -view_log() { - local log_file - log_file="$(get_log_file)" - - echo - if [[ -f "$log_file" ]]; then - less "$log_file" - else - echo "Log file not found: $log_file" - echo - read -rp "Press Enter to continue..." - fi -} - -follow_log() { - local log_file - log_file="$(get_log_file)" - - echo - if [[ -f "$log_file" ]]; then - echo "Following log: $log_file" - echo "Press Ctrl+C to stop." - echo - tail -f "$log_file" - else - echo "Log file not found: $log_file" - fi - - echo - read -rp "Press Enter to continue..." -} - -show_log_location() { - local log_file - log_file="$(get_log_file)" - - echo - echo "Log file location:" - echo "$log_file" - echo - read -rp "Press Enter to continue..." -} - -show_menu() { - clear - echo "==================================" - echo " Update Manager UI" - echo "==================================" - echo - echo "1) Run update check" - echo "2) View full log" - echo "3) Follow log live" - echo "4) Show log location" - echo "0) Exit" - echo -} - -main() { - if [[ ! -f "$UPDATE_MANAGER_SCRIPT" ]]; then - echo "Update manager script not found: $UPDATE_MANAGER_SCRIPT" - exit 1 - fi - - while true; do - show_menu - read -rp "Choose an option: " choice - - case "$choice" in - 1) - run_check - ;; - 2) - view_log - ;; - 3) - follow_log - ;; - 4) - show_log_location - ;; - 0) - echo - echo "Bye." - exit 0 - ;; - *) - echo - echo "Invalid choice." - read -rp "Press Enter to continue..." - ;; - esac - done -} - -main diff --git a/update-manager-ui.png b/update-manager-ui.png new file mode 100644 index 0000000..33929c8 Binary files /dev/null and b/update-manager-ui.png differ diff --git a/update-manager-ui.sh b/update-manager-ui.sh deleted file mode 100755 index af17391..0000000 --- a/update-manager-ui.sh +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/env bash - -export DIALOGRC="/opt/update-manager/dialogrc" - -UPDATE_MANAGER_SCRIPT="$HOME/update-manager/update-manager.sh" -HOSTS_FILE="/opt/update-manager/hosts.conf" - -get_log_file() { - local primary="/opt/update-manager/log/update-manager.log" - local fallback="$HOME/update-manager/log/update-manager.log" - - if [[ -f "$primary" ]]; then - echo "$primary" - elif [[ -f "$fallback" ]]; then - echo "$fallback" - else - echo "" - fi -} - -show_log_menu() { - while true; do - log_choice=$(dialog --clear \ - --backtitle "Update Manager" \ - --title "Log menu" \ - --menu "Select log action:" 18 60 10 \ - 1 "View full log" \ - 2 "Follow log live" \ - 3 "Show log location" \ - 4 "Show last 20 log lines" \ - 0 "Back" \ - 3>&1 1>&2 2>&3) - - clear - - case "$log_choice" in - 1) - log_file="$(get_log_file)" - if [[ -n "$log_file" ]]; then - less "$log_file" - else - echo "No log file found yet." - read -rp "Press Enter to continue..." - fi - ;; - 2) - log_file="$(get_log_file)" - if [[ -n "$log_file" ]]; then - echo "Press Ctrl+C to stop" - tail -n 20 -f "$log_file" - else - echo "No log file found yet." - fi - read -rp "Press Enter to continue..." - ;; - 3) - log_file="$(get_log_file)" - if [[ -n "$log_file" ]]; then - echo "Log file:" - echo "$log_file" - else - echo "No log file found yet." - fi - read -rp "Press Enter to continue..." - ;; - 4) - log_file="$(get_log_file)" - if [[ -n "$log_file" ]]; then - tail -n 20 "$log_file" - else - echo "No log file found yet." - fi - read -rp "Press Enter to continue..." - ;; - 0|"") - break - ;; - esac - done -} - -while true; do - choice=$(dialog --clear \ - --backtitle "Update Manager" \ - --title "Choose an action" \ - --menu "Select option:" 20 60 10 \ - 1 "Check all hosts" \ - 2 "View hosts file" \ - 3 "Edit hosts file" \ - 4 "Add host" \ - 5 "Remove host" \ - 6 "Log menu" \ - 0 "Exit" \ - 3>&1 1>&2 2>&3) - - clear - - case "$choice" in - 1) - bash "$UPDATE_MANAGER_SCRIPT" check - read -rp "Press Enter to continue..." - ;; - 2) - less "$HOSTS_FILE" - ;; - 3) - nano "$HOSTS_FILE" - ;; - 4) - read -rp "Name: " name - read -rp "IP: " ip - read -rp "User: " user - if [[ -z "$name" || -z "$ip" || -z "$user" ]]; then - echo "All fields are required." - else - echo "$name $ip $user" >> "$HOSTS_FILE" - echo "Host added." - fi - read -rp "Press Enter to continue..." - ;; - 5) - nl -w2 -s'. ' "$HOSTS_FILE" - read -rp "Line to remove: " line - if [[ "$line" =~ ^[0-9]+$ ]]; then - sed -i "${line}d" "$HOSTS_FILE" - echo "Host removed." - else - echo "Invalid line number." - fi - read -rp "Press Enter to continue..." - ;; - 6) - show_log_menu - ;; - 0|"") - clear - exit 0 - ;; - esac -done diff --git a/update-manager.sh b/update-manager.sh index 679fea0..89b5ef9 100755 --- a/update-manager.sh +++ b/update-manager.sh @@ -1,79 +1,127 @@ #!/usr/bin/env bash -UPDATE_MANAGER_SCRIPT="$HOME/update-manager/update-manager.sh" -HOSTS_FILE="/opt/update-manager/hosts.conf" +CONFIG_FILE="/etc/update-manager.conf" +[[ -f "$CONFIG_FILE" ]] || CONFIG_FILE="./update-manager.conf" -get_log_file() { - local primary="/opt/update-manager/log/update-manager.log" - local fallback="$HOME/update-manager/log/update-manager.log" +if [[ -f "$CONFIG_FILE" ]]; then + # shellcheck disable=SC1090 + source "$CONFIG_FILE" +fi - if [[ -f "$primary" ]]; then - echo "$primary" - else - echo "$fallback" +DEFAULT_HOSTS_FILE="${HOSTS_FILE:-/opt/update-manager/hosts.conf}" +SSH_OPTIONS="${SSH_OPTIONS:--o BatchMode=yes -o ConnectTimeout=5}" + +######################################## +# Ensure hosts file exists +######################################## + +ensure_hosts_file() { + if [[ ! -f "$DEFAULT_HOSTS_FILE" ]]; then + echo "Creating example hosts file: $DEFAULT_HOSTS_FILE" + + mkdir -p "$(dirname "$DEFAULT_HOSTS_FILE")" + + cat > "$DEFAULT_HOSTS_FILE" <<'EOF' +# Example hosts file +# Format: +# name ip user +# +# server1 192.168.1.10 user +# server2 192.168.1.20 user +# server3 10.0.0.5 root +EOF fi } -while true; do - choice=$(dialog --clear \ - --backtitle "Update Manager" \ - --title "Choose an action" \ - --menu "Select option:" 15 50 10 \ - 1 "Check all hosts" \ - 2 "View hosts file" \ - 3 "Edit hosts file" \ - 4 "Add host" \ - 5 "Remove host" \ - 6 "View log" \ - 7 "Follow log live" \ - 8 "Show log location" \ - 0 "Exit" \ - 3>&1 1>&2 2>&3) +######################################## +# Helpers +######################################## - clear +get_hosts_file() { + if [[ -n "$2" ]]; then + echo "$2" + else + echo "$DEFAULT_HOSTS_FILE" + fi +} - case $choice in - 1) - bash "$UPDATE_MANAGER_SCRIPT" check - read -rp "Press Enter to continue..." - ;; - 2) - less "$HOSTS_FILE" - ;; - 3) - nano "$HOSTS_FILE" - ;; - 4) - read -rp "Name: " name - read -rp "IP: " ip - read -rp "User: " user - echo "$name $ip $user" >> "$HOSTS_FILE" - echo "Host added." - read -rp "Press Enter to continue..." - ;; - 5) - nl -w2 -s'. ' "$HOSTS_FILE" - read -rp "Line to remove: " line - sed -i "${line}d" "$HOSTS_FILE" - echo "Host removed." - read -rp "Press Enter to continue..." - ;; - 6) - less "$(get_log_file)" - ;; - 7) - echo "Press Ctrl+C to stop" - tail -f "$(get_log_file)" - read -rp "Press Enter to continue..." - ;; - 8) - echo "Log file:" - echo "$(get_log_file)" - read -rp "Press Enter to continue..." - ;; - 0) - clear - exit 0 - ;; - esac -done +usage() { + cat </dev/null | sed '/^Listing/d'" 2>&1) + rc=$? + + printf "===== %s (%s) =====\n" "$name" "$ip" + + if [[ $rc -ne 0 ]]; then + echo "❌ connection failed" + echo "$result" + echo + return + fi + + if [[ -z "$result" ]]; then + echo "Up-to-date" + else + echo "$result" + fi + + echo +} + +######################################## +# Check all hosts +######################################## + +check_all() { + local hosts_file="$1" + + ensure_hosts_file + + while IFS= read -r line; do + [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue + + local name ip user + read -r name ip user <<< "$line" + + [[ -z "$name" || -z "$ip" || -z "$user" ]] && continue + + check_host "$name" "$ip" "$user" + done < "$hosts_file" +} + +######################################## +# Main +######################################## + +case "${1:-}" in + check) + HOSTS_FILE_TO_USE="$(get_hosts_file "$@")" + check_all "$HOSTS_FILE_TO_USE" + ;; + *) + usage + exit 1 + ;; +esac