NewRelicPS.Configuration.SyntheticLocationCondition.psm1
<#
.Synopsis Idempotently applies New Relic synthetic condition configurations .Description Idempotently applies New Relic synthetic condition configurations .Example Set-SyntheticConditionConfiguration -AdminAPIKey $AdminAPIKey -DefinedPolicies $Config.AlertPolicies Uses New Relic APIs to update synthetic alert conditions to match the conditions defined in $Config.AlertPolicies. Any existing conditions that are not defined will be removed. .Parameter AdminAPIAPIKey Must be an admin user's API Key, not an account-level REST API Key. See more here: https://docs.newrelic.com/docs/apis/get-started/intro-apis/types-new-relic-api-keys .Parameter DefinedPolicies An array of policy objects which define the desired configuration state for New Relic alert policies and conditions #> Function Set-NRSyntheticLocationConditionConfiguration { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", '', Justification = "All CMDLets being called have ShouldProcess in place and the preference is passed to them." )] [CMDLetBinding(SupportsShouldProcess = $true)] Param ( [Parameter (Mandatory = $true)] [string] $AdminAPIKey, [array] $DefinedPolicies ) # Iterate over each defined policy $existingPolicies = Get-NRAlertPolicy -APIKey $AdminAPIKey Foreach ($policy in $DefinedPolicies) { $existingPolicy = $existingPolicies | Where-Object {$_.name -eq $policy.name} [System.Collections.ArrayList]$existingConditions = @(Get-NRSyntheticLocationCondition -APIKey $AdminAPIKey -PolicyId $existingPolicy.id) $definedConditionCount = ($policy.conditions | Where-Object {$_.type -eq 'SyntheticLocation'}).name.count Write-Verbose "Policy $($policy.name) has $definedConditionCount defined Synthetic conditions and $($existingConditions.count) existing Synthetic conditions." # Iterate over each synthetic location condition described in the policy Foreach ($condition in ($policy.conditions | Where-Object {$_.type -eq 'SyntheticLocation'})) { [array]$existingConditionConfig = $existingConditions | Where-Object { $_.name -eq $condition.name } # Items are declared by name and are later given an ID by New Relic, therefore resources with the same name will cause issues and are unsupported. If ($existingConditionConfig.count -gt 1) { Write-Error "Multiple conditions found with the name $($existingConditionConfig.name[0])! Ids: $($existingConditionConfig.id -join (',')) This must be resolved manually before continuing." -ErrorAction 'Stop' } # Update existing condition if needed If ($existingConditionConfig) { $conditionRequiresUpdate = Compare-NRSyntheticLocationConditionState -APIKey $AdminAPIKey -DefinedCondition $condition -ExistingCondition $existingConditionConfig -Verbose:$PSCMDLet.GetVariableValue('VerbosePreference') If ($conditionRequiresUpdate) { Write-Verbose "Updating condition $($condition.name) on policy $($policy.name)." $params = Get-NRSyntheticLocationConditionParams -APIKey $AdminAPIKey -Condition $condition Update-NRSyntheticLocationCondition @params -Id $existingConditionConfig.id -PolicyId $existingPolicy.id -Whatif:$WhatIfPreference | Out-Null } # Any extra existing conditions that are not defined will be removed later $existingConditions.Remove($existingConditionConfig[0]) } # Otherwise, create the condition if the policy exists ElseIf ($existingPolicy) { $params = Get-NRSyntheticLocationConditionParams -APIKey $AdminAPIKey -Condition $condition Write-Verbose "Creating condition $($condition.name)" New-NRSyntheticLocationCondition @params -PolicyId $existingPolicy.id -Whatif:$WhatIfPreference | Out-Null } } # Check for existing conditions not in the policy's definition and remove them If ($existingConditions) { Write-Verbose "Removing condition(s) $($existingConditions.Name -join (','))" $existingConditions.Id | Remove-NRSyntheticLocationCondition $AdminAPIKey -Whatif:$WhatIfPreference | Out-Null } } } ########################## # Internal Functions ########################## Function Get-NRSyntheticLocationConditionParams { [CMDLetBinding()] param ( [Parameter (Mandatory = $true)] $APIKey, [Parameter (Mandatory = $true)] $Condition ) # Take the data available and create a hash table of CMDLET parameters $params = @{ APIKey = $APIKEY } # Build up all optional parameters Foreach ($Property in ($Condition.Keys | Where-Object {$_ -ne 'Type'})) { # Entities require special handling because the monitor names are provided in the configuration instead of Ids which are generated by New Relic If ($Property -eq 'entities') { # Grab the IDs of the associated Synthetic monitors and add them to the params object Foreach ($EntityName in $Condition['entities']) { [array]$monitorIds += (Get-NRSyntheticMonitor -APIKey $APIKEY | Where-Object {$_.name -eq $EntityName}).id } $Params += @{ Entities = $monitorIds } } # Terms require special handling since they are nested objects and a warning term is optional ElseIf ($Property -eq 'terms') { Foreach ($term in $Condition.$Property) { If ($term.priority -eq 'Critical') { Switch ($term.keys) { 'operator' {$params += @{CriticalOperator = $term.operator}} 'threshold' {$params += @{CriticalThreshold = $term.threshold}} } } ElseIf ($term.priority -eq 'Warning') { Switch ($term.keys) { 'operator' {$params += @{WarningOperator = $term.operator}} 'threshold' {$params += @{WarningThreshold = $term.threshold}} } } Else { Write-Error "$($Condition.name) has terms defined but a priority was not found!" -ErrorAction 'Stop' } } } # Process the top-level properties Else { $params += @{ $Property = $Condition.$Property } } } Return $params } Function Compare-NRSyntheticLocationConditionState { [CMDLetBinding()] Param ( $APIKEY, $DefinedCondition, $ExistingCondition ) $returnValue = $false Foreach ($Property in ($DefinedCondition.Keys | Where-Object {$_ -ne 'Type'})) { # Terms require special handling since there may be multiple term objects returned in any order If ($Property -eq 'terms') { Foreach ($term in $DefinedCondition.$Property) { # There can only be one Warning term and one Critical term so match the term based on priority $existingTerm = $ExistingCondition.$Property | Where-Object {$_.priority -eq $term.priority} # Iterate over sub items in terms and compare them - no need to compare priority as it won't change Foreach ($subProperty in ($term.keys | Where-Object {$_ -ne 'priority'})) { # If a user specifies 0 to remove a warning term and no warning term exists, do not update the condition $warningThresholdAlreadyRemoved = $term.$subProperty -eq 0 -and $null -eq $existingTerm.$subProperty If ($term.$subProperty -ne $existingTerm.$subProperty -and -NOT $warningThresholdAlreadyRemoved) { Write-Verbose "Condition $($DefinedCondition.Name) has subproperty $subProperty defined as $($term.$subProperty) but it is currently set to $($Existingterm.$subProperty)" $returnValue = $true } } } } # Entities also require special handling since the names must be converted to IDs ElseIf ($Property -eq 'entities') { Foreach ($EntityName in $Condition['entities']) { $entityId = (Get-NRSyntheticMonitor -APIKey $APIKEY | Where-Object {$_.name -eq $EntityName}).id # Throw an error if the entity does not exist. If (-NOT $entityId) { Write-Error "You must define a Synthetic monitor with name $EntityName in order to specify it as a condition entity in condition $($Condition.name)." -ErrorAction 'Stop' } [array]$definedMonitorIds += $entityId } $monitorDiff = Compare-Object -ReferenceObject $definedMonitorIds -DifferenceObject $ExistingCondition.$Property -PassThru If ($monitorDiff) { Write-Verbose "Condition $($DefinedCondition.Name) has an entities list of $($definedMonitorIds) but it is currently set to $($ExistingCondition.$Property)" $returnValue = $true } } # Compare top-level properties ElseIf ($DefinedCondition.$Property -ne $ExistingCondition.$Property) { Write-Verbose "Condition $($DefinedCondition.Name) has property $Property defined as $($DefinedCondition.$Property) but it is currently set to $($ExistingCondition.$Property)" $returnValue = $true } } Return $returnValue } |