Ad Widget

Collapse

Filter DMZ boxes from Trigger

Collapse
This topic has been answered.
X
X
 
  • Time
  • Show
Clear All
new posts
  • reginaldmerritt
    Junior Member
    • Sep 2025
    • 2

    #1

    Filter DMZ boxes from Trigger

    We have the trigger VM Ping Loss >10m which uses the expression avg(/VMware Guest/icmppingloss[{HOST.IP},4],#60)=100, icmppingloss polls around every 10s. This trigger is tagged as service:vm-uptime-problems. we then have a 'VM Uptime Monitoring' service which uses a single child service named 'VM Uptime Problems' which uses the problem tag service:vm-uptime-problems.

    This works great to show uptime service level and is only impacted when a host is down for 10+ mins, unfortunately this also means the DMZ VMs, where the Zabbix server can not ping them as there are on an isolated network, also are throwing this 10m+ no ping trigger.

    Our DMZ VMs are using a dedicated virtual switch within vSphere but i cant seem to find any item that could be added to list the virtual switch the VMs network adapter is using.

    Our DMZ VMs are within their own subnet but i cant see how to add the VM IP address to an item and if i could I'm not sure if a trigger could be filtered to not include item with value of '192.168.0.*' for example.

    I would imagine the DMZ VMs will have to be tagged in some way but even then the problem tags used with in the child services only have 'Equals' or 'Contains' operator not a 'Does Not Equal' operation.

    So the question is, How do other Zabbix Administrators automatically tag their DMZ VMs and how can these then be excluded from Services and SLA?

    Any suggestions welcome.
  • Answer selected by reginaldmerritt at 03-11-2025, 15:42.
    reginaldmerritt
    Junior Member
    • Sep 2025
    • 2

    To solve this, we created a PowerShell script that uses the Zabbix API to create or update the macro at the host level.

    We currently run this script as a scheduled cron job on the Ubuntu server hosting Zabbix, but it could easily run from any machine with network access to the API.

    The script loops through host groups, then through the hosts within each group, assigning a macro value based on a predefined mapping. This reverse approach (group → host) works well if you're using VM folder-based groups, but could cause conflicts if a host belongs to multiple mapped groups. If we were basing macro values purely on hostnames, we would have looped through hosts directly instead.

    We also considered other ways to determine macro values, for example:
    • Using the IP address (via Zabbix API or DNS lookup),
    • Or even the Active Directory OU location.
    Once the macro is in place, we updated our trigger expressions to make them more context-aware.

    For example:
    Before: last(/VMware Guest/icmppingloss[{HOST.IP},4])=100
    This would trigger on 100% ping loss, regardless of host type.

    After:last(/VMware Guest/icmppingloss[{HOST.IP},4])=100 and {$TYPE} <> "DMZ"
    Now it only triggers on 100% ping lossand if the host is not in the DMZ, helping us avoid false positives for expected behavior in certain zones.

    Code:
    # Zabbix API Token and URL
    $apiUrl = "http://zabbixserver.localdomain/zabbix/api_jsonrpc.php"
    $apiToken = "API_TOKEN"
    $macroName = '{$TYPE}'
    
    # Host group to macro value mapping
    $groupTypeMap = @{
        "Datacenter/Citrix Management (vm)" = "CITRIX-MGMT"
        "Datacenter/Citrix Production (vm)" = "CITRIX-PRD"
        "Datacenter/DMZ (vm)" = "DMZ"
    }
    
    # Helper: Send API request using token in header
    function Invoke-ZabbixAPI {
        param (
            [string]$method,
            [hashtable]$params
        )
    
        $headers = @{
            "Content-Type"  = "application/json"
            "Authorization" = "Bearer $apiToken"
        }
    
        $body = @{
            jsonrpc = "2.0"
            method  = $method
            params  = $params
            id      = 1
        } | ConvertTo-Json -Depth 5 -Compress
    
        Invoke-RestMethod -Uri $apiUrl -Method Post -Headers $headers -Body $body
    }
    
    # Step 1: Get all host groups with their hosts
    $groupResponse = Invoke-ZabbixAPI -method "hostgroup.get" -params @{
        output      = "extend"
        selectHosts = @("hostid", "name")
    }
    
    # Step 2: Loop through groups and update macros for matching hosts
    foreach ($group in $groupResponse.result) {
        $groupName = $group.name
    
        if ($groupTypeMap.ContainsKey($groupName)) {
            foreach ($ZabbixHost in $group.hosts) {
                Write-Host ""
                Write-Host "HOST: $($ZabbixHost.name)"
                Write-Host "GROUP: $groupName"
    
                # Default macro value from group
                $macroValue = $groupTypeMap[$groupName]
    
                # Override TYPE value by Name rather than group
                if ($ZabbixHost.name -like "*-IMG") {
                    Write-Host "OVERRIDE: Using name as Type rather than group"
                    $macroValue = "CITRIX-MGMT-IMG"
                }
    
                # Try to create macro
                $createResponse = Invoke-ZabbixAPI -method "usermacro.create" -params @{
                    hostid = $ZabbixHost.hostid
                    macro  = $macroName
                    value  = $macroValue
                }
    
                if ($createResponse.error) {
                    Write-Host "RESULT: FAILED to create macro $($macroName): $($createResponse.error.data)"
    
                    # Try to update existing macro
                    $existingMacro = Invoke-ZabbixAPI -method "usermacro.get" -params @{
                        hostids = @($ZabbixHost.hostid)
                        filter  = @{ macro = $macroName }
                        output  = "extend"
                    }
    
                    if ($existingMacro.result.Count -gt 0) {
                        foreach ($macro in $existingMacro.result) {
                            try {
                                $updateResponse = Invoke-ZabbixAPI -method "usermacro.update" -params @{
                                    hostmacroid = $macro.hostmacroid
                                    value       = $macroValue
                                }
                                Write-Host "ACTION: Updated macro $macroName to '$macroValue'"
                            }
                            catch {
                                Write-Host "RESULT: FAILED to update macro $($macroName): $($_.Exception.Message)"
                            }
                        }
                    }
                    else {
                        Write-Host "RESULT: Macro $macroName not found or not allowed on host '$($ZabbixHost.name)'"
                    }
                }
                else {
                    Write-Host "ACTION: Created macro $macroName with value '$macroValue'"
                }
    
                # Verification step
                $verifyMacro = Invoke-ZabbixAPI -method "usermacro.get" -params @{
                    hostids = @($ZabbixHost.hostid)
                    filter  = @{ macro = $macroName }
                    output  = "extend"
                }
    
                if ($verifyMacro.result.Count -gt 0 -and $verifyMacro.result[0].value -eq $macroValue) {
                    Write-Host "VERIFICATION: macro $macroName for host '$($ZabbixHost.name)' has value '$macroValue'"
                }
                else {
                    Write-Host "VERIFICATION: FAILED for macro $macroName with value $macroValue"
                }
            }
        }
    }​

    Comment

    • reginaldmerritt
      Junior Member
      • Sep 2025
      • 2

      #2
      To solve this, we created a PowerShell script that uses the Zabbix API to create or update the macro at the host level.

      We currently run this script as a scheduled cron job on the Ubuntu server hosting Zabbix, but it could easily run from any machine with network access to the API.

      The script loops through host groups, then through the hosts within each group, assigning a macro value based on a predefined mapping. This reverse approach (group → host) works well if you're using VM folder-based groups, but could cause conflicts if a host belongs to multiple mapped groups. If we were basing macro values purely on hostnames, we would have looped through hosts directly instead.

      We also considered other ways to determine macro values, for example:
      • Using the IP address (via Zabbix API or DNS lookup),
      • Or even the Active Directory OU location.
      Once the macro is in place, we updated our trigger expressions to make them more context-aware.

      For example:
      Before: last(/VMware Guest/icmppingloss[{HOST.IP},4])=100
      This would trigger on 100% ping loss, regardless of host type.

      After:last(/VMware Guest/icmppingloss[{HOST.IP},4])=100 and {$TYPE} <> "DMZ"
      Now it only triggers on 100% ping lossand if the host is not in the DMZ, helping us avoid false positives for expected behavior in certain zones.

      Code:
      # Zabbix API Token and URL
      $apiUrl = "http://zabbixserver.localdomain/zabbix/api_jsonrpc.php"
      $apiToken = "API_TOKEN"
      $macroName = '{$TYPE}'
      
      # Host group to macro value mapping
      $groupTypeMap = @{
          "Datacenter/Citrix Management (vm)" = "CITRIX-MGMT"
          "Datacenter/Citrix Production (vm)" = "CITRIX-PRD"
          "Datacenter/DMZ (vm)" = "DMZ"
      }
      
      # Helper: Send API request using token in header
      function Invoke-ZabbixAPI {
          param (
              [string]$method,
              [hashtable]$params
          )
      
          $headers = @{
              "Content-Type"  = "application/json"
              "Authorization" = "Bearer $apiToken"
          }
      
          $body = @{
              jsonrpc = "2.0"
              method  = $method
              params  = $params
              id      = 1
          } | ConvertTo-Json -Depth 5 -Compress
      
          Invoke-RestMethod -Uri $apiUrl -Method Post -Headers $headers -Body $body
      }
      
      # Step 1: Get all host groups with their hosts
      $groupResponse = Invoke-ZabbixAPI -method "hostgroup.get" -params @{
          output      = "extend"
          selectHosts = @("hostid", "name")
      }
      
      # Step 2: Loop through groups and update macros for matching hosts
      foreach ($group in $groupResponse.result) {
          $groupName = $group.name
      
          if ($groupTypeMap.ContainsKey($groupName)) {
              foreach ($ZabbixHost in $group.hosts) {
                  Write-Host ""
                  Write-Host "HOST: $($ZabbixHost.name)"
                  Write-Host "GROUP: $groupName"
      
                  # Default macro value from group
                  $macroValue = $groupTypeMap[$groupName]
      
                  # Override TYPE value by Name rather than group
                  if ($ZabbixHost.name -like "*-IMG") {
                      Write-Host "OVERRIDE: Using name as Type rather than group"
                      $macroValue = "CITRIX-MGMT-IMG"
                  }
      
                  # Try to create macro
                  $createResponse = Invoke-ZabbixAPI -method "usermacro.create" -params @{
                      hostid = $ZabbixHost.hostid
                      macro  = $macroName
                      value  = $macroValue
                  }
      
                  if ($createResponse.error) {
                      Write-Host "RESULT: FAILED to create macro $($macroName): $($createResponse.error.data)"
      
                      # Try to update existing macro
                      $existingMacro = Invoke-ZabbixAPI -method "usermacro.get" -params @{
                          hostids = @($ZabbixHost.hostid)
                          filter  = @{ macro = $macroName }
                          output  = "extend"
                      }
      
                      if ($existingMacro.result.Count -gt 0) {
                          foreach ($macro in $existingMacro.result) {
                              try {
                                  $updateResponse = Invoke-ZabbixAPI -method "usermacro.update" -params @{
                                      hostmacroid = $macro.hostmacroid
                                      value       = $macroValue
                                  }
                                  Write-Host "ACTION: Updated macro $macroName to '$macroValue'"
                              }
                              catch {
                                  Write-Host "RESULT: FAILED to update macro $($macroName): $($_.Exception.Message)"
                              }
                          }
                      }
                      else {
                          Write-Host "RESULT: Macro $macroName not found or not allowed on host '$($ZabbixHost.name)'"
                      }
                  }
                  else {
                      Write-Host "ACTION: Created macro $macroName with value '$macroValue'"
                  }
      
                  # Verification step
                  $verifyMacro = Invoke-ZabbixAPI -method "usermacro.get" -params @{
                      hostids = @($ZabbixHost.hostid)
                      filter  = @{ macro = $macroName }
                      output  = "extend"
                  }
      
                  if ($verifyMacro.result.Count -gt 0 -and $verifyMacro.result[0].value -eq $macroValue) {
                      Write-Host "VERIFICATION: macro $macroName for host '$($ZabbixHost.name)' has value '$macroValue'"
                  }
                  else {
                      Write-Host "VERIFICATION: FAILED for macro $macroName with value $macroValue"
                  }
              }
          }
      }​

      Comment

      Working...