Compare commits

...

37 Commits

Author SHA1 Message Date
Juan Ferrer a0a0026f6e Update roles/db/templates/conf/z99-local.cnf 2025-04-04 16:25:15 +00:00
Juan Ferrer 1d06e159be Merge pull request 'db: refs #8140 - variable local-backup' (!83) from 8140_local-backup into main
Reviewed-on: #83
Reviewed-by: Juan Ferrer <juan@verdnatura.es>
2025-04-04 13:25:40 +00:00
Xavi Lleó 772a3f3fa2 db: refs #8140 - variable local-backup 2025-04-04 15:09:03 +02:00
Xavi Lleó 391707701f Merge pull request 'db: refs #8140 - add new script to change server rol' (!82) from 8140_feat_promote_and_demote into main
Reviewed-on: #82
Reviewed-by: Juan Ferrer <juan@verdnatura.es>
2025-04-04 12:50:37 +00:00
Xavi Lleó 7a925b67c4 db: refs #8140 - clean festival 2025-04-04 14:27:11 +02:00
Xavi Lleó 1f745a1c8c db: refs #8140 - clean party 2025-04-04 13:38:56 +02:00
Xavi Lleó 54733ee4fe db: refs #8140 - add new script to change server rol 2025-04-04 13:04:34 +02:00
Juan Ferrer 3fd2bcd6d0 Update roles/db/templates/conf/z99-local.cnf 2025-04-02 15:35:47 +00:00
Xavi Lleó b7073888ac Merge pull request '8748_VPN_Conntrack' (!81) from 8748_VPN_Conntrack into main
Reviewed-on: #81
Reviewed-by: Juan Ferrer <juan@verdnatura.es>
2025-04-02 13:19:01 +00:00
Xavi Lleó 2135ff9ec5 Merge branch 'main' into 8748_VPN_Conntrack 2025-04-02 13:18:21 +00:00
Xavi Lleó 0e073c7ba1 vpn: refs #8748 - add conntrack iptables default block 2025-04-02 11:34:17 +02:00
Xavi Lleó 7ee760f506 dns: refs #8552 - indentation jinga master.conf 2025-03-28 15:49:06 +01:00
Xavi Lleó 651ee7edf6 dns: refs #8552 - disable ipv6 and move delete ns file 2025-03-28 14:12:42 +01:00
Xavi Lleó 45bf706f93 Merge pull request 'dns: refs #8552 - Main approche - before final named.conf' (!79) from 8552_DNS_server into main
Reviewed-on: #79
Reviewed-by: Juan Ferrer <juan@verdnatura.es>
2025-03-27 09:50:51 +00:00
Xavi Lleó 00f078695f Merge branch 'main' into 8552_DNS_server 2025-03-27 09:50:34 +00:00
Xavi Lleó babf43cfba dns: refs #8552 - Juan Request #79 2025-03-27 10:43:50 +01:00
Xavi Lleó 24d8864cf6 dns: refs #8552 - Main approche - final touch 2025-03-26 14:49:26 +01:00
Xavi Lleó 93586290db dns: refs #8552 - Main approche - before final named.conf 2025-03-26 13:15:41 +01:00
Xavi Lleó 8f6db08d1f Merge pull request 'vpn: refs #8140 - Refactor main yml and add pmm template' (!78) from 8140_db_pmm_template_fix into main
Reviewed-on: #78
Reviewed-by: Juan Ferrer <juan@verdnatura.es>
2025-03-24 12:41:25 +00:00
Xavi Lleó 596dc1f6be Merge branch 'main' into 8140_db_pmm_template_fix 2025-03-24 06:47:31 +00:00
Juan Ferrer d7a1de2f5c refs #8776 PVE and Ceph monitoring 2025-03-17 17:51:25 +01:00
Juan Ferrer 2cbf9c5619 refs #8776 PVE and Ceph monitoring 2025-03-17 17:50:56 +01:00
Juan Ferrer aef6cb5bc0 refs #8776 PVE and Ceph monitoring 2025-03-17 17:49:06 +01:00
Xavi Lleó 7f372d20f4 vpn: refs #8140 - Refactor main yml and add pmm template 2025-03-17 15:58:29 +01:00
Xavi Lleó e969c33f65 Merge pull request '8748_VPN_IPsec' (!77) from 8748_VPN_IPsec into main
Reviewed-on: #77
Reviewed-by: Juan Ferrer <juan@verdnatura.es>
2025-03-17 11:51:02 +00:00
Xavi Lleó aba7121907 vpn: refs #8748 - Final touch 2025-03-14 14:33:53 +01:00
Xavi Lleó c1074a90e5 vpn: refs #8748 - Iptables approche - what to do 2025-03-14 12:58:15 +01:00
Xavi Lleó 0e393b49c8 vpn: refs #8748 - Variables array 2025-03-14 11:41:13 +01:00
Xavi Lleó 8c168d4fa8 vpn: refs #8748 - Names fix 2025-03-14 11:34:21 +01:00
Xavi Lleó 9ac8501f14 vpn: refs #8748 - Names fix 2025-03-14 11:33:01 +01:00
Xavi Lleó 00239750a2 vpn: refs #8748 - Initial approche 2025-03-14 11:29:31 +01:00
Xavi Lleó b897482076 Merge pull request 'fix: refs #8762 Fix table cache hitrate' (!76) from 8762-fixTableCacheHitrate into main
Reviewed-on: #76
Reviewed-by: Xavi Lleó <xavi@verdnatura.es>
2025-03-13 08:36:11 +00:00
Juan Ferrer eaddc25c38 fix: refs #8762 Fix table cache hitrate 2025-03-12 17:35:47 +00:00
Xavi Lleó 92ba2b9238 Merge pull request 'db: refs #8414 - Add jenkins Url and nrpe threshold' (!75) from 8414_jenkins_Url into main
Reviewed-on: #75
Reviewed-by: Juan Ferrer <juan@verdnatura.es>
2025-03-12 13:40:29 +00:00
Xavi Lleó 7d7d855384 db: refs #8414 - Add jenkins Url and nrpe threshold 2025-03-12 14:22:50 +01:00
Xavi Lleó 82b25c6a88 Merge pull request 'refs #8553 - add ntp_servers variable' (!73) from 8553_DHCP_final_touch into main
Reviewed-on: #73
Reviewed-by: Juan Ferrer <juan@verdnatura.es>
2025-03-12 12:46:17 +00:00
Xavi Lleó 2990e7e969 refs #8553 - add ntp_servers variable 2025-03-06 08:25:26 +01:00
58 changed files with 2548 additions and 95 deletions

