From eb83c4ccbdfb93a2b5fd038b6f0dc8181aeb18a8 Mon Sep 17 00:00:00 2001 From: "Bastian (BaM)" Date: Sun, 14 Sep 2025 18:27:39 +0200 Subject: [PATCH] Add desktop session detection to auto-boot-ollama-host script Implement a new module for checking if the user is logged into a Windows desktop session. The script now skips Ollama startup and shutdown if the user is currently logged in, preventing interruptions. Update README to reflect new features and module structure. --- scripts/README.md | 31 +++++++++++++++- scripts/auto-boot-ollama-host.lua | 23 ++++++++++++ scripts/session_check.lua | 45 +++++++++++++++++++++++ scripts/ssh.lua | 60 +++++++++++++++++++++++++++++++ 4 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 scripts/session_check.lua diff --git a/scripts/README.md b/scripts/README.md index 296dda8..8195b03 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -5,13 +5,16 @@ This directory contains the refactored version of the auto-boot-ollama-host scri ## File Structure ### Main Script + - `auto-boot-ollama-host.lua` - Original monolithic script - `auto-boot-ollama-host-refactored.lua` - New modular main script ### Modules #### `config.lua` + Handles all environment variable configuration with sensible defaults: + - Docker configuration (container name, since time) - Ollama service configuration (host, port) - SSH configuration (port, user, identity file) @@ -19,24 +22,39 @@ Handles all environment variable configuration with sensible defaults: - Wake-on-LAN configuration #### `utils.lua` + Provides utility functions: + - `log(msg)` - Timestamped logging - `getenv(name, def)` - Environment variable with default #### `network.lua` + Network-related functionality: + - `port_is_up(host, port, timeout)` - Check if TCP port is accessible - `send_wol(mac, bcast_ip, port)` - Send Wake-on-LAN magic packet #### `ssh.lua` + SSH command execution: + - `execute(command, user, host, port, identity_file)` - Execute remote SSH command +- `execute_with_output(command, user, host, port, identity_file)` - Execute SSH command and return output #### `ollama_manager.lua` + Ollama service management: + - `start_service(config)` - Start Ollama service via SSH - `stop_service_and_shutdown(config)` - Stop service and shutdown host +#### `session_check.lua` + +Windows desktop session detection: + +- `is_user_logged_in_enhanced(config)` - Check if user is logged into desktop session + ## Benefits of Refactoring 1. **Separation of Concerns**: Each module has a single responsibility @@ -46,11 +64,22 @@ Ollama service management: 5. **Readability**: Clear structure and organization 6. **Configuration**: Centralized configuration management +## New Features + +### Desktop Session Detection + +The refactored version now includes Windows desktop session detection: + +- Checks if the SSH_USER is currently logged into a Windows desktop session +- If user is logged in, skips Ollama startup/shutdown to avoid interruption +- If user is not logged in, proceeds with normal operation + ## Usage To use the refactored version, simply run: + ```bash -lua auto-boot-ollama-host-refactored.lua +lua auto-boot-ollama-host.lua ``` The refactored version maintains full compatibility with the original script while providing better structure and maintainability. diff --git a/scripts/auto-boot-ollama-host.lua b/scripts/auto-boot-ollama-host.lua index 09d2fe8..f3fdb02 100644 --- a/scripts/auto-boot-ollama-host.lua +++ b/scripts/auto-boot-ollama-host.lua @@ -13,11 +13,23 @@ local utils = require("utils") local network = require("network") local ssh = require("ssh") local ollama_manager = require("ollama_manager") +local session_check = require("session_check") -- Handle error pattern detection and recovery local function handle_error_pattern(config, powered_on) utils.log(("Detected EHOSTUNREACH for Ollama (%s:%d)."):format(config.OLLAMA_HOST, config.OLLAMA_PORT)) + -- Check if user is currently logged into a desktop session + utils.log("Checking if user is currently logged into desktop session...") + local user_logged_in = session_check.is_user_logged_in(config) + + if user_logged_in then + utils.log(("User '%s' is currently logged into a desktop session. Skipping Ollama startup to avoid interruption."):format(config.SSH_USER)) + return powered_on -- Return current powered_on state without changes + end + + utils.log(("User '%s' is not logged into a desktop session. Proceeding with Ollama startup."):format(config.SSH_USER)) + -- Send Wake-on-LAN if configured if config.WOL_MAC ~= "" then utils.log(("Sending WOL to %s via %s:%d"):format(config.WOL_MAC, config.WOL_BCAST, config.WOL_PORT)) @@ -40,6 +52,17 @@ end -- Handle finish pattern detection and shutdown local function handle_finish_pattern(config) utils.log(("Detected finish pattern: %q"):format(config.FINISH_PATTERN)) + + -- Check if user is currently logged into a desktop session + utils.log("Checking if user is currently logged into desktop session before shutdown...") + local user_logged_in = session_check.is_user_logged_in(config) + + if user_logged_in then + utils.log(("User '%s' is currently logged into a desktop session. Skipping shutdown to avoid interruption."):format(config.SSH_USER)) + return -- Exit without shutting down + end + + utils.log(("User '%s' is not logged into a desktop session. Proceeding with shutdown."):format(config.SSH_USER)) ollama_manager.stop_service_and_shutdown(config) end diff --git a/scripts/session_check.lua b/scripts/session_check.lua new file mode 100644 index 0000000..f414040 --- /dev/null +++ b/scripts/session_check.lua @@ -0,0 +1,45 @@ +-- Windows desktop session check module for auto-boot-ollama-host +-- Checks if a specific user is currently logged into a Windows desktop session + +local utils = require("utils") +local ssh = require("ssh") + +local session_check = {} + +-- Check if user is currently logged into a Windows desktop session using quser +-- Returns true if user is logged in, false otherwise +function session_check.is_user_logged_in(config) + utils.log(("Checking if user '%s' is logged into desktop session using quser..."):format(config.SSH_USER)) + + -- Use quser command to check for active sessions + -- This works regardless of Windows language (looks for console/rdp sessions) + local command = "quser 2>nul | findstr /i \"console rdp-tcp#\" >nul && echo 1 || echo 0" + + local ok, output, err = ssh.execute_with_output(command, config.SSH_USER, config.OLLAMA_HOST, config.SSH_PORT, config.SSH_IDENTITY_FILE) + + if not ok then + utils.log(("Failed to execute quser session check command: %s"):format(tostring(err))) + return false + end + + if output and output ~= "" then + utils.log("Quser session check output received: " .. output) + + -- Parse the result (remove any whitespace/newlines) + local clean_output = output:gsub("%s+", "") + local result = tonumber(clean_output) + + if result == 1 then + utils.log(("User '%s' has an active desktop session"):format(config.SSH_USER)) + return true + else + utils.log(("User '%s' has no active desktop sessions"):format(config.SSH_USER)) + return false + end + else + utils.log("No output received from quser session check command") + return false + end +end + +return session_check diff --git a/scripts/ssh.lua b/scripts/ssh.lua index 6151fd5..de5435a 100644 --- a/scripts/ssh.lua +++ b/scripts/ssh.lua @@ -66,4 +66,64 @@ function ssh_module.execute(command, user, host, port, identity_file) end end +-- Execute a remote command over SSH and return the output +-- Signature: ssh.execute_with_output(command, user, host, port, identity_file) +-- Returns: success, output, error_message +function ssh_module.execute_with_output(command, user, host, port, identity_file) + -- Basic validation and defaults + user = tostring(user or "") + host = tostring(host or "") + port = tonumber(port or 22) or 22 + identity_file = tostring(identity_file or "") + + -- Build base ssh command (run locally) + local dest = (user ~= "" and (user .. "@" .. host) or host) + local pieces = { + "ssh", + "-p", tostring(port), + "-o", "BatchMode=yes", + "-o", "ConnectTimeout=30", + "-o", "ServerAliveInterval=5", + "-o", "ServerAliveCountMax=1", + "-o", "UserKnownHostsFile=/root/.ssh/known_hosts", + "-o", "StrictHostKeyChecking=yes", + } + + if identity_file ~= "" then + table.insert(pieces, "-i") + table.insert(pieces, identity_file) + end + table.insert(pieces, dest) + + -- Pass remote command as provided + table.insert(pieces, "--") + table.insert(pieces, command) + + -- Join with spaces for io.popen + local function join(args) + return table.concat(args, " ") + end + + local full = join(pieces) + utils.log("SSH exec (with output): " .. full) + + -- Use io.popen to capture output + local fh = io.popen(full, "r") + if not fh then + return false, "", "Failed to open SSH command" + end + + local output = fh:read("*a") + local success, reason, code = fh:close() + + if success then + utils.log("SSH command completed successfully with output") + return true, output, nil + else + local msg = string.format("SSH failed: reason=%s code=%s", tostring(reason), tostring(code)) + utils.log(msg) + return false, output, msg + end +end + return ssh_module