Compare commits

...

4 Commits

6 changed files with 224 additions and 7 deletions

View File

@ -1,5 +1,18 @@
# Changelog
## 2025-03-25 - 2.3.0 - feat(installer/cli)
Add OS detection and git auto-installation support to install.sh and improve service setup prompt in CLI
- Implemented helper functions in install.sh to detect OS type and automatically install git if missing
- Prompt user for git installation if not present before cloning the repository
- Enhanced CLI service setup flow to offer starting the NUPST service immediately after installation
## 2025-03-25 - 2.2.0 - feat(cli)
Add 'config' command to display current configuration and update CLI help
- Introduce new 'config' command to show SNMP settings, thresholds, and configuration file location
- Update help text to include details for 'nupst config' command
## 2025-03-25 - 2.1.0 - feat(cli)
Add uninstall command to CLI and update shutdown delay for graceful VM shutdown

View File

@ -17,6 +17,78 @@ if [ ! -t 0 ]; then
PIPED=1
fi
# Helper function to detect OS type
detect_os() {
if [ -f /etc/os-release ]; then
. /etc/os-release
OS=$ID
elif type lsb_release >/dev/null 2>&1; then
OS=$(lsb_release -si | tr '[:upper:]' '[:lower:]')
elif [ -f /etc/lsb-release ]; then
. /etc/lsb-release
OS=$DISTRIB_ID
elif [ -f /etc/debian_version ]; then
OS="debian"
elif [ -f /etc/redhat-release ]; then
if grep -q "CentOS" /etc/redhat-release; then
OS="centos"
elif grep -q "Fedora" /etc/redhat-release; then
OS="fedora"
else
OS="rhel"
fi
else
OS=$(uname -s)
fi
echo $OS
}
# Helper function to install git
install_git() {
OS=$(detect_os)
echo "Detected OS: $OS"
case "$OS" in
ubuntu|debian|pop|mint|elementary|kali|zorin)
echo "Installing git using apt..."
apt-get update && apt-get install -y git
;;
fedora|rhel|centos|almalinux|rocky)
echo "Installing git using dnf/yum..."
if command -v dnf &> /dev/null; then
dnf install -y git
else
yum install -y git
fi
;;
arch|manjaro|endeavouros|garuda)
echo "Installing git using pacman..."
pacman -Sy --noconfirm git
;;
opensuse*|suse|sles)
echo "Installing git using zypper..."
zypper install -y git
;;
alpine)
echo "Installing git using apk..."
apk add git
;;
*)
echo "Unsupported OS: $OS"
echo "Please install git manually and run the installer again."
exit 1
;;
esac
# Check if git was installed successfully
if ! command -v git &> /dev/null; then
echo "Failed to install git. Please install git manually and run the installer again."
exit 1
fi
echo "Git installed successfully."
}
# Define installation directory
INSTALL_DIR="/opt/nupst"
REPO_URL="https://code.foss.global/serve.zone/nupst.git"
@ -26,8 +98,15 @@ if [ $PIPED -eq 1 ]; then
# Check if git is installed
if ! command -v git &> /dev/null; then
echo "Git is required but not installed. Please install git first."
exit 1
echo "Git is required but not installed."
read -p "Would you like to install git now? (Y/n): " install_git_prompt
if [[ "$install_git_prompt" =~ ^[Nn]$ ]]; then
echo "Git installation skipped. Please install git manually and run the installer again."
exit 1
else
install_git
fi
fi
# Check if installation directory exists

