Compare commits
21 Commits
fix/engine
...
feat/mcp
| Author | SHA1 | Date | |
|---|---|---|---|
| 0c7f736d73 | |||
|
|
c1dbeeea1c | ||
|
|
1e221eafe7 | ||
|
|
ca7224391d | ||
|
|
25ed7571a1 | ||
|
|
9f36ca794e | ||
|
|
ea4006b290 | ||
|
|
cb99fc2470 | ||
|
|
76c9ed376c | ||
|
|
e01fc6c7c9 | ||
|
|
30a3360f72 | ||
|
|
1fb7093032 | ||
|
|
00e27a77de | ||
|
|
b4b06f361e | ||
|
|
f682432188 | ||
|
|
838a206ed3 | ||
|
|
cfcd5550f2 | ||
|
|
2e01af7957 | ||
|
|
1c72182a73 | ||
|
|
74f15debbc | ||
|
|
01384741c2 |
11
CHANGELOG.md
11
CHANGELOG.md
@@ -2,6 +2,17 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## Release 1.1.4 (2025-01-13)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/webalexeu/winbgp/compare/v1.1.3...v1.1.4)
|
||||||
|
|
||||||
|
**Features**
|
||||||
|
|
||||||
|
- Improve API graceful shutdown
|
||||||
|
- Add control on HealtChecks jobs through CLI
|
||||||
|
|
||||||
|
**Bugfixes**
|
||||||
|
|
||||||
## Release 1.1.3 (2025-01-07)
|
## Release 1.1.3 (2025-01-07)
|
||||||
|
|
||||||
[Full Changelog](https://github.com/webalexeu/winbgp/compare/v1.1.2...v1.1.3)
|
[Full Changelog](https://github.com/webalexeu/winbgp/compare/v1.1.2...v1.1.3)
|
||||||
|
|||||||
@@ -21,8 +21,22 @@ Trap {
|
|||||||
# Reset working dir on error
|
# Reset working dir on error
|
||||||
Pop-Location
|
Pop-Location
|
||||||
}
|
}
|
||||||
|
# If signing, get the certificate
|
||||||
|
if ($Sign) {
|
||||||
|
$cert=Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert | Where-Object { $_.Thumbprint -eq $CertificateThumbprint }
|
||||||
|
}
|
||||||
|
|
||||||
$cert=Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert | Where-Object { $_.Thumbprint -eq $CertificateThumbprint }
|
# Building service executable
|
||||||
|
Write-Output "Building WinBGP service"
|
||||||
|
& "..\service\WinBGP-Service.ps1" -Build
|
||||||
|
Move-Item -Path "..\builder\WinBGP-Service.exe" -Destination "..\service\WinBGP-Service.exe" -Force
|
||||||
|
if ($Sign) {
|
||||||
|
& "C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe" sign /sha1 $CertificateThumbprint /tr http://time.certum.pl/ /td sha256 /fd sha256 /v "..\service\WinBGP-Service.exe"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Building engine
|
||||||
|
Write-Output "Building engine"
|
||||||
|
New-Item -ItemType Directory -Path "..\engine" -Force | Out-Null
|
||||||
Get-ChildItem -Path '..\src' | Where-Object {$_.Extension -eq '.ps1'} | ForEach-Object {
|
Get-ChildItem -Path '..\src' | Where-Object {$_.Extension -eq '.ps1'} | ForEach-Object {
|
||||||
Copy-Item -Path $_.FullName -Destination "..\engine" -Force
|
Copy-Item -Path $_.FullName -Destination "..\engine" -Force
|
||||||
if ($Sign) {
|
if ($Sign) {
|
||||||
@@ -30,17 +44,18 @@ Get-ChildItem -Path '..\src' | Where-Object {$_.Extension -eq '.ps1'} | ForEach
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Verbose "Creating winbgp-${Version}-${Arch}.msi"
|
Write-Output "Building winbgp-${Version}-${Arch}.msi"
|
||||||
$wixArch = @{"amd64" = "x64"; "arm64" = "arm64"}[$Arch]
|
$wixArch = @{"amd64" = "x64"; "arm64" = "arm64"}[$Arch]
|
||||||
|
|
||||||
Invoke-Expression "wix build -arch $wixArch -o .\WinBGP-$($Version)-$($Arch).msi .\files.wxs .\main.wxs -d ProductName=WinBGP -d Version=$($MsiVersion) -ext WixToolset.Firewall.wixext -ext WixToolset.UI.wixext -ext WixToolset.Util.wixext"
|
Invoke-Expression "wix build -arch $wixArch -o .\WinBGP-$($Version)-$($Arch).msi .\files.wxs .\main.wxs -d ProductName=WinBGP -d Version=$($MsiVersion) -ext WixToolset.Firewall.wixext -ext WixToolset.UI.wixext -ext WixToolset.Util.wixext"
|
||||||
|
|
||||||
Write-Verbose "Done!"
|
Write-Output "Build complete !"
|
||||||
Pop-Location
|
|
||||||
|
|
||||||
# Clean temporary build folder
|
# Clean temporary build folder
|
||||||
Remove-Item -Path "..\engine\*"
|
Remove-Item -Path "..\engine\*"
|
||||||
|
|
||||||
|
Write-Output "Release build"
|
||||||
|
New-Item -ItemType Directory -Path "..\release" -Force | Out-Null
|
||||||
Copy-Item -Path "WinBGP-$($Version)-$($Arch).msi" -Destination "..\release" -Force
|
Copy-Item -Path "WinBGP-$($Version)-$($Arch).msi" -Destination "..\release" -Force
|
||||||
if ($Sign) {
|
if ($Sign) {
|
||||||
& "C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe" sign /sha1 $CertificateThumbprint /tr http://time.certum.pl/ /td sha256 /fd sha256 /v "..\release\WinBGP-$($Version)-$($Arch).msi"
|
& "C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe" sign /sha1 $CertificateThumbprint /tr http://time.certum.pl/ /td sha256 /fd sha256 /v "..\release\WinBGP-$($Version)-$($Arch).msi"
|
||||||
|
|||||||
@@ -897,10 +897,10 @@ if ($Build) { # Install the service
|
|||||||
# Generate the service .EXE from the C# source embedded in this script
|
# Generate the service .EXE from the C# source embedded in this script
|
||||||
|
|
||||||
# Overwrite for builder
|
# Overwrite for builder
|
||||||
$exeFullName=".\$exeName"
|
$exeFullName=$exeName
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Write-Verbose "Compiling $exeFullName"
|
Write-Output "Compiling $exeFullName"
|
||||||
Add-Type -TypeDefinition $source -Language CSharp -OutputAssembly $exeFullName -OutputType ConsoleApplication -ReferencedAssemblies "System.ServiceProcess" -Debug:$false
|
Add-Type -TypeDefinition $source -Language CSharp -OutputAssembly $exeFullName -OutputType ConsoleApplication -ReferencedAssemblies "System.ServiceProcess" -Debug:$false
|
||||||
} catch {
|
} catch {
|
||||||
$msg = $_.Exception.Message
|
$msg = $_.Exception.Message
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ Param (
|
|||||||
$Configuration=$false
|
$Configuration=$false
|
||||||
)
|
)
|
||||||
|
|
||||||
$scriptVersion = '1.1.1'
|
$scriptVersion = '1.1.2'
|
||||||
|
|
||||||
# Create detailled log for WinBGP-API
|
# Create detailled log for WinBGP-API
|
||||||
# New-EventLog –LogName Application –Source 'WinBGP-API' -ErrorAction SilentlyContinue
|
# New-EventLog –LogName Application –Source 'WinBGP-API' -ErrorAction SilentlyContinue
|
||||||
@@ -316,6 +316,10 @@ if ($Configuration) {
|
|||||||
}
|
}
|
||||||
# Starting listerner
|
# Starting listerner
|
||||||
$listener.Start()
|
$listener.Start()
|
||||||
|
|
||||||
|
# Flag to control the loop
|
||||||
|
$keepListening = $true
|
||||||
|
|
||||||
# Output listeners
|
# Output listeners
|
||||||
foreach ($ListenerPrefixe in $ListenerPrefixes) {
|
foreach ($ListenerPrefixe in $ListenerPrefixes) {
|
||||||
[String]$Protocol = $ListenerPrefixe.Split('://')[0]
|
[String]$Protocol = $ListenerPrefixe.Split('://')[0]
|
||||||
@@ -324,11 +328,12 @@ if ($Configuration) {
|
|||||||
Write-Log -Message "API started - Listening on '$($IP):$($Port)' (Protocol: $Protocol)"
|
Write-Log -Message "API started - Listening on '$($IP):$($Port)' (Protocol: $Protocol)"
|
||||||
}
|
}
|
||||||
|
|
||||||
while ($listener.IsListening) {
|
while (($listener.IsListening) -and ($keepListening)) {
|
||||||
# Default return
|
# Default return
|
||||||
$statusCode = [System.Net.HttpStatusCode]::OK
|
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||||
$commandOutput = [string]::Empty
|
$commandOutput = [string]::Empty
|
||||||
$outputHeader = @{}
|
$outputHeader = @{}
|
||||||
|
# Accept incoming request
|
||||||
$context = $listener.GetContext()
|
$context = $listener.GetContext()
|
||||||
$request = $context.Request
|
$request = $context.Request
|
||||||
[string]$RequestHost=$request.RemoteEndPoint
|
[string]$RequestHost=$request.RemoteEndPoint
|
||||||
@@ -358,185 +363,282 @@ if ($Configuration) {
|
|||||||
# Write-Log "API request received: $FullRequest" -EventLogSource 'WinBGP-API'
|
# Write-Log "API request received: $FullRequest" -EventLogSource 'WinBGP-API'
|
||||||
$FullPath=($request.RawUrl).substring(1)
|
$FullPath=($request.RawUrl).substring(1)
|
||||||
$Path=$FullPath.Split('?')[0]
|
$Path=$FullPath.Split('?')[0]
|
||||||
switch ($request.HttpMethod) {
|
switch -wildcard ($FullPath) {
|
||||||
'GET' {
|
'api*' {
|
||||||
if ($FullPath -eq 'api') {
|
switch ($request.HttpMethod) {
|
||||||
$commandOutput = ConvertTo-Json -InputObject @{'message'='WinBGP API running'}
|
'GET' {
|
||||||
$statusCode = [System.Net.HttpStatusCode]::OK
|
if ($FullPath -eq 'api') {
|
||||||
} elseif ($FullPath -like 'api/*') {
|
$commandOutput = ConvertTo-Json -InputObject @{'message'='WinBGP API running'}
|
||||||
$Path=$Path.replace('api/','')
|
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||||
$shortPath=$Path.Split('/')[0]
|
} elseif ($FullPath -like 'api/*') {
|
||||||
switch ($shortPath) {
|
$Path=$Path.replace('api/','')
|
||||||
'config' {
|
$shortPath=$Path.Split('/')[0]
|
||||||
if (($Path -eq 'config') -or ($Path -eq 'config/')) {
|
switch ($shortPath) {
|
||||||
$commandOutput = WinBGP -Config | ConvertTo-JSON
|
'config' {
|
||||||
$outputHeader.Add('Content-Type', 'application/json')
|
if (($Path -eq 'config') -or ($Path -eq 'config/')) {
|
||||||
$statusCode = [System.Net.HttpStatusCode]::OK
|
$commandOutput = WinBGP -Config | ConvertTo-JSON
|
||||||
} else {
|
$outputHeader.Add('Content-Type', 'application/json')
|
||||||
$SubConfig=$Path.Split('/')[1]
|
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||||
$commandOutput = (WinBGP -Config).$SubConfig
|
} else {
|
||||||
if ($commandOutput) {
|
$SubConfig=$Path.Split('/')[1]
|
||||||
$commandOutput = $commandOutput | ConvertTo-JSON
|
$commandOutput = (WinBGP -Config).$SubConfig
|
||||||
|
if ($commandOutput) {
|
||||||
|
$commandOutput = $commandOutput | ConvertTo-JSON
|
||||||
|
$outputHeader.Add('Content-Type', 'application/json')
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||||
|
} else {
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::NotFound
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'logs' {
|
||||||
|
$Last = $request.QueryString.Item("Last")
|
||||||
|
if (!($Last)) { $Last = 10 }
|
||||||
|
$commandOutput = WinBGP -Logs -Last $Last | Select-Object Index,TimeGenerated,@{Label='EntryType';Expression={($_.EntryType).ToString()}},Message,RouteName | ConvertTo-JSON
|
||||||
$outputHeader.Add('Content-Type', 'application/json')
|
$outputHeader.Add('Content-Type', 'application/json')
|
||||||
$statusCode = [System.Net.HttpStatusCode]::OK
|
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||||
} else {
|
}
|
||||||
$statusCode = [System.Net.HttpStatusCode]::NotFound
|
'peers' {
|
||||||
|
if (($Path -eq 'peers') -or ($Path -eq 'peers/')) {
|
||||||
|
$commandOutput = ConvertTo-Json -InputObject @(Get-BgpPeer | Select-Object PeerName,LocalIPAddress,LocalASN,PeerIPAddress,PeerASN,@{Label='ConnectivityStatus';Expression={$_.ConnectivityStatus.ToString()}}) #Using @() as inputobject to always return an array
|
||||||
|
$outputHeader.Add('Content-Type', 'application/json')
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||||
|
} else {
|
||||||
|
$PeerName=$Path.Split('/')[1]
|
||||||
|
$commandOutput = Get-BgpPeer | Where-Object {$_.PeerName -eq $PeerName} | Select-Object PeerName,LocalIPAddress,PeerIPAddress,PeerASN,@{Label='ConnectivityStatus';Expression={$_.ConnectivityStatus.ToString()}}
|
||||||
|
if ($commandOutput) {
|
||||||
|
$commandOutput = $commandOutput | ConvertTo-JSON
|
||||||
|
$outputHeader.Add('Content-Type', 'application/json')
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||||
|
} else {
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::NotFound
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'router' {
|
||||||
|
$commandOutput = Get-BgpRouter | Select-Object BgpIdentifier,LocalASN,PeerName,PolicyName | ConvertTo-JSON
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||||
|
}
|
||||||
|
'routes' {
|
||||||
|
if (($Path -eq 'routes') -or ($Path -eq 'routes/')) {
|
||||||
|
$commandOutput = ConvertTo-Json -InputObject @(WinBGP | Select-Object Name,Network,Status,@{Label='MaintenanceTimestamp';Expression={($_.MaintenanceTimestamp).ToString("yyyy-MM-ddTHH:mm:ss.fffK")}}) #Using @() as inputobject to always return an array
|
||||||
|
$outputHeader.Add('Content-Type', 'application/json')
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||||
|
} else {
|
||||||
|
$RouteName=$Path.Split('/')[1]
|
||||||
|
$commandOutput = WinBGP | Where-Object {$_.Name -eq $RouteName} | Select-Object Name,Network,Status,@{Label='MaintenanceTimestamp';Expression={($_.MaintenanceTimestamp).ToString("yyyy-MM-ddTHH:mm:ss.fffK")}}
|
||||||
|
if ($commandOutput) {
|
||||||
|
$commandOutput = $commandOutput | ConvertTo-JSON
|
||||||
|
$outputHeader.Add('Content-Type', 'application/json')
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||||
|
} else {
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::NotFound
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'statistics' {
|
||||||
|
$commandOutput=(Invoke-CimMethod -ClassName "PS_BgpStatistics" -Namespace 'ROOT\Microsoft\Windows\RemoteAccess' -MethodName Get -OperationTimeoutSec 5).cmdletoutput | Select-Object PeerName,TcpConnectionEstablished,TcpConnectionClosed,@{Label='OpenMessage';Expression={$_.OpenMessage.CimInstanceProperties | Select-Object Name,Value}},@{Label='NotificationMessage';Expression={$_.NotificationMessage.CimInstanceProperties | Select-Object Name,Value}},@{Label='KeepAliveMessage';Expression={$_.KeepAliveMessage.CimInstanceProperties | Select-Object Name,Value}},@{Label='RouteRefreshMessage';Expression={$_.RouteRefreshMessage.CimInstanceProperties | Select-Object Name,Value}},@{Label='UpdateMessage';Expression={$_.UpdateMessage.CimInstanceProperties | Select-Object Name,Value}},@{Label='IPv4Route';Expression={$_.IPv4Route.CimInstanceProperties | Select-Object Name,Value}},@{Label='IPv6Route';Expression={$_.IPv6Route.CimInstanceProperties | Select-Object Name,Value}} | ConvertTo-JSON
|
||||||
|
$outputHeader.Add('Content-Type', 'application/json')
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||||
|
}
|
||||||
|
'status' {
|
||||||
|
[string]$status = WinBGP -Status
|
||||||
|
$commandOutput = ConvertTo-Json -InputObject @{'service'=$status}
|
||||||
|
$outputHeader.Add('Content-Type', 'application/json')
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||||
|
}
|
||||||
|
'version' {
|
||||||
|
$commandOutput = WinBGP -Version | ConvertTo-JSON
|
||||||
|
$outputHeader.Add('Content-Type', 'application/json')
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||||
|
}
|
||||||
|
Default {
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::NotImplemented
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'logs' {
|
}
|
||||||
$Last = $request.QueryString.Item("Last")
|
'POST' {
|
||||||
if (!($Last)) { $Last = 10 }
|
$RouteName = $request.QueryString.Item("RouteName")
|
||||||
$commandOutput = WinBGP -Logs -Last $Last | Select-Object Index,TimeGenerated,@{Label='EntryType';Expression={($_.EntryType).ToString()}},Message,RouteName | ConvertTo-JSON
|
$Path=$Path.replace('api/','')
|
||||||
$outputHeader.Add('Content-Type', 'application/json')
|
Write-Log "API received POST request '$Path' from '$RequestUser' - Source IP: '$RequestHost'" -AdditionalFields $RouteName
|
||||||
$statusCode = [System.Net.HttpStatusCode]::OK
|
switch ($Path) {
|
||||||
}
|
'Reload' {
|
||||||
'peers' {
|
[string]$ActionOutput=WinBGP -Reload
|
||||||
if (($Path -eq 'peers') -or ($Path -eq 'peers/')) {
|
$commandOutput = ConvertTo-Json -InputObject @{'output'=$ActionOutput}
|
||||||
$commandOutput = ConvertTo-Json -InputObject @(Get-BgpPeer | Select-Object PeerName,LocalIPAddress,LocalASN,PeerIPAddress,PeerASN,@{Label='ConnectivityStatus';Expression={$_.ConnectivityStatus.ToString()}}) #Using @() as inputobject to always return an array
|
|
||||||
$outputHeader.Add('Content-Type', 'application/json')
|
$outputHeader.Add('Content-Type', 'application/json')
|
||||||
$statusCode = [System.Net.HttpStatusCode]::OK
|
}
|
||||||
} else {
|
'StartMaintenance' {
|
||||||
$PeerName=$Path.Split('/')[1]
|
[string]$ActionOutput=WinBGP -RouteName "$RouteName" -StartMaintenance
|
||||||
$commandOutput = Get-BgpPeer | Where-Object {$_.PeerName -eq $PeerName} | Select-Object PeerName,LocalIPAddress,PeerIPAddress,PeerASN,@{Label='ConnectivityStatus';Expression={$_.ConnectivityStatus.ToString()}}
|
$commandOutput = ConvertTo-Json -InputObject @{'output'=$ActionOutput}
|
||||||
if ($commandOutput) {
|
$outputHeader.Add('Content-Type', 'application/json')
|
||||||
$commandOutput = $commandOutput | ConvertTo-JSON
|
}
|
||||||
$outputHeader.Add('Content-Type', 'application/json')
|
'StartRoute' {
|
||||||
$statusCode = [System.Net.HttpStatusCode]::OK
|
[string]$ActionOutput=WinBGP -RouteName "$RouteName" -StartRoute
|
||||||
} else {
|
$commandOutput = ConvertTo-Json -InputObject @{'output'=$ActionOutput}
|
||||||
$statusCode = [System.Net.HttpStatusCode]::NotFound
|
$outputHeader.Add('Content-Type', 'application/json')
|
||||||
}
|
}
|
||||||
|
'StopMaintenance' {
|
||||||
|
[string]$ActionOutput=WinBGP -RouteName "$RouteName" -StopMaintenance
|
||||||
|
$commandOutput = ConvertTo-Json -InputObject @{'output'=$ActionOutput}
|
||||||
|
$outputHeader.Add('Content-Type', 'application/json')
|
||||||
|
}
|
||||||
|
'StopRoute' {
|
||||||
|
[string]$ActionOutput=WinBGP -RouteName "$RouteName" -StopRoute
|
||||||
|
$commandOutput = ConvertTo-Json -InputObject @{'output'=$ActionOutput}
|
||||||
|
$outputHeader.Add('Content-Type', 'application/json')
|
||||||
|
}
|
||||||
|
Default {
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::NotImplemented
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'router' {
|
switch ($commandOutput.output) {
|
||||||
$commandOutput = Get-BgpRouter | Select-Object BgpIdentifier,LocalASN,PeerName,PolicyName | ConvertTo-JSON
|
'Success' { $statusCode = [System.Net.HttpStatusCode]::OK }
|
||||||
$statusCode = [System.Net.HttpStatusCode]::OK
|
'WinBGP not ready' { $statusCode = [System.Net.HttpStatusCode]::InternalServerError }
|
||||||
}
|
|
||||||
'routes' {
|
|
||||||
if (($Path -eq 'routes') -or ($Path -eq 'routes/')) {
|
|
||||||
$commandOutput = ConvertTo-Json -InputObject @(WinBGP | Select-Object Name,Network,Status,@{Label='MaintenanceTimestamp';Expression={($_.MaintenanceTimestamp).ToString("yyyy-MM-ddTHH:mm:ss.fffK")}}) #Using @() as inputobject to always return an array
|
|
||||||
$outputHeader.Add('Content-Type', 'application/json')
|
|
||||||
$statusCode = [System.Net.HttpStatusCode]::OK
|
|
||||||
} else {
|
|
||||||
$RouteName=$Path.Split('/')[1]
|
|
||||||
$commandOutput = WinBGP | Where-Object {$_.Name -eq $RouteName} | Select-Object Name,Network,Status,@{Label='MaintenanceTimestamp';Expression={($_.MaintenanceTimestamp).ToString("yyyy-MM-ddTHH:mm:ss.fffK")}}
|
|
||||||
if ($commandOutput) {
|
|
||||||
$commandOutput = $commandOutput | ConvertTo-JSON
|
|
||||||
$outputHeader.Add('Content-Type', 'application/json')
|
|
||||||
$statusCode = [System.Net.HttpStatusCode]::OK
|
|
||||||
} else {
|
|
||||||
$statusCode = [System.Net.HttpStatusCode]::NotFound
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'statistics' {
|
|
||||||
$commandOutput=(Invoke-CimMethod -ClassName "PS_BgpStatistics" -Namespace 'ROOT\Microsoft\Windows\RemoteAccess' -MethodName Get -OperationTimeoutSec 5).cmdletoutput | Select-Object PeerName,TcpConnectionEstablished,TcpConnectionClosed,@{Label='OpenMessage';Expression={$_.OpenMessage.CimInstanceProperties | Select-Object Name,Value}},@{Label='NotificationMessage';Expression={$_.NotificationMessage.CimInstanceProperties | Select-Object Name,Value}},@{Label='KeepAliveMessage';Expression={$_.KeepAliveMessage.CimInstanceProperties | Select-Object Name,Value}},@{Label='RouteRefreshMessage';Expression={$_.RouteRefreshMessage.CimInstanceProperties | Select-Object Name,Value}},@{Label='UpdateMessage';Expression={$_.UpdateMessage.CimInstanceProperties | Select-Object Name,Value}},@{Label='IPv4Route';Expression={$_.IPv4Route.CimInstanceProperties | Select-Object Name,Value}},@{Label='IPv6Route';Expression={$_.IPv6Route.CimInstanceProperties | Select-Object Name,Value}} | ConvertTo-JSON
|
|
||||||
$outputHeader.Add('Content-Type', 'application/json')
|
|
||||||
$statusCode = [System.Net.HttpStatusCode]::OK
|
|
||||||
}
|
|
||||||
'status' {
|
|
||||||
[string]$status = WinBGP -Status
|
|
||||||
$commandOutput = ConvertTo-Json -InputObject @{'service'=$status}
|
|
||||||
$outputHeader.Add('Content-Type', 'application/json')
|
|
||||||
$statusCode = [System.Net.HttpStatusCode]::OK
|
|
||||||
}
|
|
||||||
'version' {
|
|
||||||
$commandOutput = WinBGP -Version | ConvertTo-JSON
|
|
||||||
$outputHeader.Add('Content-Type', 'application/json')
|
|
||||||
$statusCode = [System.Net.HttpStatusCode]::OK
|
|
||||||
}
|
|
||||||
Default {
|
|
||||||
$statusCode = [System.Net.HttpStatusCode]::NotImplemented
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif ($FullPath -eq 'metrics') {
|
Default {
|
||||||
# Define WinBGP Prometheus metrics
|
$statusCode = [System.Net.HttpStatusCode]::NotImplemented
|
||||||
$WinBGP_metrics=@()
|
|
||||||
|
|
||||||
# WinBGP peer status
|
|
||||||
$state_peerDescriptor=New-PrometheusMetricDescriptor -Name winbgp_state_peer -Type gauge -Help 'WinBGP Peers status' -Labels local_asn,local_ip,name,peer_asn,peer_ip,state
|
|
||||||
$peerStatus=@('connected','connecting','stopped')
|
|
||||||
# Try/catch to detect if BGP is configured properly
|
|
||||||
$BgpStatus=$null
|
|
||||||
try {
|
|
||||||
$peersCurrentStatus=Get-BgpPeer -ErrorAction SilentlyContinue | Select-Object PeerName,LocalIPAddress,LocalASN,PeerIPAddress,PeerASN,@{Label='ConnectivityStatus';Expression={$_.ConnectivityStatus.ToString()}}
|
|
||||||
}
|
}
|
||||||
catch {
|
|
||||||
#If BGP Router (Local) is not configured, catch it
|
|
||||||
$BgpStatus=($_).ToString()
|
|
||||||
}
|
|
||||||
if ($BgpStatus -eq 'BGP is not configured.') {
|
|
||||||
$peersCurrentStatus=$null
|
|
||||||
}
|
|
||||||
# Parse all peers and generate metric
|
|
||||||
foreach ($peerCurrentStatus in $peersCurrentStatus) {
|
|
||||||
foreach ($status in $peerStatus) {
|
|
||||||
$WinBGP_metrics+=New-PrometheusMetric -PrometheusMetricDescriptor $state_peerDescriptor -Value $(if ($status -eq $peerCurrentStatus.ConnectivityStatus) { 1 } else { 0 }) -Labels $peerCurrentStatus.LocalASN,$peerCurrentStatus.LocalIPAddress,$peerCurrentStatus.PeerName,$peerCurrentStatus.PeerASN,$peerCurrentStatus.PeerIPAddress,$status
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# WinBGP route status
|
|
||||||
$state_routeDescriptor=New-PrometheusMetricDescriptor -Name winbgp_state_route -Type gauge -Help 'WinBGP routes status' -Labels family,maintenance_timestamp,name,network,state
|
|
||||||
$routeStatus=@('down','maintenance','up','warning')
|
|
||||||
# Silently continue as WinBGP is generating errors when BGP is not configured (TO REVIEW)
|
|
||||||
$routesCurrentStatus=(WinBGP -ErrorAction SilentlyContinue | Select-Object Name,Network,Status,@{Label='MaintenanceTimestamp';Expression={($_.MaintenanceTimestamp).ToString("yyyy-MM-ddTHH:mm:ss.fffK")}})
|
|
||||||
foreach ($routeCurrentStatus in $routesCurrentStatus) {
|
|
||||||
foreach ($status in $routeStatus) {
|
|
||||||
$WinBGP_metrics+=New-PrometheusMetric -PrometheusMetricDescriptor $state_routeDescriptor -Value $(if ($status -eq $routeCurrentStatus.Status) { 1 } else { 0 }) -Labels 'ipv4',$routeCurrentStatus.MaintenanceTimestamp,$routeCurrentStatus.Name,$routeCurrentStatus.Network,$status
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Return output
|
|
||||||
$commandOutput = Export-PrometheusMetrics -Metrics $WinBGP_metrics
|
|
||||||
|
|
||||||
# Add header
|
|
||||||
$outputHeader.Add('Content-Type', 'text/plain; version=0.0.4; charset=utf-8')
|
|
||||||
$statusCode = [System.Net.HttpStatusCode]::OK
|
|
||||||
} else {
|
|
||||||
$statusCode = [System.Net.HttpStatusCode]::NotImplemented
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'POST' {
|
'metrics' {
|
||||||
if ($FullPath -like 'api/*') {
|
switch ($request.HttpMethod) {
|
||||||
$RouteName = $request.QueryString.Item("RouteName")
|
'GET' {
|
||||||
$Path=$Path.replace('api/','')
|
# Define WinBGP Prometheus metrics
|
||||||
Write-Log "API received POST request '$Path' from '$RequestUser' - Source IP: '$RequestHost'" -AdditionalFields $RouteName
|
$WinBGP_metrics=@()
|
||||||
switch ($Path) {
|
|
||||||
'Reload' {
|
# WinBGP peer status
|
||||||
[string]$ActionOutput=WinBGP -Reload
|
$state_peerDescriptor=New-PrometheusMetricDescriptor -Name winbgp_state_peer -Type gauge -Help 'WinBGP Peers status' -Labels local_asn,local_ip,name,peer_asn,peer_ip,state
|
||||||
$commandOutput = ConvertTo-Json -InputObject @{'output'=$ActionOutput}
|
$peerStatus=@('connected','connecting','stopped')
|
||||||
$outputHeader.Add('Content-Type', 'application/json')
|
# Try/catch to detect if BGP is configured properly
|
||||||
|
$BgpStatus=$null
|
||||||
|
try {
|
||||||
|
$peersCurrentStatus=Get-BgpPeer -ErrorAction SilentlyContinue | Select-Object PeerName,LocalIPAddress,LocalASN,PeerIPAddress,PeerASN,@{Label='ConnectivityStatus';Expression={$_.ConnectivityStatus.ToString()}}
|
||||||
}
|
}
|
||||||
'StartMaintenance' {
|
catch {
|
||||||
[string]$ActionOutput=WinBGP -RouteName "$RouteName" -StartMaintenance
|
# If BGP Router (Local) is not configured, catch it
|
||||||
$commandOutput = ConvertTo-Json -InputObject @{'output'=$ActionOutput}
|
$BgpStatus=($_).ToString()
|
||||||
$outputHeader.Add('Content-Type', 'application/json')
|
|
||||||
}
|
}
|
||||||
'StartRoute' {
|
if ($BgpStatus -eq 'BGP is not configured.') {
|
||||||
[string]$ActionOutput=WinBGP -RouteName "$RouteName" -StartRoute
|
$peersCurrentStatus=$null
|
||||||
$commandOutput = ConvertTo-Json -InputObject @{'output'=$ActionOutput}
|
|
||||||
$outputHeader.Add('Content-Type', 'application/json')
|
|
||||||
}
|
}
|
||||||
'StopMaintenance' {
|
# Parse all peers and generate metric
|
||||||
[string]$ActionOutput=WinBGP -RouteName "$RouteName" -StopMaintenance
|
foreach ($peerCurrentStatus in $peersCurrentStatus) {
|
||||||
$commandOutput = ConvertTo-Json -InputObject @{'output'=$ActionOutput}
|
foreach ($status in $peerStatus) {
|
||||||
$outputHeader.Add('Content-Type', 'application/json')
|
$WinBGP_metrics+=New-PrometheusMetric -PrometheusMetricDescriptor $state_peerDescriptor -Value $(if ($status -eq $peerCurrentStatus.ConnectivityStatus) { 1 } else { 0 }) -Labels $peerCurrentStatus.LocalASN,$peerCurrentStatus.LocalIPAddress,$peerCurrentStatus.PeerName,$peerCurrentStatus.PeerASN,$peerCurrentStatus.PeerIPAddress,$status
|
||||||
|
}
|
||||||
}
|
}
|
||||||
'StopRoute' {
|
|
||||||
[string]$ActionOutput=WinBGP -RouteName "$RouteName" -StopRoute
|
# WinBGP route status
|
||||||
$commandOutput = ConvertTo-Json -InputObject @{'output'=$ActionOutput}
|
$state_routeDescriptor=New-PrometheusMetricDescriptor -Name winbgp_state_route -Type gauge -Help 'WinBGP routes status' -Labels family,maintenance_timestamp,name,network,state
|
||||||
$outputHeader.Add('Content-Type', 'application/json')
|
$routeStatus=@('down','maintenance','up','warning')
|
||||||
|
# Silently continue as WinBGP is generating errors when BGP is not configured (TO REVIEW)
|
||||||
|
$routesCurrentStatus=(WinBGP -ErrorAction SilentlyContinue | Select-Object Name,Network,Status,@{Label='MaintenanceTimestamp';Expression={($_.MaintenanceTimestamp).ToString("yyyy-MM-ddTHH:mm:ss.fffK")}})
|
||||||
|
foreach ($routeCurrentStatus in $routesCurrentStatus) {
|
||||||
|
foreach ($status in $routeStatus) {
|
||||||
|
$WinBGP_metrics+=New-PrometheusMetric -PrometheusMetricDescriptor $state_routeDescriptor -Value $(if ($status -eq $routeCurrentStatus.Status) { 1 } else { 0 }) -Labels 'ipv4',$routeCurrentStatus.MaintenanceTimestamp,$routeCurrentStatus.Name,$routeCurrentStatus.Network,$status
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Default {
|
|
||||||
$statusCode = [System.Net.HttpStatusCode]::NotImplemented
|
# Return output
|
||||||
|
$commandOutput = Export-PrometheusMetrics -Metrics $WinBGP_metrics
|
||||||
|
|
||||||
|
# Add header
|
||||||
|
$outputHeader.Add('Content-Type', 'text/plain; version=0.0.4; charset=utf-8')
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||||
|
}
|
||||||
|
Default {
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::NotImplemented
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'mcp' {
|
||||||
|
# Always send json header for MCP
|
||||||
|
$outputHeader.Add('Content-Type', 'application/json')
|
||||||
|
# Body request
|
||||||
|
$requestBodyReader = New-Object System.IO.StreamReader $request.InputStream
|
||||||
|
$requestBody=$requestBodyReader.ReadToEnd()
|
||||||
|
$jsonRequestBody=$requestBody | convertfrom-json
|
||||||
|
switch ($request.HttpMethod) {
|
||||||
|
'GET' {
|
||||||
|
# Send not allowed (405) to avoid switching to SSE
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::MethodNotAllowed
|
||||||
|
}
|
||||||
|
'POST' {
|
||||||
|
switch ($jsonRequestBody.method) {
|
||||||
|
'initialize' {
|
||||||
|
$commandOutput = '{"jsonrpc":"2.0","id":' + ($jsonRequestBody.id | ConvertTo-Json -Depth 10 -Compress) + ',"result":{"protocolVersion":"2025-03-26","capabilities":{"tools":{"listChanged":false}},"serverInfo":{"name":"WinBGP MCP Server","version":"0.1.0"}}}'
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||||
|
}
|
||||||
|
'notifications/initialized' {
|
||||||
|
# Accept the initialization request
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::Accepted
|
||||||
|
}
|
||||||
|
'notifications/responses' {
|
||||||
|
# Accept the notification request
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::Accepted
|
||||||
|
}
|
||||||
|
'tools/list' {
|
||||||
|
$toolsListJson = '{"name":"Get-WinBGPRoute","description":"Get-WinBGPRoute","inputSchema":{"type":"object","properties":{"ComputerName":{"type":"string","description":"Single or multiple ComputerName (Default: localhost)"},"Name":{"type":"string","description":"Single or multiple Route Name (IntelliSense availalble)"}},"required":[]},"returns":{"type":"string","description":"Get-WinBGPRoute"}}'
|
||||||
|
$commandOutput = '{"jsonrpc":"2.0","id":' + ($jsonRequestBody.id | ConvertTo-Json -Depth 10 -Compress) + ',"result":{"tools":' + $toolsListJson + '}}'
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||||
|
}
|
||||||
|
'tools/call' {
|
||||||
|
#$toolName = $jsonRequestBody.params.name
|
||||||
|
#$Arguments = $jsonRequestBody.params.arguments
|
||||||
|
|
||||||
|
#$result = & $toolName @targetArgs
|
||||||
|
$result=[PSCustomObject]@{
|
||||||
|
Name = 'demo.webalex.lab'
|
||||||
|
Network = '172.16.10.10/32'
|
||||||
|
Status = 'up'
|
||||||
|
MaintenanceTimestamp = $null
|
||||||
|
ComputerName = 'server1.webalex.lab'
|
||||||
|
}
|
||||||
|
|
||||||
|
$callresponse = [ordered]@{
|
||||||
|
jsonrpc = "2.0"
|
||||||
|
id = $jsonRequestBody.id
|
||||||
|
result = @{
|
||||||
|
content = @(
|
||||||
|
[ordered]@{
|
||||||
|
type = "text"
|
||||||
|
text = $result | Out-String
|
||||||
|
}
|
||||||
|
)
|
||||||
|
isError = $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$commandOutput=$callresponse | ConvertTo-Json -Depth 10 -Compress
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||||
|
}
|
||||||
|
Default {
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::NotImplemented
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch ($commandOutput.output) {
|
Default {
|
||||||
'Success' { $statusCode = [System.Net.HttpStatusCode]::OK }
|
$statusCode = [System.Net.HttpStatusCode]::NotImplemented
|
||||||
'WinBGP not ready' { $statusCode = [System.Net.HttpStatusCode]::InternalServerError }
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# Add stop method to stop API (TO IMPROVE)
|
||||||
|
'stop' {
|
||||||
|
switch ($request.HttpMethod) {
|
||||||
|
'POST' {
|
||||||
|
# Only local request are authorized
|
||||||
|
if ($request.IsLocal) {
|
||||||
|
$keepListening = $false
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||||
|
} else {
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::Forbidden
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Default {
|
||||||
|
$statusCode = [System.Net.HttpStatusCode]::NotImplemented
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
$statusCode = [System.Net.HttpStatusCode]::NotImplemented
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Default {
|
Default {
|
||||||
@@ -559,7 +661,10 @@ if ($Configuration) {
|
|||||||
$output.Write($buffer,0,$buffer.Length)
|
$output.Write($buffer,0,$buffer.Length)
|
||||||
$output.Close()
|
$output.Close()
|
||||||
}
|
}
|
||||||
$listener.Stop()
|
if ($listener.IsListening) {
|
||||||
|
$listener.Stop()
|
||||||
|
$listener.Close()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Write-Log -Message "API failed - No Uri listener available" -Level Error
|
Write-Log -Message "API failed - No Uri listener available" -Level Error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -946,7 +946,7 @@ function Add-RoutePolicy() {
|
|||||||
# #
|
# #
|
||||||
# Function Start-API #
|
# Function Start-API #
|
||||||
# #
|
# #
|
||||||
# Description Starting API Engine #
|
# Description Starting API Job #
|
||||||
# #
|
# #
|
||||||
# Arguments See the Param() block at the top of this script #
|
# Arguments See the Param() block at the top of this script #
|
||||||
# #
|
# #
|
||||||
@@ -963,6 +963,7 @@ function Start-API() {
|
|||||||
)
|
)
|
||||||
# Start API
|
# Start API
|
||||||
Write-Log "Starting API engine"
|
Write-Log "Starting API engine"
|
||||||
|
|
||||||
# ArgumentList (,$ApiConfiguration) is to handle array as argument
|
# ArgumentList (,$ApiConfiguration) is to handle array as argument
|
||||||
Start-Job -Name 'API' -FilePath "$installDir\$serviceDisplayName-API.ps1" -ArgumentList (,$ApiConfiguration)
|
Start-Job -Name 'API' -FilePath "$installDir\$serviceDisplayName-API.ps1" -ArgumentList (,$ApiConfiguration)
|
||||||
}
|
}
|
||||||
@@ -971,7 +972,7 @@ function Start-API() {
|
|||||||
# #
|
# #
|
||||||
# Function Stop-API #
|
# Function Stop-API #
|
||||||
# #
|
# #
|
||||||
# Description Stopping API Engine #
|
# Description Stopping API Job #
|
||||||
# #
|
# #
|
||||||
# Arguments See the Param() block at the top of this script #
|
# Arguments See the Param() block at the top of this script #
|
||||||
# #
|
# #
|
||||||
@@ -983,20 +984,64 @@ function Start-API() {
|
|||||||
function Stop-API() {
|
function Stop-API() {
|
||||||
# Stop API
|
# Stop API
|
||||||
Write-Log "Stopping API engine"
|
Write-Log "Stopping API engine"
|
||||||
### IMPROVEMENT - To be check if we can kill API properly ###
|
# Send API stop signal (TO IMPROVE)
|
||||||
$ProcessID=$null
|
try {
|
||||||
$ApiPID=$null
|
if ((Invoke-WebRequest -Uri 'http://127.0.0.1:8888/stop' -Method Post -TimeoutSec 5).StatusCode -eq 200) {
|
||||||
# Get service PID
|
Stop-Job -Name 'API' -ErrorAction SilentlyContinue
|
||||||
$ProcessID=(Get-CimInstance Win32_Process -Filter "name = 'powershell.exe'" -OperationTimeoutSec 1 | Where-Object {$_.CommandLine -like "*'$installDir\$engineName.ps1' -Service*"}).ProcessId
|
Remove-Job -Name 'API' -Force -ErrorAction SilentlyContinue
|
||||||
if ($ProcessID) {
|
|
||||||
# Get API PID
|
|
||||||
$ApiPID=(Get-WmiObject win32_process -filter "Name='powershell.exe' AND ParentProcessId=$ProcessID").ProcessId
|
|
||||||
if ($ApiPID) {
|
|
||||||
Stop-Process -Id $ApiPID -Force -ErrorAction SilentlyContinue
|
|
||||||
}
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Log "Error stopping API engine: $_" -Level Error
|
||||||
}
|
}
|
||||||
Stop-Job -Name 'API' -ErrorAction SilentlyContinue
|
}
|
||||||
Remove-Job -Name 'API' -Force -ErrorAction SilentlyContinue
|
|
||||||
|
#-----------------------------------------------------------------------------#
|
||||||
|
# #
|
||||||
|
# Function Start-HealthCheck #
|
||||||
|
# #
|
||||||
|
# Description Starting HealthCheck Job #
|
||||||
|
# #
|
||||||
|
# Arguments See the Param() block at the top of this script #
|
||||||
|
# #
|
||||||
|
# Notes #
|
||||||
|
# #
|
||||||
|
# History #
|
||||||
|
# #
|
||||||
|
#-----------------------------------------------------------------------------#
|
||||||
|
function Start-HealthCheck() {
|
||||||
|
Param
|
||||||
|
(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
$Route
|
||||||
|
)
|
||||||
|
# Starting HealthCheck Job
|
||||||
|
Write-Log "Starting HealthCheck Process" -AdditionalFields @($Route.RouteName)
|
||||||
|
Start-Job -Name $Route.RouteName -FilePath "$installDir\WinBGP-HealthCheck.ps1" -ArgumentList $Route
|
||||||
|
}
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------------#
|
||||||
|
# #
|
||||||
|
# Function Stop-HealthCheck #
|
||||||
|
# #
|
||||||
|
# Description Stopping API HealthCheck #
|
||||||
|
# #
|
||||||
|
# Arguments See the Param() block at the top of this script #
|
||||||
|
# #
|
||||||
|
# Notes #
|
||||||
|
# #
|
||||||
|
# History #
|
||||||
|
# #
|
||||||
|
#-----------------------------------------------------------------------------#
|
||||||
|
function Stop-HealthCheck() {
|
||||||
|
Param
|
||||||
|
(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
$Route
|
||||||
|
)
|
||||||
|
# Stopping HealthCheck Job
|
||||||
|
Write-Log "Stopping HealthCheck Process" -AdditionalFields @($Route.RouteName)
|
||||||
|
Stop-Job -Name $Route.RouteName
|
||||||
|
Remove-Job -Name $Route.RouteName -Force
|
||||||
}
|
}
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------#
|
#-----------------------------------------------------------------------------#
|
||||||
@@ -1216,8 +1261,7 @@ if ($Service) { # Run the service
|
|||||||
Write-Log "Route '$($route.RouteName)' is in maintenance mode" -AdditionalFields @($route.RouteName)
|
Write-Log "Route '$($route.RouteName)' is in maintenance mode" -AdditionalFields @($route.RouteName)
|
||||||
} else {
|
} else {
|
||||||
# Starting HealthCheck Job
|
# Starting HealthCheck Job
|
||||||
Write-Log "Starting HealthCheck Process" -AdditionalFields @($route.RouteName)
|
Start-HealthCheck -Route $route
|
||||||
Start-Job -Name $route.RouteName -FilePath "$installDir\WinBGP-HealthCheck.ps1" -ArgumentList $route
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1307,7 +1351,6 @@ if ($Service) { # Run the service
|
|||||||
# Start Api
|
# Start Api
|
||||||
Start-API -ApiConfiguration $configuration.api
|
Start-API -ApiConfiguration $configuration.api
|
||||||
} else {
|
} else {
|
||||||
### TO BE IMPROVED because killing all healthchecks jobs ###
|
|
||||||
# Stop Api
|
# Stop Api
|
||||||
Stop-API
|
Stop-API
|
||||||
}
|
}
|
||||||
@@ -1340,9 +1383,7 @@ if ($Service) { # Run the service
|
|||||||
if ($routeReloaded.SideIndicator -eq '<=') {
|
if ($routeReloaded.SideIndicator -eq '<=') {
|
||||||
Write-Log "Route '$($routeReloaded.RouteName)' removed" -AdditionalFields @($oldRoute.RouteName)
|
Write-Log "Route '$($routeReloaded.RouteName)' removed" -AdditionalFields @($oldRoute.RouteName)
|
||||||
# Stopping HealthCheck Job
|
# Stopping HealthCheck Job
|
||||||
Write-Log "Stopping HealthCheck Process" -AdditionalFields @($oldRoute.RouteName)
|
Stop-HealthCheck -Route $oldRoute
|
||||||
Stop-Job -Name $oldRoute.RouteName
|
|
||||||
Remove-Job -Name $oldRoute.RouteName -Force
|
|
||||||
# Remove routing policy
|
# Remove routing policy
|
||||||
if (get-BgpRoutingPolicy -Name $oldRoute.RouteName -ErrorAction SilentlyContinue) {
|
if (get-BgpRoutingPolicy -Name $oldRoute.RouteName -ErrorAction SilentlyContinue) {
|
||||||
Write-Log "Removing BGP Routing Policy [$($oldRoute.RouteName)]" -AdditionalFields @($oldRoute.RouteName)
|
Write-Log "Removing BGP Routing Policy [$($oldRoute.RouteName)]" -AdditionalFields @($oldRoute.RouteName)
|
||||||
@@ -1369,8 +1410,7 @@ if ($Service) { # Run the service
|
|||||||
# Create routing policies
|
# Create routing policies
|
||||||
Add-RoutePolicy -Route $route -Peers $configuration.peers
|
Add-RoutePolicy -Route $route -Peers $configuration.peers
|
||||||
# Starting HealthCheck Job
|
# Starting HealthCheck Job
|
||||||
Write-Log "Starting HealthCheck Process" -AdditionalFields @($route.RouteName)
|
Start-HealthCheck -Route $route
|
||||||
Start-Job -Name $route.RouteName -FilePath "$installDir\WinBGP-HealthCheck.ps1" -ArgumentList $route
|
|
||||||
} elseif ($routeReloaded.SideIndicator -eq '==') {
|
} elseif ($routeReloaded.SideIndicator -eq '==') {
|
||||||
# Comparing old route and new route to check if there are updates to perform
|
# Comparing old route and new route to check if there are updates to perform
|
||||||
if (($route.Network -ne $oldRoute.Network) -or ($route.DynamicIpSetup -ne $oldRoute.DynamicIpSetup) -or ($route.Interface -ne $oldRoute.Interface) -or ($route.Interval -ne $oldRoute.Interval) -or (Compare-Object -ReferenceObject $oldRoute.Community -DifferenceObject $route.Community) -or ($route.Metric -ne $oldRoute.Metric) -or ($route.NextHop -ne $oldRoute.NextHop) -or ($route.WithdrawOnDown -ne $oldRoute.WithdrawOnDown) -or ($route.WithdrawOnDownCheck -ne $oldRoute.WithdrawOnDownCheck)) {
|
if (($route.Network -ne $oldRoute.Network) -or ($route.DynamicIpSetup -ne $oldRoute.DynamicIpSetup) -or ($route.Interface -ne $oldRoute.Interface) -or ($route.Interval -ne $oldRoute.Interval) -or (Compare-Object -ReferenceObject $oldRoute.Community -DifferenceObject $route.Community) -or ($route.Metric -ne $oldRoute.Metric) -or ($route.NextHop -ne $oldRoute.NextHop) -or ($route.WithdrawOnDown -ne $oldRoute.WithdrawOnDown) -or ($route.WithdrawOnDownCheck -ne $oldRoute.WithdrawOnDownCheck)) {
|
||||||
@@ -1382,10 +1422,9 @@ if ($Service) { # Run the service
|
|||||||
# If WithdrawOnDown change, restart healthcheck
|
# If WithdrawOnDown change, restart healthcheck
|
||||||
Write-Log "Restarting HealthCheck Process" -AdditionalFields @($route.RouteName)
|
Write-Log "Restarting HealthCheck Process" -AdditionalFields @($route.RouteName)
|
||||||
# Stopping HealthCheck Job
|
# Stopping HealthCheck Job
|
||||||
Stop-Job -Name $oldRoute.RouteName
|
Stop-HealthCheck -Route $route
|
||||||
Remove-Job -Name $oldRoute.RouteName -Force
|
|
||||||
# Starting HealthCheck Job
|
# Starting HealthCheck Job
|
||||||
Start-Job -Name $route.RouteName -FilePath "$installDir\WinBGP-HealthCheck.ps1" -ArgumentList $route
|
Start-HealthCheck -Route $route
|
||||||
}
|
}
|
||||||
# Manage WithdrawOnDownCheck change (Only if WithdrawOnDown was enabled and it still enabled)
|
# Manage WithdrawOnDownCheck change (Only if WithdrawOnDown was enabled and it still enabled)
|
||||||
if ($route.WithdrawOnDown -and $oldRoute.WithdrawOnDown) {
|
if ($route.WithdrawOnDown -and $oldRoute.WithdrawOnDown) {
|
||||||
@@ -1393,22 +1432,18 @@ if ($Service) { # Run the service
|
|||||||
Write-Log "WithdrawOnDownCheck change - Old Check: '$($oldRoute.WithdrawOnDownCheck)' - New Check: '$($route.WithdrawOnDownCheck)'" -AdditionalFields @($Route.RouteName)
|
Write-Log "WithdrawOnDownCheck change - Old Check: '$($oldRoute.WithdrawOnDownCheck)' - New Check: '$($route.WithdrawOnDownCheck)'" -AdditionalFields @($Route.RouteName)
|
||||||
Write-Log "Restarting HealthCheck Process" -AdditionalFields @($route.RouteName)
|
Write-Log "Restarting HealthCheck Process" -AdditionalFields @($route.RouteName)
|
||||||
# Stopping HealthCheck Job
|
# Stopping HealthCheck Job
|
||||||
Stop-Job -Name $oldRoute.RouteName
|
Stop-HealthCheck -Route $oldRoute
|
||||||
Remove-Job -Name $oldRoute.RouteName -Force
|
|
||||||
# Starting HealthCheck Job
|
# Starting HealthCheck Job
|
||||||
Start-Job -Name $route.RouteName -FilePath "$installDir\WinBGP-HealthCheck.ps1" -ArgumentList $route
|
Start-HealthCheck -Route $route
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# Manage interval change
|
# Manage interval change
|
||||||
if ($route.Interval -ne $oldRoute.Interval) {
|
if ($route.Interval -ne $oldRoute.Interval) {
|
||||||
Write-Log "Interval change - Old Interval: '$oldRouteInterval' - New Interval: '$period'" -AdditionalFields @($Route.RouteName)
|
Write-Log "Interval change - Old Interval: '$oldRouteInterval' - New Interval: '$period'" -AdditionalFields @($Route.RouteName)
|
||||||
# Stopping HealthCheck Job
|
# Stopping HealthCheck Job
|
||||||
Write-Log "Stopping HealthCheck Process" -AdditionalFields @($oldRoute.RouteName)
|
Stop-HealthCheck -Route $oldRoute
|
||||||
Stop-Job -Name $oldRoute.RouteName
|
|
||||||
Remove-Job -Name $oldRoute.RouteName -Force
|
|
||||||
# Starting HealthCheck Job
|
# Starting HealthCheck Job
|
||||||
Write-Log "Starting HealthCheck Process" -AdditionalFields @($route.RouteName)
|
Start-HealthCheck -Route $route
|
||||||
Start-Job -Name $route.RouteName -FilePath "$installDir\WinBGP-HealthCheck.ps1" -ArgumentList $route
|
|
||||||
}
|
}
|
||||||
# Manage network change
|
# Manage network change
|
||||||
if ($route.Network -ne $oldRoute.Network) {
|
if ($route.Network -ne $oldRoute.Network) {
|
||||||
@@ -1597,9 +1632,7 @@ if ($Service) { # Run the service
|
|||||||
# Export maintenance variable on each change (To be moved to function)
|
# Export maintenance variable on each change (To be moved to function)
|
||||||
$maintenance | Export-CliXml -Path $FunctionCliXml -Force
|
$maintenance | Export-CliXml -Path $FunctionCliXml -Force
|
||||||
# Stopping HealthCheck Job
|
# Stopping HealthCheck Job
|
||||||
Write-Log "Stopping HealthCheck Process" -AdditionalFields @($route_maintenance.RouteName)
|
Stop-HealthCheck -Route $route_maintenance
|
||||||
Stop-Job -Name $route_maintenance.RouteName
|
|
||||||
Remove-Job -Name $route_maintenance.RouteName -Force
|
|
||||||
# Removing route
|
# Removing route
|
||||||
if ((Get-BgpCustomRoute).Network -contains "$($route_maintenance.Network)") {
|
if ((Get-BgpCustomRoute).Network -contains "$($route_maintenance.Network)") {
|
||||||
remove-Bgp -Route $route_maintenance
|
remove-Bgp -Route $route_maintenance
|
||||||
@@ -1620,8 +1653,7 @@ if ($Service) { # Run the service
|
|||||||
# Export maintenance variable on each change (To be moved to function)
|
# Export maintenance variable on each change (To be moved to function)
|
||||||
$maintenance | Export-CliXml -Path $FunctionCliXml -Force
|
$maintenance | Export-CliXml -Path $FunctionCliXml -Force
|
||||||
# Starting HealthCheck Job
|
# Starting HealthCheck Job
|
||||||
Write-Log "Starting HealthCheck Process" -AdditionalFields @($route_maintenance.RouteName)
|
Start-HealthCheck -Route $route_maintenance
|
||||||
Start-Job -Name $route_maintenance.RouteName -FilePath "$installDir\WinBGP-HealthCheck.ps1" -ArgumentList $route_maintenance
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Write-Log "Route '$($route_maintenance.RouteName)' was not in maintenance mode" -Level Warning
|
Write-Log "Route '$($route_maintenance.RouteName)' was not in maintenance mode" -Level Warning
|
||||||
@@ -1639,6 +1671,29 @@ if ($Service) { # Run the service
|
|||||||
# Start another thread waiting for control messages
|
# Start another thread waiting for control messages
|
||||||
$pipeThread = Start-PipeHandlerThread $pipeName -Event "ControlMessage"
|
$pipeThread = Start-PipeHandlerThread $pipeName -Event "ControlMessage"
|
||||||
}
|
}
|
||||||
|
elseif ($message -like 'healthcheck*') {
|
||||||
|
$route_to_control=$message.split(' ')[1]
|
||||||
|
$control_action=$message.split(' ')[2]
|
||||||
|
# Grabbing route
|
||||||
|
$route_healthcheck=$configuration.routes | Where-Object {$_.RouteName -eq $route_to_control}
|
||||||
|
if ($control_action -eq 'start') {
|
||||||
|
# Start HealthCheck
|
||||||
|
Start-HealthCheck -Route $route_healthcheck
|
||||||
|
}
|
||||||
|
elseif ($control_action -eq 'stop') {
|
||||||
|
# Stop HealthCheck
|
||||||
|
Stop-HealthCheck -Route $route_healthcheck
|
||||||
|
} elseif ($control_action -eq 'restart') {
|
||||||
|
# Log
|
||||||
|
Write-Log "Restarting HealthCheck engine"
|
||||||
|
# Stop HealthCheck
|
||||||
|
Stop-HealthCheck -Route $route_healthcheck
|
||||||
|
# Start HealthCheck
|
||||||
|
Start-HealthCheck -Route $route_healthcheck
|
||||||
|
}
|
||||||
|
# Start another thread waiting for control messages
|
||||||
|
$pipeThread = Start-PipeHandlerThread $pipeName -Event "ControlMessage"
|
||||||
|
}
|
||||||
elseif (($message -ne "stop") -and ($message -ne "suspend")) { # Start another thread waiting for control messages
|
elseif (($message -ne "stop") -and ($message -ne "suspend")) { # Start another thread waiting for control messages
|
||||||
$pipeThread = Start-PipeHandlerThread $pipeName -Event "ControlMessage"
|
$pipeThread = Start-PipeHandlerThread $pipeName -Event "ControlMessage"
|
||||||
}
|
}
|
||||||
@@ -1673,7 +1728,7 @@ if ($Service) { # Run the service
|
|||||||
# Cleaning unhealthy HealthCheck
|
# Cleaning unhealthy HealthCheck
|
||||||
Write-Log "Restarting HealthCheck Process (Watchdog)" -AdditionalFields @($route.RouteName) -Level Warning
|
Write-Log "Restarting HealthCheck Process (Watchdog)" -AdditionalFields @($route.RouteName) -Level Warning
|
||||||
Remove-Job -Name $route.RouteName -Force -ErrorAction SilentlyContinue
|
Remove-Job -Name $route.RouteName -Force -ErrorAction SilentlyContinue
|
||||||
Start-Job -Name $route.RouteName -FilePath "$installDir\WinBGP-HealthCheck.ps1" -ArgumentList $route
|
Start-HealthCheck -Route $route
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1691,9 +1746,7 @@ if ($Service) { # Run the service
|
|||||||
Write-Log -Message "Stopping HealthCheck engine"
|
Write-Log -Message "Stopping HealthCheck engine"
|
||||||
ForEach ($route in $configuration.routes) {
|
ForEach ($route in $configuration.routes) {
|
||||||
# Stopping HealthCheck Job
|
# Stopping HealthCheck Job
|
||||||
Write-Log "Stopping HealthCheck Process" -AdditionalFields @($route.RouteName)
|
Stop-HealthCheck -Route $route
|
||||||
Stop-Job -Name $route.RouteName -ErrorAction SilentlyContinue
|
|
||||||
Remove-Job -Name $route.RouteName -Force -ErrorAction SilentlyContinue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Stopping API
|
# Stopping API
|
||||||
|
|||||||
@@ -124,6 +124,15 @@ Param(
|
|||||||
[Parameter(ParameterSetName='RouteName', Mandatory=$false)]
|
[Parameter(ParameterSetName='RouteName', Mandatory=$false)]
|
||||||
[Switch]$StopRoute, # Control message to send to the service
|
[Switch]$StopRoute, # Control message to send to the service
|
||||||
|
|
||||||
|
[Parameter(ParameterSetName='RouteName', Mandatory=$false)]
|
||||||
|
[Switch]$StartHealthCheck, # Control message to send to the service
|
||||||
|
|
||||||
|
[Parameter(ParameterSetName='RouteName', Mandatory=$false)]
|
||||||
|
[Switch]$StopHealthCheck, # Control message to send to the service
|
||||||
|
|
||||||
|
[Parameter(ParameterSetName='RouteName', Mandatory=$false)]
|
||||||
|
[Switch]$RestartHealthCheck, # Control message to send to the service
|
||||||
|
|
||||||
[Parameter(ParameterSetName='BGPStatus', Mandatory=$false)]
|
[Parameter(ParameterSetName='BGPStatus', Mandatory=$false)]
|
||||||
[Switch]$BGPStatus = $($PSCmdlet.ParameterSetName -eq 'BGPStatus'), # Get the current service status
|
[Switch]$BGPStatus = $($PSCmdlet.ParameterSetName -eq 'BGPStatus'), # Get the current service status
|
||||||
|
|
||||||
@@ -144,7 +153,7 @@ Param(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Don't forget to increment version when updating engine
|
# Don't forget to increment version when updating engine
|
||||||
$scriptVersion = '1.0.1'
|
$scriptVersion = '1.0.2'
|
||||||
|
|
||||||
# This script name, with various levels of details
|
# This script name, with various levels of details
|
||||||
# Ex: PSService
|
# Ex: PSService
|
||||||
@@ -560,9 +569,12 @@ if ($RestartAPI) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Start/stop control or Maintenance control
|
# Start/stop control or Maintenance control
|
||||||
if ($StartRoute -or $StopRoute -or $StartMaintenance -or $StopMaintenance) {
|
if ($StartRoute -or $StopRoute -or $StartMaintenance -or $StopMaintenance -or $StartHealthCheck -or $StopHealthCheck -or $RestartHealthCheck) {
|
||||||
# Logging
|
if ($StartRoute -or $StopRoute -or $StartMaintenance -or $StopMaintenance ) {
|
||||||
Write-Log "Operation for route '$RouteName' triggered by '$currentUserName'"
|
# Logging
|
||||||
|
Write-Log "Operation for route '$RouteName' triggered by '$currentUserName'"
|
||||||
|
}
|
||||||
|
|
||||||
# Read configuration
|
# Read configuration
|
||||||
$configuration = Get-Content -Path $configdir | ConvertFrom-Json
|
$configuration = Get-Content -Path $configdir | ConvertFrom-Json
|
||||||
$routeCheck=$null
|
$routeCheck=$null
|
||||||
@@ -589,6 +601,21 @@ if ($StartRoute -or $StopRoute -or $StartMaintenance -or $StopMaintenance) {
|
|||||||
$control="maintenance $RouteName stop"
|
$control="maintenance $RouteName stop"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
# Start/stop control HealthCheck
|
||||||
|
if ($StartHealthCheck -or $StopHealthCheck -or $RestartHealthCheck) {
|
||||||
|
# START
|
||||||
|
if ($StartHealthCheck) {
|
||||||
|
$control="healthcheck $RouteName start"
|
||||||
|
}
|
||||||
|
# STOP
|
||||||
|
if ($StopHealthCheck) {
|
||||||
|
$control="healthcheck $RouteName stop"
|
||||||
|
}
|
||||||
|
# RESTART
|
||||||
|
if ($RestartHealthCheck) {
|
||||||
|
$control="healthcheck $RouteName restart"
|
||||||
|
}
|
||||||
|
}
|
||||||
if($routeCheck) {
|
if($routeCheck) {
|
||||||
$PipeStatus=$null
|
$PipeStatus=$null
|
||||||
# Performing Action
|
# Performing Action
|
||||||
|
|||||||
Reference in New Issue
Block a user