param( [string]$BaseUrl = "http://192.168.200.61:18121/api/v1", [string]$ClusterID = "cfc0743d-d960-49fb-9de8-96e063d5e4aa", [string]$ActorUserID = "f67d943f-5397-4b3a-a229-695fe67ad700", [string]$EntryNodeName = "test-1", [string]$ExitNodeName = "test-2", [string]$ResultPath = "artifacts\c18y-route-intent-lifecycle-smoke-result.json" ) Set-StrictMode -Version Latest $ErrorActionPreference = "Stop" $repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\..")).ProviderPath $runId = "c18y-" + (Get-Date -Format "yyyyMMdd-HHmmss") function Invoke-ApiJson { param( [string]$Method = "GET", [string]$Path, [object]$Body = $null ) $uri = "$BaseUrl$Path" if ($null -eq $Body) { return Invoke-RestMethod -Method $Method -Uri $uri } $json = $Body | ConvertTo-Json -Depth 20 return Invoke-RestMethod -Method $Method -Uri $uri -ContentType "application/json" -Body $json } function New-RouteIntent { param( [string]$Label, [int]$Priority ) $expiresAt = (Get-Date).ToUniversalTime().AddMinutes(10).ToString("o") return Invoke-ApiJson -Method "POST" -Path "/clusters/$ClusterID/mesh/route-intents" -Body @{ actor_user_id = $ActorUserID source_selector = @{ node_id = $entryNode.id } destination_selector = @{ node_id = $exitNode.id } service_class = "vpn_packets" priority = $Priority policy = @{ synthetic_enabled = $true allowed_channels = @("vpn_packet", "fabric_control") hops = @($entryNode.id, $exitNode.id) expires_at = $expiresAt max_ttl = 8 max_hops = 8 route_version = "$runId-$Label" policy_version = "$runId-$Label" peer_directory_version = "$runId-$Label" metadata = @{ smoke = "c18y_route_intent_lifecycle" run_id = $runId label = $Label } } } } function Get-RouteIntent { param([string]$RouteIntentID) $items = (Invoke-ApiJson -Path "/clusters/$ClusterID/mesh/route-intents?actor_user_id=$ActorUserID").route_intents return @($items | Where-Object { $_.id -eq $RouteIntentID })[0] } function Get-NodeRouteIDs { param([string]$NodeID) $config = (Invoke-ApiJson -Path "/clusters/$ClusterID/nodes/$NodeID/mesh/synthetic-config").synthetic_mesh_config return @($config.routes | ForEach-Object { $_.route_id }) } $nodes = (Invoke-ApiJson -Path "/clusters/$ClusterID/nodes?actor_user_id=$ActorUserID").nodes $entryNode = @($nodes | Where-Object { $_.name -eq $EntryNodeName })[0] $exitNode = @($nodes | Where-Object { $_.name -eq $ExitNodeName })[0] if (-not $entryNode -or -not $exitNode) { throw "Required nodes not found: entry=$EntryNodeName exit=$ExitNodeName" } $expireIntent = (New-RouteIntent -Label "expire" -Priority 9810).route_intent $disableIntent = (New-RouteIntent -Label "disable" -Priority 9820).route_intent $routeIDsBefore = Get-NodeRouteIDs -NodeID $entryNode.id $expireVisibleBefore = $routeIDsBefore -contains $expireIntent.id $disableVisibleBefore = $routeIDsBefore -contains $disableIntent.id $expired = (Invoke-ApiJson -Method "POST" -Path "/clusters/$ClusterID/mesh/route-intents/$($expireIntent.id)/expire" -Body @{ actor_user_id = $ActorUserID reason = "C18Y smoke expire" }).route_intent $disabled = (Invoke-ApiJson -Method "POST" -Path "/clusters/$ClusterID/mesh/route-intents/$($disableIntent.id)/disable" -Body @{ actor_user_id = $ActorUserID reason = "C18Y smoke disable" }).route_intent $routeIDsAfter = Get-NodeRouteIDs -NodeID $entryNode.id $expireVisibleAfter = $routeIDsAfter -contains $expireIntent.id $disableVisibleAfter = $routeIDsAfter -contains $disableIntent.id $expiredListed = Get-RouteIntent -RouteIntentID $expireIntent.id $disabledListed = Get-RouteIntent -RouteIntentID $disableIntent.id $checks = [ordered]@{ route_visible_before_expire = [bool]$expireVisibleBefore route_visible_before_disable = [bool]$disableVisibleBefore expire_action_marks_expired = [bool]($expired.lifecycle_status -eq "expired" -and $expired.is_expired -eq $true) disable_action_marks_disabled = [bool]($disabled.lifecycle_status -eq "disabled" -and $disabled.status -eq "disabled") expired_route_removed_from_synthetic_config = [bool](-not $expireVisibleAfter) disabled_route_removed_from_synthetic_config = [bool](-not $disableVisibleAfter) list_reports_expired = [bool]($expiredListed.lifecycle_status -eq "expired") list_reports_disabled = [bool]($disabledListed.lifecycle_status -eq "disabled") } $passed = -not ($checks.Values -contains $false) $result = [ordered]@{ schema_version = "c18y.route_intent_lifecycle_smoke.v1" run_id = $runId base_url = $BaseUrl cluster_id = $ClusterID entry_node = @{ id = $entryNode.id; name = $entryNode.name } exit_node = @{ id = $exitNode.id; name = $exitNode.name } expire_route_intent_id = $expireIntent.id disable_route_intent_id = $disableIntent.id passed = $passed checks = $checks } $absoluteResultPath = Join-Path $repoRoot $ResultPath New-Item -ItemType Directory -Force -Path (Split-Path -Parent $absoluteResultPath) | Out-Null $result | ConvertTo-Json -Depth 20 | Set-Content -Encoding UTF8 $absoluteResultPath if (-not $passed) { throw "C18Y route-intent lifecycle smoke failed. Result: $absoluteResultPath" } Write-Host "C18Y route-intent lifecycle smoke passed. Result: $absoluteResultPath" $result