Icinga

Icinga ist ein Monitoring-System und ein Fork von Nagios. Ein Setup besteht aus mehreren Komponenten: dem Core Icinga 2 (führt die Checks aus und steuert die Cluster-Kommunikation), Icinga DB (speichert Status und History, löst das alte IDO ab), der Weboberfläche Icinga Web 2 samt Modulen, und dem Icinga Director zur Konfigurationsverwaltung über die Weboberfläche.

Begriffe
  • Agent: Icinga-2-Instanz auf einem überwachten Host, führt Checks lokal aus

  • Director: Icinga-Web-2-Modul zur Konfigurationsverwaltung über die Oberfläche

  • Endpoint: einzelne Icinga-2-Instanz in der Cluster-Kommunikation

  • Icinga DB: Backend für Status und History, löst IDO ab

  • IDO: Icinga Data Output, das alte DB-Backend (deprecated, durch Icinga DB ersetzt)

  • Master: zentrale Icinga-2-Instanz, die das Monitoring steuert

  • Satellite: Icinga-2-Instanz zwischen Master und Agents, z.B. pro Standort

  • Zone: Vertrauens- und Konfigurationsbereich aus einem oder mehreren Endpoints

Icinga Web 2 Module

Module für Icingaweb2 liegen in /usr/share/icingaweb2/modules/.

Update eines Moduls (beispielhaft für das Icubator-Modul):

MODULE_NAME=incubator
MODULE_VERSION=v0.17.0
MODULES_PATH="/usr/share/icingaweb2/modules"
MODULE_PATH="${MODULES_PATH}/${MODULE_NAME}"
RELEASES="https://github.com/Icinga/icingaweb2-module-${MODULE_NAME}/archive"

mkdir -p "$MODULE_PATH" \
&& wget -q $RELEASES/${MODULE_VERSION}.tar.gz --output-document - \
   | tar xfz - -C "$MODULE_PATH" --strip-components 1

icingacli module enable "${MODULE_NAME}"

vSphere-Module

Zurücksetzen des vSphere-Moduls, aber dabei existierende Connection-Definitionen beibehalten:

systemctl stop icinga-vspheredb

# Export connection data (just to be sure)
mysqldump \
    --host=mysql.example.com \
    --user=icinga \
    --password \
    --no-create-info \
    --skip-triggers \
    icinga_vspheredb \
        vcenter_server \
        vspheredb_schema_migration > /tmp/vsphere-connections.sql

mysql \
    --host=mysql.example.com \
    --user=icinga \
    --password \
    icinga_vspheredb \
    --execute='
        SET FOREIGN_KEY_CHECKS = 0;
        TRUNCATE TABLE alarm_history;
        TRUNCATE TABLE compute_resource;
        TRUNCATE TABLE counter_300x5;
        TRUNCATE TABLE datastore;
        TRUNCATE TABLE distributed_virtual_portgroup;
        TRUNCATE TABLE distributed_virtual_switch;
        TRUNCATE TABLE host_hba;
        TRUNCATE TABLE host_list;
        TRUNCATE TABLE host_list_member;
        TRUNCATE TABLE host_monitoring_hoststate;
        TRUNCATE TABLE host_pci_device;
        TRUNCATE TABLE host_physical_nic;
        TRUNCATE TABLE host_quick_stats;
        TRUNCATE TABLE host_sensor;
        TRUNCATE TABLE host_system;
        TRUNCATE TABLE host_virtual_nic;
        TRUNCATE TABLE monitoring_connection;
        TRUNCATE TABLE monitoring_rule_problem;
        TRUNCATE TABLE monitoring_rule_problem_history;
        TRUNCATE TABLE monitoring_rule_set;
        TRUNCATE TABLE object;
        TRUNCATE TABLE perfdata_consumer;
        TRUNCATE TABLE perfdata_subscription;
        TRUNCATE TABLE performance_collection_interval;
        TRUNCATE TABLE performance_counter;
        TRUNCATE TABLE performance_group;
        TRUNCATE TABLE performance_unit;
        TRUNCATE TABLE storage_pod;
        TRUNCATE TABLE tagging_category;
        TRUNCATE TABLE tagging_object_tag;
        TRUNCATE TABLE tagging_tag;
        TRUNCATE TABLE vcenter_session;
        TRUNCATE TABLE vcenter;
        TRUNCATE TABLE vcenter_sync;
        TRUNCATE TABLE virtual_machine;
        TRUNCATE TABLE vm_datastore_usage;
        TRUNCATE TABLE vm_disk;
        TRUNCATE TABLE vm_disk_usage;
        TRUNCATE TABLE vm_event_history;
        TRUNCATE TABLE vm_hardware;
        TRUNCATE TABLE vm_list;
        TRUNCATE TABLE vm_list_member;
        TRUNCATE TABLE vm_monitoring_hoststate;
        TRUNCATE TABLE vm_network_adapter;
        TRUNCATE TABLE vm_quick_stats;
        TRUNCATE TABLE vm_snapshot;
        TRUNCATE TABLE vspheredb_daemon;
        TRUNCATE TABLE vspheredb_daemonlog;
        SET FOREIGN_KEY_CHECKS = 1;
    '

