ansible: add 'monitor' role mirroring live monitor.vntx.net (Icinga2 + Web 2)

Codifies the bare-metal Icinga2 master + Icinga Web 2 stack on
monitor.vntx.net (Ubuntu 22.04, Apache + mod_php, MariaDB 10.6, Icinga
2.16, IDO-MySQL backend). Re-running the role against the live host
should produce a near-identical configuration.

Role includes:
- Icinga apt repo + full package set (icinga2, ido-mysql, icingaweb2,
  monitoring-plugins, nagios-plugins-contrib, php + apache deps).
- MariaDB DB + user provisioning for both icinga2 (IDO daemon) and
  icingaweb2 (UI), plus a separate read-only `icinga` user that the UI
  uses to read the IDO. Schema bootstrapped only on first install.
- Templated icinga2 config (constants/zones/icinga2.conf), features-
  enabled symlinks (api/checker/command/ido-mysql/mainlog), and the
  three secret-bearing conf.d files (api-users, pagerduty x2) wired to
  vault vars.
- 23 dormant conf.d/* host + service definitions copied verbatim under
  files/. The live install has `include_recursive "conf.d"` commented
  out (a node-setup CLI artifact); role mirrors that. Set
  `icinga2_load_confd: true` in host_vars to rehydrate them.
- Icinga Web 2 ini files (config/auth/groups/roles/modules) + templated
  resources.ini for DB credentials. monitoring module enabled via
  symlink. icingaweb2 admin user bootstrapped on first install via a
  one-shot insert into icingaweb_user (gated on schema-not-yet-imported).
- Apache rewrite + ssl modules. Vhost itself is left to certbot --apache
  (Let's Encrypt cert is operator-managed, role doesn't manage it).

Cluster-wide cleanup:
- Gut roles/general/tasks/debian/icinga2.yml down to the uninstall
  safety net (kept the sweep that removes icinga2 from non-monitoring
  hosts). The previous master-side install + cert-distribution tasks
  referenced templates that never existed in the role; the new monitor
  role replaces them properly.

Operator action before first apply:
- Create host_vars/monitor.vntx.net/vault.yml with the seven required
  secrets (see roles/monitor/README.md). Live values can be pulled from
  /etc/icinga2/conf.d/{api-users,pagerduty-*,ido-mysql}.conf and
  /etc/icingaweb2/resources.ini on the live host.
- Generate the icingaweb2 admin password hash via
  `php -r 'echo password_hash("plaintext", PASSWORD_DEFAULT);'`.
- Run --check --diff before applying; the role is meant to be idempotent
  but hasn't been verified against the live install.
This commit is contained in:
Graham McIntire 2026-05-08 13:00:53 -05:00
parent f3f10c3e36
commit 88bdbbe88f
No known key found for this signature in database
GPG key ID: F4ABF488E6029E59
45 changed files with 1885 additions and 127 deletions

View file

@ -12,3 +12,23 @@ firewall_allow_rules:
- port: 443
proto: tcp
comment: HTTPS
- port: 5665
proto: tcp
comment: Icinga2 API
# ---- monitor role overrides ----
icinga2_master_zone_name: master
# Live install has conf.d/* commented out; flip to true to load the
# dormant host/service definitions.
icinga2_load_confd: false
# Secrets — see roles/monitor/README.md and host_vars/monitor.vntx.net/vault.yml
icinga2_api_user_root_password: "{{ vault_icinga2_api_user_root_password }}"
icinga2_api_user_icingaweb2_password: "{{ vault_icinga2_api_user_icingaweb2_password }}"
icinga2_ido_db_password: "{{ vault_icinga2_ido_db_password }}"
icingaweb2_db_password: "{{ vault_icingaweb2_db_password }}"
icingaweb2_ido_db_password: "{{ vault_icingaweb2_ido_db_password }}"
icinga2_iftraffic_snmp_community: "{{ vault_icinga2_iftraffic_snmp_community }}"
icinga2_pagerduty_key: "{{ vault_icinga2_pagerduty_key }}"
icinga2_pagerduty_servers_key: "{{ vault_icinga2_pagerduty_servers_key }}"
icingaweb2_admin_password_hash: "{{ vault_icingaweb2_admin_password_hash | default('') }}"

View file

@ -42,6 +42,16 @@
roles:
- netbox
- name: Install and configure Icinga2 monitor
hosts: monitoring_servers
become: true
gather_facts: true
tags:
- monitor
- icinga2
roles:
- monitor
- name: Install and configure Caddy
hosts: caddy_servers
become: true

View file

@ -1,136 +1,17 @@
- name: Install icinga2
apt:
pkg:
- icinga2
- monitoring-plugins
- nagios-plugins-contrib
update_cache: true
state: latest
cache_valid_time: 3600
when: "'monitoring_servers' in group_names"
register: icinga2_install
tags:
- icinga2_install
# Master-side install + certificate handling for icinga2 lives in the
# `monitor` role (roles/monitor/). This file used to also include broken
# satellite-cert-distribution tasks (referenced templates that never
# existed); they've been removed. Only the uninstall safety net remains —
# every host outside `monitoring_servers` gets icinga2 removed in case it
# was historically deployed as a client.
- name: Uninstall icinga2
apt:
- name: Uninstall icinga2 (non-monitor hosts)
ansible.builtin.apt:
pkg:
- icinga2
- monitoring-plugins
- nagios-plugins-contrib
state: absent
when: "'monitoring_servers' not in group_names"
register: icinga2_uninstall
tags:
- icinga2_install
- name: ensure certificate directory exists
file:
path: "{{ base.monitoring.cert_dir }}"
state: directory
owner: 'nagios'
group: 'nagios'
mode: '0700'
when: '"monitoring_servers" in group_names'
tags:
- icinga2_cert_dir
- name: Check if icinga2 CA certificate exists locally
stat:
path: "{{ playbook_dir }}/roles/general/files/var/lib/icinga2/certs/ca.crt"
delegate_to: localhost
become: false
register: icinga2_ca_cert_local
when: '"monitoring_servers" in group_names'
- name: install icinga2 CA certificate
copy:
src: var/lib/icinga2/certs/ca.crt
dest: "{{ base.monitoring.cert_dir }}/ca.crt"
owner: 'nagios'
group: 'nagios'
when:
- '"monitoring_servers" in group_names'
- icinga2_ca_cert_local.stat.exists | default(false)
- name: check for trusted master certificate
stat:
path: "{{ base.monitoring.cert_dir }}/trusted-master.crt }}"
register: trusted_master_cert
when: '"monitoring_servers" in group_names'
- name: check trusted master certificate hash
shell:
cmd: "openssl x509 -in {{ base.monitoring.cert_dir }}/trusted-master.crt -noout -hash"
register: trusted_master_cert_hash
when: '"monitoring_servers" in group_names and trusted_master_cert.stat.exists'
- name: delete old certificates
file:
path: "{{ item }}"
state: absent
when: "'monitoring_servers' in group_names and trusted_master_cert.stat.exists and trusted_master_cert_hash.stdout != trusted_master_hash"
loop:
- "{{ base.monitoring.cert_dir }}/trusted-master.crt"
- "{{ base.monitoring.cert_dir }}/{{ inventory_hostname }}.crt"
- "{{ base.monitoring.cert_dir }}/{{ inventory_hostname }}.key"
- name: get trusted master certificate
shell:
cmd: "icinga2 pki save-cert --trustedcert {{ base.monitoring.cert_dir }}/trusted-master.crt --host {{ base.monitoring.server }}"
when: "'monitoring_servers' in group_names and (not trusted_master_cert.stat.exists or trusted_master_cert_hash.stdout != trusted_master_hash)"
- name: check for client certificate
stat:
path: "/var/lib/icinga2/certs/{{ inventory_hostname }}.crt"
register: client_certificate
when: '"monitoring_servers" in group_names'
- name: icinga2 setup
shell:
cmd: "icinga2 node setup --zone {{ inventory_hostname }} --endpoint {{ base.monitoring.server }} --parent_host {{ base.monitoring.server }} --parent_zone master --cn {{ inventory_hostname }} --accept-config --accept-commands --disable-confd --trustedcert {{ base.monitoring.cert_dir }}/trusted-master.crt"
when: "'monitoring_servers' in group_names and not client_certificate.stat.exists"
register: setup
- name: zones.conf
template:
src: etc/icinga2/zones.conf.j2
dest: /etc/icinga2/zones.conf
owner: nagios
group: nagios
mode: "0644"
register: zones_config
when: '"monitoring_servers" in group_names'
- name: icinga2.conf
template:
src: etc/icinga2/icinga2.conf.j2
dest: /etc/icinga2/icinga2.conf
owner: nagios
group: nagios
mode: "0644"
register: icinga2_config
when: '"monitoring_servers" in group_names'
- name: checks.conf
template:
src: etc/icinga2/conf.d/checks.conf.j2
dest: /etc/icinga2/conf.d/checks.conf
owner: nagios
group: nagios
mode: "0644"
register: checks_config
when: '"monitoring_servers" in group_names'
- name: check if certificate has been signed
shell:
cmd: "openssl x509 -in {{ base.monitoring.cert_dir }}/{{ inventory_hostname }}.crt -noout -issuer_hash -hash | uniq -d | wc -l"
register: signed
when: '"monitoring_servers" in group_names'
- name: restart icinga2
service:
name: icinga2
state: reloaded
enabled: true
when: '"monitoring_servers" in group_names'

View file

@ -0,0 +1,59 @@
# monitor role
Builds an Icinga2 master + Icinga Web 2 stack matching the live install on
`monitor.vntx.net`:
- Ubuntu 22.04 + Apache 2.4 + mod_php + MariaDB 10.6 + Icinga 2.16
- Single zone, master-only (no satellites configured but `zones.conf` is
templated to add them later)
- IDO-MySQL backend; `icinga2` daemon writes status, `icinga` user
read-only-selects for the Web 2 UI, `icingaweb2` user owns the UI's
own DB
- 25 dormant `conf.d/*` host + service files shipped under `files/` and
copied verbatim. The live install has `include_recursive "conf.d"`
commented out (a node-setup CLI artifact); this role mirrors that.
Set `icinga2_load_confd: true` in host_vars to rehydrate them.
## Required vault variables
Encrypt these with `ansible-vault` (e.g. `host_vars/monitor.vntx.net/vault.yml`):
```yaml
# Icinga API users (api-users.conf)
icinga2_api_user_root_password: "..."
icinga2_api_user_icingaweb2_password: "..."
# Icinga2 daemon → IDO database
icinga2_ido_db_password: "..."
# icingaweb2 UI → its own database
icingaweb2_db_password: "..."
# icingaweb2 UI → IDO database (separate read-only user)
icingaweb2_ido_db_password: "..."
# Constants
icinga2_iftraffic_snmp_community: "..."
icinga2_ticket_salt: "" # only needed for distributed setups
# PagerDuty integration keys
icinga2_pagerduty_key: "..."
icinga2_pagerduty_servers_key: "..."
# icingaweb2 admin user (web UI password). Generate the hash on any host
# with PHP installed: php -r 'echo password_hash("plaintext", PASSWORD_DEFAULT);'
icingaweb2_admin_password_hash: "$2y$10$..."
```
## What the role does NOT manage
- Let's Encrypt certificate provisioning. The live install used `certbot
--apache`; this role assumes the cert already exists at
`/etc/letsencrypt/live/<host>/`. Run certbot once by hand.
- The `icingaweb2` schema is imported once on first install. Schema
upgrades after Icinga Web 2 minor version bumps are not handled here —
see `/usr/share/icingaweb2/schema/upgrades/` and run the matching
upgrade SQL by hand.
- Distributed monitoring satellites. The role provisions a single-node
master; add Endpoint/Zone objects in `zones.d/` (or extend
`zones.conf.j2`) when you wire satellites in.

View file

@ -0,0 +1,97 @@
---
# Master Icinga2 + Icinga Web 2 stack. Mirrors the live install on
# monitor.vntx.net (Ubuntu 22.04, Apache + mod_php, MariaDB 10.6, single
# zone, IDO-MySQL backend). Per-host overrides (ALLOWED_HOSTS-equivalent,
# zone names, etc.) live in host_vars; secrets in ansible-vault.
# Icinga repo + packages
icinga2_apt_key_url: "https://packages.icinga.com/icinga.key"
icinga2_apt_keyring: "/etc/apt/keyrings/icinga-archive-keyring.gpg"
icinga2_apt_repo: "deb [signed-by={{ icinga2_apt_keyring }}] https://packages.icinga.com/ubuntu icinga-{{ ansible_distribution_release }} main"
icinga2_packages:
- icinga2
- icinga2-ido-mysql
- monitoring-plugins
- nagios-plugins-contrib
- vim-icinga2
- icingaweb2
- icingaweb2-common
- icingacli
- icinga-php-library
- icinga-php-thirdparty
# Web stack — apache + mod_php (matches live install, not php-fpm).
icinga2_web_packages:
- apache2
- libapache2-mod-php
- php
- php-curl
- php-gd
- php-intl
- php-ldap
- php-mbstring
- php-mysql
- php-xml
- php-zip
- python3-certbot-apache
# Database stack
icinga2_db_packages:
- mariadb-server
- mariadb-client
- python3-pymysql # required by community.mysql modules
# Cluster identity
icinga2_node_name: "{{ inventory_hostname }}"
icinga2_zone_name: "{{ inventory_hostname }}"
icinga2_master_zone_name: "master"
# Constants — vault-backed
# icinga2_ticket_salt: "" # set in vault if generating signed certs for satellites
# icinga2_iftraffic_snmp_community: "" # vault-only
# IDO database (icinga2 daemon writes status here)
icinga2_ido_db_host: "localhost"
icinga2_ido_db_name: "icinga2"
icinga2_ido_db_user: "icinga2"
# icinga2_ido_db_password: vault-only
# icingaweb2 database (UI's own data)
icingaweb2_db_host: "localhost"
icingaweb2_db_name: "icingaweb2"
icingaweb2_db_user: "icingaweb2"
# icingaweb2_db_password: vault-only
# How icingaweb2 reads the IDO. Live install uses a separate `icinga` user
# rather than reusing `icinga2`; keep that separation.
icingaweb2_ido_db_host: "localhost"
icingaweb2_ido_db_name: "icinga2"
icingaweb2_ido_db_user: "icinga"
# icingaweb2_ido_db_password: vault-only (live install reuses the icingaweb2
# password; default both the same value in vault unless rotating)
# Whether to load conf.d/* host/service definitions. Live monitor.vntx.net
# has the include disabled; default to that. Flip to true to rehydrate.
icinga2_load_confd: false
# IDO schema bootstrap — only runs on first install, gated by a marker.
icinga2_ido_schema_path: /usr/share/icinga2-ido-mysql/schema/mysql.sql
# Apache vhost (Let's Encrypt managed externally via certbot — this role
# just ensures apache + the icingaweb2 alias config are in place).
icinga2_apache_server_name: "{{ inventory_hostname }}"
# Features to enable on the master. Order matches live install.
icinga2_enabled_features:
- api
- checker
- command
- ido-mysql
- mainlog
# icingaweb2 admin user (Web UI password is set as a bcrypt hash directly
# in the icingaweb2 DB; this role bootstraps it on first install).
icingaweb2_admin_user: "graham"
# icingaweb2_admin_password_hash: vault-only — generate with:
# php -r 'echo password_hash("plaintext", PASSWORD_DEFAULT);'

View file

@ -0,0 +1 @@
object IcingaApplication "app" { }

View file

@ -0,0 +1,7 @@
//apply Service "apt" {
// import "generic-service"
//
// check_command = "apt"
//
// assign where host.name == NodeName
//}

View file

@ -0,0 +1 @@
// Managed by Ansible

View file

@ -0,0 +1,204 @@
/* Command objects */
/* Notification Commands
*
* Please check the documentation for all required and
* optional parameters.
*/
object NotificationCommand "mail-host-notification" {
command = [ ConfigDir + "/scripts/mail-host-notification.sh" ]
arguments += {
"-4" = "$notification_address$"
"-6" = "$notification_address6$"
"-b" = "$notification_author$"
"-c" = "$notification_comment$"
"-d" = {
required = true
value = "$notification_date$"
}
"-f" = {
value = "$notification_from$"
description = "Set from address. Requires GNU mailutils (Debian/Ubuntu) or mailx (RHEL/SUSE)"
}
"-i" = "$notification_icingaweb2url$"
"-l" = {
required = true
value = "$notification_hostname$"
}
"-n" = {
required = true
value = "$notification_hostdisplayname$"
}
"-o" = {
required = true
value = "$notification_hostoutput$"
}
"-r" = {
required = true
value = "$notification_useremail$"
}
"-s" = {
required = true
value = "$notification_hoststate$"
}
"-t" = {
required = true
value = "$notification_type$"
}
"-v" = "$notification_logtosyslog$"
}
vars += {
notification_address = "$address$"
notification_address6 = "$address6$"
notification_author = "$notification.author$"
notification_comment = "$notification.comment$"
notification_type = "$notification.type$"
notification_date = "$icinga.long_date_time$"
notification_hostname = "$host.name$"
notification_hostdisplayname = "$host.display_name$"
notification_hostoutput = "$host.output$"
notification_hoststate = "$host.state$"
notification_useremail = "$user.email$"
}
}
object NotificationCommand "mail-service-notification" {
command = [ ConfigDir + "/scripts/mail-service-notification.sh" ]
arguments += {
"-4" = "$notification_address$"
"-6" = "$notification_address6$"
"-b" = "$notification_author$"
"-c" = "$notification_comment$"
"-d" = {
required = true
value = "$notification_date$"
}
"-e" = {
required = true
value = "$notification_servicename$"
}
"-f" = {
value = "$notification_from$"
description = "Set from address. Requires GNU mailutils (Debian/Ubuntu) or mailx (RHEL/SUSE)"
}
"-i" = "$notification_icingaweb2url$"
"-l" = {
required = true
value = "$notification_hostname$"
}
"-n" = {
required = true
value = "$notification_hostdisplayname$"
}
"-o" = {
required = true
value = "$notification_serviceoutput$"
}
"-r" = {
required = true
value = "$notification_useremail$"
}
"-s" = {
required = true
value = "$notification_servicestate$"
}
"-t" = {
required = true
value = "$notification_type$"
}
"-u" = {
required = true
value = "$notification_servicedisplayname$"
}
"-v" = "$notification_logtosyslog$"
}
vars += {
notification_address = "$address$"
notification_address6 = "$address6$"
notification_author = "$notification.author$"
notification_comment = "$notification.comment$"
notification_type = "$notification.type$"
notification_date = "$icinga.long_date_time$"
notification_hostname = "$host.name$"
notification_hostdisplayname = "$host.display_name$"
notification_servicename = "$service.name$"
notification_serviceoutput = "$service.output$"
notification_servicestate = "$service.state$"
notification_useremail = "$user.email$"
notification_servicedisplayname = "$service.display_name$"
}
}
/*
* If you prefer to use the notification scripts with environment
* variables instead of command line parameters, you can use
* the following commands. They have been updated from < 2.7
* to support the new notification scripts and should help
* with an upgrade.
* Remove the comment blocks and comment the notification commands above.
*/
/*
object NotificationCommand "mail-host-notification" {
command = [ ConfigDir + "/scripts/mail-host-notification.sh" ]
env = {
NOTIFICATIONTYPE = "$notification.type$"
HOSTDISPLAYNAME = "$host.display_name$"
HOSTNAME = "$host.name$"
HOSTADDRESS = "$address$"
HOSTSTATE = "$host.state$"
LONGDATETIME = "$icinga.long_date_time$"
HOSTOUTPUT = "$host.output$"
NOTIFICATIONAUTHORNAME = "$notification.author$"
NOTIFICATIONCOMMENT = "$notification.comment$"
HOSTDISPLAYNAME = "$host.display_name$"
USEREMAIL = "$user.email$"
}
}
object NotificationCommand "mail-service-notification" {
command = [ ConfigDir + "/scripts/mail-service-notification.sh" ]
env = {
NOTIFICATIONTYPE = "$notification.type$"
SERVICENAME = "$service.name$"
HOSTNAME = "$host.name$"
HOSTDISPLAYNAME = "$host.display_name$"
HOSTADDRESS = "$address$"
SERVICESTATE = "$service.state$"
LONGDATETIME = "$icinga.long_date_time$"
SERVICEOUTPUT = "$service.output$"
NOTIFICATIONAUTHORNAME = "$notification.author$"
NOTIFICATIONCOMMENT = "$notification.comment$"
HOSTDISPLAYNAME = "$host.display_name$"
SERVICEDISPLAYNAME = "$service.display_name$"
USEREMAIL = "$user.email$"
}
}
*/
object CheckCommand "check_snmp" {
import "plugin-check-command"
command = [ PluginDir + "/check_snmp" ]
arguments = {
"-H" = "$snmpv3_address$"
"-P" = "$snmp_port$"
"-o" = "$snmpv3_oid$"
"-C" = "$snmp_community$"
"-V" = "$snmp_version$"
"-U" = "$snmpv3_user$"
"-L" = "$snmpv3_seclevel$"
"-a" = "$snmpv3_auth_alg$"
"-x" = "$snmpv3_priv_alg$"
"-A" = "$snmpv3_auth_key$"
"-X" = "$snmpv3_priv_key$"
}
}