6
playbooks/ns.yml Normal file
View File

@ -0,0 +1,6 @@
- name: Configure bind9 name server
hosts: all
tasks:
- name: Configure services to install in the server
import_role:
name: ns

6
playbooks/vpn-ipsec.yml Normal file
View File

@ -0,0 +1,6 @@
- name: Configure IPsec StrongSwan
hosts: all
tasks:
- name: Configure services to install in the server
import_role:
name: ipsec

View File

@ -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

View File

@ -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())

View File

@ -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())

View File

@ -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");

1
roles/ceph/files/sudoers Normal file
View File

@ -0,0 +1 @@
nagios ALL=(root) NOPASSWD: /usr/sbin/smartctl,/sbin/dmsetup

View File

@ -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

24
roles/ceph/tasks/nrpe.yml Normal file
View File

@ -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

View File

@ -29,10 +29,14 @@ required_mariabackup_files_and_scripts:
- { 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 +44,8 @@ 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:
- { path: /root/scripts/events-promote.sh }
- { path: /root/scripts/events-demote.sh }
- { path: /root/scripts/promote-master.sh }
- { path: /root/scripts/promote-slave.sh }

View File

@ -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

View File

@ -2,3 +2,4 @@ command[check_disk_mysqldata]=/usr/lib/nagios/plugins/check_disk -w 10% -c 5% -p
command[check_disk_mysqlbin]=/usr/lib/nagios/plugins/check_disk -w 10% -c 5% -p /mnt/mysqlbin
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

View File

@ -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"

View File

@ -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"

View File

@ -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 <https://www.gnu.org/licenses/>.
#
# 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

View File

@ -9,3 +9,7 @@
service:
name: nagios-nrpe-server
state: restarted
- name: restart-percona
service:
name: pmm-agent.service
state: restarted

View File

@ -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,12 @@
file:
path: /var/lib/mysql/
state: absent
- name: Mount all filesystems from /etc/fstab
command: mount -a
when: fstab.changed
- name: Clean old configs or scripts
file:
path: "{{ item.path }}"
state: absent
loop: "{{ clean_config_and_scripts }}"

View File

@ -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

View File

@ -1,7 +1,7 @@
#!/bin/bash
# Bacula directory for restore
baculaDir=/mnt/mysqldata/bacula-restore
baculaDir=/mnt/local-backup/bacula-restore
# Database branch name
dbBranch={{ db.branch }}
@ -15,7 +15,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 %}

View File

@ -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

View File

@ -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;

View File

@ -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' }

11
roles/ipsec/files/charon Normal file
View File

@ -0,0 +1,11 @@
/var/log/strongswan/charon.log
{
copytruncate
create 644 root root
rotate 10
weekly
missingok
notifempty
compress
delaycompress
}

19
roles/ipsec/files/vn.conf Normal file
View File

@ -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 {
}
}
}

View File

@ -0,0 +1,4 @@
- name: restart-ipsec
systemd:
name: strongswan-starter.service
state: restarted

View File

@ -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 }}"

View File

@ -0,0 +1,3 @@
- import_tasks: ipsec.yml
tags: ipsec