systemctl start icinga-vspheredb

Icinga 2 API

Liste aller Hosts zurückgeben:

API_USERNAME=alice
API_PASSWORD=linuxfabrik
curl \
    --insecure \
    --connect-timeout 5 \
    --header 'Accept: application/json' \
    --user "$API_USERNAME:$API_PASSWORD" \
    'https://monitor.example.com:5665/v1/objects/hosts'

Liste aller Services zurückgeben:

API_USERNAME=alice
API_PASSWORD=linuxfabrik
curl \
    --insecure \
    --connect-timeout 5 \
    --header 'Accept: application/json' \
    --user "$API_USERNAME:$API_PASSWORD" \
    'https://monitor.example.com:5665/v1/objects/services'

Downtime auf dem Icinga2 Master per API für alle Hosts und Services setzen:

API_USERNAME='downtime-user'
API_PASSWORD=$(icinga2 object list --type ApiUser --name $API_USERNAME | sed -n 's/.* password = "\(.*\)"/\1/p')
START_TIME=$(date +%s)
END_TIME=$(( START_TIME + 7200 )) # 2h
cat > /tmp/icinga2-api.json << EOF
{
    "type": "Host",
    "all_services": true,
    "start_time": "$START_TIME",
    "end_time": "$END_TIME",
    "author": "$USER",
    "comment": "Updating the Icinga Director config."
}
EOF
curl \
    --insecure \
    --data @/tmp/icinga2-api.json \
    --header 'Accept: application/json' \
    --request POST \
    --user $API_USERNAME:$API_PASSWORD \
    "https://localhost:5665/v1/actions/schedule-downtime" | python3 -m json.tool

Bemerkung

Meldung „Unauthorized. Please check your user credentials.“?

Lösung: icinga2 daemon -C --dump-objects und erneut laufen lassen.

Alle Downtimes auf dem Icinga2 Master per API entfernen:

API_USERNAME='downtime-user'
API_PASSWORD=$(icinga2 object list --type ApiUser --name $API_USERNAME | sed -n 's/.* password = "\(.*\)"/\1/p')
cat > /tmp/icinga2-api.json << EOF
{
    "type": "Host",
    "all_services": true
}
EOF
curl \
    --insecure \
    --data @/tmp/icinga2-api.json \
    --header 'Accept: application/json' \
    --request POST \
    --user $API_USERNAME:$API_PASSWORD \
    "https://localhost:5665/v1/actions/remove-downtime" | python3 -m json.tool

Passiven Check befüttern:

username='icinga-director-api'
password='linuxfabrik'

host_name='test-host'
service_name='passive service'

plugin_output='multiline test
line 2
line 3

