| 1 |
#!/bin/bash |
|
| 2 | ||
| 3 |
# autoSMART Node Installation Script |
|
| 4 |
# Version: 1.0 |
|
| 5 |
# Description: Install autoSMART on target nodes (Linux systems only) |
|
| 6 |
# Note: This script is called by deploy.sh and should run on target nodes |
|
| 7 | ||
| 8 |
set -e |
|
| 9 | ||
| 10 |
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
| 11 |
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" |
|
| 12 |
INSTALL_DIR="/opt/autoSMART" |
|
| 13 |
CONFIG_DIR="/etc/autosmart" |
|
| 14 |
SERVICE_NAME="autosmart" |
|
| 15 |
SYSTEMD_SERVICE="/etc/systemd/system/${SERVICE_NAME}.service"
|
|
| 16 | ||
| 17 |
# Default configuration (can be overridden by command line) |
|
| 18 |
DB_HOST="${DB_HOST:-192.168.2.102}"
|
|
| 19 |
DB_USER="${DB_USER:-autosmart}"
|
|
| 20 |
DB_PASS="${DB_PASS:-autoSMART2025!}"
|
|
| 21 |
DB_NAME="${DB_NAME:-autosmart}"
|
|
| 22 | ||
| 23 |
# Node configuration |
|
| 24 |
NODE_ID="${NODE_ID:-$(hostname -s)}"
|
|
| 25 |
SCAN_INTERVAL="${SCAN_INTERVAL:-300}"
|
|
| 26 |
FULL_SCAN_INTERVAL="${FULL_SCAN_INTERVAL:-3600}"
|
|
| 27 | ||
| 28 |
# Operation modes |
|
| 29 |
UNINSTALL=false |
|
| 30 |
FORCE_REINSTALL=false |
|
| 31 |
CONFIG_ONLY=false |
|
| 32 | ||
| 33 |
# Colors for output |
|
| 34 |
RED='\033[0;31m' |
|
| 35 |
GREEN='\033[0;32m' |
|
| 36 |
YELLOW='\033[1;33m' |
|
| 37 |
BLUE='\033[0;34m' |
|
| 38 |
NC='\033[0m' # No Color |
|
| 39 | ||
| 40 |
log_info() {
|
|
| 41 |
echo -e "${BLUE}[INFO]${NC} $1"
|
|
| 42 |
} |
|
| 43 | ||
| 44 |
log_success() {
|
|
| 45 |
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
|
| 46 |
} |
|
| 47 | ||
| 48 |
log_warning() {
|
|
| 49 |
echo -e "${YELLOW}[WARNING]${NC} $1"
|
|
| 50 |
} |
|
| 51 | ||
| 52 |
log_error() {
|
|
| 53 |
echo -e "${RED}[ERROR]${NC} $1"
|
|
| 54 |
} |
|
| 55 | ||
| 56 |
show_usage() {
|
|
| 57 |
echo "autoSMART Node Installation Script v1.0" |
|
| 58 |
echo "========================================" |
|
| 59 |
echo "" |
|
| 60 |
echo "Usage: $0 [COMMAND] [OPTIONS]" |
|
| 61 |
echo "" |
|
| 62 |
echo "Commands:" |
|
| 63 |
echo " install Install autoSMART on current node (default)" |
|
| 64 |
echo " uninstall Remove autoSMART completely from current node" |
|
| 65 |
echo "" |
|
| 66 |
echo "Options:" |
|
| 67 |
echo " --help Show this help message" |
|
| 68 |
echo " --force-reinstall Clean installation (removes previous version)" |
|
| 69 |
echo " --config-only Only create/update configuration files" |
|
| 70 |
echo " --db-host HOST Database host (default: 192.168.2.102)" |
|
| 71 |
echo " --db-user USER Database user (default: autosmart)" |
|
| 72 |
echo " --db-pass PASS Database password (default: autoSMART2025!)" |
|
| 73 |
echo " --db-name NAME Database name (default: autosmart)" |
|
| 74 |
echo " --node-id ID Node identifier (default: hostname)" |
|
| 75 |
echo " --scan-interval SEC Scan interval in seconds (default: 300)" |
|
| 76 |
echo "" |
|
| 77 |
echo "Note: This script should be called by deploy.sh, not run directly." |
|
| 78 |
echo "For deployment from development machine, use: deploy.sh install <IP>" |
|
| 79 |
echo "" |
|
| 80 |
} |
|
| 81 | ||
| 82 |
parse_arguments() {
|
|
| 83 |
COMMAND="install" # Default command |
|
| 84 | ||
| 85 |
while [[ $# -gt 0 ]]; do |
|
| 86 |
case $1 in |
|
| 87 |
install|uninstall) |
|
| 88 |
COMMAND="$1" |
|
| 89 |
shift |
|
| 90 |
;; |
|
| 91 |
--help) |
|
| 92 |
show_usage |
|
| 93 |
exit 0 |
|
| 94 |
;; |
|
| 95 |
--force-reinstall) |
|
| 96 |
FORCE_REINSTALL=true |
|
| 97 |
shift |
|
| 98 |
;; |
|
| 99 |
--config-only) |
|
| 100 |
CONFIG_ONLY=true |
|
| 101 |
shift |
|
| 102 |
;; |
|
| 103 |
--db-host) |
|
| 104 |
DB_HOST="$2" |
|
| 105 |
shift 2 |
|
| 106 |
;; |
|
| 107 |
--db-user) |
|
| 108 |
DB_USER="$2" |
|
| 109 |
shift 2 |
|
| 110 |
;; |
|
| 111 |
--db-pass) |
|
| 112 |
DB_PASS="$2" |
|
| 113 |
shift 2 |
|
| 114 |
;; |
|
| 115 |
--db-name) |
|
| 116 |
DB_NAME="$2" |
|
| 117 |
shift 2 |
|
| 118 |
;; |
|
| 119 |
--node-id) |
|
| 120 |
NODE_ID="$2" |
|
| 121 |
shift 2 |
|
| 122 |
;; |
|
| 123 |
--scan-interval) |
|
| 124 |
SCAN_INTERVAL="$2" |
|
| 125 |
shift 2 |
|
| 126 |
;; |
|
| 127 |
*) |
|
| 128 |
log_error "Unknown option: $1" |
|
| 129 |
show_usage |
|
| 130 |
exit 1 |
|
| 131 |
;; |
|
| 132 |
esac |
|
| 133 |
done |
|
| 134 |
} |
|
| 135 | ||
| 136 |
show_header() {
|
|
| 137 |
log_info "🔧 autoSMART Node Installation v1.0" |
|
| 138 |
log_info "===================================" |
|
| 139 |
log_info "Installing on target node: $(hostname)" |
|
| 140 |
log_info "" |
|
| 141 |
log_info "Operation: $COMMAND" |
|
| 142 |
log_info "Node ID: $NODE_ID" |
|
| 143 |
log_info "Database: $DB_HOST:5432/$DB_NAME" |
|
| 144 |
if [[ "$COMMAND" == "install" ]]; then |
|
| 145 |
log_info "Install Directory: $INSTALL_DIR" |
|
| 146 |
log_info "Config Directory: $CONFIG_DIR" |
|
| 147 |
fi |
|
| 148 |
log_info "" |
|
| 149 |
} |
|
| 150 | ||
| 151 |
check_requirements() {
|
|
| 152 |
log_info "🔍 Checking system requirements..." |
|
| 153 | ||
| 154 |
# Check if running as root |
|
| 155 |
if [[ $EUID -ne 0 ]]; then |
|
| 156 |
log_error "This script must be run as root (use sudo)" |
|
| 157 |
exit 1 |
|
| 158 |
fi |
|
| 159 | ||
| 160 |
# Check if running on Linux |
|
| 161 |
if [[ "$(uname)" != "Linux" ]]; then |
|
| 162 |
log_error "autoSMART can only be installed on Linux systems" |
|
| 163 |
log_error "Current system: $(uname)" |
|
| 164 |
exit 1 |
|
| 165 |
fi |
|
| 166 | ||
| 167 |
# Check systemd |
|
| 168 |
if ! command -v systemctl &> /dev/null; then |
|
| 169 |
log_error "systemd is required but not found" |
|
| 170 |
exit 1 |
|
| 171 |
fi |
|
| 172 | ||
| 173 |
# Check and report dependency status |
|
| 174 |
if ! verify_dependencies >/dev/null 2>&1; then |
|
| 175 |
log_warning "Some dependencies are missing (will be installed automatically)" |
|
| 176 |
fi |
|
| 177 | ||
| 178 |
# Check available space |
|
| 179 |
AVAILABLE_SPACE=$(df / | tail -1 | awk '{print $4}')
|
|
| 180 |
if [[ $AVAILABLE_SPACE -lt 100000 ]]; then |
|
| 181 |
log_warning "Less than 100MB available space. Installation may fail." |
|
| 182 |
fi |
|
| 183 | ||
| 184 |
log_success "System requirements check passed" |
|
| 185 |
} |
|
| 186 | ||
| 187 |
handle_uninstall() {
|
|
| 188 |
log_info "🗑️ Uninstalling autoSMART..." |
|
| 189 | ||
| 190 |
# Stop and disable service |
|
| 191 |
if systemctl is-active --quiet autosmart; then |
|
| 192 |
systemctl stop autosmart |
|
| 193 |
fi |
|
| 194 |
if systemctl is-enabled --quiet autosmart; then |
|
| 195 |
systemctl disable autosmart |
|
| 196 |
fi |
|
| 197 | ||
| 198 |
# Remove service file |
|
| 199 |
if [[ -f "$SYSTEMD_SERVICE" ]]; then |
|
| 200 |
rm "$SYSTEMD_SERVICE" |
|
| 201 |
systemctl daemon-reload |
|
| 202 |
fi |
|
| 203 | ||
| 204 |
# Remove installation directory |
|
| 205 |
if [[ -d "$INSTALL_DIR" ]]; then |
|
| 206 |
rm -rf "$INSTALL_DIR" |
|
| 207 |
fi |
|
| 208 | ||
| 209 |
# Remove configuration directory |
|
| 210 |
if [[ -d "$CONFIG_DIR" ]]; then |
|
| 211 |
rm -rf "$CONFIG_DIR" |
|
| 212 |
fi |
|
| 213 | ||
| 214 |
# Remove log rotation |
|
| 215 |
if [[ -f "/etc/logrotate.d/autosmart" ]]; then |
|
| 216 |
rm "/etc/logrotate.d/autosmart" |
|
| 217 |
fi |
|
| 218 | ||
| 219 |
log_success "✅ autoSMART uninstalled successfully" |
|
| 220 |
exit 0 |
|
| 221 |
} |
|
| 222 | ||
| 223 |
# Function to check if a package is installed |
|
| 224 |
check_package_installed() {
|
|
| 225 |
local package="$1" |
|
| 226 |
local package_manager="$2" |
|
| 227 | ||
| 228 |
case "$package_manager" in |
|
| 229 |
"apt-get") |
|
| 230 |
dpkg -l | grep -q "^ii $package " 2>/dev/null |
|
| 231 |
;; |
|
| 232 |
"yum"|"dnf") |
|
| 233 |
rpm -qa | grep -q "$package" 2>/dev/null |
|
| 234 |
;; |
|
| 235 |
"zypper") |
|
| 236 |
zypper se -i "$package" | grep -q "^i" 2>/dev/null |
|
| 237 |
;; |
|
| 238 |
"pacman") |
|
| 239 |
pacman -Q "$package" >/dev/null 2>&1 |
|
| 240 |
;; |
|
| 241 |
*) |
|
| 242 |
return 1 |
|
| 243 |
;; |
|
| 244 |
esac |
|
| 245 |
} |
|
| 246 | ||
| 247 |
# Function to verify all dependencies are installed |
|
| 248 |
verify_dependencies() {
|
|
| 249 |
log_info "🔍 Verifying system dependencies..." |
|
| 250 | ||
| 251 |
local missing_packages=() |
|
| 252 |
local package_manager="" |
|
| 253 | ||
| 254 |
# Detect package manager |
|
| 255 |
if command -v apt-get &> /dev/null; then |
|
| 256 |
package_manager="apt-get" |
|
| 257 |
elif command -v yum &> /dev/null; then |
|
| 258 |
package_manager="yum" |
|
| 259 |
elif command -v dnf &> /dev/null; then |
|
| 260 |
package_manager="dnf" |
|
| 261 |
elif command -v zypper &> /dev/null; then |
|
| 262 |
package_manager="zypper" |
|
| 263 |
elif command -v pacman &> /dev/null; then |
|
| 264 |
package_manager="pacman" |
|
| 265 |
else |
|
| 266 |
log_warning "Unknown package manager. Dependency verification limited." |
|
| 267 |
return 1 |
|
| 268 |
fi |
|
| 269 | ||
| 270 |
# Check system packages (including Perl modules from distribution) |
|
| 271 |
local system_packages=("perl" "smartmontools" "postgresql-client" "curl" "wget")
|
|
| 272 |
local perl_packages=() |
|
| 273 | ||
| 274 |
# Add Perl module packages based on package manager |
|
| 275 |
case "$package_manager" in |
|
| 276 |
"apt-get") |
|
| 277 |
perl_packages+=("libdbi-perl" "libdbd-pg-perl" "libjson-perl" "libfile-slurp-perl"
|
|
| 278 |
"libgetopt-long-descriptive-perl" "libconfig-simple-perl") |
|
| 279 |
;; |
|
| 280 |
"yum"|"dnf") |
|
| 281 |
perl_packages+=("perl-DBI" "perl-DBD-Pg" "perl-JSON" "perl-File-Slurp"
|
|
| 282 |
"perl-Getopt-Long" "perl-Config-Simple") |
|
| 283 |
;; |
|
| 284 |
"zypper") |
|
| 285 |
perl_packages+=("perl-DBI" "perl-DBD-Pg" "perl-JSON" "perl-File-Slurp"
|
|
| 286 |
"perl-Getopt-Long-Descriptive" "perl-Config-Simple") |
|
| 287 |
;; |
|
| 288 |
"pacman") |
|
| 289 |
perl_packages+=("perl-dbi" "perl-dbd-pg" "perl-json" "perl-file-slurp")
|
|
| 290 |
;; |
|
| 291 |
esac |
|
| 292 | ||
| 293 |
# Check system packages |
|
| 294 |
for package in "${system_packages[@]}"; do
|
|
| 295 |
if ! check_package_installed "$package" "$package_manager"; then |
|
| 296 |
missing_packages+=("$package")
|
|
| 297 |
fi |
|
| 298 |
done |
|
| 299 | ||
| 300 |
# Check Perl packages from distribution |
|
| 301 |
for package in "${perl_packages[@]}"; do
|
|
| 302 |
if ! check_package_installed "$package" "$package_manager"; then |
|
| 303 |
missing_packages+=("$package")
|
|
| 304 |
fi |
|
| 305 |
done |
|
| 306 | ||
| 307 |
# Report results |
|
| 308 |
if [[ ${#missing_packages[@]} -eq 0 ]]; then
|
|
| 309 |
log_success "✅ All dependencies are available" |
|
| 310 |
return 0 |
|
| 311 |
else |
|
| 312 |
log_warning "Missing dependencies detected:" |
|
| 313 |
if [[ ${#missing_packages[@]} -gt 0 ]]; then
|
|
| 314 |
log_warning " Missing packages: ${missing_packages[*]}"
|
|
| 315 |
fi |
|
| 316 |
return 1 |
|
| 317 |
fi |
|
| 318 |
} |
|
| 319 | ||
| 320 |
# Function to install dependencies |
|
| 321 |
install_dependencies() {
|
|
| 322 |
log_info "📦 Installing system dependencies..." |
|
| 323 | ||
| 324 |
# First check if dependencies are already installed |
|
| 325 |
if verify_dependencies >/dev/null 2>&1; then |
|
| 326 |
log_success "All dependencies already installed" |
|
| 327 |
return 0 |
|
| 328 |
fi |
|
| 329 | ||
| 330 |
log_info "Installing missing dependencies..." |
|
| 331 | ||
| 332 |
if command -v apt-get &> /dev/null; then |
|
| 333 |
# Debian/Ubuntu |
|
| 334 |
log_info "Updating package lists..." |
|
| 335 |
apt-get update -qq |
|
| 336 | ||
| 337 |
PACKAGES=( |
|
| 338 |
"perl" |
|
| 339 |
"libdbi-perl" |
|
| 340 |
"libdbd-pg-perl" |
|
| 341 |
"libjson-perl" |
|
| 342 |
"libfile-slurp-perl" |
|
| 343 |
"libgetopt-long-descriptive-perl" |
|
| 344 |
"libconfig-simple-perl" |
|
| 345 |
"smartmontools" |
|
| 346 |
"postgresql-client" |
|
| 347 |
"curl" |
|
| 348 |
"wget" |
|
| 349 |
) |
|
| 350 | ||
| 351 |
for package in "${PACKAGES[@]}"; do
|
|
| 352 |
if ! check_package_installed "$package" "apt-get"; then |
|
| 353 |
log_info "Installing $package..." |
|
| 354 |
if ! apt-get install -y "$package" >/dev/null 2>&1; then |
|
| 355 |
log_error "Failed to install $package" |
|
| 356 |
exit 1 |
|
| 357 |
fi |
|
| 358 |
fi |
|
| 359 |
done |
|
| 360 | ||
| 361 |
elif command -v dnf &> /dev/null; then |
|
| 362 |
# Fedora/RHEL 8+ |
|
| 363 |
log_info "Updating package lists..." |
|
| 364 |
dnf update -y -q |
|
| 365 | ||
| 366 |
PACKAGES=( |
|
| 367 |
"perl" |
|
| 368 |
"perl-DBI" |
|
| 369 |
"perl-DBD-Pg" |
|
| 370 |
"perl-JSON" |
|
| 371 |
"perl-File-Slurp" |
|
| 372 |
"perl-Getopt-Long" |
|
| 373 |
"perl-Config-Simple" |
|
| 374 |
"smartmontools" |
|
| 375 |
"postgresql" |
|
| 376 |
"curl" |
|
| 377 |
"wget" |
|
| 378 |
) |
|
| 379 | ||
| 380 |
for package in "${PACKAGES[@]}"; do
|
|
| 381 |
if ! check_package_installed "$package" "dnf"; then |
|
| 382 |
log_info "Installing $package..." |
|
| 383 |
if ! dnf install -y "$package" >/dev/null 2>&1; then |
|
| 384 |
log_error "Failed to install $package" |
|
| 385 |
exit 1 |
|
| 386 |
fi |
|
| 387 |
fi |
|
| 388 |
done |
|
| 389 | ||
| 390 |
elif command -v yum &> /dev/null; then |
|
| 391 |
# RHEL/CentOS 7 |
|
| 392 |
log_info "Updating package lists..." |
|
| 393 |
yum update -y -q |
|
| 394 | ||
| 395 |
PACKAGES=( |
|
| 396 |
"perl" |
|
| 397 |
"perl-DBI" |
|
| 398 |
"perl-DBD-Pg" |
|
| 399 |
"perl-JSON" |
|
| 400 |
"perl-File-Slurp" |
|
| 401 |
"perl-Getopt-Long" |
|
| 402 |
"perl-Config-Simple" |
|
| 403 |
"smartmontools" |
|
| 404 |
"postgresql" |
|
| 405 |
"curl" |
|
| 406 |
"wget" |
|
| 407 |
) |
|
| 408 | ||
| 409 |
for package in "${PACKAGES[@]}"; do
|
|
| 410 |
if ! check_package_installed "$package" "yum"; then |
|
| 411 |
log_info "Installing $package..." |
|
| 412 |
if ! yum install -y "$package" >/dev/null 2>&1; then |
|
| 413 |
log_error "Failed to install $package" |
|
| 414 |
exit 1 |
|
| 415 |
fi |
|
| 416 |
fi |
|
| 417 |
done |
|
| 418 | ||
| 419 |
elif command -v zypper &> /dev/null; then |
|
| 420 |
# openSUSE |
|
| 421 |
log_info "Updating package lists..." |
|
| 422 |
zypper refresh -q |
|
| 423 | ||
| 424 |
PACKAGES=( |
|
| 425 |
"perl" |
|
| 426 |
"perl-DBI" |
|
| 427 |
"perl-DBD-Pg" |
|
| 428 |
"perl-JSON" |
|
| 429 |
"perl-File-Slurp" |
|
| 430 |
"perl-Getopt-Long-Descriptive" |
|
| 431 |
"perl-Config-Simple" |
|
| 432 |
"smartmontools" |
|
| 433 |
"postgresql" |
|
| 434 |
"curl" |
|
| 435 |
"wget" |
|
| 436 |
) |
|
| 437 | ||
| 438 |
for package in "${PACKAGES[@]}"; do
|
|
| 439 |
if ! check_package_installed "$package" "zypper"; then |
|
| 440 |
log_info "Installing $package..." |
|
| 441 |
if ! zypper install -y "$package" >/dev/null 2>&1; then |
|
| 442 |
log_error "Failed to install $package" |
|
| 443 |
exit 1 |
|
| 444 |
fi |
|
| 445 |
fi |
|
| 446 |
done |
|
| 447 | ||
| 448 |
elif command -v pacman &> /dev/null; then |
|
| 449 |
# Arch Linux |
|
| 450 |
log_info "Updating package lists..." |
|
| 451 |
pacman -Sy --noconfirm |
|
| 452 | ||
| 453 |
PACKAGES=( |
|
| 454 |
"perl" |
|
| 455 |
"perl-dbi" |
|
| 456 |
"perl-dbd-pg" |
|
| 457 |
"perl-json" |
|
| 458 |
"perl-file-slurp" |
|
| 459 |
"smartmontools" |
|
| 460 |
"postgresql" |
|
| 461 |
"curl" |
|
| 462 |
"wget" |
|
| 463 |
) |
|
| 464 | ||
| 465 |
for package in "${PACKAGES[@]}"; do
|
|
| 466 |
if ! check_package_installed "$package" "pacman"; then |
|
| 467 |
log_info "Installing $package..." |
|
| 468 |
if ! pacman -S --noconfirm "$package" >/dev/null 2>&1; then |
|
| 469 |
log_error "Failed to install $package" |
|
| 470 |
exit 1 |
|
| 471 |
fi |
|
| 472 |
fi |
|
| 473 |
done |
|
| 474 | ||
| 475 |
else |
|
| 476 |
log_error "Unsupported package manager. Please install dependencies manually:" |
|
| 477 |
log_error " - perl, smartmontools, postgresql-client, curl, wget" |
|
| 478 |
log_error " - Perl modules: DBI, DBD::Pg, JSON, File::Slurp, Getopt::Long, Config::Simple" |
|
| 479 |
exit 1 |
|
| 480 |
fi |
|
| 481 | ||
| 482 |
# Verify installation was successful |
|
| 483 |
if verify_dependencies >/dev/null 2>&1; then |
|
| 484 |
log_success "✅ All dependencies installed successfully" |
|
| 485 |
else |
|
| 486 |
log_error "Some dependencies may not have installed correctly" |
|
| 487 |
exit 1 |
|
| 488 |
fi |
|
| 489 |
} |
|
| 490 | ||
| 491 |
create_directories() {
|
|
| 492 |
log_info "📁 Creating directory structure..." |
|
| 493 | ||
| 494 |
# Create main directories |
|
| 495 |
mkdir -p "$INSTALL_DIR"/{scripts,lib,config,docs}
|
|
| 496 |
mkdir -p "$CONFIG_DIR" |
|
| 497 | ||
| 498 |
# Set permissions |
|
| 499 |
chmod 755 "$INSTALL_DIR" |
|
| 500 |
chmod 755 "$CONFIG_DIR" |
|
| 501 | ||
| 502 |
log_success "Directories created" |
|
| 503 |
} |
|
| 504 | ||
| 505 |
copy_files() {
|
|
| 506 |
log_info "📋 Copying autoSMART files..." |
|
| 507 | ||
| 508 |
# Copy scripts |
|
| 509 |
if [[ -d "$PROJECT_ROOT/scripts" ]]; then |
|
| 510 |
cp -r "$PROJECT_ROOT/scripts"/* "$INSTALL_DIR/scripts/" |
|
| 511 |
chmod +x "$INSTALL_DIR/scripts"/*.sh 2>/dev/null || true |
|
| 512 |
chmod +x "$INSTALL_DIR/scripts"/*.pl 2>/dev/null || true |
|
| 513 |
fi |
|
| 514 | ||
| 515 |
# Copy libraries |
|
| 516 |
if [[ -d "$PROJECT_ROOT/lib" ]]; then |
|
| 517 |
cp -r "$PROJECT_ROOT/lib"/* "$INSTALL_DIR/lib/" |
|
| 518 |
fi |
|
| 519 | ||
| 520 |
# Copy documentation |
|
| 521 |
if [[ -d "$PROJECT_ROOT/docs" ]]; then |
|
| 522 |
cp -r "$PROJECT_ROOT/docs"/* "$INSTALL_DIR/docs/" |
|
| 523 |
fi |
|
| 524 | ||
| 525 |
# Copy SQL files |
|
| 526 |
if [[ -d "$PROJECT_ROOT/sql" ]]; then |
|
| 527 |
cp -r "$PROJECT_ROOT/sql" "$INSTALL_DIR/" |
|
| 528 |
fi |
|
| 529 | ||
| 530 |
log_success "Files copied" |
|
| 531 |
} |
|
| 532 | ||
| 533 |
create_configuration() {
|
|
| 534 |
log_info "⚙️ Creating configuration files..." |
|
| 535 | ||
| 536 |
# Main configuration file |
|
| 537 |
cat > "$CONFIG_DIR/autosmart.conf" << EOF |
|
| 538 |
# autoSMART Configuration File |
|
| 539 |
# Generated on $(date) |
|
| 540 | ||
| 541 |
[database] |
|
| 542 |
host = $DB_HOST |
|
| 543 |
port = 5432 |
|
| 544 |
user = $DB_USER |
|
| 545 |
password = $DB_PASS |
|
| 546 |
database = $DB_NAME |
|
| 547 |
timeout = 30 |
|
| 548 | ||
| 549 |
[node] |
|
| 550 |
id = $NODE_ID |
|
| 551 |
scan_interval = $SCAN_INTERVAL |
|
| 552 |
full_scan_interval = $FULL_SCAN_INTERVAL |
|
| 553 |
store_unchanged = false |
|
| 554 |
max_retries = 3 |
|
| 555 | ||
| 556 |
[collection] |
|
| 557 |
temperature_threshold = 5 |
|
| 558 |
parameter_changes_only = true |
|
| 559 |
enable_predictive_analysis = true |
|
| 560 |
health_check_interval = 86400 |
|
| 561 | ||
| 562 |
[logging] |
|
| 563 |
level = INFO |
|
| 564 |
max_size = 10M |
|
| 565 |
rotate_count = 5 |
|
| 566 |
syslog = true |
|
| 567 | ||
| 568 |
[alerts] |
|
| 569 |
enable = true |
|
| 570 |
temperature_critical = 60 |
|
| 571 |
reallocated_sectors_warning = 1 |
|
| 572 |
pending_sectors_critical = 5 |
|
| 573 |
EOF |
|
| 574 | ||
| 575 |
# YAML format configuration for Perl daemon |
|
| 576 |
cat > "$CONFIG_DIR/cluster-$NODE_ID.conf" << EOF |
|
| 577 |
# autoSMART YAML Configuration for $NODE_ID |
|
| 578 |
database: |
|
| 579 |
host: $DB_HOST |
|
| 580 |
port: 5432 |
|
| 581 |
user: $DB_USER |
|
| 582 |
password: $DB_PASS |
|
| 583 |
database: $DB_NAME |
|
| 584 | ||
| 585 |
node: |
|
| 586 |
id: $NODE_ID |
|
| 587 |
scan_interval: $SCAN_INTERVAL |
|
| 588 |
store_unchanged: false |
|
| 589 | ||
| 590 |
collection: |
|
| 591 |
temperature_threshold: 5 |
|
| 592 |
parameter_changes_only: true |
|
| 593 |
full_scan_interval: $FULL_SCAN_INTERVAL |
|
| 594 |
EOF |
|
| 595 | ||
| 596 |
# Set secure permissions on config files |
|
| 597 |
chmod 600 "$CONFIG_DIR"/*.conf |
|
| 598 | ||
| 599 |
log_success "Configuration created" |
|
| 600 |
} |
|
| 601 | ||
| 602 |
create_systemd_service() {
|
|
| 603 |
log_info "🔧 Creating systemd service..." |
|
| 604 | ||
| 605 |
cat > "$SYSTEMD_SERVICE" << EOF |
|
| 606 |
[Unit] |
|
| 607 |
Description=autoSMART SMART Data Collector |
|
| 608 |
Documentation=file://$INSTALL_DIR/docs/README.md |
|
| 609 |
After=network.target postgresql.service |
|
| 610 |
Wants=postgresql.service |
|
| 611 | ||
| 612 |
[Service] |
|
| 613 |
Type=simple |
|
| 614 |
ExecStart=$INSTALL_DIR/scripts/smart-collector-daemon.pl --config $CONFIG_DIR/cluster-$NODE_ID.conf --foreground |
|
| 615 |
ExecReload=/bin/kill -HUP \$MAINPID |
|
| 616 |
KillMode=process |
|
| 617 |
Restart=always |
|
| 618 |
RestartSec=30 |
|
| 619 |
User=root |
|
| 620 |
Group=root |
|
| 621 | ||
| 622 |
# Security settings |
|
| 623 |
NoNewPrivileges=true |
|
| 624 |
ProtectSystem=strict |
|
| 625 |
ProtectHome=true |
|
| 626 |
ReadWritePaths=$CONFIG_DIR |
|
| 627 |
PrivateTmp=true |
|
| 628 | ||
| 629 |
# Resource limits |
|
| 630 |
LimitNOFILE=1024 |
|
| 631 |
MemoryMax=100M |
|
| 632 |
CPUQuota=10% |
|
| 633 | ||
| 634 |
# Logging |
|
| 635 |
StandardOutput=journal |
|
| 636 |
StandardError=journal |
|
| 637 |
SyslogIdentifier=autosmart |
|
| 638 | ||
| 639 |
[Install] |
|
| 640 |
WantedBy=multi-user.target |
|
| 641 |
EOF |
|
| 642 | ||
| 643 |
# Reload systemd |
|
| 644 |
systemctl daemon-reload |
|
| 645 | ||
| 646 |
log_success "Systemd service created" |
|
| 647 |
} |
|
| 648 | ||
| 649 |
test_database_connection() {
|
|
| 650 |
log_info "🔗 Testing database connection..." |
|
| 651 | ||
| 652 |
# Test connection using psql |
|
| 653 |
if command -v psql &> /dev/null; then |
|
| 654 |
if PGPASSWORD="$DB_PASS" psql -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME" -c "SELECT version();" >/dev/null 2>&1; then |
|
| 655 |
log_success "Database connection successful" |
|
| 656 |
else |
|
| 657 |
log_warning "Database connection failed. Service may not start correctly." |
|
| 658 |
log_info "Please ensure:" |
|
| 659 |
log_info " • PostgreSQL server is running on $DB_HOST" |
|
| 660 |
log_info " • Database '$DB_NAME' exists" |
|
| 661 |
log_info " • User '$DB_USER' has proper permissions" |
|
| 662 |
fi |
|
| 663 |
else |
|
| 664 |
log_warning "psql not found. Cannot test database connection." |
|
| 665 |
fi |
|
| 666 |
} |
|
| 667 | ||
| 668 |
test_smart_detection() {
|
|
| 669 |
log_info "🔍 Testing SMART device detection..." |
|
| 670 | ||
| 671 |
DEVICES_FOUND=0 |
|
| 672 |
for device in /dev/sd? /dev/nvme?n?; do |
|
| 673 |
if [[ -b "$device" ]] && smartctl -i "$device" >/dev/null 2>&1; then |
|
| 674 |
MODEL=$(smartctl -i "$device" | grep "Device Model\|Model Number" | head -1 | cut -d: -f2 | xargs) |
|
| 675 |
if [[ -n "$MODEL" ]]; then |
|
| 676 |
log_info " Found: $device - $MODEL" |
|
| 677 |
((DEVICES_FOUND++)) |
|
| 678 |
fi |
|
| 679 |
fi |
|
| 680 |
done |
|
| 681 | ||
| 682 |
if [[ $DEVICES_FOUND -gt 0 ]]; then |
|
| 683 |
log_success "Detected $DEVICES_FOUND SMART-capable devices" |
|
| 684 |
else |
|
| 685 |
log_warning "No SMART-capable devices detected" |
|
| 686 |
fi |
|
| 687 |
} |
|
| 688 | ||
| 689 |
finalize_installation() {
|
|
| 690 |
log_info "🎯 Finalizing installation..." |
|
| 691 | ||
| 692 |
# Enable service (but don't start yet) |
|
| 693 |
systemctl enable "$SERVICE_NAME" |
|
| 694 | ||
| 695 |
# Create log rotation |
|
| 696 |
cat > "/etc/logrotate.d/autosmart" << EOF |
|
| 697 |
/var/log/autosmart/*.log {
|
|
| 698 |
daily |
|
| 699 |
rotate 7 |
|
| 700 |
compress |
|
| 701 |
delaycompress |
|
| 702 |
missingok |
|
| 703 |
notifempty |
|
| 704 |
postrotate |
|
| 705 |
systemctl reload-or-restart autosmart |
|
| 706 |
endscript |
|
| 707 |
} |
|
| 708 |
EOF |
|
| 709 | ||
| 710 |
log_success "Installation finalized" |
|
| 711 |
} |
|
| 712 | ||
| 713 |
show_completion_message() {
|
|
| 714 |
log_success "✅ autoSMART installation completed successfully!" |
|
| 715 |
log_info "" |
|
| 716 |
log_info "📋 Installation Summary:" |
|
| 717 |
log_info " • Install Directory: $INSTALL_DIR" |
|
| 718 |
log_info " • Config Directory: $CONFIG_DIR" |
|
| 719 |
log_info " • Service Name: $SERVICE_NAME" |
|
| 720 |
log_info " • Node ID: $NODE_ID" |
|
| 721 |
log_info "" |
|
| 722 |
log_info "🚀 Next Steps:" |
|
| 723 |
log_info " 1. Start the service:" |
|
| 724 |
log_info " systemctl start $SERVICE_NAME" |
|
| 725 |
log_info "" |
|
| 726 |
log_info " 2. Check service status:" |
|
| 727 |
log_info " systemctl status $SERVICE_NAME" |
|
| 728 |
log_info "" |
|
| 729 |
log_info " 3. View logs:" |
|
| 730 |
log_info " journalctl -u $SERVICE_NAME -f" |
|
| 731 |
log_info "" |
|
| 732 |
log_info "📖 Documentation: $INSTALL_DIR/docs/README.md" |
|
| 733 |
log_info "⚙️ Configuration: $CONFIG_DIR/autosmart.conf" |
|
| 734 |
log_info "" |
|
| 735 |
log_info "🎉 autoSMART is ready to monitor your storage devices!" |
|
| 736 |
} |
|
| 737 | ||
| 738 |
# Main execution |
|
| 739 |
main() {
|
|
| 740 |
parse_arguments "$@" |
|
| 741 |
show_header |
|
| 742 | ||
| 743 |
case "$COMMAND" in |
|
| 744 |
uninstall) |
|
| 745 |
handle_uninstall |
|
| 746 |
;; |
|
| 747 |
install) |
|
| 748 |
check_requirements |
|
| 749 | ||
| 750 |
# Handle force reinstall |
|
| 751 |
if [[ "$FORCE_REINSTALL" == true ]]; then |
|
| 752 |
log_info "🗑️ Force reinstall: cleaning previous installation..." |
|
| 753 |
handle_uninstall 2>/dev/null || true |
|
| 754 |
sleep 2 |
|
| 755 |
fi |
|
| 756 | ||
| 757 |
# Handle config-only mode |
|
| 758 |
if [[ "$CONFIG_ONLY" == true ]]; then |
|
| 759 |
log_info "⚙️ Configuration-only mode" |
|
| 760 |
if [[ ! -d "$INSTALL_DIR" ]]; then |
|
| 761 |
log_error "autoSMART is not installed. Run full installation first." |
|
| 762 |
exit 1 |
|
| 763 |
fi |
|
| 764 |
create_configuration |
|
| 765 |
log_success "✅ Configuration updated successfully!" |
|
| 766 |
exit 0 |
|
| 767 |
fi |
|
| 768 | ||
| 769 |
# Full installation |
|
| 770 |
install_dependencies |
|
| 771 |
create_directories |
|
| 772 |
copy_files |
|
| 773 |
create_configuration |
|
| 774 |
create_systemd_service |
|
| 775 |
test_database_connection |
|
| 776 |
test_smart_detection |
|
| 777 |
finalize_installation |
|
| 778 |
show_completion_message |
|
| 779 |
;; |
|
| 780 |
*) |
|
| 781 |
log_error "Unknown command: $COMMAND" |
|
| 782 |
show_usage |
|
| 783 |
exit 1 |
|
| 784 |
;; |
|
| 785 |
esac |
|
| 786 |
} |
|
| 787 | ||
| 788 |
# Run main function |
|
| 789 |
main "$@" |