SWQL to PromQL: Nodes Down

By NetMon Hub Editorial ·

SolarWinds swqlPrometheus promql fidelity: conceptual

Intent: Identify nodes that are currently down or unreachable.

No true equivalent; the closest idiomatic approach in the target tool.

SWQL to PromQL: Finding Down Nodes

SolarWinds and Prometheus answer “what is down right now?” in fundamentally different ways. Getting to a working PromQL equivalent requires understanding that gap before writing a single line of query syntax — otherwise the translation will look right and mean something different.

The source: SWQL

SELECT
    N.NodeID,
    N.Caption,
    N.IPAddress,
    N.Status,
    N.LastBoot,
    N.Vendor,
    N.MachineType
FROM Orion.Nodes AS N
WHERE N.Status = 2
ORDER BY N.Caption

SolarWinds status code 2 = Down. Other common values: 1 = Up, 3 = Warning, 9 = Unmanaged. Source: SolarWinds Orion SDK — Node Status values.

The query runs against the Orion SQL database (or SWIS API), reading a row per managed node whose Status column currently holds 2. That value is written by the SolarWinds poller on each polling cycle (default 120 s) and persists until the next poll updates it.

The target: PromQL

Option A — Prometheus up metric (scrape / probe)

up{job="network_devices"} == 0

up is a synthetic metric Prometheus itself writes: 1 when the scrape (or Blackbox Exporter probe) succeeded, 0 when it failed or timed out. It is not a device-level concept; it reflects whether Prometheus could reach and parse the target’s metrics endpoint at the last scrape interval.

Labels available on up are whatever you defined in scrape_configs — typically instance (host:port), job, and any relabelling you applied. There is no automatic vendor, machine_type, or last_boot equivalent unless you export those as target labels or as separate info metrics.

Option B — SNMP Exporter reachability

If nodes are polled via prometheus/snmp_exporter, the idiomatic reachability signal is snmp_up (1 = walk succeeded, 0 = failed):

snmp_up{job="snmp"} == 0

Source: snmp_exporter README — exposed metrics.

snmp_up is the closest structural equivalent to Orion’s Status = 2: both reflect whether the device answered a poll. The key difference is timing (see below).

Option C — Blackbox Exporter ICMP probe

For ping-based reachability (analogous to SolarWinds ICMP node status):

probe_success{job="icmp_ping"} == 0

Source: prometheus/blackbox_exporter.

probe_success is 1 on success, 0 on failure. Configure targets in blackbox.yml under a module with prober: icmp.


Why fidelity is conceptual, not exact

DimensionSolarWinds / SWQLPrometheus / PromQL
Data modelRelational database; one row per managed node, updated by pollerTime-series scrapes; each target produces samples at a scrape interval
”Down” signalStatus = 2 written by Orion poller after N failed polls (configurable)up == 0 or snmp_up == 0 on the most recent scrape
Staleness / persistenceStatus persists until next poll; visible in DB query at any timeIf a target disappears entirely, up becomes stale after --query.lookback-delta (default 5 min) and then is absent
Device inventoryOrion manages a node list; every managed device has a rowNo built-in inventory; targets must be defined in scrape_configs or a service discovery source
MetadataCaption, Vendor, MachineType, LastBoot available as columnsAvailable only if exported as target labels or info metrics; requires deliberate instrumentation
Polling vs scrapingPoller actively checks device; marks statusPrometheus scrapes an exporter; exporter walks the device
Point-in-time querySQL WHERE returns current snapshotPromQL == 0 returns the value at the most recent sample within lookback window

Note: Absent is not the same as Down in Prometheus. If a target is removed from scrape_configs, or the exporter crashes, up and snmp_up will eventually go stale and then absent — not explicitly 0. Use absent(snmp_up{job="snmp", instance="192.0.2.1:161"}) to catch entirely missing targets. An alerting rule combining both is safer than either alone.

Handling the “absent node” problem

A SolarWinds node in status 2 always has a row. In Prometheus, a target that stops being scraped produces no new samples. A robust alerting rule covers both cases:

# prometheus/alerts/node_down.yml
groups:
  - name: node_reachability
    rules:
      - alert: NodeDown
        expr: |
          snmp_up{job="snmp"} == 0
          OR absent(snmp_up{job="snmp"})
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Node {{ $labels.instance }} is down or not being scraped"
          description: >
            snmp_up is 0 or absent for {{ $labels.instance }}.
            Check snmp_exporter connectivity and scrape_config target list.

The for: 2m grace period avoids flapping on transient scrape failures — roughly analogous to SolarWinds’ “node down after N consecutive failures” threshold.


Migration checklist

  1. Build your target inventory. SolarWinds Orion.Nodes is your device list. Export it via SWIS (SELECT N.IPAddress, N.Caption, N.Vendor FROM Orion.Nodes) and convert to Prometheus static configs or a file-based service discovery JSON.

  2. Choose your exporter. SNMP-polled devices → snmp_exporter. Servers with a local agent → node_exporter (and use up). Network reachability only → blackbox_exporter with ICMP.

  3. Replicate metadata as labels. There is no automatic equivalent of Orion’s Caption, Vendor, or MachineType. Add these as target labels in scrape_configs or export a separate info metric (e.g., device_info{caption="...", vendor="..."}) joined with * on(instance) group_left(caption).

  4. Set alert thresholds to match your polling expectations. SolarWinds’ default 120 s poll cycle → use a Prometheus scrape interval ≤ 120 s and a for: duration that matches your acceptable detection latency.

  5. Test absent-target alerting separately. Remove a test target from config and confirm your absent() rule fires before declaring parity.


Caveats summary


Sources & further reading