View file

@ -0,0 +1,20 @@
/**
* The example downtime apply rule.
*/
apply ScheduledDowntime "backup-downtime" to Service {
author = "icingaadmin"
comment = "Scheduled downtime for backup"
ranges = {
monday = service.vars.backup_downtime
tuesday = service.vars.backup_downtime
wednesday = service.vars.backup_downtime
thursday = service.vars.backup_downtime
friday = service.vars.backup_downtime
saturday = service.vars.backup_downtime
sunday = service.vars.backup_downtime
}
assign where service.vars.backup_downtime != ""
}

View file

@ -0,0 +1,70 @@
/**
* Host group examples.
*/
object HostGroup "Verona" {
display_name = "Verona"
assign where host.vars.tower == "Verona"
}
object HostGroup "Climax" {
display_name = "Climax"
assign where host.vars.tower == "Climax"
}
object HostGroup "Altoga" {
display_name = "Altoga"
assign where host.vars.tower == "Altoga"
}
object HostGroup "Culleoka" {
display_name = "Culleoka"
assign where host.vars.tower == "Culleoka"
}
object HostGroup "Lowry Crossing" {
display_name = "Lowry Crossing"
assign where host.vars.tower == "Lowry Crossing"
}
object HostGroup "New Hope" {
display_name = "New Hope"
assign where host.vars.tower == "New Hope"
}
object HostGroup "982" {
display_name = "982"
assign where host.vars.tower == "982"
}
object HostGroup "380" {
display_name = "380"
assign where host.vars.tower == "380"
}
object HostGroup "linux-servers" {
display_name = "Linux Servers"
assign where host.vars.os == "Linux"
}
object HostGroup "windows-servers" {
display_name = "Windows Servers"
assign where host.vars.os == "Windows"
}
/**
* Service group examples.
*/
object ServiceGroup "ping" {
display_name = "Ping Checks"
assign where match("ping*", service.name)
}
object ServiceGroup "http" {
display_name = "HTTP Checks"
assign where match("http*", service.check_command)
}
object ServiceGroup "disk" {
display_name = "Disk Checks"
assign where match("disk*", service.check_command)
}

