param( [int]$Port = 18083 ) $ErrorActionPreference = "Stop" $Root = Resolve-Path (Join-Path $PSScriptRoot "..") $RunDir = Join-Path $Root "target\run" New-Item -ItemType Directory -Force -Path $RunDir | Out-Null $ExistingListener = Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1 if ($ExistingListener) { $Process = Get-Process -Id $ExistingListener.OwningProcess -ErrorAction SilentlyContinue $Name = if ($Process) { $Process.ProcessName } else { "未知进程" } throw "端口 $Port 已被 PID $($ExistingListener.OwningProcess) ($Name) 占用。请换一个端口,例如 -Port $($Port + 1),或先停止该进程。" } $Config = Join-Path $RunDir "server-$Port.toml" $Db = (Join-Path $RunDir "lightops-$Port.db").Replace("\", "/") @" bind = "127.0.0.1:$Port" database_url = "sqlite://${Db}?mode=rwc" jwt_secret = "local-dev-lightops-secret-please-change" public_url = "http://127.0.0.1:$Port" static_dir = "web/dist" registration_token_ttl_minutes = 30 task_timeout_secs = 20 "@ | Set-Content -Encoding UTF8 -Path $Config $ServerOut = Join-Path $RunDir "server-$Port.out" $ServerErr = Join-Path $RunDir "server-$Port.err" $AgentOut = Join-Path $RunDir "agent-$Port.out" $AgentErr = Join-Path $RunDir "agent-$Port.err" $Server = Start-Process ` -FilePath (Join-Path $Root "target\debug\lightops-server.exe") ` -ArgumentList @("--config", $Config) ` -WorkingDirectory $Root ` -PassThru ` -WindowStyle Hidden ` -RedirectStandardOutput $ServerOut ` -RedirectStandardError $ServerErr Set-Content -Path (Join-Path $RunDir "server-$Port.pid") -Value $Server.Id Start-Sleep -Seconds 2 if ($Server.HasExited) { throw "Server 提前退出,退出码 $($Server.ExitCode)。请查看 $ServerOut 和 $ServerErr" } $BaseUrl = "http://127.0.0.1:$Port" $Page = Invoke-WebRequest -UseBasicParsing "$BaseUrl/" -TimeoutSec 10 $InitBody = @{ username = "admin"; password = "LightOps@123456" } | ConvertTo-Json $Init = Invoke-RestMethod -Method Post -Uri "$BaseUrl/api/auth/init" -ContentType "application/json" -Body $InitBody -TimeoutSec 10 $Jwt = $Init.data.token $Headers = @{ Authorization = "Bearer $Jwt" } $TokenBody = @{ name = "本机测试节点"; ttl_minutes = 30 } | ConvertTo-Json $AgentTokenResp = Invoke-RestMethod -Method Post -Uri "$BaseUrl/api/agent-tokens" -Headers $Headers -ContentType "application/json" -Body $TokenBody -TimeoutSec 10 $AgentToken = $AgentTokenResp.data.token $AgentConfig = Join-Path $RunDir "agent-$Port.toml" $Agent = Start-Process ` -FilePath (Join-Path $Root "target\debug\lightops-agent.exe") ` -ArgumentList @("--server", $BaseUrl, "--token", $AgentToken, "--config", $AgentConfig, "--name", "本机测试节点") ` -WorkingDirectory $Root ` -PassThru ` -WindowStyle Hidden ` -RedirectStandardOutput $AgentOut ` -RedirectStandardError $AgentErr Set-Content -Path (Join-Path $RunDir "agent-$Port.pid") -Value $Agent.Id Start-Sleep -Seconds 5 if ($Agent.HasExited) { throw "Agent 提前退出,退出码 $($Agent.ExitCode)。请查看 $AgentOut 和 $AgentErr" } $Agents = Invoke-RestMethod -Method Get -Uri "$BaseUrl/api/agents" -Headers $Headers -TimeoutSec 10 $AgentId = $Agents.data[0].id $Metrics = Invoke-RestMethod -Method Get -Uri "$BaseUrl/api/agents/$AgentId/metrics" -Headers $Headers -TimeoutSec 10 $Files = Invoke-RestMethod -Method Get -Uri "$BaseUrl/api/agents/$AgentId/files?path=." -Headers $Headers -TimeoutSec 10 [pscustomobject]@{ url = $BaseUrl server_pid = $Server.Id agent_pid = $Agent.Id page_status = $Page.StatusCode init_success = $Init.success token_created = $AgentTokenResp.success agent_count = @($Agents.data).Count agent_id = $AgentId agent_status = $Agents.data[0].status metrics_count = @($Metrics.data).Count file_api_success = $Files.success file_count = @($Files.data.entries).Count username = "admin" password = "LightOps@123456" } | ConvertTo-Json -Depth 5