Newer Older
f16725e 3 months ago History
844 lines | 24.342kb
Bogdan Timofte authored 3 months ago
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 default configuration to /etc/default/autosmart
521
    if [[ -f "/etc/default/autosmart" ]]; then
522
        log_info "📝 Existing configuration found, merging with defaults..."
523

            
524
        # Backup existing configuration
525
        cp "/etc/default/autosmart" "/etc/default/autosmart.backup.$(date +%Y%m%d_%H%M%S)"
526

            
527
        # Read existing configuration
528
        declare -A existing_config
529
        while IFS='=' read -r key value; do
530
            if [[ $key =~ ^[A-Z_]+$ ]] && [[ -n $value ]]; then
531
                # Remove quotes and store
532
                value=$(echo "$value" | sed 's/^"//;s/"$//')
533
                existing_config["$key"]="$value"
534
            fi
535
        done < "/etc/default/autosmart"
536

            
537
        # Start with new configuration template
538
        if [[ -f "$PROJECT_ROOT/config/autosmart-defaults.conf" ]]; then
539
            cp "$PROJECT_ROOT/config/autosmart-defaults.conf" "/etc/default/autosmart"
540
        else
541
            cat > "/etc/default/autosmart" << 'EOF'
542
# AutoSMART Configuration
543
AUTOSMART_DEBUG="false"
544
EOF
545
        fi
546

            
547
        # Merge existing values back
548
        for key in "${!existing_config[@]}"; do
549
            value="${existing_config[$key]}"
550
            if grep -q "^${key}=" "/etc/default/autosmart"; then
551
                # Update existing key with preserved value
552
                sed -i "s|^${key}=.*|${key}=\"${value}\"|" "/etc/default/autosmart"
553
                log_info "✓ Preserved existing setting: ${key}=\"${value}\""
554
            else
555
                # Add new key
556
                echo "${key}=\"${value}\"" >> "/etc/default/autosmart"
557
                log_info "✓ Added custom setting: ${key}=\"${value}\""
558
            fi
559
        done
560

            
561
        log_info "✓ Configuration merged successfully"
562

            
563
    elif [[ -f "$PROJECT_ROOT/config/autosmart-defaults.conf" ]]; then
564
        cp "$PROJECT_ROOT/config/autosmart-defaults.conf" /etc/default/autosmart
565
        log_info "✓ AutoSMART default configuration installed"
566
    else
567
        log_warning "Default configuration file not found, creating basic one"
568
        cat > /etc/default/autosmart << 'EOF'
569
# AutoSMART Configuration
570
AUTOSMART_DEBUG="false"
571
EOF
572
    fi
573

            
574
    # Copy documentation
575
    if [[ -d "$PROJECT_ROOT/docs" ]]; then