View file

@ -0,0 +1,17 @@
object Host "494-router" {
import "mikrotik"
address = "10.254.254.111"
vars.tower = "494"
}
object Host "494-omni-2.4" {
import "ap-ubnt"
address = "10.10.175.10"
vars.tower = "494"
vars.parents = "10.254.254.111"
}
object Host "494-omni-epmp" {
import "ap-epmp"
address = "10.10.175.11"
vars.tower = "494"
vars.parents = "10.254.254.111"
}

View file

@ -0,0 +1,48 @@
object Host "982-router" {
import "mikrotik"
address = "10.254.254.110"
vars.tower = "982"
}
object Host "982-1" {
import "ap-ubnt"
address = "10.10.63.1"
vars.tower = "982"
vars.parents = "982-router"
}
object Host "982-2" {
import "ap-ubnt"
address = "10.10.63.2"
vars.tower = "982"
vars.parents = "982-router"
}
object Host "982-3" {
import "ap-ubnt"
address = "10.10.63.3"
vars.tower = "982"
vars.parents = "982-router"
}
object Host "982-4" {
import "ap-ubnt"
address = "10.10.63.4"
vars.tower = "982"
vars.parents = "982-router"
}
object Host "982-5" {
import "ap-ubnt"
address = "10.10.63.5"
vars.tower = "982"
vars.parents = "982-router"
}
object Host "982-6" {
import "ap-ubnt"
address = "10.10.63.6"
vars.tower = "982"
vars.parents = "982-router"
}
object Host "982-to-380" {
import "ap-ubnt"
address = "10.250.1.34"
vars.tower = "982"
vars.parents = "982-router"
}