line 4 (after empty line)
line 5
line 6
'
# convert for icinga
plugin_output=${plugin_output//$'\n'/\\n}

curl \
    --insecure \
    --silent \
    --user "$username":"$password" \
    --header 'Accept: application/json' \
    --request POST 'https://master.example.com:5665/v1/actions/process-check-result' \
    --data @- << EOF
{
    "type": "Service",
    "filter": "host.name==\"$host_name\" && service.name==\"$service_name\"",
    "exit_status": 2,
    "plugin_output": "$plugin_output",
    "performance_data": [
    "rta=5000.000000ms;3000.000000;5000.000000;0.000000",
    "pl=100%;80;100;0"
    ],
    "check_source": "example.localdomain"
}
EOF

Icinga Director

Im Icinga Director funktionieren custom variables im notes und notes_url-Feld nicht.

Siehe https://github.com/Icinga/icingaweb2-module-director/issues/1021

Listen im Icinga Director alphabetisch sortieren

Listen-Einträge wie Custom Variables, Imports oder Command-Argumente landen im Director in Eingabe-Reihenfolge. Es gibt zwei Varianten zum Sortieren.

Variante 1, einmalig per Browser-Konsole, beschränkt auf Custom-Variables-Fieldsets: Host oder Service im Director öffnen, Browser-Konsole öffnen, Snippet einfügen, ausführen, anschliessend mit „Store“ speichern.

document.querySelectorAll('fieldset[id^="fieldset-custom_fields"] ul.extensible-set').forEach((ul) => {
    if (!ul.hasChildNodes()) { return; }
    const lis = Array.from(ul.children).filter((el) => el.tagName === 'LI');
    const filled = lis.filter((li) => {
        const txt = li.querySelector('input[type="text"]');
        return txt !== null && !txt.classList.contains('extend-set');
    });
    const rest = lis.filter((li) => !filled.includes(li));
    filled.sort((a, b) => a.querySelector('input[type="text"]').value
        .localeCompare(b.querySelector('input[type="text"]').value, undefined, { numeric: true, sensitivity: 'base' }));
    filled.concat(rest).forEach((li) => ul.appendChild(li));

    // Mirror Director's fixRelatedActions: first item disables move-up,
    // last data item disables move-down.
    const last = filled.length - 1;
    filled.forEach((li, idx) => {
        const up = li.querySelector('input[name$="__MOVE_UP"]');
        const down = li.querySelector('input[name$="__MOVE_DOWN"]');
        if (up) up.disabled = (idx === 0);
        if (down) down.disabled = (idx === last);
    });
});

Variante 2, dauerhaft per Tampermonkey-Userscript, aktiv auf allen ul.extensible-set-Feldern: Fügt jedem Feld mit mindestens zwei Einträgen einen Sort-Button neben dem Fieldset-Label hinzu. Tampermonkey ist eine Browser-Extension für Chrome, Firefox, Edge und Safari, die Userscripts auf passenden Seiten automatisch ausführt. Nach Installation der Extension und Anlegen des Skripts steht der Button auf allen Director-Formularen zur Verfügung.

// ==UserScript==
// @name         Icinga Director - Simple Sort
// @namespace    http://tampermonkey.net/
// @version      2026051901
// @description  Adds a sort button next to the label of every ul.extensible-set.
// @author       Linuxfabrik GmbH
// @match        https://*/icingaweb2/director/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // The "add new" <li> is the one containing the __ADD button (plain
    // variant) or the __DROP_DOWN button (suggestionContext variant).
    // Using these buttons as the anchor is more robust than relying on
    // the extend-set class, which the Director only sets conditionally
    // (see addAddMore in ExtensibleSetElement.php, including the
    // "TODO: was === 0?!" hint).
    function getAddNewLi(ul) {
        const anchor = ul.querySelector('input[name$="__ADD"], input[name$="__DROP_DOWN"]');
        return anchor ? anchor.closest('li') : null;
    }

    // Data items are every <li> that is not the add-new one and that
    // actually contains a text input (defensive against unexpected
    // sibling nodes).
    function getDataItems(ul) {
        const addLi = getAddNewLi(ul);
        return Array.from(ul.children)
            .filter(el => el.tagName === 'LI' && el !== addLi)
            .filter(li => li.querySelector('input[type="text"]') !== null);
    }

    // The fieldset label sits in the <dt> preceding the <dd> that
    // wraps the ul. Placing the button there keeps it visually stable:
    // the <dt> does not get re-rendered when items are added, removed
    // or reordered.
    function getLabelDt(ul) {
        const dd = ul.closest('dd');
        const dt = dd ? dd.previousElementSibling : null;
        return (dt && dt.tagName === 'DT') ? dt : null;
    }

    // Mirrors Director's fixRelatedActions: first item disables move-up,
    // last data item disables move-down.
    function fixRelatedActions(ul) {
        const dataItems = getDataItems(ul);
        const last = dataItems.length - 1;
        dataItems.forEach((li, idx) => {
            const up = li.querySelector('input[name$="__MOVE_UP"]');
            const down = li.querySelector('input[name$="__MOVE_DOWN"]');
            if (up) up.disabled = (idx === 0);
            if (down) down.disabled = (idx === last);
        });
    }

    function addButtons() {
        const sets = document.querySelectorAll('ul.extensible-set');

        sets.forEach(ul => {
            const dt = getLabelDt(ul);
            if (!dt) return;

            const existing = dt.querySelector('.tm-sort-btn');
            const dataItems = getDataItems(ul);

            if (dataItems.length < 2) {
                if (existing) existing.remove();
                return;
            }

            if (existing) return;

            const btn = document.createElement('button');
            btn.type = 'button';
            btn.className = 'tm-sort-btn';
            btn.textContent = '⇅ sort';
            btn.title = 'Sort entries alphabetically';
            btn.style = 'cursor:pointer; font-size:10px; color:#007bff; font-weight:normal; margin-left:10px; padding:0 4px; background:#fff; border:1px solid #ccd; border-radius:3px; vertical-align:middle; text-transform:none;';

            btn.addEventListener('click', (e) => {
                e.preventDefault();
                e.stopPropagation();

                const items = Array.from(ul.children).filter(el => el.tagName === 'LI');
                const filled = getDataItems(ul);
                const rest = items.filter(li => !filled.includes(li));

                filled.sort((a, b) => a.querySelector('input[type="text"]').value
                    .localeCompare(b.querySelector('input[type="text"]').value,
                        undefined, { numeric: true, sensitivity: 'base' }));

                filled.concat(rest).forEach(li => ul.appendChild(li));
                fixRelatedActions(ul);
            });

            dt.appendChild(btn);
        });
    }

    // React to Icinga's AJAX-driven DOM updates instead of polling.
    // requestAnimationFrame coalesces bursts of mutations into one pass.
    let scheduled = false;
    function schedule() {
        if (scheduled) return;
        scheduled = true;
        requestAnimationFrame(() => {
            scheduled = false;
            addButtons();
        });
    }

    new MutationObserver(schedule).observe(document.body, {
        childList: true,
        subtree: true
    });

    addButtons();
})();
Icinga Director Deployment schlägt fehl wegen Closing $ not found in macro format string