576
        cp -r "$PROJECT_ROOT/docs"/* "$INSTALL_DIR/docs/"
577
    fi
578

            
579
    # Copy SQL files
580
    if [[ -d "$PROJECT_ROOT/sql" ]]; then
581
        cp -r "$PROJECT_ROOT/sql" "$INSTALL_DIR/"
582
    fi
583

            
584
    log_success "Files copied"
585
}
586

            
587
create_configuration() {
588
    log_info "⚙️  Creating configuration files..."
589

            
590
    # Main configuration file
591
    cat > "$CONFIG_DIR/autosmart.conf" << EOF
592
# autoSMART Configuration File
593
# Generated on $(date)
594

            
595
[database]
596
host = $DB_HOST
597
port = 5432
598
user = $DB_USER
599
password = $DB_PASS
600
database = $DB_NAME
601
timeout = 30
602

            
603
[node]
604
id = $NODE_ID
605
scan_interval = $SCAN_INTERVAL
606
full_scan_interval = $FULL_SCAN_INTERVAL
607
store_unchanged = false
608
max_retries = 3
609

            
610
[collection]
611
temperature_threshold = 5
612
parameter_changes_only = true
613
enable_predictive_analysis = true
614
health_check_interval = 86400
615

            
616
[logging]
617
level = INFO
618
max_size = 10M
619
rotate_count = 5
620
syslog = true
621

            
622
[alerts]
623
enable = true
624
temperature_critical = 60
625
reallocated_sectors_warning = 1
626
pending_sectors_critical = 5
627
EOF
628

            
629
    # YAML format configuration for Perl daemon
630
    cat > "$CONFIG_DIR/cluster-$NODE_ID.conf" << EOF
631
# autoSMART YAML Configuration for $NODE_ID
632
database:
633
  host: $DB_HOST
634
  port: 5432
635
  user: $DB_USER
636
  password: $DB_PASS
637
  database: $DB_NAME
638

            
639
node:
640
  id: $NODE_ID
641
  scan_interval: $SCAN_INTERVAL
642
  store_unchanged: false
643

            
644
collection:
645
  temperature_threshold: 5
646
  parameter_changes_only: true
647
  full_scan_interval: $FULL_SCAN_INTERVAL
648
EOF
649

            
650
    # Set secure permissions on config files
651
    chmod 600 "$CONFIG_DIR"/*.conf
652

            
653
    log_success "Configuration created"
654
}
655

            
656
create_systemd_service() {
657
    log_info "🔧 Creating systemd service..."
658

            
659
    cat > "$SYSTEMD_SERVICE" << EOF
660
[Unit]
661
Description=autoSMART SMART Data Collector
662
Documentation=file://$INSTALL_DIR/docs/README.md
663
After=network.target postgresql.service
664
Wants=postgresql.service
665

            
666
[Service]
667
Type=simple
668
EnvironmentFile=/etc/default/autosmart
669
ExecStart=$INSTALL_DIR/scripts/smart-collector-daemon.pl --config $CONFIG_DIR/cluster-$NODE_ID.conf --foreground
670
ExecReload=/bin/kill -HUP \$MAINPID
671
KillMode=process
672
Restart=always
673
RestartSec=30
674
User=root
675
Group=root
676

            
677
# Security settings
678
NoNewPrivileges=true
679
ProtectSystem=strict
680
ProtectHome=true
681
ReadWritePaths=$CONFIG_DIR
682
PrivateTmp=true
683

            
684
# Resource limits
685
LimitNOFILE=1024
686
MemoryMax=100M
687
CPUQuota=10%
688

            
689
# Logging
690
StandardOutput=journal
691
StandardError=journal
692
SyslogIdentifier=autosmart
693

            
694
[Install]
695
WantedBy=multi-user.target
696
EOF
697

            
698
    # Reload systemd
699
    systemctl daemon-reload
700

            
701
    log_success "Systemd service created"
702
}
703

            
704
test_database_connection() {
705
    log_info "🔗 Testing database connection..."
706

            
707
    # Test connection using psql
708
    if command -v psql &> /dev/null; then
709
        if PGPASSWORD="$DB_PASS" psql -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME" -c "SELECT version();" >/dev/null 2>&1; then
710
            log_success "Database connection successful"
711
        else
712
            log_warning "Database connection failed. Service may not start correctly."
713
            log_info "Please ensure:"
714
            log_info "  • PostgreSQL server is running on $DB_HOST"
715
            log_info "  • Database '$DB_NAME' exists"
716
            log_info "  • User '$DB_USER' has proper permissions"
717
        fi
718
    else
719
        log_warning "psql not found. Cannot test database connection."
720
    fi
721
}
722

            
723
test_smart_detection() {
724
    log_info "🔍 Testing SMART device detection..."
725

            
726
    DEVICES_FOUND=0
727
    for device in /dev/sd? /dev/nvme?n?; do
728
        if [[ -b "$device" ]] && smartctl -i "$device" >/dev/null 2>&1; then
729
            MODEL=$(smartctl -i "$device" | grep "Device Model\|Model Number" | head -1 | cut -d: -f2 | xargs)
730
            if [[ -n "$MODEL" ]]; then
731
                log_info "  Found: $device - $MODEL"
732
                DEVICES_FOUND=$((DEVICES_FOUND + 1))
733
            fi
734
        fi
735
    done
736

            
737
    if [[ $DEVICES_FOUND -gt 0 ]]; then
738
        log_success "Detected $DEVICES_FOUND SMART-capable devices"
739
    else
740
        log_warning "No SMART-capable devices detected"
741
    fi
742
}
743

            
744
finalize_installation() {
745
    log_info "🎯 Finalizing installation..."
746

            
747
    # Enable service (but don't start yet)
748
    systemctl enable "$SERVICE_NAME"
749

            
750
    # Create log rotation
751
    cat > "/etc/logrotate.d/autosmart" << EOF
752
/var/log/autosmart/*.log {
753
    daily
754
    rotate 7
755
    compress
756
    delaycompress
757
    missingok
758
    notifempty
759
    postrotate
760
        systemctl reload-or-restart autosmart
761
    endscript
762
}
763
EOF
764

            
765
    log_success "Installation finalized"
766
}
767

            
768
show_completion_message() {
769
    log_success "✅ autoSMART installation completed successfully!"
770
    log_info ""
771
    log_info "📋 Installation Summary:"
772
    log_info "  • Install Directory: $INSTALL_DIR"
773
    log_info "  • Config Directory: $CONFIG_DIR"
774
    log_info "  • Service Name: $SERVICE_NAME"
775
    log_info "  • Node ID: $NODE_ID"
776
    log_info ""
777
    log_info "🚀 Next Steps:"
778
    log_info "  1. Start the service:"
779
    log_info "     systemctl start $SERVICE_NAME"
780
    log_info ""
781
    log_info "  2. Check service status:"
782
    log_info "     systemctl status $SERVICE_NAME"
783
    log_info ""
784
    log_info "  3. View logs:"
785
    log_info "     journalctl -u $SERVICE_NAME -f"
786
    log_info ""
787
    log_info "📖 Documentation: $INSTALL_DIR/docs/README.md"
788
    log_info "⚙️  Configuration: $CONFIG_DIR/autosmart.conf"
789
    log_info ""
790
    log_info "🎉 autoSMART is ready to monitor your storage devices!"
791
}
792

            
793
# Main execution
794
main() {
795
    parse_arguments "$@"
796
    show_header
797

            
798
    case "$COMMAND" in
799
        uninstall)
800
            handle_uninstall
801
            ;;
802
        install)
803
            check_requirements
804

            
805
            # Handle force reinstall
806
            if [[ "$FORCE_REINSTALL" == true ]]; then
807
                log_info "🗑️  Force reinstall: cleaning previous installation..."
808
                handle_uninstall 2>/dev/null || true
809
                sleep 2
810
            fi
811

            
812
            # Handle config-only mode
813
            if [[ "$CONFIG_ONLY" == true ]]; then
814
                log_info "⚙️  Configuration-only mode"
815
                if [[ ! -d "$INSTALL_DIR" ]]; then
816
                    log_error "autoSMART is not installed. Run full installation first."
817
                    exit 1
818
                fi
819
                create_configuration
820
                log_success "✅ Configuration updated successfully!"
821
                exit 0
822
            fi
823

            
824
            # Full installation
825
            install_dependencies
826
            create_directories
827
            copy_files
828
            create_configuration
829
            create_systemd_service
830
            test_database_connection
831
            test_smart_detection
832
            finalize_installation
833
            show_completion_message
834
            ;;
835
        *)
836
            log_error "Unknown command: $COMMAND"
837
            show_usage
838
            exit 1
839
            ;;
840
    esac
841
}
842

            
843
# Run main function
844
main "$@"