View file

@ -0,0 +1,6 @@
//object Host "altoga-verona" {
// import "ap-ubnt"
// address = "10.250.1.149"
// vars.tower = "Altoga"
//}

View file

@ -0,0 +1,55 @@
object Host "climax-router" {
import "mikrotik"
address = "10.254.254.102"
vars.tower = "Climax"
}
object Host "climax-ubnt-nw" {
import "ap-ubnt"
address = "10.10.31.11"
vars.tower = "Climax"
vars.parents = "10.254.254.102"
}
object Host "climax-ubnt-ne" {
import "ap-ubnt"
address = "10.10.31.12"
vars.tower = "Climax"
vars.parents = "10.254.254.102"
}
object Host "climax-ubnt-s" {
import "ap-ubnt"
address = "10.10.31.13"
vars.tower = "Climax"
vars.parents = "10.254.254.102"
}
object Host "climax-epmp-nw" {
import "ap-epmp"
address = "10.10.31.30"
vars.tower = "Climax"
vars.parents = "10.254.254.102"
}
object Host "climax-900-w" {
import "ap-ubnt"
address = "10.10.31.40"
vars.tower = "Climax"
vars.parents = "10.254.254.102"
}
object Host "climax-core-af24" {
import "af24"
address = "10.250.1.90"
vars.tower = "Climax"
vars.parents = "10.254.254.102"
}
//object Host "climax-verona-af11" {
// import "af11"
// address = "10.250.1.29"
// vars.tower = "Climax"
// vars.parents = "10.254.254.102"
//}
//object Host "climax-culleoka-af11" {
// import "af11"
// address = "10.250.1.13"
// vars.tower = "Climax"
// vars.parents = "10.254.254.102"
//}

View file

@ -0,0 +1,87 @@
object Host "culleoka-router" {
import "mikrotik"
address = "10.254.254.104"
vars.tower = "Culleoka"
}
object Host "culleoka-ubnt-ac1" {
import "ap-ubnt"
address = "10.10.111.1"
vars.tower = "Culleoka"
vars.parents = "10.254.254.104"
}
object Host "culleoka-ubnt-ac2" {
import "ap-ubnt"
address = "10.10.111.2"
vars.tower = "Culleoka"
vars.parents = "10.254.254.104"
}
//object Host "culleoka-ubnt-se" {
// import "ap-ubnt"
// address = "10.10.111.11"
// vars.tower = "Culleoka"
//}
object Host "culleoka-ubnt-sw" {
import "ap-ubnt"
address = "10.10.111.12"
vars.tower = "Culleoka"
vars.parents = "10.254.254.104"
}
object Host "culleoka-n" {
import "ap-ubnt"
address = "10.10.111.14"
vars.tower = "Culleoka"
vars.parents = "10.254.254.104"
}
object Host "culleoka-epmp-n" {
import "ap-epmp"
address = "10.10.111.30"
vars.tower = "Culleoka"
vars.parents = "10.254.254.104"
}
object Host "culleoka-epmp-se" {
import "ap-epmp"
address = "10.10.111.31"
vars.tower = "Culleoka"
vars.parents = "10.254.254.104"
}
object Host "culleoka-epmp-sw" {
import "ap-epmp"
address = "10.10.111.32"
vars.tower = "Culleoka"
vars.parents = "10.254.254.104"
}
object Host "culleoka-epmp-ne" {
import "ap-epmp"
address = "10.10.111.33"
vars.tower = "Culleoka"
vars.parents = "10.254.254.104"
}
//object Host "culleoka-ac-power" {
// import "generic-host"
// address = "100.64.27.252"
// vars.tower = "Culleoka"
// vars.parents = "10.254.254.104"
//}
//object Host "culleoka-climax-af11" {
// import "af11"
// address = "10.250.1.10"
// vars.tower = "Culleoka"
// vars.parents = "10.254.254.104"
//}
//object Host "clayton-ap" {
// import "ap-ubnt"
// address = "10.10.111.50"
// vars.tower = "Culleoka"
//}
object Host "culleoka-clayton-bh" {
import "ap-ubnt"
address = "10.10.111.61"
vars.tower = "Culleoka"
vars.parents = "10.254.254.104"
}

View file

@ -0,0 +1,33 @@
object Host "lowrycrossing-router" {
import "mikrotik"
address = "10.254.254.109"
vars.tower = "Lowry Crossing"
}
object Host "lowrycrossing-omni" {
import "ap-epmp"
address = "10.10.159.10"
vars.tower = "Lowry Crossing"
vars.parents = "10.254.254.109"
}
object Host "lowrycrossing-ne" {
import "ap-epmp"
address = "10.10.159.11"
vars.tower = "Lowry Crossing"
vars.parents = "10.254.254.109"
}
object Host "lowrycrossing-n" {
import "ap-epmp"
address = "10.10.159.10"
vars.tower = "Lowry Crossing"
vars.parents = "10.254.254.109"
}
object Host "lowrycrossing-newhope-af24" {
import "af24"
address = "10.250.1.106"
vars.tower = "Lowry Crossing"
vars.parents = "10.254.254.109"
}

View file