Icinga verwendet in seiner DSL $macroname$ zum auflösen von Makros. Dollarzeichen $ müssen mit einem weiteren Dollarzeichen $$ escaped werden.

Verteiltes Monitoring (Zones)

Einen Icinga Agent im Director in eine selbst benannte Cluster-Zone legen (z.B. satellite)

Setzt man auf einem Host Agent: yes (has_agent = y), erzeugt der Director Endpoint und Zone automatisch und benennt beide nach dem Host-Objekt. Das Feld „Cluster Zone“ am Agent-Host legt nur den parent dieser Auto-Zone fest, nicht deren Namen. Eine eigene Zone wie satellite bleibt dadurch leer, und Checks, die per Service-Template-Cluster-Zone auf satellite gepinnt sind, laufen weiter auf dem Master. Die Auto-Generierung wird übersprungen, sobald der Endpoint bereits existiert. Man definiert Endpoint und Zone deshalb von Hand, dann tritt der Director zurück:

  1. Icinga Infrastructure > Endpoints > Add: Der Endpoint muss exakt dem Zertifikats-CN bzw. NodeName des Agents entsprechen (bei einem vom Director provisionierten Agent ist das der Host-Objekt-Name). Adresse und Verbindungsrichtung setzen.

  2. Icinga Infrastructure > Zones > Add: Zone Name satellite, Parent Zone = Master-Zone (die Zone des Masters, üblicherweise master).

  3. Da der Endpoint nun existiert, erzeugt der Director keine eigene Zone mehr.

  4. Auf dem Agent die lokale /etc/icinga2/zones.conf anpassen: Sie wird beim Agent-Setup einmalig erzeugt und vom Director nicht verwaltet. Standardmässig steht dort eine nach dem Hostnamen benannte object Zone. Diese Zone in satellite umbenennen, sodass der Agent sich selbst als Mitglied von satellite versteht (object Zone "satellite" { endpoints = [ "..." ]; parent = "master" }). NodeName in /etc/icinga2/constants.conf muss dem Endpoint-Namen entsprechen. Danach icinga2 daemon -C und systemctl restart icinga2.

