| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| param( |
| [Parameter(Mandatory=$true)] |
| [string]$BundleZip, |
|
|
| [Parameter(Mandatory=$true)] |
| [string]$SectionKey, |
|
|
| [string]$DataDir = "data", |
|
|
| [bool]$BackupExisting = $true |
| ) |
|
|
| $ErrorActionPreference = "Stop" |
|
|
| |
| function Write-Status($message) { |
| Write-Host " [INFO] $message" -ForegroundColor Cyan |
| } |
|
|
| function Write-Success($message) { |
| Write-Host " [OK] $message" -ForegroundColor Green |
| } |
|
|
| function Write-Warn($message) { |
| Write-Host " [WARN] $message" -ForegroundColor Yellow |
| } |
|
|
| function Write-Fail($message) { |
| Write-Host " [FAIL] $message" -ForegroundColor Red |
| } |
|
|
| function Get-FileChecksum($path) { |
| $hash = Get-FileHash -Path $path -Algorithm SHA256 |
| return $hash.Hash.ToLower() |
| } |
|
|
| |
| Write-Host "" |
| Write-Host "ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ" -ForegroundColor Blue |
| Write-Host "β SmartClass Edge Node - Bundle Deployment β" -ForegroundColor Blue |
| Write-Host "ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ" -ForegroundColor Blue |
| Write-Host "" |
|
|
| |
| if (-not (Test-Path $BundleZip)) { |
| Write-Fail "Bundle ZIP not found: $BundleZip" |
| exit 1 |
| } |
|
|
| Write-Status "Section: $SectionKey" |
| Write-Status "Bundle: $BundleZip" |
| Write-Status "Data directory: $DataDir" |
| Write-Host "" |
|
|
| |
| Write-Host "Step 1: Extracting bundle..." -ForegroundColor White |
| $tempDir = Join-Path $env:TEMP "smartclass_bundle_$(Get-Date -Format 'yyyyMMdd_HHmmss')" |
| Expand-Archive -Path $BundleZip -DestinationPath $tempDir -Force |
| Write-Success "Extracted to: $tempDir" |
|
|
| |
| Write-Host "Step 2: Validating manifest..." -ForegroundColor White |
| $manifestPath = Join-Path $tempDir "manifest.json" |
| if (-not (Test-Path $manifestPath)) { |
| Write-Fail "manifest.json not found in bundle!" |
| Remove-Item -Recurse -Force $tempDir |
| exit 1 |
| } |
|
|
| $manifest = Get-Content $manifestPath | ConvertFrom-Json |
| Write-Status "Bundle version: $($manifest.version)" |
| Write-Status "Created: $($manifest.created_at)" |
| Write-Status "Section: $($manifest.section_key)" |
| Write-Status "Students: $($manifest.student_count)" |
|
|
| if ($manifest.section_key -ne $SectionKey) { |
| Write-Warn "Bundle section ($($manifest.section_key)) doesn't match target ($SectionKey)" |
| $confirm = Read-Host "Continue anyway? (y/N)" |
| if ($confirm -ne "y") { |
| Remove-Item -Recurse -Force $tempDir |
| exit 1 |
| } |
| } |
|
|
| |
| Write-Host "Step 3: Validating checksums..." -ForegroundColor White |
| $checksumFailed = $false |
| foreach ($file in $manifest.files.PSObject.Properties) { |
| $filePath = Join-Path $tempDir $file.Name |
| if (Test-Path $filePath) { |
| $actualChecksum = Get-FileChecksum $filePath |
| $expectedChecksum = $file.Value.checksum |
| if ($actualChecksum -eq $expectedChecksum) { |
| Write-Success "$($file.Name) - checksum OK" |
| } else { |
| Write-Fail "$($file.Name) - checksum MISMATCH" |
| $checksumFailed = $true |
| } |
| } else { |
| Write-Fail "$($file.Name) - FILE MISSING" |
| $checksumFailed = $true |
| } |
| } |
|
|
| if ($checksumFailed) { |
| Write-Fail "Checksum validation failed! Aborting deployment." |
| Remove-Item -Recurse -Force $tempDir |
| exit 1 |
| } |
|
|
| |
| if ($BackupExisting) { |
| Write-Host "Step 4: Backing up existing files..." -ForegroundColor White |
| $backupDir = Join-Path $DataDir "backups" "$(Get-Date -Format 'yyyyMMdd_HHmmss')" |
| New-Item -ItemType Directory -Path $backupDir -Force | Out-Null |
|
|
| $existingIndex = Join-Path $DataDir "faiss_indices" "$SectionKey.index" |
| $existingMap = Join-Path $DataDir "student_maps" "${SectionKey}_map.json" |
|
|
| if (Test-Path $existingIndex) { |
| Copy-Item $existingIndex $backupDir |
| Write-Status "Backed up FAISS index" |
| } |
| if (Test-Path $existingMap) { |
| Copy-Item $existingMap $backupDir |
| Write-Status "Backed up student map" |
| } |
| Write-Success "Backup saved to: $backupDir" |
| } else { |
| Write-Host "Step 4: Skipping backup (disabled)" -ForegroundColor White |
| } |
|
|
| |
| Write-Host "Step 5: Deploying files..." -ForegroundColor White |
|
|
| |
| $faissDir = Join-Path $DataDir "faiss_indices" |
| New-Item -ItemType Directory -Path $faissDir -Force | Out-Null |
| $faissSource = Join-Path $tempDir "faiss_index.bin" |
| if (Test-Path $faissSource) { |
| Copy-Item $faissSource (Join-Path $faissDir "$SectionKey.index") -Force |
| Write-Success "FAISS index deployed" |
| } |
|
|
| |
| $mapDir = Join-Path $DataDir "student_maps" |
| New-Item -ItemType Directory -Path $mapDir -Force | Out-Null |
| $mapSource = Join-Path $tempDir "student_map.json" |
| if (Test-Path $mapSource) { |
| Copy-Item $mapSource (Join-Path $mapDir "${SectionKey}_map.json") -Force |
| Write-Success "Student map deployed" |
| } |
|
|
| |
| $configDir = Join-Path $DataDir ".." "config" |
| New-Item -ItemType Directory -Path $configDir -Force | Out-Null |
| $configSource = Join-Path $tempDir "edge_config.yaml" |
| if (Test-Path $configSource) { |
| Copy-Item $configSource (Join-Path $configDir "edge_config.yaml") -Force |
| Write-Success "Edge config deployed" |
| } |
|
|
| |
| $modelsSource = Join-Path $tempDir "models" |
| if (Test-Path $modelsSource) { |
| $modelsDir = Join-Path $DataDir ".." "models" |
| New-Item -ItemType Directory -Path $modelsDir -Force | Out-Null |
| Copy-Item "$modelsSource\*" $modelsDir -Recurse -Force |
| $modelCount = (Get-ChildItem $modelsSource -File).Count |
| Write-Success "Deployed $modelCount model files" |
| } |
|
|
| |
| Write-Host "Step 6: Cleanup..." -ForegroundColor White |
| Remove-Item -Recurse -Force $tempDir |
| Write-Success "Temporary files removed" |
|
|
| |
| Write-Host "" |
| Write-Host "ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ" -ForegroundColor Green |
| Write-Host "β β
Bundle deployed successfully! β" -ForegroundColor Green |
| Write-Host "ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ" -ForegroundColor Green |
| Write-Host "" |
| Write-Status "Section: $SectionKey" |
| Write-Status "Students: $($manifest.student_count)" |
| Write-Host "" |
| Write-Host " Next steps:" -ForegroundColor White |
| Write-Host " 1. Restart the edge service: docker restart smartclass-edge" -ForegroundColor Gray |
| Write-Host " 2. Check logs: docker logs -f smartclass-edge" -ForegroundColor Gray |
| Write-Host " 3. Verify metrics: curl http://localhost:9100/metrics" -ForegroundColor Gray |
| Write-Host "" |
|
|