@ -0,0 +1,57 @@
object Host "newhope-router" {
import "mikrotik"
address = "10.254.254.108"
vars.tower = "New Hope"
}
object Host "newhope-se" {
import "ap-epmp"
address = "10.10.143.11"
vars.tower = "New Hope"
vars.parents = "10.254.254.108"
}
object Host "newhope-ne" {
import "ap-epmp"
address = "10.10.143.12"
vars.tower = "New Hope"
vars.parents = "10.254.254.108"
}
object Host "newhope-nw" {
import "ap-epmp"
address = "10.10.143.13"
vars.tower = "New Hope"
vars.parents = "10.254.254.108"
}
object Host "newhope-sw" {
import "ap-epmp"
address = "10.10.143.14"
vars.tower = "New Hope"
vars.parents = "10.254.254.108"
}
//object Host "newhope-edgepoint" {
// import "edgeswitch"
// address = "100.64.19.250"
// vars.tower = "New Hope"
// vars.parents = "10.254.254.108"
//}
//object Host "newhope-edgepoint2" {
// import "edgeswitch"
// address = "100.64.19.251"
// vars.tower = "New Hope"
// vars.parents = "10.254.254.108"
//}
object Host "newhope-core-af11" {
import "af11"
address = "10.250.1.58"
vars.tower = "New Hope"
vars.parents = "10.254.254.108"
}
object Host "newhope-lowrycrossing-af24" {
import "af24"
address = "10.250.1.109"
vars.tower = "New Hope"
vars.parents = "10.254.254.108"
}

View file

@ -0,0 +1,12 @@
//object Host "380power" {
// import "server"
// address = "10.0.0.251"
//}
object Host "t2dallas" {
import "server"
address = "204.110.191.232"
}
object Host "unimus" {
import "server"
address = "204.110.191.238"
}

View file

@ -0,0 +1,42 @@
object Host "verona-router" {
import "mikrotik"
address = "10.254.254.101"
vars.tower = "Verona"
}
//object Host "verona-nw" {
// import "ap-ubnt"
// address = "10.10.15.11"
// vars.tower = "Verona"
// vars.parents = "10.254.254.101"
//}
//object Host "verona-ne" {
// import "ap-ubnt"
// address = "10.10.15.12"
// vars.tower = "Verona"
// vars.parents = "10.254.254.101"
//}
//object Host "verona-s" {
// import "ap-ubnt"
// address = "10.10.15.13"
// vars.tower = "Verona"
// vars.parents = "10.254.254.101"
//}
//object Host "verona-switch" {
// import "netonix"
// address = "100.64.3.250"
// vars.tower = "Verona"
// vars.parents = "10.254.254.101"
//}
object Host "verona-climax-af11" {
import "af11"
address = "10.250.1.26"
vars.tower = "Verona"
vars.parents = "10.254.254.101"
}
//object Host "verona-altoga" {
// import "ap-ubnt"
// address = "10.250.1.146"
// vars.tower = "Verona"
//}

View file

@ -0,0 +1,62 @@
/*
* Host definitions with object attributes
* used for apply rules for Service, Notification,
* Dependency and ScheduledDowntime objects.
*
* Tip: Use `icinga2 object list --type Host` to
* list all host objects after running
* configuration validation (`icinga2 daemon -C`).
*/
/*
* This is an example host based on your
* local host's FQDN. Specify the NodeName
* constant in `constants.conf` or use your
* own description, e.g. "db-host-1".
*/
object Host NodeName {
/* Import the default host template defined in `templates.conf`. */
import "server"
// import "generic-host"
/* Specify the address attributes for checks e.g. `ssh` or `http`. */
address = "127.0.0.1"
address6 = "::1"
vars.pushover_enabled = true
/* Set custom variable `os` for hostgroup assignment in `groups.conf`. */
vars.os = "Linux"
/* Define http vhost attributes for service apply rules in `services.conf`. */
vars.http_vhosts["http"] = {
http_uri = "/"
}
/* Uncomment if you've sucessfully installed Icinga Web 2. */
//vars.http_vhosts["Icinga Web 2"] = {
// http_uri = "/icingaweb2"
//}
/* Define disks and attributes for service apply rules in `services.conf`. */
// vars.disks["disk"] = {
/* No parameters. */
// }
// vars.disks["disk /"] = {
// disk_partitions = "/"
// }
/* Define notification mail attributes for notification apply rules in `notifications.conf`. */
vars.notification["mail"] = {
/* The UserGroup `icingaadmins` is defined in `users.conf`. */
groups = [ "icingaadmins" ]
}
}
/*
apply Dependency “Parent” for (parent in host.vars.parents) to Host {
parent_host_name = parent
assign where host.address && host.vars.parents
}
*/

View file

@ -0,0 +1,33 @@
/**
* The example notification apply rules.
*
* Only applied if host/service objects have
* the custom variable `notification` defined
* and containing `mail` as key.
*
* Check `hosts.conf` for an example.
*/
apply Notification "mail-icingaadmin" to Host {
import "mail-host-notification"
user_groups = host.vars.notification.mail.groups
users = host.vars.notification.mail.users
//interval = 2h
//vars.notification_logtosyslog = true
assign where host.vars.notification.mail
}
apply Notification "mail-icingaadmin" to Service {
import "mail-service-notification"
user_groups = host.vars.notification.mail.groups
users = host.vars.notification.mail.users
//interval = 2h
//vars.notification_logtosyslog = true
assign where host.vars.notification.mail
}

View file

@ -0,0 +1,5 @@
apply Dependency "Parent" for (parent in host.vars.parents) to Host {
parent_host_name = parent
assign where host.address && host.vars.parents
}

View file

@ -0,0 +1,117 @@
/*
* Service apply rules.
*
* The CheckCommand objects `ping4`, `ping6`, etc
* are provided by the plugin check command templates.
* Check the documentation for details.
*
* Tip: Use `icinga2 object list --type Service` to
* list all service objects after running
* configuration validation (`icinga2 daemon -C`).
*/
/*
* This is an example host based on your
* local host's FQDN. Specify the NodeName
* constant in `constants.conf` or use your
* own description, e.g. "db-host-1".
*/
/*
* These are generic `ping4` and `ping6`
* checks applied to all hosts having the
* `address` resp. `address6` attribute
* defined.
*/
apply Service "ping4" {
import "generic-service"
check_command = "ping4"
assign where host.address
}
apply Service "ping6" {
import "generic-service"
check_command = "ping6"
assign where host.address6
}
/*
* Apply the `ssh` service to all hosts
* with the `address` attribute defined and
* the custom variable `os` set to `Linux`.
*/
/*
apply Service "ssh" {
import "generic-service"
check_command = "ssh"
assign where (host.address || host.address6) && host.vars.os == "Linux"
}
*/
apply Service for (http_vhost => config in host.vars.http_vhosts) {
import "generic-service"
check_command = "http"
vars += config
}
apply Service for (disk => config in host.vars.disks) {
import "generic-service"
check_command = "disk"
vars += config
}
apply Service "icinga" {
import "generic-service"
check_command = "icinga"
assign where host.name == NodeName
}
apply Service "load" {
import "generic-service"
check_command = "load"
/* Used by the ScheduledDowntime apply rule in `downtimes.conf`. */
vars.backup_downtime = "02:00-03:00"
assign where host.name == NodeName
}
//apply Service "procs" {
// import "generic-service"
//
// check_command = "procs"
//
// assign where host.name == NodeName
//}
apply Service "swap" {
import "generic-service"
check_command = "swap"
assign where host.name == NodeName
}
apply Service "users" {
import "generic-service"
check_command = "users"
assign where host.name == NodeName
}

View file