Die Topologie muss auf beiden Seiten übereinstimmen. Solange der Agent sich lokal in einer anders benannten Zone sieht, synchronisiert der Master die zones.d/satellite/-Konfiguration nicht zum Agent (unter /var/lib/icinga2/api/zones/ taucht dann nur director-global auf), und die Checks landen weiter auf dem Master. Nach dem Restart muss dort satellite/ erscheinen. Prüfen lässt sich der Zustand mit icinga2 object list --type Zone und icinga2 object list --type Endpoint auf dem Endpoint - es sollte die satellite Zone sowie der Endpoint selbst auftauchen.

icingacli-Checks bei getrennten IcingaWeb2 und Icinga2 Master-Hosts

Betreibt man ein verteiltes Icinga2 Setup, bei dem IcingaWeb2 und dessen Module nicht auf dem gleichen Host wie der Icinga2 Master selber läuft, muss dafür gesorgt werden, dass die icingacli-Checks (wie z.B. icingacli vspheredb check vm) auf dem IcingaWeb2-Host ausgeführt werden. Idealerweise sollte der Service im Webinterface aber unter dem korrekten Host, also nicht auf dem IcingaWeb2-Host, angezeigt werden.

Ein Service wird immer unter dem Host angezeigt, dem er per host_name zugeordnet ist. Wo er ausgeführt wird, steuern zwei verschiedene Mechanismen mit unterschiedlichen Voraussetzungen:

  1. command_endpoint: Der Master plant den Check, löst die Macros auf und schickt das Kommando per event::ExecuteCommand an den Ziel-Endpoint. Der ausführende Knoten braucht nur das CheckCommand-Objekt (liegt in der globalen Zone director-global und ist überall vorhanden), nicht das Host-Objekt. Das ist der robuste Weg für „unter Host A anzeigen, auf Knoten B ausführen“. Allerdings kann nur ein Endpoint angegeben werden, es gibt kein Load Balancing oder High Availability.

    Das Director-GUI-Formular bietet für Services kein command_endpoint-Feld. Über das CLI (oder die HTTP-API) lässt es sich dennoch direkt setzen:

    # service template
    icingacli director service set tpl-service-vspheredb-check-vm --command_endpoint icingaweb-endpoint
    # check the value
    icingacli director service show tpl-service-vspheredb-check-vm
    
    # single service on a specific host
    icingacli director service set 'vSphereDB Check VM' --command_endpoint icingaweb-endpoint --host host-a
    # check the value
    icingacli director service show 'vSphereDB Check VM' --host host-a
    

    Den tatsächlich ausgerollten Wert (nach dem Deployment) zeigt auf dem Master zusätzlich icinga2 object list --type Service --name 'host-a!vSphereDB Check VM' im Feld command_endpoint.

    Der Wert von „Run on agent“ wird ignoriert, wenn explizit ein command_endpoint angegeben ist.

  2. Zone mit eigenem Scheduling (Service oder Host-Objekt in eine Satellite-Zone, z.B. icingaweb2, legen): Das funktioniert nur, wenn das Host-Objekt für diese Zone sichtbar ist. Die Config-Sync-Regel (Zone::CanAccessObject) lautet: eine Zone erhält globale Zonen, ihre eigene Zone und ihre Kind-Zonen, niemals die Eltern-Zone. Ein Host in der Master-Zone ist daher für eine darunterliegende icingaweb2-Zone unsichtbar, der Service kann dort nicht instanziiert werden, und der Master führt ihn selbst aus. Damit der Zonen-Weg greift, muss das Host-Objekt selbst in der Ziel-Zone (oder einer Kind-/globalen Zone) liegen, nicht im Master.

    Funktioniert nicht: Host in Master-Zone, Service auf Kind-Zone gepinnt.

    Zone master
    +-- Endpoint master                       executes the check itself
    +-- Host host-a
    |   +-- Service vspheredb-check-vm
    |       zone = "icingaweb2"               intended, but:
    |
    +-- Zone icingaweb2                       child zone receives
        +-- Endpoint icingaweb2-a             global + own + child zones,
        +-- Endpoint icingaweb2-b             never the parent zone master
                                              -> host host-a not visible
                                              -> service not instantiated
    

    Das heisst, für echtes Failover über zwei Knoten (also eine Zone mit zwei Endpoints) müssen die betroffenen Host-Objekte in der icingaweb2-Zone liegen. Das geht nur für agentenlose Objekte (z.B. reine vSphere-VM-Host-Objekte ohne lokalen Agent); ein Host, der bereits per lokalem Agent in seiner eigenen Zone überwacht wird, kann nicht zusätzlich in die icingaweb2-Zone, da ein Host nur in genau einer Zone liegen kann.

    Funktioniert: Host liegt in der Executor-Zone, beide Endpoints können ausführen.

    Zone master
    +-- Endpoint master
    |
    +-- Zone icingaweb2                       2 endpoints = native HA
        +-- Endpoint icingaweb2-a
        +-- Endpoint icingaweb2-b
        +-- Host host-a                       visible here
            +-- Service vspheredb-check-vm    executed by one of
                                              the zone's endpoints
    

