Compare commits
17 Commits
5fd64ed768
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
428d9bac6b | ||
|
|
e568e02cdf | ||
| 18683b4ad0 | |||
|
|
b61baac09b | ||
|
|
2aa9061114 | ||
|
|
0b8f4f30fa | ||
|
|
3ef8b09737 | ||
|
|
7d253caeee | ||
|
|
2819ea6524 | ||
|
|
c0c82520f1 | ||
|
|
712c1215ed | ||
|
|
153c1d4a1e | ||
|
|
07a413e23f | ||
|
|
37bdfcb862 | ||
|
|
cd056df109 | ||
|
|
4070a0adf8 | ||
|
|
753f48e9d0 |
2
.specstory/.gitignore
vendored
2
.specstory/.gitignore
vendored
@@ -1,2 +1,4 @@
|
|||||||
# SpecStory explanation file
|
# SpecStory explanation file
|
||||||
/.what-is-this.md
|
/.what-is-this.md
|
||||||
|
# SpecStory project identity file
|
||||||
|
/.project.json
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
{
|
{
|
||||||
"workspace_id": "32e8-397e-7a7f-56c3",
|
"workspace_id": "32e8-397e-7a7f-56c3",
|
||||||
"workspace_id_at": "2025-04-28T20:11:59.428Z"
|
"workspace_id_at": "2025-04-28T20:11:59.428Z",
|
||||||
|
"project_name": "Flamenco-Management",
|
||||||
|
"cloud_sync": false,
|
||||||
|
"git_id": "23f5-5500-1564-9719",
|
||||||
|
"git_id_at": "2025-11-03T19:27:17.099Z"
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2112
.specstory/history/2025-11-19_17-03Z-why-is-git-frozen.md
Normal file
2112
.specstory/history/2025-11-19_17-03Z-why-is-git-frozen.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,45 @@
|
|||||||
|
<!-- Generated by SpecStory, Markdown v2.1.0 -->
|
||||||
|
|
||||||
|
<!-- cursor Session 21c1dff0-7d20-4158-84d9-19180276948d (2025-11-21 01:14Z) -->
|
||||||
|
|
||||||
|
# Workers failing and SSH connection issues (2025-11-21 01:14Z)
|
||||||
|
|
||||||
|
_**User (2025-11-21 01:14Z)**_
|
||||||
|
|
||||||
|
all workers are failing?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Connecting to i9kf...
|
||||||
|
|
||||||
|
exec request failed on channel 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SSH session ended.
|
||||||
|
|
||||||
|
Press Enter to close:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_**Agent (model gpt-5.1-codex, mode Agent)**_
|
||||||
|
|
||||||
|
<think><details><summary>Thought Process</summary>
|
||||||
|
**Checking workspace directory**</details></think>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<tool-use data-tool-type="generic" data-tool-name="list_dir">
|
||||||
|
<details>
|
||||||
|
<summary>Tool use: **list_directory** • Listed directory undefined • **0** results</summary>
|
||||||
|
|
||||||
|
No results found
|
||||||
|
</details>
|
||||||
|
</tool-use>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -1,2 +0,0 @@
|
|||||||
@echo off
|
|
||||||
powershell -ExecutionPolicy Bypass -File "%~dp0recover_blender-boss.ps1"
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
Write-Host "Connecting to blender-boss..."
|
|
||||||
|
|
||||||
try {
|
|
||||||
$remoteCommand = @'
|
|
||||||
Write-Host "Checking current network connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nDisconnecting from NEXUS shares..."
|
|
||||||
# First disconnect from specific NEXUS shares
|
|
||||||
net use \\NEXUS\amazon /delete /y 2>$null
|
|
||||||
net use \\NEXUS\flamenco /delete /y 2>$null
|
|
||||||
# Then disconnect any mapped drives
|
|
||||||
net use A: /delete /y 2>$null
|
|
||||||
net use F: /delete /y 2>$null
|
|
||||||
Write-Host "Existing NEXUS connections cleared."
|
|
||||||
|
|
||||||
Write-Host "`nMapping network drives..."
|
|
||||||
Write-Host "Connecting drives to NEXUS..."
|
|
||||||
|
|
||||||
# First connect to the share without a drive letter
|
|
||||||
Write-Host "Establishing initial NEXUS connection..."
|
|
||||||
net use \\NEXUS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Initial NEXUS connection established."
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
|
|
||||||
Write-Host "`nMapping A: drive..."
|
|
||||||
net use A: \\NEXUS\amazon /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "A: drive connected successfully."
|
|
||||||
|
|
||||||
Write-Host "`nMapping F: drive..."
|
|
||||||
net use F: \\NEXUS\flamenco /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "F: drive connected successfully."
|
|
||||||
|
|
||||||
# Copy files from C:\nexus\amazon to F:\renders
|
|
||||||
Write-Host "`nCopying files..."
|
|
||||||
robocopy "C:\nexus\amazon" "F:\renders" /E /MOVE
|
|
||||||
|
|
||||||
Write-Host "Operation completed successfully!"
|
|
||||||
|
|
||||||
# Delete the C:\NEXUS directory
|
|
||||||
Write-Host "`nDeleting C:\NEXUS directory..."
|
|
||||||
rmdir /s /q "C:\NEXUS"
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "C:\NEXUS directory deleted successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to delete C:\NEXUS directory" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect F: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect A: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to establish initial NEXUS connection" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nVerifying connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to continue..."
|
|
||||||
Read-Host
|
|
||||||
'@
|
|
||||||
|
|
||||||
# Encode the command to handle special characters
|
|
||||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($remoteCommand)
|
|
||||||
$encodedCommand = [Convert]::ToBase64String($bytes)
|
|
||||||
|
|
||||||
# Execute the encoded command on the remote machine
|
|
||||||
ssh -t blender-boss "powershell -EncodedCommand $encodedCommand"
|
|
||||||
|
|
||||||
} catch {
|
|
||||||
Write-Host "`nAn error occurred:" -ForegroundColor Red
|
|
||||||
Write-Host $_.Exception.Message -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to exit..."
|
|
||||||
Read-Host
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
@echo off
|
|
||||||
powershell -ExecutionPolicy Bypass -File "%~dp0recover_echo.ps1"
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
Write-Host "Connecting to echo..."
|
|
||||||
|
|
||||||
try {
|
|
||||||
$remoteCommand = @'
|
|
||||||
Write-Host "Checking current network connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nDisconnecting from NEXUS shares..."
|
|
||||||
# First disconnect from specific NEXUS shares
|
|
||||||
net use \\NEXUS\amazon /delete /y 2>$null
|
|
||||||
net use \\NEXUS\flamenco /delete /y 2>$null
|
|
||||||
# Then disconnect any mapped drives
|
|
||||||
net use A: /delete /y 2>$null
|
|
||||||
net use F: /delete /y 2>$null
|
|
||||||
Write-Host "Existing NEXUS connections cleared."
|
|
||||||
|
|
||||||
Write-Host "`nMapping network drives..."
|
|
||||||
Write-Host "Connecting drives to NEXUS..."
|
|
||||||
|
|
||||||
# First connect to the share without a drive letter
|
|
||||||
Write-Host "Establishing initial NEXUS connection..."
|
|
||||||
net use \\NEXUS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Initial NEXUS connection established."
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
|
|
||||||
Write-Host "`nMapping A: drive..."
|
|
||||||
net use A: \\NEXUS\amazon /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "A: drive connected successfully."
|
|
||||||
|
|
||||||
Write-Host "`nMapping F: drive..."
|
|
||||||
net use F: \\NEXUS\flamenco /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "F: drive connected successfully."
|
|
||||||
|
|
||||||
# Copy files from C:\nexus\amazon to F:\renders
|
|
||||||
Write-Host "`nCopying files..."
|
|
||||||
robocopy "C:\nexus\amazon" "F:\renders" /E /MOVE
|
|
||||||
|
|
||||||
Write-Host "Operation completed successfully!"
|
|
||||||
|
|
||||||
# Delete the C:\NEXUS directory
|
|
||||||
Write-Host "`nDeleting C:\NEXUS directory..."
|
|
||||||
rmdir /s /q "C:\NEXUS"
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "C:\NEXUS directory deleted successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to delete C:\NEXUS directory" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect F: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect A: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to establish initial NEXUS connection" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nVerifying connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to continue..."
|
|
||||||
Read-Host
|
|
||||||
'@
|
|
||||||
|
|
||||||
# Encode the command to handle special characters
|
|
||||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($remoteCommand)
|
|
||||||
$encodedCommand = [Convert]::ToBase64String($bytes)
|
|
||||||
|
|
||||||
# Execute the encoded command on the remote machine
|
|
||||||
ssh -t echo "powershell -EncodedCommand $encodedCommand"
|
|
||||||
|
|
||||||
} catch {
|
|
||||||
Write-Host "`nAn error occurred:" -ForegroundColor Red
|
|
||||||
Write-Host $_.Exception.Message -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to exit..."
|
|
||||||
Read-Host
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
# Script to handle network drive mapping and file copying
|
|
||||||
# Author: Nathan
|
|
||||||
# Date: 2025-04-23
|
|
||||||
|
|
||||||
# Function to check if a drive is mapped
|
|
||||||
function Test-DriveMapped {
|
|
||||||
param (
|
|
||||||
[string]$DriveLetter
|
|
||||||
)
|
|
||||||
$drive = Get-PSDrive -Name $DriveLetter -ErrorAction SilentlyContinue
|
|
||||||
return $null -ne $drive
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to remove a mapped drive
|
|
||||||
function Remove-MappedDrive {
|
|
||||||
param (
|
|
||||||
[string]$DriveLetter
|
|
||||||
)
|
|
||||||
if (Test-DriveMapped -DriveLetter $DriveLetter) {
|
|
||||||
Write-Host "Removing existing $DriveLetter drive mapping..."
|
|
||||||
Remove-PSDrive -Name $DriveLetter -Force
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to map a network drive
|
|
||||||
function Map-NetworkDrive {
|
|
||||||
param (
|
|
||||||
[string]$DriveLetter,
|
|
||||||
[string]$NetworkPath
|
|
||||||
)
|
|
||||||
Write-Host "Mapping $DriveLetter to $NetworkPath..."
|
|
||||||
New-PSDrive -Name $DriveLetter -PSProvider FileSystem -Root $NetworkPath -Persist
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to copy files using robocopy
|
|
||||||
function Copy-FilesWithRobocopy {
|
|
||||||
param (
|
|
||||||
[string]$SourcePath,
|
|
||||||
[string]$DestinationPath
|
|
||||||
)
|
|
||||||
Write-Host "Copying files from $SourcePath to $DestinationPath..."
|
|
||||||
robocopy $SourcePath $DestinationPath /E /MOVE
|
|
||||||
}
|
|
||||||
|
|
||||||
# Main script execution
|
|
||||||
try {
|
|
||||||
Write-Host "Checking current network connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nDisconnecting from NEXUS shares..."
|
|
||||||
# First disconnect from specific NEXUS shares
|
|
||||||
net use \\NEXUS\amazon /delete /y 2>$null
|
|
||||||
net use \\NEXUS\flamenco /delete /y 2>$null
|
|
||||||
# Then disconnect any mapped drives
|
|
||||||
net use A: /delete /y 2>$null
|
|
||||||
net use F: /delete /y 2>$null
|
|
||||||
Write-Host "Existing NEXUS connections cleared."
|
|
||||||
|
|
||||||
Write-Host "`nMapping network drives..."
|
|
||||||
Write-Host "Connecting drives to NEXUS..."
|
|
||||||
|
|
||||||
# First connect to the share without a drive letter
|
|
||||||
Write-Host "Establishing initial NEXUS connection..."
|
|
||||||
net use \\NEXUS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Initial NEXUS connection established."
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
|
|
||||||
Write-Host "`nMapping A: drive..."
|
|
||||||
net use A: \\NEXUS\amazon /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "A: drive connected successfully."
|
|
||||||
|
|
||||||
Write-Host "`nMapping F: drive..."
|
|
||||||
net use F: \\NEXUS\flamenco /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "F: drive connected successfully."
|
|
||||||
|
|
||||||
# Copy files from C:\nexus\amazon to F:\renders
|
|
||||||
Copy-FilesWithRobocopy -SourcePath "C:\nexus\amazon" -DestinationPath "F:\renders"
|
|
||||||
|
|
||||||
Write-Host "Operation completed successfully!"
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect F: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect A: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to establish initial NEXUS connection" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nVerifying connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
} catch {
|
|
||||||
Write-Error "An error occurred: $_"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
@echo off
|
|
||||||
powershell -ExecutionPolicy Bypass -File "%~dp0recover_i9-13ks.ps1"
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
Write-Host "Connecting to i9-13ks..."
|
|
||||||
|
|
||||||
try {
|
|
||||||
$remoteCommand = @'
|
|
||||||
Write-Host "Checking current network connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nDisconnecting from NEXUS shares..."
|
|
||||||
# First disconnect from specific NEXUS shares
|
|
||||||
net use \\NEXUS\amazon /delete /y 2>$null
|
|
||||||
net use \\NEXUS\flamenco /delete /y 2>$null
|
|
||||||
# Then disconnect any mapped drives
|
|
||||||
net use A: /delete /y 2>$null
|
|
||||||
net use F: /delete /y 2>$null
|
|
||||||
Write-Host "Existing NEXUS connections cleared."
|
|
||||||
|
|
||||||
Write-Host "`nMapping network drives..."
|
|
||||||
Write-Host "Connecting drives to NEXUS..."
|
|
||||||
|
|
||||||
# First connect to the share without a drive letter
|
|
||||||
Write-Host "Establishing initial NEXUS connection..."
|
|
||||||
net use \\NEXUS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Initial NEXUS connection established."
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
|
|
||||||
Write-Host "`nMapping A: drive..."
|
|
||||||
net use A: \\NEXUS\amazon /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "A: drive connected successfully."
|
|
||||||
|
|
||||||
Write-Host "`nMapping F: drive..."
|
|
||||||
net use F: \\NEXUS\flamenco /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "F: drive connected successfully."
|
|
||||||
|
|
||||||
# Copy files from C:\nexus\amazon to F:\renders
|
|
||||||
Write-Host "`nCopying files..."
|
|
||||||
robocopy "C:\nexus\amazon" "F:\renders" /E /MOVE
|
|
||||||
|
|
||||||
Write-Host "Operation completed successfully!"
|
|
||||||
|
|
||||||
# Delete the C:\NEXUS directory
|
|
||||||
Write-Host "`nDeleting C:\NEXUS directory..."
|
|
||||||
rmdir /s /q "C:\NEXUS"
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "C:\NEXUS directory deleted successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to delete C:\NEXUS directory" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect F: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect A: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to establish initial NEXUS connection" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nVerifying connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to continue..."
|
|
||||||
Read-Host
|
|
||||||
'@
|
|
||||||
|
|
||||||
# Encode the command to handle special characters
|
|
||||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($remoteCommand)
|
|
||||||
$encodedCommand = [Convert]::ToBase64String($bytes)
|
|
||||||
|
|
||||||
# Execute the encoded command on the remote machine
|
|
||||||
ssh -t i9-13ks "powershell -EncodedCommand $encodedCommand"
|
|
||||||
|
|
||||||
} catch {
|
|
||||||
Write-Host "`nAn error occurred:" -ForegroundColor Red
|
|
||||||
Write-Host $_.Exception.Message -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to exit..."
|
|
||||||
Read-Host
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
@echo off
|
|
||||||
powershell -ExecutionPolicy Bypass -File "%~dp0recover_masterbox.ps1"
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
Write-Host "Connecting to masterbox..."
|
|
||||||
|
|
||||||
try {
|
|
||||||
$remoteCommand = @'
|
|
||||||
Write-Host "Checking current network connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nDisconnecting from NEXUS shares..."
|
|
||||||
# First disconnect from specific NEXUS shares
|
|
||||||
net use \\NEXUS\amazon /delete /y 2>$null
|
|
||||||
net use \\NEXUS\flamenco /delete /y 2>$null
|
|
||||||
# Then disconnect any mapped drives
|
|
||||||
net use A: /delete /y 2>$null
|
|
||||||
net use F: /delete /y 2>$null
|
|
||||||
Write-Host "Existing NEXUS connections cleared."
|
|
||||||
|
|
||||||
Write-Host "`nMapping network drives..."
|
|
||||||
Write-Host "Connecting drives to NEXUS..."
|
|
||||||
|
|
||||||
# First connect to the share without a drive letter
|
|
||||||
Write-Host "Establishing initial NEXUS connection..."
|
|
||||||
net use \\NEXUS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Initial NEXUS connection established."
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
|
|
||||||
Write-Host "`nMapping A: drive..."
|
|
||||||
net use A: \\NEXUS\amazon /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "A: drive connected successfully."
|
|
||||||
|
|
||||||
Write-Host "`nMapping F: drive..."
|
|
||||||
net use F: \\NEXUS\flamenco /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "F: drive connected successfully."
|
|
||||||
|
|
||||||
# Copy files from C:\nexus\amazon to F:\renders
|
|
||||||
Write-Host "`nCopying files..."
|
|
||||||
robocopy "C:\nexus\amazon" "F:\renders" /E /MOVE
|
|
||||||
|
|
||||||
Write-Host "Operation completed successfully!"
|
|
||||||
|
|
||||||
# Delete the C:\NEXUS directory
|
|
||||||
Write-Host "`nDeleting C:\NEXUS directory..."
|
|
||||||
rmdir /s /q "C:\NEXUS"
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "C:\NEXUS directory deleted successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to delete C:\NEXUS directory" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect F: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect A: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to establish initial NEXUS connection" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nVerifying connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to continue..."
|
|
||||||
Read-Host
|
|
||||||
'@
|
|
||||||
|
|
||||||
# Encode the command to handle special characters
|
|
||||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($remoteCommand)
|
|
||||||
$encodedCommand = [Convert]::ToBase64String($bytes)
|
|
||||||
|
|
||||||
# Execute the encoded command on the remote machine
|
|
||||||
ssh -t masterbox "powershell -EncodedCommand $encodedCommand"
|
|
||||||
|
|
||||||
} catch {
|
|
||||||
Write-Host "`nAn error occurred:" -ForegroundColor Red
|
|
||||||
Write-Host $_.Exception.Message -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to exit..."
|
|
||||||
Read-Host
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
@echo off
|
|
||||||
powershell -ExecutionPolicy Bypass -File "%~dp0recover_max.ps1"
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
Write-Host "Connecting to max..."
|
|
||||||
|
|
||||||
try {
|
|
||||||
$remoteCommand = @'
|
|
||||||
Write-Host "Checking current network connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nDisconnecting from NEXUS shares..."
|
|
||||||
# First disconnect from specific NEXUS shares
|
|
||||||
net use \\NEXUS\amazon /delete /y 2>$null
|
|
||||||
net use \\NEXUS\flamenco /delete /y 2>$null
|
|
||||||
# Then disconnect any mapped drives
|
|
||||||
net use A: /delete /y 2>$null
|
|
||||||
net use F: /delete /y 2>$null
|
|
||||||
Write-Host "Existing NEXUS connections cleared."
|
|
||||||
|
|
||||||
Write-Host "`nMapping network drives..."
|
|
||||||
Write-Host "Connecting drives to NEXUS..."
|
|
||||||
|
|
||||||
# First connect to the share without a drive letter
|
|
||||||
Write-Host "Establishing initial NEXUS connection..."
|
|
||||||
net use \\NEXUS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Initial NEXUS connection established."
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
|
|
||||||
Write-Host "`nMapping A: drive..."
|
|
||||||
net use A: \\NEXUS\amazon /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "A: drive connected successfully."
|
|
||||||
|
|
||||||
Write-Host "`nMapping F: drive..."
|
|
||||||
net use F: \\NEXUS\flamenco /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "F: drive connected successfully."
|
|
||||||
|
|
||||||
# Copy files from C:\nexus\amazon to F:\renders
|
|
||||||
Write-Host "`nCopying files..."
|
|
||||||
robocopy "C:\nexus\amazon" "F:\renders" /E /MOVE
|
|
||||||
|
|
||||||
Write-Host "Operation completed successfully!"
|
|
||||||
|
|
||||||
# Delete the C:\NEXUS directory
|
|
||||||
Write-Host "`nDeleting C:\NEXUS directory..."
|
|
||||||
rmdir /s /q "C:\NEXUS"
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "C:\NEXUS directory deleted successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to delete C:\NEXUS directory" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect F: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect A: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to establish initial NEXUS connection" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nVerifying connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to continue..."
|
|
||||||
Read-Host
|
|
||||||
'@
|
|
||||||
|
|
||||||
# Encode the command to handle special characters
|
|
||||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($remoteCommand)
|
|
||||||
$encodedCommand = [Convert]::ToBase64String($bytes)
|
|
||||||
|
|
||||||
# Execute the encoded command on the remote machine
|
|
||||||
ssh -t max "powershell -EncodedCommand $encodedCommand"
|
|
||||||
|
|
||||||
} catch {
|
|
||||||
Write-Host "`nAn error occurred:" -ForegroundColor Red
|
|
||||||
Write-Host $_.Exception.Message -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to exit..."
|
|
||||||
Read-Host
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
@echo off
|
|
||||||
title Flamenco CMD Worker Launcher
|
|
||||||
echo Starting Flamenco CMD Worker Launcher...
|
|
||||||
powershell -ExecutionPolicy Bypass -File "%~dp0cmd_run_flamenco_workers.ps1"
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
# Unified Flamenco Worker Connection Script (CMD VERSION)
|
|
||||||
Write-Host "====================================" -ForegroundColor Cyan
|
|
||||||
Write-Host " FLAMENCO CMD WORKER LAUNCHER" -ForegroundColor Cyan
|
|
||||||
Write-Host "====================================" -ForegroundColor Cyan
|
|
||||||
Write-Host
|
|
||||||
|
|
||||||
# Define available systems
|
|
||||||
$systems = @(
|
|
||||||
@{ ID = 1; Name = "masterbox"; ScriptPath = "run_masterbox_cmd.ps1"; BatchPath = "run_masterbox_cmd.bat" },
|
|
||||||
@{ ID = 2; Name = "i9-13ks"; ScriptPath = "run_i9-13ks_cmd.ps1"; BatchPath = "run_i9-13ks_cmd.bat" },
|
|
||||||
@{ ID = 3; Name = "max"; ScriptPath = "run_max_cmd.ps1"; BatchPath = "run_max_cmd.bat" },
|
|
||||||
@{ ID = 4; Name = "echo"; ScriptPath = "run_echo_cmd.ps1"; BatchPath = "run_echo_cmd.bat" },
|
|
||||||
@{ ID = 5; Name = "blender-boss"; ScriptPath = "run_blender-boss_cmd.ps1"; BatchPath = "run_blender-boss_cmd.bat" }
|
|
||||||
)
|
|
||||||
|
|
||||||
# Print menu options
|
|
||||||
Write-Host "Select a system to connect to (CMD VERSION):" -ForegroundColor Yellow
|
|
||||||
foreach ($system in $systems) {
|
|
||||||
Write-Host "$($system.ID). $($system.Name)" -ForegroundColor Green
|
|
||||||
}
|
|
||||||
Write-Host "0. Connect to ALL systems (separate windows)" -ForegroundColor Magenta
|
|
||||||
Write-Host
|
|
||||||
|
|
||||||
# Get user selection
|
|
||||||
$selection = Read-Host "Enter your selection (0-$($systems.Count))"
|
|
||||||
|
|
||||||
# Process selection
|
|
||||||
if ($selection -eq "0") {
|
|
||||||
# Launch all systems in separate windows
|
|
||||||
Write-Host "Launching all worker scripts in separate windows..." -ForegroundColor Cyan
|
|
||||||
|
|
||||||
foreach ($system in $systems) {
|
|
||||||
$scriptPath = Join-Path (Get-Location) $system.BatchPath
|
|
||||||
Start-Process "cmd.exe" -ArgumentList "/c $scriptPath" -WindowStyle Normal
|
|
||||||
Write-Host "Started $($system.Name) worker in a new window." -ForegroundColor Green
|
|
||||||
Start-Sleep -Seconds 2 # Add a small delay between launches
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nAll worker scripts have been launched." -ForegroundColor Cyan
|
|
||||||
Write-Host "Each worker is running in its own command window." -ForegroundColor Yellow
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
# Find the selected system
|
|
||||||
$selectedSystem = $systems | Where-Object { $_.ID -eq [int]$selection }
|
|
||||||
|
|
||||||
if ($selectedSystem) {
|
|
||||||
Write-Host "Launching $($selectedSystem.Name) worker script..." -ForegroundColor Cyan
|
|
||||||
|
|
||||||
# Execute the PowerShell script directly
|
|
||||||
$scriptPath = Join-Path (Get-Location) $selectedSystem.ScriptPath
|
|
||||||
& $scriptPath
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Write-Host "Invalid selection. Please run the script again." -ForegroundColor Red
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to exit..."
|
|
||||||
$null = Read-Host
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
@echo off
|
|
||||||
powershell -ExecutionPolicy Bypass -File "%~dp0run_blender-boss_cmd.ps1"
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
Write-Host "Connecting to blender-boss..."
|
|
||||||
|
|
||||||
try {
|
|
||||||
$remoteCommand = @'
|
|
||||||
Write-Host "Checking current network connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nDisconnecting from NEXUS shares..."
|
|
||||||
# First disconnect from specific NEXUS shares
|
|
||||||
net use \\NEXUS\amazon /delete /y 2>$null
|
|
||||||
net use \\NEXUS\flamenco /delete /y 2>$null
|
|
||||||
net use \\NAS\amazon /delete /y 2>$null
|
|
||||||
# Then disconnect any mapped drives
|
|
||||||
net use A: /delete /y 2>$null
|
|
||||||
net use F: /delete /y 2>$null
|
|
||||||
net use N: /delete /y 2>$null
|
|
||||||
Write-Host "Existing NEXUS connections cleared."
|
|
||||||
|
|
||||||
Write-Host "`nMapping network drives..."
|
|
||||||
Write-Host "Connecting drives to NEXUS..."
|
|
||||||
|
|
||||||
# First connect to the share without a drive letter
|
|
||||||
Write-Host "Establishing initial NEXUS connection..."
|
|
||||||
net use \\NEXUS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Initial NEXUS connection established."
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
|
|
||||||
Write-Host "`nMapping A: drive..."
|
|
||||||
net use A: \\NEXUS\amazon /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "A: drive connected successfully."
|
|
||||||
|
|
||||||
Write-Host "`nMapping F: drive..."
|
|
||||||
net use F: \\NEXUS\flamenco /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "F: drive connected successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect F: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect A: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to establish initial NEXUS connection" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nMapping N: drive..."
|
|
||||||
net use N: \\NAS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "N: drive connected successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect N: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nVerifying connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nRunning command file..."
|
|
||||||
$cmdFilePath = "F:\software\Flamenco 3.6\run-flamenco-worker.cmd"
|
|
||||||
$cmdDirectory = "F:\software\Flamenco 3.6"
|
|
||||||
|
|
||||||
if (Test-Path $cmdFilePath) {
|
|
||||||
Write-Host "Starting $cmdFilePath..."
|
|
||||||
# Change to the directory containing the CMD file first
|
|
||||||
Set-Location $cmdDirectory
|
|
||||||
# Run the CMD file
|
|
||||||
cmd /c $cmdFilePath
|
|
||||||
} else {
|
|
||||||
Write-Host "Error: Command file not found at $cmdFilePath" -ForegroundColor Red
|
|
||||||
$customPath = Read-Host "Enter the path to your .cmd file"
|
|
||||||
if (Test-Path $customPath) {
|
|
||||||
Write-Host "Starting $customPath..."
|
|
||||||
# Get the directory of the custom path
|
|
||||||
$customDirectory = Split-Path -Parent $customPath
|
|
||||||
# Change to the directory containing the CMD file
|
|
||||||
Set-Location $customDirectory
|
|
||||||
# Run the custom path CMD file
|
|
||||||
cmd /c $customPath
|
|
||||||
} else {
|
|
||||||
Write-Host "Error: Command file not found at custom path" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to continue..."
|
|
||||||
Read-Host
|
|
||||||
'@
|
|
||||||
|
|
||||||
# Encode the command to handle special characters
|
|
||||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($remoteCommand)
|
|
||||||
$encodedCommand = [Convert]::ToBase64String($bytes)
|
|
||||||
|
|
||||||
# Execute the encoded command on the remote machine
|
|
||||||
ssh -t blender-boss "powershell -EncodedCommand $encodedCommand"
|
|
||||||
|
|
||||||
} catch {
|
|
||||||
Write-Host "`nAn error occurred:" -ForegroundColor Red
|
|
||||||
Write-Host $_.Exception.Message -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to exit..."
|
|
||||||
Read-Host
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
@echo off
|
|
||||||
powershell.exe -NoExit -ExecutionPolicy Bypass -File "%~dp0run_blender-boss_worker.ps1"
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
Write-Host "Connecting to blender-boss..."
|
|
||||||
|
|
||||||
try {
|
|
||||||
$remoteCommand = @'
|
|
||||||
Write-Host "Checking current network connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nDisconnecting from NEXUS shares..."
|
|
||||||
# First disconnect from specific NEXUS shares
|
|
||||||
net use \\NEXUS\amazon /delete /y 2>$null
|
|
||||||
net use \\NEXUS\flamenco /delete /y 2>$null
|
|
||||||
net use \\NAS\amazon /delete /y 2>$null
|
|
||||||
# Then disconnect any mapped drives
|
|
||||||
net use A: /delete /y 2>$null
|
|
||||||
net use F: /delete /y 2>$null
|
|
||||||
net use N: /delete /y 2>$null
|
|
||||||
Write-Host "Existing NEXUS connections cleared."
|
|
||||||
|
|
||||||
$response = Read-Host "`nDo you want to stop any existing Flamenco workers? (y/n)"
|
|
||||||
if ($response -eq 'y') {
|
|
||||||
taskkill /IM flamenco-worker.exe /F 2>$null
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Worker process terminated."
|
|
||||||
} else {
|
|
||||||
Write-Host "No worker process found."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nMapping network drives..."
|
|
||||||
Write-Host "Connecting drives to NEXUS..."
|
|
||||||
|
|
||||||
# First connect to the share without a drive letter
|
|
||||||
Write-Host "Establishing initial NEXUS connection..."
|
|
||||||
net use \\NEXUS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Initial NEXUS connection established."
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
|
|
||||||
Write-Host "`nMapping A: drive..."
|
|
||||||
net use A: \\NEXUS\amazon /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "A: drive connected successfully."
|
|
||||||
|
|
||||||
Write-Host "`nMapping F: drive..."
|
|
||||||
net use F: \\NEXUS\flamenco /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "F: drive connected successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect F: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect A: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to establish initial NEXUS connection" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nMapping N: drive..."
|
|
||||||
net use N: \\NAS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "N: drive connected successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect N: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nVerifying connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nStarting Flamenco worker..."
|
|
||||||
if (Test-Path "C:\Program Files\Blender Foundation\Flamenco 3.6") {
|
|
||||||
Set-Location "C:\Program Files\Blender Foundation\Flamenco 3.6"
|
|
||||||
if (Test-Path "flamenco-worker.exe") {
|
|
||||||
Write-Host "Running flamenco-worker.exe directly..."
|
|
||||||
# Run the executable directly in the console instead of using Start-Process
|
|
||||||
.\flamenco-worker.exe
|
|
||||||
# This line will only execute after the worker process terminates
|
|
||||||
Write-Host "Flamenco worker process has terminated."
|
|
||||||
} else {
|
|
||||||
Write-Host "Error: flamenco-worker.exe not found in Flamenco directory" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Error: Flamenco directory not found" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to continue..."
|
|
||||||
Read-Host
|
|
||||||
'@
|
|
||||||
|
|
||||||
# Encode the command to handle special characters
|
|
||||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($remoteCommand)
|
|
||||||
$encodedCommand = [Convert]::ToBase64String($bytes)
|
|
||||||
|
|
||||||
# Execute the encoded command on the remote machine
|
|
||||||
ssh -t blender-boss "powershell -EncodedCommand $encodedCommand"
|
|
||||||
|
|
||||||
} catch {
|
|
||||||
Write-Host "`nAn error occurred:" -ForegroundColor Red
|
|
||||||
Write-Host $_.Exception.Message -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to exit..."
|
|
||||||
Read-Host
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
@echo off
|
|
||||||
powershell -ExecutionPolicy Bypass -File "%~dp0run_echo_cmd.ps1"
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
Write-Host "Connecting to echo..."
|
|
||||||
|
|
||||||
try {
|
|
||||||
$remoteCommand = @'
|
|
||||||
Write-Host "Checking current network connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nDisconnecting from NEXUS shares..."
|
|
||||||
# First disconnect from specific NEXUS shares
|
|
||||||
net use \\NEXUS\amazon /delete /y 2>$null
|
|
||||||
net use \\NEXUS\flamenco /delete /y 2>$null
|
|
||||||
net use \\NAS\amazon /delete /y 2>$null
|
|
||||||
# Then disconnect any mapped drives
|
|
||||||
net use A: /delete /y 2>$null
|
|
||||||
net use F: /delete /y 2>$null
|
|
||||||
net use N: /delete /y 2>$null
|
|
||||||
Write-Host "Existing NEXUS connections cleared."
|
|
||||||
|
|
||||||
Write-Host "`nMapping network drives..."
|
|
||||||
Write-Host "Connecting drives to NEXUS..."
|
|
||||||
|
|
||||||
# First connect to the share without a drive letter
|
|
||||||
Write-Host "Establishing initial NEXUS connection..."
|
|
||||||
net use \\NEXUS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Initial NEXUS connection established."
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
|
|
||||||
Write-Host "`nMapping A: drive..."
|
|
||||||
net use A: \\NEXUS\amazon /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "A: drive connected successfully."
|
|
||||||
|
|
||||||
Write-Host "`nMapping F: drive..."
|
|
||||||
net use F: \\NEXUS\flamenco /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "F: drive connected successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect F: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect A: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to establish initial NEXUS connection" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nMapping N: drive..."
|
|
||||||
net use N: \\NAS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "N: drive connected successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect N: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nVerifying connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nRunning command file..."
|
|
||||||
$cmdFilePath = "F:\software\Flamenco 3.6\run-flamenco-worker.cmd"
|
|
||||||
$cmdDirectory = "F:\software\Flamenco 3.6"
|
|
||||||
|
|
||||||
if (Test-Path $cmdFilePath) {
|
|
||||||
Write-Host "Starting $cmdFilePath..."
|
|
||||||
# Change to the directory containing the CMD file first
|
|
||||||
Set-Location $cmdDirectory
|
|
||||||
# Run the CMD file
|
|
||||||
cmd /c $cmdFilePath
|
|
||||||
} else {
|
|
||||||
Write-Host "Error: Command file not found at $cmdFilePath" -ForegroundColor Red
|
|
||||||
$customPath = Read-Host "Enter the path to your .cmd file"
|
|
||||||
if (Test-Path $customPath) {
|
|
||||||
Write-Host "Starting $customPath..."
|
|
||||||
# Get the directory of the custom path
|
|
||||||
$customDirectory = Split-Path -Parent $customPath
|
|
||||||
# Change to the directory containing the CMD file
|
|
||||||
Set-Location $customDirectory
|
|
||||||
# Run the custom path CMD file
|
|
||||||
cmd /c $customPath
|
|
||||||
} else {
|
|
||||||
Write-Host "Error: Command file not found at custom path" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to continue..."
|
|
||||||
Read-Host
|
|
||||||
'@
|
|
||||||
|
|
||||||
# Encode the command to handle special characters
|
|
||||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($remoteCommand)
|
|
||||||
$encodedCommand = [Convert]::ToBase64String($bytes)
|
|
||||||
|
|
||||||
# Execute the encoded command on the remote machine
|
|
||||||
ssh -t echo "powershell -EncodedCommand $encodedCommand"
|
|
||||||
|
|
||||||
} catch {
|
|
||||||
Write-Host "`nAn error occurred:" -ForegroundColor Red
|
|
||||||
Write-Host $_.Exception.Message -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to exit..."
|
|
||||||
Read-Host
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
@echo off
|
|
||||||
powershell.exe -NoExit -ExecutionPolicy Bypass -File "%~dp0run_echo_worker.ps1"
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
Write-Host "Connecting to echo..."
|
|
||||||
|
|
||||||
try {
|
|
||||||
$remoteCommand = @'
|
|
||||||
Write-Host "Checking current network connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nDisconnecting from NEXUS shares..."
|
|
||||||
# First disconnect from specific NEXUS shares
|
|
||||||
net use \\NEXUS\amazon /delete /y 2>$null
|
|
||||||
net use \\NEXUS\flamenco /delete /y 2>$null
|
|
||||||
net use \\NAS\amazon /delete /y 2>$null
|
|
||||||
# Then disconnect any mapped drives
|
|
||||||
net use A: /delete /y 2>$null
|
|
||||||
net use F: /delete /y 2>$null
|
|
||||||
net use N: /delete /y 2>$null
|
|
||||||
Write-Host "Existing NEXUS connections cleared."
|
|
||||||
|
|
||||||
$response = Read-Host "`nDo you want to stop any existing Flamenco workers? (y/n)"
|
|
||||||
if ($response -eq 'y') {
|
|
||||||
taskkill /IM flamenco-worker.exe /F 2>$null
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Worker process terminated."
|
|
||||||
} else {
|
|
||||||
Write-Host "No worker process found."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nMapping network drives..."
|
|
||||||
Write-Host "Connecting drives to NEXUS..."
|
|
||||||
|
|
||||||
# First connect to the share without a drive letter
|
|
||||||
Write-Host "Establishing initial NEXUS connection..."
|
|
||||||
net use \\NEXUS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Initial NEXUS connection established."
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
|
|
||||||
Write-Host "`nMapping A: drive..."
|
|
||||||
net use A: \\NEXUS\amazon /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "A: drive connected successfully."
|
|
||||||
|
|
||||||
Write-Host "`nMapping F: drive..."
|
|
||||||
net use F: \\NEXUS\flamenco /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "F: drive connected successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect F: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect A: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to establish initial NEXUS connection" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nMapping N: drive..."
|
|
||||||
net use N: \\NAS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "N: drive connected successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect N: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nVerifying connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nStarting Flamenco worker..."
|
|
||||||
if (Test-Path "C:\Program Files\Blender Foundation\Flamenco 3.6") {
|
|
||||||
Set-Location "C:\Program Files\Blender Foundation\Flamenco 3.6"
|
|
||||||
if (Test-Path "flamenco-worker.exe") {
|
|
||||||
Write-Host "Running flamenco-worker.exe directly..."
|
|
||||||
# Run the executable directly in the console instead of using Start-Process
|
|
||||||
.\flamenco-worker.exe
|
|
||||||
# This line will only execute after the worker process terminates
|
|
||||||
Write-Host "Flamenco worker process has terminated."
|
|
||||||
} else {
|
|
||||||
Write-Host "Error: flamenco-worker.exe not found in Flamenco directory" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Error: Flamenco directory not found" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to continue..."
|
|
||||||
Read-Host
|
|
||||||
'@
|
|
||||||
|
|
||||||
# Encode the command to handle special characters
|
|
||||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($remoteCommand)
|
|
||||||
$encodedCommand = [Convert]::ToBase64String($bytes)
|
|
||||||
|
|
||||||
# Execute the encoded command on the remote machine
|
|
||||||
ssh -t echo "powershell -EncodedCommand $encodedCommand"
|
|
||||||
|
|
||||||
} catch {
|
|
||||||
Write-Host "`nAn error occurred:" -ForegroundColor Red
|
|
||||||
Write-Host $_.Exception.Message -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to exit..."
|
|
||||||
Read-Host
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
@echo off
|
|
||||||
title Flamenco Worker Launcher
|
|
||||||
echo Starting Flamenco Worker Launcher...
|
|
||||||
powershell -ExecutionPolicy Bypass -File "%~dp0run_flamenco_workers.ps1"
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
# Unified Flamenco Worker Connection Script (STANDARD VERSION)
|
|
||||||
Write-Host "====================================" -ForegroundColor Cyan
|
|
||||||
Write-Host " FLAMENCO WORKER LAUNCHER" -ForegroundColor Cyan
|
|
||||||
Write-Host "====================================" -ForegroundColor Cyan
|
|
||||||
Write-Host
|
|
||||||
|
|
||||||
# Define available systems
|
|
||||||
$systems = @(
|
|
||||||
@{ ID = 1; Name = "masterbox"; ScriptPath = "run_masterbox_worker.ps1"; BatchPath = "run_masterbox_worker.bat" },
|
|
||||||
@{ ID = 2; Name = "i9-13ks"; ScriptPath = "run_i9-13ks_worker.ps1"; BatchPath = "run_i9-13ks_worker.bat" },
|
|
||||||
@{ ID = 3; Name = "max"; ScriptPath = "run_max_worker.ps1"; BatchPath = "run_max_worker.bat" },
|
|
||||||
@{ ID = 4; Name = "echo"; ScriptPath = "run_echo_worker.ps1"; BatchPath = "run_echo_worker.bat" },
|
|
||||||
@{ ID = 5; Name = "blender-boss"; ScriptPath = "run_blender-boss_worker.ps1"; BatchPath = "run_blender-boss_worker.bat" }
|
|
||||||
)
|
|
||||||
|
|
||||||
# Print menu options
|
|
||||||
Write-Host "Select a system to connect to:" -ForegroundColor Yellow
|
|
||||||
foreach ($system in $systems) {
|
|
||||||
Write-Host "$($system.ID). $($system.Name)" -ForegroundColor Green
|
|
||||||
}
|
|
||||||
Write-Host "0. Connect to ALL systems (separate windows)" -ForegroundColor Magenta
|
|
||||||
Write-Host
|
|
||||||
|
|
||||||
# Get user selection
|
|
||||||
$selection = Read-Host "Enter your selection (0-$($systems.Count))"
|
|
||||||
|
|
||||||
# Process selection
|
|
||||||
if ($selection -eq "0") {
|
|
||||||
# Launch all systems in separate windows
|
|
||||||
Write-Host "Launching all worker scripts in separate windows..." -ForegroundColor Cyan
|
|
||||||
|
|
||||||
foreach ($system in $systems) {
|
|
||||||
$scriptPath = Join-Path (Get-Location) $system.BatchPath
|
|
||||||
Start-Process "cmd.exe" -ArgumentList "/c $scriptPath" -WindowStyle Normal
|
|
||||||
Write-Host "Started $($system.Name) worker in a new window." -ForegroundColor Green
|
|
||||||
Start-Sleep -Seconds 2 # Add a small delay between launches
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nAll worker scripts have been launched." -ForegroundColor Cyan
|
|
||||||
Write-Host "Each worker is running in its own command window." -ForegroundColor Yellow
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
# Find the selected system
|
|
||||||
$selectedSystem = $systems | Where-Object { $_.ID -eq [int]$selection }
|
|
||||||
|
|
||||||
if ($selectedSystem) {
|
|
||||||
Write-Host "Launching $($selectedSystem.Name) worker script..." -ForegroundColor Cyan
|
|
||||||
|
|
||||||
# Execute the PowerShell script directly
|
|
||||||
$scriptPath = Join-Path (Get-Location) $selectedSystem.ScriptPath
|
|
||||||
& $scriptPath
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Write-Host "Invalid selection. Please run the script again." -ForegroundColor Red
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to exit..."
|
|
||||||
$null = Read-Host
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
@echo off
|
|
||||||
powershell -ExecutionPolicy Bypass -File "%~dp0run_i9-13ks_cmd.ps1"
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
Write-Host "Connecting to i9-13ks..."
|
|
||||||
|
|
||||||
try {
|
|
||||||
$remoteCommand = @'
|
|
||||||
Write-Host "Checking current network connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nDisconnecting from NEXUS shares..."
|
|
||||||
# First disconnect from specific NEXUS shares
|
|
||||||
net use \\NEXUS\amazon /delete /y 2>$null
|
|
||||||
net use \\NEXUS\flamenco /delete /y 2>$null
|
|
||||||
net use \\NAS\amazon /delete /y 2>$null
|
|
||||||
# Then disconnect any mapped drives
|
|
||||||
net use A: /delete /y 2>$null
|
|
||||||
net use F: /delete /y 2>$null
|
|
||||||
net use N: /delete /y 2>$null
|
|
||||||
Write-Host "Existing NEXUS connections cleared."
|
|
||||||
|
|
||||||
Write-Host "`nMapping network drives..."
|
|
||||||
Write-Host "Connecting drives to NEXUS..."
|
|
||||||
|
|
||||||
# First connect to the share without a drive letter
|
|
||||||
Write-Host "Establishing initial NEXUS connection..."
|
|
||||||
net use \\NEXUS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Initial NEXUS connection established."
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
|
|
||||||
Write-Host "`nMapping A: drive..."
|
|
||||||
net use A: \\NEXUS\amazon /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "A: drive connected successfully."
|
|
||||||
|
|
||||||
Write-Host "`nMapping F: drive..."
|
|
||||||
net use F: \\NEXUS\flamenco /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "F: drive connected successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect F: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect A: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to establish initial NEXUS connection" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nMapping N: drive..."
|
|
||||||
net use N: \\NAS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "N: drive connected successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect N: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nVerifying connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nRunning command file..."
|
|
||||||
$cmdFilePath = "F:\software\Flamenco 3.6\run-flamenco-worker.cmd"
|
|
||||||
$cmdDirectory = "F:\software\Flamenco 3.6"
|
|
||||||
|
|
||||||
if (Test-Path $cmdFilePath) {
|
|
||||||
Write-Host "Starting $cmdFilePath..."
|
|
||||||
# Change to the directory containing the CMD file first
|
|
||||||
Set-Location $cmdDirectory
|
|
||||||
# Run the CMD file
|
|
||||||
cmd /c $cmdFilePath
|
|
||||||
} else {
|
|
||||||
Write-Host "Error: Command file not found at $cmdFilePath" -ForegroundColor Red
|
|
||||||
$customPath = Read-Host "Enter the path to your .cmd file"
|
|
||||||
if (Test-Path $customPath) {
|
|
||||||
Write-Host "Starting $customPath..."
|
|
||||||
# Get the directory of the custom path
|
|
||||||
$customDirectory = Split-Path -Parent $customPath
|
|
||||||
# Change to the directory containing the CMD file
|
|
||||||
Set-Location $customDirectory
|
|
||||||
# Run the custom path CMD file
|
|
||||||
cmd /c $customPath
|
|
||||||
} else {
|
|
||||||
Write-Host "Error: Command file not found at custom path" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to continue..."
|
|
||||||
Read-Host
|
|
||||||
'@
|
|
||||||
|
|
||||||
# Encode the command to handle special characters
|
|
||||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($remoteCommand)
|
|
||||||
$encodedCommand = [Convert]::ToBase64String($bytes)
|
|
||||||
|
|
||||||
# Execute the encoded command on the remote machine
|
|
||||||
ssh -t -p 22146 i9-13ks "powershell -EncodedCommand $encodedCommand"
|
|
||||||
|
|
||||||
} catch {
|
|
||||||
Write-Host "`nAn error occurred:" -ForegroundColor Red
|
|
||||||
Write-Host $_.Exception.Message -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to exit..."
|
|
||||||
Read-Host
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
@echo off
|
|
||||||
powershell.exe -NoExit -ExecutionPolicy Bypass -File "%~dp0run_i9-13ks_worker.ps1"
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
Write-Host "Connecting to i9-13ks..."
|
|
||||||
|
|
||||||
try {
|
|
||||||
$remoteCommand = @'
|
|
||||||
Write-Host "Checking current network connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nDisconnecting from NEXUS shares..."
|
|
||||||
# First disconnect from specific NEXUS shares
|
|
||||||
net use \\NEXUS\amazon /delete /y 2>$null
|
|
||||||
net use \\NEXUS\flamenco /delete /y 2>$null
|
|
||||||
net use \\NAS\amazon /delete /y 2>$null
|
|
||||||
# Then disconnect any mapped drives
|
|
||||||
net use A: /delete /y 2>$null
|
|
||||||
net use F: /delete /y 2>$null
|
|
||||||
net use N: /delete /y 2>$null
|
|
||||||
Write-Host "Existing NEXUS connections cleared."
|
|
||||||
|
|
||||||
$response = Read-Host "`nDo you want to stop any existing Flamenco workers? (y/n)"
|
|
||||||
if ($response -eq 'y') {
|
|
||||||
taskkill /IM flamenco-worker.exe /F 2>$null
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Worker process terminated."
|
|
||||||
} else {
|
|
||||||
Write-Host "No worker process found."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nMapping network drives..."
|
|
||||||
Write-Host "Connecting drives to NEXUS..."
|
|
||||||
|
|
||||||
# First connect to the share without a drive letter
|
|
||||||
Write-Host "Establishing initial NEXUS connection..."
|
|
||||||
net use \\NEXUS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Initial NEXUS connection established."
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
|
|
||||||
Write-Host "`nMapping A: drive..."
|
|
||||||
net use A: \\NEXUS\amazon /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "A: drive connected successfully."
|
|
||||||
|
|
||||||
Write-Host "`nMapping F: drive..."
|
|
||||||
net use F: \\NEXUS\flamenco /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "F: drive connected successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect F: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect A: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to establish initial NEXUS connection" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nMapping N: drive..."
|
|
||||||
net use N: \\NAS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "N: drive connected successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect N: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nVerifying connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nStarting Flamenco worker..."
|
|
||||||
if (Test-Path "C:\Program Files\Blender Foundation\Flamenco 3.6") {
|
|
||||||
Set-Location "C:\Program Files\Blender Foundation\Flamenco 3.6"
|
|
||||||
if (Test-Path "flamenco-worker.exe") {
|
|
||||||
Write-Host "Running flamenco-worker.exe directly..."
|
|
||||||
# Run the executable directly in the console instead of using Start-Process
|
|
||||||
.\flamenco-worker.exe
|
|
||||||
# This line will only execute after the worker process terminates
|
|
||||||
Write-Host "Flamenco worker process has terminated."
|
|
||||||
} else {
|
|
||||||
Write-Host "Error: flamenco-worker.exe not found in Flamenco directory" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Error: Flamenco directory not found" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to continue..."
|
|
||||||
Read-Host
|
|
||||||
'@
|
|
||||||
|
|
||||||
# Encode the command to handle special characters
|
|
||||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($remoteCommand)
|
|
||||||
$encodedCommand = [Convert]::ToBase64String($bytes)
|
|
||||||
|
|
||||||
# Execute the encoded command on the remote machine
|
|
||||||
ssh -t -p 22146 i9-13ks "powershell -EncodedCommand $encodedCommand"
|
|
||||||
|
|
||||||
} catch {
|
|
||||||
Write-Host "`nAn error occurred:" -ForegroundColor Red
|
|
||||||
Write-Host $_.Exception.Message -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to exit..."
|
|
||||||
Read-Host
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
@echo off
|
|
||||||
powershell -ExecutionPolicy Bypass -File "%~dp0run_masterbox_cmd.ps1"
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
Write-Host "Connecting to masterbox..."
|
|
||||||
|
|
||||||
try {
|
|
||||||
$remoteCommand = @'
|
|
||||||
Write-Host "Checking current network connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nDisconnecting from NEXUS shares..."
|
|
||||||
# First disconnect from specific NEXUS shares
|
|
||||||
net use \\NEXUS\amazon /delete /y 2>$null
|
|
||||||
net use \\NEXUS\flamenco /delete /y 2>$null
|
|
||||||
net use \\NAS\amazon /delete /y 2>$null
|
|
||||||
# Then disconnect any mapped drives
|
|
||||||
net use A: /delete /y 2>$null
|
|
||||||
net use F: /delete /y 2>$null
|
|
||||||
net use N: /delete /y 2>$null
|
|
||||||
Write-Host "Existing NEXUS connections cleared."
|
|
||||||
|
|
||||||
Write-Host "`nMapping network drives..."
|
|
||||||
Write-Host "Connecting drives to NEXUS..."
|
|
||||||
|
|
||||||
# First connect to the share without a drive letter
|
|
||||||
Write-Host "Establishing initial NEXUS connection..."
|
|
||||||
net use \\NEXUS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Initial NEXUS connection established."
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
|
|
||||||
Write-Host "`nMapping A: drive..."
|
|
||||||
net use A: \\NEXUS\amazon /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "A: drive connected successfully."
|
|
||||||
|
|
||||||
Write-Host "`nMapping F: drive..."
|
|
||||||
net use F: \\NEXUS\flamenco /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "F: drive connected successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect F: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect A: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to establish initial NEXUS connection" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nMapping N: drive..."
|
|
||||||
net use N: \\NAS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "N: drive connected successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect N: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nVerifying connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nRunning command file..."
|
|
||||||
$cmdFilePath = "F:\software\Flamenco 3.6\run-flamenco-worker.cmd"
|
|
||||||
$cmdDirectory = "F:\software\Flamenco 3.6"
|
|
||||||
|
|
||||||
if (Test-Path $cmdFilePath) {
|
|
||||||
Write-Host "Starting $cmdFilePath..."
|
|
||||||
# Change to the directory containing the CMD file first
|
|
||||||
Set-Location $cmdDirectory
|
|
||||||
# Run the CMD file
|
|
||||||
cmd /c $cmdFilePath
|
|
||||||
} else {
|
|
||||||
Write-Host "Error: Command file not found at $cmdFilePath" -ForegroundColor Red
|
|
||||||
$customPath = Read-Host "Enter the path to your .cmd file"
|
|
||||||
if (Test-Path $customPath) {
|
|
||||||
Write-Host "Starting $customPath..."
|
|
||||||
# Get the directory of the custom path
|
|
||||||
$customDirectory = Split-Path -Parent $customPath
|
|
||||||
# Change to the directory containing the CMD file
|
|
||||||
Set-Location $customDirectory
|
|
||||||
# Run the custom path CMD file
|
|
||||||
cmd /c $customPath
|
|
||||||
} else {
|
|
||||||
Write-Host "Error: Command file not found at custom path" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to continue..."
|
|
||||||
Read-Host
|
|
||||||
'@
|
|
||||||
|
|
||||||
# Encode the command to handle special characters
|
|
||||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($remoteCommand)
|
|
||||||
$encodedCommand = [Convert]::ToBase64String($bytes)
|
|
||||||
|
|
||||||
# Execute the encoded command on the remote machine
|
|
||||||
ssh -t masterbox "powershell -EncodedCommand $encodedCommand"
|
|
||||||
|
|
||||||
} catch {
|
|
||||||
Write-Host "`nAn error occurred:" -ForegroundColor Red
|
|
||||||
Write-Host $_.Exception.Message -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to exit..."
|
|
||||||
Read-Host
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
@echo off
|
|
||||||
powershell.exe -NoExit -ExecutionPolicy Bypass -File "%~dp0run_masterbox_worker.ps1"
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
Write-Host "Connecting to masterbox..."
|
|
||||||
|
|
||||||
try {
|
|
||||||
$remoteCommand = @'
|
|
||||||
Write-Host "Checking current network connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nDisconnecting from NEXUS shares..."
|
|
||||||
# First disconnect from specific NEXUS shares
|
|
||||||
net use \\NEXUS\amazon /delete /y 2>$null
|
|
||||||
net use \\NEXUS\flamenco /delete /y 2>$null
|
|
||||||
net use \\NAS\amazon /delete /y 2>$null
|
|
||||||
# Then disconnect any mapped drives
|
|
||||||
net use A: /delete /y 2>$null
|
|
||||||
net use F: /delete /y 2>$null
|
|
||||||
net use N: /delete /y 2>$null
|
|
||||||
Write-Host "Existing NEXUS connections cleared."
|
|
||||||
|
|
||||||
$response = Read-Host "`nDo you want to stop any existing Flamenco workers? (y/n)"
|
|
||||||
if ($response -eq 'y') {
|
|
||||||
taskkill /IM flamenco-worker.exe /F 2>$null
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Worker process terminated."
|
|
||||||
} else {
|
|
||||||
Write-Host "No worker process found."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nMapping network drives..."
|
|
||||||
Write-Host "Connecting drives to NEXUS..."
|
|
||||||
|
|
||||||
# First connect to the share without a drive letter
|
|
||||||
Write-Host "Establishing initial NEXUS connection..."
|
|
||||||
net use \\NEXUS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Initial NEXUS connection established."
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
|
|
||||||
Write-Host "`nMapping A: drive..."
|
|
||||||
net use A: \\NEXUS\amazon /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "A: drive connected successfully."
|
|
||||||
|
|
||||||
Write-Host "`nMapping F: drive..."
|
|
||||||
net use F: \\NEXUS\flamenco /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "F: drive connected successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect F: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect A: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to establish initial NEXUS connection" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nMapping N: drive..."
|
|
||||||
net use N: \\NAS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "N: drive connected successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect N: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nVerifying connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nStarting Flamenco worker..."
|
|
||||||
if (Test-Path "C:\Program Files\Blender Foundation\Flamenco 3.6") {
|
|
||||||
Set-Location "C:\Program Files\Blender Foundation\Flamenco 3.6"
|
|
||||||
if (Test-Path "flamenco-worker.exe") {
|
|
||||||
Write-Host "Running flamenco-worker.exe directly..."
|
|
||||||
# Run the executable directly in the console instead of using Start-Process
|
|
||||||
.\flamenco-worker.exe
|
|
||||||
# This line will only execute after the worker process terminates
|
|
||||||
Write-Host "Flamenco worker process has terminated."
|
|
||||||
} else {
|
|
||||||
Write-Host "Error: flamenco-worker.exe not found in Flamenco directory" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Error: Flamenco directory not found" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to continue..."
|
|
||||||
Read-Host
|
|
||||||
'@
|
|
||||||
|
|
||||||
# Encode the command to handle special characters
|
|
||||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($remoteCommand)
|
|
||||||
$encodedCommand = [Convert]::ToBase64String($bytes)
|
|
||||||
|
|
||||||
# Execute the encoded command on the remote machine
|
|
||||||
ssh -t masterbox "powershell -EncodedCommand $encodedCommand"
|
|
||||||
|
|
||||||
} catch {
|
|
||||||
Write-Host "`nAn error occurred:" -ForegroundColor Red
|
|
||||||
Write-Host $_.Exception.Message -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to exit..."
|
|
||||||
Read-Host
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
@echo off
|
|
||||||
powershell -ExecutionPolicy Bypass -File "%~dp0run_max_cmd.ps1"
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
Write-Host "Connecting to max..."
|
|
||||||
|
|
||||||
try {
|
|
||||||
$remoteCommand = @'
|
|
||||||
Write-Host "Checking current network connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nDisconnecting from NEXUS shares..."
|
|
||||||
# First disconnect from specific NEXUS shares
|
|
||||||
net use \\NEXUS\amazon /delete /y 2>$null
|
|
||||||
net use \\NEXUS\flamenco /delete /y 2>$null
|
|
||||||
net use \\NAS\amazon /delete /y 2>$null
|
|
||||||
# Then disconnect any mapped drives
|
|
||||||
net use A: /delete /y 2>$null
|
|
||||||
net use F: /delete /y 2>$null
|
|
||||||
net use N: /delete /y 2>$null
|
|
||||||
Write-Host "Existing NEXUS connections cleared."
|
|
||||||
|
|
||||||
Write-Host "`nMapping network drives..."
|
|
||||||
Write-Host "Connecting drives to NEXUS..."
|
|
||||||
|
|
||||||
# First connect to the share without a drive letter
|
|
||||||
Write-Host "Establishing initial NEXUS connection..."
|
|
||||||
net use \\NEXUS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Initial NEXUS connection established."
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
|
|
||||||
Write-Host "`nMapping A: drive..."
|
|
||||||
net use A: \\NEXUS\amazon /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "A: drive connected successfully."
|
|
||||||
|
|
||||||
Write-Host "`nMapping F: drive..."
|
|
||||||
net use F: \\NEXUS\flamenco /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "F: drive connected successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect F: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect A: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to establish initial NEXUS connection" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nMapping N: drive..."
|
|
||||||
net use N: \\NAS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "N: drive connected successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect N: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nVerifying connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nRunning command file..."
|
|
||||||
$cmdFilePath = "F:\software\Flamenco 3.6\run-flamenco-worker.cmd"
|
|
||||||
$cmdDirectory = "F:\software\Flamenco 3.6"
|
|
||||||
|
|
||||||
if (Test-Path $cmdFilePath) {
|
|
||||||
Write-Host "Starting $cmdFilePath..."
|
|
||||||
# Change to the directory containing the CMD file first
|
|
||||||
Set-Location $cmdDirectory
|
|
||||||
# Run the CMD file
|
|
||||||
cmd /c $cmdFilePath
|
|
||||||
} else {
|
|
||||||
Write-Host "Error: Command file not found at $cmdFilePath" -ForegroundColor Red
|
|
||||||
$customPath = Read-Host "Enter the path to your .cmd file"
|
|
||||||
if (Test-Path $customPath) {
|
|
||||||
Write-Host "Starting $customPath..."
|
|
||||||
# Get the directory of the custom path
|
|
||||||
$customDirectory = Split-Path -Parent $customPath
|
|
||||||
# Change to the directory containing the CMD file
|
|
||||||
Set-Location $customDirectory
|
|
||||||
# Run the custom path CMD file
|
|
||||||
cmd /c $customPath
|
|
||||||
} else {
|
|
||||||
Write-Host "Error: Command file not found at custom path" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to continue..."
|
|
||||||
Read-Host
|
|
||||||
'@
|
|
||||||
|
|
||||||
# Encode the command to handle special characters
|
|
||||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($remoteCommand)
|
|
||||||
$encodedCommand = [Convert]::ToBase64String($bytes)
|
|
||||||
|
|
||||||
# Execute the encoded command on the remote machine
|
|
||||||
ssh -t max "powershell -EncodedCommand $encodedCommand"
|
|
||||||
|
|
||||||
} catch {
|
|
||||||
Write-Host "`nAn error occurred:" -ForegroundColor Red
|
|
||||||
Write-Host $_.Exception.Message -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to exit..."
|
|
||||||
Read-Host
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
@echo off
|
|
||||||
powershell.exe -NoExit -ExecutionPolicy Bypass -File "%~dp0run_max_worker.ps1"
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
Write-Host "Connecting to max..."
|
|
||||||
|
|
||||||
try {
|
|
||||||
$remoteCommand = @'
|
|
||||||
Write-Host "Checking current network connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nDisconnecting from NEXUS shares..."
|
|
||||||
# First disconnect from specific NEXUS shares
|
|
||||||
net use \\NEXUS\amazon /delete /y 2>$null
|
|
||||||
net use \\NEXUS\flamenco /delete /y 2>$null
|
|
||||||
net use \\NAS\amazon /delete /y 2>$null
|
|
||||||
# Then disconnect any mapped drives
|
|
||||||
net use A: /delete /y 2>$null
|
|
||||||
net use F: /delete /y 2>$null
|
|
||||||
net use N: /delete /y 2>$null
|
|
||||||
Write-Host "Existing NEXUS connections cleared."
|
|
||||||
|
|
||||||
$response = Read-Host "`nDo you want to stop any existing Flamenco workers? (y/n)"
|
|
||||||
if ($response -eq 'y') {
|
|
||||||
taskkill /IM flamenco-worker.exe /F 2>$null
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Worker process terminated."
|
|
||||||
} else {
|
|
||||||
Write-Host "No worker process found."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nMapping network drives..."
|
|
||||||
Write-Host "Connecting drives to NEXUS..."
|
|
||||||
|
|
||||||
# First connect to the share without a drive letter
|
|
||||||
Write-Host "Establishing initial NEXUS connection..."
|
|
||||||
net use \\NEXUS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "Initial NEXUS connection established."
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
|
|
||||||
Write-Host "`nMapping A: drive..."
|
|
||||||
net use A: \\NEXUS\amazon /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "A: drive connected successfully."
|
|
||||||
|
|
||||||
Write-Host "`nMapping F: drive..."
|
|
||||||
net use F: \\NEXUS\flamenco /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "F: drive connected successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect F: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect A: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to establish initial NEXUS connection" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nMapping N: drive..."
|
|
||||||
net use N: \\NAS\amazon /user:Nathan /persistent:yes
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host "N: drive connected successfully."
|
|
||||||
} else {
|
|
||||||
Write-Host "Failed to connect N: drive" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nVerifying connections..."
|
|
||||||
net use
|
|
||||||
|
|
||||||
Write-Host "`nStarting Flamenco worker..."
|
|
||||||
if (Test-Path "C:\Program Files\Blender Foundation\Flamenco 3.6") {
|
|
||||||
Set-Location "C:\Program Files\Blender Foundation\Flamenco 3.6"
|
|
||||||
if (Test-Path "flamenco-worker.exe") {
|
|
||||||
Write-Host "Running flamenco-worker.exe directly..."
|
|
||||||
# Run the executable directly in the console instead of using Start-Process
|
|
||||||
.\flamenco-worker.exe
|
|
||||||
# This line will only execute after the worker process terminates
|
|
||||||
Write-Host "Flamenco worker process has terminated."
|
|
||||||
} else {
|
|
||||||
Write-Host "Error: flamenco-worker.exe not found in Flamenco directory" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Write-Host "Error: Flamenco directory not found" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to continue..."
|
|
||||||
Read-Host
|
|
||||||
'@
|
|
||||||
|
|
||||||
# Encode the command to handle special characters
|
|
||||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($remoteCommand)
|
|
||||||
$encodedCommand = [Convert]::ToBase64String($bytes)
|
|
||||||
|
|
||||||
# Execute the encoded command on the remote machine
|
|
||||||
ssh -t max "powershell -EncodedCommand $encodedCommand"
|
|
||||||
|
|
||||||
} catch {
|
|
||||||
Write-Host "`nAn error occurred:" -ForegroundColor Red
|
|
||||||
Write-Host $_.Exception.Message -ForegroundColor Red
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nPress Enter to exit..."
|
|
||||||
Read-Host
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
@echo off
|
|
||||||
echo Starting all worker CMD scripts...
|
|
||||||
|
|
||||||
start "Masterbox Worker CMD" cmd /c run_masterbox_cmd.bat
|
|
||||||
timeout /t 2
|
|
||||||
|
|
||||||
start "i9-13ks Worker CMD" cmd /c run_i9-13ks_cmd.bat
|
|
||||||
timeout /t 2
|
|
||||||
|
|
||||||
start "Max Worker CMD" cmd /c run_max_cmd.bat
|
|
||||||
timeout /t 2
|
|
||||||
|
|
||||||
start "Echo Worker CMD" cmd /c run_echo_cmd.bat
|
|
||||||
timeout /t 2
|
|
||||||
|
|
||||||
start "Blender-Boss Worker CMD" cmd /c run_blender-boss_cmd.bat
|
|
||||||
timeout /t 2
|
|
||||||
|
|
||||||
echo All worker CMD scripts started!
|
|
||||||
echo.
|
|
||||||
echo Note: Each worker will open in its own command window.
|
|
||||||
echo.
|
|
||||||
pause
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
@echo off
|
|
||||||
echo Starting all Flamenco workers...
|
|
||||||
|
|
||||||
start "Masterbox Worker" powershell.exe -NoExit -ExecutionPolicy Bypass -File "%~dp0masterbox_worker1.ps1"
|
|
||||||
timeout /t 2 >nul
|
|
||||||
|
|
||||||
start "Blender-Boss Worker" powershell.exe -NoExit -ExecutionPolicy Bypass -File "%~dp0blender-boss_worker1.ps1"
|
|
||||||
timeout /t 2 >nul
|
|
||||||
|
|
||||||
start "Echo Worker" powershell.exe -NoExit -ExecutionPolicy Bypass -File "%~dp0echo_worker1.ps1"
|
|
||||||
timeout /t 2 >nul
|
|
||||||
|
|
||||||
start "Max Worker" powershell.exe -NoExit -ExecutionPolicy Bypass -File "%~dp0max_worker1.ps1"
|
|
||||||
|
|
||||||
echo All workers have been launched in separate windows.
|
|
||||||
echo You can close this window now.
|
|
||||||
29
persistent_workers.md
Normal file
29
persistent_workers.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
## Persistent Remote Worker Architecture
|
||||||
|
|
||||||
|
This repository now includes a small controller/attach framework that keeps both Flamenco and SheepIt workers running on each remote Windows host even after the SSH session closes.
|
||||||
|
|
||||||
|
### Components
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
| --- | --- |
|
||||||
|
| `remote_worker_controller.ps1` | Runs on each remote host. Launches the real worker process (Flamenco or SheepIt), redirects its stdout/stderr to a log file, listens for commands, and restarts the worker if it crashes. |
|
||||||
|
| `remote_worker_attach.ps1` | Also runs remotely. Streams the controller’s log file back to the local SSH session and forwards commands (`pause`, `resume`, `quit`, etc.) to the worker’s stdin. It can also be invoked in a `-CommandOnly` mode to send a single command without attaching. |
|
||||||
|
| `unified_flamenco_launcher.ps1` / `unified_sheepit_launcher.ps1` | Local launchers that copy the helper scripts to each host, start controllers in the background, and open attach sessions as requested. |
|
||||||
|
|
||||||
|
All metadata, logs and helper scripts live under `C:\ProgramData\UnifiedWorkers\<worker-type>\<worker-name>\`.
|
||||||
|
|
||||||
|
### Typical Flow
|
||||||
|
|
||||||
|
1. **Start/attach**: The launcher ensures the controller + payload are present on the target host, starts the controller through `Start-Process`, then launches `remote_worker_attach.ps1` via SSH so you can see live output and type commands. Closing the SSH window only ends the attach session—the worker keeps running.
|
||||||
|
2. **Reattach**: Run the launcher again and choose the same worker. If a controller reports that a worker is already running, the launcher simply opens another attach session.
|
||||||
|
3. **Pause/Resume/Quit all (SheepIt)**: The SheepIt launcher now exposes menu options that iterate over every enabled worker and invoke the attach helper in `-CommandOnly` mode to send the requested command.
|
||||||
|
|
||||||
|
### Manual Verification Checklist
|
||||||
|
|
||||||
|
1. **Controller deployment**: From the launcher, start a worker once and confirm `%ProgramData%\UnifiedWorkers` appears on the remote host with `controller.ps1`, `attach-helper.ps1`, `logs\worker.log`, and `state\worker-info.json`.
|
||||||
|
2. **Persistence**: Attach to a worker, close the SSH window, then reattach. The log stream should resume and the worker PID reported in metadata should remain unchanged.
|
||||||
|
3. **Command channel**: While attached, type `pause`, `resume`, and `quit`. The controller should log each command and the worker should react accordingly. Repeat the same commands using the SheepIt “Pause/Resume/Quit All” menu entries to validate the automation path.
|
||||||
|
4. **Failure recovery**: Manually terminate the worker process on a remote host. The controller should log the exit, update metadata, and restart the worker up to the configured retry limit.
|
||||||
|
|
||||||
|
These steps ensure both Flamenco and SheepIt workflows operate as intended with the new persistent worker model. Adjust the retry/backoff values inside `remote_worker_controller.ps1` if you need more aggressive or conservative restart behavior.
|
||||||
|
|
||||||
116
remote_worker_attach.ps1
Normal file
116
remote_worker_attach.ps1
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$WorkerName,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$WorkerType,
|
||||||
|
|
||||||
|
[string]$DataRoot = (Join-Path ([Environment]::GetFolderPath('LocalApplicationData')) 'UnifiedWorkers'),
|
||||||
|
|
||||||
|
[switch]$CommandOnly,
|
||||||
|
|
||||||
|
[string]$Command
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
function Get-WorkerPaths {
|
||||||
|
param([string]$Root, [string]$Type, [string]$Name)
|
||||||
|
|
||||||
|
$instanceRoot = Join-Path -Path (Join-Path -Path $Root -ChildPath $Type) -ChildPath $Name
|
||||||
|
return [pscustomobject]@{
|
||||||
|
Metadata = Join-Path -Path $instanceRoot -ChildPath 'state\worker-info.json'
|
||||||
|
Command = Join-Path -Path $instanceRoot -ChildPath 'state\commands.txt'
|
||||||
|
Log = Join-Path -Path $instanceRoot -ChildPath 'logs\worker.log'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$paths = Get-WorkerPaths -Root $DataRoot -Type $WorkerType -Name $WorkerName
|
||||||
|
|
||||||
|
if (-not (Test-Path $paths.Metadata)) {
|
||||||
|
Write-Host "No worker metadata found for $WorkerName ($WorkerType)." -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$metadata = Get-Content -Path $paths.Metadata -Raw | ConvertFrom-Json
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Host "Unable to read worker metadata: $($_.Exception.Message)" -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Test-Path $paths.Log) {
|
||||||
|
# ensure log file exists but do not truncate
|
||||||
|
$null = (Get-Item $paths.Log)
|
||||||
|
} else {
|
||||||
|
New-Item -Path $paths.Log -ItemType File -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Test-Path $paths.Command)) {
|
||||||
|
New-Item -Path $paths.Command -ItemType File -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Send-WorkerCommand {
|
||||||
|
param([string]$Value)
|
||||||
|
|
||||||
|
$clean = $Value.Trim()
|
||||||
|
if (-not $clean) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Add-Content -Path $paths.Command -Value $clean -Encoding UTF8
|
||||||
|
Write-Host "Sent command '$clean' to $WorkerName." -ForegroundColor DarkGray
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($CommandOnly) {
|
||||||
|
if (-not $Command) {
|
||||||
|
Write-Host "CommandOnly flag set but no command provided." -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Send-WorkerCommand -Value $Command
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Attaching to $WorkerName ($WorkerType) logs." -ForegroundColor Cyan
|
||||||
|
Write-Host "Type commands and press Enter. Type 'detach' to exit session." -ForegroundColor Yellow
|
||||||
|
|
||||||
|
$logJob = Start-Job -ScriptBlock {
|
||||||
|
param($LogPath)
|
||||||
|
Get-Content -Path $LogPath -Tail 50 -Wait
|
||||||
|
} -ArgumentList $paths.Log
|
||||||
|
|
||||||
|
try {
|
||||||
|
while ($true) {
|
||||||
|
$input = Read-Host "> "
|
||||||
|
if ($null -eq $input) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
$normalized = $input.Trim()
|
||||||
|
if ($normalized.StartsWith(':')) {
|
||||||
|
$normalized = $normalized.TrimStart(':').Trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($normalized.Length -eq 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($normalized.ToLowerInvariant() -eq 'detach') {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
Send-WorkerCommand -Value $input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if ($logJob) {
|
||||||
|
Stop-Job -Job $logJob -ErrorAction SilentlyContinue
|
||||||
|
Receive-Job -Job $logJob -ErrorAction SilentlyContinue | Out-Null
|
||||||
|
Remove-Job -Job $logJob -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Detached from worker $WorkerName." -ForegroundColor Cyan
|
||||||
|
}
|
||||||
|
|
||||||
330
remote_worker_controller.ps1
Normal file
330
remote_worker_controller.ps1
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$WorkerName,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$WorkerType,
|
||||||
|
|
||||||
|
[string]$PayloadBase64,
|
||||||
|
|
||||||
|
[string]$PayloadBase64Path,
|
||||||
|
|
||||||
|
[string]$DataRoot = (Join-Path ([Environment]::GetFolderPath('LocalApplicationData')) 'UnifiedWorkers'),
|
||||||
|
|
||||||
|
[int]$MaxRestarts = 5,
|
||||||
|
|
||||||
|
[int]$RestartDelaySeconds = 10
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
[System.Management.Automation.Runspaces.Runspace]::DefaultRunspace = $Host.Runspace
|
||||||
|
|
||||||
|
# region Path setup
|
||||||
|
$workerRoot = Join-Path -Path $DataRoot -ChildPath $WorkerType
|
||||||
|
$instanceRoot = Join-Path -Path $workerRoot -ChildPath $WorkerName
|
||||||
|
New-Item -ItemType Directory -Path $instanceRoot -Force | Out-Null
|
||||||
|
|
||||||
|
$logsRoot = Join-Path -Path $instanceRoot -ChildPath 'logs'
|
||||||
|
$stateRoot = Join-Path -Path $instanceRoot -ChildPath 'state'
|
||||||
|
New-Item -ItemType Directory -Path $logsRoot -Force | Out-Null
|
||||||
|
New-Item -ItemType Directory -Path $stateRoot -Force | Out-Null
|
||||||
|
|
||||||
|
$logPath = Join-Path -Path $logsRoot -ChildPath 'worker.log'
|
||||||
|
$metaPath = Join-Path -Path $stateRoot -ChildPath 'worker-info.json'
|
||||||
|
$commandPath = Join-Path -Path $stateRoot -ChildPath 'commands.txt'
|
||||||
|
$payloadPath = Join-Path -Path $stateRoot -ChildPath "payload.ps1"
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
# region Logging
|
||||||
|
$logStream = [System.IO.FileStream]::new(
|
||||||
|
$logPath,
|
||||||
|
[System.IO.FileMode]::Append,
|
||||||
|
[System.IO.FileAccess]::Write,
|
||||||
|
[System.IO.FileShare]::ReadWrite
|
||||||
|
)
|
||||||
|
$logWriter = [System.IO.StreamWriter]::new($logStream, [System.Text.Encoding]::UTF8)
|
||||||
|
$logWriter.AutoFlush = $true
|
||||||
|
|
||||||
|
# Create C# event handler class that doesn't require PowerShell runspace
|
||||||
|
if (-not ("UnifiedWorkers.ProcessLogHandler" -as [type])) {
|
||||||
|
$csharpCode = @'
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace UnifiedWorkers
|
||||||
|
{
|
||||||
|
public sealed class ProcessLogHandler
|
||||||
|
{
|
||||||
|
private readonly TextWriter _writer;
|
||||||
|
private readonly string _prefix;
|
||||||
|
private readonly object _lock = new object();
|
||||||
|
|
||||||
|
public ProcessLogHandler(TextWriter writer, string prefix)
|
||||||
|
{
|
||||||
|
_writer = writer ?? throw new ArgumentNullException("writer");
|
||||||
|
_prefix = prefix ?? throw new ArgumentNullException("prefix");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnDataReceived(object sender, DataReceivedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e == null || string.IsNullOrEmpty(e.Data))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var timestamp = DateTime.UtcNow.ToString("u");
|
||||||
|
_writer.WriteLine(string.Format("[{0} {1}] {2}", _prefix, timestamp, e.Data));
|
||||||
|
_writer.Flush();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Ignore write errors to prevent cascading failures
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'@
|
||||||
|
Add-Type -TypeDefinition $csharpCode -ErrorAction Stop
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-LogLine {
|
||||||
|
param(
|
||||||
|
[string]$Prefix,
|
||||||
|
[string]$Message
|
||||||
|
)
|
||||||
|
|
||||||
|
if (-not $logWriter) { return }
|
||||||
|
$timestamp = (Get-Date).ToString('u')
|
||||||
|
$logWriter.WriteLine("[$Prefix $timestamp] $Message")
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-ControllerLog {
|
||||||
|
param([string]$Message)
|
||||||
|
Write-LogLine -Prefix 'CTRL' -Message $Message
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-FatalLog {
|
||||||
|
param([string]$Message)
|
||||||
|
|
||||||
|
try {
|
||||||
|
Write-ControllerLog $Message
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
$timestamp = (Get-Date).ToString('u')
|
||||||
|
$fallback = "[CTRL $timestamp] $Message"
|
||||||
|
try {
|
||||||
|
[System.IO.File]::AppendAllText($logPath, $fallback + [Environment]::NewLine, [System.Text.Encoding]::UTF8)
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
# last resort: write to host
|
||||||
|
Write-Error $fallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
# region Helpers
|
||||||
|
|
||||||
|
function Resolve-PayloadBase64 {
|
||||||
|
if ($PayloadBase64) {
|
||||||
|
return $PayloadBase64.Trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($PayloadBase64Path) {
|
||||||
|
if (-not (Test-Path $PayloadBase64Path)) {
|
||||||
|
throw "Payload file '$PayloadBase64Path' not found."
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = Get-Content -Path $PayloadBase64Path -Raw
|
||||||
|
if ([string]::IsNullOrWhiteSpace($content)) {
|
||||||
|
throw "Payload file '$PayloadBase64Path' is empty."
|
||||||
|
}
|
||||||
|
|
||||||
|
return $content.Trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
throw "No payload data provided to controller."
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-Metadata {
|
||||||
|
param(
|
||||||
|
[string]$Status,
|
||||||
|
[nullable[int]]$WorkerPid = $null,
|
||||||
|
[nullable[int]]$ControllerPid = $PID,
|
||||||
|
[int]$Restarts = 0,
|
||||||
|
[nullable[int]]$LastExitCode = $null
|
||||||
|
)
|
||||||
|
|
||||||
|
$payload = [pscustomobject]@{
|
||||||
|
WorkerName = $WorkerName
|
||||||
|
WorkerType = $WorkerType
|
||||||
|
Status = $Status
|
||||||
|
ControllerPid = $ControllerPid
|
||||||
|
WorkerPid = $WorkerPid
|
||||||
|
Restarts = $Restarts
|
||||||
|
LastExitCode = $LastExitCode
|
||||||
|
LogPath = $logPath
|
||||||
|
CommandPath = $commandPath
|
||||||
|
PayloadPath = $payloadPath
|
||||||
|
UpdatedAtUtc = (Get-Date).ToUniversalTime()
|
||||||
|
}
|
||||||
|
|
||||||
|
$payload | ConvertTo-Json -Depth 5 | Set-Content -Path $metaPath -Encoding UTF8
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-PendingCommands {
|
||||||
|
if (-not (Test-Path $commandPath)) {
|
||||||
|
return @()
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$lines = Get-Content -Path $commandPath -ErrorAction Stop
|
||||||
|
Remove-Item -Path $commandPath -Force -ErrorAction SilentlyContinue
|
||||||
|
return $lines | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return @()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
try {
|
||||||
|
# record initial state before launching worker
|
||||||
|
Write-Metadata -Status 'initializing' -WorkerPid $null -ControllerPid $PID -Restarts 0
|
||||||
|
|
||||||
|
$resolvedPayloadBase64 = Resolve-PayloadBase64
|
||||||
|
$PayloadBase64 = $resolvedPayloadBase64
|
||||||
|
|
||||||
|
try {
|
||||||
|
# Write payload script to disk
|
||||||
|
# The payload is base64-encoded UTF-16 (Unicode), so decode it properly
|
||||||
|
Write-ControllerLog "Decoding payload base64 (length: $($resolvedPayloadBase64.Length))"
|
||||||
|
$payloadBytes = [Convert]::FromBase64String($resolvedPayloadBase64)
|
||||||
|
Write-ControllerLog "Decoded payload to $($payloadBytes.Length) bytes"
|
||||||
|
|
||||||
|
# Convert UTF-16 bytes back to string, then write as UTF-8 (PowerShell's preferred encoding)
|
||||||
|
$payloadText = [Text.Encoding]::Unicode.GetString($payloadBytes)
|
||||||
|
[IO.File]::WriteAllText($payloadPath, $payloadText, [Text.Encoding]::UTF8)
|
||||||
|
Write-ControllerLog "Payload written to $payloadPath ($($payloadText.Length) characters)"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-FatalLog "Unable to write payload: $($_.Exception.Message)"
|
||||||
|
if ($_.Exception.InnerException) {
|
||||||
|
Write-FatalLog "Inner exception: $($_.Exception.InnerException.Message)"
|
||||||
|
}
|
||||||
|
throw
|
||||||
|
}
|
||||||
|
|
||||||
|
$restartCount = 0
|
||||||
|
$controllerPid = $PID
|
||||||
|
|
||||||
|
while ($restartCount -le $MaxRestarts) {
|
||||||
|
try {
|
||||||
|
# Initialize worker process
|
||||||
|
$psi = [System.Diagnostics.ProcessStartInfo]::new()
|
||||||
|
$pwsh = Get-Command pwsh -ErrorAction SilentlyContinue
|
||||||
|
if ($pwsh) {
|
||||||
|
$psi.FileName = $pwsh.Source
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$psi.FileName = (Get-Command powershell -ErrorAction Stop).Source
|
||||||
|
}
|
||||||
|
|
||||||
|
$psi.Arguments = "-NoLogo -NoProfile -ExecutionPolicy Bypass -File `"$payloadPath`""
|
||||||
|
$psi.UseShellExecute = $false
|
||||||
|
$psi.RedirectStandardInput = $true
|
||||||
|
$psi.RedirectStandardOutput = $true
|
||||||
|
$psi.RedirectStandardError = $true
|
||||||
|
$psi.CreateNoWindow = $true
|
||||||
|
|
||||||
|
$workerProcess = New-Object System.Diagnostics.Process
|
||||||
|
$workerProcess.StartInfo = $psi
|
||||||
|
|
||||||
|
if (-not $workerProcess.Start()) {
|
||||||
|
throw "Failed to start worker process."
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-ControllerLog "Worker process started with PID $($workerProcess.Id)"
|
||||||
|
Write-Metadata -Status 'running' -WorkerPid $workerProcess.Id -ControllerPid $controllerPid -Restarts $restartCount
|
||||||
|
|
||||||
|
$stdoutHandler = [UnifiedWorkers.ProcessLogHandler]::new($logWriter, 'OUT')
|
||||||
|
$stderrHandler = [UnifiedWorkers.ProcessLogHandler]::new($logWriter, 'ERR')
|
||||||
|
|
||||||
|
$outputHandler = [System.Diagnostics.DataReceivedEventHandler]$stdoutHandler.OnDataReceived
|
||||||
|
$errorHandler = [System.Diagnostics.DataReceivedEventHandler]$stderrHandler.OnDataReceived
|
||||||
|
|
||||||
|
$workerProcess.add_OutputDataReceived($outputHandler)
|
||||||
|
$workerProcess.add_ErrorDataReceived($errorHandler)
|
||||||
|
$workerProcess.BeginOutputReadLine()
|
||||||
|
$workerProcess.BeginErrorReadLine()
|
||||||
|
|
||||||
|
while (-not $workerProcess.HasExited) {
|
||||||
|
$commands = Get-PendingCommands
|
||||||
|
foreach ($command in $commands) {
|
||||||
|
$trimmed = $command.Trim()
|
||||||
|
if (-not $trimmed) { continue }
|
||||||
|
|
||||||
|
Write-ControllerLog "Received command '$trimmed'"
|
||||||
|
try {
|
||||||
|
$workerProcess.StandardInput.WriteLine($trimmed)
|
||||||
|
$workerProcess.StandardInput.Flush()
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-ControllerLog "Failed to forward command '$trimmed': $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($trimmed -ieq 'quit') {
|
||||||
|
Write-ControllerLog "Quit command issued. Waiting for worker to exit."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Start-Sleep -Milliseconds 500
|
||||||
|
}
|
||||||
|
|
||||||
|
$exitCode = $workerProcess.ExitCode
|
||||||
|
Write-ControllerLog "Worker exited with code $exitCode"
|
||||||
|
Write-Metadata -Status 'stopped' -WorkerPid $null -ControllerPid $controllerPid -Restarts $restartCount -LastExitCode $exitCode
|
||||||
|
|
||||||
|
if ($exitCode -eq 0) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-ControllerLog "Controller error: $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
|
||||||
|
$restartCount++
|
||||||
|
if ($restartCount -gt $MaxRestarts) {
|
||||||
|
Write-ControllerLog "Maximum restart attempts reached. Controller stopping."
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-ControllerLog "Restarting worker in $RestartDelaySeconds seconds (attempt $restartCount of $MaxRestarts)."
|
||||||
|
Start-Sleep -Seconds $RestartDelaySeconds
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Metadata -Status 'inactive' -WorkerPid $null -ControllerPid $controllerPid -Restarts $restartCount
|
||||||
|
Write-ControllerLog "Controller exiting."
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-FatalLog "Fatal controller error: $($_.Exception.Message)"
|
||||||
|
if ($_.ScriptStackTrace) {
|
||||||
|
Write-FatalLog "Stack: $($_.ScriptStackTrace)"
|
||||||
|
}
|
||||||
|
throw
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if ($logWriter) {
|
||||||
|
$logWriter.Dispose()
|
||||||
|
}
|
||||||
|
if ($logStream) {
|
||||||
|
$logStream.Dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -46,18 +46,6 @@ const JOB_TYPE = {
|
|||||||
},
|
},
|
||||||
description: "Base path where renders are stored, typically the project's Renders folder. If empty, derived automatically."
|
description: "Base path where renders are stored, typically the project's Renders folder. If empty, derived automatically."
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: "daily_path",
|
|
||||||
type: "string",
|
|
||||||
required: false,
|
|
||||||
visible: "submission",
|
|
||||||
eval: "__import__('datetime').datetime.now().strftime('daily_%y%m%d')",
|
|
||||||
evalInfo: {
|
|
||||||
showLinkButton: true,
|
|
||||||
description: "Auto-fill with today's daily folder name"
|
|
||||||
},
|
|
||||||
description: "Daily folder name under the render root, e.g. 'daily_250813'. If empty, auto-fills to today's date."
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: "use_submodule",
|
key: "use_submodule",
|
||||||
label: "Use Submodule",
|
label: "Use Submodule",
|
||||||
@@ -79,14 +67,14 @@ const JOB_TYPE = {
|
|||||||
},
|
},
|
||||||
description: "Optional submodule under Renders (e.g. 'Waterspider B'). If empty, omitted."
|
description: "Optional submodule under Renders (e.g. 'Waterspider B'). If empty, omitted."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "render_output_path",
|
key: "render_output_path",
|
||||||
type: "string",
|
type: "string",
|
||||||
subtype: "file_path",
|
subtype: "file_path",
|
||||||
editable: false,
|
editable: false,
|
||||||
eval: "str(Path(abspath(settings.render_output_root or '//'), ((str(settings.submodule or '').strip()) if (settings.use_submodule and str(settings.submodule or '').strip()) else ((__import__('os').path.basename(__import__('os').path.dirname(bpy.data.filepath))) if settings.use_submodule else '')), (settings.daily_path or __import__('datetime').datetime.now().strftime('daily_%y%m%d')), jobname, jobname + '_######'))",
|
eval: "((lambda Path, abspath, os_path, settings_obj, blend: str(Path(abspath(settings_obj.render_output_root or '//')) / (((str(settings_obj.submodule or '').strip()) if (settings_obj.use_submodule and str(settings_obj.submodule or '').strip()) else ((os_path.basename(os_path.dirname(bpy.data.filepath))) if settings_obj.use_submodule else ''))) / blend / (blend + '_######')))(__import__('pathlib').Path, __import__('os').path.abspath, __import__('os').path, settings, __import__('os').path.splitext(__import__('os').path.basename(bpy.data.filepath))[0]))",
|
||||||
description: "Final file path of where render output will be saved"
|
description: "Final file path of where render output will be saved"
|
||||||
},
|
},
|
||||||
|
|
||||||
// Automatically evaluated settings:
|
// Automatically evaluated settings:
|
||||||
{
|
{
|
||||||
@@ -165,10 +153,6 @@ function compileJob(job) {
|
|||||||
if (projectRoot) settings.render_output_root = path.join(projectRoot, 'Renders');
|
if (projectRoot) settings.render_output_root = path.join(projectRoot, 'Renders');
|
||||||
else settings.render_output_root = path.join(path.dirname(settings.blendfile), 'Renders');
|
else settings.render_output_root = path.join(path.dirname(settings.blendfile), 'Renders');
|
||||||
}
|
}
|
||||||
if (!settings.daily_path || String(settings.daily_path).trim() === '') {
|
|
||||||
const createdDate = job && job.created ? new Date(job.created) : new Date();
|
|
||||||
settings.daily_path = formatDailyYYMMDD(createdDate);
|
|
||||||
}
|
|
||||||
const recomposed = computeAutoRenderOutputPath(job);
|
const recomposed = computeAutoRenderOutputPath(job);
|
||||||
if (recomposed) settings.render_output_path = recomposed;
|
if (recomposed) settings.render_output_path = recomposed;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -200,7 +184,7 @@ function compileJob(job) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Derive project root, submodule, and daily path from the blendfile path.
|
// Derive project root and submodule from the blendfile path.
|
||||||
function computeAutoRenderOutputPath(job) {
|
function computeAutoRenderOutputPath(job) {
|
||||||
const settings = job.settings || {};
|
const settings = job.settings || {};
|
||||||
if (!settings.blendfile) return null;
|
if (!settings.blendfile) return null;
|
||||||
@@ -220,26 +204,17 @@ function computeAutoRenderOutputPath(job) {
|
|||||||
renderRoot = path.join(path.dirname(settings.blendfile), 'Renders');
|
renderRoot = path.join(path.dirname(settings.blendfile), 'Renders');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve daily path
|
const blendname = path.stem(settings.blendfile).replace('.flamenco', '');
|
||||||
let daily = null;
|
|
||||||
if (settings.daily_path && ("" + settings.daily_path).trim()) {
|
|
||||||
daily = ("" + settings.daily_path).trim();
|
|
||||||
} else {
|
|
||||||
const createdDate = job && job.created ? new Date(job.created) : new Date();
|
|
||||||
daily = formatDailyYYMMDD(createdDate);
|
|
||||||
}
|
|
||||||
const jobname = (job && job.name) ? job.name : path.stem(settings.blendfile).replace('.flamenco', '');
|
|
||||||
|
|
||||||
print('AutoPath: blendfile=', settings.blendfile);
|
print('AutoPath: blendfile=', settings.blendfile);
|
||||||
print('AutoPath: projectRoot=', projectRoot);
|
print('AutoPath: projectRoot=', projectRoot);
|
||||||
print('AutoPath: renderRoot=', renderRoot);
|
print('AutoPath: renderRoot=', renderRoot);
|
||||||
print('AutoPath: submodule=', submodule);
|
print('AutoPath: submodule=', submodule);
|
||||||
print('AutoPath: daily=', daily);
|
print('AutoPath: blendname=', blendname);
|
||||||
print('AutoPath: jobname=', jobname);
|
|
||||||
|
|
||||||
const parts = [renderRoot];
|
const parts = [renderRoot];
|
||||||
if (submodule) parts.push(submodule);
|
if (submodule) parts.push(submodule);
|
||||||
parts.push(daily, jobname, `${jobname}_######`);
|
parts.push(blendname, `${blendname}_######`);
|
||||||
const finalPath = path.join.apply(path, parts);
|
const finalPath = path.join.apply(path, parts);
|
||||||
print('AutoPath: finalPath=', finalPath);
|
print('AutoPath: finalPath=', finalPath);
|
||||||
return finalPath;
|
return finalPath;
|
||||||
@@ -296,14 +271,6 @@ function detectSubmodule(settings) {
|
|||||||
return detectSubmoduleFromBlendfile(bf);
|
return detectSubmoduleFromBlendfile(bf);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatDailyYYMMDD(dateObj) {
|
|
||||||
const pad2 = (n) => (n < 10 ? '0' + n : '' + n);
|
|
||||||
const yy = (dateObj.getFullYear() % 100);
|
|
||||||
const mm = dateObj.getMonth() + 1;
|
|
||||||
const dd = dateObj.getDate();
|
|
||||||
return `daily_${pad2(yy)}${pad2(mm)}${pad2(dd)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do field replacement on the render output path.
|
// Do field replacement on the render output path.
|
||||||
function renderOutputPath(job) {
|
function renderOutputPath(job) {
|
||||||
let path = job.settings.render_output_path;
|
let path = job.settings.render_output_path;
|
||||||
|
|||||||
@@ -37,16 +37,6 @@ const JOB_TYPE = {
|
|||||||
description:
|
description:
|
||||||
"Base path where renders are stored, typically the project's Renders folder. If empty, derived automatically.",
|
"Base path where renders are stored, typically the project's Renders folder. If empty, derived automatically.",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: 'daily_path',
|
|
||||||
type: 'string',
|
|
||||||
required: false,
|
|
||||||
visible: 'submission',
|
|
||||||
eval: "__import__('datetime').datetime.now().strftime('daily_%y%m%d')",
|
|
||||||
evalInfo: { showLinkButton: true, description: "Auto-fill with today's daily folder name" },
|
|
||||||
description:
|
|
||||||
"Daily folder name under the render root, e.g. 'daily_250813'. If empty, auto-fills to today's date.",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: 'use_submodule',
|
key: 'use_submodule',
|
||||||
label: 'Use Submodule',
|
label: 'Use Submodule',
|
||||||
@@ -71,7 +61,8 @@ const JOB_TYPE = {
|
|||||||
type: 'string',
|
type: 'string',
|
||||||
subtype: 'file_path',
|
subtype: 'file_path',
|
||||||
editable: false,
|
editable: false,
|
||||||
eval: "str(Path(abspath(settings.render_output_root or '//'), ((str(settings.submodule or '').strip()) if (settings.use_submodule and str(settings.submodule or '').strip()) else ((__import__('os').path.basename(__import__('os').path.dirname(bpy.data.filepath))) if settings.use_submodule else '')), (settings.daily_path or __import__('datetime').datetime.now().strftime('daily_%y%m%d')), jobname, jobname + '_######'))",
|
eval:
|
||||||
|
"((lambda Path, abspath, os_path, settings_obj, blend: str(Path(abspath(settings_obj.render_output_root or '//')) / (((str(settings_obj.submodule or '').strip()) if (settings_obj.use_submodule and str(settings_obj.submodule or '').strip()) else ((os_path.basename(os_path.dirname(bpy.data.filepath))) if settings_obj.use_submodule else ''))) / blend / (blend + '_######')))(__import__('pathlib').Path, __import__('os').path.abspath, __import__('os').path, settings, __import__('os').path.splitext(__import__('os').path.basename(bpy.data.filepath))[0]))",
|
||||||
description: 'Final file path of where render output will be saved',
|
description: 'Final file path of where render output will be saved',
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -180,10 +171,6 @@ function compileJob(job) {
|
|||||||
if (projectRoot) settings.render_output_root = path.join(projectRoot, 'Renders');
|
if (projectRoot) settings.render_output_root = path.join(projectRoot, 'Renders');
|
||||||
else settings.render_output_root = path.join(path.dirname(settings.blendfile), 'Renders');
|
else settings.render_output_root = path.join(path.dirname(settings.blendfile), 'Renders');
|
||||||
}
|
}
|
||||||
if (!settings.daily_path || String(settings.daily_path).trim() === '') {
|
|
||||||
const createdDate = job && job.created ? new Date(job.created) : new Date();
|
|
||||||
settings.daily_path = formatDailyYYMMDD(createdDate);
|
|
||||||
}
|
|
||||||
const recomposed = computeAutoRenderOutputPath(job);
|
const recomposed = computeAutoRenderOutputPath(job);
|
||||||
if (recomposed) settings.render_output_path = recomposed;
|
if (recomposed) settings.render_output_path = recomposed;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -374,7 +361,7 @@ function cleanupJobSettings(settings) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Derive project root, submodule, and daily path from the blendfile path.
|
// Derive project root and submodule from the blendfile path.
|
||||||
function computeAutoRenderOutputPath(job) {
|
function computeAutoRenderOutputPath(job) {
|
||||||
const settings = job.settings || {};
|
const settings = job.settings || {};
|
||||||
if (!settings.blendfile) return null;
|
if (!settings.blendfile) return null;
|
||||||
@@ -391,19 +378,11 @@ function computeAutoRenderOutputPath(job) {
|
|||||||
} else {
|
} else {
|
||||||
renderRoot = path.join(path.dirname(settings.blendfile), 'Renders');
|
renderRoot = path.join(path.dirname(settings.blendfile), 'Renders');
|
||||||
}
|
}
|
||||||
// Resolve daily path
|
const blendname = path.stem(settings.blendfile).replace('.flamenco', '');
|
||||||
let daily = null;
|
|
||||||
if (settings.daily_path && ("" + settings.daily_path).trim()) {
|
|
||||||
daily = ("" + settings.daily_path).trim();
|
|
||||||
} else {
|
|
||||||
const createdDate = job && job.created ? new Date(job.created) : new Date();
|
|
||||||
daily = formatDailyYYMMDD(createdDate);
|
|
||||||
}
|
|
||||||
const jobname = job && job.name ? job.name : path.stem(settings.blendfile).replace('.flamenco', '');
|
|
||||||
|
|
||||||
const parts = [renderRoot];
|
const parts = [renderRoot];
|
||||||
if (submodule) parts.push(submodule);
|
if (submodule) parts.push(submodule);
|
||||||
parts.push(daily, jobname, `${jobname}_######`);
|
parts.push(blendname, `${blendname}_######`);
|
||||||
return path.join.apply(path, parts);
|
return path.join.apply(path, parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,11 +433,3 @@ function detectSubmodule(settings) {
|
|||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
return detectSubmoduleFromBlendfile(bf);
|
return detectSubmoduleFromBlendfile(bf);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatDailyYYMMDD(dateObj) {
|
|
||||||
const pad2 = (n) => (n < 10 ? '0' + n : '' + n);
|
|
||||||
const yy = dateObj.getFullYear() % 100;
|
|
||||||
const mm = dateObj.getMonth() + 1;
|
|
||||||
const dd = dateObj.getDate();
|
|
||||||
return `daily_${pad2(yy)}${pad2(mm)}${pad2(dd)}`;
|
|
||||||
}
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
sqlite/2025.11.19.11.05.13_flamenco-manager.sqlite
LFS
Normal file
BIN
sqlite/2025.11.19.11.05.13_flamenco-manager.sqlite
LFS
Normal file
Binary file not shown.
@@ -50,6 +50,372 @@ $workers = @(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
$script:ControllerScriptBase64 = $null
|
||||||
|
$script:AttachHelperScriptBase64 = $null
|
||||||
|
$script:WorkerBasePathCache = @{}
|
||||||
|
|
||||||
|
function Build-SshArgsFromParts {
|
||||||
|
param(
|
||||||
|
[pscustomobject]$Parts,
|
||||||
|
[switch]$Interactive
|
||||||
|
)
|
||||||
|
|
||||||
|
$args = @('-o','ServerAliveInterval=60','-o','ServerAliveCountMax=30')
|
||||||
|
if ($Interactive -and $Parts.RequestPty) {
|
||||||
|
$args += '-t'
|
||||||
|
}
|
||||||
|
elseif (-not $Interactive) {
|
||||||
|
$args += '-T'
|
||||||
|
}
|
||||||
|
|
||||||
|
$args += $Parts.Options
|
||||||
|
|
||||||
|
if ($Parts.Port) {
|
||||||
|
$args += '-p'
|
||||||
|
$args += $Parts.Port
|
||||||
|
}
|
||||||
|
|
||||||
|
$args += $Parts.Host
|
||||||
|
return $args
|
||||||
|
}
|
||||||
|
|
||||||
|
function Build-ScpArgsFromParts {
|
||||||
|
param(
|
||||||
|
[pscustomobject]$Parts
|
||||||
|
)
|
||||||
|
|
||||||
|
$args = @('-o','ServerAliveInterval=60','-o','ServerAliveCountMax=30')
|
||||||
|
$args += $Parts.Options
|
||||||
|
if ($Parts.Port) {
|
||||||
|
$args += '-P'
|
||||||
|
$args += $Parts.Port
|
||||||
|
}
|
||||||
|
return $args
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-SshArgs {
|
||||||
|
param(
|
||||||
|
[object]$Worker,
|
||||||
|
[switch]$Interactive
|
||||||
|
)
|
||||||
|
|
||||||
|
$parts = Get-WorkerConnectionParts -RawArgs $Worker.SSHArgs -DefaultHost $Worker.Name
|
||||||
|
return Build-SshArgsFromParts -Parts $parts -Interactive:$Interactive
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-WorkerBasePath {
|
||||||
|
param(
|
||||||
|
[object]$Worker,
|
||||||
|
[pscustomobject]$ConnectionParts = $null
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($script:WorkerBasePathCache.ContainsKey($Worker.Name)) {
|
||||||
|
return $script:WorkerBasePathCache[$Worker.Name]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $ConnectionParts) {
|
||||||
|
$ConnectionParts = Get-WorkerConnectionParts -RawArgs $Worker.SSHArgs -DefaultHost $Worker.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
$sshArgs = Build-SshArgsFromParts -Parts $ConnectionParts -Interactive:$false
|
||||||
|
$scriptBlock = "`$ProgressPreference='SilentlyContinue'; [Environment]::GetFolderPath('LocalApplicationData')"
|
||||||
|
$encoded = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($scriptBlock))
|
||||||
|
$remoteCmd = "powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -EncodedCommand $encoded"
|
||||||
|
$output = & ssh @sshArgs $remoteCmd
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
throw "Unable to determine LocalAppData on $($Worker.Name)."
|
||||||
|
}
|
||||||
|
|
||||||
|
$base = ($output | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Select-Object -Last 1).Trim()
|
||||||
|
if (-not $base) {
|
||||||
|
throw "Unable to read LocalAppData path on $($Worker.Name)."
|
||||||
|
}
|
||||||
|
|
||||||
|
$final = Join-Path $base 'UnifiedWorkers'
|
||||||
|
$script:WorkerBasePathCache[$Worker.Name] = $final
|
||||||
|
return $final
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-FileBase64 {
|
||||||
|
param([string]$Path)
|
||||||
|
[Convert]::ToBase64String([IO.File]::ReadAllBytes($Path))
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-ControllerScriptBase64 {
|
||||||
|
if (-not $script:ControllerScriptBase64) {
|
||||||
|
$controllerPath = Join-Path $PSScriptRoot 'remote_worker_controller.ps1'
|
||||||
|
$script:ControllerScriptBase64 = Get-FileBase64 -Path $controllerPath
|
||||||
|
}
|
||||||
|
return $script:ControllerScriptBase64
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-AttachHelperScriptBase64 {
|
||||||
|
if (-not $script:AttachHelperScriptBase64) {
|
||||||
|
$helperPath = Join-Path $PSScriptRoot 'remote_worker_attach.ps1'
|
||||||
|
$script:AttachHelperScriptBase64 = Get-FileBase64 -Path $helperPath
|
||||||
|
}
|
||||||
|
return $script:AttachHelperScriptBase64
|
||||||
|
}
|
||||||
|
|
||||||
|
function ConvertTo-Base64Unicode {
|
||||||
|
param([string]$Content)
|
||||||
|
[Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($Content))
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-WorkerSshArgs {
|
||||||
|
param([string]$RawArgs)
|
||||||
|
if ([string]::IsNullOrWhiteSpace($RawArgs)) {
|
||||||
|
return @()
|
||||||
|
}
|
||||||
|
return $RawArgs -split '\s+' | Where-Object { $_.Trim().Length -gt 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-WorkerConnectionParts {
|
||||||
|
param(
|
||||||
|
[string]$RawArgs,
|
||||||
|
[string]$DefaultHost
|
||||||
|
)
|
||||||
|
|
||||||
|
$tokens = Get-WorkerSshArgs -RawArgs $RawArgs
|
||||||
|
$options = New-Object System.Collections.Generic.List[string]
|
||||||
|
$targetHost = $null
|
||||||
|
$port = $null
|
||||||
|
$requestPty = $false
|
||||||
|
$optionsWithArgs = @('-i','-o','-c','-D','-E','-F','-I','-J','-L','-l','-m','-O','-Q','-R','-S','-W','-w')
|
||||||
|
|
||||||
|
for ($i = 0; $i -lt $tokens.Count; $i++) {
|
||||||
|
$token = $tokens[$i]
|
||||||
|
if ($token -eq '-t' -or $token -eq '-tt') {
|
||||||
|
$requestPty = $true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($token -eq '-p' -and ($i + 1) -lt $tokens.Count) {
|
||||||
|
$port = $tokens[$i + 1]
|
||||||
|
$i++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($token.StartsWith('-')) {
|
||||||
|
$options.Add($token)
|
||||||
|
if ($optionsWithArgs -contains $token -and ($i + 1) -lt $tokens.Count) {
|
||||||
|
$options.Add($tokens[$i + 1])
|
||||||
|
$i++
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $targetHost) {
|
||||||
|
$targetHost = $token
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
$options.Add($token)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $targetHost) {
|
||||||
|
$targetHost = $DefaultHost
|
||||||
|
}
|
||||||
|
|
||||||
|
return [pscustomobject]@{
|
||||||
|
Host = $targetHost
|
||||||
|
Options = $options.ToArray()
|
||||||
|
Port = $port
|
||||||
|
RequestPty = $requestPty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-RemotePowerShell {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)][object]$Worker,
|
||||||
|
[Parameter(Mandatory = $true)][string]$Script,
|
||||||
|
[switch]$Interactive
|
||||||
|
)
|
||||||
|
|
||||||
|
$parts = Get-WorkerConnectionParts -RawArgs $Worker.SSHArgs -DefaultHost $Worker.Name
|
||||||
|
if (-not $parts.Host) {
|
||||||
|
throw "Unable to determine SSH host for $($Worker.Name)"
|
||||||
|
}
|
||||||
|
|
||||||
|
$sshBaseArgs = Build-SshArgsFromParts -Parts $parts -Interactive:$Interactive
|
||||||
|
$remoteBasePath = Get-WorkerBasePath -Worker $Worker -ConnectionParts $parts
|
||||||
|
$localTemp = [System.IO.Path]::GetTempFileName() + '.ps1'
|
||||||
|
Set-Content -Path $localTemp -Value $Script -Encoding UTF8
|
||||||
|
|
||||||
|
$remoteTmpDir = Join-Path $remoteBasePath 'tmp'
|
||||||
|
$remoteScriptWin = Join-Path $remoteTmpDir ("script-{0}.ps1" -f ([guid]::NewGuid().ToString()))
|
||||||
|
$remoteScriptScp = $remoteScriptWin -replace '\\','/'
|
||||||
|
$remoteTarget = "{0}:{1}" -f $parts.Host, ('"'+$remoteScriptScp+'"')
|
||||||
|
|
||||||
|
$ensureScript = "New-Item -ItemType Directory -Path '$remoteTmpDir' -Force | Out-Null"
|
||||||
|
$ensureCmd = "powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -EncodedCommand " + [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($ensureScript))
|
||||||
|
& ssh @sshBaseArgs $ensureCmd
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Remove-Item $localTemp -ErrorAction SilentlyContinue
|
||||||
|
return $LASTEXITCODE
|
||||||
|
}
|
||||||
|
|
||||||
|
$scpArgs = Build-ScpArgsFromParts -Parts $parts
|
||||||
|
$scpArgs += $localTemp
|
||||||
|
$scpArgs += $remoteTarget
|
||||||
|
|
||||||
|
& scp @scpArgs
|
||||||
|
$scpExit = $LASTEXITCODE
|
||||||
|
Remove-Item $localTemp -ErrorAction SilentlyContinue
|
||||||
|
if ($scpExit -ne 0) {
|
||||||
|
return $scpExit
|
||||||
|
}
|
||||||
|
|
||||||
|
$execCmd = "powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -File `"$remoteScriptWin`""
|
||||||
|
& ssh @sshBaseArgs $execCmd
|
||||||
|
$execExit = $LASTEXITCODE
|
||||||
|
|
||||||
|
$cleanupScript = "Remove-Item -LiteralPath '$remoteScriptWin' -ErrorAction SilentlyContinue"
|
||||||
|
$cleanupCmd = "powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -EncodedCommand " + [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($cleanupScript))
|
||||||
|
& ssh @sshBaseArgs $cleanupCmd | Out-Null
|
||||||
|
|
||||||
|
return $execExit
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ensure-ControllerDeployed {
|
||||||
|
param([object]$Worker)
|
||||||
|
$controllerBase64 = Get-ControllerScriptBase64
|
||||||
|
$script = @"
|
||||||
|
`$ProgressPreference = 'SilentlyContinue'
|
||||||
|
`$dataRoot = Join-Path ([Environment]::GetFolderPath('LocalApplicationData')) 'UnifiedWorkers'
|
||||||
|
New-Item -ItemType Directory -Path `$dataRoot -Force | Out-Null
|
||||||
|
`$controllerPath = Join-Path `$dataRoot 'controller.ps1'
|
||||||
|
[IO.File]::WriteAllBytes(`$controllerPath, [Convert]::FromBase64String('$controllerBase64'))
|
||||||
|
"@
|
||||||
|
Invoke-RemotePowerShell -Worker $Worker -Script $script | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ensure-AttachHelperDeployed {
|
||||||
|
param([object]$Worker)
|
||||||
|
$helperBase64 = Get-AttachHelperScriptBase64
|
||||||
|
$script = @"
|
||||||
|
`$ProgressPreference = 'SilentlyContinue'
|
||||||
|
`$dataRoot = Join-Path ([Environment]::GetFolderPath('LocalApplicationData')) 'UnifiedWorkers'
|
||||||
|
New-Item -ItemType Directory -Path `$dataRoot -Force | Out-Null
|
||||||
|
`$attachPath = Join-Path `$dataRoot 'attach-helper.ps1'
|
||||||
|
[IO.File]::WriteAllBytes(`$attachPath, [Convert]::FromBase64String('$helperBase64'))
|
||||||
|
"@
|
||||||
|
Invoke-RemotePowerShell -Worker $Worker -Script $script | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-EnsureWorkerScript {
|
||||||
|
param(
|
||||||
|
[string]$WorkerName,
|
||||||
|
[string]$WorkerType,
|
||||||
|
[string]$PayloadBase64
|
||||||
|
)
|
||||||
|
|
||||||
|
$payload = @{
|
||||||
|
WorkerName = $WorkerName
|
||||||
|
WorkerType = $WorkerType
|
||||||
|
PayloadBase64 = $PayloadBase64
|
||||||
|
} | ConvertTo-Json -Compress
|
||||||
|
|
||||||
|
$payloadBase64 = ConvertTo-Base64Unicode -Content $payload
|
||||||
|
|
||||||
|
return @"
|
||||||
|
`$ProgressPreference = 'SilentlyContinue'
|
||||||
|
`$params = ConvertFrom-Json ([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('$payloadBase64')))
|
||||||
|
`$workerName = `$params.WorkerName
|
||||||
|
`$workerType = `$params.WorkerType
|
||||||
|
`$payloadBase64 = `$params.PayloadBase64
|
||||||
|
`$dataRoot = Join-Path ([Environment]::GetFolderPath('LocalApplicationData')) 'UnifiedWorkers'
|
||||||
|
`$instanceRoot = Join-Path (Join-Path `$dataRoot `$workerType) `$workerName
|
||||||
|
`$metaPath = Join-Path `$instanceRoot 'state\worker-info.json'
|
||||||
|
`$controllerPath = Join-Path `$dataRoot 'controller.ps1'
|
||||||
|
|
||||||
|
if (-not (Test-Path `$controllerPath)) {
|
||||||
|
throw "Controller missing at `$controllerPath"
|
||||||
|
}
|
||||||
|
|
||||||
|
`$shouldStart = `$true
|
||||||
|
if (Test-Path `$metaPath) {
|
||||||
|
try {
|
||||||
|
`$meta = Get-Content `$metaPath -Raw | ConvertFrom-Json
|
||||||
|
if (`$meta.Status -eq 'running' -and `$meta.WorkerPid) {
|
||||||
|
if (Get-Process -Id `$meta.WorkerPid -ErrorAction SilentlyContinue) {
|
||||||
|
Write-Host "Worker `$workerName already running (PID `$($meta.WorkerPid))."
|
||||||
|
`$shouldStart = `$false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Unable to parse metadata for `$workerName. Starting new controller." -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (`$shouldStart) {
|
||||||
|
`$pwsh = Get-Command pwsh -ErrorAction SilentlyContinue
|
||||||
|
if (`$pwsh) {
|
||||||
|
`$psExe = `$pwsh.Source
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
`$psExe = (Get-Command powershell -ErrorAction Stop).Source
|
||||||
|
}
|
||||||
|
|
||||||
|
`$controllerArgs = @(
|
||||||
|
'-NoLogo','-NoProfile','-ExecutionPolicy','Bypass',
|
||||||
|
'-File',"`$controllerPath",
|
||||||
|
'-WorkerName',"`$workerName",
|
||||||
|
'-WorkerType',"`$workerType",
|
||||||
|
'-PayloadBase64',"`$payloadBase64"
|
||||||
|
)
|
||||||
|
|
||||||
|
Start-Process -FilePath `$psExe -ArgumentList `$controllerArgs -WindowStyle Hidden | Out-Null
|
||||||
|
Write-Host "Worker `$workerName started under controller." -ForegroundColor Green
|
||||||
|
}
|
||||||
|
"@
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ensure-PersistentWorker {
|
||||||
|
param(
|
||||||
|
[object]$Worker,
|
||||||
|
[string]$WorkerType,
|
||||||
|
[string]$PayloadScript
|
||||||
|
)
|
||||||
|
|
||||||
|
Write-Host "[$($Worker.Name)] Ensuring worker is running under controller..." -ForegroundColor Cyan
|
||||||
|
Ensure-ControllerDeployed -Worker $Worker
|
||||||
|
$payloadBase64 = ConvertTo-Base64Unicode -Content $PayloadScript
|
||||||
|
$ensureScript = Get-EnsureWorkerScript -WorkerName $Worker.Name -WorkerType $WorkerType -PayloadBase64 $payloadBase64
|
||||||
|
$result = Invoke-RemotePowerShell -Worker $Worker -Script $ensureScript
|
||||||
|
if ($result -ne 0) {
|
||||||
|
Write-Host "[$($Worker.Name)] Remote ensure command exited with code $result." -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-WorkerAttach {
|
||||||
|
param(
|
||||||
|
[object]$Worker,
|
||||||
|
[string]$WorkerType,
|
||||||
|
[switch]$CommandOnly,
|
||||||
|
[string]$Command
|
||||||
|
)
|
||||||
|
|
||||||
|
Ensure-AttachHelperDeployed -Worker $Worker
|
||||||
|
$paramsBlock = @("-WorkerName","$($Worker.Name)","-WorkerType","$WorkerType")
|
||||||
|
if ($CommandOnly) {
|
||||||
|
$paramsBlock += "-CommandOnly"
|
||||||
|
}
|
||||||
|
if ($Command) {
|
||||||
|
$paramsBlock += "-Command"
|
||||||
|
$paramsBlock += $Command
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = Get-WorkerConnectionParts -RawArgs $Worker.SSHArgs -DefaultHost $Worker.Name
|
||||||
|
$sshArgs = Build-SshArgsFromParts -Parts $parts -Interactive:(!$CommandOnly)
|
||||||
|
$remoteBasePath = Get-WorkerBasePath -Worker $Worker -ConnectionParts $parts
|
||||||
|
$remoteHelper = Join-Path $remoteBasePath 'attach-helper.ps1'
|
||||||
|
$quotedArgs = ($paramsBlock | ForEach-Object { '"' + ($_ -replace '"','""') + '"' }) -join ' '
|
||||||
|
$remoteCmd = "powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -File `"$remoteHelper`" $quotedArgs"
|
||||||
|
|
||||||
|
& ssh @sshArgs $remoteCmd
|
||||||
|
}
|
||||||
|
|
||||||
# FUNCTIONS
|
# FUNCTIONS
|
||||||
|
|
||||||
# This function generates the standard PowerShell remote command
|
# This function generates the standard PowerShell remote command
|
||||||
@@ -259,56 +625,9 @@ function Start-StandardWorker {
|
|||||||
[object]$Worker
|
[object]$Worker
|
||||||
)
|
)
|
||||||
|
|
||||||
$retryCount = 0
|
$payloadScript = Get-RemoteStandardWorkerCommand
|
||||||
$retryDelay = 15 # seconds between retries
|
Ensure-PersistentWorker -Worker $Worker -WorkerType 'flamenco' -PayloadScript $payloadScript
|
||||||
$workerRestarted = $false
|
Invoke-WorkerAttach -Worker $Worker -WorkerType 'flamenco'
|
||||||
|
|
||||||
while ($true) { # Changed to infinite loop
|
|
||||||
if ($retryCount -gt 0) {
|
|
||||||
Write-Host "`nRestarting worker process (Attempt $($retryCount + 1))..." -ForegroundColor Yellow
|
|
||||||
Start-Sleep -Seconds $retryDelay
|
|
||||||
$workerRestarted = $true
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "Connecting to $($Worker.Name)..." -ForegroundColor Cyan
|
|
||||||
if ($workerRestarted) {
|
|
||||||
Write-Host "Worker was restarted due to disconnection or crash." -ForegroundColor Yellow
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$remoteCommand = Get-RemoteStandardWorkerCommand
|
|
||||||
|
|
||||||
# Encode the command to handle special characters
|
|
||||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($remoteCommand)
|
|
||||||
$encodedCommand = [Convert]::ToBase64String($bytes)
|
|
||||||
|
|
||||||
# Execute the encoded command on the remote machine
|
|
||||||
Write-Host "Connecting to $($Worker.Name) and executing worker script..." -ForegroundColor Yellow
|
|
||||||
|
|
||||||
# Add SSH keepalive settings to reduce chance of random disconnections
|
|
||||||
$sshCommand = "ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=30 $($Worker.SSHArgs) ""powershell -EncodedCommand $encodedCommand"""
|
|
||||||
|
|
||||||
# Execute the SSH command and capture the exit code
|
|
||||||
Invoke-Expression $sshCommand
|
|
||||||
$sshExitCode = $LASTEXITCODE
|
|
||||||
|
|
||||||
# Check if SSH command completed successfully
|
|
||||||
if ($sshExitCode -eq 0) {
|
|
||||||
Write-Host "`nWorker completed successfully. Restarting automatically..." -ForegroundColor Green
|
|
||||||
Start-Sleep -Seconds 2 # Brief pause before restarting
|
|
||||||
$retryCount = 0 # Reset counter for successful completion
|
|
||||||
continue # Continue the loop instead of breaking
|
|
||||||
} else {
|
|
||||||
throw "Worker process exited with code: $sshExitCode"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
$retryCount++
|
|
||||||
Write-Host "`nAn error occurred while running worker on $($Worker.Name):" -ForegroundColor Red
|
|
||||||
Write-Host $_.Exception.Message -ForegroundColor Red
|
|
||||||
Write-Host "`nAttempting to restart worker in $retryDelay seconds..." -ForegroundColor Yellow
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# This function launches the CMD worker
|
# This function launches the CMD worker
|
||||||
@@ -318,56 +637,9 @@ function Start-CmdWorker {
|
|||||||
[object]$Worker
|
[object]$Worker
|
||||||
)
|
)
|
||||||
|
|
||||||
$retryCount = 0
|
$payloadScript = Get-RemoteCmdWorkerCommand
|
||||||
$retryDelay = 5 # seconds between retries
|
Ensure-PersistentWorker -Worker $Worker -WorkerType 'flamenco' -PayloadScript $payloadScript
|
||||||
$workerRestarted = $false
|
Invoke-WorkerAttach -Worker $Worker -WorkerType 'flamenco'
|
||||||
|
|
||||||
while ($true) { # Changed to infinite loop
|
|
||||||
if ($retryCount -gt 0) {
|
|
||||||
Write-Host "`nRestarting worker process (Attempt $($retryCount + 1))..." -ForegroundColor Yellow
|
|
||||||
Start-Sleep -Seconds $retryDelay
|
|
||||||
$workerRestarted = $true
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "Connecting to $($Worker.Name) (CMD mode)..." -ForegroundColor Cyan
|
|
||||||
if ($workerRestarted) {
|
|
||||||
Write-Host "Worker was restarted due to disconnection or crash." -ForegroundColor Yellow
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$remoteCommand = Get-RemoteCmdWorkerCommand
|
|
||||||
|
|
||||||
# Encode the command to handle special characters
|
|
||||||
$bytes = [System.Text.Encoding]::Unicode.GetBytes($remoteCommand)
|
|
||||||
$encodedCommand = [Convert]::ToBase64String($bytes)
|
|
||||||
|
|
||||||
# Execute the encoded command on the remote machine
|
|
||||||
Write-Host "Connecting to $($Worker.Name) and executing CMD worker script..." -ForegroundColor Yellow
|
|
||||||
|
|
||||||
# Add SSH keepalive settings to reduce chance of random disconnections
|
|
||||||
$sshCommand = "ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=30 $($Worker.SSHArgs) ""powershell -EncodedCommand $encodedCommand"""
|
|
||||||
|
|
||||||
# Execute the SSH command and capture the exit code
|
|
||||||
Invoke-Expression $sshCommand
|
|
||||||
$sshExitCode = $LASTEXITCODE
|
|
||||||
|
|
||||||
# Check if SSH command completed successfully
|
|
||||||
if ($sshExitCode -eq 0) {
|
|
||||||
Write-Host "`nWorker completed successfully. Restarting automatically..." -ForegroundColor Green
|
|
||||||
Start-Sleep -Seconds 2 # Brief pause before restarting
|
|
||||||
$retryCount = 0 # Reset counter for successful completion
|
|
||||||
continue # Continue the loop instead of breaking
|
|
||||||
} else {
|
|
||||||
throw "Worker process exited with code: $sshExitCode"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
$retryCount++
|
|
||||||
Write-Host "`nAn error occurred while running worker on $($Worker.Name):" -ForegroundColor Red
|
|
||||||
Write-Host $_.Exception.Message -ForegroundColor Red
|
|
||||||
Write-Host "`nAttempting to restart worker in $retryDelay seconds..." -ForegroundColor Yellow
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# This function launches ALL workers in Windows Terminal tabs
|
# This function launches ALL workers in Windows Terminal tabs
|
||||||
@@ -377,173 +649,21 @@ function Start-AllWorkers {
|
|||||||
[string]$WorkerType
|
[string]$WorkerType
|
||||||
)
|
)
|
||||||
|
|
||||||
Write-Host "Launching ALL $WorkerType workers in Windows Terminal tabs..." -ForegroundColor Cyan
|
Write-Host "Ensuring ALL $WorkerType workers are running under controllers..." -ForegroundColor Cyan
|
||||||
|
|
||||||
try {
|
$payloadScript = if ($WorkerType -eq 'CMD') {
|
||||||
# First, check if Windows Terminal is available
|
Get-RemoteCmdWorkerCommand
|
||||||
if (-not (Get-Command wt.exe -ErrorAction SilentlyContinue)) {
|
} else {
|
||||||
Write-Host "Windows Terminal (wt.exe) not found. Falling back to separate windows." -ForegroundColor Yellow
|
Get-RemoteStandardWorkerCommand
|
||||||
$useTerminal = $false
|
|
||||||
} else {
|
|
||||||
$useTerminal = $true
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($worker in $workers) {
|
|
||||||
# Create a new PowerShell script with a unique name for this worker
|
|
||||||
$tempScriptPath = [System.IO.Path]::GetTempFileName() + ".ps1"
|
|
||||||
|
|
||||||
# Create different script content based on worker type
|
|
||||||
if ($WorkerType -eq "CMD") {
|
|
||||||
# CMD workers get retry logic at the local level
|
|
||||||
$scriptContent = @"
|
|
||||||
# Wrap everything in a try-catch to prevent script termination
|
|
||||||
try {
|
|
||||||
Write-Host 'Launching $WorkerType worker for $($worker.Name)' -ForegroundColor Cyan
|
|
||||||
|
|
||||||
`$retryCount = 0
|
|
||||||
`$retryDelay = 5 # seconds between retries
|
|
||||||
`$workerRestarted = `$false
|
|
||||||
|
|
||||||
while (`$true) { # Changed to infinite loop
|
|
||||||
try {
|
|
||||||
if (`$retryCount -gt 0) {
|
|
||||||
Write-Host "`nRestarting worker process (Attempt `$(`$retryCount + 1))..." -ForegroundColor Yellow
|
|
||||||
Start-Sleep -Seconds `$retryDelay
|
|
||||||
`$workerRestarted = `$true
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "Connecting to $($worker.Name) ($WorkerType mode)..." -ForegroundColor Cyan
|
|
||||||
if (`$workerRestarted) {
|
|
||||||
Write-Host "Worker was restarted due to disconnection or crash." -ForegroundColor Yellow
|
|
||||||
}
|
|
||||||
|
|
||||||
# Get remote command
|
|
||||||
`$remoteCommand = @'
|
|
||||||
$(Get-RemoteSimplifiedCmdWorkerCommand)
|
|
||||||
'@
|
|
||||||
|
|
||||||
# Encode the command
|
|
||||||
`$bytes = [System.Text.Encoding]::Unicode.GetBytes(`$remoteCommand)
|
|
||||||
`$encodedCommand = [Convert]::ToBase64String(`$bytes)
|
|
||||||
|
|
||||||
# Execute SSH command with keepalive settings and capture exit code
|
|
||||||
ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=30 $($worker.SSHArgs) "powershell -EncodedCommand `$encodedCommand"
|
|
||||||
`$sshExitCode = `$LASTEXITCODE
|
|
||||||
|
|
||||||
# Check if SSH command completed successfully
|
|
||||||
if (`$sshExitCode -eq 0) {
|
|
||||||
Write-Host "`nWorker completed successfully. Restarting automatically..." -ForegroundColor Green
|
|
||||||
Start-Sleep -Seconds 2 # Brief pause before restarting
|
|
||||||
`$retryCount = 0 # Reset counter for successful completion
|
|
||||||
continue # Continue the loop instead of breaking
|
|
||||||
} else {
|
|
||||||
throw "SSH command failed with exit code: `$sshExitCode"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
`$retryCount++
|
|
||||||
Write-Host "An error occurred while connecting to $($worker.Name):" -ForegroundColor Red
|
|
||||||
Write-Host `$_.Exception.Message -ForegroundColor Red
|
|
||||||
Write-Host "Attempting to reconnect in `$retryDelay seconds..." -ForegroundColor Yellow
|
|
||||||
# Don't rethrow - we want to continue the retry loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
# This outer catch block is for any unexpected errors that might terminate the script
|
|
||||||
Write-Host "`nCRITICAL ERROR: Script encountered an unexpected error:" -ForegroundColor Red
|
|
||||||
Write-Host `$_.Exception.Message -ForegroundColor Red
|
|
||||||
Write-Host "`nRestarting the entire worker process in 5 seconds..." -ForegroundColor Yellow
|
|
||||||
Start-Sleep -Seconds 5
|
|
||||||
# Restart the script by calling itself
|
|
||||||
& `$MyInvocation.MyCommand.Path
|
|
||||||
}
|
|
||||||
"@
|
|
||||||
} else {
|
|
||||||
# Standard workers keep the original retry logic
|
|
||||||
$scriptContent = @"
|
|
||||||
# Wrap everything in a try-catch to prevent script termination
|
|
||||||
try {
|
|
||||||
Write-Host 'Launching $WorkerType worker for $($worker.Name)' -ForegroundColor Cyan
|
|
||||||
|
|
||||||
`$retryCount = 0
|
|
||||||
`$retryDelay = 5 # seconds between retries
|
|
||||||
|
|
||||||
while (`$true) { # Changed to infinite loop
|
|
||||||
try {
|
|
||||||
if (`$retryCount -gt 0) {
|
|
||||||
Write-Host "Retry attempt `$retryCount..." -ForegroundColor Yellow
|
|
||||||
Start-Sleep -Seconds `$retryDelay
|
|
||||||
}
|
|
||||||
|
|
||||||
# Get remote command
|
|
||||||
`$remoteCommand = @'
|
|
||||||
$(Get-RemoteStandardWorkerCommand)
|
|
||||||
'@
|
|
||||||
|
|
||||||
# Encode the command
|
|
||||||
`$bytes = [System.Text.Encoding]::Unicode.GetBytes(`$remoteCommand)
|
|
||||||
`$encodedCommand = [Convert]::ToBase64String(`$bytes)
|
|
||||||
|
|
||||||
# Execute SSH command with keepalive settings
|
|
||||||
ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=30 $($worker.SSHArgs) "powershell -EncodedCommand `$encodedCommand"
|
|
||||||
`$sshExitCode = `$LASTEXITCODE
|
|
||||||
|
|
||||||
# Check SSH exit code and handle accordingly
|
|
||||||
if (`$sshExitCode -eq 0) {
|
|
||||||
Write-Host "`nWorker completed successfully. Restarting automatically..." -ForegroundColor Green
|
|
||||||
Start-Sleep -Seconds 2 # Brief pause before restarting
|
|
||||||
`$retryCount = 0 # Reset counter for successful completion
|
|
||||||
continue # Continue the loop instead of breaking
|
|
||||||
} else {
|
|
||||||
throw "SSH command failed with exit code: `$sshExitCode"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
`$retryCount++
|
|
||||||
Write-Host "An error occurred while connecting to $($worker.Name):" -ForegroundColor Red
|
|
||||||
Write-Host `$_.Exception.Message -ForegroundColor Red
|
|
||||||
Write-Host "Attempting to reconnect in `$retryDelay seconds..." -ForegroundColor Yellow
|
|
||||||
# Don't rethrow - we want to continue the retry loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
# This outer catch block is for any unexpected errors that might terminate the script
|
|
||||||
Write-Host "`nCRITICAL ERROR: Script encountered an unexpected error:" -ForegroundColor Red
|
|
||||||
Write-Host `$_.Exception.Message -ForegroundColor Red
|
|
||||||
Write-Host "`nRestarting the entire worker process in 5 seconds..." -ForegroundColor Yellow
|
|
||||||
Start-Sleep -Seconds 5
|
|
||||||
# Restart the script by calling itself
|
|
||||||
& `$MyInvocation.MyCommand.Path
|
|
||||||
}
|
|
||||||
"@
|
|
||||||
}
|
|
||||||
|
|
||||||
# Write the script to file
|
|
||||||
Set-Content -Path $tempScriptPath -Value $scriptContent
|
|
||||||
|
|
||||||
if ($useTerminal) {
|
|
||||||
# Launch in a new Windows Terminal tab
|
|
||||||
$tabTitle = "$($worker.Name) - $WorkerType Worker"
|
|
||||||
Start-Process wt.exe -ArgumentList "-w 0 new-tab --title `"$tabTitle`" powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -File `"$tempScriptPath`""
|
|
||||||
} else {
|
|
||||||
# Fallback to separate window if Windows Terminal is not available
|
|
||||||
Start-Process powershell -ArgumentList "-NoLogo -NoProfile -ExecutionPolicy Bypass -File `"$tempScriptPath`""
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "Started $($worker.Name) ($WorkerType) worker in a new tab." -ForegroundColor Green
|
|
||||||
Start-Sleep -Milliseconds 300 # Small delay between launches
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "`nAll $WorkerType worker scripts have been launched in Windows Terminal tabs." -ForegroundColor Cyan
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
Write-Host "Error launching workers: $($_.Exception.Message)" -ForegroundColor Red
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach ($worker in $workers) {
|
||||||
|
Ensure-PersistentWorker -Worker $worker -WorkerType 'flamenco' -PayloadScript $payloadScript
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "All workers processed. Attach to any worker from the menu to monitor output." -ForegroundColor Green
|
||||||
Write-Host "Press Enter to return to the menu..." -ForegroundColor Green
|
Write-Host "Press Enter to return to the menu..." -ForegroundColor Green
|
||||||
Read-Host
|
Read-Host | Out-Null
|
||||||
}
|
}
|
||||||
|
|
||||||
# Main menu loop
|
# Main menu loop
|
||||||
|
|||||||
5
unified_sheepit_launcher.bat
Normal file
5
unified_sheepit_launcher.bat
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
@echo off
|
||||||
|
title Unified SheepIt Launcher
|
||||||
|
echo Starting Unified SheepIt Launcher...
|
||||||
|
powershell -ExecutionPolicy Bypass -File "%~dp0unified_sheepit_launcher.ps1"
|
||||||
|
|
||||||
793
unified_sheepit_launcher.ps1
Normal file
793
unified_sheepit_launcher.ps1
Normal file
@@ -0,0 +1,793 @@
|
|||||||
|
function Show-Header {
|
||||||
|
Clear-Host
|
||||||
|
Write-Host "====================================" -ForegroundColor Cyan
|
||||||
|
Write-Host " UNIFIED SHEEPIT LAUNCHER" -ForegroundColor Cyan
|
||||||
|
Write-Host "====================================" -ForegroundColor Cyan
|
||||||
|
Write-Host
|
||||||
|
}
|
||||||
|
|
||||||
|
$SheepItJarUrls = @(
|
||||||
|
'https://www.sheepit-renderfarm.com/media/applet/client-latest.php',
|
||||||
|
'https://www.sheepit-renderfarm.com/media/applet/client-latest.jar'
|
||||||
|
)
|
||||||
|
$script:SheepItUsername = $null
|
||||||
|
$script:SheepItRenderKey = $null
|
||||||
|
|
||||||
|
function Initialize-SheepItCredentials {
|
||||||
|
if (-not $script:SheepItUsername) {
|
||||||
|
$script:SheepItUsername = "RaincloudTheDragon"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $script:SheepItRenderKey) {
|
||||||
|
$script:SheepItRenderKey = "IfCOWBHFQpceG0601DmyrwOOJOAp2UJAQ0O0X0jF"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$workers = @(
|
||||||
|
@{ ID = 1; Name = "i9kf"; SSHArgs = "-t i9kf"; Enabled = $true },
|
||||||
|
@{ ID = 2; Name = "blender-boss"; SSHArgs = "-t blender-boss"; Enabled = $true },
|
||||||
|
@{ ID = 3; Name = "max"; SSHArgs = "-t max"; Enabled = $true },
|
||||||
|
@{ ID = 4; Name = "masterbox"; SSHArgs = "-t masterbox"; Enabled = $true },
|
||||||
|
@{ ID = 5; Name = "echo"; SSHArgs = "-t echo"; Enabled = $true },
|
||||||
|
@{ ID = 6; Name = "i9-13ks"; SSHArgs = "-t -p 22146 i9-13ks"; Enabled = $true }
|
||||||
|
)
|
||||||
|
|
||||||
|
$script:ControllerScriptBase64 = $null
|
||||||
|
$script:AttachHelperScriptBase64 = $null
|
||||||
|
$script:WorkerBasePathCache = @{}
|
||||||
|
|
||||||
|
function Remove-ClixmlNoise {
|
||||||
|
param([object[]]$Lines)
|
||||||
|
|
||||||
|
$noisePatterns = @(
|
||||||
|
'^#<\s*CLIXML',
|
||||||
|
'^\s*<Objs\b', '^\s*</Objs>',
|
||||||
|
'^\s*<Obj\b', '^\s*</Obj>',
|
||||||
|
'^\s*<TN\b', '^\s*</TN>',
|
||||||
|
'^\s*<MS\b', '^\s*</MS>',
|
||||||
|
'^\s*<PR\b', '^\s*</PR>',
|
||||||
|
'^\s*<I64\b', '^\s*</I64>',
|
||||||
|
'^\s*<AI\b', '^\s*</AI>',
|
||||||
|
'^\s*<Nil\b', '^\s*</Nil>',
|
||||||
|
'^\s*<PI\b', '^\s*</PI>',
|
||||||
|
'^\s*<PC\b', '^\s*</PC>',
|
||||||
|
'^\s*<SR\b', '^\s*</SR>',
|
||||||
|
'^\s*<SD\b', '^\s*</SD>',
|
||||||
|
'^\s*<S\b', '^\s*</S>'
|
||||||
|
)
|
||||||
|
|
||||||
|
$filtered = @()
|
||||||
|
foreach ($entry in $Lines) {
|
||||||
|
if ($null -eq $entry) { continue }
|
||||||
|
$text = $entry.ToString()
|
||||||
|
$isNoise = $false
|
||||||
|
foreach ($pattern in $noisePatterns) {
|
||||||
|
if ($text -match $pattern) {
|
||||||
|
$isNoise = $true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $isNoise) {
|
||||||
|
$filtered += $text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $filtered
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-FilteredSshOutput {
|
||||||
|
param([object[]]$Lines)
|
||||||
|
$clean = Remove-ClixmlNoise -Lines $Lines
|
||||||
|
foreach ($line in $clean) {
|
||||||
|
Write-Host $line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Build-SshArgsFromParts {
|
||||||
|
param(
|
||||||
|
[pscustomobject]$Parts,
|
||||||
|
[switch]$Interactive
|
||||||
|
)
|
||||||
|
|
||||||
|
$args = @('-o','ServerAliveInterval=60','-o','ServerAliveCountMax=30')
|
||||||
|
if ($Interactive -and $Parts.RequestPty) {
|
||||||
|
$args += '-t'
|
||||||
|
}
|
||||||
|
elseif (-not $Interactive) {
|
||||||
|
$args += '-T'
|
||||||
|
}
|
||||||
|
|
||||||
|
$args += $Parts.Options
|
||||||
|
|
||||||
|
if ($Parts.Port) {
|
||||||
|
$args += '-p'
|
||||||
|
$args += $Parts.Port
|
||||||
|
}
|
||||||
|
|
||||||
|
$args += $Parts.Host
|
||||||
|
return $args
|
||||||
|
}
|
||||||
|
|
||||||
|
function Build-ScpArgsFromParts {
|
||||||
|
param(
|
||||||
|
[pscustomobject]$Parts
|
||||||
|
)
|
||||||
|
|
||||||
|
$args = @('-o','ServerAliveInterval=60','-o','ServerAliveCountMax=30')
|
||||||
|
$args += $Parts.Options
|
||||||
|
if ($Parts.Port) {
|
||||||
|
$args += '-P'
|
||||||
|
$args += $Parts.Port
|
||||||
|
}
|
||||||
|
return $args
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-SshArgs {
|
||||||
|
param(
|
||||||
|
[object]$Worker,
|
||||||
|
[switch]$Interactive
|
||||||
|
)
|
||||||
|
|
||||||
|
$parts = Get-WorkerConnectionParts -RawArgs $Worker.SSHArgs -DefaultHost $Worker.Name
|
||||||
|
return Build-SshArgsFromParts -Parts $parts -Interactive:$Interactive
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-WorkerBasePath {
|
||||||
|
param(
|
||||||
|
[object]$Worker,
|
||||||
|
[pscustomobject]$ConnectionParts = $null
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($script:WorkerBasePathCache.ContainsKey($Worker.Name)) {
|
||||||
|
return $script:WorkerBasePathCache[$Worker.Name]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $ConnectionParts) {
|
||||||
|
$ConnectionParts = Get-WorkerConnectionParts -RawArgs $Worker.SSHArgs -DefaultHost $Worker.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
$sshArgs = Build-SshArgsFromParts -Parts $ConnectionParts -Interactive:$false
|
||||||
|
$scriptBlock = "`$ProgressPreference='SilentlyContinue'; [Environment]::GetFolderPath('LocalApplicationData')"
|
||||||
|
$encoded = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($scriptBlock))
|
||||||
|
$remoteCmd = "powershell -NoLogo -NoProfile -NonInteractive -OutputFormat Text -ExecutionPolicy Bypass -EncodedCommand $encoded"
|
||||||
|
$rawOutput = & ssh @sshArgs $remoteCmd 2>&1
|
||||||
|
$output = Remove-ClixmlNoise -Lines $rawOutput
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
throw "Unable to determine LocalAppData on $($Worker.Name)."
|
||||||
|
}
|
||||||
|
|
||||||
|
$base = ($output | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Select-Object -Last 1).Trim()
|
||||||
|
if (-not $base) {
|
||||||
|
throw "Unable to read LocalAppData path on $($Worker.Name)."
|
||||||
|
}
|
||||||
|
|
||||||
|
$final = Join-Path $base 'UnifiedWorkers'
|
||||||
|
$script:WorkerBasePathCache[$Worker.Name] = $final
|
||||||
|
return $final
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-FileBase64 {
|
||||||
|
param([string]$Path)
|
||||||
|
[Convert]::ToBase64String([IO.File]::ReadAllBytes($Path))
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-ControllerScriptBase64 {
|
||||||
|
if (-not $script:ControllerScriptBase64) {
|
||||||
|
$controllerPath = Join-Path $PSScriptRoot 'remote_worker_controller.ps1'
|
||||||
|
$script:ControllerScriptBase64 = Get-FileBase64 -Path $controllerPath
|
||||||
|
}
|
||||||
|
return $script:ControllerScriptBase64
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-AttachHelperScriptBase64 {
|
||||||
|
if (-not $script:AttachHelperScriptBase64) {
|
||||||
|
$helperPath = Join-Path $PSScriptRoot 'remote_worker_attach.ps1'
|
||||||
|
$script:AttachHelperScriptBase64 = Get-FileBase64 -Path $helperPath
|
||||||
|
}
|
||||||
|
return $script:AttachHelperScriptBase64
|
||||||
|
}
|
||||||
|
|
||||||
|
function ConvertTo-Base64Unicode {
|
||||||
|
param([string]$Content)
|
||||||
|
[Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($Content))
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-WorkerSshArgs {
|
||||||
|
param([string]$RawArgs)
|
||||||
|
if ([string]::IsNullOrWhiteSpace($RawArgs)) {
|
||||||
|
return @()
|
||||||
|
}
|
||||||
|
return $RawArgs -split '\s+' | Where-Object { $_.Trim().Length -gt 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-WorkerConnectionParts {
|
||||||
|
param(
|
||||||
|
[string]$RawArgs,
|
||||||
|
[string]$DefaultHost
|
||||||
|
)
|
||||||
|
|
||||||
|
$tokens = Get-WorkerSshArgs -RawArgs $RawArgs
|
||||||
|
$options = New-Object System.Collections.Generic.List[string]
|
||||||
|
$targetHost = $null
|
||||||
|
$port = $null
|
||||||
|
$requestPty = $false
|
||||||
|
$optionsWithArgs = @('-i','-o','-c','-D','-E','-F','-I','-J','-L','-l','-m','-O','-Q','-R','-S','-W','-w')
|
||||||
|
|
||||||
|
for ($i = 0; $i -lt $tokens.Count; $i++) {
|
||||||
|
$token = $tokens[$i]
|
||||||
|
if ($token -eq '-t' -or $token -eq '-tt') {
|
||||||
|
$requestPty = $true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($token -eq '-p' -and ($i + 1) -lt $tokens.Count) {
|
||||||
|
$port = $tokens[$i + 1]
|
||||||
|
$i++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($token.StartsWith('-')) {
|
||||||
|
$options.Add($token)
|
||||||
|
if ($optionsWithArgs -contains $token -and ($i + 1) -lt $tokens.Count) {
|
||||||
|
$options.Add($tokens[$i + 1])
|
||||||
|
$i++
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $targetHost) {
|
||||||
|
$targetHost = $token
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
$options.Add($token)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $targetHost) {
|
||||||
|
$targetHost = $DefaultHost
|
||||||
|
}
|
||||||
|
|
||||||
|
return [pscustomobject]@{
|
||||||
|
Host = $targetHost
|
||||||
|
Options = $options.ToArray()
|
||||||
|
Port = $port
|
||||||
|
RequestPty = $requestPty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-RemotePowerShell {
|
||||||
|
param(
|
||||||
|
[object]$Worker,
|
||||||
|
[string]$Script,
|
||||||
|
[switch]$Interactive
|
||||||
|
)
|
||||||
|
|
||||||
|
$parts = Get-WorkerConnectionParts -RawArgs $Worker.SSHArgs -DefaultHost $Worker.Name
|
||||||
|
if (-not $parts.Host) {
|
||||||
|
throw "Unable to determine SSH host for $($Worker.Name)"
|
||||||
|
}
|
||||||
|
|
||||||
|
$sshBaseArgs = Build-SshArgsFromParts -Parts $parts -Interactive:$Interactive
|
||||||
|
$remoteBasePath = Get-WorkerBasePath -Worker $Worker -ConnectionParts $parts
|
||||||
|
$localTemp = [System.IO.Path]::GetTempFileName() + '.ps1'
|
||||||
|
Set-Content -Path $localTemp -Value $Script -Encoding UTF8
|
||||||
|
|
||||||
|
$remoteTmpDir = Join-Path $remoteBasePath 'tmp'
|
||||||
|
$remoteScriptWin = Join-Path $remoteTmpDir ("script-{0}.ps1" -f ([guid]::NewGuid().ToString()))
|
||||||
|
$remoteScriptScp = $remoteScriptWin -replace '\\','/'
|
||||||
|
$remoteTarget = "{0}:{1}" -f $parts.Host, ('"'+$remoteScriptScp+'"')
|
||||||
|
|
||||||
|
$ensureScript = "New-Item -ItemType Directory -Path '$remoteTmpDir' -Force | Out-Null"
|
||||||
|
$ensureCmd = "powershell -NoLogo -NoProfile -NonInteractive -OutputFormat Text -ExecutionPolicy Bypass -EncodedCommand " + [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($ensureScript))
|
||||||
|
$ensureOutput = & ssh @sshBaseArgs $ensureCmd 2>&1
|
||||||
|
$ensureExit = $LASTEXITCODE
|
||||||
|
Write-FilteredSshOutput -Lines $ensureOutput
|
||||||
|
if ($ensureExit -ne 0) {
|
||||||
|
Remove-Item $localTemp -ErrorAction SilentlyContinue
|
||||||
|
return $ensureExit
|
||||||
|
}
|
||||||
|
|
||||||
|
$scpArgs = Build-ScpArgsFromParts -Parts $parts
|
||||||
|
$scpArgs += $localTemp
|
||||||
|
$scpArgs += $remoteTarget
|
||||||
|
|
||||||
|
& scp @scpArgs
|
||||||
|
$scpExit = $LASTEXITCODE
|
||||||
|
Remove-Item $localTemp -ErrorAction SilentlyContinue
|
||||||
|
if ($scpExit -ne 0) {
|
||||||
|
return $scpExit
|
||||||
|
}
|
||||||
|
|
||||||
|
$execCmd = "powershell -NoLogo -NoProfile -NonInteractive -OutputFormat Text -ExecutionPolicy Bypass -File `"$remoteScriptWin`""
|
||||||
|
$execOutput = & ssh @sshBaseArgs $execCmd 2>&1
|
||||||
|
$execExit = $LASTEXITCODE
|
||||||
|
Write-FilteredSshOutput -Lines $execOutput
|
||||||
|
|
||||||
|
$cleanupScript = "Remove-Item -LiteralPath '$remoteScriptWin' -ErrorAction SilentlyContinue"
|
||||||
|
$cleanupCmd = "powershell -NoLogo -NoProfile -NonInteractive -OutputFormat Text -ExecutionPolicy Bypass -EncodedCommand " + [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($cleanupScript))
|
||||||
|
$cleanupOutput = & ssh @sshBaseArgs $cleanupCmd 2>&1
|
||||||
|
Write-FilteredSshOutput -Lines $cleanupOutput
|
||||||
|
|
||||||
|
return [int]$execExit
|
||||||
|
}
|
||||||
|
|
||||||
|
function Resolve-ExitCode {
|
||||||
|
param($Value)
|
||||||
|
|
||||||
|
if ($Value -is [System.Array]) {
|
||||||
|
for ($i = $Value.Count - 1; $i -ge 0; $i--) {
|
||||||
|
$candidate = Resolve-ExitCode -Value $Value[$i]
|
||||||
|
if ($candidate -ne $null) {
|
||||||
|
return $candidate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($Value -is [int]) {
|
||||||
|
return $Value
|
||||||
|
}
|
||||||
|
|
||||||
|
$text = $Value
|
||||||
|
if ($null -eq $text) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
$parsed = 0
|
||||||
|
if ([int]::TryParse($text.ToString(), [ref]$parsed)) {
|
||||||
|
return $parsed
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ensure-ControllerDeployed {
|
||||||
|
param([object]$Worker)
|
||||||
|
$controllerBase64 = Get-ControllerScriptBase64
|
||||||
|
$script = @"
|
||||||
|
`$ProgressPreference = 'SilentlyContinue'
|
||||||
|
`$dataRoot = Join-Path ([Environment]::GetFolderPath('LocalApplicationData')) 'UnifiedWorkers'
|
||||||
|
New-Item -ItemType Directory -Path `$dataRoot -Force | Out-Null
|
||||||
|
`$controllerPath = Join-Path `$dataRoot 'controller.ps1'
|
||||||
|
[IO.File]::WriteAllBytes(`$controllerPath, [Convert]::FromBase64String('$controllerBase64'))
|
||||||
|
"@
|
||||||
|
$exit = Resolve-ExitCode (Invoke-RemotePowerShell -Worker $Worker -Script $script)
|
||||||
|
if ($exit -ne 0) {
|
||||||
|
throw "Controller deployment failed on $($Worker.Name) (exit $exit)."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ensure-AttachHelperDeployed {
|
||||||
|
param([object]$Worker)
|
||||||
|
$helperBase64 = Get-AttachHelperScriptBase64
|
||||||
|
$script = @"
|
||||||
|
`$ProgressPreference = 'SilentlyContinue'
|
||||||
|
`$dataRoot = Join-Path ([Environment]::GetFolderPath('LocalApplicationData')) 'UnifiedWorkers'
|
||||||
|
New-Item -ItemType Directory -Path `$dataRoot -Force | Out-Null
|
||||||
|
`$attachPath = Join-Path `$dataRoot 'attach-helper.ps1'
|
||||||
|
[IO.File]::WriteAllBytes(`$attachPath, [Convert]::FromBase64String('$helperBase64'))
|
||||||
|
"@
|
||||||
|
$exit = Resolve-ExitCode (Invoke-RemotePowerShell -Worker $Worker -Script $script)
|
||||||
|
if ($exit -ne 0) {
|
||||||
|
throw "Attach helper deployment failed on $($Worker.Name) (exit $exit)."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-EnsureWorkerScript {
|
||||||
|
param(
|
||||||
|
[string]$WorkerName,
|
||||||
|
[string]$WorkerType,
|
||||||
|
[string]$PayloadBase64
|
||||||
|
)
|
||||||
|
|
||||||
|
$payload = @{
|
||||||
|
WorkerName = $WorkerName
|
||||||
|
WorkerType = $WorkerType
|
||||||
|
PayloadBase64 = $PayloadBase64
|
||||||
|
} | ConvertTo-Json -Compress
|
||||||
|
|
||||||
|
$payloadBase64 = ConvertTo-Base64Unicode -Content $payload
|
||||||
|
|
||||||
|
return @"
|
||||||
|
`$ProgressPreference = 'SilentlyContinue'
|
||||||
|
`$params = ConvertFrom-Json ([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('$payloadBase64')))
|
||||||
|
`$workerName = `$params.WorkerName
|
||||||
|
`$workerType = `$params.WorkerType
|
||||||
|
`$payloadBase64 = `$params.PayloadBase64
|
||||||
|
`$dataRoot = Join-Path ([Environment]::GetFolderPath('LocalApplicationData')) 'UnifiedWorkers'
|
||||||
|
`$instanceRoot = Join-Path (Join-Path `$dataRoot `$workerType) `$workerName
|
||||||
|
`$logsRoot = Join-Path `$instanceRoot 'logs'
|
||||||
|
`$stateRoot = Join-Path `$instanceRoot 'state'
|
||||||
|
New-Item -ItemType Directory -Path `$logsRoot -Force | Out-Null
|
||||||
|
New-Item -ItemType Directory -Path `$stateRoot -Force | Out-Null
|
||||||
|
`$logPath = Join-Path `$logsRoot 'worker.log'
|
||||||
|
`$commandPath = Join-Path `$stateRoot 'commands.txt'
|
||||||
|
`$payloadPath = Join-Path `$stateRoot 'payload.ps1'
|
||||||
|
`$payloadBase64Path = Join-Path `$stateRoot 'payload.b64'
|
||||||
|
if (-not (Test-Path `$logPath)) { New-Item -Path `$logPath -ItemType File -Force | Out-Null }
|
||||||
|
if (-not (Test-Path `$commandPath)) { New-Item -Path `$commandPath -ItemType File -Force | Out-Null }
|
||||||
|
[IO.File]::WriteAllText(`$payloadBase64Path, `$payloadBase64, [System.Text.Encoding]::UTF8)
|
||||||
|
`$metaPath = Join-Path `$instanceRoot 'state\worker-info.json'
|
||||||
|
`$controllerPath = Join-Path `$dataRoot 'controller.ps1'
|
||||||
|
|
||||||
|
if (-not (Test-Path `$controllerPath)) {
|
||||||
|
throw "Controller missing at `$controllerPath"
|
||||||
|
}
|
||||||
|
|
||||||
|
`$shouldStart = `$true
|
||||||
|
if (Test-Path `$metaPath) {
|
||||||
|
try {
|
||||||
|
`$meta = Get-Content `$metaPath -Raw | ConvertFrom-Json
|
||||||
|
if (`$meta.Status -eq 'running' -and `$meta.WorkerPid) {
|
||||||
|
if (Get-Process -Id `$meta.WorkerPid -ErrorAction SilentlyContinue) {
|
||||||
|
Write-Host "Worker `$workerName already running (PID `$($meta.WorkerPid))."
|
||||||
|
`$shouldStart = `$false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Failed to read metadata. Controller will restart worker." -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (`$shouldStart) {
|
||||||
|
`$initialMeta = [pscustomobject]@{
|
||||||
|
WorkerName = `$workerName
|
||||||
|
WorkerType = `$workerType
|
||||||
|
Status = 'launching'
|
||||||
|
ControllerPid = `$null
|
||||||
|
WorkerPid = `$null
|
||||||
|
Restarts = 0
|
||||||
|
LastExitCode = `$null
|
||||||
|
LogPath = `$logPath
|
||||||
|
CommandPath = `$commandPath
|
||||||
|
PayloadPath = `$payloadPath
|
||||||
|
UpdatedAtUtc = (Get-Date).ToUniversalTime()
|
||||||
|
} | ConvertTo-Json -Depth 5
|
||||||
|
`$initialMeta | Set-Content -Path `$metaPath -Encoding UTF8
|
||||||
|
|
||||||
|
`$pwsh = Get-Command pwsh -ErrorAction SilentlyContinue
|
||||||
|
if (`$pwsh) {
|
||||||
|
`$psExe = `$pwsh.Source
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
`$psExe = (Get-Command powershell -ErrorAction Stop).Source
|
||||||
|
}
|
||||||
|
|
||||||
|
`$controllerArgs = @(
|
||||||
|
'-NoLogo','-NoProfile','-ExecutionPolicy','Bypass',
|
||||||
|
'-File',"`$controllerPath",
|
||||||
|
'-WorkerName',"`$workerName",
|
||||||
|
'-WorkerType',"`$workerType",
|
||||||
|
'-PayloadBase64Path',"`$payloadBase64Path"
|
||||||
|
)
|
||||||
|
|
||||||
|
Start-Process -FilePath `$psExe -ArgumentList `$controllerArgs -WindowStyle Hidden | Out-Null
|
||||||
|
Write-Host "Worker `$workerName started under controller." -ForegroundColor Green
|
||||||
|
}
|
||||||
|
"@
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ensure-PersistentWorker {
|
||||||
|
param(
|
||||||
|
[object]$Worker,
|
||||||
|
[string]$WorkerType,
|
||||||
|
[string]$PayloadScript
|
||||||
|
)
|
||||||
|
|
||||||
|
Ensure-ControllerDeployed -Worker $Worker
|
||||||
|
$payloadBase64 = ConvertTo-Base64Unicode -Content $PayloadScript
|
||||||
|
$ensureScript = Get-EnsureWorkerScript -WorkerName $Worker.Name -WorkerType $WorkerType -PayloadBase64 $payloadBase64
|
||||||
|
$exit = Resolve-ExitCode (Invoke-RemotePowerShell -Worker $Worker -Script $ensureScript)
|
||||||
|
if ($exit -ne 0) {
|
||||||
|
throw "Worker ensure script failed on $($Worker.Name) (exit $exit)."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-WorkerMetadataExists {
|
||||||
|
param(
|
||||||
|
[object]$Worker,
|
||||||
|
[string]$WorkerType
|
||||||
|
)
|
||||||
|
|
||||||
|
$payload = @{
|
||||||
|
WorkerName = $Worker.Name
|
||||||
|
WorkerType = $WorkerType
|
||||||
|
} | ConvertTo-Json -Compress
|
||||||
|
$payloadBase64 = ConvertTo-Base64Unicode -Content $payload
|
||||||
|
|
||||||
|
$script = @"
|
||||||
|
`$ProgressPreference = 'SilentlyContinue'
|
||||||
|
`$params = ConvertFrom-Json ([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('$payloadBase64')))
|
||||||
|
`$dataRoot = Join-Path ([Environment]::GetFolderPath('LocalApplicationData')) 'UnifiedWorkers'
|
||||||
|
`$instanceRoot = Join-Path (Join-Path `$dataRoot `$params.WorkerType) `$params.WorkerName
|
||||||
|
`$metaPath = Join-Path `$instanceRoot 'state\worker-info.json'
|
||||||
|
if (Test-Path `$metaPath) {
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
exit 1
|
||||||
|
"@
|
||||||
|
|
||||||
|
$result = Invoke-RemotePowerShell -Worker $Worker -Script $script
|
||||||
|
return ($result -eq 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Wait-WorkerMetadata {
|
||||||
|
param(
|
||||||
|
[object]$Worker,
|
||||||
|
[string]$WorkerType,
|
||||||
|
[int]$TimeoutSeconds = 30
|
||||||
|
)
|
||||||
|
|
||||||
|
$deadline = [DateTime]::UtcNow.AddSeconds($TimeoutSeconds)
|
||||||
|
while ([DateTime]::UtcNow -lt $deadline) {
|
||||||
|
if (Test-WorkerMetadataExists -Worker $Worker -WorkerType $WorkerType) {
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
Start-Sleep -Milliseconds 500
|
||||||
|
}
|
||||||
|
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-WorkerAttach {
|
||||||
|
param(
|
||||||
|
[object]$Worker,
|
||||||
|
[string]$WorkerType,
|
||||||
|
[switch]$CommandOnly,
|
||||||
|
[string]$Command
|
||||||
|
)
|
||||||
|
|
||||||
|
Ensure-AttachHelperDeployed -Worker $Worker
|
||||||
|
$paramsBlock = @("-WorkerName","$($Worker.Name)","-WorkerType","$WorkerType")
|
||||||
|
if ($CommandOnly) {
|
||||||
|
$paramsBlock += "-CommandOnly"
|
||||||
|
}
|
||||||
|
if ($Command) {
|
||||||
|
$paramsBlock += "-Command"
|
||||||
|
$paramsBlock += $Command
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = Get-WorkerConnectionParts -RawArgs $Worker.SSHArgs -DefaultHost $Worker.Name
|
||||||
|
$sshArgs = Build-SshArgsFromParts -Parts $parts -Interactive:(!$CommandOnly)
|
||||||
|
$remoteBase = Get-WorkerBasePath -Worker $Worker -ConnectionParts $parts
|
||||||
|
$remoteHelper = Join-Path $remoteBase 'attach-helper.ps1'
|
||||||
|
$quotedArgs = ($paramsBlock | ForEach-Object { '"' + ($_ -replace '"','""') + '"' }) -join ' '
|
||||||
|
$remoteCmd = "powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -File `"$remoteHelper`" $quotedArgs"
|
||||||
|
|
||||||
|
& ssh @sshArgs $remoteCmd
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-RemoteSheepItCommand {
|
||||||
|
param(
|
||||||
|
[string]$RenderKey,
|
||||||
|
[string]$Username
|
||||||
|
)
|
||||||
|
|
||||||
|
$safeKey = $RenderKey -replace "'", "''"
|
||||||
|
$safeUser = $Username -replace "'", "''"
|
||||||
|
|
||||||
|
$urlLiteral = '@(' + (($SheepItJarUrls | ForEach-Object { "'$_'" }) -join ', ') + ')'
|
||||||
|
|
||||||
|
@"
|
||||||
|
`$ProgressPreference = 'SilentlyContinue'
|
||||||
|
`$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
try {
|
||||||
|
`$appData = [Environment]::GetFolderPath('ApplicationData')
|
||||||
|
`$sheepDir = Join-Path `$appData 'sheepit'
|
||||||
|
if (-not (Test-Path `$sheepDir)) {
|
||||||
|
New-Item -Path `$sheepDir -ItemType Directory -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
`$jarPath = Join-Path `$sheepDir 'sheepit-client.jar'
|
||||||
|
`$urls = $urlLiteral
|
||||||
|
`$headers = @{ 'User-Agent' = 'Mozilla/5.0' }
|
||||||
|
|
||||||
|
if (Test-Path `$jarPath) {
|
||||||
|
Write-Host "SheepIt client already present at `$jarPath. Skipping download." -ForegroundColor Green
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
`$downloaded = `$false
|
||||||
|
|
||||||
|
foreach (`$url in `$urls) {
|
||||||
|
Write-Host "Downloading SheepIt client from `$url..." -ForegroundColor Cyan
|
||||||
|
try {
|
||||||
|
Invoke-WebRequest -Uri `$url -OutFile `$jarPath -UseBasicParsing -Headers `$headers
|
||||||
|
`$downloaded = `$true
|
||||||
|
Write-Host "Download complete." -ForegroundColor Green
|
||||||
|
break
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Host ("Download failed from {0}: {1}" -f `$url, `$_.Exception.Message) -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not `$downloaded) {
|
||||||
|
throw 'Unable to download SheepIt client from any known URL.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Starting SheepIt client..." -ForegroundColor Cyan
|
||||||
|
|
||||||
|
# Check and fix problematic environment variables that can cause boot class path errors
|
||||||
|
`$envVarsFixed = `$false
|
||||||
|
|
||||||
|
# Check JAVA_HOME - invalid values like '\' or empty can cause issues
|
||||||
|
if (`$env:JAVA_HOME) {
|
||||||
|
if (`$env:JAVA_HOME -eq '\' -or `$env:JAVA_HOME.Trim() -eq '' -or -not (Test-Path `$env:JAVA_HOME)) {
|
||||||
|
Write-Host "Warning: Invalid JAVA_HOME detected ('`$env:JAVA_HOME'). Temporarily unsetting..." -ForegroundColor Yellow
|
||||||
|
Remove-Item Env:\JAVA_HOME -ErrorAction SilentlyContinue
|
||||||
|
`$envVarsFixed = `$true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check JAVA_TOOL_OPTIONS - invalid values can cause boot class path errors
|
||||||
|
if (`$env:JAVA_TOOL_OPTIONS) {
|
||||||
|
if (`$env:JAVA_TOOL_OPTIONS -eq '\' -or `$env:JAVA_TOOL_OPTIONS.Trim() -eq '') {
|
||||||
|
Write-Host "Warning: Invalid JAVA_TOOL_OPTIONS detected ('`$env:JAVA_TOOL_OPTIONS'). Temporarily unsetting..." -ForegroundColor Yellow
|
||||||
|
Remove-Item Env:\JAVA_TOOL_OPTIONS -ErrorAction SilentlyContinue
|
||||||
|
`$envVarsFixed = `$true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (`$envVarsFixed) {
|
||||||
|
Write-Host "Environment variables fixed. Proceeding with Java launch..." -ForegroundColor Green
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check Java version
|
||||||
|
try {
|
||||||
|
`$javaOutput = java -version 2>&1
|
||||||
|
`$javaVersion = `$javaOutput | Select-Object -First 1
|
||||||
|
Write-Host "Java version: `$javaVersion" -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Host "Warning: Could not determine Java version" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
|
||||||
|
Set-Location `$sheepDir
|
||||||
|
|
||||||
|
# Use -XX:+IgnoreUnrecognizedVMOptions to handle any incompatible JVM args
|
||||||
|
# This flag helps with Java 9+ compatibility issues
|
||||||
|
`$javaArgs = @('-XX:+IgnoreUnrecognizedVMOptions', '-jar', `$jarPath,
|
||||||
|
'-ui', 'text', '--log-stdout', '--verbose',
|
||||||
|
'-gpu', 'OPTIX_0', '-login', '${safeUser}', '-password', '${safeKey}')
|
||||||
|
|
||||||
|
try {
|
||||||
|
& java @javaArgs
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Host ('Java execution error: {0}' -f `$_.Exception.Message) -ForegroundColor Red
|
||||||
|
Write-Host "If the error persists, try reinstalling Java (Temurin 21 recommended)." -ForegroundColor Yellow
|
||||||
|
throw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
catch {
|
||||||
|
Write-Host ('Error: {0}' -f `$_.Exception.Message) -ForegroundColor Red
|
||||||
|
Write-Host ('Stack trace: {0}' -f `$_.ScriptStackTrace) -ForegroundColor DarkRed
|
||||||
|
}
|
||||||
|
"@
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ensure-SheepItWorkerController {
|
||||||
|
param([object]$Worker)
|
||||||
|
Initialize-SheepItCredentials
|
||||||
|
$payloadScript = Get-RemoteSheepItCommand -RenderKey $script:SheepItRenderKey -Username $script:SheepItUsername
|
||||||
|
Ensure-PersistentWorker -Worker $Worker -WorkerType 'sheepit' -PayloadScript $payloadScript
|
||||||
|
}
|
||||||
|
|
||||||
|
function Start-SheepItWorker {
|
||||||
|
param([object]$Worker)
|
||||||
|
try {
|
||||||
|
Write-Host "Ensuring SheepIt controller on $($Worker.Name)..." -ForegroundColor Cyan
|
||||||
|
Ensure-SheepItWorkerController -Worker $Worker
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Host "Failed to ensure controller on $($Worker.Name): $($_.Exception.Message)" -ForegroundColor Red
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Wait-WorkerMetadata -Worker $Worker -WorkerType 'sheepit' -TimeoutSeconds 30)) {
|
||||||
|
Write-Host "Worker metadata did not appear on $($Worker.Name). Check controller logs under %LocalAppData%\UnifiedWorkers." -ForegroundColor Red
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Controller ready. Attaching to SheepIt worker on $($Worker.Name)..." -ForegroundColor Cyan
|
||||||
|
Invoke-WorkerAttach -Worker $Worker -WorkerType 'sheepit'
|
||||||
|
}
|
||||||
|
|
||||||
|
function Start-AllSheepIt {
|
||||||
|
Initialize-SheepItCredentials
|
||||||
|
foreach ($worker in $workers | Where-Object { $_.Enabled }) {
|
||||||
|
Ensure-SheepItWorkerController -Worker $worker
|
||||||
|
}
|
||||||
|
Write-Host "All enabled SheepIt workers ensured running under controllers." -ForegroundColor Green
|
||||||
|
Write-Host "Use the attach option to monitor any worker." -ForegroundColor Cyan
|
||||||
|
Read-Host "Press Enter to continue" | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Send-SheepItCommandAll {
|
||||||
|
param([string]$CommandText)
|
||||||
|
|
||||||
|
foreach ($worker in $workers | Where-Object { $_.Enabled }) {
|
||||||
|
Write-Host "[$($worker.Name)] Sending '$CommandText'..." -ForegroundColor Gray
|
||||||
|
Invoke-WorkerAttach -Worker $worker -WorkerType 'sheepit' -CommandOnly -Command $CommandText
|
||||||
|
}
|
||||||
|
Write-Host "Command '$CommandText' dispatched to all enabled workers." -ForegroundColor Green
|
||||||
|
Read-Host "Press Enter to continue" | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function Select-SheepItWorker {
|
||||||
|
while ($true) {
|
||||||
|
Show-Header
|
||||||
|
Write-Host "Select a system:" -ForegroundColor Magenta
|
||||||
|
|
||||||
|
foreach ($worker in $workers) {
|
||||||
|
$status = if ($worker.Enabled) { "ready" } else { "disabled" }
|
||||||
|
$color = if ($worker.Enabled) { "Green" } else { "DarkYellow" }
|
||||||
|
Write-Host ("{0}. {1} ({2})" -f $worker.ID, $worker.Name, $status) -ForegroundColor $color
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "B. Back" -ForegroundColor Yellow
|
||||||
|
$selection = Read-Host "Choose system"
|
||||||
|
|
||||||
|
if ($selection -match '^[Bb]$') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($selection -match '^\d+$') {
|
||||||
|
$id = [int]$selection
|
||||||
|
$worker = $workers | Where-Object { $_.ID -eq $id }
|
||||||
|
|
||||||
|
if ($worker) {
|
||||||
|
Start-SheepItWorker -Worker $worker
|
||||||
|
Write-Host
|
||||||
|
Read-Host "Press Enter to return to the main menu" | Out-Null
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Unknown selection." -ForegroundColor Red
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host "Invalid input." -ForegroundColor Red
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Initialize-SheepItCredentials
|
||||||
|
|
||||||
|
while ($true) {
|
||||||
|
Show-Header
|
||||||
|
Write-Host "Main Menu:" -ForegroundColor Magenta
|
||||||
|
Write-Host "1. Launch/Attach SheepIt on a single system" -ForegroundColor Yellow
|
||||||
|
Write-Host "2. Ensure all ready systems are running" -ForegroundColor Yellow
|
||||||
|
Write-Host "3. Pause all workers" -ForegroundColor Yellow
|
||||||
|
Write-Host "4. Resume all workers" -ForegroundColor Yellow
|
||||||
|
Write-Host "5. Quit all workers" -ForegroundColor Yellow
|
||||||
|
Write-Host "6. Exit" -ForegroundColor Yellow
|
||||||
|
|
||||||
|
$choice = Read-Host "Select option (1-6)"
|
||||||
|
|
||||||
|
if ($choice -eq '6') {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($choice) {
|
||||||
|
'1' { Select-SheepItWorker }
|
||||||
|
'2' { Start-AllSheepIt }
|
||||||
|
'3' { Send-SheepItCommandAll -CommandText 'pause' }
|
||||||
|
'4' { Send-SheepItCommandAll -CommandText 'resume' }
|
||||||
|
'5' { Send-SheepItCommandAll -CommandText 'quit' }
|
||||||
|
default {
|
||||||
|
Write-Host "Invalid selection." -ForegroundColor Red
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "`nExiting SheepIt launcher." -ForegroundColor Cyan
|
||||||
|
|
||||||
Reference in New Issue
Block a user