@ -0,0 +1,160 @@
/*
* Generic template examples.
*/
/**
* Provides default settings for hosts. By convention
* all hosts should import this template.
*
* The CheckCommand object `hostalive` is provided by
* the plugin check command templates.
* Check the documentation for details.
*/
template Host "generic-host" {
max_check_attempts = 3
check_interval = 1m
retry_interval = 30s
check_command = "hostalive"
vars.enable_pagerduty = true
vars.enable_pagerduty_servers = false
}
template Host "server" {
max_check_attempts = 3
check_interval = 1m
retry_interval = 30s
check_command = "hostalive"
vars.enable_pagerduty = false
vars.enable_pagerduty_servers = true
}
template Host "mikrotik" {
max_check_attempts = 3
check_interval = 1m
retry_interval = 30s
check_command = "hostalive"
vars.enable_pagerduty = true
}
template Host "ap-ubnt" {
max_check_attempts = 3
check_interval = 1m
retry_interval = 30s
check_command = "hostalive"
vars.enable_pagerduty = true
}
template Host "netonix" {
max_check_attempts = 3
check_interval = 1m
retry_interval = 30s
check_command = "hostalive"
vars.enable_pagerduty = true
}
template Host "edgeswitch" {
max_check_attempts = 3
check_interval = 1m
retry_interval = 30s
check_command = "hostalive"
vars.enable_pagerduty = true
}
template Host "ap-epmp" {
max_check_attempts = 3
check_interval = 1m
retry_interval = 30s
check_command = "hostalive"
vars.enable_pagerduty = true
}
template Host "af11" {
max_check_attempts = 3
check_interval = 1m
retry_interval = 30s
check_command = "hostalive"
vars.enable_pagerduty = true
}
template Host "af24" {
max_check_attempts = 3
check_interval = 1m
retry_interval = 30s
check_command = "hostalive"
vars.enable_pagerduty = true
}
/**
* Provides default settings for services. By convention
* all services should import this template.
*/
template Service "generic-service" {
max_check_attempts = 5
check_interval = 1m
retry_interval = 30s
vars.enable_pagerduty = true
}
/**
* Provides default settings for users. By convention
* all users should inherit from this template.
*/
template User "generic-user" {
}
/**
* Provides default settings for host notifications.
* By convention all host notifications should import
* this template.
*/
template Notification "mail-host-notification" {
command = "mail-host-notification"
states = [ Up, Down ]
types = [ Problem, Acknowledgement, Recovery, Custom,
FlappingStart, FlappingEnd,
DowntimeStart, DowntimeEnd, DowntimeRemoved ]
vars += {
// notification_icingaweb2url = "https://www.example.com/icingaweb2"
// notification_from = "Icinga 2 Host Monitoring <icinga@example.com>"
notification_logtosyslog = false
}
period = "24x7"
}
/**
* Provides default settings for service notifications.
* By convention all service notifications should import
* this template.
*/
template Notification "mail-service-notification" {
command = "mail-service-notification"
states = [ OK, Warning, Critical, Unknown ]
types = [ Problem, Acknowledgement, Recovery, Custom,
FlappingStart, FlappingEnd,
DowntimeStart, DowntimeEnd, DowntimeRemoved ]
vars += {
// notification_icingaweb2url = "https://www.example.com/icingaweb2"
// notification_from = "Icinga 2 Service Monitoring <icinga@example.com>"
notification_logtosyslog = false
}
period = "24x7"
}

View file

@ -0,0 +1,35 @@
/**
* Sample timeperiods for Icinga 2.
* Check the documentation for details.
*/
object TimePeriod "24x7" {
display_name = "Icinga 2 24x7 TimePeriod"
ranges = {
"monday" = "00:00-24:00"
"tuesday" = "00:00-24:00"
"wednesday" = "00:00-24:00"
"thursday" = "00:00-24:00"
"friday" = "00:00-24:00"
"saturday" = "00:00-24:00"
"sunday" = "00:00-24:00"
}
}
object TimePeriod "9to5" {
display_name = "Icinga 2 9to5 TimePeriod"
ranges = {
"monday" = "09:00-17:00"
"tuesday" = "09:00-17:00"
"wednesday" = "09:00-17:00"
"thursday" = "09:00-17:00"
"friday" = "09:00-17:00"
}
}
object TimePeriod "never" {
display_name = "Icinga 2 never TimePeriod"
ranges = {
}
}

View file

@ -0,0 +1,23 @@
/**
* The example user 'icingaadmin' and the example
* group 'icingaadmins'.
*/
object User "icingaadmin" {
import "generic-user"
display_name = "Icinga 2 Admin"
groups = [ "icingaadmins" ]
email = "root@localhost"
}
object UserGroup "icingaadmins" {
display_name = "Icinga 2 Admin Group"
}
object User "graham" {
import "generic-user"
display_name = "Graham"
email = "graham@vntx.net"
}

View file

@ -0,0 +1,3 @@
[icingaweb2]
backend = "db"
resource = "icingaweb_db"

View file

@ -0,0 +1,11 @@
[global]
show_stacktraces = "1"
show_application_state_messages = "1"
config_backend = "db"
config_resource = "icingaweb_db"
[logging]
log = "syslog"
level = "ERROR"
application = "icingaweb2"
facility = "user"

View file

@ -0,0 +1,3 @@
[icingaweb2]
backend = "db"
resource = "icingaweb_db"

View file

@ -0,0 +1,3 @@
[icinga]
type = "ido"
resource = "icinga_ido"

View file

@ -0,0 +1,3 @@
[icinga2]
transport = "local"
path = "/var/run/icinga2/cmd/icinga2.cmd"

View file

@ -0,0 +1,2 @@
[security]
protected_customvars = "*pw*,*pass*,community"

View file

@ -0,0 +1,4 @@
[Administrators]
users = "graham"
permissions = "*"
groups = "Administrators"

View file

@ -0,0 +1,21 @@
---
- name: Restart icinga2
ansible.builtin.systemd:
name: icinga2
state: restarted
daemon_reload: true
- name: Reload apache2
ansible.builtin.systemd:
name: apache2
state: reloaded
- name: Restart apache2
ansible.builtin.systemd:
name: apache2
state: restarted
- name: Restart mariadb
ansible.builtin.systemd:
name: mariadb
state: restarted

View file