Icinga DB

unexpected database schema version: v4 (expected v5), please make sure you have applied all database migrations after upgrading Icinga DB
mysql --user mariadb-admin --password icingadb < /usr/share/icingadb/schema/mysql/upgrades/1.2.0.sql
mysql --user mariadb-admin --password icingadb < /usr/share/icingadb/schema/mysql/upgrades/optional/1.2.0-history.sql

systemctl restart icingadb
Icinga IDO aufräumen

Icinga IDO ist „DEPRECATED and will be removed in v2.18.“ und wurde von IcingaDB abgelöst. Wenn man IDO per LFOps konfiguriert hatte und nach der Migration zu IcingaDB nicht mehr benötigt, kann wie folgt aufgeräumt werden:

auf dem Icinga2 Master
icinga2 feature disable ido-mysql
systemctl restart icinga2
auf dem Ansible Controller
cat > /tmp/extra-vars.yml << 'EOF'
mariadb_server__databases__combined_var:
  - name: 'icinga2_ido'
    state: 'absent'
  - name: 'icinga_ido'
    state: 'absent'

mariadb_server__users__combined_var:
  - username: 'icinga-ido'
    host: 'localhost'
    state: 'absent'
  - username: 'icinga2'
    host: 'localhost'
    state: 'absent'
EOF

ansible-navigator run linuxfabrik.lfops.setup_icinga2_master --inventory /path/to/inventory --tags mariadb_server:database,mariadb_server:user --extra-vars @/tmp/extra-vars.yml

Icinga for Windows (PowerShell Framework)

Bemerkung

WinRM ist die von Microsoft und Windows genutzte Plattform, um Systeme remote zu verwalten. WMI kann als eine Möglichkeit WinRM verwenden. Wer WMI auf seinem lokalen Rechner verwendet, nutzt demnach kein WinRM.

Siehe auch https://icinga.com/docs/icinga-for-windows.

Beispiele für Abfragen gegen einen MS-SQL-Server:

PS C:\Windows\system32> icinga { Invoke-IcingaCheckMSSQLResource -SqlUsername 'user' -SqlPassword (ConvertTo-IcingaSecureString 'password') -SqlHost sqlsrv -Verbosity 1 }
[OK] MSSQL Performance (MSSQLSERVER)
| 'average_latch_wait_time_ms'=0.001238s;; 'buffer_cache_hit_ratio'=100%;;;0;100 'page_life_expectancy'=2027081;;
0

PS C:\Windows\system32> icinga { Invoke-IcingaCheckMSSQLBackupStatus -SqlUsername 'user' -SqlPassword (ConvertTo-IcingaSecureString 'password') -SqlHost sqlsrv -Verbosity 1 }
[OK] MSSQL Backup (MSSQLSERVER)
| 'average_size'=1658538B;; 'log_age'=0s;; 'size'=1670148000B;; 'status'=0;6;5 'execution_time'=0s;; 'age'=0s;; 'average_size'=24806280B;; 'log_age'=0s;; 'size'=5854283000B;; 'status'=0;6;5 'execution_time'=0s;; 'age'=54000s;; 'average_size'=1658919B;; 'log_age'=0s;; 'size'=1670531000B;; 'status'=0;6;5 'execution_time'=0s;; 'age'=0s;; 'average_size'=13233520B;; 'log_age'=0s;; 'size'=16409560000B;; 'status'=0;6;5 'execution_time'=0s;; 'age'=0s;; 'average_size'=4590350B;; 'log_age'=0s;; 'size'=5710395000B;; 'status'=0;6;5 'execution_time'=0s;; 'age'=0s;; 'average_size'=5829484B;; 'log_age'=0s;; 'size'=1375758000B;; 'status'=0;6;5 'execution_time'=0s;; 'age'=54000s;; 'average_size'=3417790B;; 'log_age'=0s;; 'size'=4255149000B;; 'status'=0;6;5 'execution_time'=0s;; 'age'=0s;; 'average_size'=981317.3B;; 'log_age'=0s;; 'size'=1224684000B;; 'status'=0;6;5 'execution_time'=0s;; 'age'=0s;; 'average_size'=56638400B;; 'log_age'=0s;; 'size'=70231610000B;; 'status'=0;6;5 'execution_time'=0s;; 'age'=0s;;
0

