Compare commits
18 Commits
fix/api_gr
...
feat/mcp
| Author | SHA1 | Date | |
|---|---|---|---|
| 0c7f736d73 | |||
|
|
c1dbeeea1c | ||
|
|
1e221eafe7 | ||
|
|
ca7224391d | ||
|
|
25ed7571a1 | ||
|
|
9f36ca794e | ||
|
|
ea4006b290 | ||
|
|
cb99fc2470 | ||
|
|
76c9ed376c | ||
|
|
e01fc6c7c9 | ||
|
|
30a3360f72 | ||
|
|
1fb7093032 | ||
|
|
00e27a77de | ||
|
|
b4b06f361e | ||
|
|
f682432188 | ||
|
|
838a206ed3 | ||
|
|
cfcd5550f2 | ||
|
|
2e01af7957 |
@@ -21,8 +21,22 @@ Trap {
|
||||
# Reset working dir on error
|
||||
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 {
|
||||
Copy-Item -Path $_.FullName -Destination "..\engine" -Force
|
||||
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]
|
||||
|
||||
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!"
|
||||
Pop-Location
|
||||
Write-Output "Build complete !"
|
||||
|
||||
# Clean temporary build folder
|
||||
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
|
||||
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"
|
||||
|
||||
@@ -897,10 +897,10 @@ if ($Build) { # Install the service
|
||||
# Generate the service .EXE from the C# source embedded in this script
|
||||
|
||||
# Overwrite for builder
|
||||
$exeFullName=".\$exeName"
|
||||
$exeFullName=$exeName
|
||||
|
||||
try {
|
||||
Write-Verbose "Compiling $exeFullName"
|
||||
Write-Output "Compiling $exeFullName"
|
||||
Add-Type -TypeDefinition $source -Language CSharp -OutputAssembly $exeFullName -OutputType ConsoleApplication -ReferencedAssemblies "System.ServiceProcess" -Debug:$false
|
||||
} catch {
|
||||
$msg = $_.Exception.Message
|
||||
|
||||
@@ -363,195 +363,282 @@ if ($Configuration) {
|
||||
# Write-Log "API request received: $FullRequest" -EventLogSource 'WinBGP-API'
|
||||
$FullPath=($request.RawUrl).substring(1)
|
||||
$Path=$FullPath.Split('?')[0]
|
||||
switch ($request.HttpMethod) {
|
||||
'GET' {
|
||||
if ($FullPath -eq 'api') {
|
||||
$commandOutput = ConvertTo-Json -InputObject @{'message'='WinBGP API running'}
|
||||
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||
} elseif ($FullPath -like 'api/*') {
|
||||
$Path=$Path.replace('api/','')
|
||||
$shortPath=$Path.Split('/')[0]
|
||||
switch ($shortPath) {
|
||||
'config' {
|
||||
if (($Path -eq 'config') -or ($Path -eq 'config/')) {
|
||||
$commandOutput = WinBGP -Config | ConvertTo-JSON
|
||||
$outputHeader.Add('Content-Type', 'application/json')
|
||||
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||
} else {
|
||||
$SubConfig=$Path.Split('/')[1]
|
||||
$commandOutput = (WinBGP -Config).$SubConfig
|
||||
if ($commandOutput) {
|
||||
$commandOutput = $commandOutput | ConvertTo-JSON
|
||||
switch -wildcard ($FullPath) {
|
||||
'api*' {
|
||||
switch ($request.HttpMethod) {
|
||||
'GET' {
|
||||
if ($FullPath -eq 'api') {
|
||||
$commandOutput = ConvertTo-Json -InputObject @{'message'='WinBGP API running'}
|
||||
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||
} elseif ($FullPath -like 'api/*') {
|
||||
$Path=$Path.replace('api/','')
|
||||
$shortPath=$Path.Split('/')[0]
|
||||
switch ($shortPath) {
|
||||
'config' {
|
||||
if (($Path -eq 'config') -or ($Path -eq 'config/')) {
|
||||
$commandOutput = WinBGP -Config | ConvertTo-JSON
|
||||
$outputHeader.Add('Content-Type', 'application/json')
|
||||
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||
} else {
|
||||
$SubConfig=$Path.Split('/')[1]
|
||||
$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')
|
||||
$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")
|
||||
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')
|
||||
$statusCode = [System.Net.HttpStatusCode]::OK
|
||||
}
|
||||
'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
|
||||
}
|
||||
'POST' {
|
||||
$RouteName = $request.QueryString.Item("RouteName")
|
||||
$Path=$Path.replace('api/','')
|
||||
Write-Log "API received POST request '$Path' from '$RequestUser' - Source IP: '$RequestHost'" -AdditionalFields $RouteName
|
||||
switch ($Path) {
|
||||
'Reload' {
|
||||
[string]$ActionOutput=WinBGP -Reload
|
||||
$commandOutput = ConvertTo-Json -InputObject @{'output'=$ActionOutput}
|
||||
$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
|
||||
}
|
||||
}
|
||||
'StartMaintenance' {
|
||||
[string]$ActionOutput=WinBGP -RouteName "$RouteName" -StartMaintenance
|
||||
$commandOutput = ConvertTo-Json -InputObject @{'output'=$ActionOutput}
|
||||
$outputHeader.Add('Content-Type', 'application/json')
|
||||
}
|
||||
'StartRoute' {
|
||||
[string]$ActionOutput=WinBGP -RouteName "$RouteName" -StartRoute
|
||||
$commandOutput = ConvertTo-Json -InputObject @{'output'=$ActionOutput}
|
||||
$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' {
|
||||
$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
|
||||
switch ($commandOutput.output) {
|
||||
'Success' { $statusCode = [System.Net.HttpStatusCode]::OK }
|
||||
'WinBGP not ready' { $statusCode = [System.Net.HttpStatusCode]::InternalServerError }
|
||||
}
|
||||
}
|
||||
} elseif ($FullPath -eq 'metrics') {
|
||||
# Define WinBGP Prometheus metrics
|
||||
$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()}}
|
||||
Default {
|
||||
$statusCode = [System.Net.HttpStatusCode]::NotImplemented
|
||||
}
|
||||
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' {
|
||||
# Add stop method to stop API (TO IMPROVE)
|
||||
if ($FullPath -eq 'stop') {
|
||||
# Only local request are authorized
|
||||
if ($request.IsLocal) {
|
||||
$keepListening = $false
|
||||
'metrics' {
|
||||
switch ($request.HttpMethod) {
|
||||
'GET' {
|
||||
# Define WinBGP Prometheus metrics
|
||||
$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]::Forbidden
|
||||
}
|
||||
Default {
|
||||
$statusCode = [System.Net.HttpStatusCode]::NotImplemented
|
||||
}
|
||||
}
|
||||
elseif ($FullPath -like 'api/*') {
|
||||
$RouteName = $request.QueryString.Item("RouteName")
|
||||
$Path=$Path.replace('api/','')
|
||||
Write-Log "API received POST request '$Path' from '$RequestUser' - Source IP: '$RequestHost'" -AdditionalFields $RouteName
|
||||
switch ($Path) {
|
||||
'Reload' {
|
||||
[string]$ActionOutput=WinBGP -Reload
|
||||
$commandOutput = ConvertTo-Json -InputObject @{'output'=$ActionOutput}
|
||||
$outputHeader.Add('Content-Type', 'application/json')
|
||||
}
|
||||
'StartMaintenance' {
|
||||
[string]$ActionOutput=WinBGP -RouteName "$RouteName" -StartMaintenance
|
||||
$commandOutput = ConvertTo-Json -InputObject @{'output'=$ActionOutput}
|
||||
$outputHeader.Add('Content-Type', 'application/json')
|
||||
}
|
||||
'StartRoute' {
|
||||
[string]$ActionOutput=WinBGP -RouteName "$RouteName" -StartRoute
|
||||
$commandOutput = ConvertTo-Json -InputObject @{'output'=$ActionOutput}
|
||||
$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
|
||||
}
|
||||
'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) {
|
||||
'Success' { $statusCode = [System.Net.HttpStatusCode]::OK }
|
||||
'WinBGP not ready' { $statusCode = [System.Net.HttpStatusCode]::InternalServerError }
|
||||
Default {
|
||||
$statusCode = [System.Net.HttpStatusCode]::NotImplemented
|
||||
}
|
||||
}
|
||||
}
|
||||
# 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 {
|
||||
|
||||
Reference in New Issue
Block a user