# @name Icinga Status # @desc Shows Icinga host/service status as OK, WARN or CRIT # @author Oli & Nilo # @version 1.2 # @config url text "Icinga CIB URL" default="https://icinga.example.local:5665/v1/status/CIB" # @config auth text "Authorization Header" default="" maxlen=256 # @config every number "Refresh" default=61 min=30 max=600 unit=s # @config icon_ok text "OK Icon" default="649" # @config icon_warn text "WARN Icon" default="1077" # @config icon_crit text "CRIT Icon" default="555" class IcingaStatus var state, count, ticks, busy, period, ic, label, color var parse_fails, net_fails def init() self.state = "WAIT" self.count = 0 self.ticks = 0 self.busy = false self.period = store.get("every") self.ic = "" self.label = "..." self.color = 0x666666 self.parse_fails = 0 self.net_fails = 0 end def on_body(b, st) self.busy = false # No usable HTTP response -> transient transport/network failure if b == nil || st == 0 self.net_fails += 1 # Keep last valid status for the first two failures if self.net_fails < 3 return end # Three consecutive transport failures self.state = "ERROR" self.count = 0 self.ic = store.get("icon_crit") self.label = "ERR NET" self.color = 0xFF0000 return end # We received a real HTTP response -> transport is healthy again self.net_fails = 0 # Real HTTP error -> show immediately if st != 200 self.state = "ERROR" self.count = st self.ic = store.get("icon_crit") self.label = "ERR " + str(st) self.color = 0xFF0000 return end # Extract relevant counters from the Icinga CIB response var d = re.search("\"num_hosts_down\":(\\d+)", b) var c = re.search("\"num_services_critical\":(\\d+)", b) var w = re.search("\"num_services_warning\":(\\d+)", b) var u = re.search("\"num_services_unknown\":(\\d+)", b) # Response received, but expected CIB values were not found if d == nil || c == nil || w == nil || u == nil self.parse_fails += 1 # Keep last valid status for the first two parse failures if self.parse_fails < 3 return end # Three consecutive parse failures self.state = "ERROR" self.count = 0 self.ic = store.get("icon_crit") self.label = "ERR" self.color = 0xFF0000 return end # Valid response -> reset parser error counter self.parse_fails = 0 var down = int(num(d[1])) var crit = int(num(c[1])) var warn = int(num(w[1])) var unknown = int(num(u[1])) if down > 0 || crit > 0 self.state = "CRIT" self.count = down + crit self.ic = store.get("icon_crit") self.label = "CRIT " + str(self.count) self.color = 0xFF0000 elif warn > 0 || unknown > 0 self.state = "WARN" self.count = warn + unknown self.ic = store.get("icon_warn") self.label = "WARN " + str(self.count) self.color = 0xFFA500 else self.state = "OK" self.count = 0 self.ic = store.get("icon_ok") self.label = "OK" self.color = 0x00FF00 end end def loop() if self.ticks <= 0 && !self.busy self.ticks = self.period self.busy = true http.get( store.get("url"), / b, st -> self.on_body(b, st), { 'headers': { 'Authorization': store.get("auth"), 'Accept': "application/json" } } ) end self.ticks -= 1 end def draw() clear() if self.ic != "" icon(self.ic, 0, 0) end text(8, 6, self.label, self.color) end def on_button(btn) if btn == "select" self.ticks = 0 end end end return IcingaStatus()