PS C:\Windows\system32> icinga { Invoke-IcingaCheckMSSQLHealth -SqlUsername 'user' -SqlPassword (ConvertTo-IcingaSecureString 'password') -SqlHost sqlsrv -Verbosity 1 }
[OK] MSSQL Health (MSSQLSERVER)
| 'service_sql_server_mssqlserver_mssqlserver'=4;;4 'connection_time'=0.069s;;
0

PS C:\Windows\system32> icinga { Invoke-IcingaCheckMSSQLPerfCounter -SqlUsername 'user' -SqlPassword (ConvertTo-IcingaSecureString 'password') -SqlHost sqlsrv -Verbosity 1 -Performanc
eCounter '\SQLServer:Buffer Manager\Buffer cache hit ratio', '\SQLServer:Latches\Average Latch Wait Time (ms)'}
[OK] MSSQL Performance Counter (MSSQLSERVER)
| 'sqlserverlatches'=56371;; 'sqlserverbuffer_manager'=24;;
0

Zertifikate

Fingerprint vom Master prüfen (You have to ensure that this certificate actually matches the parent instance's certificate in order to avoid man-in-the-middle attacks.)

Den Fingerprint sieht man auf dem Agent, wenn man entweder das icinga2 node setup oder icinga2 pki save-cert gegen den Master ausführt. Auf dem Master lässt sich der Fingerprint mit folgendem Kommando ermitteln:

openssl x509 -fingerprint -sha256 -noout -in /var/lib/icinga2/certs/$(hostname --fqdn).crt

Troubleshooting

icinga2 wird wegen out-of-memory gekillt

In so einem Fall sollte man sich die Grössen der Queues des Icinga2 Cores anschauen. Diese werden immer wieder in das Icinga2 Logfile schrieben. Alternativ werden diese auch als Performance Daten von bultin-in icinga-Check ausgegeben.

Module path "/usr/share/icingaweb2/modules" does not exist. ERROR: Cannot read enabled modules. Config directory "/etc/icingaweb2" is not readable beim Aufruf von icingacli durch Icinga2

Das kann entweder an falschen File-Permissions oder an SELinux liegen. Zu SELinux gibt es ein ungelöstes GitHub-Issue. Als Workaround kann man ein eigenes SEModule bauen und laden:

cat > icingacli.te << 'EOF'
module icingacli 1.0;

require {
    type icingaweb2_rw_content_t;
    type icingaweb2_config_t;
    type icingaweb2_content_t;
    type icinga2_t;
    class dir { getattr open read search };
    class file { getattr open read };
    class lnk_file { getattr open read };
}

#============= icinga2_t ==============

allow icinga2_t icingaweb2_config_t:dir { getattr open read search };
allow icinga2_t icingaweb2_config_t:file { getattr open read };
allow icinga2_t icingaweb2_config_t:lnk_file { getattr read };
allow icinga2_t icingaweb2_content_t:dir { getattr open read search };
allow icinga2_t icingaweb2_content_t:file { getattr open read };
allow icinga2_t icingaweb2_rw_content_t:dir getattr;
EOF

yum -y install make selinux-policy-devel
make --file /usr/share/selinux/devel/Makefile icingacli.pp
semodule --install icingacli.pp
systemctl restart icinga2
high-availability: Lost heartbeat-Meldungen im IcingaDB Journal nach Deployments im Icinga Director

Wenn der Restart des Icinga2-Prozesses nach dem Deployment etwas länger dauert (was in grösseren Umgebungen durchaus vorkommen kann), werden möglicherweise keine Heartbeats in Redis geschrieben. Sobald der Restart jedoch abgeschlossen ist, sollte alles wieder normal laufen.

Kann man String-Werte als Performance Daten mitgeben, also z.B. |'version'=test-string;;;;?

Nein, Icinga2 mag das nicht und beklagt sich im Log mit debug/PerfdataValue: Can't convert 'test-string' to a floating point number.