@ -0,0 +1,267 @@
---
# Builds the Icinga2 master + Icinga Web 2 stack on Ubuntu (matches the
# live install on monitor.vntx.net). Idempotent; safe to re-run.
- name: Assert required vault values
ansible.builtin.assert:
that:
- icinga2_ido_db_password is defined and icinga2_ido_db_password | length > 0
- icingaweb2_db_password is defined and icingaweb2_db_password | length > 0
- icingaweb2_ido_db_password is defined and icingaweb2_ido_db_password | length > 0
- icinga2_api_user_root_password is defined and icinga2_api_user_root_password | length > 0
- icinga2_api_user_icingaweb2_password is defined and icinga2_api_user_icingaweb2_password | length > 0
- icinga2_iftraffic_snmp_community is defined and icinga2_iftraffic_snmp_community | length > 0
fail_msg: >-
Missing one or more required vault variables for the monitor role.
See roles/monitor/README.md for the full list.
# ----------- Repo + packages -----------
- name: Ensure /etc/apt/keyrings exists
ansible.builtin.file:
path: /etc/apt/keyrings
state: directory
mode: "0755"
- name: Add Icinga apt signing key
ansible.builtin.get_url:
url: "{{ icinga2_apt_key_url }}"
dest: "{{ icinga2_apt_keyring }}"
mode: "0644"
force: false
- name: Add Icinga apt repository
ansible.builtin.apt_repository:
repo: "{{ icinga2_apt_repo }}"
filename: icinga
state: present
update_cache: true
- name: Install database stack
ansible.builtin.apt:
name: "{{ icinga2_db_packages }}"
state: present
update_cache: true
- name: Install web stack
ansible.builtin.apt:
name: "{{ icinga2_web_packages }}"
state: present
- name: Install Icinga2 + Icinga Web 2
ansible.builtin.apt:
name: "{{ icinga2_packages }}"
state: present
# ----------- MariaDB -----------
- name: Ensure mariadb is started + enabled
ansible.builtin.systemd:
name: mariadb
state: started
enabled: true
- name: Create IDO database
community.mysql.mysql_db:
name: "{{ icinga2_ido_db_name }}"
state: present
login_unix_socket: /run/mysqld/mysqld.sock
- name: Create IDO daemon DB user (icinga2)
community.mysql.mysql_user:
name: "{{ icinga2_ido_db_user }}"
host: localhost
password: "{{ icinga2_ido_db_password }}"
priv: "{{ icinga2_ido_db_name }}.*:ALL"
state: present
login_unix_socket: /run/mysqld/mysqld.sock
- name: Create read-only IDO user for icingaweb2 (icinga)
community.mysql.mysql_user:
name: "{{ icingaweb2_ido_db_user }}"
host: localhost
password: "{{ icingaweb2_ido_db_password }}"
priv: "{{ icingaweb2_ido_db_name }}.*:SELECT,SHOW VIEW"
state: present
login_unix_socket: /run/mysqld/mysqld.sock
- name: Create icingaweb2 database
community.mysql.mysql_db:
name: "{{ icingaweb2_db_name }}"
state: present
login_unix_socket: /run/mysqld/mysqld.sock
- name: Create icingaweb2 DB user
community.mysql.mysql_user:
name: "{{ icingaweb2_db_user }}"
host: localhost
password: "{{ icingaweb2_db_password }}"
priv: "{{ icingaweb2_db_name }}.*:ALL"
state: present
login_unix_socket: /run/mysqld/mysqld.sock
- name: Check whether IDO schema has been imported
community.mysql.mysql_query:
login_db: "{{ icinga2_ido_db_name }}"
query: "SHOW TABLES LIKE 'icinga_dbversion'"
login_unix_socket: /run/mysqld/mysqld.sock
register: ido_schema_check
changed_when: false
- name: Import IDO schema (first install only)
community.mysql.mysql_db:
name: "{{ icinga2_ido_db_name }}"
state: import
target: "{{ icinga2_ido_schema_path }}"
login_unix_socket: /run/mysqld/mysqld.sock
when: ido_schema_check.rowcount[0] == 0
notify: Restart icinga2
- name: Check whether icingaweb2 schema has been imported
community.mysql.mysql_query:
login_db: "{{ icingaweb2_db_name }}"
query: "SHOW TABLES LIKE 'icingaweb_user'"
login_unix_socket: /run/mysqld/mysqld.sock
register: iweb2_schema_check
changed_when: false
- name: Import icingaweb2 schema (first install only)
community.mysql.mysql_db:
name: "{{ icingaweb2_db_name }}"
state: import
target: /usr/share/icingaweb2/schema/mysql.schema.sql
login_unix_socket: /run/mysqld/mysqld.sock
when: iweb2_schema_check.rowcount[0] == 0
- name: Bootstrap icingaweb2 admin account (first install only)
community.mysql.mysql_query:
login_db: "{{ icingaweb2_db_name }}"
query: >-
INSERT INTO icingaweb_user (name, active, password_hash) VALUES
(%(user)s, 1, %(hash)s)
ON DUPLICATE KEY UPDATE password_hash = VALUES(password_hash)
named_args:
user: "{{ icingaweb2_admin_user }}"
hash: "{{ icingaweb2_admin_password_hash }}"
login_unix_socket: /run/mysqld/mysqld.sock
when:
- iweb2_schema_check.rowcount[0] == 0
- icingaweb2_admin_password_hash is defined
# ----------- Icinga2 daemon config -----------
- name: Render icinga2.conf
ansible.builtin.template:
src: icinga2/icinga2.conf.j2
dest: /etc/icinga2/icinga2.conf
owner: nagios
group: nagios
mode: "0640"
notify: Restart icinga2
- name: Render constants.conf
ansible.builtin.template:
src: icinga2/constants.conf.j2
dest: /etc/icinga2/constants.conf
owner: nagios
group: nagios
mode: "0640"
notify: Restart icinga2
- name: Render zones.conf
ansible.builtin.template:
src: icinga2/zones.conf.j2
dest: /etc/icinga2/zones.conf
owner: nagios
group: nagios
mode: "0640"
notify: Restart icinga2
- name: Render features-available/ido-mysql.conf
ansible.builtin.template:
src: icinga2/features-available/ido-mysql.conf.j2
dest: /etc/icinga2/features-available/ido-mysql.conf
owner: nagios
group: nagios
mode: "0640"
notify: Restart icinga2
- name: Enable Icinga2 features
ansible.builtin.file:
src: "/etc/icinga2/features-available/{{ item }}.conf"
dest: "/etc/icinga2/features-enabled/{{ item }}.conf"
state: link
force: true
loop: "{{ icinga2_enabled_features }}"
notify: Restart icinga2
# ----------- conf.d/ host + service definitions -----------
- name: Sync static conf.d files
ansible.builtin.copy:
src: icinga2/conf.d/
dest: /etc/icinga2/conf.d/
owner: nagios
group: nagios
mode: "0640"
notify: Restart icinga2
- name: Render templated conf.d files (api-users + pagerduty)
ansible.builtin.template:
src: "icinga2/conf.d/{{ item }}.j2"
dest: "/etc/icinga2/conf.d/{{ item }}"
owner: nagios
group: nagios
mode: "0640"
loop:
- api-users.conf
- pagerduty-icinga2.conf
- pagerduty-servers-icinga2.conf
notify: Restart icinga2
# ----------- Icinga Web 2 config -----------
- name: Sync icingaweb2 ini files (non-secret)
ansible.builtin.copy:
src: icingaweb2/
dest: /etc/icingaweb2/
owner: www-data
group: icingaweb2
mode: "0660"
directory_mode: "02770"
notify: Reload apache2
- name: Render icingaweb2 resources.ini (DB credentials)
ansible.builtin.template:
src: icingaweb2/resources.ini.j2
dest: /etc/icingaweb2/resources.ini
owner: www-data
group: icingaweb2
mode: "0660"
notify: Reload apache2
- name: Enable monitoring module
ansible.builtin.file:
src: /usr/share/icingaweb2/modules/monitoring
dest: /etc/icingaweb2/enabledModules/monitoring
state: link
force: true
notify: Reload apache2
# ----------- Apache -----------
- name: Enable apache modules required by icingaweb2
community.general.apache2_module:
name: "{{ item }}"
state: present
loop:
- rewrite
- ssl
notify: Restart apache2
- name: Ensure apache is started + enabled
ansible.builtin.systemd:
name: apache2
state: started
enabled: true
# ----------- Service start -----------
- name: Ensure icinga2 is started + enabled
ansible.builtin.systemd:
name: icinga2
state: started
enabled: true

View file

@ -0,0 +1,11 @@
{{ ansible_managed | comment(decoration='// ') }}
object ApiUser "root" {
password = {{ icinga2_api_user_root_password | to_json }}
permissions = [ "*" ]
}
object ApiUser "icingaweb2" {
password = {{ icinga2_api_user_icingaweb2_password | to_json }}
permissions = [ "status/query", "actions/*", "objects/modify/*", "objects/query/*" ]
}

View file

