|
| 1 | +<# |
| 2 | +.SYNOPSIS |
| 3 | +Development tool to generate filter field validation configuration from swagger YAML. |
| 4 | +
|
| 5 | +.DESCRIPTION |
| 6 | +This script parses the logicmonitor-api.yaml file to extract all API endpoints and their |
| 7 | +response schemas. It then maps each endpoint to the properties available in the response |
| 8 | +model, creating a validation configuration file that can be used at runtime to validate |
| 9 | +filter fields before sending API requests. |
| 10 | +
|
| 11 | +.EXAMPLE |
| 12 | +.\Build-LMFilterValidationConfig.ps1 |
| 13 | +
|
| 14 | +This will generate Private/LMFilterValidationConfig.psd1 with all endpoint-to-fields mappings. |
| 15 | +
|
| 16 | +.NOTES |
| 17 | +This is a development-time tool and should be run whenever the swagger file is updated. |
| 18 | +Requires the powershell-yaml module for parsing YAML files. |
| 19 | +#> |
| 20 | + |
| 21 | +[CmdletBinding()] |
| 22 | +param() |
| 23 | + |
| 24 | +# Check if powershell-yaml module is available |
| 25 | +if (-not (Get-Module -ListAvailable -Name powershell-yaml)) { |
| 26 | + Write-Warning "The powershell-yaml module is required to parse the swagger YAML file." |
| 27 | + Write-Warning "Install it with: Install-Module -Name powershell-yaml" |
| 28 | + Write-Warning "Attempting to install now..." |
| 29 | + try { |
| 30 | + Install-Module -Name powershell-yaml -Scope CurrentUser -Force -AllowClobber |
| 31 | + Write-Host "Successfully installed powershell-yaml module" -ForegroundColor Green |
| 32 | + } |
| 33 | + catch { |
| 34 | + Write-Error "Failed to install powershell-yaml module. Please install it manually." |
| 35 | + return |
| 36 | + } |
| 37 | +} |
| 38 | + |
| 39 | +Import-Module powershell-yaml |
| 40 | + |
| 41 | +$SwaggerPath = Join-Path $PSScriptRoot "logicmonitor-api.yaml" |
| 42 | +$OutputPath = Join-Path $PSScriptRoot "Private/LMFilterValidationConfig.psd1" |
| 43 | + |
| 44 | +if (-not (Test-Path $SwaggerPath)) { |
| 45 | + Write-Error "Swagger file not found at: $SwaggerPath" |
| 46 | + return |
| 47 | +} |
| 48 | + |
| 49 | +Write-Host "Parsing swagger file: $SwaggerPath" -ForegroundColor Cyan |
| 50 | + |
| 51 | +# Parse the YAML file |
| 52 | +$SwaggerContent = Get-Content -Path $SwaggerPath -Raw |
| 53 | +$Swagger = ConvertFrom-Yaml -Yaml $SwaggerContent |
| 54 | + |
| 55 | +Write-Host "Extracting API endpoints and schemas..." -ForegroundColor Cyan |
| 56 | + |
| 57 | +# Build endpoint to schema mapping |
| 58 | +$EndpointToSchema = @{} |
| 59 | +$SchemaProperties = @{} |
| 60 | + |
| 61 | +# First, extract all schema properties |
| 62 | +foreach ($schemaName in $Swagger.components.schemas.Keys) { |
| 63 | + $schema = $Swagger.components.schemas[$schemaName] |
| 64 | + $properties = @() |
| 65 | + |
| 66 | + if ($schema.properties) { |
| 67 | + $properties += $schema.properties.Keys |
| 68 | + } |
| 69 | + |
| 70 | + # Handle allOf (inheritance) |
| 71 | + if ($schema.allOf) { |
| 72 | + foreach ($allOfItem in $schema.allOf) { |
| 73 | + if ($allOfItem.properties) { |
| 74 | + $properties += $allOfItem.properties.Keys |
| 75 | + } |
| 76 | + # Handle $ref in allOf |
| 77 | + if ($allOfItem.'$ref') { |
| 78 | + $refSchema = $allOfItem.'$ref' -replace '#/components/schemas/', '' |
| 79 | + # We'll resolve these in a second pass |
| 80 | + } |
| 81 | + } |
| 82 | + } |
| 83 | + |
| 84 | + if ($properties.Count -gt 0) { |
| 85 | + $SchemaProperties[$schemaName] = $properties | Sort-Object -Unique |
| 86 | + } |
| 87 | +} |
| 88 | + |
| 89 | +Write-Host "Found $($SchemaProperties.Count) schemas with properties" -ForegroundColor Green |
| 90 | + |
| 91 | +# Now map endpoints to their response schemas |
| 92 | +foreach ($path in $Swagger.paths.Keys) { |
| 93 | + $pathItem = $Swagger.paths[$path] |
| 94 | + |
| 95 | + # We're primarily interested in GET endpoints for filtering |
| 96 | + if ($pathItem.get) { |
| 97 | + $getOp = $pathItem.get |
| 98 | + |
| 99 | + # Check if it has a filter parameter |
| 100 | + $hasFilter = $false |
| 101 | + if ($getOp.parameters) { |
| 102 | + foreach ($param in $getOp.parameters) { |
| 103 | + if ($param.name -eq 'filter') { |
| 104 | + $hasFilter = $true |
| 105 | + break |
| 106 | + } |
| 107 | + } |
| 108 | + } |
| 109 | + |
| 110 | + if ($hasFilter) { |
| 111 | + # Extract the response schema |
| 112 | + if ($getOp.responses.'200'.content.'application/json'.schema.'$ref') { |
| 113 | + $responseSchemaRef = $getOp.responses.'200'.content.'application/json'.schema.'$ref' |
| 114 | + $responseSchemaName = $responseSchemaRef -replace '#/components/schemas/', '' |
| 115 | + |
| 116 | + # For pagination responses, we need to get the items schema |
| 117 | + if ($responseSchemaName -match 'PaginationResponse$') { |
| 118 | + $paginationSchema = $Swagger.components.schemas[$responseSchemaName] |
| 119 | + if ($paginationSchema.properties.items.items.'$ref') { |
| 120 | + $itemsSchemaRef = $paginationSchema.properties.items.items.'$ref' |
| 121 | + $itemsSchemaName = $itemsSchemaRef -replace '#/components/schemas/', '' |
| 122 | + |
| 123 | + if ($SchemaProperties[$itemsSchemaName]) { |
| 124 | + $EndpointToSchema[$path] = @{ |
| 125 | + Schema = $itemsSchemaName |
| 126 | + Properties = $SchemaProperties[$itemsSchemaName] |
| 127 | + } |
| 128 | + } |
| 129 | + } |
| 130 | + } |
| 131 | + # For non-pagination responses, use the schema directly |
| 132 | + elseif ($SchemaProperties[$responseSchemaName]) { |
| 133 | + $EndpointToSchema[$path] = @{ |
| 134 | + Schema = $responseSchemaName |
| 135 | + Properties = $SchemaProperties[$responseSchemaName] |
| 136 | + } |
| 137 | + } |
| 138 | + } |
| 139 | + } |
| 140 | + } |
| 141 | +} |
| 142 | + |
| 143 | +Write-Host "Mapped $($EndpointToSchema.Count) endpoints to schemas" -ForegroundColor Green |
| 144 | + |
| 145 | +# Build the final configuration hashtable |
| 146 | +$Config = @{} |
| 147 | + |
| 148 | +foreach ($endpoint in $EndpointToSchema.Keys | Sort-Object) { |
| 149 | + $properties = $EndpointToSchema[$endpoint].Properties |
| 150 | + $schema = $EndpointToSchema[$endpoint].Schema |
| 151 | + |
| 152 | + # Add special property fields that are always valid for filtering |
| 153 | + $specialProperties = @('customProperties', 'systemProperties', 'autoProperties', 'inheritedProperties') |
| 154 | + $allProperties = @($properties) + $specialProperties | Sort-Object -Unique |
| 155 | + |
| 156 | + $Config[$endpoint] = $allProperties |
| 157 | + |
| 158 | + Write-Verbose "Endpoint: $endpoint -> Schema: $schema -> Properties: $($properties.Count)" |
| 159 | +} |
| 160 | + |
| 161 | +# Generate the PSD1 file |
| 162 | +Write-Host "Generating configuration file: $OutputPath" -ForegroundColor Cyan |
| 163 | + |
| 164 | +$PSD1Content = @" |
| 165 | +<# |
| 166 | +.SYNOPSIS |
| 167 | +Filter field validation configuration generated from logicmonitor-api.yaml |
| 168 | +
|
| 169 | +.DESCRIPTION |
| 170 | +This file contains a mapping of API endpoints to their valid filterable fields. |
| 171 | +It is automatically generated by Build-LMFilterValidationConfig.ps1 and should not be manually edited. |
| 172 | +
|
| 173 | +Generated: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') |
| 174 | +Swagger endpoints processed: $($EndpointToSchema.Count) |
| 175 | +
|
| 176 | +.NOTES |
| 177 | +To regenerate this file, run: .\Build-LMFilterValidationConfig.ps1 |
| 178 | +#> |
| 179 | +
|
| 180 | +@{ |
| 181 | +"@ |
| 182 | + |
| 183 | +foreach ($endpoint in $Config.Keys | Sort-Object) { |
| 184 | + $properties = $Config[$endpoint] |
| 185 | + $propertiesString = ($properties | ForEach-Object { "'$_'" }) -join ', ' |
| 186 | + $PSD1Content += "`n '$endpoint' = @($propertiesString)" |
| 187 | +} |
| 188 | + |
| 189 | +$PSD1Content += "`n}`n" |
| 190 | + |
| 191 | +# Write the file |
| 192 | +Set-Content -Path $OutputPath -Value $PSD1Content -Encoding UTF8 |
| 193 | + |
| 194 | +Write-Host "Successfully generated configuration file!" -ForegroundColor Green |
| 195 | +Write-Host " Endpoints: $($Config.Keys.Count)" -ForegroundColor Green |
| 196 | +Write-Host " Output: $OutputPath" -ForegroundColor Green |
| 197 | + |
| 198 | +# Display some sample mappings |
| 199 | +Write-Host "`nSample mappings:" -ForegroundColor Cyan |
| 200 | +$sampleEndpoints = @('/device/devices', '/device/groups', '/alert/alerts') | Where-Object { $Config[$_] } |
| 201 | +foreach ($endpoint in $sampleEndpoints) { |
| 202 | + Write-Host " $endpoint" -ForegroundColor Yellow |
| 203 | + Write-Host " Fields: $($Config[$endpoint] -join ', ')" -ForegroundColor Gray |
| 204 | +} |
| 205 | + |
0 commit comments