View File

@ -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 }}

View File

@ -0,0 +1,2 @@
{{ leftid }} : RSA "key.pem"
admin %any% : EAP "{{ lookup(passbolt, 'eap', folder_parent_id=passbolt_folder).password }}"

View File

@ -0,0 +1,8 @@
attr {
load = yes
dns = {{ rightdns }}
split-include = {{ leftsubnet }}
split-exclude = 0.0.0.0/0
28674 = {{ leftid }}
25 = {{ leftid }}
}

View File

@ -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 }}
}
}
}

View File

@ -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' }

10
roles/ns/files/gen-key.sh Normal file
View File

@ -0,0 +1,10 @@
#!/bin/bash
KEYNAME=$1
if [ -z "$KEYNAME" ]; then
echo "Usage: $0 <key_name>"
exit 1
fi
tsig-keygen -a hmac-sha512 "$KEYNAME"

View File

@ -0,0 +1,23 @@
#!/bin/bash
ISP=$1
if [ -z "$ISP" ]; then
echo "Usage: $0 <isp_name>"
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"

27
roles/ns/files/sync-conf Normal file
View File

@ -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

View File

@ -0,0 +1,4 @@
- name: restart-dns
systemd:
name: bind9
state: restarted

2
roles/ns/tasks/main.yml Normal file
View File

@ -0,0 +1,2 @@
- import_tasks: ns.yml
tags: ns

41
roles/ns/tasks/ns.yml Normal file
View File

@ -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

View File

@ -0,0 +1,4 @@
key "certbot" {
algorithm hmac-sha512;
secret "{{ lookup(passbolt, 'certbot', folder_parent_id=passbolt_folder).password }}";
};

View File

@ -0,0 +1,4 @@
{% for record in dns_records_delete %}
update delete {{ record.name.ljust(30) }} A
{% endfor %}
send

View File

@ -0,0 +1,4 @@
key "dhcp" {
algorithm hmac-sha512;
secret "{{ lookup(passbolt, 'dhcpkey', folder_parent_id=passbolt_folder).password }}";
};

View File

@ -0,0 +1,4 @@
{% for record in dns_records_main %}
update add {{ record.name.ljust(30) }} {{ record.ttl }} A {{ record.ip }}
{% endfor %}
send

View File

@ -0,0 +1,4 @@
{% for record in dns_records_secondary %}
update add {{ record.name.ljust(30) }} {{ record.ttl }} A {{ record.ip }}
{% endfor %}
send

View File

@ -0,0 +1,4 @@
key "lan" {
algorithm hmac-sha512;
secret "{{ lookup(passbolt, 'lankey', folder_parent_id=passbolt_folder).password }}";
};

View File

@ -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";

View File

@ -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"; };
};

View File

@ -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 %}
};

View File

@ -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 %}
};

View File

@ -0,0 +1,4 @@
key "rndc-key" {
algorithm hmac-md5;
secret "{{ lookup(passbolt, 'rndc-key', folder_parent_id=passbolt_folder).password }}";
};

View File

@ -0,0 +1,4 @@
key "wan-key" {
algorithm hmac-md5;
secret "{{ lookup(passbolt, 'wan-key', folder_parent_id=passbolt_folder).password }}";
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
#!/bin/bash
# Checks status of disks SMART
STATUS_LABEL="SMART Health Status:"
STATUS_OK="$STATUS_LABEL OK"
if [[ "$#" == "0" ]]; then
echo "Usage: $0 <disk1> [<disk2> ... <diskX>]"
exit
fi
for DISK in "$@"
do
STATUS=$(sudo /usr/sbin/smartctl -H -d scsi "$DISK" | grep "$STATUS_LABEL")
if [ "$STATUS" != "$STATUS_OK" ]; then
echo "CRITICAL: $DISK: $STATUS"
exit 2
fi
done
echo "OK: $STATUS_OK"

View File

@ -1,14 +1,20 @@
- name: Install PVE NRPE base packages
apt:
name:
- libxml-simple-perl
- libmonitoring-plugin-perl
state: present
- name: Set NRPE PVE configuration
copy:
src: nrpe.cfg
dest: /etc/nagios/nrpe.d/95-pve.cfg
src: nrpe.d/95-pve.cfg
dest: /etc/nagios/nrpe.d/
owner: root
group: root
mode: u=rw,g=r,o=r
notify: restart-nrpe
- name: Copy PVE NRPE plugins
copy:
src: nrpe/
src: plugins/
dest: /etc/nagios/plugins/
owner: root
group: root

View File

@ -7,8 +7,8 @@
group: root
register: copy_result
- name: Reboot the system if file was copied
reboot:
reboot_timeout: 600
become: true
when: copy_result.changed
#- name: Reboot the system if file was copied
# reboot:
# reboot_timeout: 600
# become: true
# when: copy_result.changed