Files
NODEDC_MISSION_CORE/deploy/telemetry-plane/telegraf/Update-NdcMissionCoreTelegraf.ps1
T

179 lines
7.4 KiB
PowerShell

[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$ConfigurationTemplate,
[string]$PipelineCollector = "$PSScriptRoot\Get-NdcMissionCorePipelineTelemetry.ps1",
[string]$PipelineJournal = "D:\NDC_MISSIONCORE\runtime\derived\.perception-persistent-publish\pipeline-telemetry.jsonl"
)
$ErrorActionPreference = "Stop"
$serviceName = "telegraf"
$installRoot = "C:\Program Files\NDC\Mission Core\Telegraf"
$configurationRoot = "C:\ProgramData\NDC\MissionCore\telemetry-agent"
$configurationPath = Join-Path $configurationRoot "telegraf.conf"
$collectorPath = Join-Path $configurationRoot "Get-NdcMissionCorePipelineTelemetry.ps1"
$executable = Join-Path $installRoot "telegraf.exe"
$serviceRegistryPath = "HKLM:\SYSTEM\CurrentControlSet\Services\$serviceName"
$service = Get-Service -Name $serviceName -ErrorAction Stop
if (-not (Test-Path -LiteralPath $executable -PathType Leaf)) {
throw "NDC Mission Core Telegraf executable is missing"
}
if (-not (Test-Path -LiteralPath $ConfigurationTemplate -PathType Leaf)) {
throw "Configuration template not found: $ConfigurationTemplate"
}
if (-not (Test-Path -LiteralPath $PipelineCollector -PathType Leaf)) {
throw "Pipeline collector not found: $PipelineCollector"
}
$journalParent = Get-Item -LiteralPath (
Resolve-Path -LiteralPath (Split-Path $PipelineJournal -Parent)
).Path -Force
if (
-not $journalParent.PSIsContainer -or
($journalParent.Attributes -band [IO.FileAttributes]::ReparsePoint) -or
[IO.Path]::GetPathRoot($journalParent.FullName).TrimEnd("\") -ine "D:"
) {
throw "Pipeline journal parent must be a real D: directory"
}
if (Test-Path -LiteralPath $PipelineJournal) {
$journal = Get-Item -LiteralPath $PipelineJournal -Force
if (
$journal.PSIsContainer -or
($journal.Attributes -band [IO.FileAttributes]::ReparsePoint)
) {
throw "Pipeline journal must be a regular file"
}
}
else {
New-Item -ItemType File -Path $PipelineJournal | Out-Null
}
$serviceEnvironmentBefore = @((Get-ItemProperty -Path $serviceRegistryPath).Environment)
foreach ($entry in $serviceEnvironmentBefore) {
$name, $value = $entry -split "=", 2
if ($name -and $value) {
Set-Item -Path "Env:$name" -Value $value
}
}
if (-not $env:MISSIONCORE_TELEMETRY_INTERVAL) {
$env:MISSIONCORE_TELEMETRY_INTERVAL = "2s"
}
$serviceEnvironmentCandidate = @($serviceEnvironmentBefore)
if (-not ($serviceEnvironmentCandidate | Where-Object {
$_ -like "MISSIONCORE_TELEMETRY_INTERVAL=*"
})) {
$serviceEnvironmentCandidate += (
"MISSIONCORE_TELEMETRY_INTERVAL=$($env:MISSIONCORE_TELEMETRY_INTERVAL)"
)
}
$temporaryRoot = Join-Path $env:TEMP "ndc-mission-core-telegraf-update-$([Guid]::NewGuid().ToString('N'))"
$validationOutput = Join-Path $temporaryRoot "validation.out.log"
$validationError = Join-Path $temporaryRoot "validation.error.log"
$backupRoot = Join-Path $configurationRoot "backups"
$backupPath = Join-Path $backupRoot "telegraf-$([DateTime]::UtcNow.ToString('yyyyMMddTHHmmssZ')).conf"
$backupCollectorPath = Join-Path $backupRoot `
"pipeline-collector-$([DateTime]::UtcNow.ToString('yyyyMMddTHHmmssZ')).ps1"
$hadCollector = Test-Path -LiteralPath $collectorPath -PathType Leaf
try {
New-Item -ItemType Directory -Path $temporaryRoot, $backupRoot -Force | Out-Null
$collectorProbe = & powershell.exe -NoLogo -NoProfile -NonInteractive `
-ExecutionPolicy Bypass -File $PipelineCollector
if ($LASTEXITCODE -ne 0) {
throw "Pipeline collector validation failed"
}
$collectorDocument = $collectorProbe | ConvertFrom-Json
if (@($collectorDocument).Count -ne 9) {
throw "Pipeline collector must publish exactly nine stage samples"
}
if ($hadCollector) {
Copy-Item -LiteralPath $collectorPath -Destination $backupCollectorPath
}
Copy-Item -LiteralPath $PipelineCollector -Destination $collectorPath
$validation = Start-Process -FilePath $executable `
-ArgumentList @("--config", $ConfigurationTemplate, "--test") `
-NoNewWindow -Wait -PassThru `
-RedirectStandardOutput $validationOutput `
-RedirectStandardError $validationError
if ($validation.ExitCode -ne 0) {
$validationDetail = Get-Content -LiteralPath $validationError -Tail 8 |
Out-String
throw "Telegraf configuration validation failed: $validationDetail"
}
Copy-Item -LiteralPath $configurationPath -Destination $backupPath
Set-ItemProperty -Path $serviceRegistryPath -Name Environment `
-Type MultiString -Value $serviceEnvironmentCandidate
Stop-Service -Name $serviceName
$service = Get-Service -Name $serviceName
$service.WaitForStatus(
[ServiceProcess.ServiceControllerStatus]::Stopped,
[TimeSpan]::FromSeconds(20)
)
try {
Copy-Item -LiteralPath $ConfigurationTemplate -Destination $configurationPath
Start-Service -Name $serviceName
$service = Get-Service -Name $serviceName
$service.WaitForStatus(
[ServiceProcess.ServiceControllerStatus]::Running,
[TimeSpan]::FromSeconds(20)
)
& sc.exe failure $serviceName reset= 86400 `
actions= restart/5000/restart/30000/restart/60000 | Out-Null
if ($LASTEXITCODE -ne 0) {
throw "Failed to configure Telegraf service recovery actions"
}
& sc.exe failureflag $serviceName 1 | Out-Null
if ($LASTEXITCODE -ne 0) {
throw "Failed to enable Telegraf recovery for non-crash failures"
}
}
catch {
Stop-Service -Name $serviceName -Force -ErrorAction SilentlyContinue
$service = Get-Service -Name $serviceName
if ($service.Status -ne [ServiceProcess.ServiceControllerStatus]::Stopped) {
$service.WaitForStatus(
[ServiceProcess.ServiceControllerStatus]::Stopped,
[TimeSpan]::FromSeconds(20)
)
}
Set-ItemProperty -Path $serviceRegistryPath -Name Environment `
-Type MultiString -Value $serviceEnvironmentBefore
Copy-Item -LiteralPath $backupPath -Destination $configurationPath
if ($hadCollector) {
Copy-Item -LiteralPath $backupCollectorPath -Destination $collectorPath
}
else {
Remove-Item -LiteralPath $collectorPath -Force -ErrorAction SilentlyContinue
}
Start-Service -Name $serviceName
throw
}
[ordered]@{
SchemaVersion = "missioncore.telemetry-agent-config-result/v1"
ServiceName = $serviceName
Status = (Get-Service -Name $serviceName).Status.ToString()
RecoveryConfigured = $true
Configuration = $configurationPath
Backup = $backupPath
PipelineCollector = $collectorPath
PipelineCollectorBackup = if ($hadCollector) { $backupCollectorPath } else { $null }
PipelineJournal = $PipelineJournal
} | ConvertTo-Json -Compress
}
catch {
Set-ItemProperty -Path $serviceRegistryPath -Name Environment `
-Type MultiString -Value $serviceEnvironmentBefore
if ($hadCollector -and (Test-Path -LiteralPath $backupCollectorPath -PathType Leaf)) {
Copy-Item -LiteralPath $backupCollectorPath -Destination $collectorPath
}
elseif (-not $hadCollector) {
Remove-Item -LiteralPath $collectorPath -Force -ErrorAction SilentlyContinue
}
throw
}
finally {
Remove-Item -LiteralPath $temporaryRoot -Recurse -Force -ErrorAction SilentlyContinue
}