21
license Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Task Venture Capital GmbH
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,6 +1,6 @@
{
"name": "@serve.zone/nupst",
"version": "2.1.0",
"version": "2.3.0",
"description": "Node.js UPS Shutdown Tool for SNMP-enabled UPS devices",
"main": "dist/index.js",
"bin": {

View File

@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@serve.zone/nupst',
version: '2.1.0',
version: '2.3.0',
description: 'Node.js UPS Shutdown Tool for SNMP-enabled UPS devices'
}

110
ts/cli.ts
View File

@ -101,6 +101,10 @@ export class NupstCli {
case 'uninstall':
await this.uninstall();
break;
case 'config':
await this.showConfig();
break;
case 'help':
default:
@ -372,6 +376,7 @@ Usage:
nupst status - Show status of the systemd service and UPS status
nupst setup - Run the interactive setup to configure SNMP settings
nupst test - Test the current configuration by connecting to the UPS
nupst config - Display the current configuration
nupst update - Update NUPST from repository and refresh systemd service (requires root)
nupst uninstall - Completely uninstall NUPST from the system (requires root)
nupst help - Show this help message
@ -829,7 +834,7 @@ Options:
}
/**
* Optionally enable systemd service
* Optionally enable and start systemd service
* @param prompt Function to prompt for user input
*/
private async optionallyEnableService(prompt: (question: string) => Promise<string>): Promise<void> {
@ -838,11 +843,110 @@ Options:
} else {
const setupService = await prompt('Would you like to enable NUPST as a system service? (y/N): ');
if (setupService.toLowerCase() === 'y') {
await this.nupst.getSystemd().install();
console.log('Service installed. Use "nupst start" to start the service.');
try {
await this.nupst.getSystemd().install();
console.log('Service installed and enabled to start on boot.');
// Ask if the user wants to start the service now
const startService = await prompt('Would you like to start the NUPST service now? (Y/n): ');
if (startService.toLowerCase() !== 'n') {
await this.nupst.getSystemd().start();
console.log('NUPST service started successfully.');
} else {
console.log('Service not started. Use "nupst start" to start the service manually.');
}
} catch (error) {
console.error(`Failed to setup service: ${error.message}`);
}
}
}
}
/**
* Display the current configuration
*/
private async showConfig(): Promise<void> {
try {
// Try to load configuration
try {
await this.nupst.getDaemon().loadConfig();
} catch (error) {
console.error('┌─ Configuration Error ─────────────────────┐');
console.error('│ No configuration found.');
console.error('│ Please run \'nupst setup\' first to create a configuration.');
console.error('└──────────────────────────────────────────┘');
return;
}
// Get current configuration
const config = this.nupst.getDaemon().getConfig();
console.log('┌─ NUPST Configuration ──────────────────────┐');
// SNMP Settings
console.log('│ SNMP Settings:');
console.log(`│ Host: ${config.snmp.host}`);
console.log(`│ Port: ${config.snmp.port}`);
console.log(`│ Version: ${config.snmp.version}`);
console.log(`│ UPS Model: ${config.snmp.upsModel || 'cyberpower'}`);
if (config.snmp.version === 1 || config.snmp.version === 2) {
console.log(`│ Community: ${config.snmp.community}`);
} else if (config.snmp.version === 3) {
console.log(`│ Security Level: ${config.snmp.securityLevel}`);
console.log(`│ Username: ${config.snmp.username}`);
// Show auth and privacy details based on security level
if (config.snmp.securityLevel === 'authNoPriv' || config.snmp.securityLevel === 'authPriv') {
console.log(`│ Auth Protocol: ${config.snmp.authProtocol || 'None'}`);
}
if (config.snmp.securityLevel === 'authPriv') {
console.log(`│ Privacy Protocol: ${config.snmp.privProtocol || 'None'}`);
}
// Show timeout value
console.log(`│ Timeout: ${config.snmp.timeout / 1000} seconds`);
}
// Show OIDs if custom model is selected
if (config.snmp.upsModel === 'custom' && config.snmp.customOIDs) {
console.log('│ Custom OIDs:');
console.log(`│ Power Status: ${config.snmp.customOIDs.POWER_STATUS || 'Not set'}`);
console.log(`│ Battery Capacity: ${config.snmp.customOIDs.BATTERY_CAPACITY || 'Not set'}`);
console.log(`│ Battery Runtime: ${config.snmp.customOIDs.BATTERY_RUNTIME || 'Not set'}`);
}
// Thresholds
console.log('│ Thresholds:');
console.log(`│ Battery: ${config.thresholds.battery}%`);
console.log(`│ Runtime: ${config.thresholds.runtime} minutes`);
console.log(`│ Check Interval: ${config.checkInterval / 1000} seconds`);
// Configuration file location
console.log('│');
console.log('│ Configuration File Location:');
console.log('│ /etc/nupst/config.json');
console.log('└──────────────────────────────────────────┘');
// Show service status
try {
const isActive = execSync('systemctl is-active nupst.service || true').toString().trim() === 'active';
const isEnabled = execSync('systemctl is-enabled nupst.service || true').toString().trim() === 'enabled';
console.log('┌─ Service Status ─────────────────────────┐');
console.log(`│ Service Active: ${isActive ? 'Yes' : 'No'}`);
console.log(`│ Service Enabled: ${isEnabled ? 'Yes' : 'No'}`);
console.log('└──────────────────────────────────────────┘');
} catch (error) {
// Ignore errors checking service status
}
} catch (error) {
console.error(`Failed to display configuration: ${error.message}`);
}
}
/**
* Completely uninstall NUPST from the system