@ -0,0 +1,91 @@
object User "pagerduty" {
pager = {{ icinga2_pagerduty_key | to_json }}
groups = [ "icingaadmins" ]
display_name = "PagerDuty Notification User"
states = [ OK, Warning, Critical, Unknown, Up, Down ]
types = [ Problem, Acknowledgement, Recovery ]
}
object NotificationCommand "notify-service-by-pagerduty" {
import "plugin-notification-command"
command = [ "/usr/share/pdagent-integrations/bin/pd-nagios" ]
arguments = {
"-n" = {
order = 0
value = "service"
}
"-k" = {
order = 1
value = "$user.pager$"
}
"-t" = {
order = 2
value = "$notification.type$"
}
"-f" = {
order = 3
repeat_key = true
value = "$f_args$"
}
}
vars.f_args = [
"SERVICEDESC=$service.name$",
"SERVICEDISPLAYNAME=$service.display_name$",
"HOSTNAME=$host.name$",
"HOSTSTATE=$host.state$",
"HOSTDISPLAYNAME=$host.display_name$",
"SERVICESTATE=$service.state$",
"SERVICEPROBLEMID=$service.state_id$",
"SERVICEOUTPUT=$service.output$"
]
}
object NotificationCommand "notify-host-by-pagerduty" {
import "plugin-notification-command"
command = [ "/usr/share/pdagent-integrations/bin/pd-nagios" ]
arguments = {
"-n" = {
order = 0
value = "host"
}
"-k" = {
order = 1
value = "$user.pager$"
}
"-t" = {
order = 2
value = "$notification.type$"
}
"-f" = {
order = 3
repeat_key = true
value = "$f_args$"
}
}
vars.f_args = [
"HOSTNAME=$host.name$",
"HOSTSTATE=$host.state$",
"HOSTPROBLEMID=$host.state_id$",
"HOSTOUTPUT=$host.output$"
]
}
apply Notification "pagerduty-service" to Service {
command = "notify-service-by-pagerduty"
states = [ OK, Warning, Critical, Unknown ]
types = [ Problem, Acknowledgement, Recovery ]
period = "24x7"
users = [ "pagerduty" ]
assign where service.vars.enable_pagerduty == true
}
apply Notification "pagerduty-host" to Host {
command = "notify-host-by-pagerduty"
states = [ Up, Down ]
types = [ Problem, Acknowledgement, Recovery ]
period = "24x7"
users = [ "pagerduty" ]
assign where host.vars.enable_pagerduty == true
}

View file

@ -0,0 +1,91 @@
object User "pagerduty-servers" {
pager = {{ icinga2_pagerduty_servers_key | to_json }}
groups = [ "icingaadmins" ]
display_name = "PagerDuty Notification User for Servers"
states = [ OK, Warning, Critical, Unknown, Up, Down ]
types = [ Problem, Acknowledgement, Recovery ]
}
object NotificationCommand "notify-service-by-pagerduty-servers" {
import "plugin-notification-command"
command = [ "/usr/share/pdagent-integrations/bin/pd-nagios" ]
arguments = {
"-n" = {
order = 0
value = "service"
}
"-k" = {
order = 1
value = "$user.pager$"
}
"-t" = {
order = 2
value = "$notification.type$"
}
"-f" = {
order = 3
repeat_key = true
value = "$f_args$"
}
}
vars.f_args = [
"SERVICEDESC=$service.name$",
"SERVICEDISPLAYNAME=$service.display_name$",
"HOSTNAME=$host.name$",
"HOSTSTATE=$host.state$",
"HOSTDISPLAYNAME=$host.display_name$",
"SERVICESTATE=$service.state$",
"SERVICEPROBLEMID=$service.state_id$",
"SERVICEOUTPUT=$service.output$"
]
}
object NotificationCommand "notify-host-by-pagerduty-servers" {
import "plugin-notification-command"
command = [ "/usr/share/pdagent-integrations/bin/pd-nagios" ]
arguments = {
"-n" = {
order = 0
value = "host"
}
"-k" = {
order = 1
value = "$user.pager$"
}
"-t" = {
order = 2
value = "$notification.type$"
}
"-f" = {
order = 3
repeat_key = true
value = "$f_args$"
}
}
vars.f_args = [
"HOSTNAME=$host.name$",
"HOSTSTATE=$host.state$",
"HOSTPROBLEMID=$host.state_id$",
"HOSTOUTPUT=$host.output$"
]
}
apply Notification "pagerduty-service-servers" to Service {
command = "notify-service-by-pagerduty-servers"
states = [ OK, Warning, Critical, Unknown ]
types = [ Problem, Acknowledgement, Recovery ]
period = "24x7"
users = [ "pagerduty-servers" ]
assign where service.vars.enable_pagerduty_servers == true
}
apply Notification "pagerduty-host-servers" to Host {
command = "notify-host-by-pagerduty-servers"
states = [ Up, Down ]
types = [ Problem, Acknowledgement, Recovery ]
period = "24x7"
users = [ "pagerduty-servers" ]
assign where host.vars.enable_pagerduty_servers == true
}

View file

@ -0,0 +1,15 @@
{{ ansible_managed | comment(decoration='// ') }}
//
// Global constants. The TicketSalt and IftrafficSnmpCommunity values come
// from ansible-vault — see roles/monitor/README.md.
const PluginDir = "/usr/lib/nagios/plugins"
const ManubulonPluginDir = "/usr/lib/nagios/plugins"
const PluginContribDir = "/usr/lib/nagios/plugins"
const NodeName = {{ icinga2_node_name | to_json }}
const ZoneName = {{ icinga2_zone_name | to_json }}
const TicketSalt = {{ icinga2_ticket_salt | default("") | to_json }}
const IftrafficSnmpCommunity = {{ icinga2_iftraffic_snmp_community | to_json }}

View file

@ -0,0 +1,10 @@
{{ ansible_managed | comment(decoration=' * ', prefix='/**', postfix=' */') }}
library "db_ido_mysql"
object IdoMysqlConnection "ido-mysql" {
user = {{ icinga2_ido_db_user | to_json }},
password = {{ icinga2_ido_db_password | to_json }},
host = {{ icinga2_ido_db_host | to_json }},
database = {{ icinga2_ido_db_name | to_json }}
}

View file

@ -0,0 +1,23 @@
{{ ansible_managed | comment(decoration=' * ', prefix='/**', postfix=' */') }}
include "constants.conf"
include "zones.conf"
include <itl>
include <plugins>
include <plugins-contrib>
include <manubulon>
include <windows-plugins>
include <nscp>
include "features-enabled/*.conf"
{% if icinga2_load_confd %}
// conf.d/ host + service definitions. Live monitor.vntx.net keeps this
// commented out (the node-setup CLI disabled it during a past distributed
// monitoring rework). Set `icinga2_load_confd: true` in host_vars to
// rehydrate the dormant definitions; default mirrors the live empty state.
include_recursive "conf.d"
{% else %}
// include_recursive "conf.d" // disabled to match live state
{% endif %}

View file

@ -0,0 +1,19 @@
{{ ansible_managed | comment(decoration='// ') }}
//
// Zone topology. This is currently a single-master setup; satellites can be
// added by appending Endpoint+Zone objects here (and a parent= ref).
object Endpoint {{ icinga2_node_name | to_json }} {
}
object Zone {{ icinga2_master_zone_name | to_json }} {
endpoints = [ {{ icinga2_node_name | to_json }} ]
}
object Zone "global-templates" {
global = true
}
object Zone "director-global" {
global = true
}

View file

@ -0,0 +1,19 @@
; {{ ansible_managed }}
[icingaweb_db]
type = "db"
db = "mysql"
host = "{{ icingaweb2_db_host }}"
dbname = "{{ icingaweb2_db_name }}"
username = "{{ icingaweb2_db_user }}"
password = "{{ icingaweb2_db_password }}"
use_ssl = "0"
[icinga_ido]
type = "db"
db = "mysql"
host = "{{ icingaweb2_ido_db_host }}"
dbname = "{{ icingaweb2_ido_db_name }}"
username = "{{ icingaweb2_ido_db_user }}"
password = "{{ icingaweb2_ido_db_password }}"
use_ssl = "0"