diff --git a/playbooks/ns.yml b/playbooks/ns.yml new file mode 100644 index 0000000..e29c441 --- /dev/null +++ b/playbooks/ns.yml @@ -0,0 +1,6 @@ +- name: Configure bind9 name server + hosts: all + tasks: + - name: Configure services to install in the server + import_role: + name: ns \ No newline at end of file diff --git a/playbooks/vpn-ipsec.yml b/playbooks/vpn-ipsec.yml new file mode 100644 index 0000000..aa9b29a --- /dev/null +++ b/playbooks/vpn-ipsec.yml @@ -0,0 +1,6 @@ +- name: Configure IPsec StrongSwan + hosts: all + tasks: + - name: Configure services to install in the server + import_role: + name: ipsec \ No newline at end of file diff --git a/roles/ceph/files/nrpe.cfg b/roles/ceph/files/nrpe.d/95-ceph.cfg similarity index 95% rename from roles/ceph/files/nrpe.cfg rename to roles/ceph/files/nrpe.d/95-ceph.cfg index 76d252f..afc0035 100644 --- a/roles/ceph/files/nrpe.cfg +++ b/roles/ceph/files/nrpe.d/95-ceph.cfg @@ -1,4 +1,4 @@ -command[check_total_procs]=/usr/lib/nagios/plugins/check_procs -w 700 -c 1000 +command[check_total_procs]=/usr/lib/nagios/plugins/check_procs -w 1300 -c 1500 command[check_chrony]=/usr/lib/nagios/plugins/check_chrony 1 2 command[check_smartdisk]=/etc/nagios/plugins/check_smartdisk.sh /dev/sda /dev/sdb command[check_raid]=/usr/lib/nagios/plugins/check_raid diff --git a/roles/ceph/files/plugins/check_ceph_mon b/roles/ceph/files/plugins/check_ceph_mon new file mode 100755 index 0000000..f8decea --- /dev/null +++ b/roles/ceph/files/plugins/check_ceph_mon @@ -0,0 +1,163 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2013 Catalyst IT http://www.catalyst.net.nz +# Copyright (c) 2015 SWITCH http://www.switch.ch +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from __future__ import print_function +import argparse +import socket +import os +import re +import subprocess +import sys +import json + +__version__ = '1.5.0' + +# default ceph values +CEPH_EXEC = '/usr/bin/ceph' +CEPH_COMMAND = 'quorum_status' + +# nagios exit code +STATUS_OK = 0 +STATUS_WARNING = 1 +STATUS_ERROR = 2 +STATUS_UNKNOWN = 3 + +## +# ceph quorum_status output example +## +ceph_quorum_status_output_example = '''{ + "quorum_leader_name" : "s0001", + "monmap" : { + "mons" : [ + { + "name" : "s0001", + "addr" : "[2001:620:5ca1:8000::1001]:6789/0", + "rank" : 0 + }, + { + "name" : "s0003", + "addr" : "[2001:620:5ca1:8000::1003]:6789/0", + "rank" : 1 + } + ], + "created" : "2014-12-15 08:28:35.153650", + "epoch" : 2, + "modified" : "2014-12-15 08:28:40.371878", + "fsid" : "22348d2b-b69d-46cc-9a79-ca93cd6bae84" + }, + "quorum_names" : [ + "s0001", + "s0003" + ], + "quorum" : [ + 0, + 1 + ], + "election_epoch" : 24 +}''' + +def main(): + + # parse args + parser = argparse.ArgumentParser(description="'ceph quorum_status' nagios plugin.") + parser.add_argument('-e','--exe', help='ceph executable [%s]' % CEPH_EXEC) + parser.add_argument('-c','--conf', help='alternative ceph conf file') + parser.add_argument('-m','--monaddress', help='ceph monitor to use for queries (address[:port])') + parser.add_argument('-i','--id', help='ceph client id') + parser.add_argument('-k','--keyring', help='ceph client keyring file') + parser.add_argument('-V','--version', help='show version and exit', action='store_true') + parser.add_argument('-I','--monid', help='mon ID to be checked for availability') + args = parser.parse_args() + + if args.version: + print('version %s' % __version__) + return STATUS_OK + + # validate args + ceph_exec = args.exe if args.exe else CEPH_EXEC + if not os.path.exists(ceph_exec): + print("MON ERROR: ceph executable '%s' doesn't exist" % ceph_exec) + return STATUS_UNKNOWN + + if args.conf and not os.path.exists(args.conf): + print("MON ERROR: ceph conf file '%s' doesn't exist" % args.conf) + return STATUS_UNKNOWN + + if args.keyring and not os.path.exists(args.keyring): + print("MON ERROR: keyring file '%s' doesn't exist" % args.keyring) + return STATUS_UNKNOWN + + if not args.monid: + print("MON ERROR: no MON ID given, use -I/--monid parameter") + return STATUS_UNKNOWN + + # build command + ceph_cmd = [ceph_exec] + if args.monaddress: + ceph_cmd.append('-m') + ceph_cmd.append(args.monaddress) + if args.conf: + ceph_cmd.append('-c') + ceph_cmd.append(args.conf) + if args.id: + ceph_cmd.append('--id') + ceph_cmd.append(args.id) + if args.keyring: + ceph_cmd.append('--keyring') + ceph_cmd.append(args.keyring) + ceph_cmd.append(CEPH_COMMAND) + + # exec command + p = subprocess.Popen(ceph_cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE) + output, err = p.communicate() + + if p.returncode != 0 or not output: + print("MON ERROR: %s" % err) + return STATUS_ERROR + + # load json output and parse + quorum_status = False + try: + quorum_status = json.loads(output) + except Exception as e: + print("MON ERROR: could not parse '%s' output: %s: %s" % (CEPH_COMMAND,output,e)) + return STATUS_UNKNOWN + + #print "XXX: quorum_status['quorum_names']:", quorum_status['quorum_names'] + + # do our checks + is_monitor = False + for mon in quorum_status['monmap']['mons']: + if mon['name'] == args.monid: + is_monitor = True + if not is_monitor: + print("MON WARN: mon '%s' is not in monmap: %s" % (args.monid,quorum_status['monmap']['mons'])) + return STATUS_WARNING + + in_quorum = args.monid in quorum_status['quorum_names'] + if in_quorum: + print("MON OK") + return STATUS_OK + else: + print("MON WARN: no MON '%s' found in quorum" % args.monid) + return STATUS_WARNING + +# main +if __name__ == "__main__": + sys.exit(main()) diff --git a/roles/ceph/files/plugins/check_ceph_osd b/roles/ceph/files/plugins/check_ceph_osd new file mode 100755 index 0000000..2ee9de6 --- /dev/null +++ b/roles/ceph/files/plugins/check_ceph_osd @@ -0,0 +1,154 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2013 Catalyst IT http://www.catalyst.net.nz +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# 1.5.2 (2019-06-16) Martin Seener: fixed regex to work with Ceph Nautilus (14.2.x) + +from __future__ import print_function +import argparse +import os +import re +import subprocess +import sys +import socket + +__version__ = '1.5.2' + +# default ceph values +CEPH_COMMAND = '/usr/bin/ceph' + +# nagios exit code +STATUS_OK = 0 +STATUS_WARNING = 1 +STATUS_ERROR = 2 +STATUS_UNKNOWN = 3 + +def main(): + + # parse args + parser = argparse.ArgumentParser(description="'ceph osd' nagios plugin.") + parser.add_argument('-e','--exe', help='ceph executable [%s]' % CEPH_COMMAND) + parser.add_argument('-c','--conf', help='alternative ceph conf file') + parser.add_argument('-m','--monaddress', help='ceph monitor address[:port]') + parser.add_argument('-i','--id', help='ceph client id') + parser.add_argument('-k','--keyring', help='ceph client keyring file') + parser.add_argument('-V','--version', help='show version and exit', action='store_true') + parser.add_argument('-H','--host', help='osd host', required=True) + parser.add_argument('-I','--osdid', help='osd id', required=False) + parser.add_argument('-C','--crit', help='Number of failed OSDs to trigger critical (default=2)',type=int,default=2, required=False) + parser.add_argument('-o','--out', help='check osds that are set OUT', default=False, action='store_true', required=False) + args = parser.parse_args() + + # validate args + ceph_exec = args.exe if args.exe else CEPH_COMMAND + if not os.path.exists(ceph_exec): + print("OSD ERROR: ceph executable '%s' doesn't exist" % ceph_exec) + return STATUS_UNKNOWN + + if args.version: + print('version %s' % __version__) + return STATUS_OK + + if args.conf and not os.path.exists(args.conf): + print("OSD ERROR: ceph conf file '%s' doesn't exist" % args.conf) + return STATUS_UNKNOWN + + if args.keyring and not os.path.exists(args.keyring): + print("OSD ERROR: keyring file '%s' doesn't exist" % args.keyring) + return STATUS_UNKNOWN + + if not args.osdid: + args.osdid = '[^ ]*' + + if not args.host: + print("OSD ERROR: no OSD hostname given") + return STATUS_UNKNOWN + + try: + addrinfo = socket.getaddrinfo(args.host, None, 0, socket.SOCK_STREAM) + args.host = addrinfo[0][-1][0] + if addrinfo[0][0] == socket.AF_INET6: + args.host = "[%s]" % args.host + except: + print('OSD ERROR: could not resolve %s' % args.host) + return STATUS_UNKNOWN + + + # build command + ceph_cmd = [ceph_exec] + if args.monaddress: + ceph_cmd.append('-m') + ceph_cmd.append(args.monaddress) + if args.conf: + ceph_cmd.append('-c') + ceph_cmd.append(args.conf) + if args.id: + ceph_cmd.append('--id') + ceph_cmd.append(args.id) + if args.keyring: + ceph_cmd.append('--keyring') + ceph_cmd.append(args.keyring) + ceph_cmd.append('osd') + ceph_cmd.append('dump') + + # exec command + p = subprocess.Popen(ceph_cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE) + output, err = p.communicate() + output = output.decode('utf8') + + if err or not output: + print("OSD ERROR: %s" % err) + return STATUS_ERROR + + # escape IPv4 host address + osd_host = args.host.replace('.', '\.') + # escape IPv6 host address + osd_host = osd_host.replace('[', '\[') + osd_host = osd_host.replace(']', '\]') + up = re.findall(r"^(osd\.%s) up.*%s:" % (args.osdid, osd_host), output, re.MULTILINE) + if args.out: + down = re.findall(r"^(osd\.%s) down.*%s:" % (args.osdid, osd_host), output, re.MULTILINE) + down_in = re.findall(r"^(osd\.%s) down[ ]+in.*%s:" % (args.osdid, osd_host), output, re.MULTILINE) + down_out = re.findall(r"^(osd\.%s) down[ ]+out.*%s:" % (args.osdid, osd_host), output, re.MULTILINE) + else: + down = re.findall(r"^(osd\.%s) down[ ]+in.*%s:" % (args.osdid, osd_host), output, re.MULTILINE) + down_in = down + down_out = re.findall(r"^(osd\.%s) down[ ]+out.*%s:" % (args.osdid, osd_host), output, re.MULTILINE) + + if down: + print("OSD %s: Down OSD%s on %s: %s" % ('CRITICAL' if len(down)>=args.crit else 'WARNING' ,'s' if len(down)>1 else '', args.host, " ".join(down))) + print("Up OSDs: " + " ".join(up)) + print("Down+In OSDs: " + " ".join(down_in)) + print("Down+Out OSDs: " + " ".join(down_out)) + print("| 'osd_up'=%d 'osd_down_in'=%d;;%d 'osd_down_out'=%d;;%d" % (len(up), len(down_in), args.crit, len(down_out), args.crit)) + if len(down)>=args.crit: + return STATUS_ERROR + else: + return STATUS_WARNING + + if up: + print("OSD OK") + print("Up OSDs: " + " ".join(up)) + print("Down+In OSDs: " + " ".join(down_in)) + print("Down+Out OSDs: " + " ".join(down_out)) + print("| 'osd_up'=%d 'osd_down_in'=%d;;%d 'osd_down_out'=%d;;%d" % (len(up), len(down_in), args.crit, len(down_out), args.crit)) + return STATUS_OK + + print("OSD WARN: no OSD.%s found on host %s" % (args.osdid, args.host)) + return STATUS_WARNING + +if __name__ == "__main__": + sys.exit(main()) diff --git a/roles/ceph/files/plugins/check_chrony b/roles/ceph/files/plugins/check_chrony new file mode 100755 index 0000000..1d220f4 --- /dev/null +++ b/roles/ceph/files/plugins/check_chrony @@ -0,0 +1,128 @@ +#!/usr/bin/env perl +#=============================================================================== +# DESCRIPTION: Icinga2 / Nagios Check for chrony time sync status and offset +# +# OPTIONS: -h : Help +# -w [warning threshold in seconds] +# -c [critical threshold in seconds] +# +# REQUIREMENTS: Chrony, perl version 5.10.1+ +# +# AUTHOR: Dennis Ullrich (request@decstasy.de) +# +# BUGS ETC: https://github.com/Decstasy/check_chrony +# +# LICENSE: GPL v3 (GNU General Public License, Version 3) +# see https://www.gnu.org/licenses/gpl-3.0.txt +#=============================================================================== + +use 5.10.1; +use strict; +use warnings; +use utf8; +use Getopt::Std; + +# +# Variables +# +my $chronyDaemonName = "chronyd"; +my $leapOk = "Normal"; + +my $rc = 3; +my $msg= ""; +my $perfdata = ""; + +# +# Subroutines +# + +sub help { + print "check_chrony [options] + -w [warning threshold in seconds] + -c [critical threshold in seconds] + e.g.: check_chrony -w 0.6 -c 2\n"; + exit(3); +} + +# Script exit with Nagios / Icinga typical output +sub _exit { + my ( $return, $line ) = @_; + my @state = ( "OK", "WARNING", "CRITICAL", "UNKNOWN" ); + print "$state[$return]: $line\n"; + exit( $return ); +} + +# Checks if a process with $_[0] as name exists +sub proc_exists { + my $PID = `ps -C $_[0] -o pid=`; + if ( ${^CHILD_ERROR_NATIVE} == 0 ){ + return 1; + } + return 0; +} + +# +# Options +# + +my %options=(); +getopts( "hw:c:", \%options ); + +# Check input +if ( keys %options == 0 || defined $options{h} ){ + &help; +} + +for my $key ( keys %options ){ + if ( $options{$key} !~ /^[\d\.]+$/ ){ + &_exit( 3, "Value of option -$key is not a valid number!" ); + } +} + +# +# Check chrony process +# + +&_exit( 2, "$chronyDaemonName is not running!" ) if not &proc_exists( $chronyDaemonName ); + +# +# Get tracking data +# + +my $chronyOutput = `chronyc tracking`; +&_exit( 3, "Chronyc tracking command failed!" ) if ${^CHILD_ERROR_NATIVE} != 0; + +my ( $offset, $dir ) = $chronyOutput =~ /(?:System\stime)[^\d]+([\d\.]+)(?:.*?)(fast|slow)/; +my ( $leap ) = $chronyOutput =~ /(?:Leap)[^\:]+(?::\s+)([\w\h]+)/; + +# +# Check stuff +# + +# Check offset +if ( $offset >= $options{"c"} ){ + $rc = 2; # Critical +} +elsif ( $offset >= $options{"w"} ){ + $rc = 1; # Warning +} +else { + $rc = 0; # Ok +} + +# Prepare offset performace data +$offset = $dir =~ "slow" ? "-$offset" : "+$offset"; +$msg = sprintf( "Time offset of %+.9f seconds to reference.", $offset); +$perfdata = sprintf( "|offset=%.9fs;%.9f;%.9f", ${offset}, $options{'w'}, $options{'c'}); + +# Check leap +if( $leap !~ $leapOk ){ + &_exit( 2, "Chrony leap status \"$leap\" is not equal to \"$leapOk\"! $msg $perfdata" ); +} + +# +# Return stuff +# + +&_exit($rc, "$msg $perfdata"); + diff --git a/roles/pve/files/nrpe/check_smartdisk.sh b/roles/ceph/files/plugins/check_smartdisk.sh similarity index 100% rename from roles/pve/files/nrpe/check_smartdisk.sh rename to roles/ceph/files/plugins/check_smartdisk.sh diff --git a/roles/ceph/files/sudoers b/roles/ceph/files/sudoers new file mode 100644 index 0000000..5e2f0cd --- /dev/null +++ b/roles/ceph/files/sudoers @@ -0,0 +1 @@ +nagios ALL=(root) NOPASSWD: /usr/sbin/smartctl,/sbin/dmsetup \ No newline at end of file diff --git a/roles/ceph/tasks/main.yml b/roles/ceph/tasks/main.yml index c1af77e..f334f87 100644 --- a/roles/ceph/tasks/main.yml +++ b/roles/ceph/tasks/main.yml @@ -1,8 +1,2 @@ -- name: Set NRPE Ceph configuration - copy: - src: nrpe.cfg - dest: /etc/nagios/nrpe.d/95-ceph.cfg - owner: root - group: root - mode: u=rw,g=r,o=r - notify: restart-nrpe +- import_tasks: nrpe.yml + tags: nrpe diff --git a/roles/ceph/tasks/nrpe.yml b/roles/ceph/tasks/nrpe.yml new file mode 100644 index 0000000..2b87bbe --- /dev/null +++ b/roles/ceph/tasks/nrpe.yml @@ -0,0 +1,24 @@ +- name: Set NRPE Ceph configuration + copy: + src: nrpe.d/95-ceph.cfg + dest: /etc/nagios/nrpe.d/ + owner: root + group: root + mode: u=rw,g=r,o=r + notify: restart-nrpe +- name: Copy Ceph NRPE plugins + copy: + src: plugins/ + dest: /etc/nagios/plugins/ + owner: root + group: root + mode: u=rwx,g=rx,o=rx + notify: restart-nrpe +- name: Add nagios to sudoers + copy: + src: sudoers + dest: /etc/sudoers.d/nagios + mode: u=rw,g=r,o= + owner: root + group: root + notify: restart-nrpe diff --git a/roles/db/defaults/main.yaml b/roles/db/defaults/main.yaml index b1818b7..6820f53 100644 --- a/roles/db/defaults/main.yaml +++ b/roles/db/defaults/main.yaml @@ -22,17 +22,20 @@ required_directories: - { path: /etc/systemd/system/mariadb.service.d, owner: root, group: root, mode: 'u=rwx,g=rx,o=rx' } required_mariabackup_files_and_scripts: - { src: mysql-flush.sh, dest: /etc/qemu/fsfreeze-hook.d/mysql-flush.sh, mode: u=rwx,g=rx,o=rx } - - { src: mariabackup/bacula-before.sh, dest: /root/mariabackup/bacula-before.sh, mode: u=rwx,g=rx,o=rx } + - { src: mariabackup/make-backup.sh, dest: /root/mariabackup/make-backup.sh, mode: u=rwx,g=rx,o=rx } - { src: mariabackup/config.sh, dest: /root/mariabackup/config.sh, mode: u=rwx,g=rx,o=x } - - { src: mariabackup/inc-backup.sh, dest: /root/mariabackup/inc-backup.sh, mode: u=rwx,g=rx,o=rx } - { src: mariabackup/restore-backup.sh, dest: /root/mariabackup/restore-backup.sh, mode: u=rwx,g=rx,o=rx } - { src: scripts/check-memory.sh, dest: /root/scripts/check-memory.sh, mode: u=rwx,g=rx,o=rx } - { src: scripts/export-privs.sh, dest: /root/scripts/export-privs.sh, mode: u=rwx,g=rx,o=rx } - { src: scripts/mysqltuner.pl, dest: /root/scripts/mysqltuner.pl, mode: u=rwx,g=rx,o=rx } - - { src: scripts/events-promote.sh, dest: /root/scripts/events-promote.sh, mode: u=rwx,g=rx,o=rx } - - { src: scripts/events-demote.sh, dest: /root/scripts/events-demote.sh, mode: u=rwx,g=rx,o=rx } + - { src: scripts/role-change.sh, dest: /root/scripts/role-change.sh, mode: u=rwx,g=rx,o=rx } - { src: scripts/README.md, dest: /root/scripts/README.md, mode: u=rw,g=r,o=r } - { src: scripts/scheduler-log.sh, dest: /root/scripts/scheduler-log.sh, mode: u=rwx,g=rx,o=rx } +configuration_files: + - { src: "conf/z99-local.cnf", dest: "/etc/mysql/mariadb.conf.d/z99-local.cnf", owner: "root", group: "root", mode: "u=rw,g=r,o=r" } + - { src: "mariabackup/my.cnf", dest: "/root/mariabackup/my.cnf", owner: "root", group: "root", mode: "u=rw,g=,o=" } + - { src: "pmm-agent.yaml", dest: "/usr/local/percona/pmm2/config/pmm-agent.yaml", owner: "pmm-agent", group: "pmm-agent", mode: "u=rw,g=rw,o=" } + - { src: "check-memory.cron", dest: "/etc/cron.d/vn-check-memory", owner: "root", group: "root", mode: "u=rw,g=r,o=r" } downloads: - url: https://r.mariadb.com/downloads/mariadb_repo_setup dest: /tmp/mariadb_repo_setup @@ -40,3 +43,10 @@ downloads: - url: https://repo.percona.com/apt/percona-release_latest.generic_all.deb dest: /tmp/percona-release_latest.generic_all.deb mode: u=rw,g=r,o=r +clean_config_and_scripts: + - /root/scripts/events-promote.sh + - /root/scripts/events-demote.sh + - /root/scripts/promote-master.sh + - /root/scripts/promote-slave.sh + - /root/scripts/inc-backup.sh + - /root/scripts/bacula-before.sh \ No newline at end of file diff --git a/roles/db/files/conf/z90-vn.cnf b/roles/db/files/conf/z90-vn.cnf index 1911135..c7db964 100644 --- a/roles/db/files/conf/z90-vn.cnf +++ b/roles/db/files/conf/z90-vn.cnf @@ -30,7 +30,7 @@ interactive_timeout = 1800 wait_timeout = 1800 open_files_limit = 20000 low_priority_updates = 1 -table_open_cache = 40000 +table_open_cache = 50000 table_definition_cache = 10000 table_open_cache_instances = 1 key_buffer_size = 256K diff --git a/roles/db/files/mariabackup/bacula-after.sh b/roles/db/files/mariabackup/bacula-after.sh index 6857ed7..32bb6b9 100755 --- a/roles/db/files/mariabackup/bacula-after.sh +++ b/roles/db/files/mariabackup/bacula-after.sh @@ -5,12 +5,12 @@ myDir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" . "$myDir/config.sh" . "$myDir/apply.config.sh" -pattern="$baculaDir/mnt/local-backup/*_full.gz" +pattern="$backupDir/*_full.gz" files=($pattern) backupFile="${files[0]}" "$myDir/restore-backup.sh" "$backupFile" -rm -r "$baculaDir" +rm -r "$backupDir/"* if [[ "${#dbClusterSiblings[@]}" -gt "0" ]]; then for node in "${dbClusterSiblings[@]}"; do @@ -46,7 +46,7 @@ fi echo "Promoting Events." -"/root/scripts/events-promote.sh" +/root/scripts/role-change.sh --promote for node in "${dbClusterSiblings[@]}"; do ssh root@$node service mysql start diff --git a/roles/db/files/mariabackup/bacula-before.sh b/roles/db/files/mariabackup/bacula-before.sh deleted file mode 100644 index f4723a3..0000000 --- a/roles/db/files/mariabackup/bacula-before.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -# https://mariadb.com/kb/en/mariabackup/ -set -e - -myDir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -. "$myDir/config.sh" - -todayDir="$(date +%Y-%m-%d)" -backupName="${todayDir}_$(date +"%H-%M")_full" -backupFile="$backupDir/$backupName.gz" - -if [ -d "$backupDir" ]; then - rm -rf "$backupDir/"* -fi - -ulimit -n 8192 -mariabackup \ - --defaults-extra-file="$myDir/my.cnf" \ - --backup \ - --extra-lsndir="$backupDir/$backupName" \ - --history="$todayDir" \ - --stream=xbstream \ - --parallel=4 \ - 2>> "$logFile" \ - | pigz -p 12 \ - > "$backupFile" - -if [ $? != "0" ]; then - echo "An error ocurred during backup, please take a look at log file: $logFile" - exit 1 -fi diff --git a/roles/db/files/mariabackup/config.sh b/roles/db/files/mariabackup/config.sh index bb61fd8..3aacc00 100644 --- a/roles/db/files/mariabackup/config.sh +++ b/roles/db/files/mariabackup/config.sh @@ -18,3 +18,5 @@ restoreDir=/mnt/mysqldata/mysql-restore # Directory of MySQL data dataDir=/mnt/mysqldata/mysql +# Number of procs created by pigz +pigzProcs=12 diff --git a/roles/db/files/mariabackup/inc-backup.sh b/roles/db/files/mariabackup/inc-backup.sh deleted file mode 100644 index c6d6e91..0000000 --- a/roles/db/files/mariabackup/inc-backup.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash -# https://mariadb.com/kb/en/incremental-backup-and-restore-with-mariabackup/ -set -e - -myDir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -. "$myDir/config.sh" - -todayDir="$(date +%Y-%m-%d)" -todayPath="$historyDir/$todayDir" - -pattern="$todayPath/${todayDir}_??-??_full.xb.gz.enc" -files=($pattern) -backupFile="${files[0]}" -backupBase=$(basename -- "$backupFile") -backupName="${backupBase%%.*}" - -incrementalName="${todayDir}_$(date +"%H-%M")_incremental" -incrementalFile="$backupDir/${incrementalName}.xb.gz.enc" - -ulimit -n 24098 -mariabackup \ - --defaults-extra-file="$myDir/my.cnf" \ - --backup \ - --incremental-basedir="$backupDir/$backupName" \ - --extra-lsndir="$backupDir/$incrementalName" \ - --incremental-history-name="$todayDir" \ - 2>> "$logFile" \ - | gzip \ - | openssl enc -aes-256-cbc -pbkdf2 -kfile "$myDir/xbcrypt.key" \ - > "$incrementalFile" - -if [ $? != "0" ]; then - echo "An error ocurred during backup, please take a look at log file: $logFile" - exit 1 -fi - -cp "$incrementalFile" "$todayPath" -cp -r "$backupDir/$incrementalName" "$todayPath" diff --git a/roles/db/files/mariabackup/make-backup.sh b/roles/db/files/mariabackup/make-backup.sh new file mode 100644 index 0000000..41d4c37 --- /dev/null +++ b/roles/db/files/mariabackup/make-backup.sh @@ -0,0 +1,120 @@ +#!/bin/bash +# +# Author: Juan Ferrer +# Copyright (c) 2025 Verdnatura S.L. All rights reserved. +# Version: 0.0.2 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Backups the MariaDB database, it supports three modes: +# - Full: Full backup of all DB data, deletes all previous backups. +# - Differential: Backup changes since the last full backup, deletes all +# previous differential backups. +# - Incremental: Backup changes since the last full backup, same as +# differential, but does not erase any previous backups. +# +# References: +# - https://mariadb.com/kb/en/mariabackup/ +# - https://mariadb.com/kb/en/mariabackup-options/ +# - https://mariadb.com/kb/en/incremental-backup-and-restore-with-mariabackup/ +# - https://mariadb.com/kb/en/setting-up-a-replica-with-mariabackup/ +# +set -e + +myDir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +. "$myDir/config.sh" + +level=$1 +historyName=$2 +curDate="$(date +%Y-%m-%d)" + +usage() { + echo "Usage: $0 [historyName]" + exit 1 +} +backup_error() { + echo "An error ocurred during backup, please take a look at log file: $logFile" + exit 2 +} + +if [ -z "$level" ]; then + usage +fi + +case "$level" in + Full) + backupName="${curDate}_$(date +"%H-%M")_full" + backupFile="$backupDir/$backupName.gz" + + if [ -d "$backupDir" ]; then + rm -rf "$backupDir/"* + fi + if [ -z "$historyName" ]; then + historyName=$backupName + fi + + ulimit -n 8192 + mariabackup \ + --defaults-extra-file="$myDir/my.cnf" \ + --backup \ + --history="$historyName" \ + --extra-lsndir="$backupDir/$backupName" \ + --slave-info \ + --safe-slave-backup \ + 2>> "$logFile" \ + | pigz -p "$pigzProcs" \ + > "$backupFile" + + if [ $? != "0" ]; then + backup_error + fi + ;; + Differential|Incremental) + pattern="$backupDir/${curDate}_??-??_full.gz" + files=($pattern) + backupFile="${files[0]}" + backupBase=$(basename -- "$backupFile") + backupName="${backupBase%%.*}" + + incrementalName="${backupName%%_full}_diff_$(date +"%H-%M")" + incrementalFile="$backupDir/${incrementalName}.gz" + + if [ "$level" = "Differential" ]; then + rm -rf "$backupDir/${curDate}_"??-??_diff_??-??{,.gz} + fi + if [ -z "$historyName" ]; then + historyName=$incrementalName + fi + + ulimit -n 24098 + mariabackup \ + --defaults-extra-file="$myDir/my.cnf" \ + --backup \ + --history="$historyName" \ + --extra-lsndir="$backupDir/$incrementalName" \ + --incremental-basedir="$backupDir/$backupName" \ + --slave-info \ + --safe-slave-backup \ + 2>> "$logFile" \ + | pigz -p "$pigzProcs" \ + > "$incrementalFile" + + if [ $? != "0" ]; then + backup_error + fi + ;; + *) + usage + ;; +esac diff --git a/roles/db/files/mariabackup/restore-backup.sh b/roles/db/files/mariabackup/restore-backup.sh index 73d06e2..ecf2fd7 100644 --- a/roles/db/files/mariabackup/restore-backup.sh +++ b/roles/db/files/mariabackup/restore-backup.sh @@ -28,7 +28,7 @@ mkdir -p "$restoreDir" echo "$(formatted_date)" echo "Decompresing backup." pigz --decompress --processes 4 --stdout "$backupFile" \ - | mbstream --extract --parallel=4 --directory="$restoreDir" + | mbstream --extract --parallel=6 --directory="$restoreDir" echo "Preparing backup." mariabackup \ diff --git a/roles/db/files/nrpe/95-mariadb.cfg b/roles/db/files/nrpe/95-mariadb.cfg index a918213..5e28bf2 100644 --- a/roles/db/files/nrpe/95-mariadb.cfg +++ b/roles/db/files/nrpe/95-mariadb.cfg @@ -3,4 +3,3 @@ command[check_disk_mysqlbin]=/usr/lib/nagios/plugins/check_disk -w 10% -c 5% -p command[check_disk_backup]=/usr/lib/nagios/plugins/check_disk -w 10% -c 5% -p /mnt/local-backup command[check_mysql_scheduler]=/etc/nagios/plugins/check_mysql_scheduler command[check_total_procs]=/usr/lib/nagios/plugins/check_procs -w 600 -c 700 - diff --git a/roles/db/files/scripts/events-demote.sh b/roles/db/files/scripts/events-demote.sh deleted file mode 100755 index 4856f4f..0000000 --- a/roles/db/files/scripts/events-demote.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -mysql -e "SET GLOBAL event_scheduler = OFF" - -echo "SELECT db, name FROM mysql.event WHERE status = 'ENABLED'" | mysql --raw --silent | \ -awk '{ - gsub("`", "``", $1); - gsub("`", "``", $2); - print "`"$1"`.`"$2"`"; -}' | \ -while read event; do - mysql -e "ALTER EVENT $event DISABLE ON SLAVE" -done - -mysql -e "SET GLOBAL event_scheduler = ON" - diff --git a/roles/db/files/scripts/events-promote.sh b/roles/db/files/scripts/events-promote.sh deleted file mode 100755 index d4b5b9f..0000000 --- a/roles/db/files/scripts/events-promote.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -mysql -e "SET GLOBAL event_scheduler = OFF" - -echo "SELECT db, name FROM mysql.event WHERE status = 'SLAVESIDE_DISABLED'" | mysql --raw --silent | \ -awk '{ - gsub("`", "``", $1); - gsub("`", "``", $2); - print "`"$1"`.`"$2"`"; -}' | \ -while read event; do - mysql -e "ALTER EVENT $event ENABLE" -done - -mysql -e "SET GLOBAL event_scheduler = ON" diff --git a/roles/db/files/scripts/role-change.sh b/roles/db/files/scripts/role-change.sh new file mode 100644 index 0000000..1ba3e0b --- /dev/null +++ b/roles/db/files/scripts/role-change.sh @@ -0,0 +1,123 @@ +#!/bin/bash +# Script to manage MariaDB events during replication role changes. +# +# Author: Xavi Lleó & GhatGPT ® +# Copyright (c) 2025 Verdnatura S.L. All rights reserved. +# Version: 1.4.0 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Description: +# This script toggles MariaDB events during replication role changes. +# It supports three modes: +# --promote : Re-enable events previously marked SLAVESIDE_DISABLED +# --demote : Disable currently ENABLED events using DISABLE ON SLAVE +# --status : Display current status of all events +# All actions are logged to /var/log/mariadb_admin.log. + +set -euo pipefail + +LOG_FILE="/var/log/mariadb_admin.log" +TIMESTAMP="$(date '+%F %T')" + +log() { + echo "$TIMESTAMP - $1" | tee -a "$LOG_FILE" +} + +disable_scheduler() { + log "Disabling event_scheduler..." + if mysql -e "SET GLOBAL event_scheduler = OFF"; then + log "Successfully disabled event_scheduler" + else + log "ERROR: Failed to disable event_scheduler" + exit 1 + fi +} + +enable_scheduler() { + log "Re-enabling event_scheduler..." + if mysql -e "SET GLOBAL event_scheduler = ON"; then + log "Successfully re-enabled event_scheduler" + else + log "ERROR: Failed to re-enable event_scheduler" + exit 1 + fi +} + +final_status() { + log "Final event_scheduler status:" + mysql --table -e "SHOW VARIABLES LIKE 'event_scheduler';" | tee -a "$LOG_FILE" + + log "Final state of all events:" + mysql --table -e "SELECT db, name, status FROM mysql.event;" | tee -a "$LOG_FILE" +} + +if [[ $# -ne 1 ]]; then + echo "Usage: $0 --promote | --demote | --status" + exit 1 +fi + +MODE="$1" + +case "$MODE" in + --status) + log "Fetching current event_scheduler status:" + mysql --table -e "SHOW VARIABLES LIKE 'event_scheduler';" | tee -a "$LOG_FILE" + + log "Fetching current event status:" + mysql --table -e "SELECT db, name, status FROM mysql.event;" | tee -a "$LOG_FILE" + ;; + + --promote) + disable_scheduler + + log "Promoting: Enabling events with SLAVESIDE_DISABLED status..." + mysql --raw --silent -e "SELECT db, name FROM mysql.event WHERE status = 'SLAVESIDE_DISABLED'" | \ + awk '{ gsub("`", "``", $1); gsub("`", "``", $2); print "`"$1"`.`"$2"`" }' | \ + while read -r event; do + if mysql -e "ALTER EVENT $event ENABLE"; then + log "Enabled event: $event" + else + log "ERROR: Failed to enable event: $event" + fi + done + + enable_scheduler + final_status + ;; + + --demote) + disable_scheduler + + log "Demoting: Disabling events currently ENABLED..." + mysql --raw --silent -e "SELECT db, name FROM mysql.event WHERE status = 'ENABLED'" | \ + awk '{ gsub("`", "``", $1); gsub("`", "``", $2); print "`"$1"`.`"$2"`" }' | \ + while read -r event; do + if mysql -e "ALTER EVENT $event DISABLE ON SLAVE"; then + log "Disabled event: $event" + else + log "ERROR: Failed to disable event: $event" + fi + done + + enable_scheduler + final_status + ;; + + *) + echo "Invalid mode: $MODE" + echo "Usage: $0 --promote | --demote | --status" + exit 1 + ;; +esac diff --git a/roles/db/handlers/main.yml b/roles/db/handlers/main.yml index 320b475..11143ee 100644 --- a/roles/db/handlers/main.yml +++ b/roles/db/handlers/main.yml @@ -9,3 +9,7 @@ service: name: nagios-nrpe-server state: restarted +- name: restart-percona + service: + name: pmm-agent.service + state: restarted diff --git a/roles/db/tasks/mariadb.yml b/roles/db/tasks/mariadb.yml index 21d4a57..b7fe120 100644 --- a/roles/db/tasks/mariadb.yml +++ b/roles/db/tasks/mariadb.yml @@ -3,35 +3,29 @@ name: "{{ mariadb_requeriments }}" state: present install_recommends: no - - name: Download required setup files get_url: url: "{{ item.url }}" dest: "{{ item.dest }}" mode: "{{ item.mode }}" loop: "{{ downloads }}" - - name: Run MariaDB repository setup script command: cmd: "/bin/bash /tmp/mariadb_repo_setup --mariadb-server-version={{ db.version | default('10.11.10') }}" creates: "/etc/apt/sources.list.d/mariadb.list" - - name: Install Percona repository package apt: deb: "/tmp/percona-release_latest.generic_all.deb" state: present install_recommends: no - - name: Update apt cache apt: update_cache: yes - - name: Install MariaDB packages apt: name: "{{ mariadb_base_packages }}" state: present install_recommends: no - - name: Add tmpfs in /etc/fstab blockinfile: path: /etc/fstab @@ -39,15 +33,6 @@ block: | tmpfs /mnt/mysqltmp tmpfs rw,size={{ mysqltmpsize }} 0 0 register: fstab - -- name: Configure MariaDB memory check CRON - template: - src: check-memory.cron - dest: /etc/cron.d/vn-check-memory - owner: root - group: root - mode: u=rw,g=r,o=r - - name: Configure MariaDB scheduler log CRON copy: src: scheduler-log.cron @@ -55,7 +40,6 @@ owner: root group: root mode: u=rw,g=r,o=r - - name: Insert MySQL certificates no_log: true copy: @@ -66,7 +50,6 @@ mode: "{{ item.mode }}" loop: "{{ certificates }}" notify: restart-mariadb - - name: Ensure required directories exist file: path: "{{ item.path }}" @@ -75,7 +58,6 @@ group: "{{ item.group }}" mode: "{{ item.mode }}" loop: "{{ required_directories }}" - - name: Copy required MariaBackup files and scripts copy: src: "{{ item.src }}" @@ -84,7 +66,15 @@ group: root mode: "{{ item.mode }}" loop: "{{ required_mariabackup_files_and_scripts }}" - +- name: Deploy configuration files + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + owner: "{{ item.owner }}" + group: "{{ item.group }}" + mode: "{{ item.mode }}" + loop: "{{ configuration_files }}" + notify: restart-percona - name: Set MariaDB common configuration copy: src: conf/z90-vn.cnf @@ -93,23 +83,6 @@ group: root mode: u=rw,g=r,o=r notify: restart-mariadb - -- name: Set MariaDB local configuration template - template: - src: conf/z99-local.cnf - dest: /etc/mysql/mariadb.conf.d/ - owner: root - group: root - mode: u=rw,g=r,o=r - -- name: Set MariaBackup connection configuration - template: - src: mariabackup/my.cnf - dest: /root/mariabackup/ - owner: root - group: root - mode: u=rw,g=,o= - - name: Override MariaDB systemd service configuration copy: src: mariadb_override.conf @@ -118,7 +91,6 @@ group: root mode: u=rw,g=r,o=r notify: reload-systemd - - name: Set MariaDB NRPE configuration copy: src: nrpe/95-mariadb.cfg @@ -127,12 +99,10 @@ group: root mode: u=rw,g=r,o=r notify: restart-nrpe - - name: Check if /var/lib/mysql/ exists stat: path: /var/lib/mysql/ register: mysql_dir - - when: mysql_dir.stat.exists block: @@ -149,7 +119,6 @@ file: path: /var/lib/mysql/ state: absent - - name: Mount all filesystems from /etc/fstab command: mount -a when: fstab.changed @@ -178,3 +147,9 @@ name: process_monitor.timer enabled: true state: stopped + +- name: Clean old configs or scripts + file: + path: "{{ item }}" + state: absent + loop: "{{ clean_config_and_scripts }}" diff --git a/roles/db/templates/conf/z99-local.cnf b/roles/db/templates/conf/z99-local.cnf index a434496..390df19 100644 --- a/roles/db/templates/conf/z99-local.cnf +++ b/roles/db/templates/conf/z99-local.cnf @@ -1,6 +1,8 @@ [mysqld] server-id = {{ serverid }} +#log_slave_updates = ON +#read_only = ON #bind-address = 127.0.0.1 #event-scheduler = OFF #skip-log-bin diff --git a/roles/db/templates/mariabackup/apply.config.sh b/roles/db/templates/mariabackup/apply.config.sh index a175dd8..ca604ae 100755 --- a/roles/db/templates/mariabackup/apply.config.sh +++ b/roles/db/templates/mariabackup/apply.config.sh @@ -1,8 +1,5 @@ #!/bin/bash -# Bacula directory for restore -baculaDir=/mnt/mysqldata/bacula-restore - # Database branch name dbBranch={{ db.branch }} @@ -15,7 +12,7 @@ dbClusterSiblings=() # Jenkins authentication string jenkinsAuth=jenkins:{{ lookup(passbolt, 'jenkinsAuth', folder_parent_id=passbolt_folder).password }} -{% if db.jenkinsUrl is defined %} +{% if db.jenkinsJob is defined %} # Jenkins job URL -jenkinsUrl={{ db.jenkinsUrl }} +jenkinsUrl={{ jenkinsUrl }}{{ db.jenkinsJob }} {% endif %} diff --git a/roles/db/templates/mariabackup/my.cnf b/roles/db/templates/mariabackup/my.cnf index 7037bef..47207c2 100644 --- a/roles/db/templates/mariabackup/my.cnf +++ b/roles/db/templates/mariabackup/my.cnf @@ -2,6 +2,6 @@ host = localhost user = mariabackup password = {{ lookup(passbolt, 'mariabackup', folder_parent_id=passbolt_folder).password }} -use-memory = 1G -parallel = 4 +use-memory = 4G +parallel = 8 stream = xbstream diff --git a/roles/db/templates/pmm-agent.yaml b/roles/db/templates/pmm-agent.yaml new file mode 100644 index 0000000..04e2b6a --- /dev/null +++ b/roles/db/templates/pmm-agent.yaml @@ -0,0 +1,34 @@ +# Updated by `pmm-agent setup`. +--- +id: /agent_id/{{ pmm.id }} +listen-address: 127.0.0.1 +listen-port: 7777 +server: + address: {{ pmm.address }} + username: {{ pmm.username }} + password: {{ pmm.password }} + insecure-tls: {{ pmm.insecure }} +paths: + paths_base: /usr/local/percona/pmm2 + exporters_base: /usr/local/percona/pmm2/exporters + node_exporter: /usr/local/percona/pmm2/exporters/node_exporter + mysqld_exporter: /usr/local/percona/pmm2/exporters/mysqld_exporter + mongodb_exporter: /usr/local/percona/pmm2/exporters/mongodb_exporter + postgres_exporter: /usr/local/percona/pmm2/exporters/postgres_exporter + proxysql_exporter: /usr/local/percona/pmm2/exporters/proxysql_exporter + rds_exporter: /usr/local/percona/pmm2/exporters/rds_exporter + azure_exporter: /usr/local/percona/pmm2/exporters/azure_exporter + vmagent: /usr/local/percona/pmm2/exporters/vmagent + tempdir: {{ pmm.tempdir }} + pt_summary: /usr/local/percona/pmm2/tools/pt-summary + pt_pg_summary: /usr/local/percona/pmm2/tools/pt-pg-summary + pt_mysql_summary: /usr/local/percona/pmm2/tools/pt-mysql-summary + pt_mongodb_summary: /usr/local/percona/pmm2/tools/pt-mongodb-summary +ports: + min: 42000 + max: 51999 +log-level: warn +debug: false +trace: false +loglinescount: 1024 +window-connected-time: 1h0m0s diff --git a/roles/dhcp/templates/dhcpd.conf b/roles/dhcp/templates/dhcpd.conf index 47f5af2..7059f42 100644 --- a/roles/dhcp/templates/dhcpd.conf +++ b/roles/dhcp/templates/dhcpd.conf @@ -14,7 +14,7 @@ max-lease-time 86400; option domain-name "{{ domain_name.name }}"; option domain-name-servers {{ domain_name.servers }}; -option ntp-servers {{ ntp_servers }}; +option ntp-servers {{ domain_name.ntp_servers }}; # DHCP daemon uses default time zone UTC db-time-format local; diff --git a/roles/ipsec/defaults/main.yml b/roles/ipsec/defaults/main.yml new file mode 100644 index 0000000..a7d3b9d --- /dev/null +++ b/roles/ipsec/defaults/main.yml @@ -0,0 +1,36 @@ +strongswan_requeriments: + - strongswan + - libstrongswan-standard-plugins + - strongswan-pki + - tcpdump + - iperf + - conntrack + - iptables-persistent +certificates: + - { content: '{{ cert_ipsec }}', dest: '/etc/ipsec.d/certs/cert.pem', mode: 'u=rw,g=r,o=r' } + - { content: '{{ ca }}', dest: '/etc/ipsec.d/cacerts/ca.pem', mode: 'u=rw,g=r,o=r' } +config_ipsec_files: + - { src: 'ipsec.conf', dest: '/etc/ipsec.conf', mode: 'u=rw,g=r,o=r' } + - { src: 'vn-attr.conf', dest: '/etc/strongswan.d/charon/vn-attr.conf', mode: 'u=rw,g=r,o=r' } + - { src: 'vn-eap-radius.conf', dest: '/etc/strongswan.d/charon/vn-eap-radius.conf', mode: 'u=r,g=,o=' } + - { src: 'ipsec.secrets', dest: '/etc/ipsec.secrets', mode: 'u=r,g=,o=' } +mangle_block: | + *mangle + :PREROUTING ACCEPT [0:0] + :INPUT ACCEPT [0:0] + :FORWARD ACCEPT [0:0] + :OUTPUT ACCEPT [0:0] + :POSTROUTING ACCEPT [0:0] + -A PREROUTING -p tcp -m policy --dir in --pol ipsec -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1536 -j TCPMSS --set-mss 1360 + -A POSTROUTING -p tcp -m policy --dir out --pol ipsec -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1536 -j TCPMSS --set-mss 1360 + COMMIT + *filter + :INPUT ACCEPT [0:0] + :FORWARD ACCEPT [0:0] + :OUTPUT ACCEPT [0:0] + -A FORWARD -m conntrack --ctstate NEW,RELATED,ESTABLISHED -j ACCEPT + -A FORWARD -m conntrack --ctstate INVALID -j LOG --log-prefix "CT INVALID: " + COMMIT +config_and_logrotate: + - { src: vn.conf, dest: '/etc/strongswan.d/vn.conf' } + - { src: charon, dest: '/etc/logrotate.d/charon' } diff --git a/roles/ipsec/files/charon b/roles/ipsec/files/charon new file mode 100644 index 0000000..9a05de0 --- /dev/null +++ b/roles/ipsec/files/charon @@ -0,0 +1,11 @@ +/var/log/strongswan/charon.log +{ + copytruncate + create 644 root root + rotate 10 + weekly + missingok + notifempty + compress + delaycompress +} diff --git a/roles/ipsec/files/vn.conf b/roles/ipsec/files/vn.conf new file mode 100644 index 0000000..0b26373 --- /dev/null +++ b/roles/ipsec/files/vn.conf @@ -0,0 +1,19 @@ +charon { + cisco_unity = yes + + filelog { + log { + path = /var/log/strongswan/charon.log + append = yes + default = 1 + flush_line = yes + ike_name = yes + time_format = %Y-%m-%d %H:%M:%S + } + } + syslog { + identifier = charon + daemon { + } + } +} diff --git a/roles/ipsec/handlers/main.yml b/roles/ipsec/handlers/main.yml new file mode 100644 index 0000000..79978af --- /dev/null +++ b/roles/ipsec/handlers/main.yml @@ -0,0 +1,4 @@ +- name: restart-ipsec + systemd: + name: strongswan-starter.service + state: restarted diff --git a/roles/ipsec/tasks/ipsec.yml b/roles/ipsec/tasks/ipsec.yml new file mode 100644 index 0000000..37f63ce --- /dev/null +++ b/roles/ipsec/tasks/ipsec.yml @@ -0,0 +1,85 @@ +- name: Update apt cache + apt: + update_cache: yes +- name: Install VPN package requirements + apt: + name: "{{ strongswan_requeriments }}" + state: present + install_recommends: no +- name: Create directory /var/log/strongswan + file: + path: /var/log/strongswan + state: directory + owner: root + group: root + mode: '0755' +- name: Insert certificates + no_log: true + copy: + content: "{{ item.content }}" + dest: "{{ item.dest }}" + owner: root + group: root + mode: "{{ item.mode }}" + loop: "{{ certificates }}" +- name: Add private key + copy: + content: "{{ lookup(passbolt, 'ipsec_private_key', folder_parent_id=passbolt_folder).description }}" + dest: /etc/ipsec.d/private/key.pem + owner: root + group: root + mode: u=r,g=r,o= +- name: Configure ipsec and charon + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + owner: root + group: root + mode: "{{ item.mode }}" + loop: "{{ config_ipsec_files }}" + notify: restart-ipsec +- name: Copy Configure file and logrotate Charon + copy: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + owner: root + group: root + mode: u=rw,g=r,o=r + loop: "{{ config_and_logrotate }}" + notify: restart-ipsec +- name: IP forward as a router + sysctl: + name: net.ipv4.ip_forward + value: "1" + state: present + sysctl_set: yes + reload: yes +- name: Add iptables rules in rules.v4 file + blockinfile: + path: /etc/iptables/rules.v4 + marker: "# {mark} ANSIBLE-MANAGED MANGLE CHAIN" + block: "{{ mangle_block }}" + register: iptables +- name: Reload iptables rules + command: netfilter-persistent reload + when: iptables.changed +- name: Get default IPv4 interface + command: ip -o -4 route show default + register: default_route +- name: Extract interface default name + set_fact: + active_interface: "{{ default_route.stdout.split()[-1] }}" +- name: Routing table for VPN + lineinfile: + path: /etc/iproute2/rt_tables + line: "10 vpn" + state: present + regexp: "vpn" +- name: Static routing rules to send VPN traffic directly to the firewall + lineinfile: + path: /etc/network/interfaces + insertafter: "dhcp" + line: "{{ item }}" + state: present + loop: "{{ static_routes }}" + \ No newline at end of file diff --git a/roles/ipsec/tasks/main.yml b/roles/ipsec/tasks/main.yml new file mode 100644 index 0000000..d3dd860 --- /dev/null +++ b/roles/ipsec/tasks/main.yml @@ -0,0 +1,3 @@ +- import_tasks: ipsec.yml + tags: ipsec + diff --git a/roles/ipsec/templates/ipsec.conf b/roles/ipsec/templates/ipsec.conf new file mode 100644 index 0000000..76d3627 --- /dev/null +++ b/roles/ipsec/templates/ipsec.conf @@ -0,0 +1,32 @@ + +config setup + charondebug="ike 1, knl 1, cfg 0" + uniqueids=no + +conn %default + auto=add + compress=no + type=tunnel + keyexchange=ikev2 + fragmentation=yes + forceencaps=yes + eap_identity=%identity + + dpdaction=clear + dpddelay=300s + rekey=no + + left=%any + leftid=@{{ leftid }} + leftcert=cert.pem + leftsendcert=always + leftsubnet={{ leftsubnet }} + + right=%any + rightid=%any + rightauth=eap-radius + rightdns={{ rightdns }} + rightsendcert=never + +{{ ipsec_groups }} + diff --git a/roles/ipsec/templates/ipsec.secrets b/roles/ipsec/templates/ipsec.secrets new file mode 100644 index 0000000..9956a00 --- /dev/null +++ b/roles/ipsec/templates/ipsec.secrets @@ -0,0 +1,2 @@ +{{ leftid }} : RSA "key.pem" +admin %any% : EAP "{{ lookup(passbolt, 'eap', folder_parent_id=passbolt_folder).password }}" diff --git a/roles/ipsec/templates/vn-attr.conf b/roles/ipsec/templates/vn-attr.conf new file mode 100644 index 0000000..94b2b2f --- /dev/null +++ b/roles/ipsec/templates/vn-attr.conf @@ -0,0 +1,8 @@ +attr { + load = yes + dns = {{ rightdns }} + split-include = {{ leftsubnet }} + split-exclude = 0.0.0.0/0 + 28674 = {{ leftid }} + 25 = {{ leftid }} +} diff --git a/roles/ipsec/templates/vn-eap-radius.conf b/roles/ipsec/templates/vn-eap-radius.conf new file mode 100644 index 0000000..de69c64 --- /dev/null +++ b/roles/ipsec/templates/vn-eap-radius.conf @@ -0,0 +1,21 @@ +eap-radius { + load = yes + accounting = yes + class_group = yes + servers { + primary { + #address = radius1.verdnatura.es + address = {{ address_radiusA }} + auth_port = {{ auth_port }} + acct_port = {{ acct_port }} + secret = {{ lookup(passbolt, 'eap-radius', folder_parent_id=passbolt_folder).password }} + } + secondary { + #address = radius2.verdnatura.es + address = {{ address_radiusB }} + auth_port = {{ auth_port }} + acct_port = {{ acct_port }} + secret = {{ lookup(passbolt, 'eap-radius', folder_parent_id=passbolt_folder).password }} + } + } +} \ No newline at end of file diff --git a/roles/ns/defaults/main.yml b/roles/ns/defaults/main.yml new file mode 100644 index 0000000..4b1213f --- /dev/null +++ b/roles/ns/defaults/main.yml @@ -0,0 +1,29 @@ +bind_packages: + - bind9 + - bind9-dnsutils + - bind9-host + - bind9-libs + - bind9-utils + - dnsutils + - python3-pycurl +bind_config_templates: + - { src: 'named.conf.j2', dest: '/etc/bind/named.conf', mode: 'u=rw,g=r,o=r' } + - { src: 'named.conf.master.j2', dest: '/etc/bind/named.conf.master', mode: 'u=rw,g=r,o=r' } + - { src: 'named.conf.local.j2', dest: '/etc/bind/named.conf.local', mode: 'u=rw,g=r,o=r' } + - { src: 'named.conf.slave.j2', dest: '/etc/bind/named.conf.slave', mode: 'u=rw,g=r,o=r' } + - { src: 'certbot.key', dest: '/etc/bind/keys/certbot.key', mode: 'u=rw,g=r,o=' } + - { src: 'lan.key', dest: '/etc/bind/keys/lan.key', mode: 'u=rw,g=r,o=' } + - { src: 'wan.key', dest: '/etc/bind/keys/wan.key', mode: 'u=rw,g=r,o=' } + - { src: 'rndc.key', dest: '/etc/bind/rndc.key', mode: 'u=rw,g=r,o=' } + - { src: 'dhcp.key', dest: '/etc/bind/keys/dhcp.key', mode: 'u=rw,g=r,o=' } + - { src: 'isp1.ns', dest: '/root/scripts/switch-isp', mode: 'u=rw,g=rw,o=r' } + - { src: 'isp2.ns', dest: '/root/scripts/switch-isp', mode: 'u=rw,g=rw,o=r' } + - { src: 'delete.ns', dest: '/root/scripts/switch-isp', mode: 'u=rw,g=rw,o=r' } +directory: + - { path: '/root/scripts', owner: 'root', group: 'root', mode: 'u=rwx,g=rx,o=rx' } + - { path: '/etc/bind/keys', owner: 'root', group: 'bind', mode: 'u=rwx,g=rxs,o=rx' } + - { path: '/root/scripts/switch-isp', owner: 'root', group: 'bind', mode: 'u=rwx,g=rxs,o=rx' } +required_files: + - { src: 'switch-isp.sh', dest: '/root/scripts', owner: 'root', group: 'root', mode: 'u=rwx,g=rx,o=rx' } + - { src: 'sync-conf', dest: '/root/scripts', owner: 'root', group: 'root', mode: 'u=rwx,g=rx,o=rx' } + - { src: 'gen-key.sh', dest: '/root/scripts', owner: 'root', group: 'bind', mode: 'u=rwx,g=rx,o=rx' } diff --git a/roles/ns/files/gen-key.sh b/roles/ns/files/gen-key.sh new file mode 100644 index 0000000..4c062a2 --- /dev/null +++ b/roles/ns/files/gen-key.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +KEYNAME=$1 + +if [ -z "$KEYNAME" ]; then + echo "Usage: $0 " + exit 1 +fi + +tsig-keygen -a hmac-sha512 "$KEYNAME" diff --git a/roles/ns/files/switch-isp.sh b/roles/ns/files/switch-isp.sh new file mode 100644 index 0000000..5444192 --- /dev/null +++ b/roles/ns/files/switch-isp.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +ISP=$1 + +if [ -z "$ISP" ]; then + echo "Usage: $0 " + exit 1 +fi + +KEY_FILE="/etc/bind/keys/wan.key" +NS_DIR="/root/scripts/switch-isp" +ISP_FILE="$NS_DIR/$ISP.ns" + +if [ ! -f "$ISP_FILE" ]; then + echo "ISP file for nsupdate not found: $ISP_FILE" + exit 2 +fi + +echo "Deleting ISP dependent DNS records." +nsupdate -k "$KEY_FILE" "$NS_DIR/delete.ns" + +echo "Registering $ISP DNS records." +nsupdate -k "$KEY_FILE" "$ISP_FILE" diff --git a/roles/ns/files/sync-conf b/roles/ns/files/sync-conf new file mode 100644 index 0000000..a3b947b --- /dev/null +++ b/roles/ns/files/sync-conf @@ -0,0 +1,27 @@ +#!/bin/bash + +if [ "$(hostname)" = "ns1" ]; then + partner=root@ns2.servers.dc.verdnatura.es +else + partner=root@ns1.servers.dc.verdnatura.es +fi + +confDir=/etc/bind + +echo "Restarting service." +service bind9 restart + +if [ $? -eq "0" ]; then + echo "Synchronizing partner configuration." + + scp "$confDir/named.conf.local" $partner:$confDir + scp "$confDir/named.conf.master" $partner:$confDir + scp "$confDir/named.conf.slave" $partner:$confDir + + ssh "$partner" rm -rf "$confDir/keys" + ssh "$partner" mkdir "$confDir/keys" + scp -r "$confDir/keys/"* $partner:"$confDir/keys" + + echo "Restarting partner service." + ssh $partner service bind9 restart +fi diff --git a/roles/ns/handlers/main.yml b/roles/ns/handlers/main.yml new file mode 100644 index 0000000..840d041 --- /dev/null +++ b/roles/ns/handlers/main.yml @@ -0,0 +1,4 @@ +- name: restart-dns + systemd: + name: bind9 + state: restarted \ No newline at end of file diff --git a/roles/ns/tasks/main.yml b/roles/ns/tasks/main.yml new file mode 100644 index 0000000..0948ab4 --- /dev/null +++ b/roles/ns/tasks/main.yml @@ -0,0 +1,2 @@ +- import_tasks: ns.yml + tags: ns diff --git a/roles/ns/tasks/ns.yml b/roles/ns/tasks/ns.yml new file mode 100644 index 0000000..beb5d3a --- /dev/null +++ b/roles/ns/tasks/ns.yml @@ -0,0 +1,41 @@ +- name: Update apt cache + apt: + update_cache: yes +- name: Install bind package requirements + apt: + name: "{{ bind_packages }}" + state: present + install_recommends: no +- name: Ensure BIND9 starts with IPv4 only (-4) + lineinfile: + path: /etc/default/named + regexp: '^OPTIONS=' + line: 'OPTIONS="-u bind -4"' + backrefs: yes + notify: restart-dns +- name: Create directory + file: + path: "{{ item.path }}" + state: directory + owner: "{{ item.group }}" + group: "{{ item.group }}" + mode: "{{ item.mode }}" + loop: "{{ directory }}" +- name: Copy required files and scripts + copy: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + owner: "{{ item.group }}" + group: "{{ item.group }}" + mode: "{{ item.mode }}" + loop: "{{ required_files }}" +- name: Deploy BIND config templates + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + owner: root + group: bind + mode: "{{ item.mode }}" + loop: "{{ bind_config_templates }}" + notify: restart-dns + diff --git a/roles/ns/templates/certbot.key b/roles/ns/templates/certbot.key new file mode 100644 index 0000000..6e9f1b9 --- /dev/null +++ b/roles/ns/templates/certbot.key @@ -0,0 +1,4 @@ +key "certbot" { + algorithm hmac-sha512; + secret "{{ lookup(passbolt, 'certbot', folder_parent_id=passbolt_folder).password }}"; +}; diff --git a/roles/ns/templates/delete.ns b/roles/ns/templates/delete.ns new file mode 100644 index 0000000..899f5cc --- /dev/null +++ b/roles/ns/templates/delete.ns @@ -0,0 +1,4 @@ +{% for record in dns_records_delete %} +update delete {{ record.name.ljust(30) }} A +{% endfor %} +send diff --git a/roles/ns/templates/dhcp.key b/roles/ns/templates/dhcp.key new file mode 100644 index 0000000..a732d1e --- /dev/null +++ b/roles/ns/templates/dhcp.key @@ -0,0 +1,4 @@ +key "dhcp" { + algorithm hmac-sha512; + secret "{{ lookup(passbolt, 'dhcpkey', folder_parent_id=passbolt_folder).password }}"; +}; diff --git a/roles/ns/templates/isp1.ns b/roles/ns/templates/isp1.ns new file mode 100644 index 0000000..57eba65 --- /dev/null +++ b/roles/ns/templates/isp1.ns @@ -0,0 +1,4 @@ +{% for record in dns_records_main %} +update add {{ record.name.ljust(30) }} {{ record.ttl }} A {{ record.ip }} +{% endfor %} +send diff --git a/roles/ns/templates/isp2.ns b/roles/ns/templates/isp2.ns new file mode 100644 index 0000000..e89b38e --- /dev/null +++ b/roles/ns/templates/isp2.ns @@ -0,0 +1,4 @@ +{% for record in dns_records_secondary %} +update add {{ record.name.ljust(30) }} {{ record.ttl }} A {{ record.ip }} +{% endfor %} +send diff --git a/roles/ns/templates/lan.key b/roles/ns/templates/lan.key new file mode 100644 index 0000000..c99ad33 --- /dev/null +++ b/roles/ns/templates/lan.key @@ -0,0 +1,4 @@ +key "lan" { + algorithm hmac-sha512; + secret "{{ lookup(passbolt, 'lankey', folder_parent_id=passbolt_folder).password }}"; +}; diff --git a/roles/ns/templates/named.conf.j2 b/roles/ns/templates/named.conf.j2 new file mode 100644 index 0000000..32e13f7 --- /dev/null +++ b/roles/ns/templates/named.conf.j2 @@ -0,0 +1,16 @@ +// This is the primary configuration file for the BIND DNS server named. +// +// Please read /usr/share/doc/bind9/README.Debian.gz for information on the +// structure of BIND configuration files in Debian, *BEFORE* you customize +// this configuration file. +// +// If you are just adding zones, please do that in /etc/bind/named.conf.local + +#include "/etc/bind/named.conf.options"; +include "/etc/bind/named.conf.local"; +{% if bind_is_master %} +include "/etc/bind/named.conf.master"; +{% else %} +include "/etc/bind/named.conf.slave"; +{% endif %} +#include "/etc/bind/named.conf.default-zones"; diff --git a/roles/ns/templates/named.conf.local.j2 b/roles/ns/templates/named.conf.local.j2 new file mode 100644 index 0000000..09a8935 --- /dev/null +++ b/roles/ns/templates/named.conf.local.j2 @@ -0,0 +1,30 @@ +include "/etc/bind/rndc.key"; +include "/etc/bind/keys/wan.key"; +include "/etc/bind/keys/lan.key"; +include "/etc/bind/keys/certbot.key"; +include "/etc/bind/keys/dhcp.key"; + +server fe80::/16 { bogus yes; }; + +acl lan { + 10.0.0.0/8; + 172.16.0.0/12; + 192.168.0.0/16; + }; + +acl rfc5735 { + 0.0.0.0/8; + 169.254.0.0/16; + 192.0.0.0/24; + 192.0.2.0/24; + 192.88.99.0/24; + 198.18.0.0/15; + 198.51.100.0/24; + 203.0.113.0/24; + 224.0.0.0/4; + 240.0.0.0/4; + }; + +controls { + inet * allow { localhost; lan; } keys { "rndc-key"; }; +}; diff --git a/roles/ns/templates/named.conf.master.j2 b/roles/ns/templates/named.conf.master.j2 new file mode 100644 index 0000000..3d0a2e0 --- /dev/null +++ b/roles/ns/templates/named.conf.master.j2 @@ -0,0 +1,85 @@ +options { + directory "/var/cache/bind"; + max-cache-size 500m; + auth-nxdomain no; + listen-on-v6 { none; }; + version "DNS"; + allow-update { none; }; + blackhole { rfc5735; }; + + allow-transfer { + {% for ip in bind_allow_transfer %} + {{ ip }}; + {% endfor %} + }; +}; + +view "lan" { + match-clients { +{% for item in key_match_clients_lan_master if item.startswith("!key") %} + {{ item }}; +{% endfor %} +{% for item in acl_match_clients %} + {{ item }}; +{% endfor %} +{% for item in key_match_clients_lan_master if not item.startswith("!key") %} + {{ item }}; +{% endfor %} + }; + + plugin query "filter-aaaa.so" { + filter-aaaa-on-v4 yes; + filter-aaaa-on-v6 yes; + filter-aaaa { any; }; + }; + + recursion yes; + allow-recursion { any; }; + empty-zones-enable yes; + notify yes; + + include "/etc/bind/named.conf.default-zones"; + +{% for zone in bind_zones.lan %} + zone "{{ zone.name }}" { + type master; + forwarders {}; + allow-update { key {{ zone.key }}; }; + file "{{ zone.file }}"; + }; +{% endfor %} +}; + +view "wan" { + match-clients { any; }; + + recursion no; + allow-query-cache { none; }; + empty-zones-enable no; + + notify explicit; + + also-notify { +{% for entry in bind_also_notify %} + {{ entry.ip }} key {{ entry.key }}; +{% endfor %} + }; + +{% for zone in bind_zones.wan %} +{% if zone.in_view is defined %} +{% for z in zone.in_view %} + zone "{{ z }}" { + in-view "lan"; + }; +{% endfor %} +{% else %} + zone "{{ zone.name }}" { + type master; + forwarders {}; + allow-update { key {{ zone.key }}; }; + file "{{ zone.file }}"; + }; +{% endif %} +{% endfor %} +}; + diff --git a/roles/ns/templates/named.conf.slave.j2 b/roles/ns/templates/named.conf.slave.j2 new file mode 100644 index 0000000..cfe4ade --- /dev/null +++ b/roles/ns/templates/named.conf.slave.j2 @@ -0,0 +1,78 @@ +options { + directory "/var/cache/bind"; + max-cache-size 500m; + auth-nxdomain no; + listen-on-v6 { none; }; + version "DNS"; + allow-update { none; }; + blackhole { rfc5735; }; + + notify no; + allow-transfer { none; }; + masterfile-format text; +}; + +masters master-ips { +{% for ip in bind_slave_masters %} + {{ ip }}; +{% endfor %} +}; + +view "lan" { + match-clients { + {%- for item in key_match_clients_lan_master if item.startswith("!key") -%} + {{ item }}; + {% endfor %} +{%- for item in acl_match_clients -%} + {{ item }}; + {% endfor %} +{%- for item in key_match_clients_lan_slave if not item.startswith("!key") -%} + {{ item }}; + {% endfor %} +}; + + plugin query "filter-aaaa.so" { + filter-aaaa-on-v4 yes; + filter-aaaa-on-v6 yes; + filter-aaaa { any; }; + }; + recursion yes; + allow-recursion { any; }; + empty-zones-enable yes; + + include "/etc/bind/named.conf.default-zones"; + + {% for zone in bind_zones.lan %} + zone "{{ zone.name }}" { + type slave; + masters { master-ips; }; + forwarders {}; + file "{{ zone.file }}"; + }; + {% endfor %} +}; + +view "wan" { + match-clients { any; }; + + recursion no; + allow-query-cache { none; }; + empty-zones-enable no; + + {% for zone in bind_zones.wan %} + {% if zone.in_view is defined %} + {% for z in zone.in_view %} + zone "{{ z }}" { + in-view "lan"; + }; + {% endfor %} + {% else %} + zone "{{ zone.name }}" { + type slave; + masters { {{ bind_slave_masters | join('; ') }} key {{ zone.key }}; }; + forwarders {}; + file "{{ zone.file }}"; + }; + {% endif %} + {% endfor %} +}; diff --git a/roles/ns/templates/rndc.key b/roles/ns/templates/rndc.key new file mode 100644 index 0000000..40d9600 --- /dev/null +++ b/roles/ns/templates/rndc.key @@ -0,0 +1,4 @@ +key "rndc-key" { + algorithm hmac-md5; + secret "{{ lookup(passbolt, 'rndc-key', folder_parent_id=passbolt_folder).password }}"; +}; diff --git a/roles/ns/templates/wan.key b/roles/ns/templates/wan.key new file mode 100644 index 0000000..daa655c --- /dev/null +++ b/roles/ns/templates/wan.key @@ -0,0 +1,4 @@ +key "wan-key" { + algorithm hmac-md5; + secret "{{ lookup(passbolt, 'wan-key', folder_parent_id=passbolt_folder).password }}"; +}; diff --git a/roles/pve/files/nrpe.cfg b/roles/pve/files/nrpe.d/95-pve.cfg similarity index 100% rename from roles/pve/files/nrpe.cfg rename to roles/pve/files/nrpe.d/95-pve.cfg diff --git a/roles/pve/files/nrpe/check_chrony b/roles/pve/files/plugins/check_chrony similarity index 100% rename from roles/pve/files/nrpe/check_chrony rename to roles/pve/files/plugins/check_chrony diff --git a/roles/pve/files/plugins/check_ilo2_health.pl b/roles/pve/files/plugins/check_ilo2_health.pl new file mode 100755 index 0000000..4f5dba4 --- /dev/null +++ b/roles/pve/files/plugins/check_ilo2_health.pl @@ -0,0 +1,1234 @@ +#!/usr/bin/perl +# icinga: -epn + +# check_ilo2_health.pl +# based on check_stuff.pl and locfg.pl +# +# Nagios plugin using the Nagios::Plugin or Monitoring::Plugin module and the +# HP Lights-Out XML PERL Scripting Sample from +# ftp://ftp.hp.com/pub/softlib2/software1/pubsw-linux/p391992567/v60711/linux-LOsamplescripts3.00.0-2.tgz +# checks if all sensors are ok, returns warning on high temperatures and +# fan failures and critical on overall health failure +# +# Alexander Greiner-Baer 2007 - 2021 +# Matthew Stier 2011 +# Claudio Kuenzler 2021 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# +# Changelog: +# 1.66 Wed, 21 Apr 2021 13:00:00 +0200 +# support both Nagios::Plugin and Monitoring::Plugin modules +# add option "-W" for checking server's current power usage (in Watt) +# 1.65 Sat, 06 Feb 2021 13:00:03 +0100 +# new option "--ignorecacheother|-O" +# ignores cache status "Other" +# 1.64 Tue, 02 Jun 2020 18:56:30 +0200 +# fix memory status (was Unknown on an otherwise healthy G8) +# fix drive check for ilo2, was broken for 5 years... +# new option "-L" +# retrieve event log from RIB_INFO section +# fix help message for "-l" +# new option "-S" +# check self_test value from https:///json/login_session +# 1.63 Tue, 13 Nov 2018 18:41:48 +0100 +# support iLO5 firmware infos +# applied patch from Rene Koch +# ignore link unknown (option "-U") +# 1.62 Mon, 14 May 2018 19:05:22 +0200 +# retrieve firmware infos only when using --getinfos +# 1.61 Thu, 01 Jun 2017 20:05:04 +0200 +# fix for iLO4 2.50 link state when using --ignorelinkdown +# 1.60 Wed, 12 Aug 2015 18:20:13 +0200 +# provide --sslopts to override defaults settings +# fix }; for GET_EVENT_LOG +# applied patch from Rene Koch : +# handle missing values when using "-g" +# CONTROLLER_STATUS not present on iLO4 anymore, use STATUS instead +# put SSL_VERIFY_NONE in '' +# 1.59 Wed, 28 Jan 2015 18:56:26 +0100 +# fix chunk size handling +# corrected HTTP/1.1 HOST Header +# applied patch from Max Winterstein : +# sslv3 support +# add retries option +# catch XMLin() errors +# applied patch from Rene Koch : +# ignore battery not installed status (option "-x") +# display server name (option "-g") +# added warning for logical drive status "Degraded (Recovering)" +# display system details (hardware model, serial number, SystemROM, iLO version) +# display memory size and part number in case of memory failure +# display hard disk model number in case of hard disk failure +# display power supply part number in case of power supply failure +# 1.58 Thu, 08 Aug 2013 18:17:02 +0200 +# ignore network link down status (option "-i") +# added ENCLOSURE_ADDR to drive bay label (bay numbering was inconsistent) +# ignore spare drives +# 1.57 Fri, 17 May 2013 19:30:48 +0200 +# SSL_verify_mode SSL_VERIFY_NONE (IO::Socket::SSL changed default) +# event log support for ilo2 +# disable embedded perl in icinga +# 1.56 Fri, 15 Mar 2013 20:47:13 +0100 +# applied patch from Niklas Edmundsson : +# check processor and memory details +# applied patches from Dragan Sekerovic : +# add location label to temperature (option "-b") +# support for checking event log (option "-l") +# add iLO version to output +# add 2 new values for power supply status +# -- +# 1.55 Sun, 05 Aug 2012 20:18:46 +0200 +# faulty drive (option "-c") exits now with CRITICAL instead of WARNING +# applied patches from Niklas Edmundsson : +# iLO4 RAID Controller Status +# nodriveexit +# add g6 drive status +# overall health probes every element now +# fixed bug with drive bay index +# supports iLO3 with multiple backplanes +# supports iLO4 disk check +# Note: overall health may show drive/storage status, even without "-c" +# -- +# 1.54 Thu, 14 Jun 2012 21:36:40 +0200 +# applied fix for iLO4 from Niklas Edmundsson +# -- +# 1.53 Tue, 14 Feb 2012 19:47:40 +0100 +# added new disk bay variant +# added power supply NOT APPLICABLE +# -- +# 1.52 Wed, 27 Jul 2011 20:46:14 +0200 +# fixed