231 lines
8.2 KiB
PowerShell
231 lines
8.2 KiB
PowerShell
param(
|
|
[string]$AgentRoot = "C:\Wooo\Agent99",
|
|
[string]$SourceRevision = "",
|
|
[switch]$InstallScheduledTasks
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
$SourceRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
$BinDir = Join-Path $AgentRoot "bin"
|
|
$ConfigDir = Join-Path $AgentRoot "config"
|
|
$EvidenceDir = Join-Path $AgentRoot "evidence"
|
|
$LogDir = Join-Path $AgentRoot "logs"
|
|
$QueueDir = Join-Path $AgentRoot "queue"
|
|
$RequestDir = Join-Path $AgentRoot "requests"
|
|
$AlertDir = Join-Path $AgentRoot "alerts"
|
|
$PlaybookDir = Join-Path $AgentRoot "playbooks"
|
|
$DashboardDir = Join-Path $AgentRoot "dashboard"
|
|
$StateDir = Join-Path $AgentRoot "state"
|
|
|
|
foreach ($dir in @($AgentRoot, $BinDir, $ConfigDir, $EvidenceDir, $LogDir, $QueueDir, $RequestDir, $AlertDir, $PlaybookDir, $DashboardDir, $StateDir)) {
|
|
New-Item -ItemType Directory -Force -Path $dir | Out-Null
|
|
}
|
|
|
|
function Copy-AgentFile {
|
|
param([string]$Name)
|
|
$src = Join-Path $SourceRoot $Name
|
|
$dst = Join-Path $BinDir $Name
|
|
if (Test-Path $src) {
|
|
$srcFull = [System.IO.Path]::GetFullPath($src)
|
|
$dstFull = [System.IO.Path]::GetFullPath($dst)
|
|
if ($srcFull -ne $dstFull) {
|
|
if ([System.IO.Path]::GetExtension($src).ToLowerInvariant() -eq ".ps1") {
|
|
$content = [System.IO.File]::ReadAllText($src)
|
|
$utf8Bom = [System.Text.UTF8Encoding]::new($true)
|
|
[System.IO.File]::WriteAllText($dst, $content, $utf8Bom)
|
|
} else {
|
|
Copy-Item -Force $src $dst
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$agentFiles = @(
|
|
"agent99-control-plane.ps1",
|
|
"agent99-register-tasks.ps1",
|
|
"agent99-submit-request.ps1",
|
|
"agent99-telegram-inbox.ps1",
|
|
"agent99-sre-alert-inbox.ps1",
|
|
"agent99-sre-alert-relay.ps1",
|
|
"host-reboot-scorecard.ps1"
|
|
)
|
|
foreach ($agentFile in $agentFiles) {
|
|
Copy-AgentFile $agentFile
|
|
}
|
|
|
|
$resolvedSourceRevision = $SourceRevision
|
|
if (-not $resolvedSourceRevision) {
|
|
try {
|
|
$gitRevision = & git -C $SourceRoot rev-parse HEAD 2>$null
|
|
if ($LASTEXITCODE -eq 0 -and $gitRevision) {
|
|
$resolvedSourceRevision = ([string]$gitRevision).Trim()
|
|
}
|
|
} catch {
|
|
$resolvedSourceRevision = ""
|
|
}
|
|
}
|
|
if (-not $resolvedSourceRevision) { $resolvedSourceRevision = "unknown" }
|
|
|
|
$manifestRows = @()
|
|
foreach ($agentFile in $agentFiles) {
|
|
$sourcePath = Join-Path $SourceRoot $agentFile
|
|
$runtimePath = Join-Path $BinDir $agentFile
|
|
$sourceExists = Test-Path $sourcePath
|
|
$runtimeExists = Test-Path $runtimePath
|
|
$sourceSha256 = if ($sourceExists) { (Get-FileHash -Algorithm SHA256 -LiteralPath $sourcePath).Hash.ToLowerInvariant() } else { $null }
|
|
$runtimeSha256 = if ($runtimeExists) { (Get-FileHash -Algorithm SHA256 -LiteralPath $runtimePath).Hash.ToLowerInvariant() } else { $null }
|
|
$contentMatched = if ($sourceExists -and $runtimeExists) { [System.IO.File]::ReadAllText($sourcePath) -ceq [System.IO.File]::ReadAllText($runtimePath) } else { $false }
|
|
$manifestRows += [pscustomobject]@{
|
|
name = $agentFile
|
|
sourceExists = $sourceExists
|
|
runtimeExists = $runtimeExists
|
|
sourceSha256 = $sourceSha256
|
|
runtimeSha256 = $runtimeSha256
|
|
contentMatched = [bool]$contentMatched
|
|
matched = [bool]$contentMatched
|
|
}
|
|
}
|
|
$runtimeMatched = [bool](@($manifestRows).Count -eq @($agentFiles).Count -and @($manifestRows | Where-Object { -not $_.matched }).Count -eq 0)
|
|
$runtimeManifest = [pscustomobject]@{
|
|
schemaVersion = "agent99_runtime_manifest_v1"
|
|
generatedAt = (Get-Date -Format o)
|
|
sourceRevision = $resolvedSourceRevision
|
|
runtimeMatched = $runtimeMatched
|
|
fileCount = @($manifestRows).Count
|
|
mismatchCount = @($manifestRows | Where-Object { -not $_.matched }).Count
|
|
files = $manifestRows
|
|
}
|
|
$manifestPath = Join-Path $StateDir "runtime-manifest.json"
|
|
$manifestEvidencePath = Join-Path $EvidenceDir ("agent99-RuntimeManifest-" + (Get-Date -Format "yyyyMMdd-HHmmss") + ".json")
|
|
$runtimeManifest | ConvertTo-Json -Depth 8 | Set-Content -Encoding UTF8 $manifestPath
|
|
$runtimeManifest | ConvertTo-Json -Depth 8 | Set-Content -Encoding UTF8 $manifestEvidencePath
|
|
if (-not $runtimeMatched) {
|
|
throw "Agent99 runtime manifest mismatch; inspect $manifestEvidencePath"
|
|
}
|
|
|
|
$exampleConfig = Join-Path $SourceRoot "agent99.config.example.json"
|
|
$configPath = Join-Path $ConfigDir "agent99.config.json"
|
|
if (-not (Test-Path $configPath)) {
|
|
if (Test-Path $exampleConfig) {
|
|
Copy-Item $exampleConfig $configPath
|
|
} else {
|
|
@"
|
|
{
|
|
"agentName": "Agent99",
|
|
"agentRoot": "$($AgentRoot.Replace('\', '\\'))",
|
|
"sshUser": "wooo",
|
|
"sshUsers": {},
|
|
"vmrunPath": "",
|
|
"hosts": ["192.168.0.110", "192.168.0.112", "192.168.0.120", "192.168.0.121", "192.168.0.188"],
|
|
"vms": [],
|
|
"publicUrls": ["awoooi.wooo.work", "stock.wooo.work", "2026fifa.wooo.work", "gitea.wooo.work", "harbor.wooo.work"],
|
|
"sreAlertRelay": {
|
|
"enabled": true,
|
|
"prefix": "http://+:8787/agent99/sre-alert/",
|
|
"tokenEnv": "AGENT99_SRE_RELAY_TOKEN",
|
|
"allowedRemotePrefixes": ["127.", "::1", "192.168.0."]
|
|
},
|
|
"telegram": {
|
|
"enabled": true,
|
|
"botTokenEnv": "AGENT99_TELEGRAM_BOT_TOKEN",
|
|
"chatIdEnv": "AGENT99_TELEGRAM_CHAT_ID",
|
|
"botTokenEnvAliases": ["AWOOOI_TG_BOT_TOKEN", "OPENCLAW_TG_BOT_TOKEN", "TELEGRAM_BOT_TOKEN", "TELEGRAM_TOKEN", "TG_BOT_TOKEN", "AIDER_WATCH_TELEGRAM_TOKEN"],
|
|
"chatIdEnvAliases": ["TELEGRAM_CHAT_ID", "TELEGRAM_ALERT_CHAT_ID", "TELEGRAM_P0_CHAT_ID", "TELEGRAM_SECURITY_CHAT_ID", "OPENCLAW_TG_CHAT_ID", "TG_CHAT_ID", "AIDER_WATCH_TELEGRAM_CHAT_ID"],
|
|
"relay": { "enabled": true, "host": "192.168.0.110", "container": "stockplatform-v2-api-1" },
|
|
"alertAllOperations": false,
|
|
"alertInfoEvents": false,
|
|
"alertOperatorCommands": true,
|
|
"alertSreCommandResults": true,
|
|
"dedupeMinutes": 30
|
|
},
|
|
"selfHealth": {
|
|
"scheduledTasks": [
|
|
"Wooo-Agent99-Startup-Recovery",
|
|
"Wooo-Agent99-Heartbeat",
|
|
"Wooo-Agent99-Performance-Guard",
|
|
"Wooo-Agent99-Control-Loop",
|
|
"Wooo-Agent99-Telegram-Inbox",
|
|
"Wooo-Agent99-SRE-Alert-Inbox",
|
|
"Wooo-Agent99-SRE-Alert-Relay",
|
|
"Wooo-Agent99-Self-Health",
|
|
"Wooo-Agent99-Backup-Health"
|
|
]
|
|
},
|
|
"performance": {
|
|
"enabled": true,
|
|
"intervalMinutes": 1,
|
|
"loadPerCoreWarning": 0.9,
|
|
"loadPerCoreCritical": 1.5,
|
|
"memoryAvailablePercentCritical": 10,
|
|
"diskUsedPercentWarning": 90,
|
|
"diskUsedPercentCritical": 95,
|
|
"captureTopCpuOnWarning": true,
|
|
"topCpuTimeoutSeconds": 10,
|
|
"loadShedding": { "enabled": true, "actions": [] }
|
|
},
|
|
"backupHealth": {
|
|
"host": "192.168.0.110",
|
|
"targets": [],
|
|
"fileChecks": [],
|
|
"cronPatterns": []
|
|
}
|
|
}
|
|
"@ | Set-Content -Encoding UTF8 $configPath
|
|
}
|
|
}
|
|
|
|
$launcher = Join-Path $AgentRoot "agent99-run.ps1"
|
|
@"
|
|
param(
|
|
[ValidateSet("Status", "Recover", "StartVMs", "PublicSmoke", "HarborRepair", "AwoooRepair", "Perf", "LoadShed", "SelfCheck", "BackupCheck", "ProviderFreshness", "SecurityTriage", "ControlTick")]
|
|
[string]`$Mode = "Status",
|
|
[switch]`$ControlledApply,
|
|
[switch]`$SuppressAlerts,
|
|
[string]`$SuppressReason = ""
|
|
)
|
|
|
|
& "$BinDir\agent99-control-plane.ps1" -Mode `$Mode -ControlledApply:`$ControlledApply -SuppressAlerts:`$SuppressAlerts -SuppressReason `$SuppressReason -ConfigPath "$configPath" -EvidenceDir "$EvidenceDir"
|
|
"@ | Set-Content -Encoding UTF8 $launcher
|
|
|
|
$submitCmd = Join-Path $AgentRoot "agent99-submit-request.cmd"
|
|
@"
|
|
@echo off
|
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "$BinDir\agent99-submit-request.ps1" -RunNow
|
|
pause
|
|
"@ | Set-Content -Encoding ASCII $submitCmd
|
|
|
|
function Find-Vmrun {
|
|
$candidates = @(
|
|
"C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe",
|
|
"C:\Program Files\VMware\VMware Workstation\vmrun.exe"
|
|
)
|
|
foreach ($candidate in $candidates) {
|
|
if (Test-Path $candidate) { return $candidate }
|
|
}
|
|
return ""
|
|
}
|
|
|
|
$vmrun = Find-Vmrun
|
|
if ($vmrun) {
|
|
$config = Get-Content $configPath -Raw | ConvertFrom-Json
|
|
$config.vmrunPath = $vmrun
|
|
$config | ConvertTo-Json -Depth 8 | Set-Content -Encoding UTF8 $configPath
|
|
}
|
|
|
|
if ($InstallScheduledTasks) {
|
|
& (Join-Path $BinDir "agent99-register-tasks.ps1") -AgentRoot $AgentRoot
|
|
}
|
|
|
|
Write-Host "Agent99 bootstrap complete"
|
|
Write-Host "AgentRoot: $AgentRoot"
|
|
Write-Host "Config: $configPath"
|
|
Write-Host "Evidence: $EvidenceDir"
|
|
Write-Host "Runtime manifest: $manifestPath"
|
|
Write-Host "Source revision: $resolvedSourceRevision"
|
|
if ($vmrun) {
|
|
Write-Host "vmrun: $vmrun"
|
|
} else {
|
|
Write-Host "vmrun: not detected; update agent99.config.json"
|
|
}
|