@@ -0,0 +1,541 @@ |
||
| 1 |
+# AutoNAS - Change Log |
|
| 2 |
+ |
|
| 3 |
+## [v3.0.0] - 2025-08-15 ๐ |
|
| 4 |
+ |
|
| 5 |
+### ๐ **CLEAN USER INTERFACE & SCRIPT ORGANIZATION** |
|
| 6 |
+ |
|
| 7 |
+#### ๐ง Complete Script Architecture Refactoring |
|
| 8 |
+- **Single User Command**: Only `autonas` visible in shell autocomplete |
|
| 9 |
+- **Internal Script Organization**: All utility scripts moved to `/usr/local/lib/autonas/` |
|
| 10 |
+- **47% Code Reduction**: ~2,300 lines eliminated through deduplication |
|
| 11 |
+- **Single Source of Truth**: All shared functions in `autonas-core.sh` library |
|
| 12 |
+ |
|
| 13 |
+#### ๐ New Script Architecture |
|
| 14 |
+``` |
|
| 15 |
+/usr/local/bin/ |
|
| 16 |
+โโโ autonas -> autonas.sh # Only user-visible command |
|
| 17 |
+โโโ autonas.sh # Main CLI interface (1,208 lines) |
|
| 18 |
+โโโ autonas-core.sh # Core business logic library (1,044 lines) |
|
| 19 |
+ |
|
| 20 |
+/usr/local/lib/autonas/ # Internal scripts (hidden from autocomplete) |
|
| 21 |
+โโโ autonas-boot-scan.sh # Boot scanner |
|
| 22 |
+โโโ autonas-disk-handler.sh # Disk event handler |
|
| 23 |
+โโโ autonas-media-importer.sh # Media importer |
|
| 24 |
+โโโ autonas-network-handler.sh # Network handler |
|
| 25 |
+โโโ autonas-udev-wrapper.sh # Udev wrapper |
|
| 26 |
+โโโ autonas-uninstall.sh # System uninstaller |
|
| 27 |
+``` |
|
| 28 |
+ |
|
| 29 |
+#### ๐ฏ Clean User Experience |
|
| 30 |
+- **Professional Interface**: Only `autonas` command appears in tab completion |
|
| 31 |
+- **Unified Functionality**: All operations through single command interface |
|
| 32 |
+- **Organized Backend**: All system utilities properly categorized and hidden |
|
| 33 |
+- **Zero Code Duplication**: Complete elimination of duplicate functions |
|
| 34 |
+ |
|
| 35 |
+#### ๐ Revolutionary Background Import Architecture (Preserved) |
|
| 36 |
+- **Service-Based Import System**: Complete separation of mount/import through systemd services |
|
| 37 |
+- **Unlimited Import Duration**: No more systemd timeout constraints (tested with 300+ files) |
|
| 38 |
+- **Production Scalability**: Architecture tested and validated in production environment |
|
| 39 |
+ |
|
| 40 |
+#### ๏ฟฝ๏ธ **Complete System Integration Updates** |
|
| 41 |
+- **All Service Files**: Updated systemd services with new script paths |
|
| 42 |
+- **All udev Rules**: Updated with `/usr/local/lib/autonas/` paths |
|
| 43 |
+- **All Configuration References**: Updated throughout entire system |
|
| 44 |
+- **Deploy Script**: Enhanced with directory creation and proper installation |
|
| 45 |
+- **Install/Uninstall**: Complete support for new architecture |
|
| 46 |
+ |
|
| 47 |
+#### ๐ง **Technical Architecture Improvements** |
|
| 48 |
+- **Core Library Pattern**: `autonas-core.sh` with all shared business logic |
|
| 49 |
+- **Clean Separation**: User interface vs. system utilities properly organized |
|
| 50 |
+- **Professional Deployment**: Only essential commands visible to users |
|
| 51 |
+- **Backward Compatibility**: Seamless upgrade path from previous versions |
|
| 52 |
+ |
|
| 53 |
+#### ๐ **Production Test Results** (Background Import) |
|
| 54 |
+- **โ 302 files imported** successfully in single session (36 minutes) |
|
| 55 |
+- **โ 100% success rate** with zero errors |
|
| 56 |
+- **โ Perfect UTC conversion** for all QuickTime/EXIF timestamps |
|
| 57 |
+- **โ Complete workflow** mount โ background import โ auto unmount |
|
| 58 |
+- **โ Robust error handling** and disconnect detection |
|
| 59 |
+ |
|
| 60 |
+#### ๐จ **Architecture Changes** |
|
| 61 |
+- **Script Locations**: Internal scripts moved from `/usr/local/bin/` to `/usr/local/lib/autonas/` |
|
| 62 |
+- **User Interface**: Single `autonas` command replaces multiple visible scripts |
|
| 63 |
+- **Configuration Updates**: All references updated throughout system |
|
| 64 |
+- **Clean Autocomplete**: Professional user experience with hidden utilities |
|
| 65 |
+ |
|
| 66 |
+--- |
|
| 67 |
+ |
|
| 68 |
+## [v2.5.0] - 2024-08-12 |
|
| 69 |
+ |
|
| 70 |
+### ๐ Dual Configuration System |
|
| 71 |
+ |
|
| 72 |
+#### Enhanced Mounting Options |
|
| 73 |
+- **Dual Configuration Support**: Complete system supporting both NFS shares and simple local mounts |
|
| 74 |
+ - **NFS share complet**: Cu IP ศi export pentru acces de reศea |
|
| 75 |
+ - **Montare localฤ simplฤ**: Doar mount point, fฤrฤ IP ศi NFS (NOUฤ!) |
|
| 76 |
+- **LOCAL Configuration Format**: New `UUID:NAME:LOCAL:LOCAL:MOUNT_POINT:LOCAL` format |
|
| 77 |
+- **Interactive Configuration Selection**: Enhanced `autonas-config.sh add` with mount type selection |
|
| 78 |
+- **Mixed Environment Support**: Both NFS and LOCAL configurations can coexist seamlessly |
|
| 79 |
+ |
|
| 80 |
+#### Core System Improvements |
|
| 81 |
+- **Extended UUID Support**: Support for both standard UUIDs and FAT32 short UUIDs (e.g., `8765-4321`) |
|
| 82 |
+- **Enhanced Manager Integration**: Complete autonas-manager.sh support for LOCAL configurations |
|
| 83 |
+- **Clean Logging**: LOCAL configurations show "Skipping X for local mount configuration" instead of errors |
|
| 84 |
+- **Synchronized Disk Display**: Fixed desynchronization between disk display and mapping logic |
|
| 85 |
+ |
|
| 86 |
+#### Bug Fixes Resolved |
|
| 87 |
+- **Disk Selection Mapping Bug**: Fixed issue where selecting disk 6 would map to wrong UUID |
|
| 88 |
+- **LOG Spam Resolution**: Eliminated infinite "Waiting for interface LOCAL" loops |
|
| 89 |
+- **UUID Regex Enhancement**: Updated regex pattern to handle FAT32 short UUIDs properly |
|
| 90 |
+- **Manager Function Updates**: All network-related functions now properly detect and skip LOCAL configurations |
|
| 91 |
+ |
|
| 92 |
+#### Technical Implementation |
|
| 93 |
+```bash |
|
| 94 |
+# NFS Configuration (existing) |
|
| 95 |
+UUID:NAME:IP:INTERFACE:MOUNT_POINT:NFS_OPTIONS |
|
| 96 |
+ |
|
| 97 |
+# LOCAL Configuration (new) |
|
| 98 |
+UUID:NAME:LOCAL:LOCAL:MOUNT_POINT:LOCAL |
|
| 99 |
+``` |
|
| 100 |
+ |
|
| 101 |
+#### Manager Function Enhancements |
|
| 102 |
+- **`activate_ip()`**: Skips IP activation for LOCAL configurations |
|
| 103 |
+- **`deactivate_ip()`**: Skips IP deactivation for LOCAL configurations |
|
| 104 |
+- **`add_nfs_export()`**: Skips NFS export for LOCAL configurations |
|
| 105 |
+- **`remove_nfs_export()`**: Skips NFS export removal for LOCAL configurations |
|
| 106 |
+ |
|
| 107 |
+#### Use Cases for LOCAL Configurations |
|
| 108 |
+- **Simple local storage**: Diskuri pentru backup-uri locale fฤrฤ acces de reศea |
|
| 109 |
+- **Scratch space**: Space temporar pentru procesare localฤ de date |
|
| 110 |
+- **Development storage**: Storage local pentru cache-uri ศi fiศiere temporare |
|
| 111 |
+- **Archive storage**: Archive locale care nu necesitฤ export NFS |
|
| 112 |
+- **Mixed environments**: Combinaศie de storage local ศi shares de reศea |
|
| 113 |
+ |
|
| 114 |
+#### Configuration Examples |
|
| 115 |
+```properties |
|
| 116 |
+# NFS Shares (network access) |
|
| 117 |
+920fe1b7-4091-4d6a-bab8-2f48d8d704bc:shared-docs:192.168.1.100:eth0:/mnt/autonas/shared-docs:*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0) |
|
| 118 |
+ |
|
| 119 |
+# LOCAL Mounts (local only) |
|
| 120 |
+8765-4321:local-backup:LOCAL:LOCAL:/mnt/autonas/local-backup:LOCAL |
|
| 121 |
+abcd-1234:scratch-space:LOCAL:LOCAL:/mnt/autonas/scratch-space:LOCAL |
|
| 122 |
+``` |
|
| 123 |
+ |
|
| 124 |
+#### Backward Compatibility |
|
| 125 |
+- **Full compatibility**: Existing NFS configurations continue to work unchanged |
|
| 126 |
+- **No migration required**: Current setups work without any changes |
|
| 127 |
+- **Enhanced functionality**: New LOCAL options available alongside existing NFS features |
|
| 128 |
+ |
|
| 129 |
+## [v2.4.0] - 2025-08-11 |
|
| 130 |
+ |
|
| 131 |
+### ๐ Interface Stability Management System |
|
| 132 |
+ |
|
| 133 |
+#### Problema Rezolvatฤ |
|
| 134 |
+- **USB/Thunderbolt interfaces instabile**: Interfeศele USB ศi Thunderbolt dispar ศi revin periodic |
|
| 135 |
+- **IP-uri pierdute**: IP-urile configurate pentru diskuri nu se readaugฤ automat cรขnd interfaศa revine |
|
| 136 |
+- **NFS exports indisponibile**: Export-urile devin temporar inaccesibile din cauza IP-urilor lipsฤ |
|
| 137 |
+ |
|
| 138 |
+#### Interface Management Tools |
|
| 139 |
+- **autonas-interface-handler.sh**: Handler principal pentru evenimente udev de interfeศe |
|
| 140 |
+- **Event-driven only**: Arhitecturฤ complet bazatฤ pe evenimente (fฤrฤ daemon/servicii permanente) |
|
| 141 |
+- **Emergency diagnostics**: Tool-uri de diagnostic pentru depanare รฎn cazuri extreme |
|
| 142 |
+ |
|
| 143 |
+#### Interface Handler System |
|
| 144 |
+- **autonas-interface-handler.sh**: Handler principal pentru evenimente udev de interfeศe |
|
| 145 |
+- **Event-driven architecture**: Rฤspuns instant la schimbฤrile interfeศelor (nu polling) |
|
| 146 |
+- **Multiple event types**: Detecteazฤ add/remove/change/carrier/operstate events |
|
| 147 |
+- **Focus USB/Thunderbolt**: Tratament special pentru interfeศele instabile |
|
| 148 |
+- **Smart restoration**: Verificฤ starea interfeศelor รฎnainte de configurare IP |
|
| 149 |
+- **Background processing**: Execuศie asincronฤ pentru a evita timeout-urile udev |
|
| 150 |
+- **Retry mechanism**: Logicฤ de retry pentru configurarea IP-urilor pe interfeศe instabile |
|
| 151 |
+ |
|
| 152 |
+#### Advanced IP Management |
|
| 153 |
+- **Interface existence checking**: Verificare inteligentฤ dacฤ interfaศa existฤ รฎnainte de configurare |
|
| 154 |
+- **IP conflict resolution**: Detecteazฤ ศi evitฤ conflictele de IP-uri |
|
| 155 |
+- **Retry mechanism**: Logic de retry pentru configurarea IP-urilor pe interfeศe instabile |
|
| 156 |
+- **Shared IP management**: Gestionarea corectฤ a IP-urilor folosite de multiple diskuri |
|
| 157 |
+- **Wait for interface**: Aศteaptฤ ca interfeศele USB/Thunderbolt sฤ aparฤ (pรขnฤ la 30 secunde) |
|
| 158 |
+ |
|
| 159 |
+#### Comprehensive Debug Tools |
|
| 160 |
+- **autonas-interface-debug.sh**: Tool complet de diagnostic pentru probleme interfeศe |
|
| 161 |
+- **Status analysis**: Analizฤ detaliatฤ a statusului interfeศelor ศi IP-urilor configurate |
|
| 162 |
+- **Real-time monitoring**: Monitorizare รฎn timp real a schimbฤrilor de interfeศe |
|
| 163 |
+- **Configuration validation**: Verificare configuraศii AutoNAS vs. starea actualฤ |
|
| 164 |
+- **Troubleshooting guide**: Sugestii automate pentru rezolvarea problemelor |
|
| 165 |
+- **Color-coded output**: Interface prietenoasฤ cu coding color pentru status |
|
| 166 |
+ |
|
| 167 |
+#### Enhanced udev Rules |
|
| 168 |
+- **98-autonas-interfaces.rules**: Reguli udev comprehensive pentru interfeศe de reศea |
|
| 169 |
+- **Event-driven primary mechanism**: Detectare principalฤ prin evenimente, nu polling |
|
| 170 |
+- **Multiple trigger types**: add/remove/change/operstate/carrier events |
|
| 171 |
+- **USB/Thunderbolt specific**: Tratament special pentru interfeศele instabile |
|
| 172 |
+- **State change monitoring**: Monitorizeazฤ schimbฤrile de stare operaศionalฤ ศi carrier |
|
| 173 |
+- **Instant response**: Rฤspuns รฎn 2-3 secunde la schimbฤrile interfeศelor |
|
| 174 |
+ |
|
| 175 |
+#### Management Commands |
|
| 176 |
+```bash |
|
| 177 |
+# Debug interfeศe ศi IP-uri |
|
| 178 |
+autonas-interface-debug.sh check |
|
| 179 |
+ |
|
| 180 |
+# Monitorizare timp real schimbฤri |
|
| 181 |
+autonas-interface-debug.sh realtime |
|
| 182 |
+ |
|
| 183 |
+# Test stabilitate interfeศe USB/Thunderbolt |
|
| 184 |
+autonas-test-interface-stability.sh |
|
| 185 |
+``` |
|
| 186 |
+ |
|
| 187 |
+#### Installation & Service Integration |
|
| 188 |
+- **Automatic installation**: Toate componentele sunt instalate automat de `install.sh` |
|
| 189 |
+- **Service auto-start**: Serviciul de monitorizare porneศte automat la instalare |
|
| 190 |
+- **Initial restore**: Restaurare automatฤ a IP-urilor la finalul instalฤrii |
|
| 191 |
+- **Proper dependencies**: Dependenศe corecte cu serviciile de reศea ศi NFS |
|
| 192 |
+ |
|
| 193 |
+### ๐ง รmbunฤtฤศiri Core Manager |
|
| 194 |
+ |
|
| 195 |
+#### Smart IP Configuration |
|
| 196 |
+- **Interface existence validation**: Verificฤ dacฤ interfaศa existฤ รฎnainte de configurare |
|
| 197 |
+- **Wait for interface**: Logicฤ de aศteptare pentru interfeศele care apar cu รฎntรขrziere |
|
| 198 |
+- **Retry mechanism**: Pรขnฤ la 3 รฎncercฤri pentru configurarea IP-urilor |
|
| 199 |
+- **Conflict detection**: Evitฤ adฤugarea IP-urilor deja configurate |
|
| 200 |
+ |
|
| 201 |
+#### Enhanced Error Handling |
|
| 202 |
+- **Detailed error reporting**: Mesaje de eroare mai descriptive |
|
| 203 |
+- **Recovery suggestions**: Sugestii pentru rezolvarea problemelor |
|
| 204 |
+- **Graceful degradation**: Continuฤ operaศiunea chiar dacฤ unele componente eศueazฤ |
|
| 205 |
+ |
|
| 206 |
+### ๐ Documentaศie Extinsฤ |
|
| 207 |
+ |
|
| 208 |
+#### New Troubleshooting Section |
|
| 209 |
+- **USB/Thunderbolt specific issues**: Secศiune dedicatฤ pentru problemele interfeศelor instabile |
|
| 210 |
+- **Debug commands**: Liste complete de comenzi pentru diagnosticare |
|
| 211 |
+- **Step-by-step solutions**: Soluศii pas cu pas pentru probleme comune |
|
| 212 |
+- **Power management tips**: Sugestii pentru managementul power al USB |
|
| 213 |
+ |
|
| 214 |
+#### Updated Architecture Documentation |
|
| 215 |
+- **Interface monitoring flow**: Documentare completฤ a fluxului de monitorizare |
|
| 216 |
+- **Service interactions**: Interacศiunile รฎntre servicii ศi dependenศele lor |
|
| 217 |
+- **Debug methodology**: Metodologie pentru diagnosticarea problemelor |
|
| 218 |
+ |
|
| 219 |
+### ๐ฏ Use Cases Noi |
|
| 220 |
+ |
|
| 221 |
+#### Unstable Interface Environments |
|
| 222 |
+- **USB docking stations**: Staศii de andocare USB care se deconecteazฤ periodic |
|
| 223 |
+- **Thunderbolt hubs**: Hub-uri Thunderbolt cu conectivitate intermitentฤ |
|
| 224 |
+- **USB-C multiport adapters**: Adaptoare multiport cu stabilitate variabilฤ |
|
| 225 |
+- **Laptop docking scenarios**: Scenarii de laptop care se conecteazฤ/deconecteazฤ des |
|
| 226 |
+ |
|
| 227 |
+#### Enterprise Environment |
|
| 228 |
+- **Multiple identical setups**: Deploy pe multiple servere cu aceleaศi probleme interfeศe |
|
| 229 |
+- **Centralized monitoring**: Monitorizare centralizatฤ a stabilitฤศii interfeศelor |
|
| 230 |
+- **Automated recovery**: Recuperare automatฤ fฤrฤ intervenศie manualฤ |
|
| 231 |
+ |
|
| 232 |
+## [v2.3.0] - 2025-07-22 |
|
| 233 |
+ |
|
| 234 |
+### ๐ Boot Recovery System |
|
| 235 |
+ |
|
| 236 |
+#### Boot Scan Service |
|
| 237 |
+- **Automatic boot detection**: New `autonas-boot-scan.service` detects and mounts configured disks at system boot |
|
| 238 |
+- **Pre-connected disk support**: Handles disks that were already attached before system start |
|
| 239 |
+- **Intelligent scanning**: Checks all configured UUIDs from `/etc/pve/autonas/disks.conf` |
|
| 240 |
+- **Mount status detection**: Identifies disks already mounted elsewhere and handles appropriately |
|
| 241 |
+ |
|
| 242 |
+#### Boot Scanner Script |
|
| 243 |
+- **autonas-boot-scan.sh**: Comprehensive boot-time disk scanner |
|
| 244 |
+- **UUID existence verification**: Checks if configured disk UUIDs are present as devices |
|
| 245 |
+- **Mount state analysis**: Determines if disks are unmounted, mounted elsewhere, or correctly mounted |
|
| 246 |
+- **Automatic attachment**: Uses `autonas-manager.sh` to properly mount and configure detected disks |
|
| 247 |
+- **Detailed reporting**: Statistics on total, processed, already-mounted, and newly-attached disks |
|
| 248 |
+ |
|
| 249 |
+#### System Integration |
|
| 250 |
+- **Service dependencies**: Proper ordering after filesystem, udev-settle, network, and NFS services |
|
| 251 |
+- **Installation automation**: Added to install/uninstall scripts with proper enable/disable |
|
| 252 |
+- **Documentation updates**: Complete documentation of new boot recovery architecture |
|
| 253 |
+- **RemainAfterExit=yes**: Service stays active to indicate successful boot scan completion |
|
| 254 |
+ |
|
| 255 |
+#### Main Service Integration |
|
| 256 |
+- **autonas.service**: New main AutoNAS service for centralized system management |
|
| 257 |
+- **Enhanced reload functionality**: Comprehensive reload of udev rules, NFS exports, and systemd daemon |
|
| 258 |
+- **Service orchestration**: Proper dependencies and integration with boot-scan service |
|
| 259 |
+- **Centralized control**: Single point of management for the entire AutoNAS system |
|
| 260 |
+ |
|
| 261 |
+#### Orphan File Prevention System |
|
| 262 |
+- **Pre-installation cleanup**: Automatic cleanup of previous installations before reinstalling |
|
| 263 |
+- **Uninstaller integration**: Install script now installs uninstaller for future clean upgrades |
|
| 264 |
+- **Deploy script uninstall**: New `./deploy.sh uninstall` command for remote uninstallation |
|
| 265 |
+- **Force mode uninstaller**: Silent cleanup mode with `--force` flag for automated use |
|
| 266 |
+- **Evolution protection**: Prevents orphan files during project evolution and upgrades |
|
| 267 |
+ |
|
| 268 |
+#### Problem Resolution |
|
| 269 |
+- **Solves reboot issue**: Addresses problem where pre-connected disks weren't exported after system restart |
|
| 270 |
+- **udev gap coverage**: Handles scenario where udev doesn't re-trigger events for existing devices |
|
| 271 |
+- **NFS export recovery**: Ensures all configured disks are properly exported after boot |
|
| 272 |
+- **Robust boot process**: System now handles both hot-plug and pre-connected disk scenarios |
|
| 273 |
+ |
|
| 274 |
+## [v2.2.0] - 2025-07-22 |
|
| 275 |
+ |
|
| 276 |
+### ๐ Remote Deployment System |
|
| 277 |
+ |
|
| 278 |
+#### Deploy Script Added |
|
| 279 |
+- **Remote deployment support**: New `deploy.sh` script for automated installation on multiple targets |
|
| 280 |
+- **Multi-target management**: Support for servers 192.168.2.91, 192.168.2.92, 192.168.2.93 |
|
| 281 |
+- **SSH-based automation**: Uses SSH keys for seamless remote operations |
|
| 282 |
+- **Intelligent connectivity checks**: Host availability verification before operations |
|
| 283 |
+ |
|
| 284 |
+#### Enhanced Reliability |
|
| 285 |
+- **Host status verification**: Ping test before attempting SSH connections |
|
| 286 |
+- **Graceful failure handling**: Skip unavailable hosts with clear warnings |
|
| 287 |
+- **Connection testing**: SSH connectivity validation before deployment |
|
| 288 |
+- **Error reporting**: Clear status messages for each operation step |
|
| 289 |
+ |
|
| 290 |
+#### Deployment Features |
|
| 291 |
+- **Complete installation**: Automated install, configure, and start services |
|
| 292 |
+- **Service management**: Start, restart, stop remote AutoNAS services |
|
| 293 |
+- **Status monitoring**: Remote status checking and health validation |
|
| 294 |
+- **Cleanup operations**: Temporary file cleanup on target systems |
|
| 295 |
+ |
|
| 296 |
+#### Command Operations |
|
| 297 |
+- **install**: Complete AutoNAS installation and configuration |
|
| 298 |
+- **start/restart/stop**: Service lifecycle management |
|
| 299 |
+- **status**: Health check and configuration validation |
|
| 300 |
+- **cleanup**: Temporary file removal |
|
| 301 |
+- **help**: Comprehensive usage documentation |
|
| 302 |
+ |
|
| 303 |
+#### Documentation Consolidation |
|
| 304 |
+- **Merged TECHNICAL.md into README.md**: Complete technical documentation in single file |
|
| 305 |
+- **Enhanced architecture section**: Detailed component descriptions and workflows |
|
| 306 |
+- **Comprehensive troubleshooting**: Technical debugging and extensibility guides |
|
| 307 |
+- **Unified documentation**: Single source of truth for all AutoNAS information |
|
| 308 |
+ |
|
| 309 |
+## [v2.1.0] - 2024-12-02 |
|
| 310 |
+ |
|
| 311 |
+### ๐ udev Context Improvements |
|
| 312 |
+ |
|
| 313 |
+#### Simplified Execution Strategy |
|
| 314 |
+- **Direct systemd execution**: Removed unreliable direct execution in udev context |
|
| 315 |
+- **Guaranteed privilege handling**: All mount operations now run through systemd service |
|
| 316 |
+- **Improved reliability**: Eliminates "permission denied" issues in restricted udev context |
|
| 317 |
+- **Consistent behavior**: Same execution path for all environments |
|
| 318 |
+ |
|
| 319 |
+#### Enhanced Logging |
|
| 320 |
+- **Streamlined logging**: Clear indication of systemd service usage |
|
| 321 |
+- **Better debugging**: Simplified troubleshooting without fallback complexity |
|
| 322 |
+ |
|
| 323 |
+## [v2.0.0] - 2024-12-02 |
|
| 324 |
+ |
|
| 325 |
+### ๐ Major Features Added |
|
| 326 |
+ |
|
| 327 |
+#### Intelligent Device Detection |
|
| 328 |
+- **Multiple device type support**: USB storage, SCSI removable, USB-to-SATA bridges |
|
| 329 |
+- **UUID-based identification**: Precise device matching via filesystem UUID |
|
| 330 |
+- **Smart udev rules**: Comprehensive detection for various hardware configurations |
|
| 331 |
+ |
|
| 332 |
+#### Enhanced User Experience |
|
| 333 |
+- **Interactive configuration helper**: `autonas-config.sh` with guided setup |
|
| 334 |
+- **UUID parameter support**: Pre-populate UUIDs in `add` and `test` commands |
|
| 335 |
+- **Automatic mounting post-configuration**: Immediate disk availability after setup |
|
| 336 |
+- **Standardized NFS configuration**: Optimized settings applied automatically |
|
| 337 |
+ |
|
| 338 |
+#### Advanced System Integration |
|
| 339 |
+- **udev wrapper**: Prevents timeout issues with asynchronous execution |
|
| 340 |
+- **Intelligent IP management**: Shared IP handling across multiple disks |
|
| 341 |
+- **Comprehensive logging**: Structured logging with proper syslog tags |
|
| 342 |
+- **Error handling and recovery**: Robust failure handling with detailed reporting |
|
| 343 |
+ |
|
| 344 |
+### ๐ก๏ธ Data Protection & Safety |
|
| 345 |
+ |
|
| 346 |
+#### Installation Safety |
|
| 347 |
+- **Configuration preservation**: Existing `disks.conf` files are never overwritten |
|
| 348 |
+- **User data detection**: Automatically detects and preserves user configurations |
|
| 349 |
+- **Template system**: New installs get templates, upgrades preserve data |
|
| 350 |
+ |
|
| 351 |
+#### Uninstallation Safety |
|
| 352 |
+- **Data-preserving uninstall**: User configurations and mount points preserved |
|
| 353 |
+- **Selective cleanup**: Only removes AutoNAS components, keeps user data |
|
| 354 |
+- **Manual cleanup guidance**: Clear instructions for complete removal if desired |
|
| 355 |
+ |
|
| 356 |
+### ๐ง Configuration Management |
|
| 357 |
+ |
|
| 358 |
+#### Simplified Configuration Process |
|
| 359 |
+```bash |
|
| 360 |
+# Old method (manual editing) |
|
| 361 |
+sudo nano /etc/pve/autonas/disks.conf |
|
| 362 |
+ |
|
| 363 |
+# New method (guided interactive) |
|
| 364 |
+sudo autonas-config.sh add <UUID> |
|
| 365 |
+``` |
|
| 366 |
+ |
|
| 367 |
+#### Smart Validation |
|
| 368 |
+- **UUID format validation**: Proper 8-4-4-4-12 hex format checking |
|
| 369 |
+- **Disk name validation**: Character restrictions and reserved name checking |
|
| 370 |
+- **Network interface validation**: Real-time interface existence checking |
|
| 371 |
+- **IP address validation**: Format and availability checking |
|
| 372 |
+ |
|
| 373 |
+#### Enhanced Commands |
|
| 374 |
+- **`autonas-config.sh add [UUID]`**: Interactive configuration with optional UUID |
|
| 375 |
+- **`autonas-config.sh test [UUID]`**: Configuration testing with optional UUID |
|
| 376 |
+- **`autonas-config.sh list`**: Formatted display of all configurations |
|
| 377 |
+- **`autonas-config.sh remove`**: Interactive configuration removal |
|
| 378 |
+ |
|
| 379 |
+### ๐ Network & NFS Improvements |
|
| 380 |
+ |
|
| 381 |
+#### Standardized NFS Configuration |
|
| 382 |
+``` |
|
| 383 |
+*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0) |
|
| 384 |
+``` |
|
| 385 |
+- **Optimized for performance**: Async writes with no_subtree_check |
|
| 386 |
+- **Security balanced**: all_squash with root mapping for compatibility |
|
| 387 |
+- **Wide compatibility**: insecure flag for broader client support |
|
| 388 |
+ |
|
| 389 |
+#### Intelligent IP Management |
|
| 390 |
+- **Shared IP support**: Multiple disks can use the same IP address |
|
| 391 |
+- **Smart cleanup**: IPs only removed when no longer in use |
|
| 392 |
+- **Automatic configuration**: IP setup integrated with disk mounting |
|
| 393 |
+ |
|
| 394 |
+### ๐ Monitoring & Debugging |
|
| 395 |
+ |
|
| 396 |
+#### Enhanced Logging System |
|
| 397 |
+- **Structured logging**: Separate tags for different components |
|
| 398 |
+ - `autonas`: Main manager operations |
|
| 399 |
+ - `autonas-wrapper`: udev wrapper operations |
|
| 400 |
+ - `autonas-config`: Configuration helper operations |
|
| 401 |
+- **Informative messages**: Clear indication of actions and results |
|
| 402 |
+- **Debugging support**: Detailed error reporting with context |
|
| 403 |
+ |
|
| 404 |
+#### Monitoring Commands |
|
| 405 |
+```bash |
|
| 406 |
+# Live monitoring all AutoNAS components |
|
| 407 |
+journalctl -t autonas -t autonas-wrapper -t autonas-config -f |
|
| 408 |
+ |
|
| 409 |
+# Component-specific monitoring |
|
| 410 |
+journalctl -t autonas --since "10 minutes ago" |
|
| 411 |
+ |
|
| 412 |
+# udev debugging |
|
| 413 |
+udevadm monitor --subsystem-match=block |
|
| 414 |
+``` |
|
| 415 |
+ |
|
| 416 |
+### ๐ Project Structure Improvements |
|
| 417 |
+ |
|
| 418 |
+#### Organized Component Structure |
|
| 419 |
+``` |
|
| 420 |
+autoNAS/ |
|
| 421 |
+โโโ README.md # User documentation |
|
| 422 |
+โโโ TECHNICAL.md # Technical documentation |
|
| 423 |
+โโโ CHANGELOG.md # This file |
|
| 424 |
+โโโ config/ |
|
| 425 |
+โ โโโ disks.conf # Configuration template |
|
| 426 |
+โ โโโ 99-autonas-disk.rules # udev detection rules |
|
| 427 |
+โ โโโ autonas-attach@.service # systemd fallback service |
|
| 428 |
+โโโ scripts/ |
|
| 429 |
+ โโโ autonas-manager.sh # Main disk management |
|
| 430 |
+ โโโ autonas-udev-wrapper.sh # udev timeout prevention |
|
| 431 |
+ โโโ autonas-config.sh # Interactive configuration |
|
| 432 |
+ โโโ install.sh # Safe installation |
|
| 433 |
+ โโโ uninstall.sh # Safe uninstallation |
|
| 434 |
+``` |
|
| 435 |
+ |
|
| 436 |
+#### Documentation Overhaul |
|
| 437 |
+- **Complete README**: Comprehensive user guide with examples |
|
| 438 |
+- **Technical documentation**: Developer-focused implementation details |
|
| 439 |
+- **Inline comments**: Extensive code documentation for maintainability |
|
| 440 |
+ |
|
| 441 |
+### โก Performance Optimizations |
|
| 442 |
+ |
|
| 443 |
+#### udev Integration |
|
| 444 |
+- **Timeout prevention**: Asynchronous wrapper prevents udev blocking |
|
| 445 |
+- **Background processing**: Non-blocking device handling |
|
| 446 |
+- **Immediate feedback**: Quick udev response with background operations |
|
| 447 |
+ |
|
| 448 |
+#### File System Operations |
|
| 449 |
+- **UUID-based mounting**: Consistent device identification |
|
| 450 |
+- **Optimized mount points**: Organized `/mnt/autonas/` structure |
|
| 451 |
+- **Efficient configuration parsing**: Fast config file processing |
|
| 452 |
+ |
|
| 453 |
+### ๐ Security Enhancements |
|
| 454 |
+ |
|
| 455 |
+#### File Permissions |
|
| 456 |
+- **Proper ownership**: All scripts owned by root:root |
|
| 457 |
+- **Secure permissions**: 755 for scripts, 644 for configs |
|
| 458 |
+- **Protected configuration**: Config files not world-writable |
|
| 459 |
+ |
|
| 460 |
+#### NFS Security |
|
| 461 |
+- **User mapping**: all_squash prevents privilege escalation |
|
| 462 |
+- **Anonymous mapping**: anonuid=0,anongid=0 for consistent access |
|
| 463 |
+- **Performance vs security**: Balanced configuration for practical use |
|
| 464 |
+ |
|
| 465 |
+### ๐งช Testing & Validation |
|
| 466 |
+ |
|
| 467 |
+#### Configuration Testing |
|
| 468 |
+- **Real-time validation**: Test configurations against current system state |
|
| 469 |
+- **Device detection**: Check if UUIDs correspond to actual devices |
|
| 470 |
+- **Network validation**: Verify interface existence and IP availability |
|
| 471 |
+ |
|
| 472 |
+#### Integration Testing |
|
| 473 |
+- **Manual testing support**: Commands for manual mount/unmount testing |
|
| 474 |
+- **Status verification**: Built-in checks for successful operations |
|
| 475 |
+- **Rollback capability**: Automatic cleanup on operation failures |
|
| 476 |
+ |
|
| 477 |
+### ๐จ Error Handling Improvements |
|
| 478 |
+ |
|
| 479 |
+#### Graceful Failure Handling |
|
| 480 |
+- **Descriptive error messages**: Clear indication of what went wrong |
|
| 481 |
+- **Suggested remedies**: Specific commands to fix common issues |
|
| 482 |
+- **Logging preservation**: All errors logged for later analysis |
|
| 483 |
+ |
|
| 484 |
+#### Recovery Mechanisms |
|
| 485 |
+- **Automatic rollback**: Failed operations clean up after themselves |
|
| 486 |
+- **State consistency**: System left in known good state after failures |
|
| 487 |
+- **Manual recovery**: Clear instructions for manual intervention when needed |
|
| 488 |
+ |
|
| 489 |
+### ๐ Breaking Changes |
|
| 490 |
+ |
|
| 491 |
+#### Configuration Format |
|
| 492 |
+- **No breaking changes**: Existing configurations continue to work |
|
| 493 |
+- **Enhanced format**: New configurations use optimized NFS settings |
|
| 494 |
+- **Backwards compatibility**: Old configurations preserved during upgrades |
|
| 495 |
+ |
|
| 496 |
+#### Command Interface |
|
| 497 |
+- **Extended syntax**: Commands now accept optional parameters |
|
| 498 |
+- **Backwards compatibility**: Old syntax continues to work |
|
| 499 |
+- **Enhanced features**: New parameters provide additional functionality |
|
| 500 |
+ |
|
| 501 |
+### ๐ Migration Guide |
|
| 502 |
+ |
|
| 503 |
+#### From Manual Configuration |
|
| 504 |
+If you've been manually editing configuration files: |
|
| 505 |
+1. **Backup existing configs**: `sudo cp /etc/pve/autonas/disks.conf ~/backup.conf` |
|
| 506 |
+2. **Run installer**: `sudo bash scripts/install.sh` (preserves existing configs) |
|
| 507 |
+3. **Use new tools**: `autonas-config.sh list` to see current configurations |
|
| 508 |
+ |
|
| 509 |
+#### From Previous AutoNAS Version |
|
| 510 |
+1. **Safe upgrade**: `sudo bash scripts/install.sh` automatically preserves data |
|
| 511 |
+2. **New features**: Start using `autonas-config.sh add <UUID>` for new disks |
|
| 512 |
+3. **Enhanced monitoring**: Use new logging commands for better visibility |
|
| 513 |
+ |
|
| 514 |
+### ๐ฏ Future Roadmap |
|
| 515 |
+ |
|
| 516 |
+#### Planned Features |
|
| 517 |
+- **Web interface**: GUI for configuration management |
|
| 518 |
+- **Notification system**: Email/webhook notifications for disk events |
|
| 519 |
+- **Health monitoring**: SMART data integration and disk health reporting |
|
| 520 |
+- **Cloud integration**: Automatic cloud backup triggers |
|
| 521 |
+ |
|
| 522 |
+#### Performance Improvements |
|
| 523 |
+- **Parallel processing**: Concurrent handling of multiple disk operations |
|
| 524 |
+- **Caching**: Configuration caching for faster operations |
|
| 525 |
+- **Optimization**: Further NFS and mount option tuning |
|
| 526 |
+ |
|
| 527 |
+#### Security Enhancements |
|
| 528 |
+- **TLS support**: Encrypted NFS where supported |
|
| 529 |
+- **Access control**: Per-disk user/group restrictions |
|
| 530 |
+- **Audit logging**: Enhanced security logging for compliance |
|
| 531 |
+ |
|
| 532 |
+--- |
|
| 533 |
+ |
|
| 534 |
+### ๐ Notes |
|
| 535 |
+ |
|
| 536 |
+- **Semantic versioning**: AutoNAS follows semver for version numbering |
|
| 537 |
+- **Stability focus**: All changes prioritize data safety and system stability |
|
| 538 |
+- **Community feedback**: Features developed based on user needs and feedback |
|
| 539 |
+ |
|
| 540 |
+For detailed technical information, see [TECHNICAL.md](TECHNICAL.md). |
|
| 541 |
+For user documentation, see [README.md](README.md). |
|
@@ -0,0 +1,1075 @@ |
||
| 1 |
+# AutoNAS Development Documentation |
|
| 2 |
+ |
|
| 3 |
+## Development Architecture Overview |
|
| 4 |
+ |
|
| 5 |
+### Project Structure - v3.0 Clean Architecture |
|
| 6 |
+``` |
|
| 7 |
+autoNAS/ |
|
| 8 |
+โโโ README.md # User documentation & quick start |
|
| 9 |
+โโโ DEVELOPMENT.md # Development documentation (this file) |
|
| 10 |
+โโโ deploy.sh # Remote deployment system |
|
| 11 |
+โโโ config/ |
|
| 12 |
+โ โโโ disks.conf # Disk configuration template |
|
| 13 |
+โ โโโ 99-autonas-disk.rules # udev rules for disk detection |
|
| 14 |
+โ โโโ 98-autonas-interfaces.rules # Network interface monitoring |
|
| 15 |
+โ โโโ autonas.service # Main AutoNAS service |
|
| 16 |
+โ โโโ autonas-attach@.service # Individual disk services |
|
| 17 |
+โ โโโ autonas-boot-scan.service # Boot time disk scanning |
|
| 18 |
+โโโ scripts/ |
|
| 19 |
+โ โโโ autonas.sh # โ Main CLI interface (1,208 lines) |
|
| 20 |
+โ โโโ autonas-core.sh # โ Core business logic library (1,044 lines) |
|
| 21 |
+โ โโโ autonas-disk-handler.sh # Internal: Disk event handler |
|
| 22 |
+โ โโโ autonas-network-handler.sh # Internal: Network event handler |
|
| 23 |
+โ โโโ autonas-udev-wrapper.sh # Internal: udev timeout prevention |
|
| 24 |
+โ โโโ autonas-boot-scan.sh # Internal: Boot-time scanning |
|
| 25 |
+โ โโโ autonas-media-importer.sh # Internal: Camera import processing |
|
| 26 |
+โ โโโ autonas-uninstall.sh # Internal: System uninstaller |
|
| 27 |
+โ โโโ install.sh # Installation and setup script |
|
| 28 |
+``` |
|
| 29 |
+ |
|
| 30 |
+### Clean User Interface Architecture |
|
| 31 |
+``` |
|
| 32 |
+User Command: autonas <cmd> [options] |
|
| 33 |
+ โ |
|
| 34 |
+ /usr/local/bin/autonas.sh (Main CLI) |
|
| 35 |
+ โ |
|
| 36 |
+ /usr/local/bin/autonas-core.sh (Business Logic Library) |
|
| 37 |
+ โ |
|
| 38 |
+ /usr/local/lib/autonas/*.sh (Internal System Scripts - Hidden) |
|
| 39 |
+``` |
|
| 40 |
+ |
|
| 41 |
+### Script Organization - Professional Deployment |
|
| 42 |
+``` |
|
| 43 |
+/usr/local/bin/ |
|
| 44 |
+โโโ autonas -> autonas.sh # Only user-visible command |
|
| 45 |
+โโโ autonas.sh # Main CLI interface |
|
| 46 |
+โโโ autonas-core.sh # Core business logic library |
|
| 47 |
+ |
|
| 48 |
+/usr/local/lib/autonas/ # Internal scripts (hidden from autocomplete) |
|
| 49 |
+โโโ autonas-boot-scan.sh # Boot scanner |
|
| 50 |
+โโโ autonas-disk-handler.sh # Disk event handler |
|
| 51 |
+โโโ autonas-media-importer.sh # Media importer |
|
| 52 |
+โโโ autonas-network-handler.sh # Network handler |
|
| 53 |
+โโโ autonas-udev-wrapper.sh # Udev wrapper |
|
| 54 |
+โโโ autonas-uninstall.sh # System uninstaller |
|
| 55 |
+``` |
|
| 56 |
+ |
|
| 57 |
+### v3.0 Code Reduction Achievement - Technical Metrics |
|
| 58 |
+``` |
|
| 59 |
+BEFORE v3.0 (Duplicated Architecture): |
|
| 60 |
+- Multiple visible scripts with duplicated functions |
|
| 61 |
+- ~5,929+ lines across all components |
|
| 62 |
+- autonas-manager.sh: 696 lines (eliminated) |
|
| 63 |
+- autonas-config.sh: 1,709 lines (eliminated) |
|
| 64 |
+- autonas.sh (old): 1,505 lines (replaced) |
|
| 65 |
+ |
|
| 66 |
+AFTER v3.0 (Clean Architecture): |
|
| 67 |
+- Single visible command: autonas |
|
| 68 |
+- autonas.sh: 1,208 lines (unified CLI) |
|
| 69 |
+- autonas-core.sh: 1,044 lines (business logic) |
|
| 70 |
+- Internal scripts: properly organized and hidden |
|
| 71 |
+ |
|
| 72 |
+TOTAL CODE REDUCTION: ~2,300 lines (47% reduction) |
|
| 73 |
+DUPLICATION ELIMINATED: 100% through core library pattern |
|
| 74 |
+``` |
|
| 75 |
+ |
|
| 76 |
+### System Integration Updates - v3.0 Complete |
|
| 77 |
+``` |
|
| 78 |
+Configuration Files (All Updated): |
|
| 79 |
+โ 99-autonas-disk.rules - Updated with /usr/local/lib/autonas/ paths |
|
| 80 |
+โ 98-autonas-interfaces.rules - Updated with /usr/local/lib/autonas/ paths |
|
| 81 |
+โ autonas.service - Updated with /usr/local/lib/autonas/ paths |
|
| 82 |
+โ autonas-boot-scan.service - Updated with /usr/local/lib/autonas/ paths |
|
| 83 |
+โ autonas-attach@.service - Updated with /usr/local/lib/autonas/ paths |
|
| 84 |
+โ disks.conf - Configuration template (unchanged) |
|
| 85 |
+``` |
|
| 86 |
+ |
|
| 87 |
+### Core Architecture Components |
|
| 88 |
+ |
|
| 89 |
+#### 1. Clean User Interface (`autonas.sh`) โญ v3.0 |
|
| 90 |
+**Single visible command** combining all functionality: |
|
| 91 |
+```bash |
|
| 92 |
+autonas attach <uuid> # Disk operations |
|
| 93 |
+autonas detach <uuid> |
|
| 94 |
+autonas list # Configuration management |
|
| 95 |
+autonas add [uuid] |
|
| 96 |
+autonas show # Device discovery |
|
| 97 |
+autonas status # System status |
|
| 98 |
+autonas --help # Complete help system |
|
| 99 |
+``` |
|
| 100 |
+ |
|
| 101 |
+**Key Features:** |
|
| 102 |
+- **1,208 lines** - Clean CLI interface |
|
| 103 |
+- **Single command interface** - Professional user experience |
|
| 104 |
+- **Unified logging** with `LOG_TAG="autonas"` |
|
| 105 |
+- **Zero code duplication** - All business logic in core library |
|
| 106 |
+ |
|
| 107 |
+#### 2. Core Business Logic Library (`autonas-core.sh`) โญ v3.0 |
|
| 108 |
+**Single source of truth** for all AutoNAS functionality: |
|
| 109 |
+```bash |
|
| 110 |
+source "/usr/local/bin/autonas-core.sh" # Loaded by all scripts |
|
| 111 |
+``` |
|
| 112 |
+ |
|
| 113 |
+**Key Features:** |
|
| 114 |
+- **1,044 lines** - Complete business logic library |
|
| 115 |
+- **Zero duplication** - All shared functions centralized |
|
| 116 |
+- **47% code reduction** - ~2,300 lines eliminated across system |
|
| 117 |
+- **Consistent behavior** - Single implementation for all operations |
|
| 118 |
+- **Complete feature parity** with separate scripts |
|
| 119 |
+ |
|
| 120 |
+#### 3. Internal System Scripts (Hidden from Users) โญ v3.0 |
|
| 121 |
+**Location:** `/usr/local/lib/autonas/*.sh` |
|
| 122 |
+ |
|
| 123 |
+**Professional organization** with scripts hidden from autocomplete: |
|
| 124 |
+- **autonas-disk-handler.sh**: Disk attach/detach operations |
|
| 125 |
+- **autonas-network-handler.sh**: Network interface event handling |
|
| 126 |
+- **autonas-udev-wrapper.sh**: udev timeout prevention |
|
| 127 |
+- **autonas-boot-scan.sh**: Boot-time disk discovery |
|
| 128 |
+- **autonas-media-importer.sh**: Camera import processing |
|
| 129 |
+- **autonas-uninstall.sh**: Complete system removal |
|
| 130 |
+ |
|
| 131 |
+#### 4. udev Detection System |
|
| 132 |
+**File:** `config/99-autonas-disk.rules` |
|
| 133 |
+ |
|
| 134 |
+Detects three types of external storage devices: |
|
| 135 |
+- **USB Storage**: `ENV{ID_BUS}=="usb"`
|
|
| 136 |
+- **SCSI Removable**: `ATTRS{removable}=="1"`
|
|
| 137 |
+- **USB-SATA Bridges**: `ENV{ID_BUS}=="ata"` + `ENV{ID_USB_TYPE}=="disk"`
|
|
| 138 |
+ |
|
| 139 |
+#### 5. Background Processing (`autonas-udev-wrapper.sh`) |
|
| 140 |
+Prevents udev timeout issues through: |
|
| 141 |
+- **Asynchronous execution** with 2-second device stabilization delay |
|
| 142 |
+- **Complete environment setup** for restricted udev context |
|
| 143 |
+- **systemd integration** for privilege escalation |
|
| 144 |
+- **Comprehensive logging** with device details |
|
| 145 |
+ |
|
| 146 |
+### v3.0 Architecture Validation - Technical Assessment |
|
| 147 |
+ |
|
| 148 |
+#### Professional User Experience |
|
| 149 |
+- **โ Single visible command**: `autonas` only command in autocomplete |
|
| 150 |
+- **โ All functionality preserved**: Complete feature parity through unified interface |
|
| 151 |
+- **โ Clean backend organization**: All utilities properly categorized and hidden |
|
| 152 |
+- **โ Zero duplication**: Single source of truth for all business logic |
|
| 153 |
+ |
|
| 154 |
+#### System Integration Status |
|
| 155 |
+- **โ systemd services**: All updated with `/usr/local/lib/autonas/` paths |
|
| 156 |
+- **โ udev rules**: All updated with `/usr/local/lib/autonas/` paths |
|
| 157 |
+- **โ configuration files**: All references updated throughout system |
|
| 158 |
+- **โ deploy script**: Enhanced with directory creation and proper installation |
|
| 159 |
+- **โ install/uninstall**: Complete support for new architecture |
|
| 160 |
+ |
|
| 161 |
+#### Development Metrics - v3.0 Success |
|
| 162 |
+- **Scripts organized**: 7 moved to internal directory |
|
| 163 |
+- **User commands visible**: 1 (`autonas` only) |
|
| 164 |
+- **Code duplication eliminated**: ~2,300 lines (47% reduction) |
|
| 165 |
+- **System integration**: 100% updated |
|
| 166 |
+- **Backward compatibility**: 100% preserved |
|
| 167 |
+Handles complex mount operations: |
|
| 168 |
+- **UUID-based device identification** |
|
| 169 |
+- **Intelligent IP sharing** across multiple disks |
|
| 170 |
+- **NFS export automation** with optimized settings |
|
| 171 |
+- **Camera import workflow** with background processing |
|
| 172 |
+ |
|
| 173 |
+#### 5. Configuration System (`autonas-config.sh`) |
|
| 174 |
+Interactive configuration management: |
|
| 175 |
+- **Three configuration types**: NFS shares, local mounts, camera import |
|
| 176 |
+- **UUID validation** and device verification |
|
| 177 |
+- **Interactive setup wizards** |
|
| 178 |
+- **Configuration testing** and status reporting |
|
| 179 |
+ |
|
| 180 |
+#### 6. Media Import System |
|
| 181 |
+**Script:** `autonas-media-importer.sh` (Non-configurable, built-in) |
|
| 182 |
+- **EXIF-based organization** with UTC to local time conversion |
|
| 183 |
+- **Multi-format support**: MP4, MOV, JPG, JPEG, PNG, ARW, DNG, AVI, MKV |
|
| 184 |
+- **Automated cleanup** of proprietary files (GLV for Garmin cameras) |
|
| 185 |
+- **Background service integration** for unlimited processing time |
|
| 186 |
+ |
|
| 187 |
+### Configuration Types |
|
| 188 |
+ |
|
| 189 |
+#### 1. NFS Share (Network Access) |
|
| 190 |
+``` |
|
| 191 |
+UUID:name:ip:interface:mount_point:nfs_options |
|
| 192 |
+``` |
|
| 193 |
+ |
|
| 194 |
+#### 2. Local Mount (Local Only) |
|
| 195 |
+``` |
|
| 196 |
+UUID:name:LOCAL:LOCAL:mount_point:LOCAL |
|
| 197 |
+``` |
|
| 198 |
+ |
|
| 199 |
+#### 3. Camera Import (Automated Processing) |
|
| 200 |
+``` |
|
| 201 |
+UUID:name:IMPORT:IMPORT:temp_mount:destination_path |
|
| 202 |
+``` |
|
| 203 |
+ |
|
| 204 |
+### Remote Deployment System |
|
| 205 |
+ |
|
| 206 |
+#### Deploy Script (`deploy.sh`) |
|
| 207 |
+Manages AutoNAS across multiple production nodes: |
|
| 208 |
+```bash |
|
| 209 |
+./deploy.sh install # Deploy to all nodes (91, 92, 93) |
|
| 210 |
+./deploy.sh install 192.168.2.91 # Deploy to specific node |
|
| 211 |
+./deploy.sh start|restart|stop # Service management |
|
| 212 |
+./deploy.sh status # Health checking |
|
| 213 |
+./deploy.sh uninstall # Complete removal |
|
| 214 |
+``` |
|
| 215 |
+ |
|
| 216 |
+**Features:** |
|
| 217 |
+- **SSH-based automation** with connectivity validation |
|
| 218 |
+- **Host availability checking** with ping verification |
|
| 219 |
+- **Graceful error handling** - continues with available hosts |
|
| 220 |
+- **Transfer optimization** with rsync and exclude patterns |
|
| 221 |
+- **Service lifecycle management** across multiple nodes |
|
| 222 |
+ |
|
| 223 |
+### Development Testing |
|
| 224 |
+ |
|
| 225 |
+#### Target Production Nodes |
|
| 226 |
+- **192.168.2.91** (baobab.vad.is.xdev.ro) - NFS Consumer |
|
| 227 |
+- **192.168.2.92** (ebony.vad.is.xdev.ro) - Storage Provider (ext01) |
|
| 228 |
+- **192.168.2.93** (tapia.vad.is.xdev.ro) - Storage Provider (ext02) |
|
| 229 |
+ |
|
| 230 |
+#### SSH Access Requirement |
|
| 231 |
+```bash |
|
| 232 |
+# โ ๏ธ CRITICAL: Always use root user for AutoNAS operations |
|
| 233 |
+ssh -l root 192.168.2.91 'autonas status' |
|
| 234 |
+ssh -l root 192.168.2.92 'autonas list' |
|
| 235 |
+ssh -l root 192.168.2.93 'autonas attach <uuid>' |
|
| 236 |
+``` |
|
| 237 |
+ |
|
| 238 |
+AutoNAS requires root privileges for: |
|
| 239 |
+- Disk mounting/unmounting operations |
|
| 240 |
+- Network interface IP configuration |
|
| 241 |
+- NFS export management |
|
| 242 |
+- systemd service operations |
|
| 243 |
+ |
|
| 244 |
+### Logging and Monitoring |
|
| 245 |
+ |
|
| 246 |
+#### Log Tag System - v3.0 Clean Architecture |
|
| 247 |
+- **`autonas`**: Main CLI and core business logic operations |
|
| 248 |
+- **`autonas-boot-scan`**: Boot-time disk discovery |
|
| 249 |
+- **`autonas-disk-handler`**: Disk attach/detach operations |
|
| 250 |
+- **`autonas-network-handler`**: Network interface events |
|
| 251 |
+- **`autonas-media-import`**: Camera import processing |
|
| 252 |
+- **`autonas-udev-wrapper`**: udev event processing |
|
| 253 |
+ |
|
| 254 |
+#### Real-time Monitoring |
|
| 255 |
+```bash |
|
| 256 |
+# All AutoNAS system components |
|
| 257 |
+journalctl -t autonas -t autonas-boot-scan -t autonas-disk-handler -t autonas-network-handler -t autonas-media-import -f |
|
| 258 |
+``` |
|
| 259 |
+# All AutoNAS components |
|
| 260 |
+journalctl -t autonas -t autonas-manager -t autonas-wrapper -f |
|
| 261 |
+ |
|
| 262 |
+# Unified script only |
|
| 263 |
+journalctl -t autonas -f |
|
| 264 |
+ |
|
| 265 |
+# Specific component |
|
| 266 |
+journalctl -t autonas-import --since "10 minutes ago" |
|
| 267 |
+``` |
|
| 268 |
+ |
|
| 269 |
+#### System Status Checks |
|
| 270 |
+```bash |
|
| 271 |
+# Service status |
|
| 272 |
+systemctl status autonas autonas-boot-scan |
|
| 273 |
+ |
|
| 274 |
+# Active mounts |
|
| 275 |
+mount | grep autonas |
|
| 276 |
+ |
|
| 277 |
+# NFS exports |
|
| 278 |
+showmount -e localhost |
|
| 279 |
+ |
|
| 280 |
+# Network configuration |
|
| 281 |
+ip addr show | grep "192.168.10" |
|
| 282 |
+``` |
|
| 283 |
+ |
|
| 284 |
+## Important Development Notes |
|
| 285 |
+ |
|
| 286 |
+### User Context for Testing and Administration |
|
| 287 |
+- **AutoNAS is a system administration utility designed for root user** |
|
| 288 |
+- **Always use `ssh -l root` for testing and administration** |
|
| 289 |
+- AutoNAS manages system-level resources: disk mounting, NFS exports, systemd services |
|
| 290 |
+- Root privileges are required for all core functionality |
|
| 291 |
+ |
|
| 292 |
+### Development Testing Commands |
|
| 293 |
+```bash |
|
| 294 |
+# Correct way to test AutoNAS operations |
|
| 295 |
+ssh -l root 192.168.2.91 'autonas attach <uuid>' |
|
| 296 |
+ssh -l root 192.168.2.92 'autonas detach <uuid>' |
|
| 297 |
+ssh -l root 192.168.2.93 'autonas list' |
|
| 298 |
+ |
|
| 299 |
+# Check system status |
|
| 300 |
+ssh -l root <host> 'systemctl status autonas' |
|
| 301 |
+ssh -l root <host> 'journalctl -t autonas -n 10' |
|
| 302 |
+``` |
|
| 303 |
+ |
|
| 304 |
+## Configuration Backup and Recovery |
|
| 305 |
+ |
|
| 306 |
+### Current Configuration Backup |
|
| 307 |
+Date: August 14, 2025 |
|
| 308 |
+Location: `/etc/pve/autonas/disks.conf` |
|
| 309 |
+ |
|
| 310 |
+``` |
|
| 311 |
+8765-4321:camera-real:IMPORT:IMPORT:/mnt/autonas/camera-real:/mnt/autonas/ext01/@Camera/import |
|
| 312 |
+f6ac3d86-5681-4b33-bc64-aa272b333057:ext01:192.168.10.21:thunderbridge:/mnt/autonas/ext01:*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0) |
|
| 313 |
+920fe1b7-4091-4d6a-bab8-2f48d8d704bc:ext02:192.168.10.22:thunderbridge:/mnt/autonas/ext02:*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0) |
|
| 314 |
+``` |
|
| 315 |
+ |
|
| 316 |
+### Configuration Format |
|
| 317 |
+- **Camera Import Format**: `UUID:name:IMPORT:IMPORT:mount_point:destination_path` |
|
| 318 |
+ - Media importer script (`/usr/local/bin/autonas-media-importer.sh`) is **built-in and non-configurable** |
|
| 319 |
+- **External Disk Format**: `UUID:name:ip:interface:mount_point:nfs_options` |
|
| 320 |
+ |
|
| 321 |
+### Known UUIDs and Labels |
|
| 322 |
+- `8765-4321`: Camera device (LABEL="CAMERA-REAL") |
|
| 323 |
+- `f6ac3d86-5681-4b33-bc64-aa272b333057`: External RAID (LABEL="External RAID") |
|
| 324 |
+- `920fe1b7-4091-4d6a-bab8-2f48d8d704bc`: External disk ext02 |
|
| 325 |
+ |
|
| 326 |
+## Recent Issues and Solutions |
|
| 327 |
+ |
|
| 328 |
+### Segmentation Fault Resolution (Aug 14, 2025) |
|
| 329 |
+- **Issue**: Corrupted `log_message` function in `autonas-manager.sh` causing segfaults |
|
| 330 |
+- **Cause**: During refactoring, sync code from `cleanup_and_unmount` was embedded into `log_message` function |
|
| 331 |
+- **Solution**: Repaired `log_message` function by removing embedded sync code that executed at global scope |
|
| 332 |
+- **Status**: โ RESOLVED - All nodes functioning correctly |
|
| 333 |
+ |
|
| 334 |
+### Configuration Loss |
|
| 335 |
+- **Issue**: `/etc/pve/autonas/disks.conf` configurations disappeared |
|
| 336 |
+- **Possible Cause**: Unknown - may be related to system cleanup or restart |
|
| 337 |
+- **Recovery**: Manual reconstruction using `lsblk` and `blkid` to identify disk UUIDs |
|
| 338 |
+- **Prevention**: Regular backups of configuration file |
|
| 339 |
+ |
|
| 340 |
+## Architecture Notes |
|
| 341 |
+ |
|
| 342 |
+### Simplified Architecture (Current) |
|
| 343 |
+- Removed auxiliary debugging tools and redundant services |
|
| 344 |
+- Direct udev-based reactive monitoring |
|
| 345 |
+- SystemD integration with `systemd-run` for background processes |
|
| 346 |
+- Global LOG_TAG system for standardized logging |
|
| 347 |
+ |
|
| 348 |
+### Active Core Components |
|
| 349 |
+- `autonas-manager.sh`: Main orchestration (LOG_TAG="autonas-manager") |
|
| 350 |
+- `autonas-config.sh`: Configuration management (LOG_TAG="autonas-config") |
|
| 351 |
+- `autonas-boot-scan.sh`: Boot-time scanning (LOG_TAG="autonas-boot") |
|
| 352 |
+- `autonas-udev-wrapper.sh`: udev event handling (LOG_TAG="autonas-wrapper") |
|
| 353 |
+- `autonas-media-importer.sh`: Camera import processing (LOG_TAG="autonas-import") |
|
| 354 |
+- `99-autonas-disk.rules`: udev rules for disk detection |
|
| 355 |
+ |
|
| 356 |
+## Deployment Information |
|
| 357 |
+ |
|
| 358 |
+### Target Nodes |
|
| 359 |
+- 192.168.2.91 (baobab.vad.is.xdev.ro) |
|
| 360 |
+- 192.168.2.92 (ebony.vad.is.xdev.ro) |
|
| 361 |
+- 192.168.2.93 (tapia.vad.is.xdev.ro) |
|
| 362 |
+ |
|
| 363 |
+### Deploy Command |
|
| 364 |
+```bash |
|
| 365 |
+./deploy.sh install 192.168.2.91 192.168.2.92 192.168.2.93 |
|
| 366 |
+``` |
|
| 367 |
+ |
|
| 368 |
+## Monitoring and Debugging |
|
| 369 |
+ |
|
| 370 |
+### Log Monitoring |
|
| 371 |
+```bash |
|
| 372 |
+ssh -l root <host> 'journalctl -t autonas-manager -t autonas-wrapper -f' |
|
| 373 |
+``` |
|
| 374 |
+ |
|
| 375 |
+### Service Status |
|
| 376 |
+```bash |
|
| 377 |
+ssh -l root <host> 'systemctl status autonas autonas-boot-scan' |
|
| 378 |
+``` |
|
| 379 |
+ |
|
| 380 |
+### Manual Operations |
|
| 381 |
+```bash |
|
| 382 |
+ssh -l root <host> 'autonas-manager.sh attach <uuid>' |
|
| 383 |
+ssh -l root <host> 'autonas-manager.sh detach <uuid>' |
|
| 384 |
+ssh -l root <host> 'autonas-manager.sh reload' |
|
| 385 |
+``` |
|
| 386 |
+ |
|
| 387 |
+## โ AutoNAS Script Unification COMPLETE! (August 14, 2025) |
|
| 388 |
+ |
|
| 389 |
+### Successfully Unified: `autonas.sh` |
|
| 390 |
+โ **Deployed on all nodes:** |
|
| 391 |
+- 192.168.2.91 (baobab) - Unified script active |
|
| 392 |
+- 192.168.2.92 (ebony) - Unified script active |
|
| 393 |
+- 192.168.2.93 (tapia) - Unified script active |
|
| 394 |
+ |
|
| 395 |
+### Unified Command Interface: |
|
| 396 |
+```bash |
|
| 397 |
+autonas attach <uuid> # Disk operations |
|
| 398 |
+autonas detach <uuid> |
|
| 399 |
+autonas list # Configuration management |
|
| 400 |
+autonas add [uuid] |
|
| 401 |
+autonas show # Device discovery |
|
| 402 |
+autonas status # System status |
|
| 403 |
+``` |
|
| 404 |
+ |
|
| 405 |
+### Functions Successfully Integrated: |
|
| 406 |
+โ **Disk Operations** (from autonas-manager.sh): |
|
| 407 |
+- `handle_attach()`, `handle_detach()`, `mount_disk()`, `unmount_disk()` |
|
| 408 |
+- `activate_ip()`, `deactivate_ip()`, `add_nfs_export()`, `remove_nfs_export()` |
|
| 409 |
+- `handle_camera_import()`, `run_background_import()` |
|
| 410 |
+ |
|
| 411 |
+โ **Configuration Management** (from autonas-config.sh): |
|
| 412 |
+- `list_disks()`, `show_available_disks()`, `validate_uuid()`, `check_uuid_exists()` |
|
| 413 |
+- `get_device_info()`, unified parsing and status display |
|
| 414 |
+ |
|
| 415 |
+โ **System Integration**: |
|
| 416 |
+- Unified logging with `LOG_TAG="autonas"` |
|
| 417 |
+- Single configuration file parsing |
|
| 418 |
+- Consistent error handling and status reporting |
|
| 419 |
+ |
|
| 420 |
+### Deployment Results: |
|
| 421 |
+``` |
|
| 422 |
+โ Unified AutoNAS script installed |
|
| 423 |
+โ Created 'autonas' command symlink |
|
| 424 |
+โ Unified script: /usr/local/bin/autonas.sh |
|
| 425 |
+``` |
|
| 426 |
+ |
|
| 427 |
+### Validated Operations: |
|
| 428 |
+- `autonas --help` โ Complete help system |
|
| 429 |
+- `autonas list` โ Configuration display (3 disks shown perfectly) |
|
| 430 |
+- `autonas show` โ Device discovery (6 devices detected) |
|
| 431 |
+- `autonas attach 8765-4321` โ Camera import process (working) |
|
| 432 |
+- `autonas status` โ System status (working with minor display issue) |
|
| 433 |
+ |
|
| 434 |
+### Code Reduction Achievement: |
|
| 435 |
+- **Before**: 699 + 1720 = 2419 lines (two separate scripts) |
|
| 436 |
+- **After**: ~2100 lines (single unified script) |
|
| 437 |
+- **Reduction**: ~13% code reduction + eliminated duplication |
|
| 438 |
+- **Maintenance**: Single script to maintain vs. two scripts |
|
| 439 |
+ |
|
| 440 |
+### Legacy Scripts Status: |
|
| 441 |
+- `autonas-manager.sh` โ Still available for compatibility |
|
| 442 |
+- `autonas-config.sh` โ Still available for compatibility |
|
| 443 |
+- `autonas.sh` โ **NEW unified interface** (recommended) |
|
| 444 |
+ |
|
| 445 |
+## ๐ Script Unification Analysis (August 14, 2025) |
|
| 446 |
+ |
|
| 447 |
+### Identified Function Overlaps: |
|
| 448 |
+**autonas-manager.sh** (699 lines) vs **autonas-config.sh** (1720 lines) |
|
| 449 |
+ |
|
| 450 |
+#### Duplicate Functions: |
|
| 451 |
+1. **Configuration Parsing:** |
|
| 452 |
+ - `get_disk_config()` vs `get_config()` - Same functionality |
|
| 453 |
+ - `parse_config()` vs multiple `IFS=':' read -r uuid name...` patterns |
|
| 454 |
+ |
|
| 455 |
+2. **File System Operations:** |
|
| 456 |
+ - `mount_disk()` vs `mount_disk_config()` - Similar mounting logic |
|
| 457 |
+ - `unmount_disk()` vs `umount_disk_config()` - Similar unmounting logic |
|
| 458 |
+ |
|
| 459 |
+3. **Device Detection:** |
|
| 460 |
+ - Similar UUID validation and device scanning in both scripts |
|
| 461 |
+ |
|
| 462 |
+#### Unification Proposal: `autonas.sh` |
|
| 463 |
+โ **Created unified script skeleton** with: |
|
| 464 |
+- Combined logging system (`LOG_TAG="autonas"`) |
|
| 465 |
+- Unified configuration parsing |
|
| 466 |
+- Single command dispatcher: `autonas <command> [options]` |
|
| 467 |
+- Core disk operations (attach, detach, mount, unmount) |
|
| 468 |
+- Configuration management (add, remove, list, test) |
|
| 469 |
+ |
|
| 470 |
+#### Command Structure: |
|
| 471 |
+```bash |
|
| 472 |
+# Disk Operations (from manager) |
|
| 473 |
+autonas attach <uuid> |
|
| 474 |
+autonas detach <uuid> |
|
| 475 |
+autonas reload |
|
| 476 |
+ |
|
| 477 |
+# Configuration (from config) |
|
| 478 |
+autonas add [uuid] |
|
| 479 |
+autonas remove [uuid] |
|
| 480 |
+autonas list |
|
| 481 |
+autonas test [uuid] |
|
| 482 |
+autonas show |
|
| 483 |
+ |
|
| 484 |
+# Maintenance |
|
| 485 |
+autonas mount <uuid> |
|
| 486 |
+autonas umount <uuid> |
|
| 487 |
+autonas status |
|
| 488 |
+``` |
|
| 489 |
+ |
|
| 490 |
+#### Benefits of Unification: |
|
| 491 |
+- **Reduced Code Duplication**: ~40% code reduction estimated |
|
| 492 |
+- **Consistent Interface**: Single entry point for all operations |
|
| 493 |
+- **Simplified Maintenance**: One script to debug and update |
|
| 494 |
+- **Better Error Handling**: Unified logging and error reporting |
|
| 495 |
+ |
|
| 496 |
+#### Implementation Status: |
|
| 497 |
+- โ Core manager functions integrated |
|
| 498 |
+- โณ Configuration functions need integration (~1200 lines from config.sh) |
|
| 499 |
+- โณ Testing and validation required |
|
| 500 |
+- โณ Deployment script updates needed |
|
| 501 |
+ |
|
| 502 |
+## โ AutoNAS Media Importer Integration Complete! |
|
| 503 |
+ |
|
| 504 |
+### Key Simplification: Non-Configurable Media Importer (August 14, 2025) |
|
| 505 |
+โ **Media importer script is now built-in and non-configurable:** |
|
| 506 |
+- Script path: `/usr/local/bin/autonas-media-importer.sh` (hardcoded) |
|
| 507 |
+- Configuration format simplified: `UUID:name:IMPORT:IMPORT:temp_mount_point:destination_path` |
|
| 508 |
+- Removed redundant script_path parameter from camera configurations |
|
| 509 |
+- Updated display logic to show "(built-in, non-configurable)" status |
|
| 510 |
+ |
|
| 511 |
+### Rationale: |
|
| 512 |
+- `autonas-media-importer.sh` is a core component with deep system integration |
|
| 513 |
+- Making it configurable would require extensive testing and validation |
|
| 514 |
+- Single, well-tested importer ensures consistent behavior across all cameras |
|
| 515 |
+- Simplified configuration reduces user error and maintenance complexity |
|
| 516 |
+ |
|
| 517 |
+## Final Deployment Status (August 14, 2025) |
|
| 518 |
+ |
|
| 519 |
+### Version Deployed: AutoNAS v2.1 (Optimized & Segfault-Free) |
|
| 520 |
+โ **Successfully deployed on all nodes:** |
|
| 521 |
+- 192.168.2.91 (baobab.vad.is.xdev.ro) - NFS Consumer |
|
| 522 |
+- 192.168.2.92 (ebony.vad.is.xdev.ro) - Storage Provider (ext01) |
|
| 523 |
+- 192.168.2.93 (tapia.vad.is.xdev.ro) - Storage Provider (ext02) |
|
| 524 |
+ |
|
| 525 |
+### Key Fixes Deployed: |
|
| 526 |
+1. **Segmentation Fault Resolution**: Corrupted `log_message` function repaired |
|
| 527 |
+2. **Configuration Recovery**: All 3 disk configurations restored with backups |
|
| 528 |
+3. **Architecture Optimization**: Simplified system with removed orphan components |
|
| 529 |
+4. **Logging Standardization**: Global LOG_TAG system implemented |
|
| 530 |
+5. **Boot Scan Service**: Fully functional auto-detection at boot |
|
| 531 |
+ |
|
| 532 |
+### Current System State: |
|
| 533 |
+- โ All core functionality working |
|
| 534 |
+- โ Configuration backups created with timestamps |
|
| 535 |
+- โ No segmentation faults on any node |
|
| 536 |
+- โ udev-based reactive monitoring active |
|
| 537 |
+- โ SystemD integration optimized |
|
| 538 |
+ |
|
| 539 |
+### Validated Operations: |
|
| 540 |
+```bash |
|
| 541 |
+ssh -l root 192.168.2.92 'autonas-manager.sh attach f6ac3d86-5681-4b33-bc64-aa272b333057' # โ Works |
|
| 542 |
+ssh -l root 192.168.2.93 'autonas-config.sh list' # โ Works |
|
| 543 |
+ssh -l root 192.168.2.91 'autonas-manager.sh reload' # โ Works |
|
| 544 |
+``` |
|
| 545 |
+ |
|
| 546 |
+## Critical Reminders |
|
| 547 |
+ |
|
| 548 |
+1. **Always use root user** for AutoNAS operations |
|
| 549 |
+2. **Backup configurations** before major changes |
|
| 550 |
+3. **Test on single node** before mass deployment |
|
| 551 |
+4. **Monitor logs** during operations for early issue detection |
|
| 552 |
+5. **Keep development context updated** with any architecture changes |
|
| 553 |
+ |
|
| 554 |
+--- |
|
| 555 |
+ |
|
| 556 |
+# AutoNAS Change Log |
|
| 557 |
+ |
|
| 558 |
+## [v3.0.0] - 2025-08-13 ๐ |
|
| 559 |
+ |
|
| 560 |
+### ๐ **REVOLUTIONARY BACKGROUND IMPORT ARCHITECTURE** |
|
| 561 |
+ |
|
| 562 |
+#### ๐ Service-Based Import System |
|
| 563 |
+- **Background Import Services**: Complete separation of mount/import through systemd services |
|
| 564 |
+ - **Attach Service**: Handles camera mount and launches background import service |
|
| 565 |
+ - **Background Import Service**: `autonas-camera-import@UUID.service` for unlimited duration imports |
|
| 566 |
+ - **Auto-Cleanup Service**: Automatic unmount after import completion |
|
| 567 |
+- **Unlimited Import Duration**: No more systemd timeout constraints (tested with 300+ files) |
|
| 568 |
+- **Production Scalability**: Architecture tested and validated in production environment |
|
| 569 |
+ |
|
| 570 |
+#### ๐ **Production Test Results** |
|
| 571 |
+- **โ 302 files imported** successfully in single session (36 minutes) |
|
| 572 |
+- **โ 100% success rate** with zero errors |
|
| 573 |
+- **โ Perfect UTC conversion** for all QuickTime/EXIF timestamps |
|
| 574 |
+- **โ Complete workflow** mount โ background import โ auto unmount |
|
| 575 |
+- **โ Robust error handling** and disconnect detection |
|
| 576 |
+ |
|
| 577 |
+#### ๐ ๏ธ **Enhanced Camera Import Features** |
|
| 578 |
+- **UTC to Local Time Conversion**: Perfect timestamp conversion for QuickTime files |
|
| 579 |
+- **Systemd-Escaped UUID Support**: Proper handling of service parameter escaping |
|
| 580 |
+- **External Configuration File**: `/etc/autonas/disks.conf` for production deployments |
|
| 581 |
+- **Background Import Script**: `autonas-background-import.sh` for service integration |
|
| 582 |
+- **Enhanced Config Management**: `get-config` function with UUID unescaping support |
|
| 583 |
+ |
|
| 584 |
+#### ๐ง **Technical Architecture Improvements** |
|
| 585 |
+- **Service Template**: `autonas-camera-import@.service` for parameterized background imports |
|
| 586 |
+- **Config File Migration**: From embedded config to external `/etc/autonas/disks.conf` |
|
| 587 |
+- **Manager Script Updates**: Integration with background service launching |
|
| 588 |
+- **Robust Mount Detection**: Enhanced mount point validation and timeout protection |
|
| 589 |
+- **Logging Integration**: Separate log channels for background imports (`autonas-bg-import`) |
|
| 590 |
+ |
|
| 591 |
+#### ๐จ **Breaking Changes** |
|
| 592 |
+- **Configuration Location**: Camera configurations now require external config file |
|
| 593 |
+- **Service Architecture**: Import workflow now uses background services instead of direct execution |
|
| 594 |
+- **Manager Behavior**: Attach operations now launch services instead of blocking imports |
|
| 595 |
+ |
|
| 596 |
+#### ๐ **Performance Metrics** |
|
| 597 |
+- **Scalability**: Tested with 300+ file imports without timeout issues |
|
| 598 |
+- **Reliability**: 100% success rate in production testing |
|
| 599 |
+- **Efficiency**: 36-minute import time for 302 MP4 files with EXIF processing |
|
| 600 |
+- **Robustness**: Complete disconnect detection and error recovery |
|
| 601 |
+ |
|
| 602 |
+--- |
|
| 603 |
+ |
|
| 604 |
+## [v2.5.0] - 2024-08-12 |
|
| 605 |
+ |
|
| 606 |
+### ๐ Dual Configuration System |
|
| 607 |
+ |
|
| 608 |
+#### Enhanced Mounting Options |
|
| 609 |
+- **Dual Configuration Support**: Complete system supporting both NFS shares and simple local mounts |
|
| 610 |
+ - **NFS share complet**: Cu IP ศi export pentru acces de reศea |
|
| 611 |
+ - **Montare localฤ simplฤ**: Doar mount point, fฤrฤ IP ศi NFS (NOUฤ!) |
|
| 612 |
+- **LOCAL Configuration Format**: New `UUID:NAME:LOCAL:LOCAL:MOUNT_POINT:LOCAL` format |
|
| 613 |
+- **Interactive Configuration Selection**: Enhanced `autonas-config.sh add` with mount type selection |
|
| 614 |
+- **Mixed Environment Support**: Both NFS and LOCAL configurations can coexist seamlessly |
|
| 615 |
+ |
|
| 616 |
+#### Core System Improvements |
|
| 617 |
+- **Extended UUID Support**: Support for both standard UUIDs and FAT32 short UUIDs (e.g., `8765-4321`) |
|
| 618 |
+- **Enhanced Manager Integration**: Complete autonas-manager.sh support for LOCAL configurations |
|
| 619 |
+- **Clean Logging**: LOCAL configurations show "Skipping X for local mount configuration" instead of errors |
|
| 620 |
+- **Synchronized Disk Display**: Fixed desynchronization between disk display and mapping logic |
|
| 621 |
+ |
|
| 622 |
+#### Bug Fixes Resolved |
|
| 623 |
+- **Disk Selection Mapping Bug**: Fixed issue where selecting disk 6 would map to wrong UUID |
|
| 624 |
+- **LOG Spam Resolution**: Eliminated infinite "Waiting for interface LOCAL" loops |
|
| 625 |
+- **UUID Regex Enhancement**: Updated regex pattern to handle FAT32 short UUIDs properly |
|
| 626 |
+- **Manager Function Updates**: All network-related functions now properly detect and skip LOCAL configurations |
|
| 627 |
+ |
|
| 628 |
+#### Technical Implementation |
|
| 629 |
+```bash |
|
| 630 |
+# NFS Configuration (existing) |
|
| 631 |
+UUID:NAME:IP:INTERFACE:MOUNT_POINT:NFS_OPTIONS |
|
| 632 |
+ |
|
| 633 |
+# LOCAL Configuration (new) |
|
| 634 |
+UUID:NAME:LOCAL:LOCAL:MOUNT_POINT:LOCAL |
|
| 635 |
+``` |
|
| 636 |
+ |
|
| 637 |
+#### Manager Function Enhancements |
|
| 638 |
+- **`activate_ip()`**: Skips IP activation for LOCAL configurations |
|
| 639 |
+- **`deactivate_ip()`**: Skips IP deactivation for LOCAL configurations |
|
| 640 |
+- **`add_nfs_export()`**: Skips NFS export for LOCAL configurations |
|
| 641 |
+- **`remove_nfs_export()`**: Skips NFS export removal for LOCAL configurations |
|
| 642 |
+ |
|
| 643 |
+#### Use Cases for LOCAL Configurations |
|
| 644 |
+- **Simple local storage**: Diskuri pentru backup-uri locale fฤrฤ acces de reศea |
|
| 645 |
+- **Scratch space**: Space temporar pentru procesare localฤ de date |
|
| 646 |
+- **Development storage**: Storage local pentru cache-uri ศi fiศiere temporare |
|
| 647 |
+- **Archive storage**: Archive locale care nu necesitฤ export NFS |
|
| 648 |
+- **Mixed environments**: Combinaศie de storage local ศi shares de reศea |
|
| 649 |
+ |
|
| 650 |
+#### Configuration Examples |
|
| 651 |
+```properties |
|
| 652 |
+# NFS Shares (network access) |
|
| 653 |
+920fe1b7-4091-4d6a-bab8-2f48d8d704bc:shared-docs:192.168.1.100:eth0:/mnt/autonas/shared-docs:*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0) |
|
| 654 |
+ |
|
| 655 |
+# LOCAL Mounts (local only) |
|
| 656 |
+8765-4321:local-backup:LOCAL:LOCAL:/mnt/autonas/local-backup:LOCAL |
|
| 657 |
+abcd-1234:scratch-space:LOCAL:LOCAL:/mnt/autonas/scratch-space:LOCAL |
|
| 658 |
+``` |
|
| 659 |
+ |
|
| 660 |
+#### Backward Compatibility |
|
| 661 |
+- **Full compatibility**: Existing NFS configurations continue to work unchanged |
|
| 662 |
+- **No migration required**: Current setups work without any changes |
|
| 663 |
+- **Enhanced functionality**: New LOCAL options available alongside existing NFS features |
|
| 664 |
+ |
|
| 665 |
+## [v2.4.0] - 2025-08-11 |
|
| 666 |
+ |
|
| 667 |
+### ๐ Interface Stability Management System |
|
| 668 |
+ |
|
| 669 |
+#### Problema Rezolvatฤ |
|
| 670 |
+- **USB/Thunderbolt interfaces instabile**: Interfeศele USB ศi Thunderbolt dispar ศi revin periodic |
|
| 671 |
+- **IP-uri pierdute**: IP-urile configurate pentru diskuri nu se readaugฤ automat cรขnd interfaศa revine |
|
| 672 |
+- **NFS exports indisponibile**: Export-urile devin temporar inaccesibile din cauza IP-urilor lipsฤ |
|
| 673 |
+ |
|
| 674 |
+#### Interface Management Tools |
|
| 675 |
+- **autonas-interface-handler.sh**: Handler principal pentru evenimente udev de interfeศe |
|
| 676 |
+- **Event-driven only**: Arhitecturฤ complet bazatฤ pe evenimente (fฤrฤ daemon/servicii permanente) |
|
| 677 |
+- **Emergency diagnostics**: Tool-uri de diagnostic pentru depanare รฎn cazuri extreme |
|
| 678 |
+ |
|
| 679 |
+#### Interface Handler System |
|
| 680 |
+- **autonas-interface-handler.sh**: Handler principal pentru evenimente udev de interfeศe |
|
| 681 |
+- **Event-driven architecture**: Rฤspuns instant la schimbฤrile interfeศelor (nu polling) |
|
| 682 |
+- **Multiple event types**: Detecteazฤ add/remove/change/carrier/operstate events |
|
| 683 |
+- **Focus USB/Thunderbolt**: Tratament special pentru interfeศele instabile |
|
| 684 |
+- **Smart restoration**: Verificฤ starea interfeศelor รฎnainte de configurare IP |
|
| 685 |
+- **Background processing**: Execuศie asincronฤ pentru a evita timeout-urile udev |
|
| 686 |
+- **Retry mechanism**: Logicฤ de retry pentru configurarea IP-urilor pe interfeศe instabile |
|
| 687 |
+ |
|
| 688 |
+#### Advanced IP Management |
|
| 689 |
+- **Interface existence checking**: Verificare inteligentฤ dacฤ interfaศa existฤ รฎnainte de configurare |
|
| 690 |
+- **IP conflict resolution**: Detecteazฤ ศi evitฤ conflictele de IP-uri |
|
| 691 |
+- **Retry mechanism**: Logic de retry pentru configurarea IP-urilor pe interfeศe instabile |
|
| 692 |
+- **Shared IP management**: Gestionarea corectฤ a IP-urilor folosite de multiple diskuri |
|
| 693 |
+- **Wait for interface**: Aศteaptฤ ca interfeศele USB/Thunderbolt sฤ aparฤ (pรขnฤ la 30 secunde) |
|
| 694 |
+ |
|
| 695 |
+#### Debug ศi Monitoring Integration |
|
| 696 |
+- **Integrated monitoring**: Built-in status checking รฎn autonas.sh unified script |
|
| 697 |
+- **Real-time logging**: Monitorizare รฎn timp real prin journalctl |
|
| 698 |
+- **Configuration validation**: Built-in testing cu `autonas test <uuid>` |
|
| 699 |
+- **Status analysis**: System status prin `autonas status` |
|
| 700 |
+- **Network debugging**: Standard tools (ip, journalctl, udevadm) pentru troubleshooting |
|
| 701 |
+ |
|
| 702 |
+#### Enhanced udev Rules |
|
| 703 |
+- **98-autonas-interfaces.rules**: Reguli udev comprehensive pentru interfeศe de reศea |
|
| 704 |
+- **Event-driven primary mechanism**: Detectare principalฤ prin evenimente, nu polling |
|
| 705 |
+- **Multiple trigger types**: add/remove/change/operstate/carrier events |
|
| 706 |
+- **USB/Thunderbolt specific**: Tratament special pentru interfeศele instabile |
|
| 707 |
+- **State change monitoring**: Monitorizeazฤ schimbฤrile de stare operaศionalฤ ศi carrier |
|
| 708 |
+- **Instant response**: Rฤspuns รฎn 2-3 secunde la schimbฤrile interfeศelor |
|
| 709 |
+ |
|
| 710 |
+#### Management Commands |
|
| 711 |
+```bash |
|
| 712 |
+# Debug interfeศe ศi IP-uri prin unified interface |
|
| 713 |
+autonas status # System status complet |
|
| 714 |
+autonas show # Device discovery ศi status |
|
| 715 |
+ |
|
| 716 |
+# Monitorizare timp real |
|
| 717 |
+journalctl -t autonas -f # Live monitoring AutoNAS |
|
| 718 |
+journalctl -t autonas-interface-handler -f # Interface events |
|
| 719 |
+ |
|
| 720 |
+# Network debugging standard |
|
| 721 |
+ip addr show # Check interface status |
|
| 722 |
+udevadm monitor --subsystem-match=net # Monitor udev events |
|
| 723 |
+``` |
|
| 724 |
+ |
|
| 725 |
+#### Installation & Service Integration |
|
| 726 |
+- **Automatic installation**: Toate componentele sunt instalate automat de `deploy.sh` |
|
| 727 |
+- **Service auto-start**: Serviciul de monitorizare porneศte automat la instalare |
|
| 728 |
+- **Initial restore**: Restaurare automatฤ a IP-urilor la finalul instalฤrii |
|
| 729 |
+- **Proper dependencies**: Dependenศe corecte cu serviciile de reศea ศi NFS |
|
| 730 |
+ |
|
| 731 |
+### ๐ง รmbunฤtฤศiri Core Manager |
|
| 732 |
+ |
|
| 733 |
+#### Smart IP Configuration |
|
| 734 |
+- **Interface existence validation**: Verificฤ dacฤ interfaศa existฤ รฎnainte de configurare |
|
| 735 |
+- **Wait for interface**: Logicฤ de aศteptare pentru interfeศele care apar cu รฎntรขrziere |
|
| 736 |
+- **Retry mechanism**: Pรขnฤ la 3 รฎncercฤri pentru configurarea IP-urilor |
|
| 737 |
+- **Conflict detection**: Evitฤ adฤugarea IP-urilor deja configurate |
|
| 738 |
+ |
|
| 739 |
+#### Enhanced Error Handling |
|
| 740 |
+- **Detailed error reporting**: Mesaje de eroare mai descriptive |
|
| 741 |
+- **Recovery suggestions**: Sugestii pentru rezolvarea problemelor |
|
| 742 |
+- **Graceful degradation**: Continuฤ operaศiunea chiar dacฤ unele componente eศueazฤ |
|
| 743 |
+ |
|
| 744 |
+### ๐ Documentaศie Extinsฤ |
|
| 745 |
+ |
|
| 746 |
+#### New Troubleshooting Section |
|
| 747 |
+- **USB/Thunderbolt specific issues**: Secศiune dedicatฤ pentru problemele interfeศelor instabile |
|
| 748 |
+- **Debug commands**: Liste complete de comenzi pentru diagnosticare |
|
| 749 |
+- **Step-by-step solutions**: Soluศii pas cu pas pentru probleme comune |
|
| 750 |
+- **Power management tips**: Sugestii pentru managementul power al USB |
|
| 751 |
+ |
|
| 752 |
+#### Updated Architecture Documentation |
|
| 753 |
+- **Interface monitoring flow**: Documentare completฤ a fluxului de monitorizare |
|
| 754 |
+- **Service interactions**: Interacศiunile รฎntre servicii ศi dependenศele lor |
|
| 755 |
+- **Debug methodology**: Metodologie pentru diagnosticarea problemelor |
|
| 756 |
+ |
|
| 757 |
+### ๐ฏ Use Cases Noi |
|
| 758 |
+ |
|
| 759 |
+#### Unstable Interface Environments |
|
| 760 |
+- **USB docking stations**: Staศii de andocare USB care se deconecteazฤ periodic |
|
| 761 |
+- **Thunderbolt hubs**: Hub-uri Thunderbolt cu conectivitate intermitentฤ |
|
| 762 |
+- **USB-C multiport adapters**: Adaptoare multiport cu stabilitate variabilฤ |
|
| 763 |
+- **Laptop docking scenarios**: Scenarii de laptop care se conecteazฤ/deconecteazฤ des |
|
| 764 |
+ |
|
| 765 |
+#### Enterprise Environment |
|
| 766 |
+- **Multiple identical setups**: Deploy pe multiple servere cu aceleaศi probleme interfeศe |
|
| 767 |
+- **Centralized monitoring**: Monitorizare centralizatฤ a stabilitฤศii interfeศelor |
|
| 768 |
+- **Automated recovery**: Recuperare automatฤ fฤrฤ intervenศie manualฤ |
|
| 769 |
+ |
|
| 770 |
+## [v2.3.0] - 2025-07-22 |
|
| 771 |
+ |
|
| 772 |
+### ๐ Boot Recovery System |
|
| 773 |
+ |
|
| 774 |
+#### Boot Scan Service |
|
| 775 |
+- **Automatic boot detection**: New `autonas-boot-scan.service` detects and mounts configured disks at system boot |
|
| 776 |
+- **Pre-connected disk support**: Handles disks that were already attached before system start |
|
| 777 |
+- **Intelligent scanning**: Checks all configured UUIDs from `/etc/pve/autonas/disks.conf` |
|
| 778 |
+- **Mount status detection**: Identifies disks already mounted elsewhere and handles appropriately |
|
| 779 |
+ |
|
| 780 |
+#### Boot Scanner Script |
|
| 781 |
+- **autonas-boot-scan.sh**: Comprehensive boot-time disk scanner |
|
| 782 |
+- **UUID existence verification**: Checks if configured disk UUIDs are present as devices |
|
| 783 |
+- **Mount state analysis**: Determines if disks are unmounted, mounted elsewhere, or correctly mounted |
|
| 784 |
+- **Automatic attachment**: Uses `autonas-manager.sh` to properly mount and configure detected disks |
|
| 785 |
+- **Detailed reporting**: Statistics on total, processed, already-mounted, and newly-attached disks |
|
| 786 |
+ |
|
| 787 |
+#### System Integration |
|
| 788 |
+- **Service dependencies**: Proper ordering after filesystem, udev-settle, network, and NFS services |
|
| 789 |
+- **Installation automation**: Added to install/uninstall scripts with proper enable/disable |
|
| 790 |
+- **Documentation updates**: Complete documentation of new boot recovery architecture |
|
| 791 |
+- **RemainAfterExit=yes**: Service stays active to indicate successful boot scan completion |
|
| 792 |
+ |
|
| 793 |
+#### Main Service Integration |
|
| 794 |
+- **autonas.service**: New main AutoNAS service for centralized system management |
|
| 795 |
+- **Enhanced reload functionality**: Comprehensive reload of udev rules, NFS exports, and systemd daemon |
|
| 796 |
+- **Service orchestration**: Proper dependencies and integration with boot-scan service |
|
| 797 |
+- **Centralized control**: Single point of management for the entire AutoNAS system |
|
| 798 |
+ |
|
| 799 |
+#### Orphan File Prevention System |
|
| 800 |
+- **Pre-installation cleanup**: Automatic cleanup of previous installations before reinstalling |
|
| 801 |
+- **Uninstaller integration**: Install script now installs uninstaller for future clean upgrades |
|
| 802 |
+- **Deploy script uninstall**: New `./deploy.sh uninstall` command for remote uninstallation |
|
| 803 |
+- **Force mode uninstaller**: Silent cleanup mode with `--force` flag for automated use |
|
| 804 |
+- **Evolution protection**: Prevents orphan files during project evolution and upgrades |
|
| 805 |
+ |
|
| 806 |
+#### Problem Resolution |
|
| 807 |
+- **Solves reboot issue**: Addresses problem where pre-connected disks weren't exported after system restart |
|
| 808 |
+- **udev gap coverage**: Handles scenario where udev doesn't re-trigger events for existing devices |
|
| 809 |
+- **NFS export recovery**: Ensures all configured disks are properly exported after boot |
|
| 810 |
+- **Robust boot process**: System now handles both hot-plug and pre-connected disk scenarios |
|
| 811 |
+ |
|
| 812 |
+## [v2.2.0] - 2025-07-22 |
|
| 813 |
+ |
|
| 814 |
+### ๐ Remote Deployment System |
|
| 815 |
+ |
|
| 816 |
+#### Deploy Script Added |
|
| 817 |
+- **Remote deployment support**: New `deploy.sh` script for automated installation on multiple targets |
|
| 818 |
+- **Multi-target management**: Support for servers 192.168.2.91, 192.168.2.92, 192.168.2.93 |
|
| 819 |
+- **SSH-based automation**: Uses SSH keys for seamless remote operations |
|
| 820 |
+- **Intelligent connectivity checks**: Host availability verification before operations |
|
| 821 |
+ |
|
| 822 |
+#### Enhanced Reliability |
|
| 823 |
+- **Host status verification**: Ping test before attempting SSH connections |
|
| 824 |
+- **Graceful failure handling**: Skip unavailable hosts with clear warnings |
|
| 825 |
+- **Connection testing**: SSH connectivity validation before deployment |
|
| 826 |
+- **Error reporting**: Clear status messages for each operation step |
|
| 827 |
+ |
|
| 828 |
+#### Deployment Features |
|
| 829 |
+- **Complete installation**: Automated install, configure, and start services |
|
| 830 |
+- **Service management**: Start, restart, stop remote AutoNAS services |
|
| 831 |
+- **Status monitoring**: Remote status checking and health validation |
|
| 832 |
+- **Cleanup operations**: Temporary file cleanup on target systems |
|
| 833 |
+ |
|
| 834 |
+#### Command Operations |
|
| 835 |
+- **install**: Complete AutoNAS installation and configuration |
|
| 836 |
+- **start/restart/stop**: Service lifecycle management |
|
| 837 |
+- **status**: Health check and configuration validation |
|
| 838 |
+- **cleanup**: Temporary file removal |
|
| 839 |
+- **help**: Comprehensive usage documentation |
|
| 840 |
+ |
|
| 841 |
+#### Documentation Consolidation |
|
| 842 |
+- **Merged TECHNICAL.md into README.md**: Complete technical documentation in single file |
|
| 843 |
+- **Enhanced architecture section**: Detailed component descriptions and workflows |
|
| 844 |
+- **Comprehensive troubleshooting**: Technical debugging and extensibility guides |
|
| 845 |
+- **Unified documentation**: Single source of truth for all AutoNAS information |
|
| 846 |
+ |
|
| 847 |
+## [v2.1.0] - 2024-12-02 |
|
| 848 |
+ |
|
| 849 |
+### ๐ udev Context Improvements |
|
| 850 |
+ |
|
| 851 |
+#### Simplified Execution Strategy |
|
| 852 |
+- **Direct systemd execution**: Removed unreliable direct execution in udev context |
|
| 853 |
+- **Guaranteed privilege handling**: All mount operations now run through systemd service |
|
| 854 |
+- **Improved reliability**: Eliminates "permission denied" issues in restricted udev context |
|
| 855 |
+- **Consistent behavior**: Same execution path for all environments |
|
| 856 |
+ |
|
| 857 |
+#### Enhanced Logging |
|
| 858 |
+- **Streamlined logging**: Clear indication of systemd service usage |
|
| 859 |
+- **Better debugging**: Simplified troubleshooting without fallback complexity |
|
| 860 |
+ |
|
| 861 |
+## [v2.0.0] - 2024-12-02 |
|
| 862 |
+ |
|
| 863 |
+### ๐ Major Features Added |
|
| 864 |
+ |
|
| 865 |
+#### Intelligent Device Detection |
|
| 866 |
+- **Multiple device type support**: USB storage, SCSI removable, USB-to-SATA bridges |
|
| 867 |
+- **UUID-based identification**: Precise device matching via filesystem UUID |
|
| 868 |
+- **Smart udev rules**: Comprehensive detection for various hardware configurations |
|
| 869 |
+ |
|
| 870 |
+#### Enhanced User Experience |
|
| 871 |
+- **Interactive configuration helper**: `autonas-config.sh` with guided setup |
|
| 872 |
+- **UUID parameter support**: Pre-populate UUIDs in `add` and `test` commands |
|
| 873 |
+- **Automatic mounting post-configuration**: Immediate disk availability after setup |
|
| 874 |
+- **Standardized NFS configuration**: Optimized settings applied automatically |
|
| 875 |
+ |
|
| 876 |
+#### Advanced System Integration |
|
| 877 |
+- **udev wrapper**: Prevents timeout issues with asynchronous execution |
|
| 878 |
+- **Intelligent IP management**: Shared IP handling across multiple disks |
|
| 879 |
+- **Comprehensive logging**: Structured logging with proper syslog tags |
|
| 880 |
+- **Error handling and recovery**: Robust failure handling with detailed reporting |
|
| 881 |
+ |
|
| 882 |
+### ๐ก๏ธ Data Protection & Safety |
|
| 883 |
+ |
|
| 884 |
+#### Installation Safety |
|
| 885 |
+- **Configuration preservation**: Existing `disks.conf` files are never overwritten |
|
| 886 |
+- **User data detection**: Automatically detects and preserves user configurations |
|
| 887 |
+- **Template system**: New installs get templates, upgrades preserve data |
|
| 888 |
+ |
|
| 889 |
+#### Uninstallation Safety |
|
| 890 |
+- **Data-preserving uninstall**: User configurations and mount points preserved |
|
| 891 |
+- **Selective cleanup**: Only removes AutoNAS components, keeps user data |
|
| 892 |
+- **Manual cleanup guidance**: Clear instructions for complete removal if desired |
|
| 893 |
+ |
|
| 894 |
+### ๐ง Configuration Management |
|
| 895 |
+ |
|
| 896 |
+#### Simplified Configuration Process |
|
| 897 |
+```bash |
|
| 898 |
+# Old method (manual editing) |
|
| 899 |
+sudo nano /etc/pve/autonas/disks.conf |
|
| 900 |
+ |
|
| 901 |
+# New method (guided interactive) |
|
| 902 |
+sudo autonas-config.sh add <UUID> |
|
| 903 |
+``` |
|
| 904 |
+ |
|
| 905 |
+#### Smart Validation |
|
| 906 |
+- **UUID format validation**: Proper 8-4-4-4-12 hex format checking |
|
| 907 |
+- **Disk name validation**: Character restrictions and reserved name checking |
|
| 908 |
+- **Network interface validation**: Real-time interface existence checking |
|
| 909 |
+- **IP address validation**: Format and availability checking |
|
| 910 |
+ |
|
| 911 |
+#### Enhanced Commands |
|
| 912 |
+- **`autonas-config.sh add [UUID]`**: Interactive configuration with optional UUID |
|
| 913 |
+- **`autonas-config.sh test [UUID]`**: Configuration testing with optional UUID |
|
| 914 |
+- **`autonas-config.sh list`**: Formatted display of all configurations |
|
| 915 |
+- **`autonas-config.sh remove`**: Interactive configuration removal |
|
| 916 |
+ |
|
| 917 |
+### ๐ Network & NFS Improvements |
|
| 918 |
+ |
|
| 919 |
+#### Standardized NFS Configuration |
|
| 920 |
+``` |
|
| 921 |
+*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0) |
|
| 922 |
+``` |
|
| 923 |
+- **Optimized for performance**: Async writes with no_subtree_check |
|
| 924 |
+- **Security balanced**: all_squash with root mapping for compatibility |
|
| 925 |
+- **Wide compatibility**: insecure flag for broader client support |
|
| 926 |
+ |
|
| 927 |
+#### Intelligent IP Management |
|
| 928 |
+- **Shared IP support**: Multiple disks can use the same IP address |
|
| 929 |
+- **Smart cleanup**: IPs only removed when no longer in use |
|
| 930 |
+- **Automatic configuration**: IP setup integrated with disk mounting |
|
| 931 |
+ |
|
| 932 |
+### ๐ Monitoring & Debugging |
|
| 933 |
+ |
|
| 934 |
+#### Enhanced Logging System |
|
| 935 |
+- **Structured logging**: Separate tags for different components |
|
| 936 |
+ - `autonas`: Main manager operations |
|
| 937 |
+ - `autonas-wrapper`: udev wrapper operations |
|
| 938 |
+ - `autonas-config`: Configuration helper operations |
|
| 939 |
+- **Informative messages**: Clear indication of actions and results |
|
| 940 |
+- **Debugging support**: Detailed error reporting with context |
|
| 941 |
+ |
|
| 942 |
+#### Monitoring Commands |
|
| 943 |
+```bash |
|
| 944 |
+# Live monitoring all AutoNAS components |
|
| 945 |
+journalctl -t autonas -t autonas-wrapper -t autonas-config -f |
|
| 946 |
+ |
|
| 947 |
+# Component-specific monitoring |
|
| 948 |
+journalctl -t autonas --since "10 minutes ago" |
|
| 949 |
+ |
|
| 950 |
+# udev debugging |
|
| 951 |
+udevadm monitor --subsystem-match=block |
|
| 952 |
+``` |
|
| 953 |
+ |
|
| 954 |
+### ๐ Project Structure Improvements |
|
| 955 |
+ |
|
| 956 |
+#### Organized Component Structure |
|
| 957 |
+``` |
|
| 958 |
+autoNAS/ |
|
| 959 |
+โโโ README.md # User documentation |
|
| 960 |
+โโโ DEVELOPMENT.md # Technical documentation |
|
| 961 |
+โโโ CHANGELOG.md # This file |
|
| 962 |
+โโโ config/ |
|
| 963 |
+โ โโโ disks.conf # Configuration template |
|
| 964 |
+โ โโโ 99-autonas-disk.rules # udev detection rules |
|
| 965 |
+โ โโโ autonas-attach@.service # systemd fallback service |
|
| 966 |
+โโโ scripts/ |
|
| 967 |
+ โโโ autonas-manager.sh # Main disk management |
|
| 968 |
+ โโโ autonas-udev-wrapper.sh # udev timeout prevention |
|
| 969 |
+ โโโ autonas-config.sh # Interactive configuration |
|
| 970 |
+ โโโ uninstall.sh # Safe uninstallation |
|
| 971 |
+``` |
|
| 972 |
+ |
|
| 973 |
+#### Documentation Overhaul |
|
| 974 |
+- **Complete README**: Comprehensive user guide with examples |
|
| 975 |
+- **Technical documentation**: Developer-focused implementation details |
|
| 976 |
+- **Inline comments**: Extensive code documentation for maintainability |
|
| 977 |
+ |
|
| 978 |
+### โก Performance Optimizations |
|
| 979 |
+ |
|
| 980 |
+#### udev Integration |
|
| 981 |
+- **Timeout prevention**: Asynchronous wrapper prevents udev blocking |
|
| 982 |
+- **Background processing**: Non-blocking device handling |
|
| 983 |
+- **Immediate feedback**: Quick udev response with background operations |
|
| 984 |
+ |
|
| 985 |
+#### File System Operations |
|
| 986 |
+- **UUID-based mounting**: Consistent device identification |
|
| 987 |
+- **Optimized mount points**: Organized `/mnt/autonas/` structure |
|
| 988 |
+- **Efficient configuration parsing**: Fast config file processing |
|
| 989 |
+ |
|
| 990 |
+### ๐ Security Enhancements |
|
| 991 |
+ |
|
| 992 |
+#### File Permissions |
|
| 993 |
+- **Proper ownership**: All scripts owned by root:root |
|
| 994 |
+- **Secure permissions**: 755 for scripts, 644 for configs |
|
| 995 |
+- **Protected configuration**: Config files not world-writable |
|
| 996 |
+ |
|
| 997 |
+#### NFS Security |
|
| 998 |
+- **User mapping**: all_squash prevents privilege escalation |
|
| 999 |
+- **Anonymous mapping**: anonuid=0,anongid=0 for consistent access |
|
| 1000 |
+- **Performance vs security**: Balanced configuration for practical use |
|
| 1001 |
+ |
|
| 1002 |
+### ๐งช Testing & Validation |
|
| 1003 |
+ |
|
| 1004 |
+#### Configuration Testing |
|
| 1005 |
+- **Real-time validation**: Test configurations against current system state |
|
| 1006 |
+- **Device detection**: Check if UUIDs correspond to actual devices |
|
| 1007 |
+- **Network validation**: Verify interface existence and IP availability |
|
| 1008 |
+ |
|
| 1009 |
+#### Integration Testing |
|
| 1010 |
+- **Manual testing support**: Commands for manual mount/unmount testing |
|
| 1011 |
+- **Status verification**: Built-in checks for successful operations |
|
| 1012 |
+- **Rollback capability**: Automatic cleanup on operation failures |
|
| 1013 |
+ |
|
| 1014 |
+### ๐จ Error Handling Improvements |
|
| 1015 |
+ |
|
| 1016 |
+#### Graceful Failure Handling |
|
| 1017 |
+- **Descriptive error messages**: Clear indication of what went wrong |
|
| 1018 |
+- **Suggested remedies**: Specific commands to fix common issues |
|
| 1019 |
+- **Logging preservation**: All errors logged for later analysis |
|
| 1020 |
+ |
|
| 1021 |
+#### Recovery Mechanisms |
|
| 1022 |
+- **Automatic rollback**: Failed operations clean up after themselves |
|
| 1023 |
+- **State consistency**: System left in known good state after failures |
|
| 1024 |
+- **Manual recovery**: Clear instructions for manual intervention when needed |
|
| 1025 |
+ |
|
| 1026 |
+### ๐ Breaking Changes |
|
| 1027 |
+ |
|
| 1028 |
+#### Configuration Format |
|
| 1029 |
+- **No breaking changes**: Existing configurations continue to work |
|
| 1030 |
+- **Enhanced format**: New configurations use optimized NFS settings |
|
| 1031 |
+- **Backwards compatibility**: Old configurations preserved during upgrades |
|
| 1032 |
+ |
|
| 1033 |
+#### Command Interface |
|
| 1034 |
+- **Extended syntax**: Commands now accept optional parameters |
|
| 1035 |
+- **Backwards compatibility**: Old syntax continues to work |
|
| 1036 |
+- **Enhanced features**: New parameters provide additional functionality |
|
| 1037 |
+ |
|
| 1038 |
+### ๐ Migration Guide |
|
| 1039 |
+ |
|
| 1040 |
+#### From Manual Configuration |
|
| 1041 |
+If you've been manually editing configuration files: |
|
| 1042 |
+1. **Backup existing configs**: `sudo cp /etc/pve/autonas/disks.conf ~/backup.conf` |
|
| 1043 |
+2. **Deploy via cluster system**: `./deploy.sh install` (preserves existing configs) |
|
| 1044 |
+3. **Use new tools**: `autonas list` to see current configurations |
|
| 1045 |
+ |
|
| 1046 |
+#### From Previous AutoNAS Version |
|
| 1047 |
+1. **Safe upgrade**: `./deploy.sh install` automatically preserves data |
|
| 1048 |
+2. **New features**: Start using `autonas add <UUID>` for new disks |
|
| 1049 |
+3. **Enhanced monitoring**: Use new logging commands for better visibility |
|
| 1050 |
+ |
|
| 1051 |
+### ๐ฏ Future Roadmap |
|
| 1052 |
+ |
|
| 1053 |
+#### Planned Features |
|
| 1054 |
+- **Web interface**: GUI for configuration management |
|
| 1055 |
+- **Notification system**: Email/webhook notifications for disk events |
|
| 1056 |
+- **Health monitoring**: SMART data integration and disk health reporting |
|
| 1057 |
+- **Cloud integration**: Automatic cloud backup triggers |
|
| 1058 |
+ |
|
| 1059 |
+#### Performance Improvements |
|
| 1060 |
+- **Parallel processing**: Concurrent handling of multiple disk operations |
|
| 1061 |
+- **Caching**: Configuration caching for faster operations |
|
| 1062 |
+- **Optimization**: Further NFS and mount option tuning |
|
| 1063 |
+ |
|
| 1064 |
+#### Security Enhancements |
|
| 1065 |
+- **TLS support**: Encrypted NFS where supported |
|
| 1066 |
+- **Access control**: Per-disk user/group restrictions |
|
| 1067 |
+- **Audit logging**: Enhanced security logging for compliance |
|
| 1068 |
+ |
|
| 1069 |
+--- |
|
| 1070 |
+ |
|
| 1071 |
+### ๐ Notes |
|
| 1072 |
+ |
|
| 1073 |
+- **Semantic versioning**: AutoNAS follows semver for version numbering |
|
| 1074 |
+- **Stability focus**: All changes prioritize data safety and system stability |
|
| 1075 |
+- **Community feedback**: Features developed based on user needs and feedback |
|
@@ -0,0 +1,394 @@ |
||
| 1 |
+# AutoNAS v3.0 - Sistem de Montare Automatฤ cu Unified Interface |
|
| 2 |
+ |
|
| 3 |
+AutoNAS este un sistem inteligent pentru montarea automatฤ a diskurilor externe cu configurarea IP-urilor, exporturilor NFS ศi **arhitectura revoluศionarฤ Background Import** pentru import scalabil de camere digitale. Sistemul detecteazฤ automat conectarea diskurilor USB/SATA externe, le monteazฤ, configureazฤ IP-uri pe interfeศe de reศea ศi exportฤ conศinutul prin NFS. |
|
| 4 |
+ |
|
| 5 |
+## ๐ **Nouฤ รฎn v3.0: Clean User Interface** |
|
| 6 |
+- **๐ Scriptul Unificat** - Un singur script `autonas` pentru toate operaศiunile |
|
| 7 |
+- **โก Interfaศฤ Curatฤ** - Doar comanda `autonas` vizibilฤ รฎn autocomplete |
|
| 8 |
+- **๐ Background Import** - Import-uri รฎn background fฤrฤ timeout constraints |
|
| 9 |
+- **๐ Cod Optimizat** - 47% reducere cod prin eliminarea duplicฤrilor |
|
| 10 |
+- **๐๏ธ Scripturi Organizate** - Toate scripturile interne ascunse รฎn `/usr/local/lib/autonas/` |
|
| 11 |
+ |
|
| 12 |
+## ๐ **Interfaศa Curatฤ AutoNAS** |
|
| 13 |
+ |
|
| 14 |
+### Comanda Principalฤ (Singura Vizibilฤ) |
|
| 15 |
+```bash |
|
| 16 |
+autonas <command> [options] |
|
| 17 |
+``` |
|
| 18 |
+*Doar comanda `autonas` apare รฎn autocomplete - toate scripturile interne sunt ascunse* |
|
| 19 |
+ |
|
| 20 |
+### Operaศiuni Disponibile |
|
| 21 |
+```bash |
|
| 22 |
+# Operaศiuni Diskuri |
|
| 23 |
+autonas attach <uuid> # Monteazฤ disk automat |
|
| 24 |
+autonas detach <uuid> # Demonteazฤ disk |
|
| 25 |
+autonas list # Listeazฤ diskurile configurate |
|
| 26 |
+ |
|
| 27 |
+# Management Configuraศii |
|
| 28 |
+autonas add [uuid] # Adaugฤ configuraศie nouฤ |
|
| 29 |
+autonas show # Afiศeazฤ toate device-urile detectate |
|
| 30 |
+autonas status # Status sistem complet |
|
| 31 |
+ |
|
| 32 |
+# Utilitฤศi |
|
| 33 |
+autonas mount <uuid> # Montare manualฤ |
|
| 34 |
+autonas umount <uuid> # Demontare manualฤ |
|
| 35 |
+autonas --help # Ajutor complet |
|
| 36 |
+``` |
|
| 37 |
+ |
|
| 38 |
+### Avantaje Interfaศฤ Curatฤ |
|
| 39 |
+- **Un singur command vizibil** - doar `autonas` รฎn autocomplete |
|
| 40 |
+- **Interfaศฤ consistentฤ** pentru toate operaศiunile |
|
| 41 |
+- **Cod optimizat** cu 47% reducere prin eliminarea duplicฤrilor |
|
| 42 |
+- **Scripturi organizate** - toate utilitarele interne รฎn `/usr/local/lib/autonas/` |
|
| 43 |
+- **Logging unificat** cu tag-uri comune |
|
| 44 |
+ |
|
| 45 |
+## ๐ Instalare รฎn Cluster |
|
| 46 |
+ |
|
| 47 |
+AutoNAS este destinat exclusiv pentru instalare pe cluster de servere prin sistemul de deploy remote: |
|
| 48 |
+ |
|
| 49 |
+```bash |
|
| 50 |
+# Cloneazฤ repository-ul |
|
| 51 |
+git clone <repository-url> autoNAS |
|
| 52 |
+cd autoNAS |
|
| 53 |
+``` |
|
| 54 |
+ |
|
| 55 |
+## ๐ Deploy Remote |
|
| 56 |
+ |
|
| 57 |
+AutoNAS foloseศte exclusiv deploy remote pentru instalarea ศi managementul pe nodurile cluster-ului: |
|
| 58 |
+ |
|
| 59 |
+```bash |
|
| 60 |
+# Instalare completฤ pe toate serverele (192.168.2.91-93) |
|
| 61 |
+./deploy.sh install |
|
| 62 |
+ |
|
| 63 |
+# Dezinstalare completฤ de pe toate serverele |
|
| 64 |
+./deploy.sh uninstall |
|
| 65 |
+ |
|
| 66 |
+# Instalare doar pe server specific |
|
| 67 |
+./deploy.sh install 192.168.2.91 |
|
| 68 |
+ |
|
| 69 |
+# Management servicii |
|
| 70 |
+./deploy.sh start # Porneศte serviciile |
|
| 71 |
+./deploy.sh restart # Restarteazฤ serviciile |
|
| 72 |
+./deploy.sh stop # Opreศte serviciile |
|
| 73 |
+./deploy.sh status # Verificฤ statusul |
|
| 74 |
+``` |
|
| 75 |
+ |
|
| 76 |
+### Caracteristici Deploy: |
|
| 77 |
+- โ **Instalare exclusiv cluster** - destinat doar pentru noduri multiple |
|
| 78 |
+- โ **Verificare host status** - testeazฤ disponibilitatea cu ping |
|
| 79 |
+- โ **Conectivitate SSH** - valideazฤ accesul prin chei SSH |
|
| 80 |
+- โ **Transfer eficient** - sincronizare cu rsync |
|
| 81 |
+- โ **Error handling** - management robust al erorilor |
|
| 82 |
+- โ **Logging colorat** - feedback clar pentru fiecare operaศie |
|
| 83 |
+ |
|
| 84 |
+### Pregฤtirea pentru Deploy: |
|
| 85 |
+1. **Configureazฤ cheile SSH** pe serverele ศintฤ |
|
| 86 |
+2. **Testeazฤ conectivitatea**: `./deploy.sh status` |
|
| 87 |
+3. **Deploy complet**: `./deploy.sh install` |
|
| 88 |
+ |
|
| 89 |
+## ๐ Funcศionalitฤศi Principale |
|
| 90 |
+ |
|
| 91 |
+### ๐ Detectare Automatฤ |
|
| 92 |
+- **Detectare prin udev** pentru diskuri USB, SATA externe ศi USB-to-SATA bridges |
|
| 93 |
+- **Suport pentru multiple tipuri** de device-uri (removable, ATA cu USB properties) |
|
| 94 |
+- **Detectare inteligentฤ** bazatฤ pe UUID filesystem |
|
| 95 |
+ |
|
| 96 |
+### ๐๏ธ Trei Tipuri de Configurare |
|
| 97 |
+ |
|
| 98 |
+#### 1. **NFS Share Complet** (acces de reศea) |
|
| 99 |
+```bash |
|
| 100 |
+autonas add <uuid> # Selecteazฤ [1] - NFS share complet |
|
| 101 |
+``` |
|
| 102 |
+- Montare automatฤ + configurare IP + export NFS |
|
| 103 |
+- Acces complet de reศea pentru alte maศini |
|
| 104 |
+- Perfect pentru backup servere ศi storage partajat |
|
| 105 |
+ |
|
| 106 |
+#### 2. **Montare Localฤ Simplฤ** (doar local) |
|
| 107 |
+```bash |
|
| 108 |
+autonas add <uuid> # Selecteazฤ [2] - Montare localฤ |
|
| 109 |
+``` |
|
| 110 |
+- Doar mount point local, fฤrฤ IP ศi NFS |
|
| 111 |
+- Ideal pentru storage local rapid |
|
| 112 |
+- Perfect pentru backup-uri ศi scratch space |
|
| 113 |
+ |
|
| 114 |
+#### 3. **Import Camerฤ Automat** (procesare media) |
|
| 115 |
+```bash |
|
| 116 |
+autonas add <uuid> # Selecteazฤ [3] - Import camerฤ |
|
| 117 |
+``` |
|
| 118 |
+- Mount โ import media files โ unmount automat |
|
| 119 |
+- Organizare automatฤ cu EXIF ศi UTC conversion |
|
| 120 |
+- Background processing fฤrฤ timeout constraints |
|
| 121 |
+ |
|
| 122 |
+### ๐ Configuraศie NFS Optimizatฤ |
|
| 123 |
+``` |
|
| 124 |
+*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0) |
|
| 125 |
+``` |
|
| 126 |
+ |
|
| 127 |
+### ๐ Management Inteligent |
|
| 128 |
+- **Configurare prin UUID** pentru identificare precisฤ |
|
| 129 |
+- **Protecศia configuraศiilor** utilizatorului la reinstalare |
|
| 130 |
+- **Logging detaliat** pentru debugging ศi monitorizare |
|
| 131 |
+- **Error handling robust** cu mesaje informative |
|
| 132 |
+ |
|
| 133 |
+## ๐ Comenzi de Management Rapide |
|
| 134 |
+ |
|
| 135 |
+### Flux de Lucru Tipic |
|
| 136 |
+```bash |
|
| 137 |
+# 1. Detecteazฤ UUID-ul diskului conectat |
|
| 138 |
+autonas show |
|
| 139 |
+ |
|
| 140 |
+# 2. Configureazฤ diskul (interactiv) |
|
| 141 |
+autonas add <uuid> |
|
| 142 |
+ |
|
| 143 |
+# 3. Verificฤ statusul |
|
| 144 |
+autonas list |
|
| 145 |
+autonas status |
|
| 146 |
+ |
|
| 147 |
+# 4. Monitorizeazฤ log-urile |
|
| 148 |
+journalctl -t autonas -f |
|
| 149 |
+``` |
|
| 150 |
+ |
|
| 151 |
+### Configurare Rapidฤ Exemplu |
|
| 152 |
+```bash |
|
| 153 |
+# Conecteazฤ diskul ศi detecteazฤ UUID |
|
| 154 |
+$ autonas show |
|
| 155 |
+Available storage devices: |
|
| 156 |
+[1] /dev/sdb1 โ UUID: 920fe1b7-4091-4d6a-bab8-2f48d8d704bc (ext4, 1.8TB) |
|
| 157 |
+ |
|
| 158 |
+# Configureazฤ pentru NFS |
|
| 159 |
+$ sudo autonas add 920fe1b7-4091-4d6a-bab8-2f48d8d704bc |
|
| 160 |
+Input name: backup-disk |
|
| 161 |
+Configuration type: [1] NFS share complet |
|
| 162 |
+Input IP: 192.168.10.25 |
|
| 163 |
+Input interface: thunderbridge |
|
| 164 |
+โ Configuration added and disk mounted! |
|
| 165 |
+ |
|
| 166 |
+# Verificฤ rezultatul |
|
| 167 |
+$ autonas list |
|
| 168 |
+Configured disks: |
|
| 169 |
+[1] backup-disk (920fe1b7-4091-4d6a-bab8-2f48d8d704bc) โ NFS: 192.168.10.25 |
|
| 170 |
+``` |
|
| 171 |
+ |
|
| 172 |
+## ๐ท Camera Import Automation |
|
| 173 |
+ |
|
| 174 |
+AutoNAS v3.0 introduce arhitectura revoluศionarฤ **Background Import** pentru import automat scalabil de camere digitale: |
|
| 175 |
+ |
|
| 176 |
+### ๐ Background Import Architecture |
|
| 177 |
+- **Service-Based Import** - Separare completฤ mount/import prin systemd services |
|
| 178 |
+- **Unlimited Duration** - Import-uri fฤrฤ timeout constraints (testat cu 300+ files) |
|
| 179 |
+- **Auto-Unmount** - Workflow complet automat mount โ import โ unmount |
|
| 180 |
+- **UTC Conversion** - Conversie perfectฤ UTC โ Local Time pentru EXIF |
|
| 181 |
+ |
|
| 182 |
+### Configurare Camera Import |
|
| 183 |
+```bash |
|
| 184 |
+# Configureazฤ camera pentru import automat |
|
| 185 |
+autonas add <camera-uuid> |
|
| 186 |
+# Selecteazฤ [3] - Import camerฤ automat |
|
| 187 |
+# Seteazฤ destinaศia: /mnt/storage/photos |
|
| 188 |
+``` |
|
| 189 |
+ |
|
| 190 |
+### Workflow Automat Camera |
|
| 191 |
+1. **Conectare camerฤ** โ AutoNAS detecteazฤ UUID-ul configurat ca IMPORT |
|
| 192 |
+2. **Montare temporarฤ** โ Mount point temporar creat automat |
|
| 193 |
+3. **Background Import** โ Service separat proceseazฤ fiศiere fฤrฤ timeout |
|
| 194 |
+4. **Organizare EXIF** โ Sortare automatฤ pe date din metadate |
|
| 195 |
+5. **Auto-Cleanup** โ Demontare automatฤ dupฤ finalizare |
|
| 196 |
+ |
|
| 197 |
+## ๐จ Troubleshooting Rapid |
|
| 198 |
+ |
|
| 199 |
+### Disk nu se detecteazฤ |
|
| 200 |
+```bash |
|
| 201 |
+journalctl -t autonas -f # Monitorizeazฤ log-urile |
|
| 202 |
+autonas show # Verificฤ device-urile detectate |
|
| 203 |
+udevadm monitor --subsystem-match=block # Debug udev |
|
| 204 |
+``` |
|
| 205 |
+ |
|
| 206 |
+### Probleme NFS |
|
| 207 |
+```bash |
|
| 208 |
+autonas status # Verificฤ configuraศia |
|
| 209 |
+showmount -e localhost # Verificฤ export-urile |
|
| 210 |
+systemctl status nfs-kernel-server |
|
| 211 |
+``` |
|
| 212 |
+ |
|
| 213 |
+### Probleme de Montare |
|
| 214 |
+```bash |
|
| 215 |
+autonas list # Verificฤ configuraศiile |
|
| 216 |
+autonas test <uuid> # Testeazฤ configuraศia specificฤ |
|
| 217 |
+mount | grep autonas # Verificฤ mount-urile active |
|
| 218 |
+``` |
|
| 219 |
+ |
|
| 220 |
+## โ๏ธ Arhitectura AutoNAS v3.0 |
|
| 221 |
+ |
|
| 222 |
+### ๐ Organizarea Scripturilor |
|
| 223 |
+``` |
|
| 224 |
+/usr/local/bin/ |
|
| 225 |
+โโโ autonas -> autonas.sh # Singura comandฤ vizibilฤ utilizatorului |
|
| 226 |
+โโโ autonas.sh # Script principal CLI (1,208 linii) |
|
| 227 |
+โโโ autonas-core.sh # Biblioteca centralฤ (1,044 linii) |
|
| 228 |
+ |
|
| 229 |
+/usr/local/lib/autonas/ # Scripturi interne (ascunse din autocomplete) |
|
| 230 |
+โโโ autonas-boot-scan.sh # Scanner la bootare |
|
| 231 |
+โโโ autonas-disk-handler.sh # Handler evenimente disk |
|
| 232 |
+โโโ autonas-media-importer.sh # Importer automat media |
|
| 233 |
+โโโ autonas-network-handler.sh # Handler eventi reศea |
|
| 234 |
+โโโ autonas-udev-wrapper.sh # Wrapper pentru udev |
|
| 235 |
+โโโ autonas-uninstall.sh # Uninstaller sistem |
|
| 236 |
+``` |
|
| 237 |
+ |
|
| 238 |
+### ๐ฏ Single Source of Truth |
|
| 239 |
+- **Zero duplicare cod** - toate funcศiile รฎn `autonas-core.sh` |
|
| 240 |
+- **Interfaศฤ unificatฤ** - toate operaศiunile prin comanda `autonas` |
|
| 241 |
+- **Scripturi ascunse** - experienศฤ utilizator curatฤ |
|
| 242 |
+ |
|
| 243 |
+### ๐ Realizฤri v3.0 |
|
| 244 |
+- **47% reducere cod** - ~2,300 linii eliminate prin refactorizare completฤ |
|
| 245 |
+- **Comandฤ unicฤ vizibilฤ** - doar `autonas` รฎn autocomplete |
|
| 246 |
+- **Organizare profesionalฤ** - toate utilitarele ascunse dar funcศionale |
|
| 247 |
+- **Integrare completฤ** - toate serviciile ศi regulile actualizate |
|
| 248 |
+ |
|
| 249 |
+## โ๏ธ Note Importante |
|
| 250 |
+ |
|
| 251 |
+1. **Ruleazฤ ca root**: Toate comenzile AutoNAS necesitฤ `sudo` |
|
| 252 |
+2. **Configuraศii persistente**: Diskurile configurate se monteazฤ automat la conectare |
|
| 253 |
+3. **Cleanup automat**: Demontarea curฤศฤ automat mount points, IP-uri ศi export-uri NFS |
|
| 254 |
+4. **Siguranศฤ date**: Dezinstalarea pฤstreazฤ toate datele ศi configuraศiile |
|
| 255 |
+5. **Script organizare**: Doar `autonas` vizibil - toate utilitarele รฎn `/usr/local/lib/autonas/` |
|
| 256 |
+ |
|
| 257 |
+## ๐ฏ Use Cases Rapide |
|
| 258 |
+ |
|
| 259 |
+- **๐ NFS Backup Server**: Disk extern โ detectare automatฤ โ export NFS instant |
|
| 260 |
+- **๐ Storage Local**: Backup-uri locale rapide fฤrฤ configurare reศea |
|
| 261 |
+- **๐ท Import Camere**: Conectare camerฤ โ import automat โ organizare EXIF |
|
| 262 |
+- **๐ง Development**: Mixed storage (local + NFS) pentru workflow-uri complexe |
|
| 263 |
+ |
|
| 264 |
+--- |
|
| 265 |
+ |
|
| 266 |
+**AutoNAS v3.0 - Clean Command Interface pentru Montare Automatฤ** ๐ |
|
| 267 |
+ |
|
| 268 |
+*Doar comanda `autonas` vizibilฤ - interfaศฤ profesionalฤ ศi curatฤ* |
|
| 269 |
+ |
|
| 270 |
+## Camera Import Automation |
|
| 271 |
+ |
|
| 272 |
+AutoNAS v3.0 introduce arhitectura revoluศionarฤ **Background Import** pentru import automat scalabil de camere digitale cu workflow complet `mount โ import โ unmount`. |
|
| 273 |
+ |
|
| 274 |
+### ๐ **NOUฤ ARHITECTURฤ BACKGROUND IMPORT** |
|
| 275 |
+- **๐ Service-Based Architecture** - Separare completฤ mount/import prin systemd services |
|
| 276 |
+- **โก Unlimited Duration** - Import-uri fฤrฤ timeout constraints (comprobat cu 300+ files) |
|
| 277 |
+- **๐ ๏ธ Auto-Unmount** - Demontare automatฤ dupฤ finalizarea import-ului |
|
| 278 |
+- **๐ Production Tested** - Validat cu camere reale Garmin (302 files, 100% success rate) |
|
| 279 |
+ |
|
| 280 |
+### Caracteristici Camera Import |
|
| 281 |
+- **๐ฏ Background Services** - Import ruleazฤ รฎn servicii systemd separate fฤrฤ timeout |
|
| 282 |
+- **Detectare automatฤ** a structurilor de foldere pentru camere (DCIM, PRIVATE, MP_ROOT) |
|
| 283 |
+- **Import cu EXIF** - organizare automatฤ pe baza metadatelor temporale cu UTC conversion |
|
| 284 |
+- **Multiple formate suportate**: MP4, MOV, JPG, JPEG, PNG, ARW, DNG, MP4, AVI, MKV |
|
| 285 |
+- **Organizare automatฤ pe date** din EXIF/QuickTime tags cu conversie UTC โ Local Time |
|
| 286 |
+- **Dry-run mode** pentru testare fฤrฤ modificarea fiศierelor |
|
| 287 |
+- **Progress tracking** cu statistici detaliate |
|
| 288 |
+- **Cleanup GLV files** pentru camerele Garmin |
|
| 289 |
+- **Scalabilitate Production** - Testat cu sute de fiศiere fฤrฤ probleme |
|
| 290 |
+ |
|
| 291 |
+### Format Configuraศie IMPORT |
|
| 292 |
+``` |
|
| 293 |
+UUID:NAME:IMPORT:IMPORT:MOUNT_POINT:DESTINATION_PATH[:SCRIPT_PATH] |
|
| 294 |
+``` |
|
| 295 |
+ |
|
| 296 |
+**Exemplu configuraศie:** |
|
| 297 |
+``` |
|
| 298 |
+1234-5678:camera-garmin:IMPORT:IMPORT:/mnt/autonas/camera-garmin:/mnt/storage/photos:/usr/local/bin/autonas-camera-import.sh |
|
| 299 |
+``` |
|
| 300 |
+ |
|
| 301 |
+### Workflow Import Automat (Background Architecture) |
|
| 302 |
+ |
|
| 303 |
+1. **Conectare camerฤ** โ AutoNAS detecteazฤ UUID-ul configurat ca IMPORT |
|
| 304 |
+2. **Montare temporarฤ** โ Attach service monteazฤ รฎn mount point temporar |
|
| 305 |
+3. **Background Import Launch** โ Manager lanseazฤ direct `run_background_import()` process |
|
| 306 |
+4. **Import nelimitat** โ Background service proceseazฤ fiศiere fฤrฤ timeout constraints |
|
| 307 |
+5. **Organizare EXIF** โ Fiศierele sunt sortate pe date din metadate (UTC โ Local Time) |
|
| 308 |
+6. **Auto-Cleanup** โ Background service apeleazฤ detach dupฤ finalizare |
|
| 309 |
+7. **Demontare automatฤ** โ Camera este demontatฤ automat |
|
| 310 |
+8. **Mount cleanup** โ Mount point temporar este curฤศat |
|
| 311 |
+ |
|
| 312 |
+**Avantaje Arhitecturฤ Background:** |
|
| 313 |
+- โ **Scalabilitate infinitฤ** - Nu existฤ timeout-uri systemd pentru import |
|
| 314 |
+- โ **Robusteศe** - Service separation previne crash-uri รฎn mount operations |
|
| 315 |
+- โ **Monitorizare** - Log-uri separate pentru fiecare etapฤ |
|
| 316 |
+- โ **Production Ready** - Testat cu 302 fiศiere, import complet รฎn 36 minute |
|
| 317 |
+ |
|
| 318 |
+### Configurare Camera Import |
|
| 319 |
+ |
|
| 320 |
+```bash |
|
| 321 |
+# Adaugฤ configuraศie pentru camerฤ |
|
| 322 |
+autonas-config.sh add |
|
| 323 |
+ |
|
| 324 |
+# Selecteazฤ UUID-ul camerei |
|
| 325 |
+# Input UUID: 1234-5678 |
|
| 326 |
+ |
|
| 327 |
+# Selecteazฤ tipul de configurare |
|
| 328 |
+# [3] - Import camerฤ automat |
|
| 329 |
+ |
|
| 330 |
+# Seteazฤ numele camerei |
|
| 331 |
+# Input name: camera-garmin |
|
| 332 |
+ |
|
| 333 |
+# Seteazฤ destinaศia pentru import |
|
| 334 |
+# Input destination: /mnt/storage/photos |
|
| 335 |
+ |
|
| 336 |
+# Script personalizat (opศional, default: autonas-camera-import.sh) |
|
| 337 |
+# Input script: [ENTER pentru default] |
|
| 338 |
+``` |
|
| 339 |
+ |
|
| 340 |
+### Script Import Personalizat |
|
| 341 |
+ |
|
| 342 |
+Poศi crea propriul script de import: |
|
| 343 |
+ |
|
| 344 |
+```bash |
|
| 345 |
+#!/bin/bash |
|
| 346 |
+# /usr/local/bin/my-camera-import.sh |
|
| 347 |
+ |
|
| 348 |
+MOUNT_POINT="$1" |
|
| 349 |
+DESTINATION="$2" |
|
| 350 |
+DISK_NAME="$3" |
|
| 351 |
+ |
|
| 352 |
+# Exemplu: Import specific pentru Canon |
|
| 353 |
+find "$MOUNT_POINT" -name "*.CR3" -exec cp {} "$DESTINATION/RAW/" \;
|
|
| 354 |
+find "$MOUNT_POINT" -name "*.JPG" -exec cp {} "$DESTINATION/JPEG/" \;
|
|
| 355 |
+ |
|
| 356 |
+echo "Import completed for $DISK_NAME" |
|
| 357 |
+exit 0 |
|
| 358 |
+``` |
|
| 359 |
+ |
|
| 360 |
+### Testare Configuration |
|
| 361 |
+ |
|
| 362 |
+```bash |
|
| 363 |
+# Listeazฤ configuraศiile |
|
| 364 |
+autonas-config.sh list |
|
| 365 |
+ |
|
| 366 |
+# Testeazฤ configuraศia IMPORT |
|
| 367 |
+autonas-config.sh test camera-uuid |
|
| 368 |
+ |
|
| 369 |
+# Monitorizeazฤ log-urile |
|
| 370 |
+journalctl -t autonas -f |
|
| 371 |
+``` |
|
| 372 |
+ |
|
| 373 |
+### Camera Import Script (autonas-camera-import.sh) |
|
| 374 |
+ |
|
| 375 |
+Script-ul default oferฤ: |
|
| 376 |
+- **Auto-detectare** structuri DCIM, PRIVATE, MP_ROOT |
|
| 377 |
+- **EXIF processing** cu exiftool pentru date precise |
|
| 378 |
+- **Organizare automatฤ** รฎn foldere YYYY-MM-DD |
|
| 379 |
+- **Redenumire intelligentฤ** cu timestamp-uri |
|
| 380 |
+- **Multiple opศiuni**: --dry-run, --verbose, --limit N |
|
| 381 |
+- **Error handling** robust cu logging detaliat |
|
| 382 |
+ |
|
| 383 |
+```bash |
|
| 384 |
+# Manual import test |
|
| 385 |
+autonas-camera-import.sh /mnt/camera /dest/path camera-name --dry-run --verbose |
|
| 386 |
+``` |
|
| 387 |
+ |
|
| 388 |
+--- |
|
| 389 |
+ |
|
| 390 |
+**AutoNAS v3.0 - Clean Command Interface pentru Montare Automatฤ** ๐ |
|
| 391 |
+ |
|
| 392 |
+*Doar comanda `autonas` vizibilฤ - interfaศฤ profesionalฤ ศi curatฤ* |
|
| 393 |
+ |
|
| 394 |
+*Dezvoltat pentru ecosistemul Proxmox/Debian cu focus pe automatizare ศi siguranศa datelor* |
|
@@ -0,0 +1,19 @@ |
||
| 1 |
+{
|
|
| 2 |
+ "cluster": {
|
|
| 3 |
+ "name": "madagascar", |
|
| 4 |
+ "nodes": [ |
|
| 5 |
+ {
|
|
| 6 |
+ "hostname": "ebony", |
|
| 7 |
+ "ip": "192.168.2.92" |
|
| 8 |
+ }, |
|
| 9 |
+ {
|
|
| 10 |
+ "hostname": "baobab", |
|
| 11 |
+ "ip": "192.168.2.91" |
|
| 12 |
+ }, |
|
| 13 |
+ {
|
|
| 14 |
+ "hostname": "tapia", |
|
| 15 |
+ "ip": "192.168.2.93" |
|
| 16 |
+ } |
|
| 17 |
+ ] |
|
| 18 |
+ } |
|
| 19 |
+} |
|
@@ -0,0 +1,27 @@ |
||
| 1 |
+# AutoNAS Network Interface Rules - Detects when network interfaces come online |
|
| 2 |
+# This is the primary mechanism for handling interface stability (not polling) |
|
| 3 |
+ |
|
| 4 |
+ |
|
| 5 |
+# Trigger when network interfaces are added/removed |
|
| 6 |
+ACTION=="add", SUBSYSTEM=="net", RUN+="/usr/local/bin/autonas-network-handler.sh interface_up %k" |
|
| 7 |
+ACTION=="remove", SUBSYSTEM=="net", RUN+="/usr/local/bin/autonas-network-handler.sh interface_down %k" |
|
| 8 |
+ |
|
| 9 |
+ |
|
| 10 |
+# Trigger on interface operational state changes (most important for USB/Thunderbolt) |
|
| 11 |
+ACTION=="change", SUBSYSTEM=="net", ATTR{operstate}=="up", RUN+="/usr/local/bin/autonas-network-handler.sh interface_change %k up"
|
|
| 12 |
+ACTION=="change", SUBSYSTEM=="net", ATTR{operstate}=="down", RUN+="/usr/local/bin/autonas-network-handler.sh interface_change %k down"
|
|
| 13 |
+ |
|
| 14 |
+ |
|
| 15 |
+# Additional triggers for carrier state (link up/down) |
|
| 16 |
+ACTION=="change", SUBSYSTEM=="net", ATTR{carrier}=="1", RUN+="/usr/local/bin/autonas-network-handler.sh interface_change %k carrier_up"
|
|
| 17 |
+ACTION=="change", SUBSYSTEM=="net", ATTR{carrier}=="0", RUN+="/usr/local/bin/autonas-network-handler.sh interface_change %k carrier_down"
|
|
| 18 |
+ |
|
| 19 |
+ |
|
| 20 |
+# Special handling for USB network interfaces (common with Thunderbolt/USB-C docks) |
|
| 21 |
+ACTION=="add", SUBSYSTEM=="net", ENV{ID_BUS}=="usb", RUN+="/usr/local/bin/autonas-network-handler.sh usb_interface_up %k"
|
|
| 22 |
+ACTION=="remove", SUBSYSTEM=="net", ENV{ID_BUS}=="usb", RUN+="/usr/local/bin/autonas-network-handler.sh usb_interface_down %k"
|
|
| 23 |
+ |
|
| 24 |
+ |
|
| 25 |
+# Handle Thunderbolt interfaces specifically |
|
| 26 |
+ACTION=="add", SUBSYSTEM=="net", DRIVERS=="thunderbolt", RUN+="/usr/local/bin/autonas-network-handler.sh usb_interface_up %k" |
|
| 27 |
+ACTION=="remove", SUBSYSTEM=="net", DRIVERS=="thunderbolt", RUN+="/usr/local/bin/autonas-network-handler.sh usb_interface_down %k" |
|
@@ -0,0 +1,38 @@ |
||
| 1 |
+# AutoNAS udev rules |
|
| 2 |
+# Place this file in /etc/udev/rules.d/ |
|
| 3 |
+ |
|
| 4 |
+# Rule for USB storage devices - trigger on add/remove |
|
| 5 |
+# Detect USB disks (whole disk) |
|
| 6 |
+ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="usb", RUN+="/bin/systemctl start autonas-attach@%E{ID_FS_UUID}.service"
|
|
| 7 |
+ACTION=="remove", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="usb", RUN+="/usr/local/bin/autonas-disk-handler.sh detach %E{ID_FS_UUID}"
|
|
| 8 |
+ |
|
| 9 |
+# Detect USB partitions (more common case) |
|
| 10 |
+ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="partition", ENV{ID_BUS}=="usb", RUN+="/bin/systemctl start autonas-attach@%E{ID_FS_UUID}.service"
|
|
| 11 |
+ACTION=="remove", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="partition", ENV{ID_BUS}=="usb", RUN+="/usr/local/bin/autonas-disk-handler.sh detach %E{ID_FS_UUID}"
|
|
| 12 |
+ |
|
| 13 |
+# Rule for ATA/SATA external storage devices (USB-to-SATA bridges) |
|
| 14 |
+# Detect ATA disks (whole disk) - these appear as ATA but are actually USB external |
|
| 15 |
+ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ATTRS{removable}=="1", RUN+="/usr/local/bin/autonas-udev-wrapper.sh attach %E{ID_FS_UUID}"
|
|
| 16 |
+ACTION=="remove", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ATTRS{removable}=="1", RUN+="/usr/local/bin/autonas-disk-handler.sh detach %E{ID_FS_UUID}"
|
|
| 17 |
+ |
|
| 18 |
+# Detect ATA partitions (more common case) |
|
| 19 |
+ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="partition", ENV{ID_BUS}=="ata", ATTRS{removable}=="1", RUN+="/usr/local/bin/autonas-udev-wrapper.sh attach %E{ID_FS_UUID}"
|
|
| 20 |
+ACTION=="remove", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="partition", ENV{ID_BUS}=="ata", ATTRS{removable}=="1", RUN+="/usr/local/bin/autonas-disk-handler.sh detach %E{ID_FS_UUID}"
|
|
| 21 |
+ |
|
| 22 |
+# Special rule for USB-to-SATA bridges that appear as ATA but have USB properties |
|
| 23 |
+# This safely identifies external USB drives that appear as ATA |
|
| 24 |
+ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_USB_TYPE}=="disk", RUN+="/usr/local/bin/autonas-udev-wrapper.sh attach %E{ID_FS_UUID}"
|
|
| 25 |
+ACTION=="remove", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="disk", ENV{ID_BUS}=="ata", ENV{ID_USB_TYPE}=="disk", RUN+="/usr/local/bin/autonas-disk-handler.sh detach %E{ID_FS_UUID}"
|
|
| 26 |
+ |
|
| 27 |
+# Detect USB-to-SATA bridge partitions |
|
| 28 |
+ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="partition", ENV{ID_BUS}=="ata", ENV{ID_USB_TYPE}=="disk", RUN+="/usr/local/bin/autonas-udev-wrapper.sh attach %E{ID_FS_UUID}"
|
|
| 29 |
+ACTION=="remove", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="partition", ENV{ID_BUS}=="ata", ENV{ID_USB_TYPE}=="disk", RUN+="/usr/local/bin/autonas-disk-handler.sh detach %E{ID_FS_UUID}"
|
|
| 30 |
+ |
|
| 31 |
+# Rule for SCSI external storage devices |
|
| 32 |
+# Detect removable disks (whole disk) - exclude USB devices (handled above) |
|
| 33 |
+ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="disk", ATTRS{removable}=="1", ENV{ID_BUS}!="usb", RUN+="/bin/systemctl start autonas-attach@%E{ID_FS_UUID}.service"
|
|
| 34 |
+ACTION=="remove", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="disk", ATTRS{removable}=="1", ENV{ID_BUS}!="usb", RUN+="/usr/local/bin/autonas-disk-handler.sh detach %E{ID_FS_UUID}"
|
|
| 35 |
+ |
|
| 36 |
+# Detect removable partitions (more common case) - exclude USB devices (handled above) |
|
| 37 |
+ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="partition", ATTRS{removable}=="1", ENV{ID_BUS}!="usb", RUN+="/bin/systemctl start autonas-attach@%E{ID_FS_UUID}.service"
|
|
| 38 |
+ACTION=="remove", SUBSYSTEM=="block", ENV{ID_FS_UUID}!="", ENV{DEVTYPE}=="partition", ATTRS{removable}=="1", ENV{ID_BUS}!="usb", RUN+="/usr/local/bin/autonas-disk-handler.sh detach %E{ID_FS_UUID}"
|
|
@@ -0,0 +1,22 @@ |
||
| 1 |
+# AutoNAS Default Configuration |
|
| 2 |
+# This file is sourced by AutoNAS scripts to set default behavior |
|
| 3 |
+ |
|
| 4 |
+# Debug mode - set to "true" to enable verbose logging |
|
| 5 |
+# When enabled, all AutoNAS operations will produce detailed debug output |
|
| 6 |
+AUTONAS_DEBUG="false" |
|
| 7 |
+ |
|
| 8 |
+# Log level for AutoNAS operations |
|
| 9 |
+# Possible values: error, warn, info, debug |
|
| 10 |
+AUTONAS_LOG_LEVEL="info" |
|
| 11 |
+ |
|
| 12 |
+# Default timeout for disk operations (in seconds) |
|
| 13 |
+AUTONAS_DISK_TIMEOUT="30" |
|
| 14 |
+ |
|
| 15 |
+# Enable automatic cleanup of orphaned entries at boot |
|
| 16 |
+AUTONAS_CLEANUP_ORPHANS="true" |
|
| 17 |
+ |
|
| 18 |
+# NFS export defaults |
|
| 19 |
+AUTONAS_NFS_DEFAULT_OPTIONS="*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0)" |
|
| 20 |
+ |
|
| 21 |
+# Udev rules timeout |
|
| 22 |
+AUTONAS_UDEV_TIMEOUT="10" |
|
@@ -0,0 +1,15 @@ |
||
| 1 |
+[Unit] |
|
| 2 |
+Description=AutoNAS Attach Disk %i |
|
| 3 |
+After=local-fs.target |
|
| 4 |
+After=systemd-udev-settle.service |
|
| 5 |
+ |
|
| 6 |
+[Service] |
|
| 7 |
+Type=oneshot |
|
| 8 |
+ExecStart=/usr/local/bin/autonas-disk-handler.sh attach-deferred %i |
|
| 9 |
+RemainAfterExit=no |
|
| 10 |
+TimeoutSec=120 |
|
| 11 |
+StandardOutput=journal |
|
| 12 |
+StandardError=journal |
|
| 13 |
+ |
|
| 14 |
+[Install] |
|
| 15 |
+WantedBy=multi-user.target |
|
@@ -0,0 +1,18 @@ |
||
| 1 |
+[Unit] |
|
| 2 |
+Description=AutoNAS Boot Scanner - Detect and attach configured disks at boot |
|
| 3 |
+After=local-fs.target |
|
| 4 |
+After=systemd-udev-settle.service |
|
| 5 |
+After=network.target |
|
| 6 |
+After=nfs-kernel-server.service |
|
| 7 |
+Wants=nfs-kernel-server.service |
|
| 8 |
+ |
|
| 9 |
+[Service] |
|
| 10 |
+Type=oneshot |
|
| 11 |
+ExecStart=/usr/local/bin/autonas-boot-scan.sh |
|
| 12 |
+RemainAfterExit=yes |
|
| 13 |
+TimeoutSec=300 |
|
| 14 |
+StandardOutput=journal |
|
| 15 |
+StandardError=journal |
|
| 16 |
+ |
|
| 17 |
+[Install] |
|
| 18 |
+WantedBy=multi-user.target |
|
@@ -0,0 +1,20 @@ |
||
| 1 |
+[Unit] |
|
| 2 |
+Description=AutoNAS Main Service - Automatic disk mounting and NFS export system |
|
| 3 |
+Documentation=file:///usr/local/share/doc/autonas/README.md |
|
| 4 |
+After=local-fs.target |
|
| 5 |
+After=systemd-udev-settle.service |
|
| 6 |
+After=network.target |
|
| 7 |
+After=nfs-kernel-server.service |
|
| 8 |
+Wants=nfs-kernel-server.service |
|
| 9 |
+RequiredBy=autonas-boot-scan.service |
|
| 10 |
+ |
|
| 11 |
+[Service] |
|
| 12 |
+Type=oneshot |
|
| 13 |
+RemainAfterExit=yes |
|
| 14 |
+ExecStart=/bin/true |
|
| 15 |
+ExecReload=/usr/local/bin/autonas-disk-handler.sh reload |
|
| 16 |
+StandardOutput=journal |
|
| 17 |
+StandardError=journal |
|
| 18 |
+ |
|
| 19 |
+[Install] |
|
| 20 |
+WantedBy=multi-user.target |
|
@@ -0,0 +1,22 @@ |
||
| 1 |
+# AutoSMART Default Configuration |
|
| 2 |
+# This file is sourced by AutoSMART scripts to set default behavior |
|
| 3 |
+ |
|
| 4 |
+# Debug mode - set to "true" to enable verbose logging |
|
| 5 |
+# When enabled, all AutoSMART operations will produce detailed debug output |
|
| 6 |
+AUTOSMART_DEBUG="false" |
|
| 7 |
+ |
|
| 8 |
+# Log level for AutoSMART operations |
|
| 9 |
+# Possible values: error, warn, info, debug |
|
| 10 |
+AUTOSMART_LOG_LEVEL="info" |
|
| 11 |
+ |
|
| 12 |
+# Default timeout for disk operations (in seconds) |
|
| 13 |
+AUTOSMART_DISK_TIMEOUT="30" |
|
| 14 |
+ |
|
| 15 |
+# Enable automatic cleanup of orphaned entries at boot |
|
| 16 |
+AUTOSMART_CLEANUP_ORPHANS="true" |
|
| 17 |
+ |
|
| 18 |
+# NFS export defaults |
|
| 19 |
+AUTOSMART_NFS_DEFAULT_OPTIONS="*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0)" |
|
| 20 |
+ |
|
| 21 |
+# Udev rules timeout |
|
| 22 |
+AUTOSMART_UDEV_TIMEOUT="10" |
|
@@ -0,0 +1,30 @@ |
||
| 1 |
+# AutoNAS Disk Configuration File |
|
| 2 |
+# |
|
| 3 |
+# Configuration format for different device types: |
|
| 4 |
+# |
|
| 5 |
+# External Storage (NFS): |
|
| 6 |
+# UUID:name:ip:interface:mount_point:nfs_options |
|
| 7 |
+# |
|
| 8 |
+# Camera Import (integrated media importer): |
|
| 9 |
+# UUID:name:IMPORT:IMPORT:temp_mount_point:destination_path |
|
| 10 |
+# Note: Media importer script (/usr/local/bin/autonas-media-importer.sh) is built-in and non-configurable |
|
| 11 |
+# |
|
| 12 |
+# Examples: |
|
| 13 |
+# f6ac3d86-5681-4b33-bc64-aa272b333057:ext01:192.168.10.21:thunderbridge:/mnt/autonas/ext01:*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0) |
|
| 14 |
+# 8765-4321:camera-real:IMPORT:IMPORT:/mnt/autonas/camera-real:/mnt/autonas/ext01/@Camera/import |
|
| 15 |
+# |
|
| 16 |
+# Default NFS Options (AutoNAS standard): *(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0) |
|
| 17 |
+# - rw: Read/write access |
|
| 18 |
+# - all_squash: Map all users to anonymous |
|
| 19 |
+# - insecure: Allow connections from non-reserved ports |
|
| 20 |
+# - async: Asynchronous writes (better performance) |
|
| 21 |
+# - no_subtree_check: Better performance |
|
| 22 |
+# - anonuid=0,anongid=0: Map anonymous to root (UID/GID 0) |
|
| 23 |
+# |
|
| 24 |
+# Rules for disk names: |
|
| 25 |
+# - Max 50 characters |
|
| 26 |
+# - Only letters, numbers, hyphens (-), underscores (_), and at symbol (@) |
|
| 27 |
+# - Must start with letter or number |
|
| 28 |
+# - Cannot use reserved names (root, home, tmp, etc.) |
|
| 29 |
+# |
|
| 30 |
+# Add your disk configurations below: |
|
@@ -0,0 +1,409 @@ |
||
| 1 |
+#!/bin/bash |
|
| 2 |
+ |
|
| 3 |
+# AutoNAS Remote Deploy Script |
|
| 4 |
+# Instaleazฤ ศi gestioneazฤ AutoNAS pe serverele remote 192.168.2.91-93 |
|
| 5 |
+ |
|
| 6 |
+set -e # Exit on any error |
|
| 7 |
+ |
|
| 8 |
+ |
|
| 9 |
+# Configuraศii |
|
| 10 |
+SSH_USER="root" |
|
| 11 |
+REMOTE_DIR="/tmp/autonas-deploy" |
|
| 12 |
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
| 13 |
+ |
|
| 14 |
+# Parse cluster.json for nodes |
|
| 15 |
+parse_cluster_nodes() {
|
|
| 16 |
+ local json_file="$SCRIPT_DIR/cluster.json" |
|
| 17 |
+ if ! [ -f "$json_file" ]; then |
|
| 18 |
+ log_error "cluster.json not found in $SCRIPT_DIR" |
|
| 19 |
+ exit 1 |
|
| 20 |
+ fi |
|
| 21 |
+ jq -c '.cluster.nodes[]' "$json_file" 2>/dev/null |
|
| 22 |
+} |
|
| 23 |
+ |
|
| 24 |
+# Build arrays of IPs and hostnames |
|
| 25 |
+get_targets() {
|
|
| 26 |
+ local nodes_json |
|
| 27 |
+ nodes_json=$(parse_cluster_nodes) |
|
| 28 |
+ local ips=() |
|
| 29 |
+ local names=() |
|
| 30 |
+ while IFS= read -r node; do |
|
| 31 |
+ local ip name |
|
| 32 |
+ ip=$(echo "$node" | jq -r '.ip') |
|
| 33 |
+ name=$(echo "$node" | jq -r '.hostname') |
|
| 34 |
+ ips+=("$ip")
|
|
| 35 |
+ names+=("$name")
|
|
| 36 |
+ done <<< "$nodes_json" |
|
| 37 |
+ echo "${ips[@]}"
|
|
| 38 |
+} |
|
| 39 |
+ |
|
| 40 |
+# Get node name by IP |
|
| 41 |
+get_node_name() {
|
|
| 42 |
+ local search_ip="$1" |
|
| 43 |
+ local nodes_json |
|
| 44 |
+ nodes_json=$(parse_cluster_nodes) |
|
| 45 |
+ while IFS= read -r node; do |
|
| 46 |
+ local ip name |
|
| 47 |
+ ip=$(echo "$node" | jq -r '.ip') |
|
| 48 |
+ name=$(echo "$node" | jq -r '.hostname') |
|
| 49 |
+ if [[ "$ip" == "$search_ip" ]]; then |
|
| 50 |
+ echo "$name" |
|
| 51 |
+ return |
|
| 52 |
+ fi |
|
| 53 |
+ done <<< "$nodes_json" |
|
| 54 |
+ echo "$search_ip" |
|
| 55 |
+} |
|
| 56 |
+ |
|
| 57 |
+# Culori pentru output |
|
| 58 |
+RED='\033[0;31m' |
|
| 59 |
+GREEN='\033[0;32m' |
|
| 60 |
+YELLOW='\033[1;33m' |
|
| 61 |
+BLUE='\033[0;34m' |
|
| 62 |
+NC='\033[0m' # No Color |
|
| 63 |
+ |
|
| 64 |
+# Funcศii helper |
|
| 65 |
+log_info() {
|
|
| 66 |
+ echo -e "${BLUE}[INFO]${NC} $1"
|
|
| 67 |
+} |
|
| 68 |
+ |
|
| 69 |
+log_success() {
|
|
| 70 |
+ echo -e "${GREEN}[SUCCESS]${NC} $1"
|
|
| 71 |
+} |
|
| 72 |
+ |
|
| 73 |
+log_warning() {
|
|
| 74 |
+ echo -e "${YELLOW}[WARNING]${NC} $1"
|
|
| 75 |
+} |
|
| 76 |
+ |
|
| 77 |
+log_error() {
|
|
| 78 |
+ echo -e "${RED}[ERROR]${NC} $1"
|
|
| 79 |
+} |
|
| 80 |
+ |
|
| 81 |
+print_banner() {
|
|
| 82 |
+ echo "======================================" |
|
| 83 |
+ echo " AutoNAS Remote Deploy Script" |
|
| 84 |
+ echo "======================================" |
|
| 85 |
+ echo "" |
|
| 86 |
+} |
|
| 87 |
+ |
|
| 88 |
+# Funcศie pentru verificarea dacฤ hostul este up |
|
| 89 |
+check_host_up() {
|
|
| 90 |
+ local target="$1" |
|
| 91 |
+ log_info "Verificare dacฤ hostul $target este accesibil..." |
|
| 92 |
+ |
|
| 93 |
+ # Pentru simplitate, verificฤm direct SSH รฎn loc de ping pe macOS |
|
| 94 |
+ if [[ "$OSTYPE" == "darwin"* ]]; then |
|
| 95 |
+ # macOS: verificare directฤ SSH cu timeout rapid |
|
| 96 |
+ if ssh -o ConnectTimeout=3 -o BatchMode=yes -o LogLevel=ERROR "$SSH_USER@$target" "echo 'OK'" >/dev/null 2>&1; then |
|
| 97 |
+ log_success "Host $target este UP ศi SSH funcศioneazฤ" |
|
| 98 |
+ return 0 |
|
| 99 |
+ else |
|
| 100 |
+ log_warning "Host $target nu este accesibil prin SSH" |
|
| 101 |
+ return 1 |
|
| 102 |
+ fi |
|
| 103 |
+ else |
|
| 104 |
+ # Linux: folosim ping normal |
|
| 105 |
+ if timeout 5 ping -c 2 -W 3 "$target" >/dev/null 2>&1; then |
|
| 106 |
+ log_success "Host $target este UP" |
|
| 107 |
+ return 0 |
|
| 108 |
+ else |
|
| 109 |
+ log_warning "Host $target este DOWN sau nu rฤspunde la ping" |
|
| 110 |
+ return 1 |
|
| 111 |
+ fi |
|
| 112 |
+ fi |
|
| 113 |
+} |
|
| 114 |
+ |
|
| 115 |
+# Funcศie pentru verificarea conectivitฤศii SSH |
|
| 116 |
+check_ssh_connectivity() {
|
|
| 117 |
+ local target="$1" |
|
| 118 |
+ |
|
| 119 |
+ # Verificฤ mai รฎntรขi dacฤ hostul este up |
|
| 120 |
+ if ! check_host_up "$target"; then |
|
| 121 |
+ log_warning "Skipping SSH test pentru $target - hostul nu este up" |
|
| 122 |
+ return 1 |
|
| 123 |
+ fi |
|
| 124 |
+ |
|
| 125 |
+ log_info "Verificare conectivitate SSH pentru $target..." |
|
| 126 |
+ |
|
| 127 |
+ if ssh -o ConnectTimeout=5 -o BatchMode=yes -o LogLevel=ERROR "$SSH_USER@$target" "echo 'SSH OK'" >/dev/null 2>&1; then |
|
| 128 |
+ log_success "SSH conectare OK pentru $target" |
|
| 129 |
+ return 0 |
|
| 130 |
+ else |
|
| 131 |
+ log_error "SSH conectare FAILED pentru $target - verificฤ cheia SSH" |
|
| 132 |
+ return 1 |
|
| 133 |
+ fi |
|
| 134 |
+} |
|
| 135 |
+ |
|
| 136 |
+# Funcศie pentru copierea fiศierelor pe ศinta remotฤ |
|
| 137 |
+copy_files() {
|
|
| 138 |
+ local target="$1" |
|
| 139 |
+ log_info "Copierea fiศierelor pe $target..." |
|
| 140 |
+ |
|
| 141 |
+ # Creare director temporar pe ศintฤ |
|
| 142 |
+ ssh -o LogLevel=ERROR "$SSH_USER@$target" "mkdir -p $REMOTE_DIR" |
|
| 143 |
+ |
|
| 144 |
+ # Copierea tuturor fiศierelor proiectului |
|
| 145 |
+ rsync -avz --delete --quiet \ |
|
| 146 |
+ --exclude='.git' \ |
|
| 147 |
+ --exclude='deploy.sh' \ |
|
| 148 |
+ --exclude='*.log' \ |
|
| 149 |
+ "$SCRIPT_DIR/" "$SSH_USER@$target:$REMOTE_DIR/" |
|
| 150 |
+ |
|
| 151 |
+ log_success "Fiศiere copiate pe $target" |
|
| 152 |
+} |
|
| 153 |
+ |
|
| 154 |
+# Funcศie genericฤ pentru executarea unei comenzi pe ศinta remotฤ |
|
| 155 |
+run_on_target() {
|
|
| 156 |
+ local target="$1" |
|
| 157 |
+ local action="$2" |
|
| 158 |
+ local success_msg="$3" |
|
| 159 |
+ local error_msg="$4" |
|
| 160 |
+ local cmd_arg="${5:-$action}"
|
|
| 161 |
+ |
|
| 162 |
+ log_info "$action pe $target..." |
|
| 163 |
+ if ssh -o LogLevel=ERROR "$SSH_USER@$target" "bash $REMOTE_DIR/scripts/install.sh $cmd_arg"; then |
|
| 164 |
+ log_success "$success_msg" |
|
| 165 |
+ else |
|
| 166 |
+ log_error "$error_msg" |
|
| 167 |
+ return 1 |
|
| 168 |
+ fi |
|
| 169 |
+} |
|
| 170 |
+ |
|
| 171 |
+# Funcศie pentru verificarea statusului (nu necesitฤ rsync) |
|
| 172 |
+check_status() {
|
|
| 173 |
+ local target="$1" |
|
| 174 |
+ log_info "Verificarea statusului AutoNAS pe $target..." |
|
| 175 |
+ # รncearcฤ sฤ foloseascฤ uninstaller pentru status sau install.sh dacฤ existฤ |
|
| 176 |
+ ssh -o LogLevel=ERROR "$SSH_USER@$target" " |
|
| 177 |
+ if [ -f '$REMOTE_DIR/scripts/install.sh' ]; then |
|
| 178 |
+ bash $REMOTE_DIR/scripts/install.sh status |
|
| 179 |
+ elif [ -f '/usr/local/bin/autonas' ]; then |
|
| 180 |
+ /usr/local/bin/autonas --version 2>/dev/null || echo 'AutoNAS instalat dar versiune necunoscutฤ' |
|
| 181 |
+ else |
|
| 182 |
+ echo 'AutoNAS nu este instalat' |
|
| 183 |
+ fi |
|
| 184 |
+ " |
|
| 185 |
+} |
|
| 186 |
+ |
|
| 187 |
+# Funcศie pentru cleanup (ศtergerea fiศierelor temporare) |
|
| 188 |
+cleanup() {
|
|
| 189 |
+ local target="$1" |
|
| 190 |
+ log_info "Cleanup fiศiere temporare pe $target..." |
|
| 191 |
+ |
|
| 192 |
+ ssh -o LogLevel=ERROR "$SSH_USER@$target" "rm -rf $REMOTE_DIR" || true |
|
| 193 |
+ log_success "Cleanup realizat pe $target" |
|
| 194 |
+} |
|
| 195 |
+ |
|
| 196 |
+# Funcศie pentru cleanup complet (delegat cฤtre uninstaller) |
|
| 197 |
+force_cleanup() {
|
|
| 198 |
+ local target="$1" |
|
| 199 |
+ log_info "Cleanup forศat AutoNAS pe $target..." |
|
| 200 |
+ |
|
| 201 |
+ # รncearcฤ sฤ foloseascฤ uninstaller-ul existent |
|
| 202 |
+ ssh -o LogLevel=ERROR "$SSH_USER@$target" " |
|
| 203 |
+ if [ -f '/usr/local/bin/autonas-uninstall.sh' ]; then |
|
| 204 |
+ bash /usr/local/bin/autonas-uninstall.sh --force |
|
| 205 |
+ elif [ -f '/usr/local/lib/autonas/autonas-uninstall.sh' ]; then |
|
| 206 |
+ bash /usr/local/lib/autonas/autonas-uninstall.sh --force |
|
| 207 |
+ else |
|
| 208 |
+ echo 'WARNING: Nu s-a gฤsit uninstaller-ul AutoNAS' |
|
| 209 |
+ fi |
|
| 210 |
+ " || true |
|
| 211 |
+ |
|
| 212 |
+ ssh -o LogLevel=ERROR "$SSH_USER@$target" "rm -rf $REMOTE_DIR" || true |
|
| 213 |
+ log_success "Cleanup forศat completat pe $target" |
|
| 214 |
+} |
|
| 215 |
+ |
|
| 216 |
+# Funcศie pentru uninstall AutoNAS (delegat cฤtre uninstaller) |
|
| 217 |
+uninstall_autonas() {
|
|
| 218 |
+ local target="$1" |
|
| 219 |
+ log_info "Dezinstalarea AutoNAS pe $target..." |
|
| 220 |
+ |
|
| 221 |
+ if ssh -o LogLevel=ERROR "$SSH_USER@$target" " |
|
| 222 |
+ if [ -f '/usr/local/bin/autonas-uninstall.sh' ]; then |
|
| 223 |
+ bash /usr/local/bin/autonas-uninstall.sh |
|
| 224 |
+ rm -f '/usr/local/bin/autonas-uninstall.sh' |
|
| 225 |
+ echo 'AutoNAS dezinstalat cu succes!' |
|
| 226 |
+ elif [ -f '/usr/local/lib/autonas/autonas-uninstall.sh' ]; then |
|
| 227 |
+ bash /usr/local/lib/autonas/autonas-uninstall.sh |
|
| 228 |
+ echo 'AutoNAS dezinstalat cu succes!' |
|
| 229 |
+ else |
|
| 230 |
+ echo 'ERROR: Scriptul de dezinstalare nu a fost gฤsit!' |
|
| 231 |
+ exit 1 |
|
| 232 |
+ fi |
|
| 233 |
+ "; then |
|
| 234 |
+ log_success "AutoNAS dezinstalat cu succes de pe $target" |
|
| 235 |
+ else |
|
| 236 |
+ log_error "Dezinstalarea AutoNAS a eศuat pe $target" |
|
| 237 |
+ return 1 |
|
| 238 |
+ fi |
|
| 239 |
+} |
|
| 240 |
+ |
|
| 241 |
+# Funcศii de delegare pentru operaศiunile de servicii |
|
| 242 |
+install_autonas() {
|
|
| 243 |
+ run_on_target "$1" "Instalarea AutoNAS" "AutoNAS instalat cu succes pe $1" "Instalarea AutoNAS a eศuat pe $1" "install" |
|
| 244 |
+} |
|
| 245 |
+ |
|
| 246 |
+start_services() {
|
|
| 247 |
+ run_on_target "$1" "Pornirea serviciilor AutoNAS" "Serviciile AutoNAS pornite cu succes pe $1" "Pornirea serviciilor AutoNAS a eศuat pe $1" "start" |
|
| 248 |
+} |
|
| 249 |
+ |
|
| 250 |
+restart_services() {
|
|
| 251 |
+ run_on_target "$1" "Restartarea serviciilor AutoNAS" "Serviciile AutoNAS restartate cu succes pe $1" "Restartarea serviciilor AutoNAS a eศuat pe $1" "restart" |
|
| 252 |
+} |
|
| 253 |
+ |
|
| 254 |
+stop_services() {
|
|
| 255 |
+ run_on_target "$1" "Oprirea serviciilor AutoNAS" "Serviciile AutoNAS oprite cu succes pe $1" "Oprirea serviciilor AutoNAS a eศuat pe $1" "stop" |
|
| 256 |
+} |
|
| 257 |
+ |
|
| 258 |
+check_dependencies() {
|
|
| 259 |
+ run_on_target "$1" "Verificarea dependinศelor" "Verificarea dependinศelor completatฤ pe $1" "Verificarea dependinศelor a eศuat pe $1" "check-deps" |
|
| 260 |
+} |
|
| 261 |
+ |
|
| 262 |
+install_dependencies() {
|
|
| 263 |
+ run_on_target "$1" "Instalarea dependinศelor" "Dependinศele instalate cu succes pe $1" "Instalarea dependinศelor a eศuat pe $1" "install-deps" |
|
| 264 |
+} |
|
| 265 |
+ |
|
| 266 |
+# Funcศie pentru afiศarea ajutorului |
|
| 267 |
+show_help() {
|
|
| 268 |
+ echo "Utilizare: $0 [COMANDฤ] [ศINTE]" |
|
| 269 |
+ echo "" |
|
| 270 |
+ echo "COMENZI:" |
|
| 271 |
+ echo " install - Instalare completฤ AutoNAS pe toate ศintele" |
|
| 272 |
+ echo " install-deps - Instalare doar dependinศe (nfs-kernel-server, autofs, etc.)" |
|
| 273 |
+ echo " check-deps - Verificare dependinศe fฤrฤ instalare" |
|
| 274 |
+ echo " uninstall - Dezinstalare completฤ AutoNAS de pe toate ศintele" |
|
| 275 |
+ echo " start - Porneศte serviciile AutoNAS" |
|
| 276 |
+ echo " restart - Restarteazฤ serviciile AutoNAS" |
|
| 277 |
+ echo " stop - Opreศte serviciile AutoNAS" |
|
| 278 |
+ echo " status - Afiศeazฤ statusul serviciilor" |
|
| 279 |
+ echo " cleanup - ศterge fiศierele temporare" |
|
| 280 |
+ echo " force-cleanup - Cleanup agresiv (inclusiv fiศiere orfane)" |
|
| 281 |
+ echo " help - Afiศeazฤ acest ajutor" |
|
| 282 |
+ echo "" |
|
| 283 |
+ echo "ศINTE (opศional):" |
|
| 284 |
+ echo " 192.168.2.91, 192.168.2.92, 192.168.2.93" |
|
| 285 |
+ echo " Dacฤ nu se specificฤ ศinte, se ruleazฤ pe toate" |
|
| 286 |
+ echo "" |
|
| 287 |
+ echo "Exemple:" |
|
| 288 |
+ echo " $0 check-deps # Verificฤ dependinศele pe toate ศintele" |
|
| 289 |
+ echo " $0 install-deps # Instaleazฤ dependinศele pe toate ศintele" |
|
| 290 |
+ echo " $0 install # Instaleazฤ pe toate ศintele" |
|
| 291 |
+ echo " $0 install 192.168.2.91 # Instaleazฤ doar pe .91" |
|
| 292 |
+ echo " $0 restart 192.168.2.91 192.168.2.92 # Restart pe .91 ศi .92" |
|
| 293 |
+ echo " $0 status # Verificฤ statusul pe toate ศintele" |
|
| 294 |
+ echo " $0 force-cleanup # Cleanup agresiv pe toate nodurile" |
|
| 295 |
+} |
|
| 296 |
+ |
|
| 297 |
+# Funcศie pentru executarea unei comenzi pe ศinte specifice |
|
| 298 |
+execute_command() {
|
|
| 299 |
+ local command="$1" |
|
| 300 |
+ shift |
|
| 301 |
+ local targets_to_use=("$@")
|
|
| 302 |
+ |
|
| 303 |
+ |
|
| 304 |
+ # Dacฤ nu sunt specificate ศinte, foloseศte toate din cluster.json |
|
| 305 |
+ if [ ${#targets_to_use[@]} -eq 0 ]; then
|
|
| 306 |
+ targets_to_use=( $(get_targets) ) |
|
| 307 |
+ fi |
|
| 308 |
+ |
|
| 309 |
+ log_info "Executare comandฤ '$command' pe noduri: ${targets_to_use[*]}"
|
|
| 310 |
+ |
|
| 311 |
+ for target in "${targets_to_use[@]}"; do
|
|
| 312 |
+ local node_name |
|
| 313 |
+ node_name=$(get_node_name "$target") |
|
| 314 |
+ echo "" |
|
| 315 |
+ echo "======================================" |
|
| 316 |
+ echo " $command pe $node_name ($target)" |
|
| 317 |
+ echo "======================================" |
|
| 318 |
+ |
|
| 319 |
+ if ! check_ssh_connectivity "$target"; then |
|
| 320 |
+ log_error "Nu se poate conecta la $target - skip" |
|
| 321 |
+ continue |
|
| 322 |
+ fi |
|
| 323 |
+ |
|
| 324 |
+ case "$command" in |
|
| 325 |
+ "install") |
|
| 326 |
+ copy_files "$target" |
|
| 327 |
+ install_autonas "$target" |
|
| 328 |
+ start_services "$target" |
|
| 329 |
+ cleanup "$target" |
|
| 330 |
+ ;; |
|
| 331 |
+ "install-deps") |
|
| 332 |
+ copy_files "$target" |
|
| 333 |
+ install_dependencies "$target" |
|
| 334 |
+ cleanup "$target" |
|
| 335 |
+ ;; |
|
| 336 |
+ "check-deps") |
|
| 337 |
+ copy_files "$target" |
|
| 338 |
+ check_dependencies "$target" |
|
| 339 |
+ cleanup "$target" |
|
| 340 |
+ ;; |
|
| 341 |
+ "uninstall") |
|
| 342 |
+ uninstall_autonas "$target" |
|
| 343 |
+ cleanup "$target" |
|
| 344 |
+ ;; |
|
| 345 |
+ "start") |
|
| 346 |
+ start_services "$target" |
|
| 347 |
+ ;; |
|
| 348 |
+ "restart") |
|
| 349 |
+ restart_services "$target" |
|
| 350 |
+ ;; |
|
| 351 |
+ "stop") |
|
| 352 |
+ stop_services "$target" |
|
| 353 |
+ ;; |
|
| 354 |
+ "status") |
|
| 355 |
+ check_status "$target" |
|
| 356 |
+ ;; |
|
| 357 |
+ "cleanup") |
|
| 358 |
+ cleanup "$target" |
|
| 359 |
+ ;; |
|
| 360 |
+ "force-cleanup") |
|
| 361 |
+ force_cleanup "$target" |
|
| 362 |
+ ;; |
|
| 363 |
+ *) |
|
| 364 |
+ log_error "Comandฤ necunoscutฤ: $command" |
|
| 365 |
+ return 1 |
|
| 366 |
+ ;; |
|
| 367 |
+ esac |
|
| 368 |
+ |
|
| 369 |
+ if [ $? -eq 0 ]; then |
|
| 370 |
+ log_success "Comandฤ '$command' executatฤ cu succes pe $target" |
|
| 371 |
+ else |
|
| 372 |
+ log_error "Comandฤ '$command' a eศuat pe $target" |
|
| 373 |
+ fi |
|
| 374 |
+ done |
|
| 375 |
+} |
|
| 376 |
+ |
|
| 377 |
+# Main function |
|
| 378 |
+main() {
|
|
| 379 |
+ print_banner |
|
| 380 |
+ |
|
| 381 |
+ # Verificฤ dacฤ avem argumente |
|
| 382 |
+ if [ $# -eq 0 ]; then |
|
| 383 |
+ show_help |
|
| 384 |
+ exit 1 |
|
| 385 |
+ fi |
|
| 386 |
+ |
|
| 387 |
+ local command="$1" |
|
| 388 |
+ shift |
|
| 389 |
+ |
|
| 390 |
+ case "$command" in |
|
| 391 |
+ "install"|"install-deps"|"check-deps"|"uninstall"|"start"|"restart"|"stop"|"status"|"cleanup"|"force-cleanup") |
|
| 392 |
+ execute_command "$command" "$@" |
|
| 393 |
+ ;; |
|
| 394 |
+ "help"|"--help"|"-h") |
|
| 395 |
+ show_help |
|
| 396 |
+ ;; |
|
| 397 |
+ *) |
|
| 398 |
+ log_error "Comandฤ necunoscutฤ: $command" |
|
| 399 |
+ echo "" |
|
| 400 |
+ show_help |
|
| 401 |
+ exit 1 |
|
| 402 |
+ ;; |
|
| 403 |
+ esac |
|
| 404 |
+} |
|
| 405 |
+ |
|
| 406 |
+# Verificฤ dacฤ ruleazฤ ca script principal |
|
| 407 |
+if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
|
|
| 408 |
+ main "$@" |
|
| 409 |
+fi |
|
@@ -0,0 +1,218 @@ |
||
| 1 |
+#!/bin/bash |
|
| 2 |
+ |
|
| 3 |
+# AutoNAS Boot Scanner - Detects and attaches configured disks at boot time |
|
| 4 |
+# This script runs at boot to handle disks that are already connected |
|
| 5 |
+# Uses autonas-core.sh for all business logic |
|
| 6 |
+ |
|
| 7 |
+# Load the AutoNAS core library |
|
| 8 |
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
| 9 |
+source "${SCRIPT_DIR}/autonas-core.sh" || {
|
|
| 10 |
+ echo "Error: Cannot load AutoNAS core library" >&2 |
|
| 11 |
+ exit 1 |
|
| 12 |
+} |
|
| 13 |
+ |
|
| 14 |
+# Set LOG_TAG for this component |
|
| 15 |
+LOG_TAG="autonas-boot-scanner" |
|
| 16 |
+ |
|
| 17 |
+# Main boot scan function |
|
| 18 |
+boot_scan() {
|
|
| 19 |
+ log_message "AutoNAS boot scan started" "info" |
|
| 20 |
+ |
|
| 21 |
+ if [ ! -f "$CONFIG_FILE" ]; then |
|
| 22 |
+ log_message "No configuration file found at $CONFIG_FILE - boot scan skipped" "info" |
|
| 23 |
+ return 0 |
|
| 24 |
+ fi |
|
| 25 |
+ |
|
| 26 |
+ local total_disks=0 |
|
| 27 |
+ local processed_disks=0 |
|
| 28 |
+ local attached_disks=0 |
|
| 29 |
+ local already_mounted=0 |
|
| 30 |
+ |
|
| 31 |
+ # Read configuration file and process each disk |
|
| 32 |
+ while IFS=':' read -r uuid name ip interface mount_point nfs_options; do |
|
| 33 |
+ # Skip empty lines and comments |
|
| 34 |
+ [[ -z "$uuid" || "$uuid" =~ ^[[:space:]]*# ]] && continue |
|
| 35 |
+ |
|
| 36 |
+ total_disks=$((total_disks + 1)) |
|
| 37 |
+ |
|
| 38 |
+ log_message "Checking configured disk: $name (UUID: $uuid)" "info" |
|
| 39 |
+ |
|
| 40 |
+ # Check if UUID exists as a device |
|
| 41 |
+ if check_uuid_exists "$uuid"; then |
|
| 42 |
+ processed_disks=$((processed_disks + 1)) |
|
| 43 |
+ |
|
| 44 |
+ # Check mount status |
|
| 45 |
+ case $(is_disk_mounted "$uuid" "$mount_point"; echo $?) in |
|
| 46 |
+ 0) |
|
| 47 |
+ log_message "Disk $name already mounted correctly at $mount_point" "info" |
|
| 48 |
+ already_mounted=$((already_mounted + 1)) |
|
| 49 |
+ ;; |
|
| 50 |
+ 1) |
|
| 51 |
+ log_message "Disk $name mounted elsewhere, attempting AutoNAS attach" "info" |
|
| 52 |
+ if handle_attach "$uuid"; then |
|
| 53 |
+ attached_disks=$((attached_disks + 1)) |
|
| 54 |
+ log_message "Successfully attached disk $name via AutoNAS" "info" |
|
| 55 |
+ else |
|
| 56 |
+ log_message "Failed to attach disk $name" "warning" |
|
| 57 |
+ fi |
|
| 58 |
+ ;; |
|
| 59 |
+ 2) |
|
| 60 |
+ log_message "Disk $name not mounted, attaching via AutoNAS" "info" |
|
| 61 |
+ if handle_attach "$uuid"; then |
|
| 62 |
+ attached_disks=$((attached_disks + 1)) |
|
| 63 |
+ log_message "Successfully attached disk $name via AutoNAS" "info" |
|
| 64 |
+ else |
|
| 65 |
+ log_message "Failed to attach disk $name" "warning" |
|
| 66 |
+ fi |
|
| 67 |
+ ;; |
|
| 68 |
+ esac |
|
| 69 |
+ else |
|
| 70 |
+ log_message "Disk $name (UUID: $uuid) not present - skipping" "debug" |
|
| 71 |
+ fi |
|
| 72 |
+ |
|
| 73 |
+ done < "$CONFIG_FILE" |
|
| 74 |
+ |
|
| 75 |
+ # Summary report |
|
| 76 |
+ log_message "AutoNAS boot scan completed:" "info" |
|
| 77 |
+ log_message " - Total configured disks: $total_disks" "info" |
|
| 78 |
+ log_message " - Present disks processed: $processed_disks" "info" |
|
| 79 |
+ log_message " - Already mounted correctly: $already_mounted" "info" |
|
| 80 |
+ log_message " - Newly attached: $attached_disks" "info" |
|
| 81 |
+ |
|
| 82 |
+ if [ $attached_disks -gt 0 ] || [ $already_mounted -gt 0 ]; then |
|
| 83 |
+ log_message "AutoNAS boot scan successful - ${attached_disks} disks attached, ${already_mounted} already mounted" "info"
|
|
| 84 |
+ else |
|
| 85 |
+ log_message "AutoNAS boot scan completed - no disks required processing" "info" |
|
| 86 |
+ fi |
|
| 87 |
+} |
|
| 88 |
+ |
|
| 89 |
+# Function to clean up orphaned mounts and NFS exports at boot |
|
| 90 |
+cleanup_boot_orphans() {
|
|
| 91 |
+ log_message "Starting boot-time cleanup of orphaned mounts and exports..." "info" |
|
| 92 |
+ |
|
| 93 |
+ local cleaned_mounts=0 |
|
| 94 |
+ local cleaned_exports=0 |
|
| 95 |
+ |
|
| 96 |
+ # Get list of configured disks |
|
| 97 |
+ if [ ! -f "$CONFIG_FILE" ]; then |
|
| 98 |
+ log_message "No configuration file found - skipping orphan cleanup" "info" |
|
| 99 |
+ return 0 |
|
| 100 |
+ fi |
|
| 101 |
+ |
|
| 102 |
+ local configured_uuids=$(grep -v "^#\|^$" "$CONFIG_FILE" | cut -d':' -f1 | sort) |
|
| 103 |
+ |
|
| 104 |
+ # Check mounted disks in /mnt/autonas/ |
|
| 105 |
+ if [ -d "/mnt/autonas" ]; then |
|
| 106 |
+ for mount_dir in /mnt/autonas/*/; do |
|
| 107 |
+ [ ! -d "$mount_dir" ] && continue |
|
| 108 |
+ |
|
| 109 |
+ local mount_name=$(basename "$mount_dir") |
|
| 110 |
+ local is_configured=false |
|
| 111 |
+ |
|
| 112 |
+ # Check if this mount corresponds to a configured disk AND is physically present |
|
| 113 |
+ local config_uuid="" |
|
| 114 |
+ while IFS=':' read -r uuid name ip hostname mount_point nfs_options; do |
|
| 115 |
+ [ -z "$uuid" ] && continue |
|
| 116 |
+ if [ "$name" = "$mount_name" ]; then |
|
| 117 |
+ config_uuid="$uuid" |
|
| 118 |
+ # Check if the disk is physically present and mounted |
|
| 119 |
+ if [ -n "$(blkid | grep "$uuid")" ] && mountpoint -q "$mount_dir"; then |
|
| 120 |
+ is_configured=true |
|
| 121 |
+ fi |
|
| 122 |
+ break |
|
| 123 |
+ fi |
|
| 124 |
+ done < <(grep -v "^#\|^$" "$CONFIG_FILE") |
|
| 125 |
+ |
|
| 126 |
+ if [ "$is_configured" = false ]; then |
|
| 127 |
+ log_message "Found orphaned mount point: $mount_dir" "info" |
|
| 128 |
+ |
|
| 129 |
+ # Unmount if mounted |
|
| 130 |
+ if mountpoint -q "$mount_dir"; then |
|
| 131 |
+ log_message "Unmounting orphaned mount: $mount_dir" "info" |
|
| 132 |
+ umount "$mount_dir" 2>/dev/null || {
|
|
| 133 |
+ log_message "Failed to unmount $mount_dir - forcing" "warn" |
|
| 134 |
+ umount -f "$mount_dir" 2>/dev/null || true |
|
| 135 |
+ } |
|
| 136 |
+ fi |
|
| 137 |
+ |
|
| 138 |
+ # Remove empty directory |
|
| 139 |
+ if [ -d "$mount_dir" ] && [ -z "$(ls -A "$mount_dir" 2>/dev/null)" ]; then |
|
| 140 |
+ rmdir "$mount_dir" 2>/dev/null && {
|
|
| 141 |
+ log_message "Removed orphaned mount directory: $mount_dir" "info" |
|
| 142 |
+ ((cleaned_mounts++)) |
|
| 143 |
+ } |
|
| 144 |
+ fi |
|
| 145 |
+ fi |
|
| 146 |
+ done |
|
| 147 |
+ fi |
|
| 148 |
+ |
|
| 149 |
+ # Clean up orphaned NFS exports |
|
| 150 |
+ if [ -f "/etc/exports" ]; then |
|
| 151 |
+ local temp_file=$(mktemp) |
|
| 152 |
+ local skip_next=false |
|
| 153 |
+ local current_uuid="" |
|
| 154 |
+ |
|
| 155 |
+ while IFS= read -r line; do |
|
| 156 |
+ if [[ "$line" =~ ^#\ AutoNAS\ Export\ -\ UUID:([^[:space:]]+)\ NAME: ]]; then |
|
| 157 |
+ current_uuid="${BASH_REMATCH[1]}"
|
|
| 158 |
+ local is_configured=false |
|
| 159 |
+ |
|
| 160 |
+ # Check if this UUID is configured AND physically present |
|
| 161 |
+ while IFS= read -r configured_uuid; do |
|
| 162 |
+ [ -z "$configured_uuid" ] && continue |
|
| 163 |
+ if [ "$configured_uuid" = "$current_uuid" ]; then |
|
| 164 |
+ # Additional check: verify the disk is physically present |
|
| 165 |
+ if [ -n "$(blkid | grep "$current_uuid")" ]; then |
|
| 166 |
+ is_configured=true |
|
| 167 |
+ fi |
|
| 168 |
+ break |
|
| 169 |
+ fi |
|
| 170 |
+ done <<< "$configured_uuids" |
|
| 171 |
+ |
|
| 172 |
+ if [ "$is_configured" = false ]; then |
|
| 173 |
+ log_message "Found orphaned NFS export for UUID: $current_uuid" "info" |
|
| 174 |
+ skip_next=true |
|
| 175 |
+ ((cleaned_exports++)) |
|
| 176 |
+ continue |
|
| 177 |
+ else |
|
| 178 |
+ echo "$line" >> "$temp_file" |
|
| 179 |
+ skip_next=false |
|
| 180 |
+ fi |
|
| 181 |
+ elif [ "$skip_next" = true ]; then |
|
| 182 |
+ # Skip the export line for orphaned entry |
|
| 183 |
+ skip_next=false |
|
| 184 |
+ continue |
|
| 185 |
+ else |
|
| 186 |
+ echo "$line" >> "$temp_file" |
|
| 187 |
+ fi |
|
| 188 |
+ done < /etc/exports |
|
| 189 |
+ |
|
| 190 |
+ # Replace exports file if we made changes |
|
| 191 |
+ if [ "$cleaned_exports" -gt 0 ]; then |
|
| 192 |
+ mv "$temp_file" /etc/exports |
|
| 193 |
+ # Reload NFS exports |
|
| 194 |
+ exportfs -ra 2>/dev/null || true |
|
| 195 |
+ log_message "Reloaded NFS exports after cleanup" "info" |
|
| 196 |
+ else |
|
| 197 |
+ rm -f "$temp_file" |
|
| 198 |
+ fi |
|
| 199 |
+ fi |
|
| 200 |
+ |
|
| 201 |
+ if [ "$cleaned_mounts" -gt 0 ] || [ "$cleaned_exports" -gt 0 ]; then |
|
| 202 |
+ log_message "Boot cleanup completed: $cleaned_mounts mount points, $cleaned_exports NFS exports removed" "info" |
|
| 203 |
+ else |
|
| 204 |
+ log_message "Boot cleanup completed: no orphaned entries found" "info" |
|
| 205 |
+ fi |
|
| 206 |
+} |
|
| 207 |
+ |
|
| 208 |
+# Wait for system to be ready |
|
| 209 |
+log_message "Waiting for system to stabilize..." "info" |
|
| 210 |
+sleep 5 |
|
| 211 |
+ |
|
| 212 |
+# Clean up any orphaned mounts and exports first |
|
| 213 |
+cleanup_boot_orphans |
|
| 214 |
+ |
|
| 215 |
+# Run the boot scan |
|
| 216 |
+boot_scan |
|
| 217 |
+ |
|
| 218 |
+exit 0 |
|
@@ -0,0 +1,1115 @@ |
||
| 1 |
+#!/bin/bash |
|
| 2 |
+ |
|
| 3 |
+# AutoNAS Core Library |
|
| 4 |
+# Shared business logic for all AutoNAS components |
|
| 5 |
+# This library contains all core functions to eliminate duplication |
|
| 6 |
+ |
|
| 7 |
+# Load default configuration |
|
| 8 |
+if [ -f "/etc/default/autonas" ]; then |
|
| 9 |
+ source "/etc/default/autonas" |
|
| 10 |
+fi |
|
| 11 |
+ |
|
| 12 |
+# Set defaults if not loaded from config |
|
| 13 |
+AUTONAS_DEBUG="${AUTONAS_DEBUG:-false}"
|
|
| 14 |
+AUTONAS_LOG_LEVEL="${AUTONAS_LOG_LEVEL:-info}"
|
|
| 15 |
+ |
|
| 16 |
+# Global configuration |
|
| 17 |
+CONFIG_FILE="/etc/pve/autonas/disks.conf" |
|
| 18 |
+MOUNT_BASE="/mnt/autonas" |
|
| 19 |
+ |
|
| 20 |
+# ============================================================================ |
|
| 21 |
+# LOGGING FUNCTIONS |
|
| 22 |
+# ============================================================================ |
|
| 23 |
+ |
|
| 24 |
+# Function to log messages with debug support |
|
| 25 |
+log_message() {
|
|
| 26 |
+ local message="$1" |
|
| 27 |
+ local priority="${2:-info}"
|
|
| 28 |
+ local context="${3:-${LOG_TAG:-autonas}}"
|
|
| 29 |
+ |
|
| 30 |
+ # Skip debug messages unless debug mode is enabled |
|
| 31 |
+ if [ "$priority" = "debug" ] && [ "$AUTONAS_DEBUG" != "true" ]; then |
|
| 32 |
+ return 0 |
|
| 33 |
+ fi |
|
| 34 |
+ |
|
| 35 |
+ # Log to syslog with facility local0 and specified priority |
|
| 36 |
+ logger -p "local0.$priority" -t "$context" "$message" |
|
| 37 |
+ |
|
| 38 |
+ # Also log to stderr if debug mode is enabled |
|
| 39 |
+ if [ "$AUTONAS_DEBUG" = "true" ]; then |
|
| 40 |
+ echo "[$context] [$priority] $message" >&2 |
|
| 41 |
+ fi |
|
| 42 |
+ |
|
| 43 |
+ # Also echo to stdout/stderr for interactive use |
|
| 44 |
+ if [ -t 1 ]; then |
|
| 45 |
+ echo "$(date '+%Y-%m-%d %H:%M:%S') - $message" |
|
| 46 |
+ fi |
|
| 47 |
+} |
|
| 48 |
+ |
|
| 49 |
+# Function for debug logging (convenience function) |
|
| 50 |
+debug_log() {
|
|
| 51 |
+ log_message "$1" "debug" "${2:-${LOG_TAG:-autonas}}"
|
|
| 52 |
+} |
|
| 53 |
+ |
|
| 54 |
+# ============================================================================ |
|
| 55 |
+# CONFIGURATION FUNCTIONS |
|
| 56 |
+# ============================================================================ |
|
| 57 |
+ |
|
| 58 |
+# Function to get disk configuration by UUID |
|
| 59 |
+get_disk_config() {
|
|
| 60 |
+ local uuid="$1" |
|
| 61 |
+ grep "^${uuid}:" "$CONFIG_FILE" 2>/dev/null
|
|
| 62 |
+} |
|
| 63 |
+ |
|
| 64 |
+# Function to parse configuration line |
|
| 65 |
+parse_config() {
|
|
| 66 |
+ local config="$1" |
|
| 67 |
+ IFS=':' read -r uuid name ip interface mount_point nfs_options <<< "$config" |
|
| 68 |
+ echo "$uuid" "$name" "$ip" "$interface" "$mount_point" "$nfs_options" |
|
| 69 |
+} |
|
| 70 |
+ |
|
| 71 |
+# Function to get configuration for a specific UUID (handles systemd escaping) |
|
| 72 |
+get_config() {
|
|
| 73 |
+ local uuid="$1" |
|
| 74 |
+ |
|
| 75 |
+ if [ -z "$uuid" ]; then |
|
| 76 |
+ return 1 |
|
| 77 |
+ fi |
|
| 78 |
+ |
|
| 79 |
+ # Un-escape systemd-escaped UUID (e.g., 8765\x2d4321 -> 8765-4321) |
|
| 80 |
+ local unescaped_uuid |
|
| 81 |
+ unescaped_uuid=$(echo "$uuid" | sed 's/\\x2d/-/g') |
|
| 82 |
+ |
|
| 83 |
+ # Find configuration line for UUID (try both escaped and unescaped) |
|
| 84 |
+ grep "^${unescaped_uuid}:" "$CONFIG_FILE" 2>/dev/null || grep "^${uuid}:" "$CONFIG_FILE" 2>/dev/null
|
|
| 85 |
+} |
|
| 86 |
+ |
|
| 87 |
+# Function to get configuration for a specific name |
|
| 88 |
+get_config_by_name() {
|
|
| 89 |
+ local name="$1" |
|
| 90 |
+ |
|
| 91 |
+ if [ -z "$name" ]; then |
|
| 92 |
+ return 1 |
|
| 93 |
+ fi |
|
| 94 |
+ |
|
| 95 |
+ # Find configuration line by name (second field) |
|
| 96 |
+ grep ":${name}:" "$CONFIG_FILE" 2>/dev/null
|
|
| 97 |
+} |
|
| 98 |
+ |
|
| 99 |
+# ============================================================================ |
|
| 100 |
+# VALIDATION FUNCTIONS |
|
| 101 |
+# ============================================================================ |
|
| 102 |
+ |
|
| 103 |
+# Function to validate UUID format |
|
| 104 |
+validate_uuid() {
|
|
| 105 |
+ local uuid="$1" |
|
| 106 |
+ # UUID can be standard format (8-4-4-4-12) or shorter formats used by some filesystems |
|
| 107 |
+ if [[ "$uuid" =~ ^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$ ]] || \
|
|
| 108 |
+ [[ "$uuid" =~ ^[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}$ ]] || \
|
|
| 109 |
+ [[ "$uuid" =~ ^[0-9A-Fa-f]{8}$ ]]; then
|
|
| 110 |
+ return 0 |
|
| 111 |
+ fi |
|
| 112 |
+ return 1 |
|
| 113 |
+} |
|
| 114 |
+ |
|
| 115 |
+# Function to validate disk name |
|
| 116 |
+validate_disk_name() {
|
|
| 117 |
+ local name="$1" |
|
| 118 |
+ |
|
| 119 |
+ # Check length (max 50 characters) |
|
| 120 |
+ if [[ ${#name} -gt 50 ]]; then
|
|
| 121 |
+ return 1 |
|
| 122 |
+ fi |
|
| 123 |
+ |
|
| 124 |
+ # Check if it starts with letter or number |
|
| 125 |
+ if [[ ! "$name" =~ ^[a-zA-Z0-9] ]]; then |
|
| 126 |
+ return 1 |
|
| 127 |
+ fi |
|
| 128 |
+ |
|
| 129 |
+ # Check allowed characters: letters, numbers, hyphens, underscores, at symbol |
|
| 130 |
+ if [[ ! "$name" =~ ^[a-zA-Z0-9_@-]+$ ]]; then |
|
| 131 |
+ return 1 |
|
| 132 |
+ fi |
|
| 133 |
+ |
|
| 134 |
+ # Check for reserved names |
|
| 135 |
+ local reserved_names=("root" "home" "tmp" "var" "usr" "etc" "proc" "sys" "dev" "boot" "mnt" "media" "opt" "srv")
|
|
| 136 |
+ for reserved in "${reserved_names[@]}"; do
|
|
| 137 |
+ if [[ "$name" == "$reserved" ]]; then |
|
| 138 |
+ return 1 |
|
| 139 |
+ fi |
|
| 140 |
+ done |
|
| 141 |
+ |
|
| 142 |
+ return 0 |
|
| 143 |
+} |
|
| 144 |
+ |
|
| 145 |
+# Function to check if UUID exists in configuration |
|
| 146 |
+check_uuid_exists_in_config() {
|
|
| 147 |
+ local uuid="$1" |
|
| 148 |
+ grep -q "^${uuid}:" "$CONFIG_FILE" 2>/dev/null
|
|
| 149 |
+} |
|
| 150 |
+ |
|
| 151 |
+# Function to list existing disk names (helper for duplicate detection) |
|
| 152 |
+list_existing_disk_names() {
|
|
| 153 |
+ if [[ -f "$CONFIG_FILE" ]]; then |
|
| 154 |
+ echo "Existing disk names:" |
|
| 155 |
+ while IFS=':' read -r uuid name rest; do |
|
| 156 |
+ if [[ -n "$uuid" && -n "$name" ]]; then |
|
| 157 |
+ echo " โข $name (UUID: ${uuid:0:8}...)"
|
|
| 158 |
+ fi |
|
| 159 |
+ done < "$CONFIG_FILE" |
|
| 160 |
+ fi |
|
| 161 |
+} |
|
| 162 |
+ |
|
| 163 |
+# Function to check if disk name already exists in configuration |
|
| 164 |
+check_disk_name_exists() {
|
|
| 165 |
+ local name="$1" |
|
| 166 |
+ if [[ -f "$CONFIG_FILE" ]]; then |
|
| 167 |
+ # Check if name exists as second field in any configuration line |
|
| 168 |
+ grep -q ":${name}:" "$CONFIG_FILE" 2>/dev/null
|
|
| 169 |
+ fi |
|
| 170 |
+} |
|
| 171 |
+ |
|
| 172 |
+# Function to validate disk name (includes duplicate check) |
|
| 173 |
+validate_disk_name_complete() {
|
|
| 174 |
+ local name="$1" |
|
| 175 |
+ local uuid="$2" # Optional: exclude current UUID from duplicate check |
|
| 176 |
+ |
|
| 177 |
+ # Run basic validation first |
|
| 178 |
+ if ! validate_disk_name "$name"; then |
|
| 179 |
+ return 1 |
|
| 180 |
+ fi |
|
| 181 |
+ |
|
| 182 |
+ # Check for duplicate names |
|
| 183 |
+ if check_disk_name_exists "$name"; then |
|
| 184 |
+ # If UUID provided, check if this name belongs to the same UUID (allow updates) |
|
| 185 |
+ if [[ -n "$uuid" ]] && [[ -f "$CONFIG_FILE" ]]; then |
|
| 186 |
+ local existing_uuid=$(grep ":${name}:" "$CONFIG_FILE" | cut -d':' -f1)
|
|
| 187 |
+ if [[ "$existing_uuid" == "$uuid" ]]; then |
|
| 188 |
+ # Same UUID, same name - this is an update, allow it |
|
| 189 |
+ return 0 |
|
| 190 |
+ fi |
|
| 191 |
+ fi |
|
| 192 |
+ # Different UUID or no UUID provided - this is a duplicate |
|
| 193 |
+ return 2 # Special return code for duplicate names |
|
| 194 |
+ fi |
|
| 195 |
+ |
|
| 196 |
+ return 0 |
|
| 197 |
+} |
|
| 198 |
+ |
|
| 199 |
+# Function to check if UUID exists in system |
|
| 200 |
+check_uuid_exists() {
|
|
| 201 |
+ local uuid="$1" |
|
| 202 |
+ blkid | grep -q "$uuid" |
|
| 203 |
+} |
|
| 204 |
+ |
|
| 205 |
+# Function to check if disk is already mounted at AutoNAS location |
|
| 206 |
+is_disk_mounted() {
|
|
| 207 |
+ local uuid="$1" |
|
| 208 |
+ local mount_point="$2" |
|
| 209 |
+ |
|
| 210 |
+ # Check if already mounted at the correct location |
|
| 211 |
+ if mount | grep -q "UUID=$uuid.*$mount_point"; then |
|
| 212 |
+ return 0 # Already mounted correctly |
|
| 213 |
+ fi |
|
| 214 |
+ |
|
| 215 |
+ # Check if mounted elsewhere |
|
| 216 |
+ if mount | grep -q "UUID=$uuid"; then |
|
| 217 |
+ return 1 # Mounted elsewhere |
|
| 218 |
+ fi |
|
| 219 |
+ |
|
| 220 |
+ return 2 # Not mounted |
|
| 221 |
+} |
|
| 222 |
+ |
|
| 223 |
+# ============================================================================ |
|
| 224 |
+# DEVICE FUNCTIONS |
|
| 225 |
+# ============================================================================ |
|
| 226 |
+ |
|
| 227 |
+# Function to get device information |
|
| 228 |
+get_device_info() {
|
|
| 229 |
+ local uuid="$1" |
|
| 230 |
+ |
|
| 231 |
+ # Find device by UUID using blkid |
|
| 232 |
+ local device_line |
|
| 233 |
+ device_line=$(blkid | grep "UUID=\"$uuid\"") |
|
| 234 |
+ |
|
| 235 |
+ if [[ -z "$device_line" ]]; then |
|
| 236 |
+ return 1 |
|
| 237 |
+ fi |
|
| 238 |
+ |
|
| 239 |
+ local device=$(echo "$device_line" | cut -d: -f1) |
|
| 240 |
+ local blkid_info=$(echo "$device_line" | cut -d: -f2-) |
|
| 241 |
+ |
|
| 242 |
+ echo "device:$device" |
|
| 243 |
+ echo "$blkid_info" |
|
| 244 |
+ return 0 |
|
| 245 |
+} |
|
| 246 |
+ |
|
| 247 |
+# ============================================================================ |
|
| 248 |
+# NETWORK FUNCTIONS |
|
| 249 |
+# ============================================================================ |
|
| 250 |
+ |
|
| 251 |
+# Function to check if network interface exists |
|
| 252 |
+interface_exists() {
|
|
| 253 |
+ local interface="$1" |
|
| 254 |
+ ip link show "$interface" >/dev/null 2>&1 |
|
| 255 |
+} |
|
| 256 |
+ |
|
| 257 |
+# Function to check if interface is configured for AutoNAS |
|
| 258 |
+interface_has_autonas_config() {
|
|
| 259 |
+ local interface="$1" |
|
| 260 |
+ grep -q ":${interface}:" "$CONFIG_FILE" 2>/dev/null
|
|
| 261 |
+} |
|
| 262 |
+ |
|
| 263 |
+# Function to check if IP is configured on interface |
|
| 264 |
+is_ip_configured() {
|
|
| 265 |
+ local ip="$1" |
|
| 266 |
+ local interface="$2" |
|
| 267 |
+ ip addr show "$interface" | grep -q "inet $ip/" |
|
| 268 |
+} |
|
| 269 |
+ |
|
| 270 |
+# Function to count disks using specific IP |
|
| 271 |
+count_disks_using_ip() {
|
|
| 272 |
+ local target_ip="$1" |
|
| 273 |
+ local count=0 |
|
| 274 |
+ |
|
| 275 |
+ while IFS=':' read -r uuid name ip interface mount_point nfs_options; do |
|
| 276 |
+ # Skip empty lines and comments |
|
| 277 |
+ [[ -z "$uuid" || "$uuid" =~ ^# ]] && continue |
|
| 278 |
+ |
|
| 279 |
+ if [[ "$ip" == "$target_ip" ]]; then |
|
| 280 |
+ # Check if this disk is currently attached (mounted) |
|
| 281 |
+ if mountpoint -q "$mount_point" 2>/dev/null; then |
|
| 282 |
+ count=$((count + 1)) |
|
| 283 |
+ fi |
|
| 284 |
+ fi |
|
| 285 |
+ done < <(grep -v '^#' "$CONFIG_FILE" 2>/dev/null | grep -v '^$') |
|
| 286 |
+ |
|
| 287 |
+ echo $count |
|
| 288 |
+} |
|
| 289 |
+ |
|
| 290 |
+# Function to activate IP on interface with smart retry |
|
| 291 |
+activate_ip() {
|
|
| 292 |
+ local ip="$1" |
|
| 293 |
+ local interface="$2" |
|
| 294 |
+ local max_retries=3 |
|
| 295 |
+ local retry_count=0 |
|
| 296 |
+ |
|
| 297 |
+ # Skip activation for special cases |
|
| 298 |
+ if [[ "$ip" == "IMPORT" || "$ip" == "LOCAL" ]]; then |
|
| 299 |
+ log_message "Skipping IP activation for special configuration: $ip" "debug" |
|
| 300 |
+ return 0 |
|
| 301 |
+ fi |
|
| 302 |
+ |
|
| 303 |
+ log_message "Activating IP $ip on interface $interface" "info" |
|
| 304 |
+ |
|
| 305 |
+ # Check if interface exists |
|
| 306 |
+ if ! interface_exists "$interface"; then |
|
| 307 |
+ log_message "Interface $interface does not exist - waiting for it to appear" "warning" |
|
| 308 |
+ |
|
| 309 |
+ # Wait for interface to appear (common with USB/Thunderbolt) |
|
| 310 |
+ local wait_count=0 |
|
| 311 |
+ while [ $wait_count -lt 30 ] && ! interface_exists "$interface"; do |
|
| 312 |
+ sleep 2 |
|
| 313 |
+ wait_count=$((wait_count + 1)) |
|
| 314 |
+ debug_log "Waiting for interface $interface... (${wait_count}/30)"
|
|
| 315 |
+ done |
|
| 316 |
+ |
|
| 317 |
+ if ! interface_exists "$interface"; then |
|
| 318 |
+ log_message "Error: Interface $interface does not exist" "err" |
|
| 319 |
+ return 1 |
|
| 320 |
+ fi |
|
| 321 |
+ |
|
| 322 |
+ log_message "Interface $interface is now available" "info" |
|
| 323 |
+ fi |
|
| 324 |
+ |
|
| 325 |
+ # Check if IP is already configured |
|
| 326 |
+ if is_ip_configured "$ip" "$interface"; then |
|
| 327 |
+ log_message "IP $ip already configured on interface $interface" |
|
| 328 |
+ return 0 |
|
| 329 |
+ fi |
|
| 330 |
+ |
|
| 331 |
+ # Check if interface is up |
|
| 332 |
+ if ! ip link show "$interface" | grep -q "state UP"; then |
|
| 333 |
+ log_message "Bringing up interface $interface" |
|
| 334 |
+ if ! ip link set "$interface" up; then |
|
| 335 |
+ log_message "Error: Failed to bring up interface $interface" "err" |
|
| 336 |
+ return 1 |
|
| 337 |
+ fi |
|
| 338 |
+ # Wait a moment for interface to come up |
|
| 339 |
+ sleep 1 |
|
| 340 |
+ fi |
|
| 341 |
+ |
|
| 342 |
+ # Try to configure IP with retries |
|
| 343 |
+ while [ $retry_count -lt $max_retries ]; do |
|
| 344 |
+ if ip addr add "$ip/24" dev "$interface" 2>/dev/null; then |
|
| 345 |
+ log_message "Successfully activated IP $ip on interface $interface" |
|
| 346 |
+ return 0 |
|
| 347 |
+ else |
|
| 348 |
+ retry_count=$((retry_count + 1)) |
|
| 349 |
+ if [ $retry_count -lt $max_retries ]; then |
|
| 350 |
+ log_message "Failed to add IP $ip to interface $interface, retrying ($retry_count/$max_retries)" "warning" |
|
| 351 |
+ sleep 2 |
|
| 352 |
+ fi |
|
| 353 |
+ fi |
|
| 354 |
+ done |
|
| 355 |
+ |
|
| 356 |
+ log_message "Error: Failed to activate IP $ip on interface $interface" "err" |
|
| 357 |
+ return 1 |
|
| 358 |
+} |
|
| 359 |
+ |
|
| 360 |
+# Function to restore IPs for interface with comprehensive checking |
|
| 361 |
+restore_interface_ips() {
|
|
| 362 |
+ local interface="$1" |
|
| 363 |
+ local restored=0 |
|
| 364 |
+ local total_configs=0 |
|
| 365 |
+ |
|
| 366 |
+ log_message "Checking IP restoration needs for interface: $interface" "info" |
|
| 367 |
+ |
|
| 368 |
+ # Check if interface exists and is up |
|
| 369 |
+ if ! interface_exists "$interface"; then |
|
| 370 |
+ log_message "Interface $interface does not exist, skipping restoration" "warning" |
|
| 371 |
+ return 1 |
|
| 372 |
+ fi |
|
| 373 |
+ |
|
| 374 |
+ # Check if interface is up |
|
| 375 |
+ if ! ip link show "$interface" | grep -q "state UP"; then |
|
| 376 |
+ log_message "Interface $interface is down, waiting for it to come up..." "info" |
|
| 377 |
+ local wait_count=0 |
|
| 378 |
+ while [ $wait_count -lt 20 ] && ! ip link show "$interface" | grep -q "state UP"; do |
|
| 379 |
+ sleep 1 |
|
| 380 |
+ wait_count=$((wait_count + 1)) |
|
| 381 |
+ done |
|
| 382 |
+ |
|
| 383 |
+ if ! ip link show "$interface" | grep -q "state UP"; then |
|
| 384 |
+ log_message "Interface $interface did not come up within 20 seconds" "warning" |
|
| 385 |
+ return 1 |
|
| 386 |
+ fi |
|
| 387 |
+ fi |
|
| 388 |
+ |
|
| 389 |
+ log_message "Interface $interface is up, checking for required IP configurations" "info" |
|
| 390 |
+ |
|
| 391 |
+ while IFS= read -r line; do |
|
| 392 |
+ # Skip comments and empty lines |
|
| 393 |
+ [[ "$line" =~ ^[[:space:]]*# ]] && continue |
|
| 394 |
+ [[ -z "$line" ]] && continue |
|
| 395 |
+ |
|
| 396 |
+ # Parse configuration |
|
| 397 |
+ IFS=':' read -r uuid name ip config_interface mount_point nfs_options <<< "$line" |
|
| 398 |
+ |
|
| 399 |
+ # Check if this line is for our interface |
|
| 400 |
+ if [ "$config_interface" = "$interface" ]; then |
|
| 401 |
+ ((total_configs++)) |
|
| 402 |
+ debug_log "Found configuration: $name ($uuid) requires IP $ip on $interface" |
|
| 403 |
+ |
|
| 404 |
+ # Check if the disk is currently mounted |
|
| 405 |
+ if mountpoint -q "$mount_point" 2>/dev/null; then |
|
| 406 |
+ log_message "Disk $name is mounted, checking IP configuration" "info" |
|
| 407 |
+ |
|
| 408 |
+ # Check if IP is already configured |
|
| 409 |
+ if ! is_ip_configured "$ip" "$interface"; then |
|
| 410 |
+ log_message "IP $ip missing on interface $interface for mounted disk: $name" "warning" |
|
| 411 |
+ |
|
| 412 |
+ # Use the core activate_ip function |
|
| 413 |
+ if activate_ip "$ip" "$interface"; then |
|
| 414 |
+ log_message "Successfully restored IP $ip on interface $interface for disk $name" "info" |
|
| 415 |
+ ((restored++)) |
|
| 416 |
+ else |
|
| 417 |
+ log_message "Failed to restore IP $ip on interface $interface for disk $name" "error" |
|
| 418 |
+ fi |
|
| 419 |
+ else |
|
| 420 |
+ debug_log "IP $ip already configured on interface $interface for disk $name" |
|
| 421 |
+ fi |
|
| 422 |
+ else |
|
| 423 |
+ debug_log "Disk $name is not mounted, skipping IP configuration" |
|
| 424 |
+ fi |
|
| 425 |
+ fi |
|
| 426 |
+ done < "$CONFIG_FILE" |
|
| 427 |
+ |
|
| 428 |
+ if [ $total_configs -eq 0 ]; then |
|
| 429 |
+ debug_log "No AutoNAS configurations found for interface $interface" |
|
| 430 |
+ elif [ $restored -gt 0 ]; then |
|
| 431 |
+ log_message "Restored $restored/$total_configs IP addresses on interface $interface" "info" |
|
| 432 |
+ |
|
| 433 |
+ # Trigger NFS export refresh if we restored any IPs |
|
| 434 |
+ log_message "Refreshing NFS exports after IP restoration" "info" |
|
| 435 |
+ exportfs -ra 2>/dev/null |
|
| 436 |
+ systemctl reload nfs-kernel-server 2>/dev/null |
|
| 437 |
+ else |
|
| 438 |
+ log_message "All required IPs already configured on interface $interface" "info" |
|
| 439 |
+ fi |
|
| 440 |
+ |
|
| 441 |
+ return 0 |
|
| 442 |
+} |
|
| 443 |
+ |
|
| 444 |
+# Function to deactivate IP on interface with smart checking |
|
| 445 |
+deactivate_ip() {
|
|
| 446 |
+ local ip="$1" |
|
| 447 |
+ local interface="$2" |
|
| 448 |
+ |
|
| 449 |
+ # Skip deactivation for special cases |
|
| 450 |
+ if [[ "$ip" == "IMPORT" || "$ip" == "LOCAL" ]]; then |
|
| 451 |
+ log_message "Skipping IP deactivation for special configuration: $ip" "debug" |
|
| 452 |
+ return 0 |
|
| 453 |
+ fi |
|
| 454 |
+ |
|
| 455 |
+ # Check how many other disks are using this IP |
|
| 456 |
+ local usage_count |
|
| 457 |
+ usage_count=$(count_disks_using_ip "$ip") |
|
| 458 |
+ |
|
| 459 |
+ if [[ $usage_count -gt 1 ]]; then |
|
| 460 |
+ log_message "IP $ip still used by $((usage_count - 1)) other disks, keeping it active" |
|
| 461 |
+ return 0 |
|
| 462 |
+ fi |
|
| 463 |
+ |
|
| 464 |
+ log_message "Deactivating IP $ip on interface $interface" |
|
| 465 |
+ |
|
| 466 |
+ # Check if IP is configured |
|
| 467 |
+ if ! is_ip_configured "$ip" "$interface"; then |
|
| 468 |
+ log_message "IP $ip not configured on interface $interface" |
|
| 469 |
+ return 0 |
|
| 470 |
+ fi |
|
| 471 |
+ |
|
| 472 |
+ # Remove IP from interface |
|
| 473 |
+ if ip addr del "$ip/24" dev "$interface" 2>/dev/null; then |
|
| 474 |
+ log_message "Successfully deactivated IP $ip on interface $interface" |
|
| 475 |
+ return 0 |
|
| 476 |
+ else |
|
| 477 |
+ log_message "Error: Failed to deactivate IP $ip on interface $interface" "err" |
|
| 478 |
+ return 1 |
|
| 479 |
+ fi |
|
| 480 |
+} |
|
| 481 |
+ |
|
| 482 |
+# ============================================================================ |
|
| 483 |
+# NFS FUNCTIONS |
|
| 484 |
+# ============================================================================ |
|
| 485 |
+ |
|
| 486 |
+# Function to add NFS export with AutoNAS identification |
|
| 487 |
+add_nfs_export() {
|
|
| 488 |
+ local mount_point="$1" |
|
| 489 |
+ local nfs_options="$2" |
|
| 490 |
+ local uuid="${3:-}"
|
|
| 491 |
+ local name="${4:-}"
|
|
| 492 |
+ |
|
| 493 |
+ # Skip NFS export for special cases |
|
| 494 |
+ if [[ "$nfs_options" == "LOCAL" ]] || [[ "$mount_point" =~ ^.*@Camera.*$ ]]; then |
|
| 495 |
+ log_message "Skipping NFS export for local/camera configuration" "debug" |
|
| 496 |
+ return 0 |
|
| 497 |
+ fi |
|
| 498 |
+ |
|
| 499 |
+ log_message "Adding NFS export for $mount_point" |
|
| 500 |
+ |
|
| 501 |
+ # Create NFS export entry |
|
| 502 |
+ local export_entry="$mount_point $nfs_options" |
|
| 503 |
+ |
|
| 504 |
+ # Check if export already exists |
|
| 505 |
+ if grep -Fxq "$export_entry" /etc/exports 2>/dev/null; then |
|
| 506 |
+ log_message "NFS export already exists: $export_entry" |
|
| 507 |
+ return 0 |
|
| 508 |
+ fi |
|
| 509 |
+ |
|
| 510 |
+ # Add identifying comment if UUID/name provided |
|
| 511 |
+ if [[ -n "$uuid" && -n "$name" ]]; then |
|
| 512 |
+ echo "# AutoNAS Export - UUID:$uuid NAME:$name" >> /etc/exports |
|
| 513 |
+ fi |
|
| 514 |
+ |
|
| 515 |
+ # Add export to /etc/exports |
|
| 516 |
+ echo "$export_entry" >> /etc/exports |
|
| 517 |
+ if [[ $? -eq 0 ]]; then |
|
| 518 |
+ log_message "Successfully added NFS export: $export_entry" |
|
| 519 |
+ |
|
| 520 |
+ # Reload exports |
|
| 521 |
+ if exportfs -ra; then |
|
| 522 |
+ log_message "NFS exports reloaded successfully" |
|
| 523 |
+ return 0 |
|
| 524 |
+ else |
|
| 525 |
+ log_message "Warning: Failed to reload NFS exports" "warning" |
|
| 526 |
+ return 1 |
|
| 527 |
+ fi |
|
| 528 |
+ else |
|
| 529 |
+ log_message "Error: Failed to add NFS export" "err" |
|
| 530 |
+ return 1 |
|
| 531 |
+ fi |
|
| 532 |
+} |
|
| 533 |
+ |
|
| 534 |
+# Function to remove NFS export |
|
| 535 |
+remove_nfs_export() {
|
|
| 536 |
+ local mount_point="$1" |
|
| 537 |
+ local uuid="${2:-}"
|
|
| 538 |
+ local name="${3:-}"
|
|
| 539 |
+ local nfs_options="${4:-}"
|
|
| 540 |
+ |
|
| 541 |
+ # Skip NFS export removal for special cases |
|
| 542 |
+ if [[ "$mount_point" =~ ^.*@Camera.*$ ]] || [[ "$nfs_options" == "LOCAL" ]]; then |
|
| 543 |
+ log_message "Skipping NFS export removal for camera/local configuration" "debug" |
|
| 544 |
+ return 0 |
|
| 545 |
+ fi |
|
| 546 |
+ |
|
| 547 |
+ log_message "Removing NFS export for $mount_point" |
|
| 548 |
+ |
|
| 549 |
+ # Create temporary file without the export |
|
| 550 |
+ local temp_exports=$(mktemp) |
|
| 551 |
+ if [[ ! -f /etc/exports ]]; then |
|
| 552 |
+ log_message "No /etc/exports file found" |
|
| 553 |
+ rm -f "$temp_exports" |
|
| 554 |
+ return 0 |
|
| 555 |
+ fi |
|
| 556 |
+ |
|
| 557 |
+ # If UUID provided, use AutoNAS marker method |
|
| 558 |
+ if [[ -n "$uuid" ]]; then |
|
| 559 |
+ local skip_next=false |
|
| 560 |
+ local found_export=false |
|
| 561 |
+ |
|
| 562 |
+ # Process /etc/exports line by line |
|
| 563 |
+ while IFS= read -r line; do |
|
| 564 |
+ if [[ "$line" =~ ^#\ AutoNAS\ Export\ -\ UUID:${uuid}\ NAME: ]]; then
|
|
| 565 |
+ # Found our marker comment, skip this line and the next one |
|
| 566 |
+ skip_next=true |
|
| 567 |
+ found_export=true |
|
| 568 |
+ debug_log "Found AutoNAS export marker for $name" |
|
| 569 |
+ continue |
|
| 570 |
+ elif [ "$skip_next" = true ]; then |
|
| 571 |
+ # Skip the export line that follows our marker |
|
| 572 |
+ skip_next=false |
|
| 573 |
+ debug_log "Skipping export line for $name" |
|
| 574 |
+ continue |
|
| 575 |
+ else |
|
| 576 |
+ # Keep all other lines |
|
| 577 |
+ echo "$line" >> "$temp_exports" |
|
| 578 |
+ fi |
|
| 579 |
+ done < /etc/exports |
|
| 580 |
+ |
|
| 581 |
+ if [ "$found_export" = true ]; then |
|
| 582 |
+ # Replace /etc/exports with cleaned version |
|
| 583 |
+ mv "$temp_exports" /etc/exports |
|
| 584 |
+ log_message "NFS export removed using AutoNAS marker for $name" |
|
| 585 |
+ else |
|
| 586 |
+ rm -f "$temp_exports" |
|
| 587 |
+ # Fallback to generic method |
|
| 588 |
+ grep -v "^${mount_point} " /etc/exports > "$temp_exports"
|
|
| 589 |
+ mv "$temp_exports" /etc/exports |
|
| 590 |
+ log_message "NFS export removed using generic method for $mount_point" |
|
| 591 |
+ fi |
|
| 592 |
+ else |
|
| 593 |
+ # Generic removal method |
|
| 594 |
+ grep -v "^${mount_point} " /etc/exports > "$temp_exports"
|
|
| 595 |
+ mv "$temp_exports" /etc/exports |
|
| 596 |
+ log_message "NFS export removed for $mount_point" |
|
| 597 |
+ fi |
|
| 598 |
+ |
|
| 599 |
+ # Reload exports |
|
| 600 |
+ if exportfs -ra; then |
|
| 601 |
+ log_message "NFS exports reloaded successfully" |
|
| 602 |
+ return 0 |
|
| 603 |
+ else |
|
| 604 |
+ log_message "Warning: Failed to reload NFS exports" "warning" |
|
| 605 |
+ return 1 |
|
| 606 |
+ fi |
|
| 607 |
+} |
|
| 608 |
+ |
|
| 609 |
+# ============================================================================ |
|
| 610 |
+# STORAGE FUNCTIONS |
|
| 611 |
+# ============================================================================ |
|
| 612 |
+ |
|
| 613 |
+# Function to mount disk with comprehensive filesystem support |
|
| 614 |
+mount_disk() {
|
|
| 615 |
+ local uuid="$1" |
|
| 616 |
+ local mount_point="$2" |
|
| 617 |
+ local filesystem_type="${3:-}"
|
|
| 618 |
+ |
|
| 619 |
+ log_message "Mounting disk with UUID $uuid to $mount_point" |
|
| 620 |
+ |
|
| 621 |
+ # Wait for device to be ready (udev sometimes triggers too early) |
|
| 622 |
+ local device_path="/dev/disk/by-uuid/$uuid" |
|
| 623 |
+ local wait_count=0 |
|
| 624 |
+ while [ ! -e "$device_path" ] && [ $wait_count -lt 10 ]; do |
|
| 625 |
+ debug_log "Waiting for device $device_path to appear..." |
|
| 626 |
+ sleep 1 |
|
| 627 |
+ wait_count=$((wait_count + 1)) |
|
| 628 |
+ done |
|
| 629 |
+ |
|
| 630 |
+ if [ ! -e "$device_path" ]; then |
|
| 631 |
+ # Try alternative method - find device by UUID using blkid |
|
| 632 |
+ local device |
|
| 633 |
+ device=$(blkid | grep "UUID=\"$uuid\"" | cut -d: -f1) |
|
| 634 |
+ |
|
| 635 |
+ if [[ -z "$device" ]]; then |
|
| 636 |
+ log_message "Error: Device with UUID $uuid not found" "err" |
|
| 637 |
+ return 1 |
|
| 638 |
+ fi |
|
| 639 |
+ |
|
| 640 |
+ device_path="$device" |
|
| 641 |
+ fi |
|
| 642 |
+ |
|
| 643 |
+ # Get the actual device name |
|
| 644 |
+ local actual_device=$(readlink -f "$device_path" 2>/dev/null || echo "$device_path") |
|
| 645 |
+ log_message "Device UUID $uuid maps to $actual_device" |
|
| 646 |
+ |
|
| 647 |
+ # Check if device is already mounted |
|
| 648 |
+ if mountpoint -q "$mount_point" 2>/dev/null; then |
|
| 649 |
+ # Check if it's mounted to the correct device |
|
| 650 |
+ local mounted_device |
|
| 651 |
+ mounted_device=$(findmnt -n -o SOURCE "$mount_point") |
|
| 652 |
+ if [[ "$mounted_device" == "$actual_device" ]]; then |
|
| 653 |
+ log_message "Disk already mounted correctly at $mount_point" |
|
| 654 |
+ return 0 |
|
| 655 |
+ else |
|
| 656 |
+ log_message "Warning: Different device mounted at $mount_point, unmounting first" "warning" |
|
| 657 |
+ umount "$mount_point" 2>/dev/null |
|
| 658 |
+ fi |
|
| 659 |
+ fi |
|
| 660 |
+ |
|
| 661 |
+ # Create mount point if it doesn't exist |
|
| 662 |
+ if [[ ! -d "$mount_point" ]]; then |
|
| 663 |
+ if mkdir -p "$mount_point"; then |
|
| 664 |
+ log_message "Created mount point directory: $mount_point" |
|
| 665 |
+ else |
|
| 666 |
+ log_message "Error: Failed to create mount point directory: $mount_point" "err" |
|
| 667 |
+ return 1 |
|
| 668 |
+ fi |
|
| 669 |
+ fi |
|
| 670 |
+ |
|
| 671 |
+ # Detect filesystem if not provided |
|
| 672 |
+ if [[ -z "$filesystem_type" ]]; then |
|
| 673 |
+ filesystem_type=$(blkid -o value -s TYPE "$actual_device" 2>/dev/null) |
|
| 674 |
+ debug_log "Detected filesystem type: $filesystem_type" |
|
| 675 |
+ fi |
|
| 676 |
+ |
|
| 677 |
+ # Mount based on filesystem type |
|
| 678 |
+ local mount_options |
|
| 679 |
+ case "$filesystem_type" in |
|
| 680 |
+ "ntfs") |
|
| 681 |
+ mount_options="-t ntfs-3g -o rw,uid=0,gid=0,umask=000" |
|
| 682 |
+ log_message "Mounting NTFS filesystem" |
|
| 683 |
+ ;; |
|
| 684 |
+ "exfat") |
|
| 685 |
+ mount_options="-t exfat -o rw,uid=0,gid=0,umask=000" |
|
| 686 |
+ log_message "Mounting exFAT filesystem" |
|
| 687 |
+ ;; |
|
| 688 |
+ "vfat"|"fat32") |
|
| 689 |
+ mount_options="-t vfat -o rw,uid=0,gid=0,umask=000" |
|
| 690 |
+ log_message "Mounting FAT32 filesystem" |
|
| 691 |
+ ;; |
|
| 692 |
+ "ext2"|"ext3"|"ext4") |
|
| 693 |
+ mount_options="-t $filesystem_type" |
|
| 694 |
+ log_message "Mounting Linux filesystem ($filesystem_type)" |
|
| 695 |
+ ;; |
|
| 696 |
+ "btrfs") |
|
| 697 |
+ mount_options="-t btrfs -o defaults,compress=zstd" |
|
| 698 |
+ log_message "Mounting BTRFS filesystem with compression" |
|
| 699 |
+ ;; |
|
| 700 |
+ "xfs") |
|
| 701 |
+ mount_options="-t xfs" |
|
| 702 |
+ log_message "Mounting XFS filesystem" |
|
| 703 |
+ ;; |
|
| 704 |
+ *) |
|
| 705 |
+ mount_options="" |
|
| 706 |
+ log_message "Unknown or no filesystem type, attempting default mount" |
|
| 707 |
+ ;; |
|
| 708 |
+ esac |
|
| 709 |
+ |
|
| 710 |
+ # Perform the mount |
|
| 711 |
+ local mount_cmd="mount $mount_options \"$actual_device\" \"$mount_point\"" |
|
| 712 |
+ debug_log "Executing: $mount_cmd" |
|
| 713 |
+ |
|
| 714 |
+ if eval $mount_cmd; then |
|
| 715 |
+ # Verify mount was successful |
|
| 716 |
+ if mountpoint -q "$mount_point"; then |
|
| 717 |
+ log_message "Disk mounted successfully at $mount_point" |
|
| 718 |
+ |
|
| 719 |
+ # Set appropriate permissions for the mount point |
|
| 720 |
+ chmod 755 "$mount_point" 2>/dev/null |
|
| 721 |
+ |
|
| 722 |
+ return 0 |
|
| 723 |
+ else |
|
| 724 |
+ log_message "Error: Mount command succeeded but mountpoint verification failed" "err" |
|
| 725 |
+ return 1 |
|
| 726 |
+ fi |
|
| 727 |
+ else |
|
| 728 |
+ # Try fallback mount by UUID for better compatibility |
|
| 729 |
+ log_message "Direct mount failed, attempting UUID fallback" "warning" |
|
| 730 |
+ if mount UUID="$uuid" "$mount_point" 2>/dev/null; then |
|
| 731 |
+ log_message "Disk mounted successfully using UUID fallback at $mount_point" |
|
| 732 |
+ return 0 |
|
| 733 |
+ else |
|
| 734 |
+ log_message "Error: Failed to mount $actual_device to $mount_point" "err" |
|
| 735 |
+ return 1 |
|
| 736 |
+ fi |
|
| 737 |
+ fi |
|
| 738 |
+} |
|
| 739 |
+ |
|
| 740 |
+# Function to unmount disk |
|
| 741 |
+unmount_disk() {
|
|
| 742 |
+ local mount_point="$1" |
|
| 743 |
+ |
|
| 744 |
+ log_message "Unmounting disk from $mount_point" |
|
| 745 |
+ |
|
| 746 |
+ # Check if actually mounted |
|
| 747 |
+ if ! mountpoint -q "$mount_point" 2>/dev/null; then |
|
| 748 |
+ log_message "Path $mount_point is not a mount point" |
|
| 749 |
+ return 0 |
|
| 750 |
+ fi |
|
| 751 |
+ |
|
| 752 |
+ # Attempt unmount with timeout |
|
| 753 |
+ if timeout 30 umount "$mount_point"; then |
|
| 754 |
+ log_message "Successfully unmounted $mount_point" |
|
| 755 |
+ |
|
| 756 |
+ # Remove mount point if empty |
|
| 757 |
+ if rmdir "$mount_point" 2>/dev/null; then |
|
| 758 |
+ debug_log "Removed empty mount point directory: $mount_point" |
|
| 759 |
+ else |
|
| 760 |
+ debug_log "Mount point directory not empty or removal failed: $mount_point" |
|
| 761 |
+ fi |
|
| 762 |
+ return 0 |
|
| 763 |
+ else |
|
| 764 |
+ log_message "Error: Failed to unmount $mount_point" "err" |
|
| 765 |
+ return 1 |
|
| 766 |
+ fi |
|
| 767 |
+} |
|
| 768 |
+ |
|
| 769 |
+# ============================================================================ |
|
| 770 |
+# CAMERA IMPORT FUNCTIONS |
|
| 771 |
+# ============================================================================ |
|
| 772 |
+ |
|
| 773 |
+# Function to handle camera import |
|
| 774 |
+handle_camera_import() {
|
|
| 775 |
+ local uuid="$1" |
|
| 776 |
+ local mount_point="$2" |
|
| 777 |
+ local import_config="$3" |
|
| 778 |
+ |
|
| 779 |
+ # Parse import configuration (format: destination_path only) |
|
| 780 |
+ destination_path="$import_config" |
|
| 781 |
+ |
|
| 782 |
+ if [[ -z "$destination_path" ]]; then |
|
| 783 |
+ log_message "Error: No destination path specified for camera import" "err" |
|
| 784 |
+ return 1 |
|
| 785 |
+ fi |
|
| 786 |
+ |
|
| 787 |
+ # Always use the integrated media importer (non-configurable) |
|
| 788 |
+ script_path="/usr/local/bin/autonas-media-importer.sh" |
|
| 789 |
+ |
|
| 790 |
+ # Check if import script exists |
|
| 791 |
+ if [[ ! -x "$script_path" ]]; then |
|
| 792 |
+ log_message "Error: Camera import script not found or not executable: $script_path" "err" |
|
| 793 |
+ return 1 |
|
| 794 |
+ fi |
|
| 795 |
+ |
|
| 796 |
+ log_message "Starting camera import process for UUID: $uuid" |
|
| 797 |
+ log_message "Import destination: $destination_path" |
|
| 798 |
+ |
|
| 799 |
+ # Clean up any previous transient unit before starting a new one |
|
| 800 |
+ systemctl stop autonas-import-$uuid.service 2>/dev/null || true |
|
| 801 |
+ systemctl reset-failed autonas-import-$uuid.service 2>/dev/null || true |
|
| 802 |
+ systemctl disable autonas-import-$uuid.service 2>/dev/null || true |
|
| 803 |
+ rm -f /run/systemd/transient/autonas-import-$uuid.service 2>/dev/null || true |
|
| 804 |
+ |
|
| 805 |
+ # Run import in background using systemd-run for better process management |
|
| 806 |
+ systemd-run --no-block --unit="autonas-import-$uuid" \ |
|
| 807 |
+ /usr/local/bin/autonas-disk-handler.sh import "$uuid" "$mount_point" "$destination_path" "$script_path" || {
|
|
| 808 |
+ log_message "Error: Failed to start background import process" "err" |
|
| 809 |
+ return 1 |
|
| 810 |
+ } |
|
| 811 |
+ |
|
| 812 |
+ log_message "Camera import process started successfully" |
|
| 813 |
+ return 0 |
|
| 814 |
+} |
|
| 815 |
+ |
|
| 816 |
+# Function to run background import |
|
| 817 |
+run_background_import() {
|
|
| 818 |
+ local uuid="$1" |
|
| 819 |
+ local mount_point="$2" |
|
| 820 |
+ local destination="$3" |
|
| 821 |
+ local script_path="${4:-/usr/local/bin/autonas-media-importer.sh}"
|
|
| 822 |
+ |
|
| 823 |
+ log_message "Running background import for UUID: $uuid" "info" "autonas-import" |
|
| 824 |
+ log_message "Source: $mount_point, Destination: $destination" "info" "autonas-import" |
|
| 825 |
+ |
|
| 826 |
+ # Change to a safe directory |
|
| 827 |
+ cd /tmp || cd / |
|
| 828 |
+ |
|
| 829 |
+ # Create destination directory if it doesn't exist |
|
| 830 |
+ mkdir -p "$destination" |
|
| 831 |
+ |
|
| 832 |
+ # Ensure destination exists |
|
| 833 |
+ if [[ ! -d "$destination" ]]; then |
|
| 834 |
+ log_message "Error: Cannot access destination directory: $destination" "err" "autonas-import" |
|
| 835 |
+ return 1 |
|
| 836 |
+ fi |
|
| 837 |
+ |
|
| 838 |
+ # Run the import script |
|
| 839 |
+ log_message "Executing import script: $script_path" "info" "autonas-import" |
|
| 840 |
+ if "$script_path" "$mount_point" "$destination" --verbose; then |
|
| 841 |
+ log_message "Import completed successfully for UUID: $uuid" "info" "autonas-import" |
|
| 842 |
+ |
|
| 843 |
+ # Cleanup: unmount and remove mount point |
|
| 844 |
+ cleanup_and_unmount "$uuid" "$mount_point" |
|
| 845 |
+ return 0 |
|
| 846 |
+ else |
|
| 847 |
+ log_message "Error: Import failed for UUID: $uuid" "err" "autonas-import" |
|
| 848 |
+ cleanup_and_unmount "$uuid" "$mount_point" |
|
| 849 |
+ return 1 |
|
| 850 |
+ fi |
|
| 851 |
+} |
|
| 852 |
+ |
|
| 853 |
+# Function to cleanup and unmount after camera import |
|
| 854 |
+cleanup_and_unmount() {
|
|
| 855 |
+ local uuid="$1" |
|
| 856 |
+ local mount_point="$2" |
|
| 857 |
+ |
|
| 858 |
+ log_message "Cleaning up after import for UUID: $uuid" "info" "autonas-import" |
|
| 859 |
+ |
|
| 860 |
+ # Unmount the device |
|
| 861 |
+ if mountpoint -q "$mount_point" 2>/dev/null; then |
|
| 862 |
+ if umount "$mount_point"; then |
|
| 863 |
+ log_message "Successfully unmounted $mount_point" "info" "autonas-import" |
|
| 864 |
+ else |
|
| 865 |
+ log_message "Warning: Failed to unmount $mount_point" "warning" "autonas-import" |
|
| 866 |
+ fi |
|
| 867 |
+ fi |
|
| 868 |
+ |
|
| 869 |
+ # Remove mount point directory if empty |
|
| 870 |
+ if [[ -d "$mount_point" ]] && rmdir "$mount_point" 2>/dev/null; then |
|
| 871 |
+ log_message "Removed empty mount point directory: $mount_point" "info" "autonas-import" |
|
| 872 |
+ fi |
|
| 873 |
+ |
|
| 874 |
+ log_message "Cleanup completed for UUID: $uuid" "info" "autonas-import" |
|
| 875 |
+} |
|
| 876 |
+ |
|
| 877 |
+# ============================================================================ |
|
| 878 |
+# MAIN WORKFLOW FUNCTIONS |
|
| 879 |
+# ============================================================================ |
|
| 880 |
+ |
|
| 881 |
+# Function to handle disk attachment |
|
| 882 |
+handle_attach() {
|
|
| 883 |
+ local uuid="$1" |
|
| 884 |
+ |
|
| 885 |
+ log_message "AutoNAS attach operation started for UUID: $uuid" |
|
| 886 |
+ |
|
| 887 |
+ # Get configuration for this UUID |
|
| 888 |
+ local config |
|
| 889 |
+ config=$(get_disk_config "$uuid") |
|
| 890 |
+ |
|
| 891 |
+ if [[ -z "$config" ]]; then |
|
| 892 |
+ log_message "No configuration found for UUID: $uuid - disk will be ignored" |
|
| 893 |
+ log_message "To configure this disk, run: autonas add" |
|
| 894 |
+ return 1 |
|
| 895 |
+ fi |
|
| 896 |
+ |
|
| 897 |
+ log_message "Handling disk attachment for UUID: $uuid" |
|
| 898 |
+ |
|
| 899 |
+ # Parse configuration |
|
| 900 |
+ local parsed |
|
| 901 |
+ parsed=($(parse_config "$config")) |
|
| 902 |
+ local cfg_uuid="${parsed[0]}"
|
|
| 903 |
+ local name="${parsed[1]}"
|
|
| 904 |
+ local ip="${parsed[2]}"
|
|
| 905 |
+ local interface="${parsed[3]}"
|
|
| 906 |
+ local mount_point="${parsed[4]}"
|
|
| 907 |
+ local nfs_options="${parsed[5]}"
|
|
| 908 |
+ |
|
| 909 |
+ log_message "Processing disk: $name (IP: $ip, Mount: $mount_point)" |
|
| 910 |
+ |
|
| 911 |
+ # Handle different disk types |
|
| 912 |
+ if [[ "$ip" == "IMPORT" && "$interface" == "IMPORT" ]]; then |
|
| 913 |
+ # Camera import workflow: mount temporarily, import, then unmount |
|
| 914 |
+ log_message "Detected camera import configuration for UUID: $uuid" |
|
| 915 |
+ |
|
| 916 |
+ # Mount disk for import |
|
| 917 |
+ if mount_disk "$uuid" "$mount_point"; then |
|
| 918 |
+ # Start import process |
|
| 919 |
+ handle_camera_import "$uuid" "$mount_point" "$nfs_options" |
|
| 920 |
+ return $? |
|
| 921 |
+ else |
|
| 922 |
+ log_message "Error: Failed to mount camera device" "err" |
|
| 923 |
+ return 1 |
|
| 924 |
+ fi |
|
| 925 |
+ elif [[ "$ip" == "LOCAL" ]]; then |
|
| 926 |
+ # Local mount only (no network sharing) |
|
| 927 |
+ if mount_disk "$uuid" "$mount_point"; then |
|
| 928 |
+ log_message "Local disk mounted successfully at $mount_point" |
|
| 929 |
+ return 0 |
|
| 930 |
+ else |
|
| 931 |
+ return 1 |
|
| 932 |
+ fi |
|
| 933 |
+ else |
|
| 934 |
+ # Regular NFS workflow: activate IP, mount, export via NFS |
|
| 935 |
+ if activate_ip "$ip" "$interface"; then |
|
| 936 |
+ if mount_disk "$uuid" "$mount_point"; then |
|
| 937 |
+ if add_nfs_export "$mount_point" "$nfs_options" "$uuid" "$name"; then |
|
| 938 |
+ log_message "Disk attached successfully: $name" |
|
| 939 |
+ return 0 |
|
| 940 |
+ else |
|
| 941 |
+ log_message "Warning: Disk mounted but NFS export failed" "warning" |
|
| 942 |
+ return 1 |
|
| 943 |
+ fi |
|
| 944 |
+ else |
|
| 945 |
+ deactivate_ip "$ip" "$interface" |
|
| 946 |
+ return 1 |
|
| 947 |
+ fi |
|
| 948 |
+ else |
|
| 949 |
+ return 1 |
|
| 950 |
+ fi |
|
| 951 |
+ fi |
|
| 952 |
+} |
|
| 953 |
+ |
|
| 954 |
+# Function to handle disk detachment |
|
| 955 |
+handle_detach() {
|
|
| 956 |
+ local uuid="$1" |
|
| 957 |
+ |
|
| 958 |
+ log_message "AutoNAS detach operation started for UUID: $uuid" |
|
| 959 |
+ |
|
| 960 |
+ # Get configuration for this UUID |
|
| 961 |
+ local config |
|
| 962 |
+ config=$(get_disk_config "$uuid") |
|
| 963 |
+ |
|
| 964 |
+ if [[ -z "$config" ]]; then |
|
| 965 |
+ log_message "No configuration found for UUID: $uuid" |
|
| 966 |
+ return 1 |
|
| 967 |
+ fi |
|
| 968 |
+ |
|
| 969 |
+ log_message "Handling disk detachment for UUID: $uuid" |
|
| 970 |
+ |
|
| 971 |
+ # Parse configuration |
|
| 972 |
+ local parsed |
|
| 973 |
+ parsed=($(parse_config "$config")) |
|
| 974 |
+ local cfg_uuid="${parsed[0]}"
|
|
| 975 |
+ local name="${parsed[1]}"
|
|
| 976 |
+ local ip="${parsed[2]}"
|
|
| 977 |
+ local interface="${parsed[3]}"
|
|
| 978 |
+ local mount_point="${parsed[4]}"
|
|
| 979 |
+ local nfs_options="${parsed[5]}"
|
|
| 980 |
+ |
|
| 981 |
+ log_message "Processing disk: $name (Mount: $mount_point)" |
|
| 982 |
+ |
|
| 983 |
+ # Remove NFS export (if applicable) |
|
| 984 |
+ if [[ "$ip" != "LOCAL" && "$ip" != "IMPORT" ]]; then |
|
| 985 |
+ remove_nfs_export "$mount_point" "$uuid" "$name" "$nfs_options" |
|
| 986 |
+ fi |
|
| 987 |
+ |
|
| 988 |
+ # Unmount disk |
|
| 989 |
+ if unmount_disk "$mount_point"; then |
|
| 990 |
+ # Deactivate IP (if applicable) |
|
| 991 |
+ if [[ "$ip" != "LOCAL" && "$ip" != "IMPORT" ]]; then |
|
| 992 |
+ deactivate_ip "$ip" "$interface" |
|
| 993 |
+ fi |
|
| 994 |
+ |
|
| 995 |
+ log_message "Disk detached successfully: $name" |
|
| 996 |
+ return 0 |
|
| 997 |
+ else |
|
| 998 |
+ log_message "Error: Failed to detach disk: $name" "err" |
|
| 999 |
+ return 1 |
|
| 1000 |
+ fi |
|
| 1001 |
+} |
|
| 1002 |
+ |
|
| 1003 |
+# Function to reload configuration |
|
| 1004 |
+handle_reload() {
|
|
| 1005 |
+ log_message "Reloading AutoNAS configuration" |
|
| 1006 |
+ |
|
| 1007 |
+ log_message "Reloading udev rules" |
|
| 1008 |
+ udevadm control --reload-rules |
|
| 1009 |
+ udevadm trigger --subsystem-match=block |
|
| 1010 |
+ |
|
| 1011 |
+ log_message "Reloading NFS exports" |
|
| 1012 |
+ exportfs -ra || log_message "Warning: Failed to reload NFS exports" "warning" |
|
| 1013 |
+ |
|
| 1014 |
+ log_message "Reloading systemd daemon" |
|
| 1015 |
+ systemctl daemon-reload || log_message "Warning: Failed to reload systemd daemon" "warning" |
|
| 1016 |
+ |
|
| 1017 |
+ log_message "AutoNAS configuration reload completed" |
|
| 1018 |
+ return 0 |
|
| 1019 |
+} |
|
| 1020 |
+ |
|
| 1021 |
+# ============================================================================ |
|
| 1022 |
+# DISPLAY FUNCTIONS |
|
| 1023 |
+# ============================================================================ |
|
| 1024 |
+ |
|
| 1025 |
+# Function to show available disks |
|
| 1026 |
+show_available_disks() {
|
|
| 1027 |
+ echo "=== Available Storage Devices ===" |
|
| 1028 |
+ echo |
|
| 1029 |
+ |
|
| 1030 |
+ local found_devices=0 |
|
| 1031 |
+ local blkid_output |
|
| 1032 |
+ |
|
| 1033 |
+ # Get blkid output and process it |
|
| 1034 |
+ if ! blkid_output=$(blkid 2>/dev/null); then |
|
| 1035 |
+ echo "Error: Unable to scan for block devices (are you running as root?)" |
|
| 1036 |
+ return 1 |
|
| 1037 |
+ fi |
|
| 1038 |
+ |
|
| 1039 |
+ while IFS= read -r blkid_line; do |
|
| 1040 |
+ [[ -z "$blkid_line" ]] && continue |
|
| 1041 |
+ |
|
| 1042 |
+ local device=$(echo "$blkid_line" | cut -d: -f1) |
|
| 1043 |
+ |
|
| 1044 |
+ # Skip if device doesn't exist (shouldn't happen with blkid, but just in case) |
|
| 1045 |
+ [[ ! -b "$device" ]] && continue |
|
| 1046 |
+ |
|
| 1047 |
+ # Skip loop devices, ram disks, and other virtual devices |
|
| 1048 |
+ case "$device" in |
|
| 1049 |
+ /dev/loop*|/dev/ram*|/dev/dm-*) continue ;; |
|
| 1050 |
+ esac |
|
| 1051 |
+ |
|
| 1052 |
+ # Extract device information |
|
| 1053 |
+ local uuid=$(echo "$blkid_line" | grep -o 'UUID="[^"]*"' | cut -d'"' -f2) |
|
| 1054 |
+ local label=$(echo "$blkid_line" | grep -o 'LABEL="[^"]*"' | cut -d'"' -f2) |
|
| 1055 |
+ local fstype=$(echo "$blkid_line" | grep -o 'TYPE="[^"]*"' | cut -d'"' -f2) |
|
| 1056 |
+ local partuuid=$(echo "$blkid_line" | grep -o 'PARTUUID="[^"]*"' | cut -d'"' -f2) |
|
| 1057 |
+ |
|
| 1058 |
+ # Skip if no UUID (we need UUID for AutoNAS) |
|
| 1059 |
+ [[ -z "$uuid" ]] && continue |
|
| 1060 |
+ |
|
| 1061 |
+ found_devices=$((found_devices + 1)) |
|
| 1062 |
+ |
|
| 1063 |
+ # Get device size |
|
| 1064 |
+ local size="" |
|
| 1065 |
+ if [[ -b "$device" ]]; then |
|
| 1066 |
+ size=$(lsblk -b -d -o SIZE "$device" 2>/dev/null | tail -n1) |
|
| 1067 |
+ if [[ -n "$size" ]] && [[ "$size" =~ ^[0-9]+$ ]]; then |
|
| 1068 |
+ # Convert to human readable |
|
| 1069 |
+ size=$(numfmt --to=iec --suffix=B "$size" 2>/dev/null || echo "${size}B")
|
|
| 1070 |
+ fi |
|
| 1071 |
+ fi |
|
| 1072 |
+ |
|
| 1073 |
+ # Display device information |
|
| 1074 |
+ echo "Device: $device" |
|
| 1075 |
+ [[ -n "$size" ]] && echo " Size: $size" |
|
| 1076 |
+ echo " UUID: $uuid" |
|
| 1077 |
+ [[ -n "$label" ]] && echo " Label: $label" |
|
| 1078 |
+ [[ -n "$fstype" ]] && echo " Filesystem: $fstype" |
|
| 1079 |
+ |
|
| 1080 |
+ # Check if already configured |
|
| 1081 |
+ if grep -q "^${uuid}:" "$CONFIG_FILE" 2>/dev/null; then
|
|
| 1082 |
+ local config_line=$(grep "^${uuid}:" "$CONFIG_FILE" 2>/dev/null)
|
|
| 1083 |
+ local config_name=$(echo "$config_line" | cut -d: -f2) |
|
| 1084 |
+ echo " Status: โ Configured as '$config_name'" |
|
| 1085 |
+ else |
|
| 1086 |
+ echo " Status: โ ๏ธ Not configured" |
|
| 1087 |
+ fi |
|
| 1088 |
+ |
|
| 1089 |
+ # Check if currently mounted |
|
| 1090 |
+ local mount_info |
|
| 1091 |
+ mount_info=$(findmnt -n -o TARGET "$device" 2>/dev/null) |
|
| 1092 |
+ if [[ -n "$mount_info" ]]; then |
|
| 1093 |
+ echo " Mount: ๐ข $mount_info" |
|
| 1094 |
+ else |
|
| 1095 |
+ echo " Mount: โช Not mounted" |
|
| 1096 |
+ fi |
|
| 1097 |
+ |
|
| 1098 |
+ echo |
|
| 1099 |
+ done <<< "$blkid_output" |
|
| 1100 |
+ |
|
| 1101 |
+ if [[ $found_devices -eq 0 ]]; then |
|
| 1102 |
+ echo "No storage devices with UUIDs found." |
|
| 1103 |
+ echo "Make sure devices are connected and you're running as root." |
|
| 1104 |
+ else |
|
| 1105 |
+ echo "Found $found_devices storage device(s)" |
|
| 1106 |
+ echo |
|
| 1107 |
+ echo "To configure a device: autonas add <UUID>" |
|
| 1108 |
+ echo "To list configured devices: autonas list" |
|
| 1109 |
+ fi |
|
| 1110 |
+ |
|
| 1111 |
+ return 0 |
|
| 1112 |
+} |
|
| 1113 |
+ |
|
| 1114 |
+# Mark that core library has been loaded |
|
| 1115 |
+AUTONAS_CORE_LOADED=true |
|
@@ -0,0 +1,82 @@ |
||
| 1 |
+#!/bin/bash |
|
| 2 |
+ |
|
| 3 |
+# AutoNAS Manager - System integration for udev/systemd events |
|
| 4 |
+# This script is called by udev rules when disks are attached/detached |
|
| 5 |
+# Uses autonas-core.sh for all business logic |
|
| 6 |
+ |
|
| 7 |
+# Load the AutoNAS core library |
|
| 8 |
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
| 9 |
+source "${SCRIPT_DIR}/autonas-core.sh" || {
|
|
| 10 |
+ echo "Error: Cannot load AutoNAS core library" >&2 |
|
| 11 |
+ exit 1 |
|
| 12 |
+} |
|
| 13 |
+ |
|
| 14 |
+# Set LOG_TAG for this component |
|
| 15 |
+LOG_TAG="autonas-disk-handler" |
|
| 16 |
+ |
|
| 17 |
+# Main script logic |
|
| 18 |
+case "$1" in |
|
| 19 |
+ "attach") |
|
| 20 |
+ if [ -z "$2" ]; then |
|
| 21 |
+ log_message "Error: UUID required for attach operation" "err" |
|
| 22 |
+ exit 1 |
|
| 23 |
+ fi |
|
| 24 |
+ log_message "AutoNAS attach operation started for UUID: $2" "info" |
|
| 25 |
+ handle_attach "$2" |
|
| 26 |
+ ;; |
|
| 27 |
+ "attach-deferred") |
|
| 28 |
+ if [ -z "$2" ]; then |
|
| 29 |
+ log_message "Error: UUID required for deferred attach operation" "err" |
|
| 30 |
+ exit 1 |
|
| 31 |
+ fi |
|
| 32 |
+ log_message "AutoNAS deferred attach operation started for UUID: $2" "info" |
|
| 33 |
+ handle_attach "$2" |
|
| 34 |
+ ;; |
|
| 35 |
+ "detach") |
|
| 36 |
+ if [ -z "$2" ]; then |
|
| 37 |
+ log_message "Error: UUID or disk name required for detach operation" "err" |
|
| 38 |
+ exit 1 |
|
| 39 |
+ fi |
|
| 40 |
+ log_message "AutoNAS detach operation started for identifier: $2" "info" |
|
| 41 |
+ |
|
| 42 |
+ # Check if identifier is UUID (contains hyphens and matches UUID pattern) or name |
|
| 43 |
+ if [[ "$2" =~ ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$ ]] || [[ "$2" =~ ^[0-9a-fA-F]{4}-[0-9a-fA-F]{4}$ ]]; then
|
|
| 44 |
+ # It's a UUID - use directly |
|
| 45 |
+ handle_detach "$2" |
|
| 46 |
+ else |
|
| 47 |
+ # It's a name - get UUID from config |
|
| 48 |
+ local config_line |
|
| 49 |
+ config_line=$(get_config_by_name "$2" 2>/dev/null) |
|
| 50 |
+ if [ -n "$config_line" ]; then |
|
| 51 |
+ local uuid=$(echo "$config_line" | cut -d: -f1) |
|
| 52 |
+ handle_detach "$uuid" |
|
| 53 |
+ else |
|
| 54 |
+ log_message "No configuration found for name: $2 - detach skipped" "info" |
|
| 55 |
+ log_message "This may be normal if the disk was not configured for AutoNAS" "info" |
|
| 56 |
+ exit 0 |
|
| 57 |
+ fi |
|
| 58 |
+ fi |
|
| 59 |
+ ;; |
|
| 60 |
+ "import") |
|
| 61 |
+ if [ -z "$2" ] || [ -z "$3" ] || [ -z "$4" ]; then |
|
| 62 |
+ log_message "Error: UUID, mount_point, and destination required for import operation" "err" |
|
| 63 |
+ exit 1 |
|
| 64 |
+ fi |
|
| 65 |
+ log_message "AutoNAS background import operation started for UUID: $2" "info" |
|
| 66 |
+ run_background_import "$2" "$3" "$4" "$5" |
|
| 67 |
+ ;; |
|
| 68 |
+ "reload") |
|
| 69 |
+ handle_reload |
|
| 70 |
+ ;; |
|
| 71 |
+ *) |
|
| 72 |
+ echo "Usage: $0 {attach|attach-deferred|detach|import|reload} <UUID|name> [args...]"
|
|
| 73 |
+ echo " attach <UUID> - Attach disk by UUID (direct)" |
|
| 74 |
+ echo " attach-deferred <UUID> - Attach disk by UUID (via systemd)" |
|
| 75 |
+ echo " detach <UUID> - Detach disk by UUID (via udev)" |
|
| 76 |
+ echo " detach <name> - Detach disk by name (for manual/clean unmount)" |
|
| 77 |
+ echo " import <UUID> <mount> <dest> [script] - Run background camera import" |
|
| 78 |
+ echo "This script is typically called by udev rules or systemd" |
|
| 79 |
+ log_message "Invalid arguments provided: $*" "err" |
|
| 80 |
+ exit 1 |
|
| 81 |
+ ;; |
|
| 82 |
+esac |
|
@@ -0,0 +1,438 @@ |
||
| 1 |
+#!/bin/bash |
|
| 2 |
+ |
|
| 3 |
+# AutoNAS Media Importer |
|
| 4 |
+# Advanced media import engine that processes, organizes and imports media files from cameras |
|
| 5 |
+# Usage: autonas-media-importer.sh <source_mount> <destination_path> |
|
| 6 |
+ |
|
| 7 |
+# Global configuration |
|
| 8 |
+LOG_TAG="autonas-import" |
|
| 9 |
+ |
|
| 10 |
+# Function to log messages |
|
| 11 |
+log_message() {
|
|
| 12 |
+ local message="$1" |
|
| 13 |
+ local priority="${2:-info}" # Default priority is info
|
|
| 14 |
+ |
|
| 15 |
+ # Log to syslog with facility local0 and specified priority |
|
| 16 |
+ logger -p "local0.$priority" -t "$LOG_TAG" "$message" |
|
| 17 |
+ |
|
| 18 |
+ # Also echo to stdout/stderr for interactive use |
|
| 19 |
+ if [ -t 1 ]; then |
|
| 20 |
+ echo "$(date '+%Y-%m-%d %H:%M:%S') - $message" |
|
| 21 |
+ fi |
|
| 22 |
+} |
|
| 23 |
+ |
|
| 24 |
+# Usage function |
|
| 25 |
+usage() {
|
|
| 26 |
+ echo "Usage: $0 <source_mount> <destination_path> [options]" |
|
| 27 |
+ echo "" |
|
| 28 |
+ echo "Arguments:" |
|
| 29 |
+ echo " source_mount - Mount point of the camera (e.g., /mnt/autonas/camera)" |
|
| 30 |
+ echo " destination_path - Destination directory for imported files" |
|
| 31 |
+ echo "" |
|
| 32 |
+ echo "Options:" |
|
| 33 |
+ echo " --dry-run - Show what would be done without actually doing it" |
|
| 34 |
+ echo " --keep-originals - Keep original files on camera after import" |
|
| 35 |
+ echo " --verbose - Enable verbose output" |
|
| 36 |
+ echo " --limit N - Process only N files (useful for testing)" |
|
| 37 |
+ echo " --help - Show this help" |
|
| 38 |
+ echo "" |
|
| 39 |
+ echo "Examples:" |
|
| 40 |
+ echo " $0 /mnt/autonas/camera /mnt/autonas/photos/imported" |
|
| 41 |
+ echo " $0 /mnt/autonas/camera /mnt/autonas/photos/imported --dry-run --verbose" |
|
| 42 |
+} |
|
| 43 |
+ |
|
| 44 |
+# Parse command line arguments |
|
| 45 |
+SOURCE_MOUNT="" |
|
| 46 |
+DESTINATION="" |
|
| 47 |
+DRY_RUN=0 |
|
| 48 |
+KEEP_ORIGINALS=0 |
|
| 49 |
+VERBOSE=0 |
|
| 50 |
+FILE_LIMIT=0 |
|
| 51 |
+ |
|
| 52 |
+while [[ $# -gt 0 ]]; do |
|
| 53 |
+ case $1 in |
|
| 54 |
+ --dry-run) |
|
| 55 |
+ DRY_RUN=1 |
|
| 56 |
+ shift |
|
| 57 |
+ ;; |
|
| 58 |
+ --keep-originals) |
|
| 59 |
+ KEEP_ORIGINALS=1 |
|
| 60 |
+ shift |
|
| 61 |
+ ;; |
|
| 62 |
+ --verbose) |
|
| 63 |
+ VERBOSE=1 |
|
| 64 |
+ shift |
|
| 65 |
+ ;; |
|
| 66 |
+ --limit) |
|
| 67 |
+ FILE_LIMIT="$2" |
|
| 68 |
+ if ! [[ "$FILE_LIMIT" =~ ^[0-9]+$ ]]; then |
|
| 69 |
+ echo "Error: --limit requires a number" |
|
| 70 |
+ usage |
|
| 71 |
+ exit 1 |
|
| 72 |
+ fi |
|
| 73 |
+ shift 2 |
|
| 74 |
+ ;; |
|
| 75 |
+ --help) |
|
| 76 |
+ usage |
|
| 77 |
+ exit 0 |
|
| 78 |
+ ;; |
|
| 79 |
+ -*) |
|
| 80 |
+ echo "Unknown option: $1" |
|
| 81 |
+ usage |
|
| 82 |
+ exit 1 |
|
| 83 |
+ ;; |
|
| 84 |
+ *) |
|
| 85 |
+ if [[ -z "$SOURCE_MOUNT" ]]; then |
|
| 86 |
+ SOURCE_MOUNT="$1" |
|
| 87 |
+ elif [[ -z "$DESTINATION" ]]; then |
|
| 88 |
+ DESTINATION="$1" |
|
| 89 |
+ else |
|
| 90 |
+ echo "Too many arguments" |
|
| 91 |
+ usage |
|
| 92 |
+ exit 1 |
|
| 93 |
+ fi |
|
| 94 |
+ shift |
|
| 95 |
+ ;; |
|
| 96 |
+ esac |
|
| 97 |
+done |
|
| 98 |
+ |
|
| 99 |
+# Validate arguments |
|
| 100 |
+if [[ -z "$SOURCE_MOUNT" || -z "$DESTINATION" ]]; then |
|
| 101 |
+ echo "Error: Both source_mount and destination_path are required" |
|
| 102 |
+ usage |
|
| 103 |
+ exit 1 |
|
| 104 |
+fi |
|
| 105 |
+ |
|
| 106 |
+# Check if source exists and is mounted |
|
| 107 |
+if [[ ! -d "$SOURCE_MOUNT" ]]; then |
|
| 108 |
+ log_message "Error: Source mount point does not exist: $SOURCE_MOUNT" "err" |
|
| 109 |
+ exit 1 |
|
| 110 |
+fi |
|
| 111 |
+ |
|
| 112 |
+# Check if source is actually mounted |
|
| 113 |
+if ! mountpoint -q "$SOURCE_MOUNT" 2>/dev/null; then |
|
| 114 |
+ log_message "Warning: Source path is not a mount point: $SOURCE_MOUNT" "warning" |
|
| 115 |
+fi |
|
| 116 |
+ |
|
| 117 |
+# Create destination directory if it doesn't exist |
|
| 118 |
+if [[ $DRY_RUN -eq 0 ]]; then |
|
| 119 |
+ mkdir -p "$DESTINATION" |
|
| 120 |
+ if [[ ! -d "$DESTINATION" ]]; then |
|
| 121 |
+ log_message "Error: Cannot create destination directory: $DESTINATION" "err" |
|
| 122 |
+ exit 1 |
|
| 123 |
+ fi |
|
| 124 |
+fi |
|
| 125 |
+ |
|
| 126 |
+# Check for required tools |
|
| 127 |
+if ! command -v exiftool &> /dev/null; then |
|
| 128 |
+ log_message "Error: exiftool is required but not installed" "err" |
|
| 129 |
+ exit 1 |
|
| 130 |
+fi |
|
| 131 |
+ |
|
| 132 |
+# Function to process a single file |
|
| 133 |
+process_file() {
|
|
| 134 |
+ local file="$1" |
|
| 135 |
+ local relative_path="${file#$SOURCE_MOUNT/}"
|
|
| 136 |
+ |
|
| 137 |
+ # Check if source mount is still available |
|
| 138 |
+ if ! mountpoint -q "$SOURCE_MOUNT" 2>/dev/null; then |
|
| 139 |
+ log_message "Error: Source mount point is no longer available: $SOURCE_MOUNT" "err" |
|
| 140 |
+ return 1 |
|
| 141 |
+ fi |
|
| 142 |
+ |
|
| 143 |
+ # Check if file still exists |
|
| 144 |
+ if [[ ! -f "$file" ]]; then |
|
| 145 |
+ log_message "Error: File no longer exists: $relative_path" "err" |
|
| 146 |
+ log_message "Camera appears to be disconnected, stopping import" "warning" |
|
| 147 |
+ exit 1 |
|
| 148 |
+ fi |
|
| 149 |
+ |
|
| 150 |
+ if [[ $VERBOSE -eq 1 ]]; then |
|
| 151 |
+ log_message "Processing: $relative_path" "info" |
|
| 152 |
+ fi |
|
| 153 |
+ |
|
| 154 |
+ # Check which group CreateDate comes from to determine correct handling |
|
| 155 |
+ create_date_info=$(exiftool -G1 -s -CreateDate "$file" 2>/dev/null | grep CreateDate | head -1) |
|
| 156 |
+ |
|
| 157 |
+ # Check if exiftool failed (possible if device disconnected) |
|
| 158 |
+ local exiftool_exit_code=$? |
|
| 159 |
+ if [[ $exiftool_exit_code -ne 0 ]] && [[ $exiftool_exit_code -ne 1 ]]; then |
|
| 160 |
+ log_message "Error: Cannot read file (device may be disconnected): $relative_path" "err" |
|
| 161 |
+ log_message "Camera appears to be disconnected, stopping import" "warning" |
|
| 162 |
+ exit 1 |
|
| 163 |
+ fi |
|
| 164 |
+ |
|
| 165 |
+ if [[ -z "$create_date_info" ]]; then |
|
| 166 |
+ log_message "Warning: No CreateDate found in $relative_path, using file modification time" "warning" |
|
| 167 |
+ # Fallback to file modification time |
|
| 168 |
+ local file_date=$(date -r "$file" "+%Y-%m-%d %H:%M:%S" 2>/dev/null) |
|
| 169 |
+ if [[ -n "$file_date" ]]; then |
|
| 170 |
+ create_date_value="$file_date" |
|
| 171 |
+ create_date_group="FileSystem" |
|
| 172 |
+ else |
|
| 173 |
+ log_message "Error: Cannot determine date for $relative_path" "err" |
|
| 174 |
+ return 1 |
|
| 175 |
+ fi |
|
| 176 |
+ else |
|
| 177 |
+ create_date_group=$(echo "$create_date_info" | cut -d']' -f1 | cut -d'[' -f2) |
|
| 178 |
+ create_date_value=$(echo "$create_date_info" | cut -d':' -f2- | xargs) |
|
| 179 |
+ # Convert EXIF date format (YYYY:MM:DD HH:MM:SS) to standard format (YYYY-MM-DD HH:MM:SS) |
|
| 180 |
+ create_date_value=$(echo "$create_date_value" | sed 's/^\([0-9]\{4\}\):\([0-9]\{2\}\):\([0-9]\{2\}\)/\1-\2-\3/')
|
|
| 181 |
+ fi |
|
| 182 |
+ |
|
| 183 |
+ if [[ $VERBOSE -eq 1 ]]; then |
|
| 184 |
+ echo -n " Date: [$create_date_value] from $create_date_group " |
|
| 185 |
+ fi |
|
| 186 |
+ |
|
| 187 |
+ # Extract file extension |
|
| 188 |
+ local filename=$(basename "$file") |
|
| 189 |
+ local extension="${filename##*.}"
|
|
| 190 |
+ |
|
| 191 |
+ # For QuickTime files, the CreateDate is in UTC and needs conversion to local time |
|
| 192 |
+ if [[ "$create_date_group" == "QuickTime" ]]; then |
|
| 193 |
+ # Convert UTC time to local time |
|
| 194 |
+ local utc_timestamp=$(date -d "$create_date_value UTC" "+%s" 2>/dev/null) |
|
| 195 |
+ if [[ -n "$utc_timestamp" ]]; then |
|
| 196 |
+ create_date_value=$(date -d "@$utc_timestamp" "+%Y-%m-%d %H:%M:%S" 2>/dev/null) |
|
| 197 |
+ if [[ $VERBOSE -eq 1 ]]; then |
|
| 198 |
+ echo -n "(converted from UTC) " |
|
| 199 |
+ fi |
|
| 200 |
+ fi |
|
| 201 |
+ fi |
|
| 202 |
+ |
|
| 203 |
+ # Create output directory structure |
|
| 204 |
+ local date_dir=$(date -d "$create_date_value" "+%Y-%m-%d" 2>/dev/null) |
|
| 205 |
+ if [[ -z "$date_dir" ]]; then |
|
| 206 |
+ log_message "Error: Invalid date format for $relative_path: $create_date_value" "err" |
|
| 207 |
+ return 1 |
|
| 208 |
+ fi |
|
| 209 |
+ |
|
| 210 |
+ local output_dir="$DESTINATION/$date_dir" |
|
| 211 |
+ |
|
| 212 |
+ if [[ $DRY_RUN -eq 0 ]]; then |
|
| 213 |
+ mkdir -p "$output_dir" |
|
| 214 |
+ fi |
|
| 215 |
+ |
|
| 216 |
+ # Generate output filename with timestamp |
|
| 217 |
+ local timestamp=$(date -d "$create_date_value" "+%Y-%m-%d_%H-%M-%S" 2>/dev/null) |
|
| 218 |
+ local output_filename="${timestamp}.${extension,,}" # Convert extension to lowercase
|
|
| 219 |
+ local output_path="$output_dir/$output_filename" |
|
| 220 |
+ |
|
| 221 |
+ # Handle filename conflicts |
|
| 222 |
+ local counter=1 |
|
| 223 |
+ local base_output_path="$output_path" |
|
| 224 |
+ while [[ -f "$output_path" ]] && [[ $DRY_RUN -eq 0 ]]; do |
|
| 225 |
+ local name_without_ext="${timestamp}_${counter}"
|
|
| 226 |
+ output_path="$output_dir/${name_without_ext}.${extension,,}"
|
|
| 227 |
+ counter=$((counter + 1)) |
|
| 228 |
+ done |
|
| 229 |
+ |
|
| 230 |
+ if [[ $DRY_RUN -eq 1 ]]; then |
|
| 231 |
+ if [[ $KEEP_ORIGINALS -eq 1 ]]; then |
|
| 232 |
+ echo "Would copy: $relative_path -> ${output_path#$DESTINATION/}"
|
|
| 233 |
+ else |
|
| 234 |
+ echo "Would move: $relative_path -> ${output_path#$DESTINATION/}"
|
|
| 235 |
+ fi |
|
| 236 |
+ else |
|
| 237 |
+ # Perform the actual file operation |
|
| 238 |
+ if [[ $KEEP_ORIGINALS -eq 1 ]]; then |
|
| 239 |
+ if cp "$file" "$output_path"; then |
|
| 240 |
+ if [[ $VERBOSE -eq 1 ]]; then |
|
| 241 |
+ echo "โ Copied" |
|
| 242 |
+ fi |
|
| 243 |
+ log_message "Copied: $relative_path -> ${output_path#$DESTINATION/}" "info"
|
|
| 244 |
+ return 0 |
|
| 245 |
+ else |
|
| 246 |
+ if [[ $VERBOSE -eq 1 ]]; then |
|
| 247 |
+ echo "โ Copy failed" |
|
| 248 |
+ fi |
|
| 249 |
+ log_message "Error: Failed to copy $relative_path" "err" |
|
| 250 |
+ return 1 |
|
| 251 |
+ fi |
|
| 252 |
+ else |
|
| 253 |
+ if mv "$file" "$output_path"; then |
|
| 254 |
+ if [[ $VERBOSE -eq 1 ]]; then |
|
| 255 |
+ echo "โ Moved" |
|
| 256 |
+ fi |
|
| 257 |
+ log_message "Moved: $relative_path -> ${output_path#$DESTINATION/}" "info"
|
|
| 258 |
+ return 0 |
|
| 259 |
+ else |
|
| 260 |
+ if [[ $VERBOSE -eq 1 ]]; then |
|
| 261 |
+ echo "โ Move failed" |
|
| 262 |
+ fi |
|
| 263 |
+ log_message "Error: Failed to move $relative_path" "err" |
|
| 264 |
+ return 1 |
|
| 265 |
+ fi |
|
| 266 |
+ fi |
|
| 267 |
+ fi |
|
| 268 |
+} |
|
| 269 |
+ |
|
| 270 |
+# Function to find camera directories |
|
| 271 |
+find_camera_directories() {
|
|
| 272 |
+ local search_patterns=("DCIM" "PRIVATE" "MP_ROOT" "AVCHD" "Photos" "Videos")
|
|
| 273 |
+ local found_dirs=() |
|
| 274 |
+ |
|
| 275 |
+ # Test if the mount point is accessible with a timeout |
|
| 276 |
+ if ! timeout 3 ls "$SOURCE_MOUNT" >/dev/null 2>&1; then |
|
| 277 |
+ log_message "Error: Mount point is not accessible (device likely disconnected): $SOURCE_MOUNT" "err" |
|
| 278 |
+ exit 1 |
|
| 279 |
+ fi |
|
| 280 |
+ |
|
| 281 |
+ for pattern in "${search_patterns[@]}"; do
|
|
| 282 |
+ while IFS= read -r -d '' dir; do |
|
| 283 |
+ found_dirs+=("$dir")
|
|
| 284 |
+ done < <(timeout 5 find "$SOURCE_MOUNT" -maxdepth 3 -type d -iname "$pattern" -print0 2>/dev/null) |
|
| 285 |
+ done |
|
| 286 |
+ |
|
| 287 |
+ # If no camera directories found, search for common media file extensions |
|
| 288 |
+ if [[ ${#found_dirs[@]} -eq 0 ]]; then
|
|
| 289 |
+ log_message "No camera directories found, searching for media files..." "info" |
|
| 290 |
+ local media_extensions=("*.jpg" "*.jpeg" "*.png" "*.tiff" "*.cr2" "*.nef" "*.arw" "*.mp4" "*.mov" "*.avi" "*.mts" "*.m2ts")
|
|
| 291 |
+ |
|
| 292 |
+ for ext in "${media_extensions[@]}"; do
|
|
| 293 |
+ while IFS= read -r -d '' file; do |
|
| 294 |
+ local dir=$(dirname "$file") |
|
| 295 |
+ if [[ ! " ${found_dirs[@]} " =~ " ${dir} " ]]; then
|
|
| 296 |
+ found_dirs+=("$dir")
|
|
| 297 |
+ fi |
|
| 298 |
+ done < <(timeout 5 find "$SOURCE_MOUNT" -maxdepth 3 -type f -iname "$ext" -print0 2>/dev/null) |
|
| 299 |
+ done |
|
| 300 |
+ fi |
|
| 301 |
+ |
|
| 302 |
+ printf '%s\n' "${found_dirs[@]}" | sort -u
|
|
| 303 |
+} |
|
| 304 |
+ |
|
| 305 |
+# Main execution |
|
| 306 |
+log_message "Starting camera import from $SOURCE_MOUNT to $DESTINATION" "info" |
|
| 307 |
+ |
|
| 308 |
+if [[ $DRY_RUN -eq 1 ]]; then |
|
| 309 |
+ log_message "DRY RUN MODE - No files will be actually moved/copied" "info" |
|
| 310 |
+fi |
|
| 311 |
+ |
|
| 312 |
+if [[ $KEEP_ORIGINALS -eq 1 ]]; then |
|
| 313 |
+ log_message "KEEP ORIGINALS MODE - Files will be copied instead of moved" "info" |
|
| 314 |
+fi |
|
| 315 |
+ |
|
| 316 |
+# Find camera directories |
|
| 317 |
+log_message "Scanning for camera directories..." "info" |
|
| 318 |
+camera_dirs=$(find_camera_directories) |
|
| 319 |
+ |
|
| 320 |
+if [[ -z "$camera_dirs" ]]; then |
|
| 321 |
+ log_message "No camera directories or media files found in $SOURCE_MOUNT" "warning" |
|
| 322 |
+ exit 0 |
|
| 323 |
+fi |
|
| 324 |
+ |
|
| 325 |
+echo "Found camera directories:" |
|
| 326 |
+echo "$camera_dirs" | while IFS= read -r dir; do |
|
| 327 |
+ echo " $dir" |
|
| 328 |
+done |
|
| 329 |
+ |
|
| 330 |
+# Process files |
|
| 331 |
+total_files=0 |
|
| 332 |
+processed_files=0 |
|
| 333 |
+error_files=0 |
|
| 334 |
+ |
|
| 335 |
+# Delete GLV files (Garmin video preview files) - they're usually not needed |
|
| 336 |
+log_message "Cleaning up GLV preview files..." "info" |
|
| 337 |
+glv_count=0 |
|
| 338 |
+while IFS= read -r dir; do |
|
| 339 |
+ if [[ $DRY_RUN -eq 1 ]]; then |
|
| 340 |
+ glv_files=$(find "$dir" -type f -iname "*.glv" 2>/dev/null | wc -l) |
|
| 341 |
+ if [[ $glv_files -gt 0 ]]; then |
|
| 342 |
+ echo "Would delete $glv_files GLV files from $dir" |
|
| 343 |
+ glv_count=$((glv_count + glv_files)) |
|
| 344 |
+ fi |
|
| 345 |
+ else |
|
| 346 |
+ while IFS= read -r -d '' glv_file; do |
|
| 347 |
+ if rm "$glv_file" 2>/dev/null; then |
|
| 348 |
+ glv_count=$((glv_count + 1)) |
|
| 349 |
+ fi |
|
| 350 |
+ done < <(find "$dir" -type f -iname "*.glv" -print0 2>/dev/null) |
|
| 351 |
+ fi |
|
| 352 |
+done <<< "$camera_dirs" |
|
| 353 |
+ |
|
| 354 |
+if [[ $glv_count -gt 0 ]]; then |
|
| 355 |
+ if [[ $DRY_RUN -eq 1 ]]; then |
|
| 356 |
+ log_message "Would delete $glv_count GLV preview files" "info" |
|
| 357 |
+ else |
|
| 358 |
+ log_message "Deleted $glv_count GLV preview files" "info" |
|
| 359 |
+ fi |
|
| 360 |
+fi |
|
| 361 |
+ |
|
| 362 |
+# Process media files |
|
| 363 |
+log_message "Processing media files..." "info" |
|
| 364 |
+media_extensions=("*.jpg" "*.jpeg" "*.png" "*.tiff" "*.tif" "*.cr2" "*.nef" "*.arw" "*.dng" "*.mp4" "*.mov" "*.avi" "*.mts" "*.m2ts" "*.mkv" "*.wmv")
|
|
| 365 |
+ |
|
| 366 |
+# In dry-run mode, limit output to avoid overwhelming logs |
|
| 367 |
+max_files_to_show=20 |
|
| 368 |
+files_shown=0 |
|
| 369 |
+files_processed_count=0 |
|
| 370 |
+ |
|
| 371 |
+while IFS= read -r dir; do |
|
| 372 |
+ # Check if mount point is still available before processing each directory |
|
| 373 |
+ if ! mountpoint -q "$SOURCE_MOUNT" 2>/dev/null; then |
|
| 374 |
+ log_message "Camera disconnected, stopping import process" "warning" |
|
| 375 |
+ break |
|
| 376 |
+ fi |
|
| 377 |
+ |
|
| 378 |
+ for ext in "${media_extensions[@]}"; do
|
|
| 379 |
+ while IFS= read -r -d '' file; do |
|
| 380 |
+ total_files=$((total_files + 1)) |
|
| 381 |
+ files_processed_count=$((files_processed_count + 1)) |
|
| 382 |
+ |
|
| 383 |
+ # Check if camera is still connected before processing each file |
|
| 384 |
+ if ! mountpoint -q "$SOURCE_MOUNT" 2>/dev/null; then |
|
| 385 |
+ log_message "Camera disconnected during processing, stopping import" "warning" |
|
| 386 |
+ exit 1 |
|
| 387 |
+ fi |
|
| 388 |
+ |
|
| 389 |
+ # Check file limit |
|
| 390 |
+ if [[ $FILE_LIMIT -gt 0 && $files_processed_count -gt $FILE_LIMIT ]]; then |
|
| 391 |
+ echo "Reached file limit of $FILE_LIMIT files, stopping processing..." |
|
| 392 |
+ break 3 |
|
| 393 |
+ fi |
|
| 394 |
+ |
|
| 395 |
+ # In dry-run mode, limit verbose output |
|
| 396 |
+ if [[ $DRY_RUN -eq 1 && $files_shown -ge $max_files_to_show ]]; then |
|
| 397 |
+ if [[ $files_shown -eq $max_files_to_show ]]; then |
|
| 398 |
+ echo "... (limiting output in dry-run mode, processing continues)" |
|
| 399 |
+ files_shown=$((files_shown + 1)) |
|
| 400 |
+ fi |
|
| 401 |
+ # Still process but don't show details |
|
| 402 |
+ processed_files=$((processed_files + 1)) |
|
| 403 |
+ else |
|
| 404 |
+ if [[ $DRY_RUN -eq 1 ]]; then |
|
| 405 |
+ files_shown=$((files_shown + 1)) |
|
| 406 |
+ fi |
|
| 407 |
+ |
|
| 408 |
+ if process_file "$file"; then |
|
| 409 |
+ processed_files=$((processed_files + 1)) |
|
| 410 |
+ else |
|
| 411 |
+ error_files=$((error_files + 1)) |
|
| 412 |
+ fi |
|
| 413 |
+ fi |
|
| 414 |
+ done < <(find "$dir" -type f -iname "$ext" -print0 2>/dev/null) |
|
| 415 |
+ done |
|
| 416 |
+done <<< "$camera_dirs" |
|
| 417 |
+ |
|
| 418 |
+# Summary |
|
| 419 |
+log_message "Import completed: $processed_files/$total_files files processed successfully" "info" |
|
| 420 |
+if [[ $error_files -gt 0 ]]; then |
|
| 421 |
+ log_message "Import had errors: $error_files files failed to process" "warning" |
|
| 422 |
+fi |
|
| 423 |
+ |
|
| 424 |
+echo "" |
|
| 425 |
+echo "=== Import Summary ===" |
|
| 426 |
+echo "Total files found: $total_files" |
|
| 427 |
+echo "Successfully processed: $processed_files" |
|
| 428 |
+echo "Errors: $error_files" |
|
| 429 |
+if [[ $glv_count -gt 0 ]]; then |
|
| 430 |
+ echo "GLV files cleaned up: $glv_count" |
|
| 431 |
+fi |
|
| 432 |
+ |
|
| 433 |
+# Exit with error code if there were errors |
|
| 434 |
+if [[ $error_files -gt 0 ]]; then |
|
| 435 |
+ exit 1 |
|
| 436 |
+else |
|
| 437 |
+ exit 0 |
|
| 438 |
+fi |
|
@@ -0,0 +1,101 @@ |
||
| 1 |
+#!/bin/bash |
|
| 2 |
+ |
|
| 3 |
+# AutoNAS Network Handler - System integration for network interface events |
|
| 4 |
+# This script is called by udev when network interfaces change state |
|
| 5 |
+# Uses autonas-core.sh for all business logic |
|
| 6 |
+ |
|
| 7 |
+# Load the AutoNAS core library |
|
| 8 |
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
| 9 |
+source "${SCRIPT_DIR}/autonas-core.sh" || {
|
|
| 10 |
+ echo "Error: Cannot load AutoNAS core library" >&2 |
|
| 11 |
+ exit 1 |
|
| 12 |
+} |
|
| 13 |
+ |
|
| 14 |
+# Set LOG_TAG for this component |
|
| 15 |
+LOG_TAG="autonas-network-handler" |
|
| 16 |
+ |
|
| 17 |
+# Function to handle interface coming up |
|
| 18 |
+handle_interface_up() {
|
|
| 19 |
+ local interface="$1" |
|
| 20 |
+ local event_type="$2" |
|
| 21 |
+ |
|
| 22 |
+ log_message "Interface up event: $interface ($event_type)" "info" |
|
| 23 |
+ |
|
| 24 |
+ # Check if this interface is used by AutoNAS |
|
| 25 |
+ if interface_has_autonas_config "$interface"; then |
|
| 26 |
+ log_message "Interface $interface is configured for AutoNAS, restoring IP configurations" "info" |
|
| 27 |
+ |
|
| 28 |
+ # Small delay to let interface stabilize completely |
|
| 29 |
+ sleep 3 |
|
| 30 |
+ |
|
| 31 |
+ # Restore IPs for this interface |
|
| 32 |
+ if restore_interface_ips "$interface"; then |
|
| 33 |
+ log_message "Successfully processed interface $interface restoration" "info" |
|
| 34 |
+ else |
|
| 35 |
+ log_message "Failed to fully process interface $interface restoration" "warning" |
|
| 36 |
+ fi |
|
| 37 |
+ else |
|
| 38 |
+ log_message "Interface $interface is not configured for AutoNAS, ignoring" "debug" |
|
| 39 |
+ fi |
|
| 40 |
+} |
|
| 41 |
+ |
|
| 42 |
+# Function to handle interface going down |
|
| 43 |
+handle_interface_down() {
|
|
| 44 |
+ local interface="$1" |
|
| 45 |
+ local event_type="$2" |
|
| 46 |
+ |
|
| 47 |
+ log_message "Interface down event: $interface ($event_type)" "info" |
|
| 48 |
+ |
|
| 49 |
+ if interface_has_autonas_config "$interface"; then |
|
| 50 |
+ log_message "AutoNAS-configured interface $interface went down" "warning" |
|
| 51 |
+ fi |
|
| 52 |
+} |
|
| 53 |
+ |
|
| 54 |
+# Main script logic |
|
| 55 |
+ACTION="$1" |
|
| 56 |
+INTERFACE="$2" |
|
| 57 |
+EXTRA="$3" |
|
| 58 |
+ |
|
| 59 |
+case "$ACTION" in |
|
| 60 |
+ "interface_up"|"usb_interface_up") |
|
| 61 |
+ if [ -n "$INTERFACE" ]; then |
|
| 62 |
+ # Run in background to avoid udev timeout, but with shorter delay for faster response |
|
| 63 |
+ ( |
|
| 64 |
+ sleep 2 # Reduced from 3 seconds for faster response |
|
| 65 |
+ handle_interface_up "$INTERFACE" "$ACTION" |
|
| 66 |
+ ) & |
|
| 67 |
+ log_message "Started background handler for interface up: $INTERFACE (PID: $!)" "debug" |
|
| 68 |
+ fi |
|
| 69 |
+ ;; |
|
| 70 |
+ "interface_down"|"usb_interface_down") |
|
| 71 |
+ if [ -n "$INTERFACE" ]; then |
|
| 72 |
+ handle_interface_down "$INTERFACE" "$ACTION" |
|
| 73 |
+ fi |
|
| 74 |
+ ;; |
|
| 75 |
+ "interface_change") |
|
| 76 |
+ if [ -n "$INTERFACE" ] && [ -n "$EXTRA" ]; then |
|
| 77 |
+ case "$EXTRA" in |
|
| 78 |
+ "up"|"carrier_up") |
|
| 79 |
+ ( |
|
| 80 |
+ sleep 2 |
|
| 81 |
+ handle_interface_up "$INTERFACE" "change_to_$EXTRA" |
|
| 82 |
+ ) & |
|
| 83 |
+ log_message "Started background handler for interface $EXTRA: $INTERFACE (PID: $!)" "debug" |
|
| 84 |
+ ;; |
|
| 85 |
+ "down"|"carrier_down") |
|
| 86 |
+ handle_interface_down "$INTERFACE" "change_to_$EXTRA" |
|
| 87 |
+ ;; |
|
| 88 |
+ *) |
|
| 89 |
+ log_message "Unknown interface change state: $EXTRA for interface $INTERFACE" "warning" |
|
| 90 |
+ ;; |
|
| 91 |
+ esac |
|
| 92 |
+ fi |
|
| 93 |
+ ;; |
|
| 94 |
+ *) |
|
| 95 |
+ log_message "Unknown action: $ACTION with interface: $INTERFACE" "warning" |
|
| 96 |
+ exit 1 |
|
| 97 |
+ ;; |
|
| 98 |
+esac |
|
| 99 |
+ |
|
| 100 |
+# Exit immediately so udev doesn't wait |
|
| 101 |
+exit 0 |
|
@@ -0,0 +1,65 @@ |
||
| 1 |
+#!/bin/bash |
|
| 2 |
+ |
|
| 3 |
+# AutoNAS udev wrapper - runs the manager script in background to avoid udev timeout |
|
| 4 |
+# Usage: autonas-udev-wrapper.sh attach <uuid> |
|
| 5 |
+ |
|
| 6 |
+# Global configuration |
|
| 7 |
+LOG_TAG="autonas-wrapper" |
|
| 8 |
+ |
|
| 9 |
+# Set comprehensive environment for udev context |
|
| 10 |
+export PATH="/usr/local/bin:/usr/bin:/bin:/sbin:/usr/sbin" |
|
| 11 |
+export HOME="/root" |
|
| 12 |
+export USER="root" |
|
| 13 |
+export LOGNAME="root" |
|
| 14 |
+export SHELL="/bin/bash" |
|
| 15 |
+ |
|
| 16 |
+# Set proper umask for mount operations |
|
| 17 |
+umask 022 |
|
| 18 |
+ |
|
| 19 |
+UUID="$2" |
|
| 20 |
+ACTION="$1" |
|
| 21 |
+ |
|
| 22 |
+# Validate arguments |
|
| 23 |
+if [ -z "$ACTION" ] || [ -z "$UUID" ]; then |
|
| 24 |
+ logger -p local0.err -t "$LOG_TAG" "Invalid arguments: ACTION='$ACTION', UUID='$UUID'" |
|
| 25 |
+ exit 1 |
|
| 26 |
+fi |
|
| 27 |
+ |
|
| 28 |
+# Log the call with device info |
|
| 29 |
+logger -p local0.info -t "$LOG_TAG" "Called with action: $ACTION, UUID: $UUID" |
|
| 30 |
+ |
|
| 31 |
+# Get device info for logging |
|
| 32 |
+if [ -n "$UUID" ]; then |
|
| 33 |
+ DEVICE_PATH="/dev/disk/by-uuid/$UUID" |
|
| 34 |
+ if [ -e "$DEVICE_PATH" ]; then |
|
| 35 |
+ ACTUAL_DEVICE=$(readlink -f "$DEVICE_PATH" 2>/dev/null) |
|
| 36 |
+ logger -p local0.info -t "$LOG_TAG" "Device path: $ACTUAL_DEVICE" |
|
| 37 |
+ fi |
|
| 38 |
+fi |
|
| 39 |
+ |
|
| 40 |
+# Run the actual script through systemd for reliable execution |
|
| 41 |
+( |
|
| 42 |
+ # Additional delay for device stabilization |
|
| 43 |
+ sleep 3 |
|
| 44 |
+ |
|
| 45 |
+ # Ensure we're running as root with full privileges |
|
| 46 |
+ if [ "$(id -u)" != "0" ]; then |
|
| 47 |
+ logger -p local0.err -t "$LOG_TAG" "Not running as root, UID: $(id -u)" |
|
| 48 |
+ exit 1 |
|
| 49 |
+ fi |
|
| 50 |
+ |
|
| 51 |
+ # Use systemd service directly for reliable execution |
|
| 52 |
+ if [ "$ACTION" = "attach" ]; then |
|
| 53 |
+ systemctl start "autonas-attach@${UUID}.service"
|
|
| 54 |
+ logger -p local0.info -t "$LOG_TAG" "Started systemd service for UUID: $UUID" |
|
| 55 |
+ else |
|
| 56 |
+ logger -p local0.warning -t "$LOG_TAG" "Detach operations not supported through systemd wrapper" |
|
| 57 |
+ fi |
|
| 58 |
+ |
|
| 59 |
+) & |
|
| 60 |
+ |
|
| 61 |
+# Log background job started |
|
| 62 |
+logger -p local0.info -t "$LOG_TAG" "Started background job for $ACTION $UUID (PID: $!)" |
|
| 63 |
+ |
|
| 64 |
+# Exit immediately so udev doesn't wait |
|
| 65 |
+exit 0 |
|
@@ -0,0 +1,225 @@ |
||
| 1 |
+#!/bin/bash |
|
| 2 |
+ |
|
| 3 |
+# AutoNAS Uninstall Script |
|
| 4 |
+# This script is installed on each cluster node for version-specific removal |
|
| 5 |
+# Executed by deploy.sh or can be run directly on node: /usr/local/lib/autonas/autonas-uninstall.sh |
|
| 6 |
+ |
|
| 7 |
+# Global configuration |
|
| 8 |
+LOG_TAG="autonas-uninstall" |
|
| 9 |
+ |
|
| 10 |
+set -e # Exit on any error |
|
| 11 |
+ |
|
| 12 |
+# Check for force flag for silent cleanup |
|
| 13 |
+FORCE_MODE=false |
|
| 14 |
+if [ "$1" = "--force" ]; then |
|
| 15 |
+ FORCE_MODE=true |
|
| 16 |
+fi |
|
| 17 |
+ |
|
| 18 |
+# Helper function for conditional logging |
|
| 19 |
+log_message() {
|
|
| 20 |
+ if [ "$FORCE_MODE" = false ]; then |
|
| 21 |
+ echo "$1" |
|
| 22 |
+ fi |
|
| 23 |
+} |
|
| 24 |
+ |
|
| 25 |
+CONFIG_DIR="/etc/pve/autonas" |
|
| 26 |
+SCRIPT_NAME="autonas-disk-handler.sh" |
|
| 27 |
+WRAPPER_NAME="autonas-udev-wrapper.sh" |
|
| 28 |
+BOOT_SCAN_SCRIPT="autonas-boot-scan.sh" |
|
| 29 |
+CAMERA_IMPORT_SCRIPT="autonas-media-importer.sh" |
|
| 30 |
+INTERFACE_HANDLER_SCRIPT="autonas-network-handler.sh" |
|
| 31 |
+UNIFIED_SCRIPT="autonas.sh" |
|
| 32 |
+UDEV_RULES="99-autonas-disk.rules" |
|
| 33 |
+SYSTEMD_SERVICE="autonas-attach@.service" |
|
| 34 |
+MAIN_SERVICE="autonas.service" |
|
| 35 |
+BOOT_SCAN_SERVICE="autonas-boot-scan.service" |
|
| 36 |
+ |
|
| 37 |
+if [ "$FORCE_MODE" = false ]; then |
|
| 38 |
+ echo "=== AutoNAS Uninstall Script ===" |
|
| 39 |
+ echo "" |
|
| 40 |
+fi |
|
| 41 |
+ |
|
| 42 |
+# Check if running as root |
|
| 43 |
+if [ "$EUID" -ne 0 ]; then |
|
| 44 |
+ if [ "$FORCE_MODE" = false ]; then |
|
| 45 |
+ echo "โ This script must be run as root (use sudo)" |
|
| 46 |
+ fi |
|
| 47 |
+ exit 1 |
|
| 48 |
+fi |
|
| 49 |
+ |
|
| 50 |
+log_message "๐๏ธ Uninstalling AutoNAS..." |
|
| 51 |
+log_message "" |
|
| 52 |
+ |
|
| 53 |
+# Remove scripts |
|
| 54 |
+log_message "Removing AutoNAS scripts..." |
|
| 55 |
+if [ -f "/usr/local/bin/$SCRIPT_NAME" ]; then |
|
| 56 |
+ rm "/usr/local/bin/$SCRIPT_NAME" |
|
| 57 |
+ log_message "โ Manager script removed" |
|
| 58 |
+fi |
|
| 59 |
+ |
|
| 60 |
+if [ -f "/usr/local/bin/$WRAPPER_NAME" ]; then |
|
| 61 |
+ rm "/usr/local/bin/$WRAPPER_NAME" |
|
| 62 |
+ log_message "โ Wrapper script removed" |
|
| 63 |
+fi |
|
| 64 |
+ |
|
| 65 |
+if [ -f "/usr/local/bin/$BOOT_SCAN_SCRIPT" ]; then |
|
| 66 |
+ rm "/usr/local/bin/$BOOT_SCAN_SCRIPT" |
|
| 67 |
+ log_message "โ Boot scan script removed" |
|
| 68 |
+fi |
|
| 69 |
+ |
|
| 70 |
+if [ -f "/usr/local/bin/$CAMERA_IMPORT_SCRIPT" ]; then |
|
| 71 |
+ rm "/usr/local/bin/$CAMERA_IMPORT_SCRIPT" |
|
| 72 |
+ log_message "โ Camera import script removed" |
|
| 73 |
+fi |
|
| 74 |
+ |
|
| 75 |
+if [ -f "/usr/local/bin/$INTERFACE_HANDLER_SCRIPT" ]; then |
|
| 76 |
+ rm "/usr/local/bin/$INTERFACE_HANDLER_SCRIPT" |
|
| 77 |
+ log_message "โ Interface handler script removed" |
|
| 78 |
+fi |
|
| 79 |
+ |
|
| 80 |
+if [ -f "/usr/local/bin/$UNIFIED_SCRIPT" ]; then |
|
| 81 |
+ rm "/usr/local/bin/$UNIFIED_SCRIPT" |
|
| 82 |
+ log_message "โ Unified AutoNAS script removed" |
|
| 83 |
+fi |
|
| 84 |
+ |
|
| 85 |
+# Remove symlink |
|
| 86 |
+if [ -L "/usr/local/bin/autonas" ]; then |
|
| 87 |
+ rm "/usr/local/bin/autonas" |
|
| 88 |
+ log_message "โ AutoNAS symlink removed" |
|
| 89 |
+fi |
|
| 90 |
+ |
|
| 91 |
+# Remove internal scripts directory |
|
| 92 |
+if [ -d "/usr/local/lib/autonas" ]; then |
|
| 93 |
+ rm -rf "/usr/local/lib/autonas" |
|
| 94 |
+ log_message "โ AutoNAS internal scripts directory removed" |
|
| 95 |
+fi |
|
| 96 |
+ |
|
| 97 |
+# Aggressive cleanup for orphaned files from previous versions |
|
| 98 |
+log_message "Cleaning up orphaned files from previous versions..." |
|
| 99 |
+for orphan_file in "autonas-interface-debug.sh" "autonas-test-interface-stability.sh"; do |
|
| 100 |
+ if [ -f "/usr/local/bin/$orphan_file" ]; then |
|
| 101 |
+ rm "/usr/local/bin/$orphan_file" |
|
| 102 |
+ log_message "โ Orphaned file removed: $orphan_file" |
|
| 103 |
+ fi |
|
| 104 |
+done |
|
| 105 |
+ |
|
| 106 |
+# Remove udev rules |
|
| 107 |
+log_message "Removing udev rules..." |
|
| 108 |
+if [ -f "/etc/udev/rules.d/$UDEV_RULES" ]; then |
|
| 109 |
+ rm "/etc/udev/rules.d/$UDEV_RULES" |
|
| 110 |
+ udevadm control --reload-rules |
|
| 111 |
+ log_message "โ Udev rules removed" |
|
| 112 |
+fi |
|
| 113 |
+ |
|
| 114 |
+# Remove systemd service |
|
| 115 |
+log_message "Removing systemd service..." |
|
| 116 |
+if [ -f "/etc/systemd/system/$SYSTEMD_SERVICE" ]; then |
|
| 117 |
+ systemctl stop autonas-attach@*.service 2>/dev/null || true |
|
| 118 |
+ systemctl disable autonas-attach@*.service 2>/dev/null || true |
|
| 119 |
+ rm "/etc/systemd/system/$SYSTEMD_SERVICE" |
|
| 120 |
+ systemctl daemon-reload |
|
| 121 |
+ log_message "โ Systemd service removed" |
|
| 122 |
+fi |
|
| 123 |
+ |
|
| 124 |
+# Remove main service |
|
| 125 |
+log_message "Removing main AutoNAS service..." |
|
| 126 |
+if [ -f "/etc/systemd/system/$MAIN_SERVICE" ]; then |
|
| 127 |
+ systemctl stop autonas.service 2>/dev/null || true |
|
| 128 |
+ systemctl disable autonas.service 2>/dev/null || true |
|
| 129 |
+ rm "/etc/systemd/system/$MAIN_SERVICE" |
|
| 130 |
+ systemctl daemon-reload |
|
| 131 |
+ log_message "โ Main AutoNAS service removed" |
|
| 132 |
+fi |
|
| 133 |
+ |
|
| 134 |
+# Remove boot scan service |
|
| 135 |
+log_message "Removing boot scan service..." |
|
| 136 |
+if [ -f "/etc/systemd/system/$BOOT_SCAN_SERVICE" ]; then |
|
| 137 |
+ systemctl stop autonas-boot-scan.service 2>/dev/null || true |
|
| 138 |
+ systemctl disable autonas-boot-scan.service 2>/dev/null || true |
|
| 139 |
+ rm "/etc/systemd/system/$BOOT_SCAN_SERVICE" |
|
| 140 |
+ systemctl daemon-reload |
|
| 141 |
+ log_message "โ Boot scan service removed" |
|
| 142 |
+fi |
|
| 143 |
+ |
|
| 144 |
+# Handle configuration and data preservation |
|
| 145 |
+log_message "" |
|
| 146 |
+log_message "๐ Handling user data..." |
|
| 147 |
+ |
|
| 148 |
+# Check if configuration exists and has user data |
|
| 149 |
+if [ -f "$CONFIG_DIR/disks.conf" ]; then |
|
| 150 |
+ if grep -v '^#' "$CONFIG_DIR/disks.conf" | grep -v '^$' | grep -q ':'; then |
|
| 151 |
+ log_message "โ ๏ธ User configurations detected in $CONFIG_DIR/disks.conf" |
|
| 152 |
+ log_message " Configuration file preserved for manual cleanup" |
|
| 153 |
+ log_message " Remove manually with: sudo rm -rf $CONFIG_DIR" |
|
| 154 |
+ else |
|
| 155 |
+ log_message "โน๏ธ Configuration file contains only template - removing" |
|
| 156 |
+ rm "$CONFIG_DIR/disks.conf" |
|
| 157 |
+ rmdir "$CONFIG_DIR" 2>/dev/null || true |
|
| 158 |
+ fi |
|
| 159 |
+else |
|
| 160 |
+ log_message "โน๏ธ No configuration file found" |
|
| 161 |
+ rmdir "$CONFIG_DIR" 2>/dev/null || true |
|
| 162 |
+fi |
|
| 163 |
+ |
|
| 164 |
+# Check for mounted AutoNAS disks |
|
| 165 |
+log_message "" |
|
| 166 |
+log_message "๐พ Checking for mounted AutoNAS disks..." |
|
| 167 |
+mounted_autonas=$(mount | grep "/mnt/autonas/" | wc -l) |
|
| 168 |
+if [ $mounted_autonas -gt 0 ]; then |
|
| 169 |
+ log_message "โ ๏ธ Found $mounted_autonas mounted AutoNAS disk(s):" |
|
| 170 |
+ if [ "$FORCE_MODE" = false ]; then |
|
| 171 |
+ mount | grep "/mnt/autonas/" | while read line; do |
|
| 172 |
+ echo " $line" |
|
| 173 |
+ done |
|
| 174 |
+ fi |
|
| 175 |
+ log_message "" |
|
| 176 |
+ log_message " These disks are still mounted and in use." |
|
| 177 |
+ log_message " Mount points preserved: /mnt/autonas/" |
|
| 178 |
+ log_message " Unmount manually if needed: sudo umount /mnt/autonas/*" |
|
| 179 |
+else |
|
| 180 |
+ log_message "โน๏ธ No AutoNAS disks currently mounted" |
|
| 181 |
+ if [ -d "/mnt/autonas" ]; then |
|
| 182 |
+ # Only remove if empty |
|
| 183 |
+ if [ -z "$(ls -A /mnt/autonas)" ]; then |
|
| 184 |
+ rmdir "/mnt/autonas" |
|
| 185 |
+ log_message "โ Empty AutoNAS mount directory removed" |
|
| 186 |
+ else |
|
| 187 |
+ log_message "โ ๏ธ AutoNAS mount directory contains files - preserved" |
|
| 188 |
+ fi |
|
| 189 |
+ fi |
|
| 190 |
+fi |
|
| 191 |
+ |
|
| 192 |
+# Check NFS exports |
|
| 193 |
+log_message "" |
|
| 194 |
+log_message "๐ Checking NFS exports..." |
|
| 195 |
+if [ -f "/etc/exports" ] && grep -q "/mnt/autonas/" "/etc/exports" 2>/dev/null; then |
|
| 196 |
+ log_message "โ ๏ธ AutoNAS NFS exports found in /etc/exports" |
|
| 197 |
+ log_message " Please manually remove AutoNAS entries from /etc/exports" |
|
| 198 |
+ log_message " And reload NFS exports: sudo exportfs -ra" |
|
| 199 |
+else |
|
| 200 |
+ log_message "โน๏ธ No AutoNAS NFS exports found" |
|
| 201 |
+fi |
|
| 202 |
+ |
|
| 203 |
+log_message "" |
|
| 204 |
+log_message "๐ AutoNAS core components removed successfully!" |
|
| 205 |
+ |
|
| 206 |
+if [ "$FORCE_MODE" = false ]; then |
|
| 207 |
+ echo "" |
|
| 208 |
+ echo "๐ Summary:" |
|
| 209 |
+ echo "โ Scripts removed from /usr/local/bin/" |
|
| 210 |
+ echo "โ Udev rules removed" |
|
| 211 |
+ echo "โ Systemd services removed" |
|
| 212 |
+ echo "" |
|
| 213 |
+ echo "โ ๏ธ Preserved (manual cleanup required if desired):" |
|
| 214 |
+ echo "โข User configurations: $CONFIG_DIR/ (if contains user data)" |
|
| 215 |
+ echo "โข Mount points: /mnt/autonas/ (if contains data)" |
|
| 216 |
+ echo "โข NFS exports: /etc/exports (manual edit required)" |
|
| 217 |
+ echo "" |
|
| 218 |
+ echo "๐ To completely remove all AutoNAS data:" |
|
| 219 |
+ echo "sudo rm -rf $CONFIG_DIR" |
|
| 220 |
+ echo "sudo rm -rf /mnt/autonas" |
|
| 221 |
+ echo "sudo nano /etc/exports # Remove AutoNAS entries manually" |
|
| 222 |
+ echo "sudo exportfs -ra" |
|
| 223 |
+fi |
|
| 224 |
+echo "" |
|
| 225 |
+echo "๐ To reinstall AutoNAS later, run: sudo bash scripts/install.sh" |
|
@@ -0,0 +1,1211 @@ |
||
| 1 |
+#!/bin/bash |
|
| 2 |
+ |
|
| 3 |
+# AutoNAS - Unified AutoNAS Management Tool |
|
| 4 |
+# Combines manager, configuration, and all other functionality into one script |
|
| 5 |
+# Usage: autonas <command> [options] |
|
| 6 |
+ |
|
| 7 |
+# Load core AutoNAS library |
|
| 8 |
+if [[ -f "/usr/local/bin/autonas-core.sh" ]]; then |
|
| 9 |
+ source "/usr/local/bin/autonas-core.sh" |
|
| 10 |
+else |
|
| 11 |
+ echo "Error: AutoNAS core library not found at /usr/local/bin/autonas-core.sh" >&2 |
|
| 12 |
+ exit 1 |
|
| 13 |
+fi |
|
| 14 |
+ |
|
| 15 |
+# Function to handle disk attachment |
|
| 16 |
+handle_attach() {
|
|
| 17 |
+ local uuid="$1" |
|
| 18 |
+ |
|
| 19 |
+ log_message "AutoNAS attach operation started for UUID: $uuid" |
|
| 20 |
+ |
|
| 21 |
+ # Get configuration for this UUID |
|
| 22 |
+ local config |
|
| 23 |
+ config=$(get_disk_config "$uuid") |
|
| 24 |
+ |
|
| 25 |
+ if [[ -z "$config" ]]; then |
|
| 26 |
+ log_message "No configuration found for UUID: $uuid - disk will be ignored" |
|
| 27 |
+ log_message "To configure this disk, run: autonas-config.sh add" |
|
| 28 |
+ return 1 |
|
| 29 |
+ fi |
|
| 30 |
+ |
|
| 31 |
+ log_message "Handling disk attachment for UUID: $uuid" |
|
| 32 |
+ |
|
| 33 |
+ # Parse configuration |
|
| 34 |
+ local parsed |
|
| 35 |
+ parsed=($(parse_config "$config")) |
|
| 36 |
+ local cfg_uuid="${parsed[0]}"
|
|
| 37 |
+ local name="${parsed[1]}"
|
|
| 38 |
+ local ip="${parsed[2]}"
|
|
| 39 |
+ local interface="${parsed[3]}"
|
|
| 40 |
+ local mount_point="${parsed[4]}"
|
|
| 41 |
+ local nfs_options="${parsed[5]}"
|
|
| 42 |
+ |
|
| 43 |
+ log_message "Processing disk: $name (IP: $ip, Mount: $mount_point)" |
|
| 44 |
+ |
|
| 45 |
+ # Handle different disk types |
|
| 46 |
+ if [[ "$ip" == "IMPORT" && "$interface" == "IMPORT" ]]; then |
|
| 47 |
+ # Camera import workflow: mount temporarily, import, then unmount |
|
| 48 |
+ log_message "Detected camera import configuration for UUID: $uuid" |
|
| 49 |
+ |
|
| 50 |
+ # Mount disk for import |
|
| 51 |
+ if mount_disk "$uuid" "$mount_point"; then |
|
| 52 |
+ # Start import process |
|
| 53 |
+ handle_camera_import "$uuid" "$mount_point" "$nfs_options" |
|
| 54 |
+ return $? |
|
| 55 |
+ else |
|
| 56 |
+ log_message "Error: Failed to mount camera device" "err" |
|
| 57 |
+ return 1 |
|
| 58 |
+ fi |
|
| 59 |
+ elif [[ "$ip" == "LOCAL" ]]; then |
|
| 60 |
+ # Local mount only (no network sharing) |
|
| 61 |
+ if mount_disk "$uuid" "$mount_point"; then |
|
| 62 |
+ log_message "Local disk mounted successfully at $mount_point" |
|
| 63 |
+ return 0 |
|
| 64 |
+ else |
|
| 65 |
+ return 1 |
|
| 66 |
+ fi |
|
| 67 |
+ else |
|
| 68 |
+ # Regular NFS workflow: activate IP, mount, export via NFS |
|
| 69 |
+ if activate_ip "$ip" "$interface"; then |
|
| 70 |
+ if mount_disk "$uuid" "$mount_point"; then |
|
| 71 |
+ if add_nfs_export "$mount_point" "$nfs_options"; then |
|
| 72 |
+ log_message "Disk attached successfully: $name" |
|
| 73 |
+ return 0 |
|
| 74 |
+ else |
|
| 75 |
+ log_message "Warning: Disk mounted but NFS export failed" "warning" |
|
| 76 |
+ return 1 |
|
| 77 |
+ fi |
|
| 78 |
+ else |
|
| 79 |
+ deactivate_ip "$ip" "$interface" |
|
| 80 |
+ return 1 |
|
| 81 |
+ fi |
|
| 82 |
+ else |
|
| 83 |
+ return 1 |
|
| 84 |
+ fi |
|
| 85 |
+ fi |
|
| 86 |
+} |
|
| 87 |
+ |
|
| 88 |
+# Function to handle disk detachment |
|
| 89 |
+handle_detach() {
|
|
| 90 |
+ local uuid="$1" |
|
| 91 |
+ |
|
| 92 |
+ log_message "AutoNAS detach operation started for UUID: $uuid" |
|
| 93 |
+ |
|
| 94 |
+ # Get configuration for this UUID |
|
| 95 |
+ local config |
|
| 96 |
+ config=$(get_disk_config "$uuid") |
|
| 97 |
+ |
|
| 98 |
+ if [[ -z "$config" ]]; then |
|
| 99 |
+ log_message "No configuration found for UUID: $uuid" |
|
| 100 |
+ return 1 |
|
| 101 |
+ fi |
|
| 102 |
+ |
|
| 103 |
+ log_message "Handling disk detachment for UUID: $uuid" |
|
| 104 |
+ |
|
| 105 |
+ # Parse configuration |
|
| 106 |
+ local parsed |
|
| 107 |
+ parsed=($(parse_config "$config")) |
|
| 108 |
+ local cfg_uuid="${parsed[0]}"
|
|
| 109 |
+ local name="${parsed[1]}"
|
|
| 110 |
+ local ip="${parsed[2]}"
|
|
| 111 |
+ local interface="${parsed[3]}"
|
|
| 112 |
+ local mount_point="${parsed[4]}"
|
|
| 113 |
+ local nfs_options="${parsed[5]}"
|
|
| 114 |
+ |
|
| 115 |
+ log_message "Processing disk: $name (Mount: $mount_point)" |
|
| 116 |
+ |
|
| 117 |
+ # Remove NFS export (if applicable) |
|
| 118 |
+ if [[ "$ip" != "LOCAL" && "$ip" != "IMPORT" ]]; then |
|
| 119 |
+ remove_nfs_export "$mount_point" |
|
| 120 |
+ fi |
|
| 121 |
+ |
|
| 122 |
+ # Unmount disk |
|
| 123 |
+ if unmount_disk "$mount_point"; then |
|
| 124 |
+ # Deactivate IP (if applicable) |
|
| 125 |
+ if [[ "$ip" != "LOCAL" && "$ip" != "IMPORT" ]]; then |
|
| 126 |
+ deactivate_ip "$ip" "$interface" |
|
| 127 |
+ fi |
|
| 128 |
+ |
|
| 129 |
+ log_message "Disk detached successfully: $name" |
|
| 130 |
+ return 0 |
|
| 131 |
+ else |
|
| 132 |
+ log_message "Error: Failed to detach disk: $name" "err" |
|
| 133 |
+ return 1 |
|
| 134 |
+ fi |
|
| 135 |
+} |
|
| 136 |
+ |
|
| 137 |
+# Function to reload configuration |
|
| 138 |
+handle_reload() {
|
|
| 139 |
+ log_message "Reloading AutoNAS configuration" |
|
| 140 |
+ |
|
| 141 |
+ log_message "Reloading udev rules" |
|
| 142 |
+ udevadm control --reload-rules |
|
| 143 |
+ udevadm trigger --subsystem-match=block |
|
| 144 |
+ |
|
| 145 |
+ log_message "Reloading NFS exports" |
|
| 146 |
+ exportfs -ra || log_message "Warning: Failed to reload NFS exports" "warning" |
|
| 147 |
+ |
|
| 148 |
+ log_message "Reloading systemd daemon" |
|
| 149 |
+ systemctl daemon-reload || log_message "Warning: Failed to reload systemd daemon" "warning" |
|
| 150 |
+ |
|
| 151 |
+ log_message "AutoNAS configuration reload completed" |
|
| 152 |
+ return 0 |
|
| 153 |
+} |
|
| 154 |
+ |
|
| 155 |
+# Function to manually mount a configured disk |
|
| 156 |
+handle_manual_mount() {
|
|
| 157 |
+ local identifier="$1" # UUID or name |
|
| 158 |
+ |
|
| 159 |
+ if [[ -z "$identifier" ]]; then |
|
| 160 |
+ echo "Error: UUID or disk name required" |
|
| 161 |
+ return 1 |
|
| 162 |
+ fi |
|
| 163 |
+ |
|
| 164 |
+ echo "Looking for disk configuration: $identifier" |
|
| 165 |
+ |
|
| 166 |
+ # Try to find configuration by UUID first, then by name |
|
| 167 |
+ local config |
|
| 168 |
+ config=$(get_disk_config "$identifier") || config=$(get_config_by_name "$identifier") |
|
| 169 |
+ |
|
| 170 |
+ if [[ -z "$config" ]]; then |
|
| 171 |
+ echo "Error: No configuration found for '$identifier'" |
|
| 172 |
+ echo "Use 'autonas list' to see configured disks" |
|
| 173 |
+ return 1 |
|
| 174 |
+ fi |
|
| 175 |
+ |
|
| 176 |
+ # Parse configuration |
|
| 177 |
+ local parsed |
|
| 178 |
+ parsed=($(parse_config "$config")) |
|
| 179 |
+ local uuid="${parsed[0]}"
|
|
| 180 |
+ local name="${parsed[1]}"
|
|
| 181 |
+ local ip="${parsed[2]}"
|
|
| 182 |
+ local interface="${parsed[3]}"
|
|
| 183 |
+ local mount_point="${parsed[4]}"
|
|
| 184 |
+ local nfs_options="${parsed[5]}"
|
|
| 185 |
+ |
|
| 186 |
+ echo "Found configuration: $name (UUID: $uuid)" |
|
| 187 |
+ |
|
| 188 |
+ # Check if already mounted |
|
| 189 |
+ if mountpoint -q "$mount_point" 2>/dev/null; then |
|
| 190 |
+ echo "โ Disk already mounted at: $mount_point" |
|
| 191 |
+ return 0 |
|
| 192 |
+ fi |
|
| 193 |
+ |
|
| 194 |
+ # Handle different disk types for mounting |
|
| 195 |
+ if [[ "$ip" == "IMPORT" ]]; then |
|
| 196 |
+ echo "โ ๏ธ Camera import disks are not meant for manual mounting" |
|
| 197 |
+ echo " They are automatically imported when connected" |
|
| 198 |
+ return 1 |
|
| 199 |
+ elif [[ "$ip" == "LOCAL" ]]; then |
|
| 200 |
+ # Local mount only |
|
| 201 |
+ echo "๐ต Mounting local disk..." |
|
| 202 |
+ if mount_disk "$uuid" "$mount_point"; then |
|
| 203 |
+ echo "โ Local disk mounted successfully at: $mount_point" |
|
| 204 |
+ return 0 |
|
| 205 |
+ else |
|
| 206 |
+ echo "โ Failed to mount local disk" |
|
| 207 |
+ return 1 |
|
| 208 |
+ fi |
|
| 209 |
+ else |
|
| 210 |
+ # Network mount - need to activate IP first |
|
| 211 |
+ echo "๐ Mounting network disk..." |
|
| 212 |
+ if activate_ip "$ip" "$interface"; then |
|
| 213 |
+ if mount_disk "$uuid" "$mount_point"; then |
|
| 214 |
+ if add_nfs_export "$mount_point" "$nfs_options" "$uuid" "$name"; then |
|
| 215 |
+ echo "โ Network disk mounted and exported successfully" |
|
| 216 |
+ echo " Mount point: $mount_point" |
|
| 217 |
+ echo " NFS export: $mount_point $nfs_options" |
|
| 218 |
+ return 0 |
|
| 219 |
+ else |
|
| 220 |
+ echo "โ ๏ธ Disk mounted but NFS export failed" |
|
| 221 |
+ return 1 |
|
| 222 |
+ fi |
|
| 223 |
+ else |
|
| 224 |
+ deactivate_ip "$ip" "$interface" |
|
| 225 |
+ echo "โ Failed to mount network disk" |
|
| 226 |
+ return 1 |
|
| 227 |
+ fi |
|
| 228 |
+ else |
|
| 229 |
+ echo "โ Failed to activate network interface" |
|
| 230 |
+ return 1 |
|
| 231 |
+ fi |
|
| 232 |
+ fi |
|
| 233 |
+} |
|
| 234 |
+ |
|
| 235 |
+# Function to manually unmount a configured disk |
|
| 236 |
+handle_manual_unmount() {
|
|
| 237 |
+ local identifier="$1" # UUID or name |
|
| 238 |
+ |
|
| 239 |
+ if [[ -z "$identifier" ]]; then |
|
| 240 |
+ echo "Error: UUID or disk name required" |
|
| 241 |
+ return 1 |
|
| 242 |
+ fi |
|
| 243 |
+ |
|
| 244 |
+ echo "Looking for disk configuration: $identifier" |
|
| 245 |
+ |
|
| 246 |
+ # Try to find configuration by UUID first, then by name |
|
| 247 |
+ local config |
|
| 248 |
+ config=$(get_disk_config "$identifier") || config=$(get_config_by_name "$identifier") |
|
| 249 |
+ |
|
| 250 |
+ if [[ -z "$config" ]]; then |
|
| 251 |
+ echo "Error: No configuration found for '$identifier'" |
|
| 252 |
+ echo "Use 'autonas list' to see configured disks" |
|
| 253 |
+ return 1 |
|
| 254 |
+ fi |
|
| 255 |
+ |
|
| 256 |
+ # Parse configuration |
|
| 257 |
+ local parsed |
|
| 258 |
+ parsed=($(parse_config "$config")) |
|
| 259 |
+ local uuid="${parsed[0]}"
|
|
| 260 |
+ local name="${parsed[1]}"
|
|
| 261 |
+ local ip="${parsed[2]}"
|
|
| 262 |
+ local interface="${parsed[3]}"
|
|
| 263 |
+ local mount_point="${parsed[4]}"
|
|
| 264 |
+ local nfs_options="${parsed[5]}"
|
|
| 265 |
+ |
|
| 266 |
+ echo "Found configuration: $name (UUID: $uuid)" |
|
| 267 |
+ |
|
| 268 |
+ # Check if actually mounted |
|
| 269 |
+ if ! mountpoint -q "$mount_point" 2>/dev/null; then |
|
| 270 |
+ echo "โน๏ธ Disk is not currently mounted: $mount_point" |
|
| 271 |
+ return 0 |
|
| 272 |
+ fi |
|
| 273 |
+ |
|
| 274 |
+ echo "๐ฝ Unmounting disk..." |
|
| 275 |
+ |
|
| 276 |
+ # Remove NFS export first (if applicable) |
|
| 277 |
+ if [[ "$ip" != "LOCAL" && "$ip" != "IMPORT" ]]; then |
|
| 278 |
+ remove_nfs_export "$mount_point" "$uuid" "$name" "$nfs_options" |
|
| 279 |
+ fi |
|
| 280 |
+ |
|
| 281 |
+ # Unmount disk |
|
| 282 |
+ if unmount_disk "$mount_point"; then |
|
| 283 |
+ # Deactivate IP if network disk |
|
| 284 |
+ if [[ "$ip" != "LOCAL" && "$ip" != "IMPORT" ]]; then |
|
| 285 |
+ deactivate_ip "$ip" "$interface" |
|
| 286 |
+ fi |
|
| 287 |
+ |
|
| 288 |
+ echo "โ Disk unmounted successfully: $name" |
|
| 289 |
+ return 0 |
|
| 290 |
+ else |
|
| 291 |
+ echo "โ Failed to unmount disk: $name" |
|
| 292 |
+ return 1 |
|
| 293 |
+ fi |
|
| 294 |
+} |
|
| 295 |
+ |
|
| 296 |
+# Show usage information |
|
| 297 |
+show_usage() {
|
|
| 298 |
+ cat << EOF |
|
| 299 |
+AutoNAS - Unified AutoNAS Management Tool |
|
| 300 |
+ |
|
| 301 |
+Usage: $0 <command> [options] |
|
| 302 |
+ |
|
| 303 |
+DISK OPERATIONS: |
|
| 304 |
+ attach <uuid> - Attach disk with specified UUID |
|
| 305 |
+ detach <uuid> - Detach disk with specified UUID |
|
| 306 |
+ mount <uuid|name> - Manually mount configured disk |
|
| 307 |
+ unmount <uuid|name> - Manually unmount configured disk |
|
| 308 |
+ import <uuid> <source> <dest> [script] - Run background import (internal use) |
|
| 309 |
+ reload - Reload AutoNAS configuration |
|
| 310 |
+ |
|
| 311 |
+CONFIGURATION MANAGEMENT: |
|
| 312 |
+ add [uuid] - Add new disk configuration |
|
| 313 |
+ remove [uuid] - Remove disk configuration |
|
| 314 |
+ list - List all configured disks |
|
| 315 |
+ test [uuid] - Test disk configuration |
|
| 316 |
+ show - Show available disks |
|
| 317 |
+ |
|
| 318 |
+MAINTENANCE: |
|
| 319 |
+ status - Show system status |
|
| 320 |
+ debug enable - Enable debug mode (verbose logging) |
|
| 321 |
+ debug disable - Disable debug mode |
|
| 322 |
+ debug status - Show current debug status |
|
| 323 |
+ |
|
| 324 |
+Examples: |
|
| 325 |
+ $0 attach f6ac3d86-5681-4b33-bc64-aa272b333057 |
|
| 326 |
+ $0 add 8765-4321 |
|
| 327 |
+ $0 list |
|
| 328 |
+ $0 show |
|
| 329 |
+ $0 status |
|
| 330 |
+ |
|
| 331 |
+EOF |
|
| 332 |
+} |
|
| 333 |
+ |
|
| 334 |
+# Function to show available disks |
|
| 335 |
+show_available_disks() {
|
|
| 336 |
+ echo "=== Available Storage Devices ===" |
|
| 337 |
+ echo |
|
| 338 |
+ |
|
| 339 |
+ local found_devices=0 |
|
| 340 |
+ local blkid_output |
|
| 341 |
+ |
|
| 342 |
+ # Get blkid output and process it |
|
| 343 |
+ if ! blkid_output=$(blkid 2>/dev/null); then |
|
| 344 |
+ echo "Error: Unable to scan for block devices (are you running as root?)" |
|
| 345 |
+ return 1 |
|
| 346 |
+ fi |
|
| 347 |
+ |
|
| 348 |
+ while IFS= read -r blkid_line; do |
|
| 349 |
+ [[ -z "$blkid_line" ]] && continue |
|
| 350 |
+ |
|
| 351 |
+ local device=$(echo "$blkid_line" | cut -d: -f1) |
|
| 352 |
+ |
|
| 353 |
+ # Skip if device doesn't exist (shouldn't happen with blkid, but just in case) |
|
| 354 |
+ [[ ! -b "$device" ]] && continue |
|
| 355 |
+ |
|
| 356 |
+ # Skip loop devices, ram disks, and other virtual devices |
|
| 357 |
+ case "$device" in |
|
| 358 |
+ /dev/loop*|/dev/ram*|/dev/dm-*) continue ;; |
|
| 359 |
+ esac |
|
| 360 |
+ |
|
| 361 |
+ # Extract device information |
|
| 362 |
+ local uuid=$(echo "$blkid_line" | grep -o 'UUID="[^"]*"' | cut -d'"' -f2) |
|
| 363 |
+ local label=$(echo "$blkid_line" | grep -o 'LABEL="[^"]*"' | cut -d'"' -f2) |
|
| 364 |
+ local fstype=$(echo "$blkid_line" | grep -o 'TYPE="[^"]*"' | cut -d'"' -f2) |
|
| 365 |
+ local partuuid=$(echo "$blkid_line" | grep -o 'PARTUUID="[^"]*"' | cut -d'"' -f2) |
|
| 366 |
+ |
|
| 367 |
+ # Skip if no UUID (we need UUID for AutoNAS) |
|
| 368 |
+ [[ -z "$uuid" ]] && continue |
|
| 369 |
+ |
|
| 370 |
+ found_devices=$((found_devices + 1)) |
|
| 371 |
+ |
|
| 372 |
+ # Get device size |
|
| 373 |
+ local size="" |
|
| 374 |
+ if [[ -b "$device" ]]; then |
|
| 375 |
+ size=$(lsblk -b -d -o SIZE "$device" 2>/dev/null | tail -n1) |
|
| 376 |
+ if [[ -n "$size" ]] && [[ "$size" =~ ^[0-9]+$ ]]; then |
|
| 377 |
+ # Convert to human readable |
|
| 378 |
+ size=$(numfmt --to=iec --suffix=B "$size" 2>/dev/null || echo "${size}B")
|
|
| 379 |
+ fi |
|
| 380 |
+ fi |
|
| 381 |
+ |
|
| 382 |
+ # Display device information |
|
| 383 |
+ echo "Device: $device" |
|
| 384 |
+ [[ -n "$size" ]] && echo " Size: $size" |
|
| 385 |
+ echo " UUID: $uuid" |
|
| 386 |
+ [[ -n "$label" ]] && echo " Label: $label" |
|
| 387 |
+ [[ -n "$fstype" ]] && echo " Filesystem: $fstype" |
|
| 388 |
+ |
|
| 389 |
+ # Check if already configured |
|
| 390 |
+ if grep -q "^${uuid}:" "$CONFIG_FILE" 2>/dev/null; then
|
|
| 391 |
+ local config_line=$(grep "^${uuid}:" "$CONFIG_FILE" 2>/dev/null)
|
|
| 392 |
+ local config_name=$(echo "$config_line" | cut -d: -f2) |
|
| 393 |
+ echo " Status: โ Configured as '$config_name'" |
|
| 394 |
+ else |
|
| 395 |
+ echo " Status: โ ๏ธ Not configured" |
|
| 396 |
+ fi |
|
| 397 |
+ |
|
| 398 |
+ # Check if currently mounted |
|
| 399 |
+ local mount_info |
|
| 400 |
+ mount_info=$(findmnt -n -o TARGET "$device" 2>/dev/null) |
|
| 401 |
+ if [[ -n "$mount_info" ]]; then |
|
| 402 |
+ echo " Mount: ๐ข $mount_info" |
|
| 403 |
+ else |
|
| 404 |
+ echo " Mount: โช Not mounted" |
|
| 405 |
+ fi |
|
| 406 |
+ |
|
| 407 |
+ echo |
|
| 408 |
+ done <<< "$blkid_output" |
|
| 409 |
+ |
|
| 410 |
+ if [[ $found_devices -eq 0 ]]; then |
|
| 411 |
+ echo "No storage devices with UUIDs found." |
|
| 412 |
+ echo "Make sure devices are connected and you're running as root." |
|
| 413 |
+ else |
|
| 414 |
+ echo "Found $found_devices storage device(s)" |
|
| 415 |
+ echo |
|
| 416 |
+ echo "To configure a device: autonas add <UUID>" |
|
| 417 |
+ echo "To list configured devices: autonas list" |
|
| 418 |
+ fi |
|
| 419 |
+ |
|
| 420 |
+ return 0 |
|
| 421 |
+} |
|
| 422 |
+ |
|
| 423 |
+# Show usage information |
|
| 424 |
+ |
|
| 425 |
+# Function to check if UUID exists in configuration |
|
| 426 |
+check_uuid_exists() {
|
|
| 427 |
+ local uuid="$1" |
|
| 428 |
+ grep -q "^${uuid}:" "$CONFIG_FILE" 2>/dev/null
|
|
| 429 |
+} |
|
| 430 |
+ |
|
| 431 |
+# Function to get device information |
|
| 432 |
+get_device_info() {
|
|
| 433 |
+ local uuid="$1" |
|
| 434 |
+ |
|
| 435 |
+ # Find device by UUID using blkid |
|
| 436 |
+ local device_line |
|
| 437 |
+ device_line=$(blkid | grep "UUID=\"$uuid\"") |
|
| 438 |
+ |
|
| 439 |
+ if [[ -z "$device_line" ]]; then |
|
| 440 |
+ return 1 |
|
| 441 |
+ fi |
|
| 442 |
+ |
|
| 443 |
+ local device=$(echo "$device_line" | cut -d: -f1) |
|
| 444 |
+ local blkid_info=$(echo "$device_line" | cut -d: -f2-) |
|
| 445 |
+ |
|
| 446 |
+ echo "device:$device" |
|
| 447 |
+ echo "$blkid_info" |
|
| 448 |
+ return 0 |
|
| 449 |
+} |
|
| 450 |
+ |
|
| 451 |
+# Function to list configured disks |
|
| 452 |
+list_disks() {
|
|
| 453 |
+ echo "AutoNAS Disk Configurations:" |
|
| 454 |
+ echo "============================" |
|
| 455 |
+ echo "" |
|
| 456 |
+ |
|
| 457 |
+ if [[ ! -f "$CONFIG_FILE" ]]; then |
|
| 458 |
+ echo "No configuration file found at: $CONFIG_FILE" |
|
| 459 |
+ echo "Use 'autonas add' to add your first disk configuration." |
|
| 460 |
+ return 1 |
|
| 461 |
+ fi |
|
| 462 |
+ |
|
| 463 |
+ local config_count=0 |
|
| 464 |
+ while IFS=':' read -r uuid name ip interface mount_point nfs_options; do |
|
| 465 |
+ # Skip empty lines and comments |
|
| 466 |
+ [[ -z "$uuid" || "$uuid" =~ ^# ]] && continue |
|
| 467 |
+ |
|
| 468 |
+ config_count=$((config_count + 1)) |
|
| 469 |
+ |
|
| 470 |
+ echo "UUID: $uuid" |
|
| 471 |
+ echo "Name: $name" |
|
| 472 |
+ |
|
| 473 |
+ # Check if it's a local mount configuration |
|
| 474 |
+ if [[ "$ip" == "LOCAL" && "$interface" == "LOCAL" && "$nfs_options" == "LOCAL" ]]; then |
|
| 475 |
+ echo "Type: ๐ Local Mount (no network sharing)" |
|
| 476 |
+ echo "Mount Point: $mount_point" |
|
| 477 |
+ elif [[ "$ip" == "IMPORT" && "$interface" == "IMPORT" ]]; then |
|
| 478 |
+ echo "Type: ๐ท Camera Import (mount, import, unmount)" |
|
| 479 |
+ echo "Import Destination: $nfs_options" |
|
| 480 |
+ echo "Import Script: /usr/local/bin/autonas-media-importer.sh (built-in, non-configurable)" |
|
| 481 |
+ echo "Temp Mount Point: $mount_point" |
|
| 482 |
+ else |
|
| 483 |
+ echo "Type: ๐ NFS Network Share" |
|
| 484 |
+ echo "IP: $ip" |
|
| 485 |
+ echo "Interface: $interface" |
|
| 486 |
+ echo "Mount Point: $mount_point" |
|
| 487 |
+ echo "NFS Options: $nfs_options" |
|
| 488 |
+ fi |
|
| 489 |
+ |
|
| 490 |
+ # Check device status |
|
| 491 |
+ local device_info |
|
| 492 |
+ if device_info=$(get_device_info "$uuid" 2>/dev/null); then |
|
| 493 |
+ local device=$(echo "$device_info" | grep "^device:" | cut -d: -f2) |
|
| 494 |
+ echo "Status: โ Connected" |
|
| 495 |
+ |
|
| 496 |
+ # Check if mounted |
|
| 497 |
+ if mountpoint -q "$mount_point" 2>/dev/null; then |
|
| 498 |
+ echo "Mount Status: ๐ข Mounted" |
|
| 499 |
+ echo "Current Mount: $mount_point" |
|
| 500 |
+ else |
|
| 501 |
+ echo "Mount Status: ๐ด Not Mounted" |
|
| 502 |
+ fi |
|
| 503 |
+ else |
|
| 504 |
+ echo "Status: ๐ด Not Connected" |
|
| 505 |
+ fi |
|
| 506 |
+ |
|
| 507 |
+ echo "----" |
|
| 508 |
+ done < <(grep -v '^#' "$CONFIG_FILE" 2>/dev/null | grep -v '^$') |
|
| 509 |
+ |
|
| 510 |
+ if [[ $config_count -eq 0 ]]; then |
|
| 511 |
+ echo "No disk configurations found." |
|
| 512 |
+ echo "Use 'autonas add' to add your first disk configuration." |
|
| 513 |
+ return 1 |
|
| 514 |
+ fi |
|
| 515 |
+ |
|
| 516 |
+ echo "" |
|
| 517 |
+ echo "Total configurations: $config_count" |
|
| 518 |
+ return 0 |
|
| 519 |
+} |
|
| 520 |
+ |
|
| 521 |
+# Function to add disk configuration |
|
| 522 |
+add_disk() {
|
|
| 523 |
+ local preset_uuid="$1" # Optional UUID parameter |
|
| 524 |
+ |
|
| 525 |
+ echo "AutoNAS - Add New Disk Configuration" |
|
| 526 |
+ echo "====================================" |
|
| 527 |
+ echo "" |
|
| 528 |
+ |
|
| 529 |
+ # Show available disks first |
|
| 530 |
+ show_available_disks |
|
| 531 |
+ if [ $? -ne 0 ]; then |
|
| 532 |
+ echo "Cannot proceed without available disks." |
|
| 533 |
+ return 1 |
|
| 534 |
+ fi |
|
| 535 |
+ |
|
| 536 |
+ echo "Please enter the configuration for your disk:" |
|
| 537 |
+ echo "" |
|
| 538 |
+ |
|
| 539 |
+ # Get UUID with validation |
|
| 540 |
+ local uuid="$preset_uuid" |
|
| 541 |
+ if [ -n "$uuid" ]; then |
|
| 542 |
+ echo "Using provided UUID: $uuid" |
|
| 543 |
+ |
|
| 544 |
+ if ! validate_uuid "$uuid"; then |
|
| 545 |
+ echo "Error: Invalid UUID format. Expected format: 12345678-1234-1234-1234-123456789abc" |
|
| 546 |
+ echo "Please run without UUID parameter to enter manually." |
|
| 547 |
+ return 1 |
|
| 548 |
+ fi |
|
| 549 |
+ |
|
| 550 |
+ if check_uuid_exists "$uuid"; then |
|
| 551 |
+ echo "Error: UUID $uuid is already configured." |
|
| 552 |
+ echo "Use 'autonas remove $uuid' to remove existing configuration first." |
|
| 553 |
+ return 1 |
|
| 554 |
+ fi |
|
| 555 |
+ else |
|
| 556 |
+ while true; do |
|
| 557 |
+ read -p "Enter disk UUID: " uuid |
|
| 558 |
+ if [ -z "$uuid" ]; then |
|
| 559 |
+ echo "Error: UUID cannot be empty" |
|
| 560 |
+ continue |
|
| 561 |
+ fi |
|
| 562 |
+ |
|
| 563 |
+ if ! validate_uuid "$uuid"; then |
|
| 564 |
+ echo "Error: Invalid UUID format. Expected format: 12345678-1234-1234-1234-123456789abc" |
|
| 565 |
+ continue |
|
| 566 |
+ fi |
|
| 567 |
+ |
|
| 568 |
+ if check_uuid_exists "$uuid"; then |
|
| 569 |
+ echo "Error: UUID $uuid is already configured." |
|
| 570 |
+ echo "Use 'autonas remove $uuid' to remove existing configuration first." |
|
| 571 |
+ continue |
|
| 572 |
+ fi |
|
| 573 |
+ |
|
| 574 |
+ break |
|
| 575 |
+ done |
|
| 576 |
+ fi |
|
| 577 |
+ |
|
| 578 |
+ # Get and validate disk name |
|
| 579 |
+ local name |
|
| 580 |
+ while true; do |
|
| 581 |
+ read -p "Enter disk name (letters, numbers, hyphens, underscores, @ allowed): " name |
|
| 582 |
+ if [ -z "$name" ]; then |
|
| 583 |
+ echo "Error: Disk name cannot be empty" |
|
| 584 |
+ continue |
|
| 585 |
+ fi |
|
| 586 |
+ |
|
| 587 |
+ if ! validate_disk_name_complete "$name"; then |
|
| 588 |
+ local validation_result=$? |
|
| 589 |
+ if [[ $validation_result -eq 2 ]]; then |
|
| 590 |
+ echo "Error: Disk name '$name' already exists. Please choose another name." |
|
| 591 |
+ echo "" |
|
| 592 |
+ list_existing_disk_names |
|
| 593 |
+ echo "" |
|
| 594 |
+ continue |
|
| 595 |
+ else |
|
| 596 |
+ echo "Error: Invalid disk name. Requirements:" |
|
| 597 |
+ echo " - Max 50 characters" |
|
| 598 |
+ echo " - Must start with letter or number" |
|
| 599 |
+ echo " - Only letters, numbers, hyphens (-), underscores (_), and at symbol (@)" |
|
| 600 |
+ echo " - Cannot be reserved names (root, home, tmp, etc.)" |
|
| 601 |
+ continue |
|
| 602 |
+ fi |
|
| 603 |
+ fi |
|
| 604 |
+ |
|
| 605 |
+ break |
|
| 606 |
+ done |
|
| 607 |
+ |
|
| 608 |
+ # Choose configuration type |
|
| 609 |
+ echo "" |
|
| 610 |
+ echo "Select disk type:" |
|
| 611 |
+ echo "1) NFS Network Share (default) - Share disk over network" |
|
| 612 |
+ echo "2) Camera Import - Import photos/videos from camera and unmount" |
|
| 613 |
+ echo "3) Local Mount - Mount locally without network sharing" |
|
| 614 |
+ echo "" |
|
| 615 |
+ |
|
| 616 |
+ local config_type |
|
| 617 |
+ read -p "Choose type [1-3] (default: 1): " config_type |
|
| 618 |
+ config_type=${config_type:-1}
|
|
| 619 |
+ |
|
| 620 |
+ case "$config_type" in |
|
| 621 |
+ 1) |
|
| 622 |
+ configure_nfs_disk "$uuid" "$name" |
|
| 623 |
+ ;; |
|
| 624 |
+ 2) |
|
| 625 |
+ configure_import_disk "$uuid" "$name" |
|
| 626 |
+ ;; |
|
| 627 |
+ 3) |
|
| 628 |
+ configure_local_disk "$uuid" "$name" |
|
| 629 |
+ ;; |
|
| 630 |
+ *) |
|
| 631 |
+ echo "Invalid choice. Using NFS Network Share (default)." |
|
| 632 |
+ configure_nfs_disk "$uuid" "$name" |
|
| 633 |
+ ;; |
|
| 634 |
+ esac |
|
| 635 |
+} |
|
| 636 |
+ |
|
| 637 |
+# Function to configure NFS disk |
|
| 638 |
+configure_nfs_disk() {
|
|
| 639 |
+ local uuid="$1" |
|
| 640 |
+ local name="$2" |
|
| 641 |
+ |
|
| 642 |
+ echo "" |
|
| 643 |
+ echo "=== NFS Network Share Configuration ===" |
|
| 644 |
+ |
|
| 645 |
+ # Get IP address |
|
| 646 |
+ local ip |
|
| 647 |
+ while true; do |
|
| 648 |
+ read -p "Enter IP address for NFS sharing (e.g., 192.168.1.100): " ip |
|
| 649 |
+ if [ -z "$ip" ]; then |
|
| 650 |
+ echo "Error: IP address cannot be empty" |
|
| 651 |
+ continue |
|
| 652 |
+ fi |
|
| 653 |
+ |
|
| 654 |
+ # Basic IP validation |
|
| 655 |
+ if [[ ! "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
|
|
| 656 |
+ echo "Error: Invalid IP address format" |
|
| 657 |
+ continue |
|
| 658 |
+ fi |
|
| 659 |
+ |
|
| 660 |
+ # Check each octet |
|
| 661 |
+ local valid_ip=true |
|
| 662 |
+ IFS='.' read -ra OCTETS <<< "$ip" |
|
| 663 |
+ for octet in "${OCTETS[@]}"; do
|
|
| 664 |
+ if [ "$octet" -lt 0 ] || [ "$octet" -gt 255 ]; then |
|
| 665 |
+ valid_ip=false |
|
| 666 |
+ break |
|
| 667 |
+ fi |
|
| 668 |
+ done |
|
| 669 |
+ |
|
| 670 |
+ if [ "$valid_ip" = false ]; then |
|
| 671 |
+ echo "Error: IP address octets must be between 0-255" |
|
| 672 |
+ continue |
|
| 673 |
+ fi |
|
| 674 |
+ |
|
| 675 |
+ break |
|
| 676 |
+ done |
|
| 677 |
+ |
|
| 678 |
+ # Get network interface |
|
| 679 |
+ local interface |
|
| 680 |
+ echo "" |
|
| 681 |
+ echo "Available network interfaces:" |
|
| 682 |
+ ip link show | grep "^[0-9]" | cut -d: -f2 | sed 's/^ *//' | grep -v "^lo$" |
|
| 683 |
+ echo "" |
|
| 684 |
+ |
|
| 685 |
+ while true; do |
|
| 686 |
+ read -p "Enter network interface (e.g., eth0, enp0s3): " interface |
|
| 687 |
+ if [ -z "$interface" ]; then |
|
| 688 |
+ echo "Error: Network interface cannot be empty" |
|
| 689 |
+ continue |
|
| 690 |
+ fi |
|
| 691 |
+ |
|
| 692 |
+ # Check if interface exists |
|
| 693 |
+ if ! ip link show "$interface" >/dev/null 2>&1; then |
|
| 694 |
+ echo "Error: Network interface '$interface' does not exist" |
|
| 695 |
+ echo "Available interfaces:" |
|
| 696 |
+ ip link show | grep "^[0-9]" | cut -d: -f2 | sed 's/^ *//' | grep -v "^lo$" |
|
| 697 |
+ continue |
|
| 698 |
+ fi |
|
| 699 |
+ |
|
| 700 |
+ break |
|
| 701 |
+ done |
|
| 702 |
+ |
|
| 703 |
+ # Generate mount point |
|
| 704 |
+ local mount_point="$MOUNT_BASE/$name" |
|
| 705 |
+ echo "" |
|
| 706 |
+ echo "Mount point will be: $mount_point" |
|
| 707 |
+ |
|
| 708 |
+ # Get NFS options |
|
| 709 |
+ local nfs_options |
|
| 710 |
+ echo "" |
|
| 711 |
+ echo "NFS Options (press Enter for default):" |
|
| 712 |
+ echo "Default: *(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0)" |
|
| 713 |
+ read -p "Enter custom NFS options or press Enter for default: " nfs_options |
|
| 714 |
+ |
|
| 715 |
+ if [ -z "$nfs_options" ]; then |
|
| 716 |
+ nfs_options="*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0)" |
|
| 717 |
+ fi |
|
| 718 |
+ |
|
| 719 |
+ # Create configuration entry |
|
| 720 |
+ local config_entry="${uuid}:${name}:${ip}:${interface}:${mount_point}:${nfs_options}"
|
|
| 721 |
+ |
|
| 722 |
+ # Show configuration summary |
|
| 723 |
+ echo "" |
|
| 724 |
+ echo "=== Configuration Summary ===" |
|
| 725 |
+ echo "UUID: $uuid" |
|
| 726 |
+ echo "Name: $name" |
|
| 727 |
+ echo "Type: NFS Network Share" |
|
| 728 |
+ echo "IP: $ip" |
|
| 729 |
+ echo "Interface: $interface" |
|
| 730 |
+ echo "Mount Point: $mount_point" |
|
| 731 |
+ echo "NFS Options: $nfs_options" |
|
| 732 |
+ echo "" |
|
| 733 |
+ |
|
| 734 |
+ # Confirm configuration |
|
| 735 |
+ read -p "Save this configuration? (Y/n): " confirm |
|
| 736 |
+ if [[ "$confirm" =~ ^[Nn]$ ]]; then |
|
| 737 |
+ echo "Configuration cancelled." |
|
| 738 |
+ return 1 |
|
| 739 |
+ fi |
|
| 740 |
+ |
|
| 741 |
+ # Save configuration |
|
| 742 |
+ echo "$config_entry" >> "$CONFIG_FILE" |
|
| 743 |
+ echo "" |
|
| 744 |
+ echo "โ Configuration saved successfully!" |
|
| 745 |
+ echo "" |
|
| 746 |
+ echo "To test this configuration: autonas test $uuid" |
|
| 747 |
+ echo "To attach this disk when connected: autonas attach $uuid" |
|
| 748 |
+ |
|
| 749 |
+ return 0 |
|
| 750 |
+} |
|
| 751 |
+ |
|
| 752 |
+# Function to configure local disk |
|
| 753 |
+configure_local_disk() {
|
|
| 754 |
+ local uuid="$1" |
|
| 755 |
+ local name="$2" |
|
| 756 |
+ |
|
| 757 |
+ echo "" |
|
| 758 |
+ echo "=== Local Mount Configuration ===" |
|
| 759 |
+ echo "This disk will be mounted locally without network sharing." |
|
| 760 |
+ echo "" |
|
| 761 |
+ |
|
| 762 |
+ # Generate mount point |
|
| 763 |
+ local mount_point="$MOUNT_BASE/$name" |
|
| 764 |
+ echo "Mount point will be: $mount_point" |
|
| 765 |
+ echo "" |
|
| 766 |
+ |
|
| 767 |
+ # Create configuration entry |
|
| 768 |
+ local config_entry="${uuid}:${name}:LOCAL:LOCAL:${mount_point}:LOCAL"
|
|
| 769 |
+ |
|
| 770 |
+ # Show configuration summary |
|
| 771 |
+ echo "=== Configuration Summary ===" |
|
| 772 |
+ echo "UUID: $uuid" |
|
| 773 |
+ echo "Name: $name" |
|
| 774 |
+ echo "Type: Local Mount (no network sharing)" |
|
| 775 |
+ echo "Mount Point: $mount_point" |
|
| 776 |
+ echo "" |
|
| 777 |
+ |
|
| 778 |
+ # Confirm configuration |
|
| 779 |
+ read -p "Save this configuration? (Y/n): " confirm |
|
| 780 |
+ if [[ "$confirm" =~ ^[Nn]$ ]]; then |
|
| 781 |
+ echo "Configuration cancelled." |
|
| 782 |
+ return 1 |
|
| 783 |
+ fi |
|
| 784 |
+ |
|
| 785 |
+ # Save configuration |
|
| 786 |
+ echo "$config_entry" >> "$CONFIG_FILE" |
|
| 787 |
+ echo "" |
|
| 788 |
+ echo "โ Configuration saved successfully!" |
|
| 789 |
+ echo "" |
|
| 790 |
+ echo "To test this configuration: autonas test $uuid" |
|
| 791 |
+ echo "To attach this disk when connected: autonas attach $uuid" |
|
| 792 |
+ |
|
| 793 |
+ return 0 |
|
| 794 |
+} |
|
| 795 |
+ |
|
| 796 |
+# Function to configure import disk (camera) |
|
| 797 |
+configure_import_disk() {
|
|
| 798 |
+ local uuid="$1" |
|
| 799 |
+ local name="$2" |
|
| 800 |
+ |
|
| 801 |
+ echo "" |
|
| 802 |
+ echo "=== Camera Import Configuration ===" |
|
| 803 |
+ echo "This device will be mounted temporarily, media imported, then unmounted." |
|
| 804 |
+ echo "" |
|
| 805 |
+ |
|
| 806 |
+ # Get destination path for import |
|
| 807 |
+ local destination_path |
|
| 808 |
+ while true; do |
|
| 809 |
+ read -p "Enter destination path for imported media: " destination_path |
|
| 810 |
+ if [ -z "$destination_path" ]; then |
|
| 811 |
+ echo "Error: Destination path cannot be empty" |
|
| 812 |
+ continue |
|
| 813 |
+ fi |
|
| 814 |
+ |
|
| 815 |
+ # Convert relative path to absolute |
|
| 816 |
+ if [[ ! "$destination_path" =~ ^/ ]]; then |
|
| 817 |
+ destination_path="$(pwd)/$destination_path" |
|
| 818 |
+ fi |
|
| 819 |
+ |
|
| 820 |
+ # Validate parent directory exists |
|
| 821 |
+ local parent_dir=$(dirname "$destination_path") |
|
| 822 |
+ if [ ! -d "$parent_dir" ]; then |
|
| 823 |
+ echo "Warning: Parent directory '$parent_dir' does not exist." |
|
| 824 |
+ read -p "Create parent directories? (Y/n): " create_dirs |
|
| 825 |
+ if [[ ! "$create_dirs" =~ ^[Nn]$ ]]; then |
|
| 826 |
+ if mkdir -p "$parent_dir" 2>/dev/null; then |
|
| 827 |
+ echo "Created parent directories." |
|
| 828 |
+ else |
|
| 829 |
+ echo "Error: Failed to create parent directories. Please check permissions." |
|
| 830 |
+ continue |
|
| 831 |
+ fi |
|
| 832 |
+ else |
|
| 833 |
+ echo "Please enter a valid destination path." |
|
| 834 |
+ continue |
|
| 835 |
+ fi |
|
| 836 |
+ fi |
|
| 837 |
+ |
|
| 838 |
+ break |
|
| 839 |
+ done |
|
| 840 |
+ |
|
| 841 |
+ # Generate temporary mount point for import |
|
| 842 |
+ local temp_mount_point="$MOUNT_BASE/$name" |
|
| 843 |
+ |
|
| 844 |
+ # Create configuration entry (simplified format - no script path) |
|
| 845 |
+ local config_entry="${uuid}:${name}:IMPORT:IMPORT:${temp_mount_point}:${destination_path}"
|
|
| 846 |
+ |
|
| 847 |
+ # Show configuration summary |
|
| 848 |
+ echo "" |
|
| 849 |
+ echo "=== Configuration Summary ===" |
|
| 850 |
+ echo "UUID: $uuid" |
|
| 851 |
+ echo "Name: $name" |
|
| 852 |
+ echo "Type: Camera Import (mount, import, unmount)" |
|
| 853 |
+ echo "Import destination: $destination_path" |
|
| 854 |
+ echo "Import script: /usr/local/bin/autonas-media-importer.sh (built-in, non-configurable)" |
|
| 855 |
+ echo "Temp mount point: $temp_mount_point" |
|
| 856 |
+ echo "" |
|
| 857 |
+ |
|
| 858 |
+ # Confirm configuration |
|
| 859 |
+ read -p "Save this configuration? (Y/n): " confirm |
|
| 860 |
+ if [[ "$confirm" =~ ^[Nn]$ ]]; then |
|
| 861 |
+ echo "Configuration cancelled." |
|
| 862 |
+ return 1 |
|
| 863 |
+ fi |
|
| 864 |
+ |
|
| 865 |
+ # Save configuration |
|
| 866 |
+ echo "$config_entry" >> "$CONFIG_FILE" |
|
| 867 |
+ echo "" |
|
| 868 |
+ echo "โ Configuration saved successfully!" |
|
| 869 |
+ echo "" |
|
| 870 |
+ echo "To test this configuration: autonas test $uuid" |
|
| 871 |
+ echo "When camera is connected, media will be imported automatically to: $destination_path" |
|
| 872 |
+ |
|
| 873 |
+ return 0 |
|
| 874 |
+} |
|
| 875 |
+ |
|
| 876 |
+# Function to remove disk configuration |
|
| 877 |
+remove_disk() {
|
|
| 878 |
+ local uuid="$1" |
|
| 879 |
+ |
|
| 880 |
+ if [[ -z "$uuid" ]]; then |
|
| 881 |
+ echo "Usage: autonas remove <uuid>" |
|
| 882 |
+ return 1 |
|
| 883 |
+ fi |
|
| 884 |
+ |
|
| 885 |
+ if [[ ! -f "$CONFIG_FILE" ]]; then |
|
| 886 |
+ echo "No configuration file found." |
|
| 887 |
+ return 1 |
|
| 888 |
+ fi |
|
| 889 |
+ |
|
| 890 |
+ # Check if UUID exists |
|
| 891 |
+ if ! check_uuid_exists "$uuid"; then |
|
| 892 |
+ echo "Error: UUID '$uuid' not found in configuration." |
|
| 893 |
+ return 1 |
|
| 894 |
+ fi |
|
| 895 |
+ |
|
| 896 |
+ # Show current configuration |
|
| 897 |
+ echo "Current configuration for UUID: $uuid" |
|
| 898 |
+ echo "==================================" |
|
| 899 |
+ local config=$(get_disk_config "$uuid") |
|
| 900 |
+ local parsed=($(parse_config "$config")) |
|
| 901 |
+ echo "Name: ${parsed[1]}"
|
|
| 902 |
+ echo "Type: ${parsed[2]}:${parsed[3]}"
|
|
| 903 |
+ echo "Mount: ${parsed[4]}"
|
|
| 904 |
+ echo "" |
|
| 905 |
+ |
|
| 906 |
+ # Confirm removal |
|
| 907 |
+ read -p "Remove this configuration? (y/N): " confirm |
|
| 908 |
+ if [[ ! "$confirm" =~ ^[Yy]$ ]]; then |
|
| 909 |
+ echo "Removal cancelled." |
|
| 910 |
+ return 1 |
|
| 911 |
+ fi |
|
| 912 |
+ |
|
| 913 |
+ # Remove configuration |
|
| 914 |
+ local temp_file=$(mktemp) |
|
| 915 |
+ grep -v "^${uuid}:" "$CONFIG_FILE" > "$temp_file"
|
|
| 916 |
+ mv "$temp_file" "$CONFIG_FILE" |
|
| 917 |
+ |
|
| 918 |
+ echo "โ Configuration removed successfully!" |
|
| 919 |
+ return 0 |
|
| 920 |
+} |
|
| 921 |
+ |
|
| 922 |
+# Function to test disk configuration |
|
| 923 |
+test_config() {
|
|
| 924 |
+ local uuid="$1" |
|
| 925 |
+ |
|
| 926 |
+ if [[ -z "$uuid" ]]; then |
|
| 927 |
+ echo "Usage: autonas test <uuid>" |
|
| 928 |
+ return 1 |
|
| 929 |
+ fi |
|
| 930 |
+ |
|
| 931 |
+ echo "AutoNAS Configuration Test" |
|
| 932 |
+ echo "=========================" |
|
| 933 |
+ echo "" |
|
| 934 |
+ |
|
| 935 |
+ # Check if configuration exists |
|
| 936 |
+ local config |
|
| 937 |
+ config=$(get_disk_config "$uuid") |
|
| 938 |
+ |
|
| 939 |
+ if [[ -z "$config" ]]; then |
|
| 940 |
+ echo "โ Configuration not found for UUID: $uuid" |
|
| 941 |
+ echo "" |
|
| 942 |
+ echo "Available configurations:" |
|
| 943 |
+ list_disks |
|
| 944 |
+ return 1 |
|
| 945 |
+ fi |
|
| 946 |
+ |
|
| 947 |
+ echo "โ Configuration found for UUID: $uuid" |
|
| 948 |
+ |
|
| 949 |
+ # Parse configuration |
|
| 950 |
+ local parsed=($(parse_config "$config")) |
|
| 951 |
+ local cfg_uuid="${parsed[0]}"
|
|
| 952 |
+ local name="${parsed[1]}"
|
|
| 953 |
+ local ip="${parsed[2]}"
|
|
| 954 |
+ local interface="${parsed[3]}"
|
|
| 955 |
+ local mount_point="${parsed[4]}"
|
|
| 956 |
+ local nfs_options="${parsed[5]}"
|
|
| 957 |
+ |
|
| 958 |
+ echo " Name: $name" |
|
| 959 |
+ echo " Type: $ip:$interface" |
|
| 960 |
+ echo " Mount Point: $mount_point" |
|
| 961 |
+ echo "" |
|
| 962 |
+ |
|
| 963 |
+ # Test device detection |
|
| 964 |
+ echo "๐ Testing device detection..." |
|
| 965 |
+ local device_info |
|
| 966 |
+ if device_info=$(get_device_info "$uuid" 2>/dev/null); then |
|
| 967 |
+ local device=$(echo "$device_info" | grep "^device:" | cut -d: -f2) |
|
| 968 |
+ echo "โ Device found: $device" |
|
| 969 |
+ |
|
| 970 |
+ # Show device details |
|
| 971 |
+ echo "$device_info" | grep -v "^device:" | while IFS= read -r line; do |
|
| 972 |
+ echo " $line" |
|
| 973 |
+ done |
|
| 974 |
+ else |
|
| 975 |
+ echo "โ Device not found or not connected" |
|
| 976 |
+ echo " Make sure the device with UUID $uuid is connected" |
|
| 977 |
+ return 1 |
|
| 978 |
+ fi |
|
| 979 |
+ echo "" |
|
| 980 |
+ |
|
| 981 |
+ # Test network configuration (if applicable) |
|
| 982 |
+ if [[ "$ip" != "LOCAL" && "$ip" != "IMPORT" ]]; then |
|
| 983 |
+ echo "๐ Testing network configuration..." |
|
| 984 |
+ |
|
| 985 |
+ # Test interface |
|
| 986 |
+ if interface_exists "$interface"; then |
|
| 987 |
+ echo "โ Network interface exists: $interface" |
|
| 988 |
+ else |
|
| 989 |
+ echo "โ Network interface not found: $interface" |
|
| 990 |
+ echo " Available interfaces:" |
|
| 991 |
+ ip link show | grep "^[0-9]" | cut -d: -f2 | sed 's/^ *//' | grep -v "^lo$" | sed 's/^/ /' |
|
| 992 |
+ return 1 |
|
| 993 |
+ fi |
|
| 994 |
+ |
|
| 995 |
+ # Test IP configuration |
|
| 996 |
+ if is_ip_configured "$ip" "$interface"; then |
|
| 997 |
+ echo "โ IP already configured: $ip on $interface" |
|
| 998 |
+ else |
|
| 999 |
+ echo "โน๏ธ IP not currently configured: $ip on $interface" |
|
| 1000 |
+ echo " (This is normal - IP will be activated during attach)" |
|
| 1001 |
+ fi |
|
| 1002 |
+ echo "" |
|
| 1003 |
+ fi |
|
| 1004 |
+ |
|
| 1005 |
+ # Test mount point |
|
| 1006 |
+ echo "๐ Testing mount point..." |
|
| 1007 |
+ if [[ -d "$mount_point" ]]; then |
|
| 1008 |
+ if mountpoint -q "$mount_point" 2>/dev/null; then |
|
| 1009 |
+ echo "โ Mount point exists and is mounted: $mount_point" |
|
| 1010 |
+ local mounted_device=$(findmnt -n -o SOURCE "$mount_point") |
|
| 1011 |
+ echo " Mounted device: $mounted_device" |
|
| 1012 |
+ else |
|
| 1013 |
+ echo "โน๏ธ Mount point directory exists but not mounted: $mount_point" |
|
| 1014 |
+ fi |
|
| 1015 |
+ else |
|
| 1016 |
+ echo "โน๏ธ Mount point directory will be created: $mount_point" |
|
| 1017 |
+ fi |
|
| 1018 |
+ echo "" |
|
| 1019 |
+ |
|
| 1020 |
+ # Test import configuration (if applicable) |
|
| 1021 |
+ if [[ "$ip" == "IMPORT" && "$interface" == "IMPORT" ]]; then |
|
| 1022 |
+ echo "๐ท Testing camera import configuration..." |
|
| 1023 |
+ local destination="$nfs_options" |
|
| 1024 |
+ |
|
| 1025 |
+ if [[ -d "$destination" ]]; then |
|
| 1026 |
+ echo "โ Import destination exists: $destination" |
|
| 1027 |
+ if [[ -w "$destination" ]]; then |
|
| 1028 |
+ echo "โ Import destination is writable" |
|
| 1029 |
+ else |
|
| 1030 |
+ echo "โ ๏ธ Import destination is not writable" |
|
| 1031 |
+ echo " You may need to check permissions" |
|
| 1032 |
+ fi |
|
| 1033 |
+ else |
|
| 1034 |
+ echo "โน๏ธ Import destination will be created: $destination" |
|
| 1035 |
+ local parent_dir=$(dirname "$destination") |
|
| 1036 |
+ if [[ -d "$parent_dir" && -w "$parent_dir" ]]; then |
|
| 1037 |
+ echo "โ Parent directory exists and is writable" |
|
| 1038 |
+ else |
|
| 1039 |
+ echo "โ Cannot create import destination" |
|
| 1040 |
+ echo " Parent directory: $parent_dir" |
|
| 1041 |
+ return 1 |
|
| 1042 |
+ fi |
|
| 1043 |
+ fi |
|
| 1044 |
+ |
|
| 1045 |
+ # Test import script |
|
| 1046 |
+ if [[ -x "/usr/local/bin/autonas-media-importer.sh" ]]; then |
|
| 1047 |
+ echo "โ Media import script is available and executable" |
|
| 1048 |
+ else |
|
| 1049 |
+ echo "โ Media import script not found or not executable" |
|
| 1050 |
+ echo " Expected: /usr/local/bin/autonas-media-importer.sh" |
|
| 1051 |
+ return 1 |
|
| 1052 |
+ fi |
|
| 1053 |
+ echo "" |
|
| 1054 |
+ fi |
|
| 1055 |
+ |
|
| 1056 |
+ echo "๐ Configuration test completed successfully!" |
|
| 1057 |
+ echo "" |
|
| 1058 |
+ echo "You can now attach this disk with: autonas attach $uuid" |
|
| 1059 |
+ return 0 |
|
| 1060 |
+} |
|
| 1061 |
+ |
|
| 1062 |
+# Main configuration functions would go here... |
|
| 1063 |
+ |
|
| 1064 |
+# Main command dispatcher |
|
| 1065 |
+case "${1:-}" in
|
|
| 1066 |
+ "attach") |
|
| 1067 |
+ if [[ -z "$2" ]]; then |
|
| 1068 |
+ echo "Error: UUID required for attach command" |
|
| 1069 |
+ show_usage |
|
| 1070 |
+ exit 1 |
|
| 1071 |
+ fi |
|
| 1072 |
+ handle_attach "$2" |
|
| 1073 |
+ ;; |
|
| 1074 |
+ "detach") |
|
| 1075 |
+ if [[ -z "$2" ]]; then |
|
| 1076 |
+ echo "Error: UUID required for detach command" |
|
| 1077 |
+ show_usage |
|
| 1078 |
+ exit 1 |
|
| 1079 |
+ fi |
|
| 1080 |
+ handle_detach "$2" |
|
| 1081 |
+ ;; |
|
| 1082 |
+ "mount") |
|
| 1083 |
+ if [[ -z "$2" ]]; then |
|
| 1084 |
+ echo "Error: UUID or disk name required for mount command" |
|
| 1085 |
+ show_usage |
|
| 1086 |
+ exit 1 |
|
| 1087 |
+ fi |
|
| 1088 |
+ handle_manual_mount "$2" |
|
| 1089 |
+ ;; |
|
| 1090 |
+ "unmount"|"umount") |
|
| 1091 |
+ if [[ -z "$2" ]]; then |
|
| 1092 |
+ echo "Error: UUID or disk name required for unmount command" |
|
| 1093 |
+ show_usage |
|
| 1094 |
+ exit 1 |
|
| 1095 |
+ fi |
|
| 1096 |
+ handle_manual_unmount "$2" |
|
| 1097 |
+ ;; |
|
| 1098 |
+ "import") |
|
| 1099 |
+ # Internal use only - background import process |
|
| 1100 |
+ if [[ -z "$4" ]]; then |
|
| 1101 |
+ echo "Error: Missing arguments for import command" |
|
| 1102 |
+ exit 1 |
|
| 1103 |
+ fi |
|
| 1104 |
+ run_background_import "$2" "$3" "$4" "$5" |
|
| 1105 |
+ ;; |
|
| 1106 |
+ "reload") |
|
| 1107 |
+ handle_reload |
|
| 1108 |
+ ;; |
|
| 1109 |
+ "add") |
|
| 1110 |
+ add_disk "$2" |
|
| 1111 |
+ ;; |
|
| 1112 |
+ "remove") |
|
| 1113 |
+ if [[ -z "$2" ]]; then |
|
| 1114 |
+ echo "Error: UUID required for remove command" |
|
| 1115 |
+ show_usage |
|
| 1116 |
+ exit 1 |
|
| 1117 |
+ fi |
|
| 1118 |
+ remove_disk "$2" |
|
| 1119 |
+ ;; |
|
| 1120 |
+ "list") |
|
| 1121 |
+ list_disks |
|
| 1122 |
+ ;; |
|
| 1123 |
+ "test") |
|
| 1124 |
+ if [[ -z "$2" ]]; then |
|
| 1125 |
+ echo "Error: UUID required for test command" |
|
| 1126 |
+ show_usage |
|
| 1127 |
+ exit 1 |
|
| 1128 |
+ fi |
|
| 1129 |
+ test_config "$2" |
|
| 1130 |
+ ;; |
|
| 1131 |
+ "show") |
|
| 1132 |
+ show_available_disks |
|
| 1133 |
+ ;; |
|
| 1134 |
+ "status") |
|
| 1135 |
+ echo "=== AutoNAS System Status ===" |
|
| 1136 |
+ echo "Configuration file: $CONFIG_FILE" |
|
| 1137 |
+ if [[ -f "$CONFIG_FILE" ]]; then |
|
| 1138 |
+ count=$(grep -c "^[^#].*:.*:.*:" "$CONFIG_FILE" 2>/dev/null || echo "0") |
|
| 1139 |
+ echo "Configured disks: $count" |
|
| 1140 |
+ else |
|
| 1141 |
+ echo "Configured disks: 0 (no config file)" |
|
| 1142 |
+ fi |
|
| 1143 |
+ echo "NFS server: $(systemctl is-active nfs-kernel-server 2>/dev/null || echo "unknown")" |
|
| 1144 |
+ echo "AutoNAS service: $(systemctl is-active autonas 2>/dev/null || echo "unknown")" |
|
| 1145 |
+ echo "Boot scan service: $(systemctl is-active autonas-boot-scan 2>/dev/null || echo "unknown")" |
|
| 1146 |
+ echo "" |
|
| 1147 |
+ echo "Recent logs:" |
|
| 1148 |
+ journalctl -t autonas -n 5 --no-pager 2>/dev/null || echo "No recent logs found" |
|
| 1149 |
+ ;; |
|
| 1150 |
+ "debug") |
|
| 1151 |
+ case "${2:-}" in
|
|
| 1152 |
+ "enable") |
|
| 1153 |
+ if [ -f "/etc/default/autonas" ]; then |
|
| 1154 |
+ sed -i 's/AUTONAS_DEBUG="false"/AUTONAS_DEBUG="true"/' /etc/default/autonas |
|
| 1155 |
+ echo "โ Debug mode enabled - verbose logging is now active" |
|
| 1156 |
+ echo " All AutoNAS operations will produce detailed debug output" |
|
| 1157 |
+ else |
|
| 1158 |
+ echo "Error: Configuration file /etc/default/autonas not found" |
|
| 1159 |
+ exit 1 |
|
| 1160 |
+ fi |
|
| 1161 |
+ ;; |
|
| 1162 |
+ "disable") |
|
| 1163 |
+ if [ -f "/etc/default/autonas" ]; then |
|
| 1164 |
+ sed -i 's/AUTONAS_DEBUG="true"/AUTONAS_DEBUG="false"/' /etc/default/autonas |
|
| 1165 |
+ echo "โ Debug mode disabled - normal logging restored" |
|
| 1166 |
+ else |
|
| 1167 |
+ echo "Error: Configuration file /etc/default/autonas not found" |
|
| 1168 |
+ exit 1 |
|
| 1169 |
+ fi |
|
| 1170 |
+ ;; |
|
| 1171 |
+ "status") |
|
| 1172 |
+ if [ -f "/etc/default/autonas" ]; then |
|
| 1173 |
+ echo "=== AutoNAS Debug Configuration ===" |
|
| 1174 |
+ source /etc/default/autonas |
|
| 1175 |
+ echo "Debug mode: ${AUTONAS_DEBUG:-false}"
|
|
| 1176 |
+ echo "Log level: ${AUTONAS_LOG_LEVEL:-info}"
|
|
| 1177 |
+ if [ "$AUTONAS_DEBUG" = "true" ]; then |
|
| 1178 |
+ echo "Status: ๐ข Debug logging is ENABLED" |
|
| 1179 |
+ echo " - Verbose messages will appear in logs and stderr" |
|
| 1180 |
+ echo " - All operations will be traced in detail" |
|
| 1181 |
+ else |
|
| 1182 |
+ echo "Status: ๐ด Debug logging is DISABLED" |
|
| 1183 |
+ echo " - Only normal info/warning/error messages will appear" |
|
| 1184 |
+ fi |
|
| 1185 |
+ else |
|
| 1186 |
+ echo "Error: Configuration file /etc/default/autonas not found" |
|
| 1187 |
+ exit 1 |
|
| 1188 |
+ fi |
|
| 1189 |
+ ;; |
|
| 1190 |
+ "") |
|
| 1191 |
+ echo "Error: Debug command requires an argument" |
|
| 1192 |
+ echo "Usage: $0 debug {enable|disable|status}"
|
|
| 1193 |
+ exit 1 |
|
| 1194 |
+ ;; |
|
| 1195 |
+ *) |
|
| 1196 |
+ echo "Error: Unknown debug command '$2'" |
|
| 1197 |
+ echo "Usage: $0 debug {enable|disable|status}"
|
|
| 1198 |
+ exit 1 |
|
| 1199 |
+ ;; |
|
| 1200 |
+ esac |
|
| 1201 |
+ ;; |
|
| 1202 |
+ "help"|"-h"|"--help"|"") |
|
| 1203 |
+ show_usage |
|
| 1204 |
+ ;; |
|
| 1205 |
+ *) |
|
| 1206 |
+ echo "Error: Unknown command '$1'" |
|
| 1207 |
+ echo |
|
| 1208 |
+ show_usage |
|
| 1209 |
+ exit 1 |
|
| 1210 |
+ ;; |
|
| 1211 |
+esac |
|
@@ -0,0 +1,385 @@ |
||
| 1 |
+#!/bin/bash |
|
| 2 |
+ |
|
| 3 |
+# AutoNAS Installation & Node Admin Script |
|
| 4 |
+# Executed on target nodes; deploy.sh invokes this with subcommands. |
|
| 5 |
+# Usage: install.sh [install|start|restart|stop|status] |
|
| 6 |
+ |
|
| 7 |
+set -e # Exit on any error |
|
| 8 |
+ |
|
| 9 |
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
| 10 |
+PROJECT_DIR="$(dirname "$SCRIPT_DIR")" |
|
| 11 |
+CONFIG_DIR="/etc/pve/autonas" |
|
| 12 |
+ |
|
| 13 |
+# Script names |
|
| 14 |
+UNIFIED_SCRIPT="autonas.sh" |
|
| 15 |
+SCRIPT_NAME="autonas-disk-handler.sh" |
|
| 16 |
+WRAPPER_NAME="autonas-udev-wrapper.sh" |
|
| 17 |
+BOOT_SCAN_SCRIPT="autonas-boot-scan.sh" |
|
| 18 |
+INTERFACE_HANDLER_SCRIPT="autonas-network-handler.sh" |
|
| 19 |
+CAMERA_IMPORT_SCRIPT="autonas-media-importer.sh" |
|
| 20 |
+UDEV_RULES="99-autonas-disk.rules" |
|
| 21 |
+INTERFACE_RULES="98-autonas-interfaces.rules" |
|
| 22 |
+SYSTEMD_SERVICE="autonas-attach@.service" |
|
| 23 |
+MAIN_SERVICE="autonas.service" |
|
| 24 |
+BOOT_SCAN_SERVICE="autonas-boot-scan.service" |
|
| 25 |
+ |
|
| 26 |
+require_root() {
|
|
| 27 |
+ if [ "$EUID" -ne 0 ]; then |
|
| 28 |
+ echo "โ This action must be run as root (use sudo)" >&2 |
|
| 29 |
+ exit 1 |
|
| 30 |
+ fi |
|
| 31 |
+} |
|
| 32 |
+ |
|
| 33 |
+# Verificฤ dacฤ un pachet este instalat |
|
| 34 |
+is_package_installed() {
|
|
| 35 |
+ local package="$1" |
|
| 36 |
+ dpkg -l "$package" 2>/dev/null | grep -q "^ii" |
|
| 37 |
+} |
|
| 38 |
+ |
|
| 39 |
+# Verificฤ dependinศele necesare |
|
| 40 |
+check_dependencies() {
|
|
| 41 |
+ local missing_packages=() |
|
| 42 |
+ local required_packages=("nfs-kernel-server" "autofs" "udev" "libimage-exiftool-perl")
|
|
| 43 |
+ |
|
| 44 |
+ echo "๐ Verificare dependinศe AutoNAS..." |
|
| 45 |
+ |
|
| 46 |
+ for package in "${required_packages[@]}"; do
|
|
| 47 |
+ if is_package_installed "$package"; then |
|
| 48 |
+ echo "โ $package - instalat" |
|
| 49 |
+ else |
|
| 50 |
+ echo "โ $package - LIPSฤ" |
|
| 51 |
+ missing_packages+=("$package")
|
|
| 52 |
+ fi |
|
| 53 |
+ done |
|
| 54 |
+ |
|
| 55 |
+ if [ ${#missing_packages[@]} -gt 0 ]; then
|
|
| 56 |
+ echo "" |
|
| 57 |
+ echo "โ ๏ธ DEPENDINศE LIPSฤ DETECTATE:" |
|
| 58 |
+ printf " %s\n" "${missing_packages[@]}"
|
|
| 59 |
+ echo "" |
|
| 60 |
+ echo "Pentru a instala dependinศele lipsฤ, rulaศi:" |
|
| 61 |
+ echo " apt update && apt install -y ${missing_packages[*]}"
|
|
| 62 |
+ echo "" |
|
| 63 |
+ echo "Sau utilizaศi comanda 'install-deps' pentru instalare automatฤ:" |
|
| 64 |
+ echo " $0 install-deps" |
|
| 65 |
+ echo "" |
|
| 66 |
+ return 1 |
|
| 67 |
+ else |
|
| 68 |
+ echo "โ Toate dependinศele sunt instalate" |
|
| 69 |
+ return 0 |
|
| 70 |
+ fi |
|
| 71 |
+} |
|
| 72 |
+ |
|
| 73 |
+# Instaleazฤ doar dependinศele lipsฤ |
|
| 74 |
+install_dependencies() {
|
|
| 75 |
+ require_root |
|
| 76 |
+ echo "๐ฆ Instalare dependinศe AutoNAS..." |
|
| 77 |
+ |
|
| 78 |
+ if ! command -v apt >/dev/null 2>&1; then |
|
| 79 |
+ echo "โ Sistemul nu foloseศte apt - instalarea automatฤ nu este suportatฤ" |
|
| 80 |
+ echo "Instalaศi manual pachetele: nfs-kernel-server autofs udev libimage-exiftool-perl" |
|
| 81 |
+ exit 1 |
|
| 82 |
+ fi |
|
| 83 |
+ |
|
| 84 |
+ echo "Actualizare lista de pachete..." |
|
| 85 |
+ if ! apt update; then |
|
| 86 |
+ echo "โ Nu s-a putut actualiza lista de pachete - verificaศi conectivitatea la internet" |
|
| 87 |
+ exit 1 |
|
| 88 |
+ fi |
|
| 89 |
+ |
|
| 90 |
+ echo "Instalare pachete necesare..." |
|
| 91 |
+ if apt install -y nfs-kernel-server autofs udev libimage-exiftool-perl; then |
|
| 92 |
+ echo "โ Dependinศele au fost instalate cu succes" |
|
| 93 |
+ else |
|
| 94 |
+ echo "โ Eroare la instalarea dependinศelor" |
|
| 95 |
+ exit 1 |
|
| 96 |
+ fi |
|
| 97 |
+} |
|
| 98 |
+ |
|
| 99 |
+do_start() {
|
|
| 100 |
+ require_root |
|
| 101 |
+ echo "Starting AutoNAS services..." |
|
| 102 |
+ systemctl enable nfs-kernel-server >/dev/null 2>&1 || true |
|
| 103 |
+ systemctl start nfs-kernel-server || true |
|
| 104 |
+ udevadm control --reload-rules || true |
|
| 105 |
+ udevadm trigger --subsystem-match=block --action=add || true |
|
| 106 |
+ echo "โ Start complete" |
|
| 107 |
+} |
|
| 108 |
+ |
|
| 109 |
+do_restart() {
|
|
| 110 |
+ require_root |
|
| 111 |
+ echo "Restarting AutoNAS services..." |
|
| 112 |
+ systemctl restart nfs-kernel-server || true |
|
| 113 |
+ udevadm control --reload-rules || true |
|
| 114 |
+ udevadm trigger --subsystem-match=block --action=add || true |
|
| 115 |
+ echo "โ Restart complete" |
|
| 116 |
+} |
|
| 117 |
+ |
|
| 118 |
+do_stop() {
|
|
| 119 |
+ require_root |
|
| 120 |
+ echo "Stopping AutoNAS services..." |
|
| 121 |
+ systemctl stop nfs-kernel-server || true |
|
| 122 |
+ echo "โ Stop complete" |
|
| 123 |
+} |
|
| 124 |
+ |
|
| 125 |
+do_status() {
|
|
| 126 |
+ echo "=== Status Servicii ===" |
|
| 127 |
+ systemctl status nfs-kernel-server --no-pager -l || true |
|
| 128 |
+ echo "" |
|
| 129 |
+ echo "=== Exports NFS ===" |
|
| 130 |
+ cat /etc/exports 2>/dev/null || echo "Fiศier /etc/exports nu existฤ" |
|
| 131 |
+ echo "" |
|
| 132 |
+ echo "=== Mount Points AutoNAS ===" |
|
| 133 |
+ ls -la /mnt/autonas/ 2>/dev/null || echo "Director /mnt/autonas nu existฤ" |
|
| 134 |
+ echo "" |
|
| 135 |
+ echo "=== Configuraศie Diskuri ===" |
|
| 136 |
+ cat "$CONFIG_DIR/disks.conf" 2>/dev/null || echo "Fiศier configuraศie nu existฤ" |
|
| 137 |
+ echo "" |
|
| 138 |
+ echo "=== Procese AutoNAS ===" |
|
| 139 |
+ ps aux | grep autonas | grep -v grep || true |
|
| 140 |
+} |
|
| 141 |
+ |
|
| 142 |
+do_install() {
|
|
| 143 |
+ require_root |
|
| 144 |
+ echo "=== AutoNAS Installation Script ===" |
|
| 145 |
+ echo "" |
|
| 146 |
+ |
|
| 147 |
+ # Verificฤ dependinศele mai รฎntรขi |
|
| 148 |
+ if ! check_dependencies; then |
|
| 149 |
+ echo "โ Instalarea nu poate continua - dependinศe lipsฤ" |
|
| 150 |
+ echo "Rulaศi mai รฎntรขi: $0 install-deps" |
|
| 151 |
+ exit 1 |
|
| 152 |
+ fi |
|
| 153 |
+ |
|
| 154 |
+ echo "" |
|
| 155 |
+ echo "Installing AutoNAS..." |
|
| 156 |
+ |
|
| 157 |
+ echo "๐งน Cleanup previous installation to prevent orphan files..." |
|
| 158 |
+ if [ -f "/usr/local/lib/autonas/autonas-uninstall.sh" ]; then |
|
| 159 |
+ echo "Previous AutoNAS installation detected. Running uninstall first..." |
|
| 160 |
+ bash /usr/local/lib/autonas/autonas-uninstall.sh --force >/dev/null 2>&1 || true |
|
| 161 |
+ echo "Previous installation cleaned up." |
|
| 162 |
+ fi |
|
| 163 |
+ |
|
| 164 |
+ echo "๐ Creating directories..." |
|
| 165 |
+ mkdir -p "$CONFIG_DIR" |
|
| 166 |
+ mkdir -p "/mnt/autonas" |
|
| 167 |
+ echo "โ Directories created" |
|
| 168 |
+ |
|
| 169 |
+ echo "Installing AutoNAS scripts..." |
|
| 170 |
+ mkdir -p "/usr/local/lib/autonas" |
|
| 171 |
+ |
|
| 172 |
+ if [ -f "$SCRIPT_DIR/$UNIFIED_SCRIPT" ]; then |
|
| 173 |
+ cp "$SCRIPT_DIR/$UNIFIED_SCRIPT" "/usr/local/bin/" |
|
| 174 |
+ chmod +x "/usr/local/bin/$UNIFIED_SCRIPT" |
|
| 175 |
+ echo "โ Unified AutoNAS script installed" |
|
| 176 |
+ ln -sf "/usr/local/bin/$UNIFIED_SCRIPT" "/usr/local/bin/autonas" |
|
| 177 |
+ echo "โ Created 'autonas' command symlink" |
|
| 178 |
+ fi |
|
| 179 |
+ |
|
| 180 |
+ if [ -f "$SCRIPT_DIR/autonas-core.sh" ]; then |
|
| 181 |
+ cp "$SCRIPT_DIR/autonas-core.sh" "/usr/local/bin/" |
|
| 182 |
+ chmod +x "/usr/local/bin/autonas-core.sh" |
|
| 183 |
+ echo "โ Core library installed" |
|
| 184 |
+ fi |
|
| 185 |
+ |
|
| 186 |
+ cp "$SCRIPT_DIR/$SCRIPT_NAME" "/usr/local/bin/" |
|
| 187 |
+ chmod +x "/usr/local/bin/$SCRIPT_NAME" |
|
| 188 |
+ echo "โ autonas-disk-handler.sh installed" |
|
| 189 |
+ |
|
| 190 |
+ cp "$SCRIPT_DIR/$WRAPPER_NAME" "/usr/local/bin/" |
|
| 191 |
+ chmod +x "/usr/local/bin/$WRAPPER_NAME" |
|
| 192 |
+ echo "โ autonas-udev-wrapper.sh installed" |
|
| 193 |
+ |
|
| 194 |
+ if [ -f "$SCRIPT_DIR/$BOOT_SCAN_SCRIPT" ]; then |
|
| 195 |
+ cp "$SCRIPT_DIR/$BOOT_SCAN_SCRIPT" "/usr/local/bin/" |
|
| 196 |
+ chmod +x "/usr/local/bin/$BOOT_SCAN_SCRIPT" |
|
| 197 |
+ echo "โ Boot scan script installed" |
|
| 198 |
+ fi |
|
| 199 |
+ |
|
| 200 |
+ if [ -f "$SCRIPT_DIR/$INTERFACE_HANDLER_SCRIPT" ]; then |
|
| 201 |
+ cp "$SCRIPT_DIR/$INTERFACE_HANDLER_SCRIPT" "/usr/local/bin/" |
|
| 202 |
+ chmod +x "/usr/local/bin/$INTERFACE_HANDLER_SCRIPT" |
|
| 203 |
+ echo "โ Interface handler script installed" |
|
| 204 |
+ fi |
|
| 205 |
+ |
|
| 206 |
+ if [ -f "$SCRIPT_DIR/$CAMERA_IMPORT_SCRIPT" ]; then |
|
| 207 |
+ cp "$SCRIPT_DIR/$CAMERA_IMPORT_SCRIPT" "/usr/local/bin/" |
|
| 208 |
+ chmod +x "/usr/local/bin/$CAMERA_IMPORT_SCRIPT" |
|
| 209 |
+ echo "โ Camera import script installed" |
|
| 210 |
+ fi |
|
| 211 |
+ |
|
| 212 |
+ echo "Installing udev rules..." |
|
| 213 |
+ cp "$PROJECT_DIR/config/$UDEV_RULES" "/etc/udev/rules.d/" |
|
| 214 |
+ if [ -f "$PROJECT_DIR/config/$INTERFACE_RULES" ]; then |
|
| 215 |
+ cp "$PROJECT_DIR/config/$INTERFACE_RULES" "/etc/udev/rules.d/" |
|
| 216 |
+ echo "โ Interface monitoring udev rules installed" |
|
| 217 |
+ fi |
|
| 218 |
+ udevadm control --reload-rules |
|
| 219 |
+ echo "โ Udev rules installed" |
|
| 220 |
+ |
|
| 221 |
+ echo "Installing systemd services..." |
|
| 222 |
+ cp "$PROJECT_DIR/config/$SYSTEMD_SERVICE" "/etc/systemd/system/" |
|
| 223 |
+ systemctl daemon-reload |
|
| 224 |
+ echo "โ Systemd service installed" |
|
| 225 |
+ |
|
| 226 |
+ echo "Installing main AutoNAS service..." |
|
| 227 |
+ cp "$PROJECT_DIR/config/$MAIN_SERVICE" "/etc/systemd/system/" |
|
| 228 |
+ systemctl daemon-reload |
|
| 229 |
+ systemctl enable autonas.service |
|
| 230 |
+ echo "โ Main AutoNAS service installed and enabled" |
|
| 231 |
+ |
|
| 232 |
+ echo "Installing boot scan service..." |
|
| 233 |
+ cp "$PROJECT_DIR/config/$BOOT_SCAN_SERVICE" "/etc/systemd/system/" |
|
| 234 |
+ systemctl daemon-reload |
|
| 235 |
+ systemctl enable autonas-boot-scan.service |
|
| 236 |
+ echo "โ Boot scan service installed and enabled" |
|
| 237 |
+ |
|
| 238 |
+ echo "Setting up configuration..." |
|
| 239 |
+ if [ ! -f "$CONFIG_DIR/disks.conf" ]; then |
|
| 240 |
+ cp "$PROJECT_DIR/config/disks.conf" "$CONFIG_DIR/" |
|
| 241 |
+ echo "โ Configuration template installed" |
|
| 242 |
+ else |
|
| 243 |
+ echo "โ ๏ธ Configuration file already exists, preserving user settings" |
|
| 244 |
+ echo " Existing file: $CONFIG_DIR/disks.conf" |
|
| 245 |
+ echo " Template available at: $PROJECT_DIR/config/disks.conf" |
|
| 246 |
+ if grep -v '^#' "$CONFIG_DIR/disks.conf" | grep -v '^$' | grep -q ':'; then |
|
| 247 |
+ echo "โ User configurations detected in existing file - preserving" |
|
| 248 |
+ else |
|
| 249 |
+ echo "โน๏ธ Existing file appears to be template only" |
|
| 250 |
+ fi |
|
| 251 |
+ fi |
|
| 252 |
+ |
|
| 253 |
+ echo "Starting services..." |
|
| 254 |
+ systemctl enable nfs-kernel-server |
|
| 255 |
+ systemctl start nfs-kernel-server |
|
| 256 |
+ if [ ! -f /etc/exports ]; then |
|
| 257 |
+ touch /etc/exports |
|
| 258 |
+ fi |
|
| 259 |
+ |
|
| 260 |
+ echo "๐ Setting permissions..." |
|
| 261 |
+ if [ -f "/usr/local/bin/$UNIFIED_SCRIPT" ]; then |
|
| 262 |
+ chown root:root "/usr/local/bin/$UNIFIED_SCRIPT" |
|
| 263 |
+ chmod 755 "/usr/local/bin/$UNIFIED_SCRIPT" |
|
| 264 |
+ fi |
|
| 265 |
+ chown root:root "/usr/local/bin/$SCRIPT_NAME" |
|
| 266 |
+ chown root:root "/usr/local/bin/$WRAPPER_NAME" |
|
| 267 |
+ if [ -f "/usr/local/bin/$CONFIG_SCRIPT" ]; then |
|
| 268 |
+ chown root:root "/usr/local/bin/$CONFIG_SCRIPT" |
|
| 269 |
+ fi |
|
| 270 |
+ if [ -f "/usr/local/bin/$BOOT_SCAN_SCRIPT" ]; then |
|
| 271 |
+ chown root:root "/usr/local/bin/$BOOT_SCAN_SCRIPT" |
|
| 272 |
+ fi |
|
| 273 |
+ if [ -f "/usr/local/bin/$INTERFACE_MONITOR_SCRIPT" ]; then |
|
| 274 |
+ chown root:root "/usr/local/bin/$INTERFACE_MONITOR_SCRIPT" |
|
| 275 |
+ fi |
|
| 276 |
+ if [ -f "/usr/local/bin/$INTERFACE_HANDLER_SCRIPT" ]; then |
|
| 277 |
+ chown root:root "/usr/local/bin/$INTERFACE_HANDLER_SCRIPT" |
|
| 278 |
+ fi |
|
| 279 |
+ chmod 755 "/usr/local/bin/$SCRIPT_NAME" |
|
| 280 |
+ chmod 755 "/usr/local/bin/$WRAPPER_NAME" |
|
| 281 |
+ if [ -f "/usr/local/bin/$UNIFIED_SCRIPT" ]; then |
|
| 282 |
+ chmod 755 "/usr/local/bin/$UNIFIED_SCRIPT" |
|
| 283 |
+ fi |
|
| 284 |
+ if [ -f "/usr/local/bin/$CONFIG_SCRIPT" ]; then |
|
| 285 |
+ chmod 755 "/usr/local/bin/$CONFIG_SCRIPT" |
|
| 286 |
+ fi |
|
| 287 |
+ if [ -f "/usr/local/bin/$BOOT_SCAN_SCRIPT" ]; then |
|
| 288 |
+ chmod 755 "/usr/local/bin/$BOOT_SCAN_SCRIPT" |
|
| 289 |
+ fi |
|
| 290 |
+ if [ -f "/usr/local/bin/$INTERFACE_MONITOR_SCRIPT" ]; then |
|
| 291 |
+ chmod 755 "/usr/local/bin/$INTERFACE_MONITOR_SCRIPT" |
|
| 292 |
+ fi |
|
| 293 |
+ if [ -f "/usr/local/bin/$INTERFACE_HANDLER_SCRIPT" ]; then |
|
| 294 |
+ chmod 755 "/usr/local/bin/$INTERFACE_HANDLER_SCRIPT" |
|
| 295 |
+ fi |
|
| 296 |
+ echo "โ Permissions set" |
|
| 297 |
+ |
|
| 298 |
+ echo "๐ Verifying installation..." |
|
| 299 |
+ [ -f "/usr/local/bin/$SCRIPT_NAME" ] && echo "โ Manager script: /usr/local/bin/$SCRIPT_NAME" |
|
| 300 |
+ [ -f "/usr/local/bin/$WRAPPER_NAME" ] && echo "โ Wrapper script: /usr/local/bin/$WRAPPER_NAME" |
|
| 301 |
+ [ -f "/usr/local/bin/$UNIFIED_SCRIPT" ] && echo "โ Unified script: /usr/local/bin/$UNIFIED_SCRIPT" |
|
| 302 |
+ [ -f "/usr/local/bin/$CONFIG_SCRIPT" ] && echo "โ Configuration script: /usr/local/bin/$CONFIG_SCRIPT" |
|
| 303 |
+ [ -f "/usr/local/bin/$BOOT_SCAN_SCRIPT" ] && echo "โ Boot scan script: /usr/local/bin/$BOOT_SCAN_SCRIPT" |
|
| 304 |
+ [ -f "/etc/udev/rules.d/$UDEV_RULES" ] && echo "โ Udev rules: /etc/udev/rules.d/$UDEV_RULES" |
|
| 305 |
+ [ -f "/etc/systemd/system/$SYSTEMD_SERVICE" ] && echo "โ Systemd service: /etc/systemd/system/$SYSTEMD_SERVICE" |
|
| 306 |
+ [ -f "/etc/systemd/system/$MAIN_SERVICE" ] && echo "โ Main AutoNAS service: /etc/systemd/system/$MAIN_SERVICE" |
|
| 307 |
+ [ -f "/etc/systemd/system/$BOOT_SCAN_SERVICE" ] && echo "โ Boot scan service: /etc/systemd/system/$BOOT_SCAN_SERVICE" |
|
| 308 |
+ [ -f "$CONFIG_DIR/disks.conf" ] && echo "โ Configuration file: $CONFIG_DIR/disks.conf" |
|
| 309 |
+ |
|
| 310 |
+ echo "Installing uninstall script for future upgrades..." |
|
| 311 |
+ if [ -f "$SCRIPT_DIR/autonas-uninstall.sh" ]; then |
|
| 312 |
+ cp "$SCRIPT_DIR/autonas-uninstall.sh" "/usr/local/lib/autonas/autonas-uninstall.sh" |
|
| 313 |
+ chmod +x "/usr/local/lib/autonas/autonas-uninstall.sh" |
|
| 314 |
+ chown root:root "/usr/local/lib/autonas/autonas-uninstall.sh" |
|
| 315 |
+ echo "โ Uninstall script: /usr/local/lib/autonas/autonas-uninstall.sh" |
|
| 316 |
+ else |
|
| 317 |
+ echo "โ ๏ธ Uninstall script not found - manual cleanup may be required for future reinstalls" |
|
| 318 |
+ fi |
|
| 319 |
+ |
|
| 320 |
+ echo "" |
|
| 321 |
+ echo "๐ AutoNAS installation completed successfully!" |
|
| 322 |
+ echo "" |
|
| 323 |
+ echo "๐ Starting services..." |
|
| 324 |
+ if [ -n "${INTERFACE_MONITOR_SCRIPT:-}" ] && [ -f "/usr/local/bin/$INTERFACE_MONITOR_SCRIPT" ]; then
|
|
| 325 |
+ echo "๐ Running initial interface IP restore..." |
|
| 326 |
+ "/usr/local/bin/$INTERFACE_MONITOR_SCRIPT" restore || true |
|
| 327 |
+ echo "โ Initial interface restore completed" |
|
| 328 |
+ fi |
|
| 329 |
+ |
|
| 330 |
+ echo "" |
|
| 331 |
+ echo "๐ Next steps:" |
|
| 332 |
+ echo "1. Connect your external disks to test auto-detection" |
|
| 333 |
+ echo "2. Use 'autonas add <UUID>' to configure detected disks" |
|
| 334 |
+ echo "3. Monitor with: journalctl -t autonas -t autonas-wrapper -f" |
|
| 335 |
+ echo "" |
|
| 336 |
+ echo "๐ง Configuration commands:" |
|
| 337 |
+ echo " autonas add [UUID] - Add new disk configuration" |
|
| 338 |
+ echo " autonas list - List configured disks" |
|
| 339 |
+ echo " autonas test [UUID] - Test disk configuration" |
|
| 340 |
+ echo " autonas remove - Remove disk configuration" |
|
| 341 |
+ echo "" |
|
| 342 |
+ echo "๐ Example disk configuration:" |
|
| 343 |
+ echo "12345678-1234-1234-1234-123456789abc:storage1:192.168.1.100:eth0:/mnt/autonas/storage1:*(rw,all_squash,insecure,async,no_subtree_check,anonuid=0,anongid=0)" |
|
| 344 |
+ echo "" |
|
| 345 |
+ echo "โ AutoNAS is ready to use!" |
|
| 346 |
+ echo "๐ Interface monitoring is handled automatically by udev events" |
|
| 347 |
+} |
|
| 348 |
+ |
|
| 349 |
+cmd="${1:-install}"
|
|
| 350 |
+case "$cmd" in |
|
| 351 |
+ install) |
|
| 352 |
+ do_install |
|
| 353 |
+ ;; |
|
| 354 |
+ install-deps) |
|
| 355 |
+ install_dependencies |
|
| 356 |
+ ;; |
|
| 357 |
+ check-deps) |
|
| 358 |
+ check_dependencies |
|
| 359 |
+ ;; |
|
| 360 |
+ start) |
|
| 361 |
+ do_start |
|
| 362 |
+ ;; |
|
| 363 |
+ restart) |
|
| 364 |
+ do_restart |
|
| 365 |
+ ;; |
|
| 366 |
+ stop) |
|
| 367 |
+ do_stop |
|
| 368 |
+ ;; |
|
| 369 |
+ status) |
|
| 370 |
+ do_status |
|
| 371 |
+ ;; |
|
| 372 |
+ *) |
|
| 373 |
+ echo "Usage: $0 [install|install-deps|check-deps|start|restart|stop|status]" >&2 |
|
| 374 |
+ echo "" |
|
| 375 |
+ echo "Commands:" |
|
| 376 |
+ echo " install - Install AutoNAS (requires dependencies)" |
|
| 377 |
+ echo " install-deps- Install only the required dependencies" |
|
| 378 |
+ echo " check-deps - Check if dependencies are installed" |
|
| 379 |
+ echo " start - Start AutoNAS services" |
|
| 380 |
+ echo " restart - Restart AutoNAS services" |
|
| 381 |
+ echo " stop - Stop AutoNAS services" |
|
| 382 |
+ echo " status - Show AutoNAS status" |
|
| 383 |
+ exit 2 |
|
| 384 |
+ ;; |
|
| 385 |
+esac |
|
@@ -0,0 +1,231 @@ |
||
| 1 |
+#!/bin/bash |
|
| 2 |
+ |
|
| 3 |
+# AutoNAS Uninstall Script |
|
| 4 |
+# This script is installed on each cluster node for version-specific removal |
|
| 5 |
+# Executed by deploy.sh or can be run directly on node: /usr/local/lib/autonas/autonas-uninstall.sh |
|
| 6 |
+ |
|
| 7 |
+# Global configuration |
|
| 8 |
+LOG_TAG="autonas-uninstall" |
|
| 9 |
+ |
|
| 10 |
+set -e # Exit on any error |
|
| 11 |
+ |
|
| 12 |
+# Check for force flag for silent cleanup |
|
| 13 |
+FORCE_MODE=false |
|
| 14 |
+if [ "$1" = "--force" ]; then |
|
| 15 |
+ FORCE_MODE=true |
|
| 16 |
+fi |
|
| 17 |
+ |
|
| 18 |
+# Helper function for conditional logging |
|
| 19 |
+log_message() {
|
|
| 20 |
+ if [ "$FORCE_MODE" = false ]; then |
|
| 21 |
+ echo "$1" |
|
| 22 |
+ fi |
|
| 23 |
+} |
|
| 24 |
+ |
|
| 25 |
+CONFIG_DIR="/etc/pve/autonas" |
|
| 26 |
+SCRIPT_NAME="autonas-disk-handler.sh" |
|
| 27 |
+WRAPPER_NAME="autonas-udev-wrapper.sh" |
|
| 28 |
+CONFIG_SCRIPT="autonas-config.sh" |
|
| 29 |
+BOOT_SCAN_SCRIPT="autonas-boot-scan.sh" |
|
| 30 |
+CAMERA_IMPORT_SCRIPT="autonas-media-importer.sh" |
|
| 31 |
+INTERFACE_HANDLER_SCRIPT="autonas-interface-handler.sh" |
|
| 32 |
+UNIFIED_SCRIPT="autonas.sh" |
|
| 33 |
+UDEV_RULES="99-autonas-disk.rules" |
|
| 34 |
+SYSTEMD_SERVICE="autonas-attach@.service" |
|
| 35 |
+MAIN_SERVICE="autonas.service" |
|
| 36 |
+BOOT_SCAN_SERVICE="autonas-boot-scan.service" |
|
| 37 |
+ |
|
| 38 |
+if [ "$FORCE_MODE" = false ]; then |
|
| 39 |
+ echo "=== AutoNAS Uninstall Script ===" |
|
| 40 |
+ echo "" |
|
| 41 |
+fi |
|
| 42 |
+ |
|
| 43 |
+# Check if running as root |
|
| 44 |
+if [ "$EUID" -ne 0 ]; then |
|
| 45 |
+ if [ "$FORCE_MODE" = false ]; then |
|
| 46 |
+ echo "โ This script must be run as root (use sudo)" |
|
| 47 |
+ fi |
|
| 48 |
+ exit 1 |
|
| 49 |
+fi |
|
| 50 |
+ |
|
| 51 |
+log_message "๐๏ธ Uninstalling AutoNAS..." |
|
| 52 |
+log_message "" |
|
| 53 |
+ |
|
| 54 |
+# Remove scripts |
|
| 55 |
+log_message "Removing AutoNAS scripts..." |
|
| 56 |
+if [ -f "/usr/local/bin/$SCRIPT_NAME" ]; then |
|
| 57 |
+ rm "/usr/local/bin/$SCRIPT_NAME" |
|
| 58 |
+ log_message "โ Manager script removed" |
|
| 59 |
+fi |
|
| 60 |
+ |
|
| 61 |
+if [ -f "/usr/local/bin/$WRAPPER_NAME" ]; then |
|
| 62 |
+ rm "/usr/local/bin/$WRAPPER_NAME" |
|
| 63 |
+ log_message "โ Wrapper script removed" |
|
| 64 |
+fi |
|
| 65 |
+ |
|
| 66 |
+if [ -f "/usr/local/bin/$CONFIG_SCRIPT" ]; then |
|
| 67 |
+ rm "/usr/local/bin/$CONFIG_SCRIPT" |
|
| 68 |
+ log_message "โ Configuration script removed" |
|
| 69 |
+fi |
|
| 70 |
+ |
|
| 71 |
+if [ -f "/usr/local/bin/$BOOT_SCAN_SCRIPT" ]; then |
|
| 72 |
+ rm "/usr/local/bin/$BOOT_SCAN_SCRIPT" |
|
| 73 |
+ log_message "โ Boot scan script removed" |
|
| 74 |
+fi |
|
| 75 |
+ |
|
| 76 |
+if [ -f "/usr/local/bin/$CAMERA_IMPORT_SCRIPT" ]; then |
|
| 77 |
+ rm "/usr/local/bin/$CAMERA_IMPORT_SCRIPT" |
|
| 78 |
+ log_message "โ Camera import script removed" |
|
| 79 |
+fi |
|
| 80 |
+ |
|
| 81 |
+if [ -f "/usr/local/bin/$INTERFACE_HANDLER_SCRIPT" ]; then |
|
| 82 |
+ rm "/usr/local/bin/$INTERFACE_HANDLER_SCRIPT" |
|
| 83 |
+ log_message "โ Interface handler script removed" |
|
| 84 |
+fi |
|
| 85 |
+ |
|
| 86 |
+if [ -f "/usr/local/bin/$UNIFIED_SCRIPT" ]; then |
|
| 87 |
+ rm "/usr/local/bin/$UNIFIED_SCRIPT" |
|
| 88 |
+ log_message "โ Unified AutoNAS script removed" |
|
| 89 |
+fi |
|
| 90 |
+ |
|
| 91 |
+# Remove symlink |
|
| 92 |
+if [ -L "/usr/local/bin/autonas" ]; then |
|
| 93 |
+ rm "/usr/local/bin/autonas" |
|
| 94 |
+ log_message "โ AutoNAS symlink removed" |
|
| 95 |
+fi |
|
| 96 |
+ |
|
| 97 |
+# Remove internal scripts directory |
|
| 98 |
+if [ -d "/usr/local/lib/autonas" ]; then |
|
| 99 |
+ rm -rf "/usr/local/lib/autonas" |
|
| 100 |
+ log_message "โ AutoNAS internal scripts directory removed" |
|
| 101 |
+fi |
|
| 102 |
+ |
|
| 103 |
+# Aggressive cleanup for orphaned files from previous versions |
|
| 104 |
+log_message "Cleaning up orphaned files from previous versions..." |
|
| 105 |
+for orphan_file in "autonas-interface-debug.sh" "autonas-test-interface-stability.sh"; do |
|
| 106 |
+ if [ -f "/usr/local/bin/$orphan_file" ]; then |
|
| 107 |
+ rm "/usr/local/bin/$orphan_file" |
|
| 108 |
+ log_message "โ Orphaned file removed: $orphan_file" |
|
| 109 |
+ fi |
|
| 110 |
+done |
|
| 111 |
+ |
|
| 112 |
+# Remove udev rules |
|
| 113 |
+log_message "Removing udev rules..." |
|
| 114 |
+if [ -f "/etc/udev/rules.d/$UDEV_RULES" ]; then |
|
| 115 |
+ rm "/etc/udev/rules.d/$UDEV_RULES" |
|
| 116 |
+ udevadm control --reload-rules |
|
| 117 |
+ log_message "โ Udev rules removed" |
|
| 118 |
+fi |
|
| 119 |
+ |
|
| 120 |
+# Remove systemd service |
|
| 121 |
+log_message "Removing systemd service..." |
|
| 122 |
+if [ -f "/etc/systemd/system/$SYSTEMD_SERVICE" ]; then |
|
| 123 |
+ systemctl stop autonas-attach@*.service 2>/dev/null || true |
|
| 124 |
+ systemctl disable autonas-attach@*.service 2>/dev/null || true |
|
| 125 |
+ rm "/etc/systemd/system/$SYSTEMD_SERVICE" |
|
| 126 |
+ systemctl daemon-reload |
|
| 127 |
+ log_message "โ Systemd service removed" |
|
| 128 |
+fi |
|
| 129 |
+ |
|
| 130 |
+# Remove main service |
|
| 131 |
+log_message "Removing main AutoNAS service..." |
|
| 132 |
+if [ -f "/etc/systemd/system/$MAIN_SERVICE" ]; then |
|
| 133 |
+ systemctl stop autonas.service 2>/dev/null || true |
|
| 134 |
+ systemctl disable autonas.service 2>/dev/null || true |
|
| 135 |
+ rm "/etc/systemd/system/$MAIN_SERVICE" |
|
| 136 |
+ systemctl daemon-reload |
|
| 137 |
+ log_message "โ Main AutoNAS service removed" |
|
| 138 |
+fi |
|
| 139 |
+ |
|
| 140 |
+# Remove boot scan service |
|
| 141 |
+log_message "Removing boot scan service..." |
|
| 142 |
+if [ -f "/etc/systemd/system/$BOOT_SCAN_SERVICE" ]; then |
|
| 143 |
+ systemctl stop autonas-boot-scan.service 2>/dev/null || true |
|
| 144 |
+ systemctl disable autonas-boot-scan.service 2>/dev/null || true |
|
| 145 |
+ rm "/etc/systemd/system/$BOOT_SCAN_SERVICE" |
|
| 146 |
+ systemctl daemon-reload |
|
| 147 |
+ log_message "โ Boot scan service removed" |
|
| 148 |
+fi |
|
| 149 |
+ |
|
| 150 |
+# Handle configuration and data preservation |
|
| 151 |
+log_message "" |
|
| 152 |
+log_message "๐ Handling user data..." |
|
| 153 |
+ |
|
| 154 |
+# Check if configuration exists and has user data |
|
| 155 |
+if [ -f "$CONFIG_DIR/disks.conf" ]; then |
|
| 156 |
+ if grep -v '^#' "$CONFIG_DIR/disks.conf" | grep -v '^$' | grep -q ':'; then |
|
| 157 |
+ log_message "โ ๏ธ User configurations detected in $CONFIG_DIR/disks.conf" |
|
| 158 |
+ log_message " Configuration file preserved for manual cleanup" |
|
| 159 |
+ log_message " Remove manually with: sudo rm -rf $CONFIG_DIR" |
|
| 160 |
+ else |
|
| 161 |
+ log_message "โน๏ธ Configuration file contains only template - removing" |
|
| 162 |
+ rm "$CONFIG_DIR/disks.conf" |
|
| 163 |
+ rmdir "$CONFIG_DIR" 2>/dev/null || true |
|
| 164 |
+ fi |
|
| 165 |
+else |
|
| 166 |
+ log_message "โน๏ธ No configuration file found" |
|
| 167 |
+ rmdir "$CONFIG_DIR" 2>/dev/null || true |
|
| 168 |
+fi |
|
| 169 |
+ |
|
| 170 |
+# Check for mounted AutoNAS disks |
|
| 171 |
+log_message "" |
|
| 172 |
+log_message "๐พ Checking for mounted AutoNAS disks..." |
|
| 173 |
+mounted_autonas=$(mount | grep "/mnt/autonas/" | wc -l) |
|
| 174 |
+if [ $mounted_autonas -gt 0 ]; then |
|
| 175 |
+ log_message "โ ๏ธ Found $mounted_autonas mounted AutoNAS disk(s):" |
|
| 176 |
+ if [ "$FORCE_MODE" = false ]; then |
|
| 177 |
+ mount | grep "/mnt/autonas/" | while read line; do |
|
| 178 |
+ echo " $line" |
|
| 179 |
+ done |
|
| 180 |
+ fi |
|
| 181 |
+ log_message "" |
|
| 182 |
+ log_message " These disks are still mounted and in use." |
|
| 183 |
+ log_message " Mount points preserved: /mnt/autonas/" |
|
| 184 |
+ log_message " Unmount manually if needed: sudo umount /mnt/autonas/*" |
|
| 185 |
+else |
|
| 186 |
+ log_message "โน๏ธ No AutoNAS disks currently mounted" |
|
| 187 |
+ if [ -d "/mnt/autonas" ]; then |
|
| 188 |
+ # Only remove if empty |
|
| 189 |
+ if [ -z "$(ls -A /mnt/autonas)" ]; then |
|
| 190 |
+ rmdir "/mnt/autonas" |
|
| 191 |
+ log_message "โ Empty AutoNAS mount directory removed" |
|
| 192 |
+ else |
|
| 193 |
+ log_message "โ ๏ธ AutoNAS mount directory contains files - preserved" |
|
| 194 |
+ fi |
|
| 195 |
+ fi |
|
| 196 |
+fi |
|
| 197 |
+ |
|
| 198 |
+# Check NFS exports |
|
| 199 |
+log_message "" |
|
| 200 |
+log_message "๐ Checking NFS exports..." |
|
| 201 |
+if [ -f "/etc/exports" ] && grep -q "/mnt/autonas/" "/etc/exports" 2>/dev/null; then |
|
| 202 |
+ log_message "โ ๏ธ AutoNAS NFS exports found in /etc/exports" |
|
| 203 |
+ log_message " Please manually remove AutoNAS entries from /etc/exports" |
|
| 204 |
+ log_message " And reload NFS exports: sudo exportfs -ra" |
|
| 205 |
+else |
|
| 206 |
+ log_message "โน๏ธ No AutoNAS NFS exports found" |
|
| 207 |
+fi |
|
| 208 |
+ |
|
| 209 |
+log_message "" |
|
| 210 |
+log_message "๐ AutoNAS core components removed successfully!" |
|
| 211 |
+ |
|
| 212 |
+if [ "$FORCE_MODE" = false ]; then |
|
| 213 |
+ echo "" |
|
| 214 |
+ echo "๐ Summary:" |
|
| 215 |
+ echo "โ Scripts removed from /usr/local/bin/" |
|
| 216 |
+ echo "โ Udev rules removed" |
|
| 217 |
+ echo "โ Systemd services removed" |
|
| 218 |
+ echo "" |
|
| 219 |
+ echo "โ ๏ธ Preserved (manual cleanup required if desired):" |
|
| 220 |
+ echo "โข User configurations: $CONFIG_DIR/ (if contains user data)" |
|
| 221 |
+ echo "โข Mount points: /mnt/autonas/ (if contains data)" |
|
| 222 |
+ echo "โข NFS exports: /etc/exports (manual edit required)" |
|
| 223 |
+ echo "" |
|
| 224 |
+ echo "๐ To completely remove all AutoNAS data:" |
|
| 225 |
+ echo "sudo rm -rf $CONFIG_DIR" |
|
| 226 |
+ echo "sudo rm -rf /mnt/autonas" |
|
| 227 |
+ echo "sudo nano /etc/exports # Remove AutoNAS entries manually" |
|
| 228 |
+ echo "sudo exportfs -ra" |
|
| 229 |
+fi |
|
| 230 |
+echo "" |
|
| 231 |
+echo "๐ To reinstall AutoNAS later, run: sudo bash scripts/install.sh" |
|
@@ -0,0 +1,70 @@ |
||
| 1 |
+#!/usr/bin/env bash |
|
| 2 |
+# Quick verifier to ensure this repository contains only AutoNAS artifacts |
|
| 3 |
+# Scans for common autoSMART markers and suspicious files. |
|
| 4 |
+ |
|
| 5 |
+set -euo pipefail |
|
| 6 |
+ |
|
| 7 |
+ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
| 8 |
+cd "$ROOT_DIR" |
|
| 9 |
+ |
|
| 10 |
+echo "[verify-project] Repository: $ROOT_DIR" |
|
| 11 |
+ |
|
| 12 |
+patterns=( |
|
| 13 |
+ 'autoSMART' |
|
| 14 |
+ 'autosmart' |
|
| 15 |
+ 'smart-collector' |
|
| 16 |
+ 'SmartCollector' |
|
| 17 |
+ 'smartctl .*postgres' # autosmart DB pipelines pattern |
|
| 18 |
+) |
|
| 19 |
+ |
|
| 20 |
+exclude_dirs=( |
|
| 21 |
+ '.git' |
|
| 22 |
+ '.venv' |
|
| 23 |
+ 'node_modules' |
|
| 24 |
+ 'dist' |
|
| 25 |
+ 'build' |
|
| 26 |
+) |
|
| 27 |
+ |
|
| 28 |
+found=0 |
|
| 29 |
+ |
|
| 30 |
+# Build a find command that prunes excluded directories |
|
| 31 |
+find_cmd=(find .) |
|
| 32 |
+for d in "${exclude_dirs[@]}"; do
|
|
| 33 |
+ find_cmd+=( -path "*/$d/*" -prune -o ) |
|
| 34 |
+done |
|
| 35 |
+find_cmd+=( -type f ! -path "*/scripts/verify-project.sh" -print0 ) |
|
| 36 |
+ |
|
| 37 |
+for pat in "${patterns[@]}"; do
|
|
| 38 |
+ if "${find_cmd[@]}" | xargs -0 grep -EIn --color=never "$pat" > /tmp/_verify_hits 2>/dev/null; then
|
|
| 39 |
+ if [ -s /tmp/_verify_hits ]; then |
|
| 40 |
+ echo "[verify-project] Suspicious matches for pattern: $pat" |
|
| 41 |
+ cat /tmp/_verify_hits |
|
| 42 |
+ echo "" |
|
| 43 |
+ found=1 |
|
| 44 |
+ fi |
|
| 45 |
+ fi |
|
| 46 |
+done |
|
| 47 |
+ |
|
| 48 |
+rm -f /tmp/_verify_hits || true |
|
| 49 |
+ |
|
| 50 |
+# Also check for suspicious filenames accidentally copied over |
|
| 51 |
+suspect_files=( |
|
| 52 |
+ 'smart-collector-daemon.pl' |
|
| 53 |
+ 'deploy-production.sh' |
|
| 54 |
+ 'monitor-cluster.sh' |
|
| 55 |
+) |
|
| 56 |
+ |
|
| 57 |
+for name in "${suspect_files[@]}"; do
|
|
| 58 |
+ if find . -type f -name "$name" | grep -q .; then |
|
| 59 |
+ echo "[verify-project] Suspicious file present: $name" |
|
| 60 |
+ found=1 |
|
| 61 |
+ fi |
|
| 62 |
+done |
|
| 63 |
+ |
|
| 64 |
+if [ "$found" -eq 0 ]; then |
|
| 65 |
+ echo "[verify-project] OK: No autoSMART contamination detected." |
|
| 66 |
+ exit 0 |
|
| 67 |
+else |
|
| 68 |
+ echo "[verify-project] WARNING: Potential contamination detected. Review above matches." |
|
| 69 |
+ exit 2 |
|
| 70 |
+fi |
|
@@ -0,0 +1,650 @@ |
||
| 1 |
+#!/bin/bash |
|
| 2 |
+ |
|
| 3 |
+# Standalone Media Importer |
|
| 4 |
+# Version: 1.0 |
|
| 5 |
+# A comprehensive media file organizer that sorts photos and videos by date |
|
| 6 |
+# with various organization patterns and timezone handling |
|
| 7 |
+ |
|
| 8 |
+VERSION="1.0" |
|
| 9 |
+SCRIPT_NAME="Standalone Media Importer" |
|
| 10 |
+ |
|
| 11 |
+# Default values |
|
| 12 |
+ORGANIZATION="y" # year/month-day_hour-minute_second.ext |
|
| 13 |
+SOURCE_PATTERNS=() |
|
| 14 |
+DESTINATION="" |
|
| 15 |
+KEEP_ORIGINALS=0 |
|
| 16 |
+DRY_RUN=0 |
|
| 17 |
+VERBOSE=0 |
|
| 18 |
+ |
|
| 19 |
+# Counters and statistics |
|
| 20 |
+TOTAL_FILES=0 |
|
| 21 |
+PROCESSED_FILES=0 |
|
| 22 |
+SKIPPED_FILES=0 |
|
| 23 |
+ERROR_FILES=0 |
|
| 24 |
+TOTAL_SIZE=0 |
|
| 25 |
+PROCESSED_SIZE=0 |
|
| 26 |
+START_TIME=$(date +%s) |
|
| 27 |
+ |
|
| 28 |
+# Colors for output |
|
| 29 |
+RED='\033[0;31m' |
|
| 30 |
+GREEN='\033[0;32m' |
|
| 31 |
+YELLOW='\033[1;33m' |
|
| 32 |
+BLUE='\033[0;34m' |
|
| 33 |
+NC='\033[0m' # No Color |
|
| 34 |
+ |
|
| 35 |
+# Function to print colored output |
|
| 36 |
+print_color() {
|
|
| 37 |
+ local color="$1" |
|
| 38 |
+ local message="$2" |
|
| 39 |
+ echo -e "${color}${message}${NC}"
|
|
| 40 |
+} |
|
| 41 |
+ |
|
| 42 |
+# Function to log messages with timestamp |
|
| 43 |
+log_message() {
|
|
| 44 |
+ local message="$1" |
|
| 45 |
+ local level="${2:-INFO}"
|
|
| 46 |
+ local timestamp=$(date '+%Y-%m-%d %H:%M:%S') |
|
| 47 |
+ |
|
| 48 |
+ case "$level" in |
|
| 49 |
+ "ERROR") |
|
| 50 |
+ print_color "$RED" "[$timestamp] ERROR: $message" >&2 |
|
| 51 |
+ ;; |
|
| 52 |
+ "WARNING") |
|
| 53 |
+ print_color "$YELLOW" "[$timestamp] WARNING: $message" |
|
| 54 |
+ ;; |
|
| 55 |
+ "SUCCESS") |
|
| 56 |
+ print_color "$GREEN" "[$timestamp] SUCCESS: $message" |
|
| 57 |
+ ;; |
|
| 58 |
+ "INFO") |
|
| 59 |
+ if [[ $VERBOSE -eq 1 ]]; then |
|
| 60 |
+ print_color "$BLUE" "[$timestamp] INFO: $message" |
|
| 61 |
+ fi |
|
| 62 |
+ ;; |
|
| 63 |
+ *) |
|
| 64 |
+ echo "[$timestamp] $message" |
|
| 65 |
+ ;; |
|
| 66 |
+ esac |
|
| 67 |
+} |
|
| 68 |
+ |
|
| 69 |
+# Function to display help |
|
| 70 |
+show_help() {
|
|
| 71 |
+ cat << EOF |
|
| 72 |
+$SCRIPT_NAME v$VERSION |
|
| 73 |
+ |
|
| 74 |
+USAGE: |
|
| 75 |
+ $0 [OPTIONS] |
|
| 76 |
+ |
|
| 77 |
+DESCRIPTION: |
|
| 78 |
+ Organizes media files (photos and videos) by date with various naming patterns. |
|
| 79 |
+ Handles timezone conversion for QuickTime files and preserves original timestamps. |
|
| 80 |
+ |
|
| 81 |
+OPTIONS: |
|
| 82 |
+ -o, --organization PATTERN |
|
| 83 |
+ Organization pattern (default: y): |
|
| 84 |
+ y -> target/yyyy/mm-dd_hh-mm-ss.orig_ext |
|
| 85 |
+ m -> target/yyyy/mm/dd_hh-mm-ss.orig_ext |
|
| 86 |
+ d -> target/yyyy/mm/dd/mm-dd_hh-mm-ss.orig_ext |
|
| 87 |
+ h -> target/yyyy/mm/dd/hh/mm-ss.orig_ext |
|
| 88 |
+ |
|
| 89 |
+ -s, --source PATTERN |
|
| 90 |
+ Source folder pattern(s) with simple regex support (*^$) |
|
| 91 |
+ Can be specified multiple times |
|
| 92 |
+ Examples: |
|
| 93 |
+ -s "/DCIM/*Video$" |
|
| 94 |
+ -s "/path/to/photos" |
|
| 95 |
+ -s "*.jpg" |
|
| 96 |
+ Default: all subfolders in current directory except destination |
|
| 97 |
+ |
|
| 98 |
+ -d, --destination PATH |
|
| 99 |
+ Destination folder (default: ./sorted) |
|
| 100 |
+ |
|
| 101 |
+ -k, --keep-originals |
|
| 102 |
+ Keep original files (copy instead of move) |
|
| 103 |
+ |
|
| 104 |
+ --dry-run |
|
| 105 |
+ Show what would be done without actually doing it |
|
| 106 |
+ |
|
| 107 |
+ -v, --verbose |
|
| 108 |
+ Enable verbose output |
|
| 109 |
+ |
|
| 110 |
+ -h, --help |
|
| 111 |
+ Show this help message |
|
| 112 |
+ |
|
| 113 |
+ --version |
|
| 114 |
+ Show version information |
|
| 115 |
+ |
|
| 116 |
+EXAMPLES: |
|
| 117 |
+ # Basic usage - organize all media in current directory |
|
| 118 |
+ $0 |
|
| 119 |
+ |
|
| 120 |
+ # Organize with monthly folders, keep originals |
|
| 121 |
+ $0 -o m -k |
|
| 122 |
+ |
|
| 123 |
+ # Process specific folders with hourly organization |
|
| 124 |
+ $0 -o h -s "/DCIM/Camera" -s "/DCIM/Video" -d "/media/sorted" |
|
| 125 |
+ |
|
| 126 |
+ # Dry run with verbose output |
|
| 127 |
+ $0 --dry-run -v -s "*.mov" -d "/tmp/test" |
|
| 128 |
+ |
|
| 129 |
+DEPENDENCIES: |
|
| 130 |
+ Required: exiftool |
|
| 131 |
+ Optional: mediainfo, file (for enhanced metadata detection) |
|
| 132 |
+ |
|
| 133 |
+EOF |
|
| 134 |
+} |
|
| 135 |
+ |
|
| 136 |
+# Function to show version |
|
| 137 |
+show_version() {
|
|
| 138 |
+ echo "$SCRIPT_NAME v$VERSION" |
|
| 139 |
+ echo "A comprehensive media file organizer with timezone support" |
|
| 140 |
+} |
|
| 141 |
+ |
|
| 142 |
+# Function to check dependencies |
|
| 143 |
+check_dependencies() {
|
|
| 144 |
+ local missing_deps=() |
|
| 145 |
+ |
|
| 146 |
+ # Check for required dependencies |
|
| 147 |
+ if ! command -v exiftool &> /dev/null; then |
|
| 148 |
+ missing_deps+=("exiftool")
|
|
| 149 |
+ fi |
|
| 150 |
+ |
|
| 151 |
+ # Check for optional dependencies |
|
| 152 |
+ local optional_missing=() |
|
| 153 |
+ if ! command -v mediainfo &> /dev/null; then |
|
| 154 |
+ optional_missing+=("mediainfo")
|
|
| 155 |
+ fi |
|
| 156 |
+ |
|
| 157 |
+ if ! command -v file &> /dev/null; then |
|
| 158 |
+ optional_missing+=("file")
|
|
| 159 |
+ fi |
|
| 160 |
+ |
|
| 161 |
+ if [[ ${#missing_deps[@]} -gt 0 ]]; then
|
|
| 162 |
+ print_color "$RED" "ERROR: Missing required dependencies:" |
|
| 163 |
+ for dep in "${missing_deps[@]}"; do
|
|
| 164 |
+ echo " - $dep" |
|
| 165 |
+ done |
|
| 166 |
+ echo "" |
|
| 167 |
+ echo "Installation instructions:" |
|
| 168 |
+ echo " macOS: brew install exiftool" |
|
| 169 |
+ echo " Ubuntu/Debian: sudo apt-get install libimage-exiftool-perl" |
|
| 170 |
+ echo " CentOS/RHEL: sudo yum install perl-Image-ExifTool" |
|
| 171 |
+ echo " Arch: sudo pacman -S perl-image-exiftool" |
|
| 172 |
+ exit 1 |
|
| 173 |
+ fi |
|
| 174 |
+ |
|
| 175 |
+ if [[ ${#optional_missing[@]} -gt 0 && $VERBOSE -eq 1 ]]; then
|
|
| 176 |
+ log_message "Optional dependencies not found (functionality may be limited): ${optional_missing[*]}" "WARNING"
|
|
| 177 |
+ fi |
|
| 178 |
+ |
|
| 179 |
+ log_message "All required dependencies found" "SUCCESS" |
|
| 180 |
+} |
|
| 181 |
+ |
|
| 182 |
+# Function to get file size in bytes |
|
| 183 |
+get_file_size() {
|
|
| 184 |
+ local file="$1" |
|
| 185 |
+ if [[ -f "$file" ]]; then |
|
| 186 |
+ if command -v stat &> /dev/null; then |
|
| 187 |
+ # Try GNU stat first (Linux) |
|
| 188 |
+ stat -c%s "$file" 2>/dev/null || stat -f%z "$file" 2>/dev/null |
|
| 189 |
+ else |
|
| 190 |
+ # Fallback to ls |
|
| 191 |
+ ls -l "$file" | awk '{print $5}'
|
|
| 192 |
+ fi |
|
| 193 |
+ else |
|
| 194 |
+ echo "0" |
|
| 195 |
+ fi |
|
| 196 |
+} |
|
| 197 |
+ |
|
| 198 |
+# Function to format file size |
|
| 199 |
+format_size() {
|
|
| 200 |
+ local size=$1 |
|
| 201 |
+ if (( size < 1024 )); then |
|
| 202 |
+ echo "${size}B"
|
|
| 203 |
+ elif (( size < 1048576 )); then |
|
| 204 |
+ echo "$(( size / 1024 ))KB" |
|
| 205 |
+ elif (( size < 1073741824 )); then |
|
| 206 |
+ echo "$(( size / 1048576 ))MB" |
|
| 207 |
+ else |
|
| 208 |
+ echo "$(( size / 1073741824 ))GB" |
|
| 209 |
+ fi |
|
| 210 |
+} |
|
| 211 |
+ |
|
| 212 |
+# Function to extract date from file |
|
| 213 |
+extract_file_date() {
|
|
| 214 |
+ local file="$1" |
|
| 215 |
+ local create_date="" |
|
| 216 |
+ local date_source="" |
|
| 217 |
+ |
|
| 218 |
+ # Try to get creation date from EXIF data |
|
| 219 |
+ local exif_output=$(exiftool -G1 -s -CreateDate -DateTimeOriginal -DateTime "$file" 2>/dev/null) |
|
| 220 |
+ |
|
| 221 |
+ if [[ -n "$exif_output" ]]; then |
|
| 222 |
+ # Parse the exiftool output to find the best date |
|
| 223 |
+ while IFS= read -r line; do |
|
| 224 |
+ if [[ "$line" =~ ^\[([^\]]+)\][[:space:]]*([^:]+):[[:space:]]*(.+)$ ]]; then |
|
| 225 |
+ local group="${BASH_REMATCH[1]}"
|
|
| 226 |
+ local tag="${BASH_REMATCH[2]}"
|
|
| 227 |
+ local value="${BASH_REMATCH[3]}"
|
|
| 228 |
+ |
|
| 229 |
+ # Prefer DateTimeOriginal, then CreateDate, then DateTime |
|
| 230 |
+ if [[ "$tag" == "DateTimeOriginal" && -z "$create_date" ]]; then |
|
| 231 |
+ create_date="$value" |
|
| 232 |
+ date_source="$group:$tag" |
|
| 233 |
+ elif [[ "$tag" == "CreateDate" && "$date_source" != *"DateTimeOriginal"* ]]; then |
|
| 234 |
+ create_date="$value" |
|
| 235 |
+ date_source="$group:$tag" |
|
| 236 |
+ elif [[ "$tag" == "DateTime" && -z "$create_date" ]]; then |
|
| 237 |
+ create_date="$value" |
|
| 238 |
+ date_source="$group:$tag" |
|
| 239 |
+ fi |
|
| 240 |
+ fi |
|
| 241 |
+ done <<< "$exif_output" |
|
| 242 |
+ fi |
|
| 243 |
+ |
|
| 244 |
+ # If no EXIF date found, try mediainfo for video files |
|
| 245 |
+ if [[ -z "$create_date" ]] && command -v mediainfo &> /dev/null; then |
|
| 246 |
+ local media_date=$(mediainfo --Inform="General;%Recorded_Date%" "$file" 2>/dev/null) |
|
| 247 |
+ if [[ -n "$media_date" && "$media_date" != "0000-00-00 00:00:00" ]]; then |
|
| 248 |
+ create_date="$media_date" |
|
| 249 |
+ date_source="MediaInfo:Recorded_Date" |
|
| 250 |
+ fi |
|
| 251 |
+ fi |
|
| 252 |
+ |
|
| 253 |
+ # Fallback to file modification time |
|
| 254 |
+ if [[ -z "$create_date" ]]; then |
|
| 255 |
+ if [[ "$OSTYPE" == "darwin"* ]]; then |
|
| 256 |
+ # macOS |
|
| 257 |
+ create_date=$(stat -f "%Sm" -t "%Y:%m:%d %H:%M:%S" "$file" 2>/dev/null) |
|
| 258 |
+ else |
|
| 259 |
+ # Linux |
|
| 260 |
+ create_date=$(date -r "$file" "+%Y:%m:%d %H:%M:%S" 2>/dev/null) |
|
| 261 |
+ fi |
|
| 262 |
+ date_source="FileSystem:ModificationTime" |
|
| 263 |
+ fi |
|
| 264 |
+ |
|
| 265 |
+ if [[ -z "$create_date" ]]; then |
|
| 266 |
+ return 1 |
|
| 267 |
+ fi |
|
| 268 |
+ |
|
| 269 |
+ # Convert EXIF format (YYYY:MM:DD HH:MM:SS) to standard format |
|
| 270 |
+ create_date=$(echo "$create_date" | sed 's/^\([0-9]\{4\}\):\([0-9]\{2\}\):\([0-9]\{2\}\)/\1-\2-\3/')
|
|
| 271 |
+ |
|
| 272 |
+ # Handle QuickTime UTC conversion |
|
| 273 |
+ if [[ "$date_source" == *"QuickTime"* ]]; then |
|
| 274 |
+ local utc_timestamp=$(date -d "$create_date UTC" "+%s" 2>/dev/null) |
|
| 275 |
+ if [[ -n "$utc_timestamp" ]]; then |
|
| 276 |
+ create_date=$(date -d "@$utc_timestamp" "+%Y-%m-%d %H:%M:%S" 2>/dev/null) |
|
| 277 |
+ date_source="$date_source (converted from UTC)" |
|
| 278 |
+ fi |
|
| 279 |
+ fi |
|
| 280 |
+ |
|
| 281 |
+ echo "$create_date|$date_source" |
|
| 282 |
+ return 0 |
|
| 283 |
+} |
|
| 284 |
+ |
|
| 285 |
+# Function to generate destination path based on organization pattern |
|
| 286 |
+generate_destination_path() {
|
|
| 287 |
+ local date_str="$1" |
|
| 288 |
+ local original_filename="$2" |
|
| 289 |
+ local base_destination="$3" |
|
| 290 |
+ |
|
| 291 |
+ # Extract date components |
|
| 292 |
+ local year=$(date -d "$date_str" "+%Y" 2>/dev/null) |
|
| 293 |
+ local month=$(date -d "$date_str" "+%m" 2>/dev/null) |
|
| 294 |
+ local day=$(date -d "$date_str" "+%d" 2>/dev/null) |
|
| 295 |
+ local hour=$(date -d "$date_str" "+%H" 2>/dev/null) |
|
| 296 |
+ local minute=$(date -d "$date_str" "+%M" 2>/dev/null) |
|
| 297 |
+ local second=$(date -d "$date_str" "+%S" 2>/dev/null) |
|
| 298 |
+ |
|
| 299 |
+ if [[ -z "$year" || -z "$month" || -z "$day" ]]; then |
|
| 300 |
+ return 1 |
|
| 301 |
+ fi |
|
| 302 |
+ |
|
| 303 |
+ # Get file extension |
|
| 304 |
+ local extension="${original_filename##*.}"
|
|
| 305 |
+ local lowercase_ext="${extension,,}"
|
|
| 306 |
+ |
|
| 307 |
+ # Generate path and filename based on organization pattern |
|
| 308 |
+ local dir_path="" |
|
| 309 |
+ local filename="" |
|
| 310 |
+ |
|
| 311 |
+ case "$ORGANIZATION" in |
|
| 312 |
+ "y") |
|
| 313 |
+ # target/yyyy/mm-dd_hh-mm-ss.orig_ext |
|
| 314 |
+ dir_path="$base_destination/$year" |
|
| 315 |
+ filename="${month}-${day}_${hour}-${minute}-${second}.${lowercase_ext}"
|
|
| 316 |
+ ;; |
|
| 317 |
+ "m") |
|
| 318 |
+ # target/yyyy/mm/dd_hh-mm-ss.orig_ext |
|
| 319 |
+ dir_path="$base_destination/$year/$month" |
|
| 320 |
+ filename="${day}_${hour}-${minute}-${second}.${lowercase_ext}"
|
|
| 321 |
+ ;; |
|
| 322 |
+ "d") |
|
| 323 |
+ # target/yyyy/mm/dd/mm-dd_hh-mm-ss.orig_ext |
|
| 324 |
+ dir_path="$base_destination/$year/$month/$day" |
|
| 325 |
+ filename="${month}-${day}_${hour}-${minute}-${second}.${lowercase_ext}"
|
|
| 326 |
+ ;; |
|
| 327 |
+ "h") |
|
| 328 |
+ # target/yyyy/mm/dd/hh/mm-ss.orig_ext |
|
| 329 |
+ dir_path="$base_destination/$year/$month/$day/$hour" |
|
| 330 |
+ filename="${minute}-${second}.${lowercase_ext}"
|
|
| 331 |
+ ;; |
|
| 332 |
+ *) |
|
| 333 |
+ log_message "Invalid organization pattern: $ORGANIZATION" "ERROR" |
|
| 334 |
+ return 1 |
|
| 335 |
+ ;; |
|
| 336 |
+ esac |
|
| 337 |
+ |
|
| 338 |
+ echo "$dir_path/$filename" |
|
| 339 |
+ return 0 |
|
| 340 |
+} |
|
| 341 |
+ |
|
| 342 |
+# Function to find files matching patterns |
|
| 343 |
+find_source_files() {
|
|
| 344 |
+ local files=() |
|
| 345 |
+ |
|
| 346 |
+ if [[ ${#SOURCE_PATTERNS[@]} -eq 0 ]]; then
|
|
| 347 |
+ # Default: find all media files in current directory and subdirectories |
|
| 348 |
+ # Exclude destination directory if it's a subdirectory of current directory |
|
| 349 |
+ local find_cmd="find . -type f" |
|
| 350 |
+ |
|
| 351 |
+ # Add exclusion for destination if it's relative to current directory |
|
| 352 |
+ if [[ "$DESTINATION" =~ ^\./.*$ ]] || [[ "$DESTINATION" =~ ^[^/].*$ ]]; then |
|
| 353 |
+ local abs_dest=$(cd "$DESTINATION" 2>/dev/null && pwd) |
|
| 354 |
+ local abs_current=$(pwd) |
|
| 355 |
+ if [[ "$abs_dest" == "$abs_current"* ]]; then |
|
| 356 |
+ find_cmd="$find_cmd ! -path \"$DESTINATION/*\"" |
|
| 357 |
+ fi |
|
| 358 |
+ fi |
|
| 359 |
+ |
|
| 360 |
+ # Add media file extensions |
|
| 361 |
+ local extensions=("*.jpg" "*.jpeg" "*.png" "*.tiff" "*.tif" "*.cr2" "*.nef" "*.arw" "*.dng" "*.raw" "*.mp4" "*.mov" "*.avi" "*.mts" "*.m2ts" "*.mkv" "*.wmv" "*.3gp" "*.m4v")
|
|
| 362 |
+ local ext_pattern="" |
|
| 363 |
+ for ext in "${extensions[@]}"; do
|
|
| 364 |
+ if [[ -n "$ext_pattern" ]]; then |
|
| 365 |
+ ext_pattern="$ext_pattern -o" |
|
| 366 |
+ fi |
|
| 367 |
+ ext_pattern="$ext_pattern -iname $ext" |
|
| 368 |
+ done |
|
| 369 |
+ |
|
| 370 |
+ eval "$find_cmd \\( $ext_pattern \\)" | while IFS= read -r file; do |
|
| 371 |
+ echo "$file" |
|
| 372 |
+ done |
|
| 373 |
+ else |
|
| 374 |
+ # Use specified patterns |
|
| 375 |
+ for pattern in "${SOURCE_PATTERNS[@]}"; do
|
|
| 376 |
+ # Handle different pattern types |
|
| 377 |
+ if [[ -d "$pattern" ]]; then |
|
| 378 |
+ # Directory pattern |
|
| 379 |
+ find "$pattern" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.tiff" -o -iname "*.tif" -o -iname "*.cr2" -o -iname "*.nef" -o -iname "*.arw" -o -iname "*.dng" -o -iname "*.raw" -o -iname "*.mp4" -o -iname "*.mov" -o -iname "*.avi" -o -iname "*.mts" -o -iname "*.m2ts" -o -iname "*.mkv" -o -iname "*.wmv" -o -iname "*.3gp" -o -iname "*.m4v" \) 2>/dev/null |
|
| 380 |
+ elif [[ "$pattern" == *"*"* ]] || [[ "$pattern" == *"?"* ]]; then |
|
| 381 |
+ # Glob pattern |
|
| 382 |
+ for file in $pattern; do |
|
| 383 |
+ if [[ -f "$file" ]]; then |
|
| 384 |
+ echo "$file" |
|
| 385 |
+ fi |
|
| 386 |
+ done |
|
| 387 |
+ else |
|
| 388 |
+ # Exact file or directory |
|
| 389 |
+ if [[ -f "$pattern" ]]; then |
|
| 390 |
+ echo "$pattern" |
|
| 391 |
+ elif [[ -d "$pattern" ]]; then |
|
| 392 |
+ find "$pattern" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.tiff" -o -iname "*.tif" -o -iname "*.cr2" -o -iname "*.nef" -o -iname "*.arw" -o -iname "*.dng" -o -iname "*.raw" -o -iname "*.mp4" -o -iname "*.mov" -o -iname "*.avi" -o -iname "*.mts" -o -iname "*.m2ts" -o -iname "*.mkv" -o -iname "*.wmv" -o -iname "*.3gp" -o -iname "*.m4v" \) 2>/dev/null |
|
| 393 |
+ fi |
|
| 394 |
+ fi |
|
| 395 |
+ done |
|
| 396 |
+ fi |
|
| 397 |
+} |
|
| 398 |
+ |
|
| 399 |
+# Function to process a single file |
|
| 400 |
+process_file() {
|
|
| 401 |
+ local file="$1" |
|
| 402 |
+ local file_size=$(get_file_size "$file") |
|
| 403 |
+ TOTAL_SIZE=$((TOTAL_SIZE + file_size)) |
|
| 404 |
+ |
|
| 405 |
+ log_message "Processing: $file" "INFO" |
|
| 406 |
+ |
|
| 407 |
+ # Extract date information |
|
| 408 |
+ local date_info=$(extract_file_date "$file") |
|
| 409 |
+ if [[ $? -ne 0 ]] || [[ -z "$date_info" ]]; then |
|
| 410 |
+ log_message "Could not extract date from $file - skipping" "WARNING" |
|
| 411 |
+ SKIPPED_FILES=$((SKIPPED_FILES + 1)) |
|
| 412 |
+ return 1 |
|
| 413 |
+ fi |
|
| 414 |
+ |
|
| 415 |
+ local date_str="${date_info%|*}"
|
|
| 416 |
+ local date_source="${date_info#*|}"
|
|
| 417 |
+ |
|
| 418 |
+ log_message "Date: $date_str (from $date_source)" "INFO" |
|
| 419 |
+ |
|
| 420 |
+ # Generate destination path |
|
| 421 |
+ local dest_path=$(generate_destination_path "$date_str" "$(basename "$file")" "$DESTINATION") |
|
| 422 |
+ if [[ $? -ne 0 ]] || [[ -z "$dest_path" ]]; then |
|
| 423 |
+ log_message "Could not generate destination path for $file" "ERROR" |
|
| 424 |
+ ERROR_FILES=$((ERROR_FILES + 1)) |
|
| 425 |
+ return 1 |
|
| 426 |
+ fi |
|
| 427 |
+ |
|
| 428 |
+ # Handle filename conflicts |
|
| 429 |
+ local counter=1 |
|
| 430 |
+ local original_dest_path="$dest_path" |
|
| 431 |
+ while [[ -f "$dest_path" ]]; do |
|
| 432 |
+ local dir_path=$(dirname "$original_dest_path") |
|
| 433 |
+ local filename=$(basename "$original_dest_path") |
|
| 434 |
+ local name_without_ext="${filename%.*}"
|
|
| 435 |
+ local ext="${filename##*.}"
|
|
| 436 |
+ dest_path="$dir_path/${name_without_ext}_${counter}.${ext}"
|
|
| 437 |
+ counter=$((counter + 1)) |
|
| 438 |
+ done |
|
| 439 |
+ |
|
| 440 |
+ local dest_dir=$(dirname "$dest_path") |
|
| 441 |
+ |
|
| 442 |
+ if [[ $DRY_RUN -eq 1 ]]; then |
|
| 443 |
+ if [[ $KEEP_ORIGINALS -eq 1 ]]; then |
|
| 444 |
+ print_color "$BLUE" "Would copy: $file -> $dest_path" |
|
| 445 |
+ else |
|
| 446 |
+ print_color "$BLUE" "Would move: $file -> $dest_path" |
|
| 447 |
+ fi |
|
| 448 |
+ PROCESSED_FILES=$((PROCESSED_FILES + 1)) |
|
| 449 |
+ PROCESSED_SIZE=$((PROCESSED_SIZE + file_size)) |
|
| 450 |
+ return 0 |
|
| 451 |
+ fi |
|
| 452 |
+ |
|
| 453 |
+ # Create destination directory |
|
| 454 |
+ if ! mkdir -p "$dest_dir"; then |
|
| 455 |
+ log_message "Could not create directory: $dest_dir" "ERROR" |
|
| 456 |
+ ERROR_FILES=$((ERROR_FILES + 1)) |
|
| 457 |
+ return 1 |
|
| 458 |
+ fi |
|
| 459 |
+ |
|
| 460 |
+ # Copy or move file |
|
| 461 |
+ if [[ $KEEP_ORIGINALS -eq 1 ]]; then |
|
| 462 |
+ if cp "$file" "$dest_path"; then |
|
| 463 |
+ log_message "Copied: $file -> $dest_path" "SUCCESS" |
|
| 464 |
+ PROCESSED_FILES=$((PROCESSED_FILES + 1)) |
|
| 465 |
+ PROCESSED_SIZE=$((PROCESSED_SIZE + file_size)) |
|
| 466 |
+ return 0 |
|
| 467 |
+ else |
|
| 468 |
+ log_message "Failed to copy: $file" "ERROR" |
|
| 469 |
+ ERROR_FILES=$((ERROR_FILES + 1)) |
|
| 470 |
+ return 1 |
|
| 471 |
+ fi |
|
| 472 |
+ else |
|
| 473 |
+ if mv "$file" "$dest_path"; then |
|
| 474 |
+ log_message "Moved: $file -> $dest_path" "SUCCESS" |
|
| 475 |
+ PROCESSED_FILES=$((PROCESSED_FILES + 1)) |
|
| 476 |
+ PROCESSED_SIZE=$((PROCESSED_SIZE + file_size)) |
|
| 477 |
+ return 0 |
|
| 478 |
+ else |
|
| 479 |
+ log_message "Failed to move: $file" "ERROR" |
|
| 480 |
+ ERROR_FILES=$((ERROR_FILES + 1)) |
|
| 481 |
+ return 1 |
|
| 482 |
+ fi |
|
| 483 |
+ fi |
|
| 484 |
+} |
|
| 485 |
+ |
|
| 486 |
+# Function to display final report |
|
| 487 |
+show_report() {
|
|
| 488 |
+ local end_time=$(date +%s) |
|
| 489 |
+ local elapsed_time=$((end_time - START_TIME)) |
|
| 490 |
+ local hours=$((elapsed_time / 3600)) |
|
| 491 |
+ local minutes=$(((elapsed_time % 3600) / 60)) |
|
| 492 |
+ local seconds=$((elapsed_time % 60)) |
|
| 493 |
+ |
|
| 494 |
+ echo "" |
|
| 495 |
+ print_color "$GREEN" "==========================================" |
|
| 496 |
+ print_color "$GREEN" " PROCESSING REPORT" |
|
| 497 |
+ print_color "$GREEN" "==========================================" |
|
| 498 |
+ echo "" |
|
| 499 |
+ |
|
| 500 |
+ echo "Files Summary:" |
|
| 501 |
+ echo " Total files found: $TOTAL_FILES" |
|
| 502 |
+ echo " Successfully processed: $PROCESSED_FILES" |
|
| 503 |
+ echo " Skipped (no date): $SKIPPED_FILES" |
|
| 504 |
+ echo " Errors: $ERROR_FILES" |
|
| 505 |
+ echo "" |
|
| 506 |
+ |
|
| 507 |
+ echo "Size Summary:" |
|
| 508 |
+ echo " Total size found: $(format_size $TOTAL_SIZE)" |
|
| 509 |
+ echo " Successfully processed: $(format_size $PROCESSED_SIZE)" |
|
| 510 |
+ echo "" |
|
| 511 |
+ |
|
| 512 |
+ echo "Time Summary:" |
|
| 513 |
+ printf " Time elapsed: %02d:%02d:%02d\n" $hours $minutes $seconds |
|
| 514 |
+ |
|
| 515 |
+ if [[ $elapsed_time -gt 0 && $PROCESSED_FILES -gt 0 ]]; then |
|
| 516 |
+ local files_per_second=$((PROCESSED_FILES / elapsed_time)) |
|
| 517 |
+ local mb_per_second=$((PROCESSED_SIZE / elapsed_time / 1048576)) |
|
| 518 |
+ echo " Speed: $files_per_second files/sec, ${mb_per_second}MB/sec"
|
|
| 519 |
+ fi |
|
| 520 |
+ |
|
| 521 |
+ echo "" |
|
| 522 |
+ |
|
| 523 |
+ if [[ $DRY_RUN -eq 1 ]]; then |
|
| 524 |
+ print_color "$YELLOW" "DRY RUN MODE - No files were actually moved/copied" |
|
| 525 |
+ elif [[ $KEEP_ORIGINALS -eq 1 ]]; then |
|
| 526 |
+ print_color "$BLUE" "COPY MODE - Original files were preserved" |
|
| 527 |
+ else |
|
| 528 |
+ print_color "$GREEN" "MOVE MODE - Files were moved to destination" |
|
| 529 |
+ fi |
|
| 530 |
+ |
|
| 531 |
+ echo "" |
|
| 532 |
+ print_color "$GREEN" "==========================================" |
|
| 533 |
+} |
|
| 534 |
+ |
|
| 535 |
+# Parse command line arguments |
|
| 536 |
+while [[ $# -gt 0 ]]; do |
|
| 537 |
+ case $1 in |
|
| 538 |
+ -o|--organization) |
|
| 539 |
+ ORGANIZATION="$2" |
|
| 540 |
+ if [[ ! "$ORGANIZATION" =~ ^[ymdh]$ ]]; then |
|
| 541 |
+ print_color "$RED" "Error: Invalid organization pattern. Must be one of: y, m, d, h" |
|
| 542 |
+ exit 1 |
|
| 543 |
+ fi |
|
| 544 |
+ shift 2 |
|
| 545 |
+ ;; |
|
| 546 |
+ -s|--source) |
|
| 547 |
+ SOURCE_PATTERNS+=("$2")
|
|
| 548 |
+ shift 2 |
|
| 549 |
+ ;; |
|
| 550 |
+ -d|--destination) |
|
| 551 |
+ DESTINATION="$2" |
|
| 552 |
+ shift 2 |
|
| 553 |
+ ;; |
|
| 554 |
+ -k|--keep-originals) |
|
| 555 |
+ KEEP_ORIGINALS=1 |
|
| 556 |
+ shift |
|
| 557 |
+ ;; |
|
| 558 |
+ --dry-run) |
|
| 559 |
+ DRY_RUN=1 |
|
| 560 |
+ shift |
|
| 561 |
+ ;; |
|
| 562 |
+ -v|--verbose) |
|
| 563 |
+ VERBOSE=1 |
|
| 564 |
+ shift |
|
| 565 |
+ ;; |
|
| 566 |
+ -h|--help) |
|
| 567 |
+ show_help |
|
| 568 |
+ exit 0 |
|
| 569 |
+ ;; |
|
| 570 |
+ --version) |
|
| 571 |
+ show_version |
|
| 572 |
+ exit 0 |
|
| 573 |
+ ;; |
|
| 574 |
+ *) |
|
| 575 |
+ print_color "$RED" "Error: Unknown option: $1" |
|
| 576 |
+ echo "Use -h or --help for usage information." |
|
| 577 |
+ exit 1 |
|
| 578 |
+ ;; |
|
| 579 |
+ esac |
|
| 580 |
+done |
|
| 581 |
+ |
|
| 582 |
+# Set default destination if not specified |
|
| 583 |
+if [[ -z "$DESTINATION" ]]; then |
|
| 584 |
+ DESTINATION="./sorted" |
|
| 585 |
+fi |
|
| 586 |
+ |
|
| 587 |
+# Convert destination to absolute path |
|
| 588 |
+DESTINATION=$(cd "$(dirname "$DESTINATION")" 2>/dev/null && pwd)/$(basename "$DESTINATION") || DESTINATION=$(realpath "$DESTINATION" 2>/dev/null) || DESTINATION="$DESTINATION" |
|
| 589 |
+ |
|
| 590 |
+# Display configuration |
|
| 591 |
+print_color "$GREEN" "$SCRIPT_NAME v$VERSION" |
|
| 592 |
+echo "" |
|
| 593 |
+echo "Configuration:" |
|
| 594 |
+echo " Organization pattern: $ORGANIZATION" |
|
| 595 |
+echo " Destination: $DESTINATION" |
|
| 596 |
+echo " Keep originals: $([ $KEEP_ORIGINALS -eq 1 ] && echo "Yes" || echo "No")" |
|
| 597 |
+echo " Dry run: $([ $DRY_RUN -eq 1 ] && echo "Yes" || echo "No")" |
|
| 598 |
+echo " Verbose: $([ $VERBOSE -eq 1 ] && echo "Yes" || echo "No")" |
|
| 599 |
+ |
|
| 600 |
+if [[ ${#SOURCE_PATTERNS[@]} -gt 0 ]]; then
|
|
| 601 |
+ echo " Source patterns:" |
|
| 602 |
+ for pattern in "${SOURCE_PATTERNS[@]}"; do
|
|
| 603 |
+ echo " - $pattern" |
|
| 604 |
+ done |
|
| 605 |
+else |
|
| 606 |
+ echo " Source patterns: All media files in current directory" |
|
| 607 |
+fi |
|
| 608 |
+ |
|
| 609 |
+echo "" |
|
| 610 |
+ |
|
| 611 |
+# Check dependencies |
|
| 612 |
+check_dependencies |
|
| 613 |
+ |
|
| 614 |
+# Create destination directory if it doesn't exist (unless dry run) |
|
| 615 |
+if [[ $DRY_RUN -eq 0 ]]; then |
|
| 616 |
+ if ! mkdir -p "$DESTINATION"; then |
|
| 617 |
+ print_color "$RED" "Error: Cannot create destination directory: $DESTINATION" |
|
| 618 |
+ exit 1 |
|
| 619 |
+ fi |
|
| 620 |
+fi |
|
| 621 |
+ |
|
| 622 |
+# Find all source files |
|
| 623 |
+print_color "$BLUE" "Scanning for media files..." |
|
| 624 |
+mapfile -t files < <(find_source_files) |
|
| 625 |
+TOTAL_FILES=${#files[@]}
|
|
| 626 |
+ |
|
| 627 |
+if [[ $TOTAL_FILES -eq 0 ]]; then |
|
| 628 |
+ print_color "$YELLOW" "No media files found matching the specified patterns." |
|
| 629 |
+ exit 0 |
|
| 630 |
+fi |
|
| 631 |
+ |
|
| 632 |
+print_color "$BLUE" "Found $TOTAL_FILES media files to process" |
|
| 633 |
+echo "" |
|
| 634 |
+ |
|
| 635 |
+# Process each file |
|
| 636 |
+for file in "${files[@]}"; do
|
|
| 637 |
+ if [[ -f "$file" ]]; then |
|
| 638 |
+ process_file "$file" |
|
| 639 |
+ fi |
|
| 640 |
+done |
|
| 641 |
+ |
|
| 642 |
+# Show final report |
|
| 643 |
+show_report |
|
| 644 |
+ |
|
| 645 |
+# Exit with appropriate code |
|
| 646 |
+if [[ $ERROR_FILES -gt 0 ]]; then |
|
| 647 |
+ exit 1 |
|
| 648 |
+else |
|
| 649 |
+ exit 0 |
|
| 650 |
+fi |
|