From a1995f0e74d282b9496bb0a7ce7cc22a57792fe5 Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Fri, 17 Jun 2022 10:54:26 +0200 Subject: [PATCH 01/74] WIP: add vrrp addresses via Ansible --- vrrpd/defaults/main.yml | 13 ++++++++++ vrrpd/tasks/ip.yml | 20 ++++++++++++++++ vrrpd/tasks/main.yml | 42 +++++++++++++++++++++++++++++---- vrrpd/templates/vrrp.service.j2 | 11 +++++++++ 4 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 vrrpd/defaults/main.yml create mode 100644 vrrpd/tasks/ip.yml create mode 100644 vrrpd/templates/vrrp.service.j2 diff --git a/vrrpd/defaults/main.yml b/vrrpd/defaults/main.yml new file mode 100644 index 00000000..f5950a14 --- /dev/null +++ b/vrrpd/defaults/main.yml @@ -0,0 +1,13 @@ +--- + +vrrp_addresses: [] +# - { +# interface: Null # the interface name to run on +# delay: 10 # the advertisement interval (in sec) (default: 1) +# id: Null # the id of the virtual server [1-255] +# priority: Null # the priority of this host in the virtual server (default: 100) +# authentication: Null # authentification type: auth=(none|pw/hexkey|ah/hexkey) hexkey=0x[0-9a-fA-F]+ +# label: Null # use this name is syslog messages (helps when several vrid are running) +# ip: Null # the ip address(es) (and optionnaly subnet mask) of the virtual server +# state: Null # 'started' or 'stopped' +# } \ No newline at end of file diff --git a/vrrpd/tasks/ip.yml b/vrrpd/tasks/ip.yml new file mode 100644 index 00000000..38d75ccb --- /dev/null +++ b/vrrpd/tasks/ip.yml @@ -0,0 +1,20 @@ +--- + +- name: set unit name + set_fact: + vrrp_systemd_unit_name: "vrrp-{{ vrrp_address.id }}.service" + +- name: add systemd unit + template: + src: vrrp.service.j2 + dest: "/etc/systemd/system/vrrp-{{ vrrp_systemd_unit_name }}" + force: yes + register: vrrp_systemd_unit + +- name: enable and start systemd unit + systemd: + name: "{{ vrrp_systemd_unit_name }}" + daemon_reload: yes + enabled: yes + state: "{{ vrrp_address.state }}" + when: vrrp_systemd_unit is changed \ No newline at end of file diff --git a/vrrpd/tasks/main.yml b/vrrpd/tasks/main.yml index 5804cb39..44ebe65a 100644 --- a/vrrpd/tasks/main.yml +++ b/vrrpd/tasks/main.yml @@ -14,7 +14,36 @@ tags: - vrrpd -- name: Adjust sysctl config +- name: Adjust sysctl config (except rp_filter) + sysctl: + name: "{{ item.name }}" + value: "{{ item.value }}" + sysctl_file: /etc/sysctl.d/vrrpd.conf + sysctl_set: yes + state: present + loop: + - { name: 'net.ipv4.conf.all.arp_ignore', value: 1 } + - { name: 'net.ipv4.conf.all.arp_announce', value: 2 } + - { name: 'net.ipv4.ip_nonlocal_bind', value: 1 } + tags: + - vrrpd + +- name: look if rp_filter is managed by minifirewall + command: grep "SYSCTL_RP_FILTER=" /etc/default/minifirewall + failed_when: False + changed_when: False + check_mode: no + register: grep_sysctl_rp_filter_minifirewall + +- name: Configure SYSCTL_RP_FILTER in minifirewall + lineinfile: + dest: "/etc/default/minifirewall" + line: "SYSCTL_RP_FILTER='0'" + regexp: "SYSCTL_RP_FILTER=('|\").*('|\")" + create: no + when: grep_sysctl_rp_filter_minifirewall.rc == 0 + +- name: Adjust sysctl config (only rp_filter) sysctl: name: "{{ item.name }}" value: "{{ item.value }}" @@ -23,10 +52,13 @@ state: present loop: - { name: 'net.ipv4.conf.default.rp_filter', value: 0 } - - { name: 'net.ipv4.conf.eth0.rp_filter', value: 0 } - { name: 'net.ipv4.conf.all.rp_filter', value: 0 } - - { name: 'net.ipv4.conf.all.arp_ignore', value: 1 } - - { name: 'net.ipv4.conf.all.arp_announce', value: 2 } - - { name: 'net.ipv4.ip_nonlocal_bind', value: 1 } + when: grep_sysctl_rp_filter_minifirewall.rc != 0 tags: - vrrpd + +- name: Create VRRP address + include: ip.yml + loop: "{{ vrrp_addresses }}" + loop_control: + loop_var: "vrrp_address" \ No newline at end of file diff --git a/vrrpd/templates/vrrp.service.j2 b/vrrpd/templates/vrrp.service.j2 new file mode 100644 index 00000000..7bd588d7 --- /dev/null +++ b/vrrpd/templates/vrrp.service.j2 @@ -0,0 +1,11 @@ +[Unit] +Description=VRRP Daemon for IP {{ vrrp_address.ip }} on {{ vrrp_address.interface }} +After=network.target + +[Service] +ExecStart=/usr/sbin/vrrpd -i {{ vrrp_address.interface | mandatory }} -x -D -d {{ vrrp_address.delay | mandatory }} -v {{ vrrp_address.id | mandatory }} -p {{ vrrp_address.priority | mandatory }} -a {{ vrrp_address.authentication | mandatory }} -l {{ vrrp_address.label | mandatory }} {{ vrrp_address.ip | mandatory }} + +Type=forking + +[Install] +WantedBy=default.target \ No newline at end of file From 0f899dcd09f384d348b36eb357221e3e8c227536 Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Thu, 28 Jul 2022 13:58:09 +0200 Subject: [PATCH 02/74] evocheck: remove failure if deprecated variable is used --- CHANGELOG.md | 2 ++ evocheck/tasks/main.yml | 7 ------- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a162ae9..9761cf5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Removed +* evocheck: remove failure if deprecated variable is used + ### Security ## [22.07.1] 2022-07-28 diff --git a/evocheck/tasks/main.yml b/evocheck/tasks/main.yml index 2032740b..14c6988f 100644 --- a/evocheck/tasks/main.yml +++ b/evocheck/tasks/main.yml @@ -1,12 +1,5 @@ --- -- name: Package install is not supported anymore - fail: - msg: Package install is not supported anymore - when: - - evocheck_force_install is defined - - evocheck_force_install == "package" - - include: install.yml - include: cron.yml From 6c33e11d5fd46e21a2d48406d74d89068c15ed15 Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Thu, 28 Jul 2022 14:18:12 +0200 Subject: [PATCH 03/74] evocheck: upstream release 22.07.1 --- CHANGELOG.md | 2 ++ evocheck/files/evocheck.sh | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9761cf5e..502ee302 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Changed +* evocheck: upstream release 22.07.1 + ### Fixed ### Removed diff --git a/evocheck/files/evocheck.sh b/evocheck/files/evocheck.sh index 1bc54d79..8468c5cb 100644 --- a/evocheck/files/evocheck.sh +++ b/evocheck/files/evocheck.sh @@ -1226,18 +1226,18 @@ check_usrsharescripts() { check_sshpermitrootno() { sshd_args="-C addr=,user=,host=,laddr=,lport=0" if is_debian_jessie || is_debian_stretch; then - # Noop, we'll use the default $sshd_args + # Noop, we'll use the default $sshd_args : elif is_debian_buster; then - sshd_args="${sshd_args},rdomain=" + sshd_args="${sshd_args},rdomain=" else - # NOTE: From Debian Bullseye 11 onward, with OpenSSH 8.1, the argument + # NOTE: From Debian Bullseye 11 onward, with OpenSSH 8.1, the argument # -T doesn't require the additional -C. - sshd_args= + sshd_args= fi # shellcheck disable=SC2086 - if ! (sshd -T ${sshd_args} | grep -q 'permitrootlogin no'); then - failed "IS_SSHPERMITROOTNO" "PermitRoot should be set to no" + if ! (sshd -T ${sshd_args} 2> /dev/null | grep -qi 'permitrootlogin no'); then + failed "IS_SSHPERMITROOTNO" "PermitRoot should be set to no" fi } check_evomaintenanceusers() { From 9aa043d1abe315162788616a2bdc7bb5d5b4f535 Mon Sep 17 00:00:00 2001 From: David Prevot Date: Thu, 28 Jul 2022 17:24:43 +0200 Subject: [PATCH 04/74] CI: Use Jenkins only --- .Jenkinsfile | 4 ---- .drone.yml | 36 ------------------------------------ 2 files changed, 40 deletions(-) delete mode 100644 .drone.yml diff --git a/.Jenkinsfile b/.Jenkinsfile index 3f488638..67f84d95 100644 --- a/.Jenkinsfile +++ b/.Jenkinsfile @@ -21,11 +21,9 @@ pipeline { def major = versions[0] def minor = versions[0] + '.' + versions[1] def patch = version.trim() - /* No crendentials yet im.push(major) im.push(minor) im.push(patch) - */ } } } @@ -40,9 +38,7 @@ pipeline { im.inside { sh 'echo Test needed' } - /* No crendentials yet im.push('latest') - */ } } } diff --git a/.drone.yml b/.drone.yml deleted file mode 100644 index 514a8b3f..00000000 --- a/.drone.yml +++ /dev/null @@ -1,36 +0,0 @@ -kind: pipeline -name: default - -steps: -- name: build tagged docker image - image: plugins/docker - settings: - username: - from_secret: docker_username - password: - from_secret: docker_password - dockerfile: Dockerfile - repo: evolix/ansible-roles - auto_tag: true - environment: - ROLES_VERSION: $DRONE_COMMIT_SHA - when: - event: - - tag - -- name: build latest docker image - image: plugins/docker - settings: - username: - from_secret: docker_username - password: - from_secret: docker_password - dockerfile: Dockerfile - repo: evolix/ansible-roles - tags: latest - environment: - ROLES_VERSION: $DRONE_COMMIT_SHA - when: - branch: - - unstable - From 7e21b13d6a6de56709e18eed86e97d1128a27997 Mon Sep 17 00:00:00 2001 From: David Prevot Date: Fri, 29 Jul 2022 08:33:51 +0200 Subject: [PATCH 05/74] CI: Explicit registry credentials --- .Jenkinsfile | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.Jenkinsfile b/.Jenkinsfile index 67f84d95..3f591b98 100644 --- a/.Jenkinsfile +++ b/.Jenkinsfile @@ -21,9 +21,11 @@ pipeline { def major = versions[0] def minor = versions[0] + '.' + versions[1] def patch = version.trim() - im.push(major) - im.push(minor) - im.push(patch) + docker.withRegistry('', 'hub.docker') { + im.push(major) + im.push(minor) + im.push(patch) + } } } } @@ -38,7 +40,9 @@ pipeline { im.inside { sh 'echo Test needed' } - im.push('latest') + docker.withRegistry('', 'hub.docker') { + im.push('latest') + } } } } From 2ec3c91ed9b81f43933b609b4e8c1f5c2b1c0415 Mon Sep 17 00:00:00 2001 From: "William Hirigoyen (Evolix)" Date: Fri, 29 Jul 2022 16:33:03 +0200 Subject: [PATCH 06/74] [nagios-nrpe] Add check_ssl_local script --- nagios-nrpe/files/plugins/check_ssl_local | 69 +++++++++++++++++++++++ nagios-nrpe/templates/evolix.cfg.j2 | 1 + 2 files changed, 70 insertions(+) create mode 100755 nagios-nrpe/files/plugins/check_ssl_local diff --git a/nagios-nrpe/files/plugins/check_ssl_local b/nagios-nrpe/files/plugins/check_ssl_local new file mode 100755 index 00000000..d32cc40b --- /dev/null +++ b/nagios-nrpe/files/plugins/check_ssl_local @@ -0,0 +1,69 @@ +#!/bin/bash + +# Check permettant de monitorer une liste de certificats +# /etc/nagios/ssl_local.cfg +# +# Développé par Will (2022) +# + +certs_list_path=/etc/nagios/check_ssl_local_list.cfg + +# Dates in seconds +_10_days="864000" +_15_days="1296000" + +critical=0 +warning=0 + + +if [[ ! -f "$certs_list_path" ]]; then + touch "$certs_list_path" +fi + +certs_list=$(cat "$certs_list_path" | sed -E 's/(.*)#.*/\1/g' | grep -v -E '^$') + +for cert_path in $certs_list; do + + if [ ! -f "$cert_path" ]; then + >&2 echo "Warning: Cert file '$cert_path' does not exist." + warning=1 + continue + fi + + enddate=$(openssl x509 -noout -enddate -in "$cert_path" | cut -d'=' -f2) + + # Check cert expiré (critique) + if ! openssl x509 -checkend 0 -in "$cert_path" &> /dev/null; then + critical=1 + >&2 echo "Critical: Cert '$cert_path' has expired on $enddate." + continue + fi + + # Check cert expire < 10 jours (critique) + if ! openssl x509 -checkend "$_10_days" -in "$cert_path" &> /dev/null; then + critical=1 + >&2 echo "Critical: Cert '$cert_path' will expire on $enddate." + continue + fi + + # Check cert expire < 15 jours (warning) + if ! openssl x509 -checkend "$_15_days" -in "$cert_path" &> /dev/null; then + warning=1 + >&2 echo "Warning: Cert '$cert_path' will expire on $enddate." + continue + fi + + # Cert expire > 15 jours (OK) + echo "Cert '$cert_path' OK." + +done + +if [ $critical -eq 1 ]; then + exit 2 +elif [ $warning -eq 1 ]; then + exit 1 +else + exit 0 +fi + + diff --git a/nagios-nrpe/templates/evolix.cfg.j2 b/nagios-nrpe/templates/evolix.cfg.j2 index b007b3a8..5b8c1d28 100644 --- a/nagios-nrpe/templates/evolix.cfg.j2 +++ b/nagios-nrpe/templates/evolix.cfg.j2 @@ -48,6 +48,7 @@ command[check_redis]=/usr/lib/nagios/plugins/check_tcp -p 6379 command[check_clamd]=/usr/lib/nagios/plugins/check_clamd -H /var/run/clamav/clamd.ctl -v command[check_clamav_db]=/usr/lib/nagios/plugins/check_file_age -w 86400 -c 172800 -f /var/lib/clamav/evolix.ndb command[check_ssl]=/usr/lib/nagios/plugins/check_http -f follow -I 127.0.0.1 -S -p 443 -H ssl.evolix.net -C 15,5 +command[check_ssl_local]={{ nagios_plugins_directory }}/check_ssl_local command[check_elasticsearch]=/usr/lib/nagios/plugins/check_http -I 127.0.0.1 -u /_cat/health?h=st -p 9200 -r 'red' --invert-regex command[check_memcached]=/usr/lib/nagios/plugins/check_tcp -H 127.0.0.1 -p 11211 command[check_opendkim]=/usr/lib/nagios/plugins/check_tcp -H 127.0.0.1 -p 54321 From a91479a1b00962bf6f195d0fe5a2f3086a1401d2 Mon Sep 17 00:00:00 2001 From: "William Hirigoyen (Evolix)" Date: Fri, 29 Jul 2022 16:34:48 +0200 Subject: [PATCH 07/74] [nagios-nrpe] Fix unsecable space --- nagios-nrpe/files/plugins/check_ssl_local | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nagios-nrpe/files/plugins/check_ssl_local b/nagios-nrpe/files/plugins/check_ssl_local index d32cc40b..7c8d241e 100755 --- a/nagios-nrpe/files/plugins/check_ssl_local +++ b/nagios-nrpe/files/plugins/check_ssl_local @@ -1,7 +1,7 @@ #!/bin/bash # Check permettant de monitorer une liste de certificats -# /etc/nagios/ssl_local.cfg +# /etc/nagios/ssl_local.cfg # # Développé par Will (2022) # From 70225180eb0e7f843873b8f987633f677625c48b Mon Sep 17 00:00:00 2001 From: David Prevot Date: Mon, 1 Aug 2022 10:33:18 +0200 Subject: [PATCH 08/74] CI: Handle [ci skip] keyword --- .Jenkinsfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.Jenkinsfile b/.Jenkinsfile index 3f591b98..70cbc06a 100644 --- a/.Jenkinsfile +++ b/.Jenkinsfile @@ -6,6 +6,12 @@ pipeline { } stages { + stage('Check commit message') { + steps { + scmSkip(deleteBuild: true, skipPattern:'.*\\[ci skip\\].*') + } + } + stage('Build tagged docker image') { when { buildingTag() From 644793d2ecf4e202fc522ff80c7d184671ddb31e Mon Sep 17 00:00:00 2001 From: Alexis Ben Miloud--Josselin Date: Mon, 1 Aug 2022 17:43:00 +0200 Subject: [PATCH 09/74] Ajouter check_rabbitmq pour Python 3 --- rabbitmq/files/check_rabbitmq.python3 | 226 ++++++++++++++++++++++++++ rabbitmq/tasks/nrpe.yml | 11 ++ 2 files changed, 237 insertions(+) create mode 100644 rabbitmq/files/check_rabbitmq.python3 diff --git a/rabbitmq/files/check_rabbitmq.python3 b/rabbitmq/files/check_rabbitmq.python3 new file mode 100644 index 00000000..0a941dd4 --- /dev/null +++ b/rabbitmq/files/check_rabbitmq.python3 @@ -0,0 +1,226 @@ +#!/usr/bin/env python3 +from optparse import OptionParser +import shlex +import subprocess +import sys +import requests +import json + +if "check_output" not in dir( subprocess ): # duck punch it in! + def f(*popenargs, **kwargs): + if 'stdout' in kwargs: + raise ValueError('stdout argument not allowed, it will be overridden.') + process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs) + output, unused_err = process.communicate() + retcode = process.poll() + if retcode: + cmd = kwargs.get("args") + if cmd is None: + cmd = popenargs[0] + raise subprocess.CalledProcessError(retcode, cmd) + return output + subprocess.check_output = f + + +class RabbitCmdWrapper(object): + """So basically this just runs rabbitmqctl commands and returns parsed output. + Typically this means you need root privs for this to work. + Made this it's own class so it could be used in other monitoring tools + if desired.""" + + @classmethod + def list_connections(cls): + args = shlex.split("sudo rabbitmqctl list_connections") + cmd_result = subprocess.check_output(args, text=True).strip() + results = cls._parse_list_results(cmd_result) + return results + + @classmethod + def list_queues(cls): + args = shlex.split('sudo rabbitmqctl list_queues') + cmd_result = subprocess.check_output(args, text=True).strip() + results = cls._parse_list_results(cmd_result) + return results + + @classmethod + def status(cls): + args = shlex.split('sudo rabbitmqctl status') + cmd_result = subprocess.check_output(args, text=True).strip() + results = cls._parse_list_results(cmd_result) + return results + + @classmethod + def _parse_list_results(cls, result_string): + results = result_string.strip().split('\n') + #remove text fluff + if "Listing connections ..." in results: results.remove("Listing connections ...") + if "Listing queues ..." in results: results.remove("Listing queues ...") + return_data = [] + for row in results: + return_data.append(row.split('\t')) + return return_data + + +def check_connection_count(critical=0, warning=0): + """Checks to make sure the numbers of connections are within parameters.""" + try: + count = len(RabbitCmdWrapper.list_connections()) + if count >= critical: + print("CRITICAL - Connection Count %d" % count) + sys.exit(2) + elif count >= warning: + print("WARNING - Connection Count %d" % count) + sys.exit(1) + else: + print("OK - Connection Count %d" % count) + except Exception as err: + print("CRITICAL - %s" % err) + + +def check_queues_count(critical=1000, warning=1000): + """ + A blanket check to make sure all queues are within count parameters. + TODO: Possibly break this out so test can be done on individual queues. + """ + try: + critical_q = [] + warning_q = [] + results = RabbitCmdWrapper.list_queues() + for queue in results: + if queue.count == 2: + count = int(queue[1]) + if count >= critical: + critical_q.append("%s: %s" % (queue[0], count)) + elif count >= warning: + warning_q.append("%s: %s" % (queue[0], count)) + if critical_q: + print("CRITICAL - %s" % ", ".join(critical_q)) + sys.exit(2) + elif warning_q: + print("WARNING - %s" % ", ".join(warning_q)) + sys.exit(1) + else: + print("OK - NO QUEUES EXCEED THRESHOLDS") + sys.exit(0) + except Exception as err: + print("CRITICAL - %s" % err) + sys.exit(2) + +def check_mem_usage(critical=75, warning=50): + """Check to make sure the RAM usage of rabbitmq process does not exceed 50%% of its max""" + try: + results = RabbitCmdWrapper.status() + + for idx,val in enumerate(results): + if "memory," in str(val): + mem_used_raw = str(results[idx + 1]) + if "vm_memory_limit" in str(val): + mem_limit_raw = str(val) + + memory_used = float(filter(str.isdigit, mem_used_raw)) + memory_limit = float(filter(str.isdigit, mem_limit_raw)) + percent_usage = int(memory_used/memory_limit * 100) + + if percent_usage > critical: + print("CRITICAL - RABBITMQ RAM USAGE at %s%% of max" % percent_usage) + sys.exit(2) + elif percent_usage > warning: + print("WARNING - RABBITMQ RAM USAGE at %s%% of max" % percent_usage) + sys.exit(1) + else: + print("OK - RABBITMQ RAM USAGE OK at %s%% of max" % percent_usage) + sys.exit(0) + except Exception as err: + print("Critical - %s" % err) + sys.exit(2) + +def check_aliveness(username, password, timeout, cluster): + """Declares a test queue, then publishes and consumes a message. Intended for use by monitoring tools. If everything is working correctly, will return HTTP status 200 with body""" + try: + r = requests.get("http://%s:15672/api/aliveness-test/%%2F" % cluster, auth=(username, password), timeout=timeout) + except requests.exceptions.RequestException as e: # Throw error if rabbitmq is down + print("Critical - %s" % e) + sys.exit(2) + if r.status_code == 200: + print("OK - RABBITMQ Aliveness Test Returns: %s" % r) + sys.exit(0) + elif r.status_code != 200: + print("CRITICAL - RabbitMQ Error: %s" % r.content) + sys.exit(2) + else: + print("UNKNOWN - RABBITMQ Aliveness Test") + sys.ext(1) + +def check_cluster(username, password, timeout, cluster): + """Checks the health of a cluster, if a node is not running mark as offline """ + try: + url = "http://%s:15672/api/nodes" % cluster + r = requests.get(url, auth=(username, password), timeout=timeout) + except requests.exceptions.RequestException as e: # Throw error if no response + print("Critical - %s" % e) + sys.exit(2) + text = r.text + nodes = json.loads(text) + + running_nodes = [] + failed_nodes = [] + for node in nodes: + if not node['running']: + failed_nodes.append(node['name']) + if node['running']: + running_nodes.append(node['name']) + if len(failed_nodes) == 1: + print("WARNING: RabbitMQ cluster is degraged: Not running %s" % failed_nodes[0]) + sys.exit(1) + elif len(failed_nodes) >= 2: + print("CRITICAL: RabbitMQ cluster is critical: Not running %s" % failed_nodes) + sys.exit(2) + else: + print("OK: RabbitMQ cluster members: %s" % (" ".join(running_nodes))) + sys.exit(0) + + +USAGE = """Usage: ./check_rabbitmq -a [action] -C [critical] -W [warning] + Actions: + - connection_count + checks the number of connection in rabbitmq's list_connections + - queues_count + checks the count in each of the queues in rabbitmq's list_queues + - mem_usage + checks to ensure mem usage of rabbitmq process does not exceed 50% + - aliveness + Use the /api/aliveness-test API to send/receive a message. (requires -u username -p password args) + - cluster_status + Parse /api/nodes to check the cluster status. (requires -u username -p password""" + +if __name__ == "__main__": + parser = OptionParser(USAGE) + parser.add_option("-a", "--action", dest="action", + help="Action to Check") + parser.add_option("-C", "--critical", dest="critical", + type="int", help="Critical Threshold") + parser.add_option("-W", "--warning", dest="warning", + type="int", help="Warning Threshold") + parser.add_option("-u", "--username", dest="username", default="guest", + type="string", help="RabbitMQ username, Default guest") + parser.add_option("-p", "--password", dest="password", default="guest", + type="string", help="RabbitMQ password, Default guest") + parser.add_option("-t", "--timeout", dest="timeout", default=1, + type="int", help="Request Timeout, defaults to 1 second") + parser.add_option("-c", "--cluster", dest="cluster", default="localhost", + type="string", help="Cluster IP/DNS name, defaults to localhost") + (options, args) = parser.parse_args() + + if options.action == "connection_count": + check_connection_count(options.critical, options.warning) + elif options.action == "queues_count": + check_queues_count(options.critical, options.warning) + elif options.action == "mem_usage": + check_mem_usage(options.critical, options.warning) + elif options.action == "aliveness": + check_aliveness(options.username, options.password, options.timeout, options.cluster) + elif options.action == "cluster_status": + check_cluster(options.username, options.password, options.timeout, options.cluster) + else: + print("Invalid action: %s" % options.action) + print(USAGE) diff --git a/rabbitmq/tasks/nrpe.yml b/rabbitmq/tasks/nrpe.yml index 4272f57b..ba6b8d47 100644 --- a/rabbitmq/tasks/nrpe.yml +++ b/rabbitmq/tasks/nrpe.yml @@ -24,6 +24,17 @@ group: root mode: "0755" force: yes + when: ansible_distribution_major_version is version('11', '<=') + +- name: check_rabbitmq (Python 3 version) is installed + copy: + src: check_rabbitmq.python3 + dest: /usr/local/lib/nagios/plugins/check_rabbitmq + owner: root + group: root + mode: "0755" + force: yes + when: ansible_distribution_major_version is version('11', '==') - name: check_rabbitmq is available for NRPE lineinfile: From 6f5bad4a443159355d8bfc4eb107d06da7ee3747 Mon Sep 17 00:00:00 2001 From: "William Hirigoyen (Evolix)" Date: Tue, 2 Aug 2022 16:44:08 +0200 Subject: [PATCH 10/74] [nagios-nrpe] Add 401 error i expected default HTTP code of check_https --- nagios-nrpe/templates/evolix.cfg.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nagios-nrpe/templates/evolix.cfg.j2 b/nagios-nrpe/templates/evolix.cfg.j2 index 5b8c1d28..ae0e0abd 100644 --- a/nagios-nrpe/templates/evolix.cfg.j2 +++ b/nagios-nrpe/templates/evolix.cfg.j2 @@ -34,7 +34,7 @@ command[check_pop]=/usr/lib/nagios/plugins/check_pop -H localhost command[check_pops]=/usr/lib/nagios/plugins/check_pop -S -H localhost -p 995 command[check_ftp]=/usr/lib/nagios/plugins/check_ftp -H localhost command[check_http]=/usr/lib/nagios/plugins/check_http -e 301 -I 127.0.0.1 -H localhost -command[check_https]=/usr/lib/nagios/plugins/check_http -e 403 -I 127.0.0.1 -S -p 443 --sni -H ssl.evolix.net +command[check_https]=/usr/lib/nagios/plugins/check_http -e 401,403 -I 127.0.0.1 -S -p 443 --sni -H ssl.evolix.net command[check_bind]=/usr/lib/nagios/plugins/check_dig -l evolix.net -H localhost command[check_unbound]=/usr/lib/nagios/plugins/check_dig -l evolix.net -H localhost command[check_smb]=/usr/lib/nagios/plugins/check_tcp -H 127.0.0.1 -p 445 From f78e60d72af0506998e2670ffeaeb276a9788f18 Mon Sep 17 00:00:00 2001 From: David Prevot Date: Wed, 3 Aug 2022 13:55:39 +0200 Subject: [PATCH 11/74] Revert "CI: Handle [ci skip] keyword" This reverts commit 70225180eb0e7f843873b8f987633f677625c48b. --- .Jenkinsfile | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.Jenkinsfile b/.Jenkinsfile index 70cbc06a..3f591b98 100644 --- a/.Jenkinsfile +++ b/.Jenkinsfile @@ -6,12 +6,6 @@ pipeline { } stages { - stage('Check commit message') { - steps { - scmSkip(deleteBuild: true, skipPattern:'.*\\[ci skip\\].*') - } - } - stage('Build tagged docker image') { when { buildingTag() From 0748a090c34f68275a1d85b2c57a782c725d9539 Mon Sep 17 00:00:00 2001 From: "William Hirigoyen (Evolix)" Date: Fri, 5 Aug 2022 09:26:01 +0200 Subject: [PATCH 12/74] [evocheck] Add /etc/network/interfaces.d support --- evocheck/files/evocheck.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evocheck/files/evocheck.sh b/evocheck/files/evocheck.sh index 8468c5cb..ee1ee439 100644 --- a/evocheck/files/evocheck.sh +++ b/evocheck/files/evocheck.sh @@ -582,7 +582,7 @@ check_autoif() { interfaces=$(/sbin/ifconfig -s | tail -n +2 | grep -E -v "^(lo|vnet|docker|veth|tun|tap|macvtap|vrrp)" | cut -d " " -f 1 |tr "\n" " ") fi for interface in $interfaces; do - if ! grep -q "^auto $interface" /etc/network/interfaces; then + if ! grep -Rq "^auto $interface" /etc/network/interfaces*; then failed "IS_AUTOIF" "Network interface \`${interface}' is not set to auto" test "${VERBOSE}" = 1 || break fi From 141423f966815ce42af1a42889e76180603dbec8 Mon Sep 17 00:00:00 2001 From: Mathieu Trossevin Date: Wed, 10 Aug 2022 10:24:55 +0200 Subject: [PATCH 13/74] haproxy: Take into account haproxy_stats_path for munin --- haproxy/templates/munin.conf.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haproxy/templates/munin.conf.j2 b/haproxy/templates/munin.conf.j2 index 24042f66..149896b2 100644 --- a/haproxy/templates/munin.conf.j2 +++ b/haproxy/templates/munin.conf.j2 @@ -1,4 +1,4 @@ [haproxy_*] {% if haproxy_stats_internal_enable %} -env.url http://{{ haproxy_stats_internal_host }}:{{ haproxy_stats_internal_port }}/;csv;norefresh +env.url http://{{ haproxy_stats_internal_host }}:{{ haproxy_stats_internal_port }}{{ haproxy_stats_path }};csv;norefresh {% endif %} From 08a4f1ed5f710d7ea2642dd13cd5ccbd54971ba0 Mon Sep 17 00:00:00 2001 From: Mathieu Trossevin Date: Wed, 10 Aug 2022 10:26:37 +0200 Subject: [PATCH 14/74] Document previous change --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 502ee302..b27b7ff7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Fixed +* haproxy: make it so that munin doesn't break if there is a non default `haproxy_stats_path` + ### Removed * evocheck: remove failure if deprecated variable is used From 78dcec8656b2c24257a700152e0f1d078e3db52f Mon Sep 17 00:00:00 2001 From: Mathieu Trossevin Date: Wed, 10 Aug 2022 11:18:23 +0200 Subject: [PATCH 15/74] varnish: Repair systemd unit for jessie/stretch --- CHANGELOG.md | 1 + varnish/templates/varnish.conf.jessie.j2 | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b27b7ff7..b367df0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Fixed * haproxy: make it so that munin doesn't break if there is a non default `haproxy_stats_path` +* varnish: make `-j ` the first argument on jessie/stretch as it has to be the first argument there. ### Removed diff --git a/varnish/templates/varnish.conf.jessie.j2 b/varnish/templates/varnish.conf.jessie.j2 index f340323d..c3653708 100644 --- a/varnish/templates/varnish.conf.jessie.j2 +++ b/varnish/templates/varnish.conf.jessie.j2 @@ -2,6 +2,6 @@ [Service] ExecStart= -ExecStart=/usr/sbin/varnishd -F -j {{ varnish_jail }} {{ varnish_addresses | map('regex_replace', '^(.*)$', '-a \\1') | list | join(' ') }} -T {{ varnish_management_address }} -f {{ varnish_config_file }} -S {{ varnish_secret_file }} -s {{ varnish_storage }} -p thread_pools={{ varnish_thread_pools }} -p thread_pool_add_delay={{ varnish_thread_pool_add_delay }} -p thread_pool_min={{ varnish_thread_pool_min }} -p thread_pool_max={{ varnish_thread_pool_max }} +ExecStart=/usr/sbin/varnishd -j {{ varnish_jail }} -F {{ varnish_addresses | map('regex_replace', '^(.*)$', '-a \\1') | list | join(' ') }} -T {{ varnish_management_address }} -f {{ varnish_config_file }} -S {{ varnish_secret_file }} -s {{ varnish_storage }} -p thread_pools={{ varnish_thread_pools }} -p thread_pool_add_delay={{ varnish_thread_pool_add_delay }} -p thread_pool_min={{ varnish_thread_pool_min }} -p thread_pool_max={{ varnish_thread_pool_max }} ExecReload= ExecReload=/etc/varnish/reload-vcl.sh From de0c4fd31469d526b3d306bbe8ecaa7b5cda62b3 Mon Sep 17 00:00:00 2001 From: Jeremy Dubois Date: Wed, 10 Aug 2022 17:23:47 +0200 Subject: [PATCH 16/74] openvpn: automate the initialization of the CA and the creation of the server certificate ; use openssl_dhparam module instead of a command --- CHANGELOG.md | 1 + openvpn/tasks/debian.yml | 46 ++++++++++++++++++++++++++++++++------- openvpn/tasks/openbsd.yml | 46 ++++++++++++++++++++++++++++++++------- 3 files changed, 77 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b367df0b..d5203bc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Changed * evocheck: upstream release 22.07.1 +* openvpn: automate the initialization of the CA and the creation of the server certificate ; use openssl_dhparam module instead of a command ### Fixed diff --git a/openvpn/tasks/debian.yml b/openvpn/tasks/debian.yml index 4c2f6c5d..d6b03ac9 100644 --- a/openvpn/tasks/debian.yml +++ b/openvpn/tasks/debian.yml @@ -62,7 +62,9 @@ group: shellpki - name: Generate dhparam - command: "openssl dhparam -out /etc/shellpki/dh2048.pem 2048" + openssl_dhparam: + path: /etc/shellpki/dh2048.pem + size: 2048 - include_role: name: evolix/remount-usr @@ -239,7 +241,7 @@ - include_role: name: evolix/remount-usr -- name: Copy shellpki script +- name: Copy script to check expirations copy: src: "shellpki/cert-expirations.sh" dest: "/usr/share/scripts/cert-expirations.sh" @@ -253,15 +255,43 @@ special_time: monthly job: '/usr/share/scripts/cert-expirations.sh | mail -E -s "PKI VPN {{ ansible_hostname }} : recapitulatif expirations" {{ client_email }}' -- name: Warn the user about command to execute manually +- name: Generate the CA password + set_fact: + ca_pwd: "{{ lookup('password', '/dev/null length=25 chars=ascii_letters,digits') }}" + check_mode: no + changed_when: no + +- name: Initialization of the CA + shell: 'CA_PASSWORD="{{ ca_pwd }}" shellpki init --non-interactive {{ ansible_fqdn }}' + +- name: Creation of the server's certificate + shell: 'CA_PASSWORD="{{ ca_pwd }}" shellpki create --days 3650 --non-interactive {{ ansible_fqdn }}' + +- name: Get the server key + shell: 'ls -tr /etc/shellpki/private/ | tail -1' + register: ca_key + check_mode: no + changed_when: no + +- name: Configure the server key + replace: + path: /etc/openvpn/server.conf + regexp: 'key /etc/shellpki/private/TO_COMPLETE' + replace: 'key /etc/shellpki/private/{{ ca_key.stdout }}' + +- name: Restart OpenVPN + systemd: + name: "openvpn@server.service" + state: restarted + +- name: Warn the user about manual checks pause: prompt: | /!\ WARNING /!\ - You have to manually create the CA on the server with "shellpki init {{ ansible_fqdn }}". The command will ask you to create a password, and will ask you again to give the same one several times. - You have to manually generate the CRL on the server with "openssl ca -gencrl -keyfile /etc/shellpki/cakey.key -cert /etc/shellpki/cacert.pem -out /etc/shellpki/crl.pem -config /etc/shellpki/openssl.cnf". The previously created password will be asked. - You have to manually create the server's certificate with "shellpki create {{ ansible_fqdn }}". - You have to adjust the config file "/etc/openvpn/server.conf" for the following parameters : local (to check), cert (to check), key (to add), server (to check), push (to complete if needed). - Finally, you can (re)start the OpenVPN service with "systemctl restart openvpn@server.service". + You must check and adjust if necessary the configuration file "/etc/openvpn/server.conf", and then restart the OpenVPN service with "systemctl restart openvpn@server.service". + The "push" parameter may be needed to push a route to the client, so that the client can access that route through OpenVPN. + + Take note of the generated CA password and store it in your password manager : {{ ca_pwd }} Press enter to exit when it's done. diff --git a/openvpn/tasks/openbsd.yml b/openvpn/tasks/openbsd.yml index d3238cea..f5d9e4ff 100644 --- a/openvpn/tasks/openbsd.yml +++ b/openvpn/tasks/openbsd.yml @@ -56,7 +56,9 @@ group: _shellpki - name: Generate dhparam - command: "openssl dhparam -out /etc/shellpki/dh2048.pem 2048" + openssl_dhparam: + path: /etc/shellpki/dh2048.pem + size: 2048 - name: Fix CRL rights in shellpki command lineinfile: @@ -175,7 +177,7 @@ notify: restart nrpe when: nrpe_evolix_config.stat.exists -- name: Copy shellpki script +- name: Copy script to check expirations copy: src: "shellpki/cert-expirations.sh" dest: "/usr/share/scripts/cert-expirations.sh" @@ -189,15 +191,43 @@ special_time: monthly job: '/usr/share/scripts/cert-expirations.sh | mail -E -s "PKI VPN {{ ansible_hostname }} : recapitulatif expirations" {{ client_email }}' -- name: Warn the user about command to execute manually +- name: Generate the CA password + set_fact: + ca_pwd: "{{ lookup('password', '/dev/null length=25 chars=ascii_letters,digits') }}" + check_mode: no + changed_when: no + +- name: Initialization of the CA + shell: 'CA_PASSWORD="{{ ca_pwd }}" shellpki init --non-interactive {{ ansible_fqdn }}' + +- name: Creation of the server's certificate + shell: 'CA_PASSWORD="{{ ca_pwd }}" shellpki create --days 3650 --non-interactive {{ ansible_fqdn }}' + +- name: Get the server key + shell: 'ls -tr /etc/shellpki/private/ | tail -1' + register: ca_key + check_mode: no + changed_when: no + +- name: Configure the server key + replace: + path: /etc/openvpn/server.conf + regexp: 'key /etc/shellpki/private/TO_COMPLETE' + replace: 'key /etc/shellpki/private/{{ ca_key.stdout }}' + +- name: Restart OpenVPN + service: + name: openvpn + state: restarted + +- name: Warn the user about manual checks pause: prompt: | /!\ WARNING /!\ - You have to manually create the CA on the server with "shellpki init {{ ansible_fqdn }}". The command will ask you to create a password, and will ask you again to give the same one several times. - You have to manually generate the CRL on the server with "openssl ca -gencrl -keyfile /etc/shellpki/cakey.key -cert /etc/shellpki/cacert.pem -out /etc/shellpki/crl.pem -config /etc/shellpki/openssl.cnf". The previously created password will be asked. - You have to manually create the server's certificate with "shellpki create {{ ansible_fqdn }}". - You have to adjust the config file "/etc/openvpn/server.conf" for the following parameters : local (to check), cert (to check), key (to add), server (to check), push (to complete if needed). - Finally, you can (re)start the OpenVPN service with "rcctl restart openvpn". + You must check and adjust if necessary the configuration file "/etc/openvpn/server.conf", and then restart the OpenVPN service with "rcctl restart openvpn". + The "push" parameter may be needed to push a route to the client, so that the client can access that route through OpenVPN. + + Take note of the generated CA password and store it in your password manager : {{ ca_pwd }} Press enter to exit when it's done. From b47a2e46d935df6c987be391c5cad07edbeabbe1 Mon Sep 17 00:00:00 2001 From: "William Hirigoyen (Evolix)" Date: Thu, 11 Aug 2022 15:08:07 +0200 Subject: [PATCH 17/74] [nagios-nrpe] Ajout check_ssl_local --- nagios-nrpe/files/plugins/check_ssl_local | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nagios-nrpe/files/plugins/check_ssl_local b/nagios-nrpe/files/plugins/check_ssl_local index 7c8d241e..f3d10ced 100755 --- a/nagios-nrpe/files/plugins/check_ssl_local +++ b/nagios-nrpe/files/plugins/check_ssl_local @@ -24,8 +24,8 @@ certs_list=$(cat "$certs_list_path" | sed -E 's/(.*)#.*/\1/g' | grep -v -E '^$') for cert_path in $certs_list; do - if [ ! -f "$cert_path" ]; then - >&2 echo "Warning: Cert file '$cert_path' does not exist." + if [ ! -f "$cert_path" ] && [ ! -d "$cert_path" ]; then + >&2 echo "Warning: path '$cert_path' is not a file or a directory." warning=1 continue fi From 541efa78a3d538cd3414a4832e7307e5ee2ff5b3 Mon Sep 17 00:00:00 2001 From: "William Hirigoyen (Evolix)" Date: Thu, 11 Aug 2022 15:08:16 +0200 Subject: [PATCH 18/74] [nagios-nrpe] Ajout check_ssl_local --- nagios-nrpe/files/plugins/check_ssl_local | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nagios-nrpe/files/plugins/check_ssl_local b/nagios-nrpe/files/plugins/check_ssl_local index f3d10ced..860ed676 100755 --- a/nagios-nrpe/files/plugins/check_ssl_local +++ b/nagios-nrpe/files/plugins/check_ssl_local @@ -1,12 +1,12 @@ #!/bin/bash -# Check permettant de monitorer une liste de certificats +# Check permettant de monitorer une liste de certificats se trouvant dans # /etc/nagios/ssl_local.cfg # # Développé par Will (2022) # -certs_list_path=/etc/nagios/check_ssl_local_list.cfg +certs_list_path="/etc/nagios/check_ssl_local_list.cfg" # Dates in seconds _10_days="864000" From a55d06f58e7df9382a021c3534a39a5051febcee Mon Sep 17 00:00:00 2001 From: David Prevot Date: Wed, 17 Aug 2022 16:25:48 +0200 Subject: [PATCH 19/74] PHP: Install php-xml now that it has been split off --- lxc-php/tasks/php74.yml | 2 +- lxc-php/tasks/php80.yml | 2 +- lxc-php/tasks/php81.yml | 2 +- php/tasks/main_bullseye.yml | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lxc-php/tasks/php74.yml b/lxc-php/tasks/php74.yml index eaae77fd..64677009 100644 --- a/lxc-php/tasks/php74.yml +++ b/lxc-php/tasks/php74.yml @@ -3,7 +3,7 @@ - name: "{{ lxc_php_version }} - Install PHP packages" lxc_container: name: "{{ lxc_php_version }}" - container_command: "DEBIAN_FRONTEND=noninteractive apt install -y php-fpm php-cli php-gd php-intl php-imap php-ldap php-mysql php-pgsql php-sqlite3 php-curl php-zip php-mbstring php-zip composer libphp-phpmailer" + container_command: "DEBIAN_FRONTEND=noninteractive apt install -y php-fpm php-cli php-gd php-intl php-imap php-ldap php-mysql php-pgsql php-sqlite3 php-curl php-zip php-mbstring php-xml php-zip composer libphp-phpmailer" - name: "{{ lxc_php_version }} - fix bullseye repository" replace: diff --git a/lxc-php/tasks/php80.yml b/lxc-php/tasks/php80.yml index 4f725f0b..47039fe7 100644 --- a/lxc-php/tasks/php80.yml +++ b/lxc-php/tasks/php80.yml @@ -46,7 +46,7 @@ - name: "{{ lxc_php_version }} - Install PHP packages" lxc_container: name: "{{ lxc_php_version }}" - container_command: "DEBIAN_FRONTEND=noninteractive apt install -y php-fpm php-cli php-gd php-intl php-imap php-ldap php-mysql php-pgsql php-sqlite3 php-curl php-zip php-mbstring php-zip composer libphp-phpmailer" + container_command: "DEBIAN_FRONTEND=noninteractive apt install -y php-fpm php-cli php-gd php-intl php-imap php-ldap php-mysql php-pgsql php-sqlite3 php-curl php-zip php-mbstring php-xml php-zip composer libphp-phpmailer" - name: "{{ lxc_php_version }} - Copy evolinux PHP configuration" template: diff --git a/lxc-php/tasks/php81.yml b/lxc-php/tasks/php81.yml index f4498dd2..8883cbcc 100644 --- a/lxc-php/tasks/php81.yml +++ b/lxc-php/tasks/php81.yml @@ -46,7 +46,7 @@ - name: "{{ lxc_php_version }} - Install PHP packages" lxc_container: name: "{{ lxc_php_version }}" - container_command: "DEBIAN_FRONTEND=noninteractive apt install -y php-fpm php-cli php-gd php-intl php-imap php-ldap php-mysql php-pgsql php-sqlite3 php-curl php-zip php-mbstring php-zip composer libphp-phpmailer" + container_command: "DEBIAN_FRONTEND=noninteractive apt install -y php-fpm php-cli php-gd php-intl php-imap php-ldap php-mysql php-pgsql php-sqlite3 php-curl php-zip php-mbstring php-xml php-zip composer libphp-phpmailer" - name: "{{ lxc_php_version }} - Copy evolinux PHP configuration" template: diff --git a/php/tasks/main_bullseye.yml b/php/tasks/main_bullseye.yml index a1f7d5f5..403a7b76 100644 --- a/php/tasks/main_bullseye.yml +++ b/php/tasks/main_bullseye.yml @@ -30,6 +30,7 @@ - php-sqlite3 - php-curl - php-ssh2 + - php-xml - php-zip - composer - libphp-phpmailer From d0abfa985cc21b6d21819b7a007e4e64fc99ce9d Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Wed, 17 Aug 2022 16:53:05 +0200 Subject: [PATCH 20/74] redis: config directory must be owned by the user that runs the service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … to be able to write tmp config files in it --- CHANGELOG.md | 1 + redis/tasks/default-server.yml | 9 +++++++++ redis/tasks/instance-server.yml | 12 ++++++------ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5203bc7..4852a591 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * haproxy: make it so that munin doesn't break if there is a non default `haproxy_stats_path` * varnish: make `-j ` the first argument on jessie/stretch as it has to be the first argument there. +* redis: config directory must be owned by the user that runs the service (to be able to write tmp config files in it) ### Removed diff --git a/redis/tasks/default-server.yml b/redis/tasks/default-server.yml index 08653cfa..10b4d382 100644 --- a/redis/tasks/default-server.yml +++ b/redis/tasks/default-server.yml @@ -11,6 +11,15 @@ tags: - redis +- name: Config directory permissions are set + file: + dest: "{{ redis_conf_dir }}" + mode: "0750" + owner: redis + group: redis + tags: + - redis + - name: Redis is running and enabled on boot. systemd: name: "{{ redis_systemd_name }}" diff --git a/redis/tasks/instance-server.yml b/redis/tasks/instance-server.yml index 3e6af623..3f70733e 100644 --- a/redis/tasks/instance-server.yml +++ b/redis/tasks/instance-server.yml @@ -28,9 +28,9 @@ - name: "Instance '{{ redis_instance_name }}' config directory is present" file: dest: "{{ redis_conf_dir }}" - mode: "0755" - owner: "root" - group: "root" + mode: "0750" + owner: "redis-{{ redis_instance_name }}" + group: "redis-{{ redis_instance_name }}" follow: yes state: directory tags: @@ -39,9 +39,9 @@ - name: "Instance '{{ redis_instance_name }}' config hooks directories are present" file: dest: "{{ _dir }}" - mode: "0755" - owner: "root" - group: "root" + mode: "0750" + owner: "redis-{{ redis_instance_name }}" + group: "redis-{{ redis_instance_name }}" follow: yes state: directory loop: From 3bd4b9242520db21cd5d585cf91f4ad8fe7b67f4 Mon Sep 17 00:00:00 2001 From: David Prevot Date: Thu, 18 Aug 2022 10:27:08 +0200 Subject: [PATCH 21/74] CHANGELOG: Document previous ($self) change --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4852a591..a4d0f3a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Added +* php: install php-xml with recent PHP versions + ### Changed * evocheck: upstream release 22.07.1 From 1972826c79286d4ead1ac6b7756761673a905cc6 Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Fri, 19 Aug 2022 12:03:34 +0200 Subject: [PATCH 22/74] vrrpd: better process management in systemd unit --- vrrpd/templates/vrrp.service.j2 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/vrrpd/templates/vrrp.service.j2 b/vrrpd/templates/vrrp.service.j2 index 7bd588d7..4db5d7a9 100644 --- a/vrrpd/templates/vrrp.service.j2 +++ b/vrrpd/templates/vrrp.service.j2 @@ -4,8 +4,12 @@ After=network.target [Service] ExecStart=/usr/sbin/vrrpd -i {{ vrrp_address.interface | mandatory }} -x -D -d {{ vrrp_address.delay | mandatory }} -v {{ vrrp_address.id | mandatory }} -p {{ vrrp_address.priority | mandatory }} -a {{ vrrp_address.authentication | mandatory }} -l {{ vrrp_address.label | mandatory }} {{ vrrp_address.ip | mandatory }} - +# PIDFile=/var/run/vrrpd_{{ vrrp_address.label }}_{{ vrrp_address.id }}.pid +Restart=on-failure Type=forking +IgnoreSIGPIPE=no +KillMode=process +RemainAfterExit=yes [Install] WantedBy=default.target \ No newline at end of file From 9dfcfe1ef36afe920b06a87f6e97808018c81068 Mon Sep 17 00:00:00 2001 From: Patrick Marchand Date: Tue, 23 Aug 2022 17:45:19 -0400 Subject: [PATCH 23/74] Made it possible to only create a subset of users The evolinux_users_create variable is a list of tags that defaults to ['active']. Only the users that have one of the tags in the evolinux_users_create list will be created. --- CHANGELOG.md | 1 + evolinux-users/defaults/main.yml | 4 ++++ evolinux-users/tasks/main.yml | 4 +++- evolinux-users/tasks/ssh.yml | 1 + evolinux-users/tasks/sudo.yml | 4 ++++ 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4d0f3a6..b01a2bb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Added * php: install php-xml with recent PHP versions +* evolinux_user_create variable for evolinux-users that allows creating only a subset of users, defaults to active ### Changed diff --git a/evolinux-users/defaults/main.yml b/evolinux-users/defaults/main.yml index 8ff94551..cbe6bca4 100644 --- a/evolinux-users/defaults/main.yml +++ b/evolinux-users/defaults/main.yml @@ -6,3 +6,7 @@ evolinux_ssh_group: "evolinux-ssh" evolinux_internal_group: "" evolinux_root_disable_ssh: True + +# Defines which groups of users are created +evolinux_users_create: + - active \ No newline at end of file diff --git a/evolinux-users/tasks/main.yml b/evolinux-users/tasks/main.yml index 1b838e01..e8c52408 100644 --- a/evolinux-users/tasks/main.yml +++ b/evolinux-users/tasks/main.yml @@ -16,7 +16,9 @@ vars: user: "{{ item.value }}" loop: "{{ evolinux_users | dict2items }}" - when: evolinux_users | length > 0 + when: + - user.create | intersect(evolinux_users_create) | length > 0 + - evolinux_users | length > 0 - name: Configure sudo include: sudo.yml diff --git a/evolinux-users/tasks/ssh.yml b/evolinux-users/tasks/ssh.yml index b0bf8b58..16c4eb67 100644 --- a/evolinux-users/tasks/ssh.yml +++ b/evolinux-users/tasks/ssh.yml @@ -50,6 +50,7 @@ user: "{{ item.value }}" loop: "{{ evolinux_users | dict2items }}" when: + - user.create | intersect(evolinux_users_create) | length > 0 - ssh_allowusers - not ssh_allowgroups diff --git a/evolinux-users/tasks/sudo.yml b/evolinux-users/tasks/sudo.yml index 4056e7ad..fa537079 100644 --- a/evolinux-users/tasks/sudo.yml +++ b/evolinux-users/tasks/sudo.yml @@ -6,6 +6,7 @@ loop: "{{ evolinux_users | dict2items }}" when: - evolinux_users | length > 0 + - user.create | intersect(evolinux_users_create) | length > 0 - ansible_distribution_release == "jessie" @@ -16,6 +17,9 @@ vars: user: "{{ item.value }}" loop: "{{ evolinux_users | dict2items }}" + when: + - evolinux_users | length > 0 + - user.create | intersect(evolinux_users_create) | length > 0 when: - ansible_distribution_major_version is defined - ansible_distribution_major_version is version('9', '>=') From 2c1ec040d18ba3c7b3417e421b3fbfcf848d6e18 Mon Sep 17 00:00:00 2001 From: Patrick Marchand Date: Wed, 24 Aug 2022 09:05:29 -0400 Subject: [PATCH 24/74] Simplify user subset creation Instead of tags, allow only one subset of users to be created at a time. --- CHANGELOG.md | 2 +- evolinux-users/defaults/main.yml | 3 +-- evolinux-users/tasks/main.yml | 2 +- evolinux-users/tasks/ssh.yml | 2 +- evolinux-users/tasks/sudo.yml | 4 ++-- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b01a2bb1..d4405a2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Added * php: install php-xml with recent PHP versions -* evolinux_user_create variable for evolinux-users that allows creating only a subset of users, defaults to active +* evolinux_user_create variable for evolinux-users that allows creating only a subset of users, defaults to always ### Changed diff --git a/evolinux-users/defaults/main.yml b/evolinux-users/defaults/main.yml index cbe6bca4..658e4a31 100644 --- a/evolinux-users/defaults/main.yml +++ b/evolinux-users/defaults/main.yml @@ -8,5 +8,4 @@ evolinux_internal_group: "" evolinux_root_disable_ssh: True # Defines which groups of users are created -evolinux_users_create: - - active \ No newline at end of file +evolinux_users_create: always \ No newline at end of file diff --git a/evolinux-users/tasks/main.yml b/evolinux-users/tasks/main.yml index e8c52408..d105aefe 100644 --- a/evolinux-users/tasks/main.yml +++ b/evolinux-users/tasks/main.yml @@ -17,7 +17,7 @@ user: "{{ item.value }}" loop: "{{ evolinux_users | dict2items }}" when: - - user.create | intersect(evolinux_users_create) | length > 0 + - user.create == evolinux_users_create - evolinux_users | length > 0 - name: Configure sudo diff --git a/evolinux-users/tasks/ssh.yml b/evolinux-users/tasks/ssh.yml index 16c4eb67..25a08297 100644 --- a/evolinux-users/tasks/ssh.yml +++ b/evolinux-users/tasks/ssh.yml @@ -50,7 +50,7 @@ user: "{{ item.value }}" loop: "{{ evolinux_users | dict2items }}" when: - - user.create | intersect(evolinux_users_create) | length > 0 + - user.create == evolinux_users_create - ssh_allowusers - not ssh_allowgroups diff --git a/evolinux-users/tasks/sudo.yml b/evolinux-users/tasks/sudo.yml index fa537079..769e7a4e 100644 --- a/evolinux-users/tasks/sudo.yml +++ b/evolinux-users/tasks/sudo.yml @@ -6,7 +6,7 @@ loop: "{{ evolinux_users | dict2items }}" when: - evolinux_users | length > 0 - - user.create | intersect(evolinux_users_create) | length > 0 + - user.create == evolinux_users_create - ansible_distribution_release == "jessie" @@ -19,7 +19,7 @@ loop: "{{ evolinux_users | dict2items }}" when: - evolinux_users | length > 0 - - user.create | intersect(evolinux_users_create) | length > 0 + - user.create == evolinux_users_create when: - ansible_distribution_major_version is defined - ansible_distribution_major_version is version('9', '>=') From 018eee7ea088464aa67316c65dac56dfead0fe1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lecour?= Date: Wed, 24 Aug 2022 15:22:25 +0200 Subject: [PATCH 25/74] Update 'CHANGELOG.md' * use role name * more descriptive message * order items alphabetically --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4405a2b..09d25126 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,8 +12,8 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Added +* evolinux_users: create only users who have a certain value for the `create` key (default: `always`). * php: install php-xml with recent PHP versions -* evolinux_user_create variable for evolinux-users that allows creating only a subset of users, defaults to always ### Changed From 8e7c3a47aa52a950bae6bcbf2e80a7ba27c93c08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lecour?= Date: Wed, 24 Aug 2022 15:24:54 +0200 Subject: [PATCH 26/74] Update 'evolinux-users/README.md' Add a `create` key in examples --- evolinux-users/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/evolinux-users/README.md b/evolinux-users/README.md index c0f6e9ef..9c7beab4 100644 --- a/evolinux-users/README.md +++ b/evolinux-users/README.md @@ -19,6 +19,7 @@ evolinux_users: groups: "baz" password_hash: 'sdfgsdfgsdfgsdfg' ssh_key: 'ssh-rsa AZERTYXYZ' + create: always bar: name: bar uid: 1002 @@ -30,6 +31,7 @@ evolinux_users: ssh_keys: - 'ssh-rsa QWERTYUIOP' - 'ssh-ed25519 QWERTYUIOP' + create: on_demand ``` * `evolinux_sudo_group`: which group to use for sudo (default: `evolinux-sudo`) From bd6c7792a84f85ddedbf5243ac65dfa544c5321f Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Wed, 24 Aug 2022 17:57:27 +0200 Subject: [PATCH 27/74] vrrpd: Fix systemd service name file --- vrrpd/tasks/ip.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vrrpd/tasks/ip.yml b/vrrpd/tasks/ip.yml index 38d75ccb..59594395 100644 --- a/vrrpd/tasks/ip.yml +++ b/vrrpd/tasks/ip.yml @@ -7,7 +7,7 @@ - name: add systemd unit template: src: vrrp.service.j2 - dest: "/etc/systemd/system/vrrp-{{ vrrp_systemd_unit_name }}" + dest: "/etc/systemd/system/{{ vrrp_systemd_unit_name }}" force: yes register: vrrp_systemd_unit From 5fa7f4809c6ea7c238a92ed2315e780d69a9d5b2 Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Wed, 24 Aug 2022 17:58:44 +0200 Subject: [PATCH 28/74] vrrp: fix systemd unit name --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09d25126..92e9da42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * evolinux_users: create only users who have a certain value for the `create` key (default: `always`). * php: install php-xml with recent PHP versions +* vrrp: add an `ip.yml` task file to help create VRRP addresses ### Changed From f1485451ef23c5c7aee17b54d6750c0e578149ca Mon Sep 17 00:00:00 2001 From: Eric Morino Date: Thu, 25 Aug 2022 17:35:10 +0200 Subject: [PATCH 29/74] =?UTF-8?q?rendu=20compatible=20le=20r=C3=B4le=20ave?= =?UTF-8?q?c=20apache=20pour=20nextcloud01?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- webapps/nextcloud/handlers/main.yml | 5 +++ webapps/nextcloud/tasks/main.yml | 9 +++- webapps/nextcloud/tasks/vhost-apache.yml | 24 ++++++++++ .../tasks/{vhost.yml => vhost-nginx.yml} | 0 webapps/nextcloud/templates/apache.conf.j2 | 44 +++++++++++++++++++ 5 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 webapps/nextcloud/tasks/vhost-apache.yml rename webapps/nextcloud/tasks/{vhost.yml => vhost-nginx.yml} (100%) create mode 100644 webapps/nextcloud/templates/apache.conf.j2 diff --git a/webapps/nextcloud/handlers/main.yml b/webapps/nextcloud/handlers/main.yml index 2db4770d..46b3b014 100644 --- a/webapps/nextcloud/handlers/main.yml +++ b/webapps/nextcloud/handlers/main.yml @@ -8,3 +8,8 @@ service: name: nginx state: reloaded + +- name: reload apache + service: + name: apache2 + state: reloaded \ No newline at end of file diff --git a/webapps/nextcloud/tasks/main.yml b/webapps/nextcloud/tasks/main.yml index a6d39b4b..7ce81693 100644 --- a/webapps/nextcloud/tasks/main.yml +++ b/webapps/nextcloud/tasks/main.yml @@ -45,7 +45,14 @@ - include: archive.yml -- include: vhost.yml +- name: Check if Apache or Nginx + service_facts: + +- include: vhost-nginx.yml + when: "'nginx.service' in services" + +- include: vhost-apache.yml + when: "'apache2.service' in services" - include: mysql.yml diff --git a/webapps/nextcloud/tasks/vhost-apache.yml b/webapps/nextcloud/tasks/vhost-apache.yml new file mode 100644 index 00000000..595c283b --- /dev/null +++ b/webapps/nextcloud/tasks/vhost-apache.yml @@ -0,0 +1,24 @@ +--- +- block: + - name: Copy Apache vhost + template: + src: apache.conf.j2 + dest: "/etc/apache2/sites-available/{{ nextcloud_instance_name }}.conf" + mode: "0640" + notify: reload apache + tags: + - nextcloud + + - name: Enable Apache vhost + file: + src: "/etc/apache2/sites-available/{{ nextcloud_instance_name }}.conf" + dest: "/etc/apache2/sites-enabled/{{ nextcloud_instance_name }}.conf" + state: link + notify: reload apache + tags: + - nextcloud + + # - name: Generate ssl config + # shell: + # cmd: "/usr/local/sbin/vhost-domains {{ nextcloud_instance_name }} | /usr/local/sbin/make-csr {{ nextcloud_instance_name }}" + # creates: "/etc/nginx/ssl/{{ nextcloud_instance_name }}.conf" \ No newline at end of file diff --git a/webapps/nextcloud/tasks/vhost.yml b/webapps/nextcloud/tasks/vhost-nginx.yml similarity index 100% rename from webapps/nextcloud/tasks/vhost.yml rename to webapps/nextcloud/tasks/vhost-nginx.yml diff --git a/webapps/nextcloud/templates/apache.conf.j2 b/webapps/nextcloud/templates/apache.conf.j2 new file mode 100644 index 00000000..bb41efab --- /dev/null +++ b/webapps/nextcloud/templates/apache.conf.j2 @@ -0,0 +1,44 @@ + + ServerName {{ nextcloud_domains | join(' ') }} + + DocumentRoot {{ nextcloud_webroot }}/ + + + Require all granted + AllowOverride All + Options FollowSymLinks MultiViews + + + Dav off + + + + # user - group (thanks to sesse@debian.org) + AssignUserID {{ nextcloud_instance_name }} {{ nextcloud_instance_name }} + + # LOG + CustomLog /var/log/apache2/access.log vhost_combined + CustomLog /home/{{ nextcloud_instance_name }}/log/access.log combined + ErrorLog /home/{{ nextcloud_instance_name }}/log/error.log + + # REWRITE + UseCanonicalName On + RewriteEngine On + RewriteCond %{HTTP_HOST} !^{{ nextcloud_domains | join(' ') }}$ + RewriteRule ^/(.*) http://%{SERVER_NAME}/$1 [L,R] + + # PHP + #php_admin_flag engine off + #AddType text/html .html + #php_admin_flag display_errors On + #php_flag short_open_tag On + #php_flag register_globals On + #php_admin_value memory_limit 256M + #php_admin_value max_execution_time 60 + #php_admin_value upload_max_filesize 8M + #php_admin_flag allow_url_fopen Off + #php_value default_charset ISO-8859-15 + php_admin_value sendmail_path "/usr/sbin/sendmail -t -i -f {{ nextcloud_instance_name }}" + php_admin_value open_basedir "/usr/share/php:/home/{{ nextcloud_instance_name }}:/tmp" + + \ No newline at end of file From aee925d667d19277e8ac9d134644223fb5b6d7ec Mon Sep 17 00:00:00 2001 From: Eric Morino Date: Fri, 26 Aug 2022 16:28:30 +0200 Subject: [PATCH 30/74] Add php configuration for apache and cli globaly --- .../files/zzz-apache2-evolinux-custom.ini | 20 ++++++++++++++++ .../files/zzz-cli-evolinux-custom.ini | 4 ++++ webapps/nextcloud/tasks/vhost-apache.yml | 24 +++++++++++++++++++ webapps/nextcloud/templates/apache.conf.j2 | 10 -------- 4 files changed, 48 insertions(+), 10 deletions(-) create mode 100644 webapps/nextcloud/files/zzz-apache2-evolinux-custom.ini create mode 100644 webapps/nextcloud/files/zzz-cli-evolinux-custom.ini diff --git a/webapps/nextcloud/files/zzz-apache2-evolinux-custom.ini b/webapps/nextcloud/files/zzz-apache2-evolinux-custom.ini new file mode 100644 index 00000000..361628c2 --- /dev/null +++ b/webapps/nextcloud/files/zzz-apache2-evolinux-custom.ini @@ -0,0 +1,20 @@ +; Put customized values here. +allow_url_fopen = On +disable_functions = exec,shell-exec,system,passthru,popen +disable_functions = +user_ini.filename = ".user.ini" +max_execution_time = 300 + +memory_limit = 512M + +opcache.enable=1 +opcache.enable_cli=1 +opcache.interned_strings_buffer=24 +opcache.max_accelerated_files=60000 +opcache.memory_consumption=512 +opcache.save_comments=1 +opcache.revalidate_freq=1 + + +upload_max_filesize = 2G +post_max_size = 2G \ No newline at end of file diff --git a/webapps/nextcloud/files/zzz-cli-evolinux-custom.ini b/webapps/nextcloud/files/zzz-cli-evolinux-custom.ini new file mode 100644 index 00000000..f6785459 --- /dev/null +++ b/webapps/nextcloud/files/zzz-cli-evolinux-custom.ini @@ -0,0 +1,4 @@ +; Put customized values here. +; default_charset = "ISO-8859-1" +allow_url_fopen = On +apc.enable_cli=1 \ No newline at end of file diff --git a/webapps/nextcloud/tasks/vhost-apache.yml b/webapps/nextcloud/tasks/vhost-apache.yml index 595c283b..b710b07a 100644 --- a/webapps/nextcloud/tasks/vhost-apache.yml +++ b/webapps/nextcloud/tasks/vhost-apache.yml @@ -17,6 +17,30 @@ notify: reload apache tags: - nextcloud + + - name: Enable apache2 php configuration + copy: + src: "zzz-apache2-evolinux-custom.ini" + dest: "/etc/php/7.4/apache2/conf.d/zzz-evolinux-custom.ini" + mode: "0644" + owner: root + group: root + force: yes + notify: reload apache + tags: + - nextcloud + + - name: Enable cli php configuration + copy: + src: "zzz-cli-evolinux-custom.ini" + dest: "/etc/php/7.4/cli/conf.d/zzz-evolinux-custom.ini" + mode: "0644" + owner: root + group: root + force: yes + notify: reload apache + tags: + - nextcloud # - name: Generate ssl config # shell: diff --git a/webapps/nextcloud/templates/apache.conf.j2 b/webapps/nextcloud/templates/apache.conf.j2 index bb41efab..20a4d2eb 100644 --- a/webapps/nextcloud/templates/apache.conf.j2 +++ b/webapps/nextcloud/templates/apache.conf.j2 @@ -28,16 +28,6 @@ RewriteRule ^/(.*) http://%{SERVER_NAME}/$1 [L,R] # PHP - #php_admin_flag engine off - #AddType text/html .html - #php_admin_flag display_errors On - #php_flag short_open_tag On - #php_flag register_globals On - #php_admin_value memory_limit 256M - #php_admin_value max_execution_time 60 - #php_admin_value upload_max_filesize 8M - #php_admin_flag allow_url_fopen Off - #php_value default_charset ISO-8859-15 php_admin_value sendmail_path "/usr/sbin/sendmail -t -i -f {{ nextcloud_instance_name }}" php_admin_value open_basedir "/usr/share/php:/home/{{ nextcloud_instance_name }}:/tmp" From 9a25d5981f1f669e78265d141dd1ba92ef80a167 Mon Sep 17 00:00:00 2001 From: Eric Morino Date: Fri, 26 Aug 2022 16:34:19 +0200 Subject: [PATCH 31/74] add webapps/nextcloud changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92e9da42..eb9a8ce2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * evolinux_users: create only users who have a certain value for the `create` key (default: `always`). * php: install php-xml with recent PHP versions * vrrp: add an `ip.yml` task file to help create VRRP addresses +* webapps/nextcloud: Add compatibility with apache2, and apache2 mod_php. ### Changed From 71aafe161ce52b748c0b6a5eebd24afde6b5bd28 Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Mon, 29 Aug 2022 16:47:12 +0200 Subject: [PATCH 32/74] evocheck: upstream release 22.08 --- CHANGELOG.md | 2 +- evocheck/files/evocheck.sh | 339 ++++++++++++------------------------- 2 files changed, 109 insertions(+), 232 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb9a8ce2..323f0c13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Changed -* evocheck: upstream release 22.07.1 +* evocheck: upstream release 22.08 * openvpn: automate the initialization of the CA and the creation of the server certificate ; use openssl_dhparam module instead of a command ### Fixed diff --git a/evocheck/files/evocheck.sh b/evocheck/files/evocheck.sh index ee1ee439..e924debd 100644 --- a/evocheck/files/evocheck.sh +++ b/evocheck/files/evocheck.sh @@ -1,10 +1,10 @@ #!/bin/bash # EvoCheck -# Script to verify compliance of a Debian/OpenBSD server +# Script to verify compliance of a Linux (Debian) server # powered by Evolix -VERSION="22.07" +VERSION="22.08" readonly VERSION # base functions @@ -30,7 +30,7 @@ END } show_help() { cat < /dev/null 2>&1 || failed "IS_VIM" - fi - - if [ "${IS_TTYC0SECURE:=1}" = 1 ]; then - grep -Eqv "^ttyC0.*secure$" /etc/ttys || failed "IS_TTYC0SECURE" - fi - - if [ "${IS_CUSTOMSYSLOG:=1}" = 1 ]; then - grep -q "Evolix" /etc/newsyslog.conf || failed "IS_CUSTOMSYSLOG" - fi - - if [ "${IS_NOINETD:=1}" = 1 ]; then - grep -q "inetd=NO" /etc/rc.conf.local 2>/dev/null || failed "IS_NOINETD" - fi - - if [ "${IS_SUDOMAINT:=1}" = 1 ]; then - f=/etc/sudoers - { grep -q "Cmnd_Alias MAINT = /usr/share/scripts/evomaintenance.sh" $f \ - && grep -q "ADMIN ALL=NOPASSWD: MAINT" $f; - } || failed "IS_SUDOMAINT" - fi - - if [ "${IS_POSTGRESQL:=1}" = 1 ]; then - pkg info | grep -q postgresql-client || failed "IS_POSTGRESQL" "postgresql-client is not installed" - fi - - if [ "${IS_NRPE:=1}" = 1 ]; then - { pkg info | grep -qE "nagios-plugins-[0-9.]" \ - && pkg info | grep -q nagios-plugins-ntp \ - && pkg info | grep -q nrpe; - } || failed "IS_NRPE" "NRPE is not installed" - fi - - # if [ "${IS_NRPEDISKS:=1}" = 1 ]; then - # NRPEDISKS=$(grep command.check_disk /etc/nrpe.cfg 2>/dev/null | grep "^command.check_disk[0-9]" | sed -e "s/^command.check_disk\([0-9]\+\).*/\1/" | sort -n | tail -1) - # DFDISKS=$(df -Pl | grep -E -v "(^Filesystem|/lib/init/rw|/dev/shm|udev|rpc_pipefs)" | wc -l) - # [ "$NRPEDISKS" = "$DFDISKS" ] || failed "IS_NRPEDISKS" - # fi - - # Verification du check_mailq dans nrpe.cfg (celui-ci doit avoir l'option "-M postfix" si le MTA est Postfix) - # - # if [ "${IS_NRPEPOSTFIX:=1}" = 1 ]; then - # pkg info | grep -q postfix && ( grep -q "^command.*check_mailq -M postfix" /etc/nrpe.cfg 2>/dev/null || failed "IS_NRPEPOSTFIX" ) - # fi - - if [ "${IS_NRPEDAEMON:=1}" = 1 ]; then - grep -q "echo -n ' nrpe'; /usr/local/sbin/nrpe -d" /etc/rc.local \ - || failed "IS_NREPEDAEMON" - fi - - if [ "${IS_ALERTBOOT:=1}" = 1 ]; then - grep -qE "^date \| mail -sboot/reboot .*evolix.fr$" /etc/rc.local \ - || failed "IS_ALERTBOOT" - fi - - if [ "${IS_RSYNC:=1}" = 1 ]; then - pkg info | grep -q rsync || failed "IS_RSYNC" - fi - - if [ "${IS_CRONPATH:=1}" = 1 ]; then - grep -q "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin" /var/cron/tabs/root \ - || failed "IS_CRONPATH" - fi - - #TODO - # - Check en profondeur de postfix - # - NRPEDISK et NRPEPOSTFIX - fi + test "${IS_LSBRELEASE:=1}" = 1 && check_lsbrelease + test "${IS_DPKGWARNING:=1}" = 1 && check_dpkgwarning + test "${IS_UMASKSUDOERS:=1}" = 1 && check_umasksudoers + test "${IS_NRPEPOSTFIX:=1}" = 1 && check_nrpepostfix + test "${IS_MODSECURITY:=1}" = 1 && check_modsecurity + test "${IS_CUSTOMSUDOERS:=1}" = 1 && check_customsudoers + test "${IS_VARTMPFS:=1}" = 1 && check_vartmpfs + test "${IS_SERVEURBASE:=1}" = 1 && check_serveurbase + test "${IS_LOGROTATECONF:=1}" = 1 && check_logrotateconf + test "${IS_SYSLOGCONF:=1}" = 1 && check_syslogconf + test "${IS_DEBIANSECURITY:=1}" = 1 && check_debiansecurity + test "${IS_APTITUDEONLY:=1}" = 1 && check_aptitudeonly + test "${IS_APTITUDE:=1}" = 1 && check_aptitude + test "${IS_APTGETBAK:=1}" = 1 && check_aptgetbak + test "${IS_APTICRON:=0}" = 1 && check_apticron + test "${IS_USRRO:=1}" = 1 && check_usrro + test "${IS_TMPNOEXEC:=1}" = 1 && check_tmpnoexec + test "${IS_MOUNT_FSTAB:=1}" = 1 && check_mountfstab + test "${IS_LISTCHANGESCONF:=1}" = 1 && check_listchangesconf + test "${IS_CUSTOMCRONTAB:=1}" = 1 && check_customcrontab + test "${IS_SSHALLOWUSERS:=1}" = 1 && check_sshallowusers + test "${IS_DISKPERF:=0}" = 1 && check_diskperf + test "${IS_TMOUTPROFILE:=1}" = 1 && check_tmoutprofile + test "${IS_ALERT5BOOT:=1}" = 1 && check_alert5boot + test "${IS_ALERT5MINIFW:=1}" = 1 && check_alert5minifw + test "${IS_ALERT5MINIFW:=1}" = 1 && test "${IS_MINIFW:=1}" = 1 && check_minifw + test "${IS_NRPEPERMS:=1}" = 1 && check_nrpeperms + test "${IS_MINIFWPERMS:=1}" = 1 && check_minifwperms + # Enable when minifirewall is released + test "${IS_MINIFWINCLUDES:=0}" = 1 && check_minifw_includes + test "${IS_NRPEDISKS:=0}" = 1 && check_nrpedisks + test "${IS_NRPEPID:=1}" = 1 && check_nrpepid + test "${IS_GRSECPROCS:=1}" = 1 && check_grsecprocs + test "${IS_APACHEMUNIN:=1}" = 1 && check_apachemunin + test "${IS_MYSQLUTILS:=1}" = 1 && check_mysqlutils + test "${IS_RAIDSOFT:=1}" = 1 && check_raidsoft + test "${IS_AWSTATSLOGFORMAT:=1}" = 1 && check_awstatslogformat + test "${IS_MUNINLOGROTATE:=1}" = 1 && check_muninlogrotate + test "${IS_SQUID:=1}" = 1 && check_squid + test "${IS_EVOMAINTENANCE_FW:=1}" = 1 && check_evomaintenance_fw + test "${IS_MODDEFLATE:=1}" = 1 && check_moddeflate + test "${IS_LOG2MAILRUNNING:=1}" = 1 && check_log2mailrunning + test "${IS_LOG2MAILAPACHE:=1}" = 1 && check_log2mailapache + test "${IS_LOG2MAILMYSQL:=1}" = 1 && check_log2mailmysql + test "${IS_LOG2MAILSQUID:=1}" = 1 && check_log2mailsquid + test "${IS_BINDCHROOT:=1}" = 1 && check_bindchroot + test "${IS_REPVOLATILE:=1}" = 1 && check_repvolatile + test "${IS_NETWORK_INTERFACES:=1}" = 1 && check_network_interfaces + test "${IS_AUTOIF:=1}" = 1 && check_autoif + test "${IS_INTERFACESGW:=1}" = 1 && check_interfacesgw + test "${IS_NETWORKING_SERVICE:=1}" = 1 && check_networking_service + test "${IS_EVOBACKUP:=1}" = 1 && check_evobackup + test "${IS_EVOBACKUP_EXCLUDE_MOUNT:=1}" = 1 && check_evobackup_exclude_mount + test "${IS_USERLOGROTATE:=1}" = 1 && check_userlogrotate + test "${IS_APACHECTL:=1}" = 1 && check_apachectl + test "${IS_APACHESYMLINK:=1}" = 1 && check_apachesymlink + test "${IS_APACHEIPINALLOW:=1}" = 1 && check_apacheipinallow + test "${IS_MUNINAPACHECONF:=1}" = 1 && check_muninapacheconf + test "${IS_SAMBAPINPRIORITY:=1}" = 1 && check_sambainpriority + test "${IS_KERNELUPTODATE:=1}" = 1 && check_kerneluptodate + test "${IS_UPTIME:=1}" = 1 && check_uptime + test "${IS_MUNINRUNNING:=1}" = 1 && check_muninrunning + test "${IS_BACKUPUPTODATE:=1}" = 1 && check_backupuptodate + test "${IS_ETCGIT:=1}" = 1 && check_etcgit + test "${IS_GITPERMS:=1}" = 1 && check_gitperms + test "${IS_NOTUPGRADED:=1}" = 1 && check_notupgraded + test "${IS_TUNE2FS_M5:=1}" = 1 && check_tune2fs_m5 + test "${IS_EVOLINUXSUDOGROUP:=1}" = 1 && check_evolinuxsudogroup + test "${IS_USERINADMGROUP:=1}" = 1 && check_userinadmgroup + test "${IS_APACHE2EVOLINUXCONF:=1}" = 1 && check_apache2evolinuxconf + test "${IS_BACKPORTSCONF:=1}" = 1 && check_backportsconf + test "${IS_BIND9MUNIN:=1}" = 1 && check_bind9munin + test "${IS_BIND9LOGROTATE:=1}" = 1 && check_bind9logrotate + test "${IS_BROADCOMFIRMWARE:=1}" = 1 && check_broadcomfirmware + test "${IS_HARDWARERAIDTOOL:=1}" = 1 && check_hardwareraidtool + test "${IS_LOG2MAILSYSTEMDUNIT:=1}" = 1 && check_log2mailsystemdunit + test "${IS_LISTUPGRADE:=1}" = 1 && check_listupgrade + test "${IS_MARIADBEVOLINUXCONF:=0}" = 1 && check_mariadbevolinuxconf + test "${IS_SQL_BACKUP:=1}" = 1 && check_sql_backup + test "${IS_POSTGRES_BACKUP:=1}" = 1 && check_postgres_backup + test "${IS_MONGO_BACKUP:=1}" = 1 && check_mongo_backup + test "${IS_LDAP_BACKUP:=1}" = 1 && check_ldap_backup + test "${IS_REDIS_BACKUP:=1}" = 1 && check_redis_backup + test "${IS_ELASTIC_BACKUP:=1}" = 1 && check_elastic_backup + test "${IS_MARIADBSYSTEMDUNIT:=1}" = 1 && check_mariadbsystemdunit + test "${IS_MYSQLMUNIN:=1}" = 1 && check_mysqlmunin + test "${IS_MYSQLNRPE:=1}" = 1 && check_mysqlnrpe + test "${IS_PHPEVOLINUXCONF:=0}" = 1 && check_phpevolinuxconf + test "${IS_SQUIDLOGROTATE:=1}" = 1 && check_squidlogrotate + test "${IS_SQUIDEVOLINUXCONF:=1}" = 1 && check_squidevolinuxconf + test "${IS_DUPLICATE_FS_LABEL:=1}" = 1 && check_duplicate_fs_label + test "${IS_EVOLIX_USER:=1}" = 1 && check_evolix_user + test "${IS_EVOACME_CRON:=1}" = 1 && check_evoacme_cron + test "${IS_EVOACME_LIVELINKS:=1}" = 1 && check_evoacme_livelinks + test "${IS_APACHE_CONFENABLED:=1}" = 1 && check_apache_confenabled + test "${IS_MELTDOWN_SPECTRE:=1}" = 1 && check_meltdown_spectre + test "${IS_OLD_HOME_DIR:=0}" = 1 && check_old_home_dir + test "${IS_EVOBACKUP_INCS:=1}" = 1 && check_evobackup_incs + test "${IS_OSPROBER:=1}" = 1 && check_osprober + test "${IS_JESSIE_BACKPORTS:=1}" = 1 && check_jessie_backports + test "${IS_APT_VALID_UNTIL:=1}" = 1 && check_apt_valid_until + test "${IS_CHROOTED_BINARY_UPTODATE:=1}" = 1 && check_chrooted_binary_uptodate + test "${IS_NGINX_LETSENCRYPT_UPTODATE:=1}" = 1 && check_nginx_letsencrypt_uptodate + test "${IS_LXC_CONTAINER_RESOLV_CONF:=1}" = 1 && check_lxc_container_resolv_conf + test "${IS_CHECK_VERSIONS:=1}" = 1 && check_versions if [ -f "${main_output_file}" ]; then lines_found=$(wc -l < "${main_output_file}") From c7a6b3e6945f839aeac26b87c1d8fa6db22afe88 Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Mon, 29 Aug 2022 17:03:29 +0200 Subject: [PATCH 33/74] evocheck: upstream release 22.08.1 --- CHANGELOG.md | 2 +- evocheck/files/evocheck.sh | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 323f0c13..1587a7fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Changed -* evocheck: upstream release 22.08 +* evocheck: upstream release 22.08.1 * openvpn: automate the initialization of the CA and the creation of the server certificate ; use openssl_dhparam module instead of a command ### Fixed diff --git a/evocheck/files/evocheck.sh b/evocheck/files/evocheck.sh index e924debd..2771c904 100644 --- a/evocheck/files/evocheck.sh +++ b/evocheck/files/evocheck.sh @@ -4,7 +4,7 @@ # Script to verify compliance of a Linux (Debian) server # powered by Evolix -VERSION="22.08" +VERSION="22.08.1" readonly VERSION # base functions @@ -575,8 +575,8 @@ check_autoif() { interfaces=$(/sbin/ifconfig -s | tail -n +2 | grep -E -v "^(lo|vnet|docker|veth|tun|tap|macvtap|vrrp)" | cut -d " " -f 1 |tr "\n" " ") fi for interface in $interfaces; do - if ! grep -Rq "^auto $interface" /etc/network/interfaces*; then - failed "IS_AUTOIF" "Network interface \`${interface}' is not set to auto" + if grep -Rq "^iface $interface" /etc/network/interfaces* && ! grep -Rq "^auto $interface" /etc/network/interfaces*; then + failed "IS_AUTOIF" "Network interface \`${interface}' is statically defined but not set to auto" test "${VERBOSE}" = 1 || break fi done From efdbdee6a194ba85d8f25dd216a0047c35b566b6 Mon Sep 17 00:00:00 2001 From: William Hirigoyen Date: Mon, 29 Aug 2022 17:28:57 +0200 Subject: [PATCH 34/74] =?UTF-8?q?[generate-ldif]=C2=A0Make=20MariaDB=20ver?= =?UTF-8?q?sion=20detection=20more=20generic.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- generate-ldif/templates/generateldif.sh.j2 | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/generate-ldif/templates/generateldif.sh.j2 b/generate-ldif/templates/generateldif.sh.j2 index 17ff759a..229c1443 100755 --- a/generate-ldif/templates/generateldif.sh.j2 +++ b/generate-ldif/templates/generateldif.sh.j2 @@ -408,12 +408,8 @@ EOT fi # MariaDB -if is_pkg_installed mariadb-server-10.3; then - mariadb_version=$(get_pkg_version mariadb-server-10.3) -elif is_pkg_installed mariadb-server-10.1; then - mariadb_version=$(get_pkg_version mariadb-server-10.1) -elif is_pkg_installed mariadb-server-10.0; then - mariadb_version=$(get_pkg_version mariadb-server-10.0) +if is_pkg_installed mariadb-server; then + mariadb_version=$(get_pkg_version mariadb-server) fi if [ -n "${mariadb_version}" ]; then cat <> "${ldif_file}" From 4a3b40d986bc0adde7f96785239233a1d5ab788b Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Mon, 29 Aug 2022 17:29:09 +0200 Subject: [PATCH 35/74] generate-ldif: Support any MariaDB version --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1587a7fe..1bc2e240 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Changed * evocheck: upstream release 22.08.1 +* generate-ldif: Support any MariaDB version * openvpn: automate the initialization of the CA and the creation of the server certificate ; use openssl_dhparam module instead of a command ### Fixed From f2e49d7b121b526a27b38726c8fbe038a695bfdd Mon Sep 17 00:00:00 2001 From: William Hirigoyen Date: Mon, 29 Aug 2022 18:05:57 +0200 Subject: [PATCH 36/74] mysql: support for new Debian 11 conf for Munin --- mysql/tasks/munin.yml | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/mysql/tasks/munin.yml b/mysql/tasks/munin.yml index 9ee8f95f..7d67065f 100644 --- a/mysql/tasks/munin.yml +++ b/mysql/tasks/munin.yml @@ -66,13 +66,42 @@ - replication notify: restart munin-node - - name: verify Munin configuration for mysql + - name: verify Munin configuration for mysql < Debian 11 replace: dest: /etc/munin/plugin-conf.d/munin-node after: '\[mysql\*\]' regexp: '^env.mysqluser (.+)$' replace: 'env.mysqluser debian-sys-maint' notify: restart munin-node + when: ansible_distribution_major_version is version_compare('11', '<') + + - name: set Munin env.mysqluser option for mysql >= Debian 11 + replace: + dest: /etc/munin/plugin-conf.d/munin-node + after: '\[mysql\*\]' + regexp: '^env.mysqluser (.+)$' + replace: 'env.mysqluser root' + notify: restart munin-node + when: ansible_distribution_major_version is version_compare('11', '>=') + + - name: set Munin env.mysqlopts option for mysql >= Debian 11 + replace: + dest: /etc/munin/plugin-conf.d/munin-node + after: '\[mysql\*\]' + regexp: '^env.mysqlopts (.+)$' + replace: 'env.mysqlopts --defaults-file=/root/.my.cnf' + notify: restart munin-node + when: ansible_distribution_major_version is version_compare('11', '>=') + + - name: set Munin env.mysqlconnection option for mysql >= Debian 11 + replace: + dest: /etc/munin/plugin-conf.d/munin-node + after: '\[mysql\*\]' + regexp: '^env.mysqlconnection (.+)$' + replace: 'env.mysqlconnection DBI:mysql:mysql;mysql_read_default_file=/root/.my.cnf' + notify: restart munin-node + when: ansible_distribution_major_version is version_compare('11', '>=') + when: munin_node_plugins_config.stat.exists tags: From 18dd64df50fba229448f74e19af0e5246ddb362c Mon Sep 17 00:00:00 2001 From: Eric Morino Date: Wed, 31 Aug 2022 16:52:25 +0200 Subject: [PATCH 37/74] Add load module mod_ident --- proftpd/templates/evolinux.conf.j2 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/proftpd/templates/evolinux.conf.j2 b/proftpd/templates/evolinux.conf.j2 index 8a810a99..08484714 100644 --- a/proftpd/templates/evolinux.conf.j2 +++ b/proftpd/templates/evolinux.conf.j2 @@ -1,5 +1,9 @@ # Evolix's specific configuration + + LoadModule mod_ident.c + + ServerName "{{ proftpd_hostname }} FTP Server" ServerIdent on "FTP Server Ready" AccessGrantMsg "Hey, bienvenue %u sur le serveur FTP {{ proftpd_fqdn }} !" From 3a59f5b7ca020ac9fc1701491676ce564c438710 Mon Sep 17 00:00:00 2001 From: Eric Morino Date: Wed, 31 Aug 2022 17:03:02 +0200 Subject: [PATCH 38/74] Add variable 'proftpd_default_address' on virtualhost --- proftpd/templates/ftps.conf.j2 | 2 +- proftpd/templates/sftp.conf.j2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/proftpd/templates/ftps.conf.j2 b/proftpd/templates/ftps.conf.j2 index 33a2cff3..2db74b37 100644 --- a/proftpd/templates/ftps.conf.j2 +++ b/proftpd/templates/ftps.conf.j2 @@ -2,7 +2,7 @@ LoadModule mod_tls.c - + TLSEngine on TLSLog /var/log/proftpd/ftps.log TLSProtocol TLSv1 diff --git a/proftpd/templates/sftp.conf.j2 b/proftpd/templates/sftp.conf.j2 index 9a96e5ef..432e9ba8 100644 --- a/proftpd/templates/sftp.conf.j2 +++ b/proftpd/templates/sftp.conf.j2 @@ -6,7 +6,7 @@ LoadModule mod_sftp.c - + SFTPEngine on Port {{ proftpd_sftp_port }} DefaultRoot ~ From d165a104f214667939457022246752f787b9f4f1 Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Thu, 1 Sep 2022 11:28:08 +0200 Subject: [PATCH 39/74] * webapps/nextcloud: Add missing dependencies for imagick --- CHANGELOG.md | 1 + webapps/nextcloud/tasks/main.yml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bc2e240..154b8175 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * haproxy: make it so that munin doesn't break if there is a non default `haproxy_stats_path` * varnish: make `-j ` the first argument on jessie/stretch as it has to be the first argument there. * redis: config directory must be owned by the user that runs the service (to be able to write tmp config files in it) +* webapps/nextcloud: Add missing dependencies for imagick ### Removed diff --git a/webapps/nextcloud/tasks/main.yml b/webapps/nextcloud/tasks/main.yml index 7ce81693..95269246 100644 --- a/webapps/nextcloud/tasks/main.yml +++ b/webapps/nextcloud/tasks/main.yml @@ -16,6 +16,8 @@ - php-apcu - php-redis - php-bcmath + - php-imagick + - libmagickcore-6.q16-6-extra tags: - nextcloud From f74b6f394bbdf2feab5131838683ce978a1b5e7b Mon Sep 17 00:00:00 2001 From: William Hirigoyen Date: Thu, 1 Sep 2022 12:05:14 +0200 Subject: [PATCH 40/74] nagios-nrpe: add heck_domains --- nagios-nrpe/README.md | 6 +++++ nagios-nrpe/files/plugins/check_domains | 14 +++++++++++ nagios-nrpe/tasks/configure_check_domains.yml | 25 +++++++++++++++++++ nagios-nrpe/tasks/main.yml | 1 + nagios-nrpe/templates/evolix.cfg.j2 | 1 + 5 files changed, 47 insertions(+) create mode 100755 nagios-nrpe/files/plugins/check_domains create mode 100644 nagios-nrpe/tasks/configure_check_domains.yml diff --git a/nagios-nrpe/README.md b/nagios-nrpe/README.md index 6d72920e..c52cab05 100644 --- a/nagios-nrpe/README.md +++ b/nagios-nrpe/README.md @@ -12,3 +12,9 @@ Everything is in the `tasks/main.yml` file. * `nagios_nrpe_force_update_allowed_hosts` : force update list of allowed hosts (default: `False`) The full list of variables (with default values) can be found in `defaults/main.yml`. + +## Available tags + +* `nagios-nrpe` : install Nagios and plugins (idempotent) +* `nagios-plugins` : install only plugins (idempotent) + diff --git a/nagios-nrpe/files/plugins/check_domains b/nagios-nrpe/files/plugins/check_domains new file mode 100755 index 00000000..23f48022 --- /dev/null +++ b/nagios-nrpe/files/plugins/check_domains @@ -0,0 +1,14 @@ +#!/usr/bin/bash +# +# Check domains using script inspect-domains. +# +# Written by Will +# + +if ! command -v inspect-domains >/dev/null; then + echo 'UNKNOWN - Missing dependency inspect-domains.' + exit 3 +fi + +inspect-domains -o nrpe -a check-dns + diff --git a/nagios-nrpe/tasks/configure_check_domains.yml b/nagios-nrpe/tasks/configure_check_domains.yml new file mode 100644 index 00000000..0d81b652 --- /dev/null +++ b/nagios-nrpe/tasks/configure_check_domains.yml @@ -0,0 +1,25 @@ +- name: Install check_domains dependency + include_role: + name: inspect-domains + +- name: Configure check_domains in /etc/nagios/nrpe.d/evolix.cfg + ansible.builtin.lineinfile: + path: /etc/nagios/nrpe.d/evolix.cfg + regexp: '^command\[check_domains\]=' + line: command[check_domains]=sudo {{ nagios_plugins_directory }}/check_domains + notify: restart nagios-nrpe-server + +- name: Is evolinux sudoers installed? + ansible.builtin.stat: + path: /etc/sudoers.d/evolinux + register: sudoers_evolinux + +- name: Allow nagios user to execute check_domains without sudo password + ansible.builtin.lineinfile: + path: /etc/sudoers.d/evolinux + regexp: 'check_domains' + line: 'nagios ALL = NOPASSWD: {{ nagios_plugins_directory }}/check_domains' + insertafter: '^nagios' + validate: "visudo -cf %s" + when: sudoers_evolinux.stat.exists + diff --git a/nagios-nrpe/tasks/main.yml b/nagios-nrpe/tasks/main.yml index 77770020..28ab11a9 100644 --- a/nagios-nrpe/tasks/main.yml +++ b/nagios-nrpe/tasks/main.yml @@ -22,6 +22,7 @@ - ansible_distribution == "Debian" - ansible_distribution_major_version is version('10', '>=') tags: + - nagios-nrpe - nagios-plugins - name: custom configuration is present diff --git a/nagios-nrpe/templates/evolix.cfg.j2 b/nagios-nrpe/templates/evolix.cfg.j2 index ae0e0abd..7546f2bc 100644 --- a/nagios-nrpe/templates/evolix.cfg.j2 +++ b/nagios-nrpe/templates/evolix.cfg.j2 @@ -47,6 +47,7 @@ command[check_proxy]=/usr/lib/nagios/plugins/check_http -H {{ nagios_nrpe_check_ command[check_redis]=/usr/lib/nagios/plugins/check_tcp -p 6379 command[check_clamd]=/usr/lib/nagios/plugins/check_clamd -H /var/run/clamav/clamd.ctl -v command[check_clamav_db]=/usr/lib/nagios/plugins/check_file_age -w 86400 -c 172800 -f /var/lib/clamav/evolix.ndb +command[check_domains]=sudo {{ nagios_plugins_directory }}/check_domains command[check_ssl]=/usr/lib/nagios/plugins/check_http -f follow -I 127.0.0.1 -S -p 443 -H ssl.evolix.net -C 15,5 command[check_ssl_local]={{ nagios_plugins_directory }}/check_ssl_local command[check_elasticsearch]=/usr/lib/nagios/plugins/check_http -I 127.0.0.1 -u /_cat/health?h=st -p 9200 -r 'red' --invert-regex From 46eab710ee92caf0741e0591df8727264fd40018 Mon Sep 17 00:00:00 2001 From: William Hirigoyen Date: Thu, 1 Sep 2022 12:05:44 +0200 Subject: [PATCH 41/74] inspect-domains: add role --- inspect-domains/files/inspect-domains.py | 254 +++++++++++++++++++++++ inspect-domains/tasks/main.yml | 8 + 2 files changed, 262 insertions(+) create mode 100755 inspect-domains/files/inspect-domains.py create mode 100644 inspect-domains/tasks/main.yml diff --git a/inspect-domains/files/inspect-domains.py b/inspect-domains/files/inspect-domains.py new file mode 100755 index 00000000..35f7e410 --- /dev/null +++ b/inspect-domains/files/inspect-domains.py @@ -0,0 +1,254 @@ +#!/usr/bin/python3 +# +# Vérifie si les domaines listés dans les configurations de Apache, +# Nginx et Haproxy pointent bien sur le serveur. +# +# Développé par Will +# + +list_domains_path = '/usr/local/sbin/list_domains.py' +excludes_path = '/etc/nagios/domains_exclude.list' +includes_path = '/etc/nagios/domains_include.list' + +import os +import sys +import re +import subprocess +import threading +import time +import argparse + +#import importlib.machinery +#list_domains = importlib.machinery.SourceFileLoader('list_domains.py', list_domains_path).load_module() + + +def execute(cmd): + """Execute Bash command cmd. + Return stdout and stderr as arrays of UTF-8 strings.""" + + proc = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = proc.communicate() + + stdout_lines = stdout.decode('utf-8').splitlines() + stderr_lines = stderr.decode('utf-8').splitlines() + + return stdout_lines, stderr_lines + + +def get_my_ips(): + """Return localhost IPs.""" + stdout, stderr = execute('hostname -I') + if not stdout: + return [] + return stdout[0].strip().split() + + +def dig(domain): + """Return dig +short result on domain as a list.""" + stdout, stderr = execute('dig +short {}'.format(domain)) + return stdout + +def list_apache_domains(): + """Return a dict containing : + - key: Apache domain (from command "apache2ctl -D DUMP_VHOSTS"). + - value: a list of strings "apache::" + """ + domains = {} + + try: + stdout, stderr = execute("apache2ctl -D DUMP_VHOSTS") + except: + # Apache is not on the server + return domains + + vhost_infos = "" + for line in stdout: + dom = "" + words = line.strip().split() + + if "namevhost" in line and len(words) >= 5: + # line format: port namevhost (:) + dom = words[3] + vhost_infos = "apache:" + words[4].strip('()') + + elif "alias" in line and len(words) >= 2: + # line format: alias + dom = words[1] # vhost_infos defined in previous lines + + if dom: + if dom not in domains: + domains[dom] = [] + if vhost_infos not in domains[dom]: + domains[dom].append(vhost_infos) + + return domains + + +class ResolutionThread(threading.Thread): + + def __init__(self, domain): + threading.Thread.__init__(self, daemon=True) + self.domain = domain + self.ips = [] + + def run(self): + """Resolve domain with dig.""" + try: + dig_results = dig(self.domain) + + if not dig_results: + return + + for line in dig_results: + match = re.search('^([0-9abcdef\.:]+)$', line) + if match: + ip = match.group(1) + if ip not in self.ips: + self.ips.append(ip) + + except Exception as e: + #print(e) + return + + +def run_check_domains(domains): + """Check resolution of domains (list).""" + + excludes = ['_'] + timeout = 5 + + my_ips = get_my_ips() + + domains_noexcludes = [dom for dom in domains if dom not in excludes] + + jobs = [] + for dom in domains_noexcludes: + #print(d) + t = ResolutionThread(dom) + t.start() + jobs.append(t) + + # Let secs to DNS servers to answer in jobs threads + time.sleep(timeout) + + timeout_domains = [] + none_domains = [] + outside_ips = {} + ok_domains = [] + + for j in jobs: + if j.is_alive(): + timeout_domains.append(j.domain) + continue + + if not j.ips: + none_domains.append(j.domain) + continue + + is_outside = False + for ip in j.ips: + if ip not in my_ips: + is_outside = True + break + if is_outside: + outside_ips[j.domain] = j.ips + else: + ok_domains.append(j.domain) + + return timeout_domains, none_domains, outside_ips, ok_domains + + +def output_check_mode(timeout_domains, none_domains, outside_ips, ok_domains): + """Output result for check mode. + For now, consider everyting as warnings to avoid too much alerts. + """ + + n_ok = len(ok_domains) + n_warnings = len(timeout_domains) + len(none_domains) + len(outside_ips) + + msg = 'WARNING' if n_warnings else 'OK' + + print('{} - 0 UNK / 0 CRIT / {} WARN / {} OK \n'.format(msg, n_warnings, n_ok)) + + if timeout_domains or none_domains or outside_ips: + for d in timeout_domains: + print('WARNING - timeout resolving {}'.format(d)) + for d in none_domains: + print('WARNING - no resolution for {}'.format(d)) + for d in outside_ips: + print('WARNING - {} pointing elsewhere ({})'.format(d, ' '.join(outside_ips[d]))) + + sys.exit(1) if n_warnings else sys.exit(0) + + +def output_friendly_mode(doms, timeout_domains, none_domains, outside_ips): + if timeout_domains or none_domains or outside_ips: + if timeout_domains: print('\nTimeouts:') + for d in timeout_domains: + print('\t{} {}'.format(d, ' '.join(doms[d]))) + if none_domains: print('\nNo resolution:') + for d in none_domains: + print('\t{} {}'.format(d, ' '.join(doms[d]))) + if outside_ips: print('\nPointing elsewhere:') + for d in outside_ips: + print('\t{} {} -> [{}]'.format(d, ' '.join(doms[d]), ' '.join(outside_ips[d]))) + + sys.exit(1) + + print('Domains resolve to right IPs !') + + +def main(argv): + parser = argparse.ArgumentParser() + parser.add_argument('action', metavar='ACTION', help='Values: check-dns, list') + parser.add_argument('-o', '--output-style', help='Values: stdout (default), nrpe') + parser.add_argument('-a', '--all-domains', action='store_true', help='Include all domains (default).') + parser.add_argument('-ap', '--apache-domains', action='store_true', help='Include Apache domains.') + parser.add_argument('-ng', '--nginx-domains', action='store_true', help='Include Nginx domains.') + parser.add_argument('-ha', '--haproxy-domains', action='store_true', help='Include HaProxy domains.') + args = parser.parse_args() + + if args.action not in ['check-dns', 'list']: + if args.output_style == 'nrpe': + print('UNKNOWN - unkown {} action, use -h option for help.'.format(args.action)) + sys.exit(3) + else: + print('Unkown {} action, use -h option for help.'.format(args.action)) + sys.exit(1) + + if not (args.all_domains or args.apache_domains or args.nginx_domains or args.haproxy_domains): + print('Domains not specified, looking for all domains (default).') + args.all_domains = True + + doms = [] + + if args.all_domains: + doms.extend(list_apache_domains()) + + else: + if args.apache_domains: + doms.extend(list_apache_domains()) + if args.nginx_domains: + print("Option --nginx-domains not supported yet.") + if args.haproxy_domains: + print("Option --haproxy-domains not supported yet.") + + if not doms: + if args.output_style == 'nrpe': + print('UNKNOWN - No domain found on this server.') + sys.exit(3) + else: + print('No domain found on this server.') + sys.exit(1) + + timeout_domains, none_domains, outside_ips, ok_domains = run_check_domains(doms.keys()) + + if args.check: + output_check_mode(timeout_domains, none_domains, outside_ips, ok_domains) + + else: + output_friendly_mode(doms, timeout_domains, none_domains, outside_ips) + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/inspect-domains/tasks/main.yml b/inspect-domains/tasks/main.yml new file mode 100644 index 00000000..f5d915fe --- /dev/null +++ b/inspect-domains/tasks/main.yml @@ -0,0 +1,8 @@ +- name: Copy inspect-domains script to local sbin + ansible.builtin.copy: + src: inspect-domains.py + dest: /usr/local/sbin/inspect-domains + mode: '0700' + + + From 2bda54a7bdf2f4e80b2eb450e05d269468e21b29 Mon Sep 17 00:00:00 2001 From: William Hirigoyen Date: Thu, 1 Sep 2022 12:07:47 +0200 Subject: [PATCH 42/74] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 154b8175..5f2190ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,12 +16,14 @@ The **patch** part changes is incremented if multiple releases happen the same m * php: install php-xml with recent PHP versions * vrrp: add an `ip.yml` task file to help create VRRP addresses * webapps/nextcloud: Add compatibility with apache2, and apache2 mod_php. +* inspect-domains: Add role ### Changed * evocheck: upstream release 22.08.1 * generate-ldif: Support any MariaDB version * openvpn: automate the initialization of the CA and the creation of the server certificate ; use openssl_dhparam module instead of a command +* nagios-nrpe: Add check_domains ### Fixed From ee67ebca8b198b2d0ff09df094bdb3f20b163024 Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Thu, 1 Sep 2022 11:58:24 +0200 Subject: [PATCH 43/74] webapps/nextcloud: Drop support for Nginx --- CHANGELOG.md | 1 + webapps/nextcloud/defaults/main.yml | 1 - webapps/nextcloud/meta/main.yml | 3 - webapps/nextcloud/tasks/main.yml | 7 - webapps/nextcloud/tasks/vhost-nginx.yml | 34 ----- webapps/nextcloud/templates/nginx.conf.j2 | 134 -------------------- webapps/nextcloud/templates/php-fpm.conf.j2 | 17 --- 7 files changed, 1 insertion(+), 196 deletions(-) delete mode 100644 webapps/nextcloud/tasks/vhost-nginx.yml delete mode 100644 webapps/nextcloud/templates/nginx.conf.j2 delete mode 100644 webapps/nextcloud/templates/php-fpm.conf.j2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f2190ec..4a56dbdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Removed * evocheck: remove failure if deprecated variable is used +* webapps/nextcloud: Drop support for Nginx ### Security diff --git a/webapps/nextcloud/defaults/main.yml b/webapps/nextcloud/defaults/main.yml index 3c1bf40a..574727de 100644 --- a/webapps/nextcloud/defaults/main.yml +++ b/webapps/nextcloud/defaults/main.yml @@ -1,5 +1,4 @@ --- -nextcloud_webserver: 'nginx' nextcloud_version: "21.0.0" nextcloud_archive_name: "nextcloud-{{ nextcloud_version }}.tar.bz2" nextcloud_releases_baseurl: "https://download.nextcloud.com/server/releases/" diff --git a/webapps/nextcloud/meta/main.yml b/webapps/nextcloud/meta/main.yml index d5852e32..ed97d539 100644 --- a/webapps/nextcloud/meta/main.yml +++ b/webapps/nextcloud/meta/main.yml @@ -1,4 +1 @@ --- -# dependencies: - # - { role: nginx, when: nextcloud_webserver == 'nginx' } - # - { role: php, php_fpm_enable: True } diff --git a/webapps/nextcloud/tasks/main.yml b/webapps/nextcloud/tasks/main.yml index 95269246..f11d62fa 100644 --- a/webapps/nextcloud/tasks/main.yml +++ b/webapps/nextcloud/tasks/main.yml @@ -47,14 +47,7 @@ - include: archive.yml -- name: Check if Apache or Nginx - service_facts: - -- include: vhost-nginx.yml - when: "'nginx.service' in services" - - include: vhost-apache.yml - when: "'apache2.service' in services" - include: mysql.yml diff --git a/webapps/nextcloud/tasks/vhost-nginx.yml b/webapps/nextcloud/tasks/vhost-nginx.yml deleted file mode 100644 index 1f1592cc..00000000 --- a/webapps/nextcloud/tasks/vhost-nginx.yml +++ /dev/null @@ -1,34 +0,0 @@ ---- -- block: - - name: Copy Nginx vhost - template: - src: nginx.conf.j2 - dest: "/etc/nginx/sites-available/{{ nextcloud_instance_name }}.conf" - mode: "0640" - notify: reload nginx - tags: - - nextcloud - - - name: Enable Nginx vhost - file: - src: "/etc/nginx/sites-available/{{ nextcloud_instance_name }}.conf" - dest: "/etc/nginx/sites-enabled/{{ nextcloud_instance_name }}.conf" - state: link - notify: reload nginx - tags: - - nextcloud - - - name: Generate ssl config - shell: - cmd: "/usr/local/sbin/vhost-domains {{ nextcloud_instance_name }} | /usr/local/sbin/make-csr {{ nextcloud_instance_name }}" - creates: "/etc/nginx/ssl/{{ nextcloud_instance_name }}.conf" - - - name: Copy PHP-FPM pool - template: - src: php-fpm.conf.j2 - dest: "/etc/php/7.3/fpm/pool.d/{{ nextcloud_instance_name }}.conf" - mode: "0640" - notify: reload php-fpm - tags: - - nextcloud - when: nextcloud_webserver == 'nginx' diff --git a/webapps/nextcloud/templates/nginx.conf.j2 b/webapps/nextcloud/templates/nginx.conf.j2 deleted file mode 100644 index c2b7b7e3..00000000 --- a/webapps/nextcloud/templates/nginx.conf.j2 +++ /dev/null @@ -1,134 +0,0 @@ -upstream php-handler-{{ nextcloud_instance_name }} { - server unix:/var/run/php/php-fpm-{{ nextcloud_instance_name }}.sock; -} - -server { - listen 80; - listen [::]:80; - listen 443 ssl http2; - listen [::]:443 ssl http2; - - server_name {{ nextcloud_domains | join(' ') }}; - - access_log {{ nextcloud_home }}/log/access.log; - error_log {{ nextcloud_home }}/log/error.log; - - include /etc/nginx/snippets/letsencrypt.conf; - include /etc/nginx/ssl/{{ nextcloud_instance_name }}.conf; - - add_header Referrer-Policy "no-referrer" always; - add_header X-Content-Type-Options "nosniff" always; - add_header X-Download-Options "noopen" always; - add_header X-Frame-Options "SAMEORIGIN" always; - add_header X-Permitted-Cross-Domain-Policies "none" always; - add_header X-Robots-Tag "none" always; - add_header X-XSS-Protection "1; mode=block" always; - - # Remove X-Powered-By, which is an information leak - fastcgi_hide_header X-Powered-By; - - root {{ nextcloud_webroot }}; - - location = /robots.txt { - allow all; - log_not_found off; - access_log off; - } - - # Make a regex exception for `/.well-known` so that clients can still - # access it despite the existence of the regex rule - # `location ~ /(\.|autotest|...)` which would otherwise handle requests - # for `/.well-known`. - location ^~ /.well-known { - # The following 6 rules are borrowed from `.htaccess` - - location = /.well-known/carddav { return 301 /remote.php/dav/; } - location = /.well-known/caldav { return 301 /remote.php/dav/; } - # Anything else is dynamically handled by Nextcloud - location ^~ /.well-known { return 301 /index.php$uri; } - location ~ ^/.well-known/acme-challenge/* { allow all; } - - try_files $uri $uri/ =404; - } - - # set max upload size - client_max_body_size 512M; - fastcgi_buffers 64 4K; - - # Enable gzip but do not remove ETag headers - gzip on; - gzip_vary on; - gzip_comp_level 4; - gzip_min_length 256; - gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; - gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; - - - location / { - rewrite ^ /index.php; - } - - location ~ ^\/(?:build|tests|config|lib|3rdparty|templates|data)\/ { - deny all; - } - location ~ ^\/(?:\.|autotest|occ|issue|indie|db_|console) { - deny all; - } - - - location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy)\.php(?:$|\/) { - fastcgi_split_path_info ^(.+?\.php)(\/.*|)$; - set $path_info $fastcgi_path_info; - try_files $fastcgi_script_name =404; - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_param PATH_INFO $path_info; - fastcgi_param HTTPS on; - # Avoid sending the security headers twice - fastcgi_param modHeadersAvailable true; - # Enable pretty urls - fastcgi_param front_controller_active true; - fastcgi_pass php-handler-{{ nextcloud_instance_name }}; - fastcgi_intercept_errors on; - fastcgi_request_buffering off; - } - - location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) { - try_files $uri/ =404; - index index.php; - } - - # Adding the cache control header for js, css and map files - # Make sure it is BELOW the PHP block - location ~ \.(?:css|js|woff2?|svg|gif|map)$ { - try_files $uri /index.php$request_uri; - add_header Cache-Control "public, max-age=15778463"; - # Add headers to serve security related headers (It is intended to - # have those duplicated to the ones above) - # Before enabling Strict-Transport-Security headers please read into - # this topic first. - #add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always; - # - # WARNING: Only add the preload option once you read about - # the consequences in https://hstspreload.org/. This option - # will add the domain to a hardcoded list that is shipped - # in all major browsers and getting removed from this list - # could take several months. - add_header Referrer-Policy "no-referrer" always; - add_header X-Content-Type-Options "nosniff" always; - add_header X-Download-Options "noopen" always; - add_header X-Frame-Options "SAMEORIGIN" always; - add_header X-Permitted-Cross-Domain-Policies "none" always; - add_header X-Robots-Tag "none" always; - add_header X-XSS-Protection "1; mode=block" always; - - # Optional: Don't log access to assets - access_log off; - } - - location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap|mp4|webm)$ { - try_files $uri /index.php$request_uri; - # Optional: Don't log access to other assets - access_log off; - } -} diff --git a/webapps/nextcloud/templates/php-fpm.conf.j2 b/webapps/nextcloud/templates/php-fpm.conf.j2 deleted file mode 100644 index 1b4c7861..00000000 --- a/webapps/nextcloud/templates/php-fpm.conf.j2 +++ /dev/null @@ -1,17 +0,0 @@ -[{{ nextcloud_instance_name }}] -user = {{ nextcloud_user }} -group = {{ nextcloud_user }} -listen = /run/php/php-fpm-{{ nextcloud_instance_name }}.sock -listen.owner = {{ nextcloud_user }} -listen.group = {{ nextcloud_user }} - -pm = ondemand -pm.max_children = 50 -pm.process_idle_timeout = 120s -pm.status_path = /fpm_status - -env[HOSTNAME] = $HOSTNAME -env[PATH] = /usr/local/bin:/usr/bin:/bin -env[TMP] = {{ nextcloud_home }}/tmp -env[TMPDIR] = {{ nextcloud_home }}/tmp -env[TEMP] = {{ nextcloud_home }}/tmp From a03a338af94a406dbbd7b414d39fc83c2863effc Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Thu, 1 Sep 2022 12:02:23 +0200 Subject: [PATCH 44/74] webapps/nextcloud: Use var nextcloud_user for unix group instead of instance_name to prevent mixup --- webapps/nextcloud/tasks/user.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapps/nextcloud/tasks/user.yml b/webapps/nextcloud/tasks/user.yml index e89fe41a..dfe3a9cb 100644 --- a/webapps/nextcloud/tasks/user.yml +++ b/webapps/nextcloud/tasks/user.yml @@ -1,7 +1,7 @@ --- - name: Create Nextcloud group group: - name: "{{ nextcloud_instance_name | mandatory }}" + name: "{{ nextcloud_user | mandatory }}" state: present tags: - nextcloud @@ -9,7 +9,7 @@ - name: Create Nextcloud user user: name: "{{ nextcloud_user | mandatory }}" - group: "{{ nextcloud_user }}" + group: "{{ nextcloud_user | mandatory }}" home: "{{ nextcloud_home | mandatory }}" shell: '/bin/bash' create_home: True From 2656b5fc519633472d63b11f9b99737eded49bf0 Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Thu, 1 Sep 2022 12:38:10 +0200 Subject: [PATCH 45/74] webapp/nextcloud: Change default folder mode to 0700 (+ better tasks name for user/group creation) --- webapps/nextcloud/tasks/user.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webapps/nextcloud/tasks/user.yml b/webapps/nextcloud/tasks/user.yml index dfe3a9cb..4df6737d 100644 --- a/webapps/nextcloud/tasks/user.yml +++ b/webapps/nextcloud/tasks/user.yml @@ -1,12 +1,12 @@ --- -- name: Create Nextcloud group +- name: Create {{ nextcloud_user }} unix group group: name: "{{ nextcloud_user | mandatory }}" state: present tags: - nextcloud -- name: Create Nextcloud user +- name: Create {{ nextcloud_user | mandatory }} unix user user: name: "{{ nextcloud_user | mandatory }}" group: "{{ nextcloud_user | mandatory }}" @@ -28,7 +28,7 @@ file: dest: "{{ item }}" state: directory - mode: "0770" + mode: "0700" owner: "{{ nextcloud_user }}" group: "{{ nextcloud_user }}" loop: From 1ad3e0de37fa948a7bf8378eaf6d4f309f098c50 Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Thu, 1 Sep 2022 12:38:46 +0200 Subject: [PATCH 46/74] webapp/nextcloud: Dont add www-data to the application group --- webapps/nextcloud/tasks/user.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/webapps/nextcloud/tasks/user.yml b/webapps/nextcloud/tasks/user.yml index 4df6737d..8fa3fee1 100644 --- a/webapps/nextcloud/tasks/user.yml +++ b/webapps/nextcloud/tasks/user.yml @@ -18,12 +18,6 @@ tags: - nextcloud -- name: Add the user 'www-data' to Nextcloud group - user: - name: www-data - groups: "{{ nextcloud_user | mandatory }}" - append: yes - - name: Create top-level directories file: dest: "{{ item }}" From d5e34d0a7776569e4cd43e0aa2984ec23084b8f7 Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Thu, 1 Sep 2022 12:40:36 +0200 Subject: [PATCH 47/74] webapp/nextcloud: Multiple changes in vhost - Have only one domain as ServerName (otherwise you get an invalid apache config - Add all other domains as ServerAlias - Remove auto redirect vers ServerName - Correct indentation --- webapps/nextcloud/templates/apache.conf.j2 | 30 ++++++++++------------ 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/webapps/nextcloud/templates/apache.conf.j2 b/webapps/nextcloud/templates/apache.conf.j2 index 20a4d2eb..6844933d 100644 --- a/webapps/nextcloud/templates/apache.conf.j2 +++ b/webapps/nextcloud/templates/apache.conf.j2 @@ -1,5 +1,9 @@ - ServerName {{ nextcloud_domains | join(' ') }} + ServerName {{ nextcloud_domains[0] }} + + {% for domain_alias in nextcloud_domains[1:] %} + ServerAlias {{ domain_alias }} + {% endfor %} DocumentRoot {{ nextcloud_webroot }}/ @@ -13,22 +17,16 @@ - # user - group (thanks to sesse@debian.org) - AssignUserID {{ nextcloud_instance_name }} {{ nextcloud_instance_name }} + # user - group (thanks to sesse@debian.org) + AssignUserID {{ nextcloud_user }} {{ nextcloud_user }} - # LOG - CustomLog /var/log/apache2/access.log vhost_combined - CustomLog /home/{{ nextcloud_instance_name }}/log/access.log combined - ErrorLog /home/{{ nextcloud_instance_name }}/log/error.log + # LOG + CustomLog /var/log/apache2/access.log vhost_combined + CustomLog /home/{{ nextcloud_instance_name }}/log/access.log combined + ErrorLog /home/{{ nextcloud_instance_name }}/log/error.log - # REWRITE - UseCanonicalName On - RewriteEngine On - RewriteCond %{HTTP_HOST} !^{{ nextcloud_domains | join(' ') }}$ - RewriteRule ^/(.*) http://%{SERVER_NAME}/$1 [L,R] - - # PHP - php_admin_value sendmail_path "/usr/sbin/sendmail -t -i -f {{ nextcloud_instance_name }}" - php_admin_value open_basedir "/usr/share/php:/home/{{ nextcloud_instance_name }}:/tmp" + # PHP + php_admin_value sendmail_path "/usr/sbin/sendmail -t -i -f {{ nextcloud_user }}" + php_admin_value open_basedir "/usr/share/php:{{ nextcloud_home }}:/tmp" \ No newline at end of file From 5c7a7fe768e6139ae42cce142bd89cb64460412d Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Thu, 1 Sep 2022 12:43:56 +0200 Subject: [PATCH 48/74] webapp/nextlcloud: Reorganize tasks files - Apache : Split system/vhost stuff - MySQL : Rename task file to follow same convention as apache --- webapps/nextcloud/tasks/apache-system.yml | 30 ++++++++++++ webapps/nextcloud/tasks/apache-vhost.yml | 23 +++++++++ webapps/nextcloud/tasks/main.yml | 10 ++-- .../tasks/{mysql.yml => mysql-user.yml} | 0 webapps/nextcloud/tasks/vhost-apache.yml | 48 ------------------- .../{apache.conf.j2 => apache-vhost.conf.j2} | 0 6 files changed, 59 insertions(+), 52 deletions(-) create mode 100644 webapps/nextcloud/tasks/apache-system.yml create mode 100644 webapps/nextcloud/tasks/apache-vhost.yml rename webapps/nextcloud/tasks/{mysql.yml => mysql-user.yml} (100%) delete mode 100644 webapps/nextcloud/tasks/vhost-apache.yml rename webapps/nextcloud/templates/{apache.conf.j2 => apache-vhost.conf.j2} (100%) diff --git a/webapps/nextcloud/tasks/apache-system.yml b/webapps/nextcloud/tasks/apache-system.yml new file mode 100644 index 00000000..38b85906 --- /dev/null +++ b/webapps/nextcloud/tasks/apache-system.yml @@ -0,0 +1,30 @@ +--- + +- name: Enable apache2 php configuration + copy: + src: "zzz-apache2-evolinux-custom.ini" + dest: "/etc/php/7.4/apache2/conf.d/zzz-evolinux-custom.ini" + mode: "0644" + owner: root + group: root + force: yes + notify: reload apache + tags: + - nextcloud + +- name: Enable cli php configuration + copy: + src: "zzz-cli-evolinux-custom.ini" + dest: "/etc/php/7.4/cli/conf.d/zzz-evolinux-custom.ini" + mode: "0644" + owner: root + group: root + force: yes + notify: reload apache + tags: + - nextcloud + +# - name: Generate ssl config +# shell: +# cmd: "/usr/local/sbin/vhost-domains {{ nextcloud_instance_name }} | /usr/local/sbin/make-csr {{ nextcloud_instance_name }}" +# creates: "/etc/nginx/ssl/{{ nextcloud_instance_name }}.conf" \ No newline at end of file diff --git a/webapps/nextcloud/tasks/apache-vhost.yml b/webapps/nextcloud/tasks/apache-vhost.yml new file mode 100644 index 00000000..e3f213ca --- /dev/null +++ b/webapps/nextcloud/tasks/apache-vhost.yml @@ -0,0 +1,23 @@ +--- +- name: Copy Apache vhost + template: + src: apache-vhost.conf.j2 + dest: "/etc/apache2/sites-available/{{ nextcloud_instance_name }}.conf" + mode: "0640" + notify: reload apache + tags: + - nextcloud + +- name: Enable Apache vhost + file: + src: "/etc/apache2/sites-available/{{ nextcloud_instance_name }}.conf" + dest: "/etc/apache2/sites-enabled/{{ nextcloud_instance_name }}.conf" + state: link + notify: reload apache + tags: + - nextcloud + +# - name: Generate ssl config +# shell: +# cmd: "/usr/local/sbin/vhost-domains {{ nextcloud_instance_name }} | /usr/local/sbin/make-csr {{ nextcloud_instance_name }}" +# creates: "/etc/nginx/ssl/{{ nextcloud_instance_name }}.conf" \ No newline at end of file diff --git a/webapps/nextcloud/tasks/main.yml b/webapps/nextcloud/tasks/main.yml index f11d62fa..2823f8f5 100644 --- a/webapps/nextcloud/tasks/main.yml +++ b/webapps/nextcloud/tasks/main.yml @@ -21,7 +21,7 @@ tags: - nextcloud -# dependency for mysql_user and mysql_db +# dependency for mysql_user and mysql_db - python2 - name: python modules is installed (Ansible dependency) apt: name: @@ -32,7 +32,7 @@ - nextcloud when: ansible_python_version is version('3', '<') -# dependency for mysql_user and mysql_db +# dependency for mysql_user and mysql_db - python3 - name: python3 modules is installed (Ansible dependency) apt: name: @@ -43,12 +43,14 @@ - nextcloud when: ansible_python_version is version('3', '>=') +- include: apache-system.yml + - include: user.yml - include: archive.yml -- include: vhost-apache.yml +- include: apache-vhost.yml -- include: mysql.yml +- include: mysql-user.yml - include: config.yml diff --git a/webapps/nextcloud/tasks/mysql.yml b/webapps/nextcloud/tasks/mysql-user.yml similarity index 100% rename from webapps/nextcloud/tasks/mysql.yml rename to webapps/nextcloud/tasks/mysql-user.yml diff --git a/webapps/nextcloud/tasks/vhost-apache.yml b/webapps/nextcloud/tasks/vhost-apache.yml deleted file mode 100644 index b710b07a..00000000 --- a/webapps/nextcloud/tasks/vhost-apache.yml +++ /dev/null @@ -1,48 +0,0 @@ ---- -- block: - - name: Copy Apache vhost - template: - src: apache.conf.j2 - dest: "/etc/apache2/sites-available/{{ nextcloud_instance_name }}.conf" - mode: "0640" - notify: reload apache - tags: - - nextcloud - - - name: Enable Apache vhost - file: - src: "/etc/apache2/sites-available/{{ nextcloud_instance_name }}.conf" - dest: "/etc/apache2/sites-enabled/{{ nextcloud_instance_name }}.conf" - state: link - notify: reload apache - tags: - - nextcloud - - - name: Enable apache2 php configuration - copy: - src: "zzz-apache2-evolinux-custom.ini" - dest: "/etc/php/7.4/apache2/conf.d/zzz-evolinux-custom.ini" - mode: "0644" - owner: root - group: root - force: yes - notify: reload apache - tags: - - nextcloud - - - name: Enable cli php configuration - copy: - src: "zzz-cli-evolinux-custom.ini" - dest: "/etc/php/7.4/cli/conf.d/zzz-evolinux-custom.ini" - mode: "0644" - owner: root - group: root - force: yes - notify: reload apache - tags: - - nextcloud - - # - name: Generate ssl config - # shell: - # cmd: "/usr/local/sbin/vhost-domains {{ nextcloud_instance_name }} | /usr/local/sbin/make-csr {{ nextcloud_instance_name }}" - # creates: "/etc/nginx/ssl/{{ nextcloud_instance_name }}.conf" \ No newline at end of file diff --git a/webapps/nextcloud/templates/apache.conf.j2 b/webapps/nextcloud/templates/apache-vhost.conf.j2 similarity index 100% rename from webapps/nextcloud/templates/apache.conf.j2 rename to webapps/nextcloud/templates/apache-vhost.conf.j2 From 4bb2edae696aa7d228490a6dbbda5d9d44092b24 Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Thu, 1 Sep 2022 12:44:21 +0200 Subject: [PATCH 49/74] webapp/nextcloud: Use latest version of branch 24 --- webapps/nextcloud/defaults/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapps/nextcloud/defaults/main.yml b/webapps/nextcloud/defaults/main.yml index 574727de..5c586620 100644 --- a/webapps/nextcloud/defaults/main.yml +++ b/webapps/nextcloud/defaults/main.yml @@ -1,6 +1,6 @@ --- -nextcloud_version: "21.0.0" -nextcloud_archive_name: "nextcloud-{{ nextcloud_version }}.tar.bz2" +nextcloud_version: "latest-24" +nextcloud_archive_name: "{{ nextcloud_version }}.tar.bz2" nextcloud_releases_baseurl: "https://download.nextcloud.com/server/releases/" nextcloud_instance_name: "nextcloud" From 16e0f923ef34dac850bf4ffe37c205f008879c3f Mon Sep 17 00:00:00 2001 From: William Hirigoyen Date: Thu, 1 Sep 2022 14:58:35 +0200 Subject: [PATCH 50/74] check_domains: Fix script and check --- inspect-domains/files/inspect-domains.py | 8 ++++---- nagios-nrpe/files/plugins/check_domains | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/inspect-domains/files/inspect-domains.py b/inspect-domains/files/inspect-domains.py index 35f7e410..e1120994 100755 --- a/inspect-domains/files/inspect-domains.py +++ b/inspect-domains/files/inspect-domains.py @@ -220,14 +220,14 @@ def main(argv): print('Domains not specified, looking for all domains (default).') args.all_domains = True - doms = [] + doms = {} if args.all_domains: - doms.extend(list_apache_domains()) + doms.update(list_apache_domains()) else: if args.apache_domains: - doms.extend(list_apache_domains()) + doms.update(list_apache_domains()) if args.nginx_domains: print("Option --nginx-domains not supported yet.") if args.haproxy_domains: @@ -243,7 +243,7 @@ def main(argv): timeout_domains, none_domains, outside_ips, ok_domains = run_check_domains(doms.keys()) - if args.check: + if args.output_style == 'nrpe': output_check_mode(timeout_domains, none_domains, outside_ips, ok_domains) else: diff --git a/nagios-nrpe/files/plugins/check_domains b/nagios-nrpe/files/plugins/check_domains index 23f48022..78db2914 100755 --- a/nagios-nrpe/files/plugins/check_domains +++ b/nagios-nrpe/files/plugins/check_domains @@ -1,4 +1,4 @@ -#!/usr/bin/bash +#!/bin/bash # # Check domains using script inspect-domains. # From 1f52700b47587dfde4b84d21f51a2948478d5527 Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Thu, 1 Sep 2022 15:32:56 +0200 Subject: [PATCH 51/74] memcached: NRPE check for multi-instance setup Also some cleanup & split of tasks between single and multi instance Note: Munin part seems still broken at the time --- CHANGELOG.md | 1 + memcached/files/check_memcached_instances.sh | 82 ++++++++++++++++++++ memcached/tasks/instance-default.yml | 17 ++++ memcached/tasks/instance-multi.yml | 41 ++++++++++ memcached/tasks/main.yml | 68 ++-------------- memcached/tasks/munin.yml | 2 +- memcached/tasks/nrpe.yml | 29 +++++-- 7 files changed, 171 insertions(+), 69 deletions(-) create mode 100644 memcached/files/check_memcached_instances.sh create mode 100644 memcached/tasks/instance-default.yml create mode 100644 memcached/tasks/instance-multi.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a56dbdb..1b6ead1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * vrrp: add an `ip.yml` task file to help create VRRP addresses * webapps/nextcloud: Add compatibility with apache2, and apache2 mod_php. * inspect-domains: Add role +* memcached: NRPE check for multi-instance setup ### Changed diff --git a/memcached/files/check_memcached_instances.sh b/memcached/files/check_memcached_instances.sh new file mode 100644 index 00000000..9e468670 --- /dev/null +++ b/memcached/files/check_memcached_instances.sh @@ -0,0 +1,82 @@ +#!/bin/sh + +# {{ ansible_managed }} + +set -u + +return=0 +nb_crit=0 +nb_warn=0 +nb_ok=0 +nb_unchk=0 +output="" + +vendored_check=/usr/local/lib/nagios/plugins/check_memcached.pl + +if [ -x $vendored_check ]; then + check_bin=$vendored_check +else + echo "UNCHK - can't find check_memcached" + exit 3 +fi + +check_server() { + name=$1 + conf_file=$2 + + host=$(config_var "-l" "${conf_file}") + port=$(config_var "-p" "${conf_file}") + + cmd="${check_bin} -H ${host} -p ${port}" + + result=$($cmd) + ret="${?}" + if [ "${ret}" -ge 2 ]; then + nb_crit=$((nb_crit + 1)) + printf -v output "%s%s\n" "${output}" "${result}" + [ "${return}" -le 2 ] && return=2 + elif [ "${ret}" -ge 1 ]; then + nb_warn=$((nb_warn + 1)) + printf -v output "%s%s\n" "${output}" "${result}" + [ "${return}" -le 1 ] && return=1 + else + nb_ok=$((nb_ok + 1)) + printf -v output "%s%s\n" "${output}" "${result}" + [ "${return}" -le 0 ] && return=0 + fi +} +config_var() { + variable=$1 + file=$2 + test -f "${file}" && grep -E "^${variable}\s+.+$" "${file}" | awk '{ print $2 }' | sed -e "s/^[\"']//" -e "s/[\"']$//" +} + +# default instance +if systemctl is-enabled -q memcached; then + check_server "default" "/etc/memcached.conf" +fi + +# additional instances +conf_files=$(ls -1 /etc/memcached_*.conf 2> /dev/null) +for conf_file in ${conf_files}; do + name=$(basename "${conf_file}" | sed '{s|memcached_||;s|\.conf||}') + if systemctl is-enabled -q "memcached@${name}.service"; then + check_server "${name}" "${conf_file}" + else + nb_unchk=$((nb_unchk + 1)) + output="${output}UNCHK - ${name} (unit is disabled or missing)\n" + fi +done + +[ "${return}" -ge 0 ] && header="OK" +[ "${return}" -ge 1 ] && header="WARNING" +[ "${return}" -ge 2 ] && header="CRITICAL" + +printf "%s - %s UNCHK / %s CRIT / %s WARN / %s OK\n\n" "${header}" "${nb_unchk}" "${nb_crit}" "${nb_warn}" "${nb_ok}" + +printf "%s" "${output}" | grep -E "CRITICAL" +printf "%s" "${output}" | grep -E "WARNING" +printf "%s" "${output}" | grep -E "OK" +printf "%s" "${output}" | grep -E "UNCHK" + +exit "${return}" diff --git a/memcached/tasks/instance-default.yml b/memcached/tasks/instance-default.yml new file mode 100644 index 00000000..635b3576 --- /dev/null +++ b/memcached/tasks/instance-default.yml @@ -0,0 +1,17 @@ + +- name: Memcached is configured. + template: + src: memcached.conf.j2 + dest: /etc/memcached.conf + mode: "0644" + notify: restart memcached + tags: + - memcached + +- name: Memcached is running and enabled on boot. + service: + name: memcached + enabled: yes + state: started + tags: + - memcached diff --git a/memcached/tasks/instance-multi.yml b/memcached/tasks/instance-multi.yml new file mode 100644 index 00000000..61568a5d --- /dev/null +++ b/memcached/tasks/instance-multi.yml @@ -0,0 +1,41 @@ +--- + +- name: Add systemd unit template + copy: + src: memcached@.service + dest: /etc/systemd/system/memcached@.service + tags: + - memcached + +- name: Disable default memcached systemd unit + systemd: + name: memcached + enabled: false + state: stopped + tags: + - memcached + +- name: Make sure memcached.conf is absent + file: + path: /etc/memcached.conf + state: absent + tags: + - memcached + +- name: "Create a configuration file for instance ({{ memcached_instance_name }})" + template: + src: memcached.conf.j2 + dest: /etc/memcached_{{ memcached_instance_name }}.conf + mode: "0644" + tags: + - memcached + +- name: "Enable and start the memcached instance ({{ memcached_instance_name }})" + systemd: + name: memcached@{{ memcached_instance_name }} + enabled: yes + state: started + daemon_reload: yes + masked: no + tags: + - memcached diff --git a/memcached/tasks/main.yml b/memcached/tasks/main.yml index 0159f8d6..86d0aa40 100644 --- a/memcached/tasks/main.yml +++ b/memcached/tasks/main.yml @@ -1,73 +1,15 @@ -- name: ensure packages are installed +- name: Ensure memcached is installed apt: name: memcached state: present tags: - memcached -- name: Memcached is configured. - template: - src: memcached.conf.j2 - dest: /etc/memcached.conf - mode: "0644" - notify: restart memcached - tags: - - memcached - when: memcached_instance_name | length == 0 +- include: instance-default.yml + when: memcached_instance_name is undefined -- name: Memcached is running and enabled on boot. - service: - name: memcached - enabled: yes - state: started - tags: - - memcached - when: memcached_instance_name | length == 0 - -- name: Add systemd template - copy: - src: memcached@.service - dest: /etc/systemd/system/memcached@.service - tags: - - memcached - when: memcached_instance_name | length > 0 - -- name: Delete default memcached systemd configuration file - systemd: - name: memcached - enabled: false - state: stopped - tags: - - memcached - when: memcached_instance_name | length > 0 - -- name: Make sure memcached.conf is absent - file: - path: /etc/memcached.conf - state: absent - tags: - - memcached - when: memcached_instance_name | length > 0 - -- name: Create a configuration file - template: - src: memcached.conf.j2 - dest: /etc/memcached_{{ memcached_instance_name }}.conf - mode: "0644" - tags: - - memcached - when: memcached_instance_name | length > 0 - -- name: Enable and start the memcached instance - systemd: - name: memcached@{{ memcached_instance_name }} - enabled: yes - state: started - daemon_reload: yes - masked: no - tags: - - memcached - when: memcached_instance_name | length > 0 +- include: instance-multi.yml + when: memcached_instance_name is defined - include: munin.yml diff --git a/memcached/tasks/munin.yml b/memcached/tasks/munin.yml index 6e2f6d6f..f97962c4 100644 --- a/memcached/tasks/munin.yml +++ b/memcached/tasks/munin.yml @@ -2,7 +2,7 @@ - name: Choose packages (Oracle) set_fact: multi: "multi_" - when: memcached_instance_name | length > 0 + when: memcached_instance_name is defined - name: is Munin present ? stat: diff --git a/memcached/tasks/nrpe.yml b/memcached/tasks/nrpe.yml index 21070aec..ff0fc8b3 100644 --- a/memcached/tasks/nrpe.yml +++ b/memcached/tasks/nrpe.yml @@ -1,6 +1,4 @@ --- -- include_role: - name: evolix/remount-usr - name: Is nrpe present ? stat: @@ -10,7 +8,12 @@ - block: - name: Install dependencies apt: - name: libcache-memcached-perl + name: + - libcache-memcached-perl + - libmemcached11 + + - include_role: + name: evolix/remount-usr - name: Copy Nagios check for memcached copy: @@ -18,13 +21,29 @@ dest: /usr/local/lib/nagios/plugins/ mode: "0755" - # TODO: install a "multi-instances" check if the memcached_instance_name variable is not null + - name: install check_memcached_instances + copy: + src: check_memcached_instances.sh + dest: /usr/local/lib/nagios/plugins/check_memcached_instances + force: yes + mode: "0755" + owner: root + group: root - - name: Add NRPE check + - name: Add NRPE check (single instance) lineinfile: name: /etc/nagios/nrpe.d/evolix.cfg regexp: '^command\[check_memcached\]=' line: 'command[check_memcached]=/usr/local/lib/nagios/plugins/check_memcached.pl -H 127.0.0.1 -p {{ memcached_port }}' notify: restart nagios-nrpe-server + when: memcached_instance_name is undefined + + - name: Add NRPE check (multi instance) + lineinfile: + name: /etc/nagios/nrpe.d/evolix.cfg + regexp: '^command\[check_memcached\]=' + line: 'command[check_memcached]=/usr/local/lib/nagios/plugins/check_memcached_instances' + notify: restart nagios-nrpe-server + when: memcached_instance_name is defined when: nrpe_evolix_config.stat.exists From 0ec14fa2eb652fc8dac4149bacbeeb1a642f864c Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Thu, 1 Sep 2022 15:48:15 +0200 Subject: [PATCH 52/74] memcached: multi instance check requires bash instead of sh --- memcached/files/check_memcached_instances.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/memcached/files/check_memcached_instances.sh b/memcached/files/check_memcached_instances.sh index 9e468670..e97352f7 100644 --- a/memcached/files/check_memcached_instances.sh +++ b/memcached/files/check_memcached_instances.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # {{ ansible_managed }} From 4f0553c057eb7655ba96486d5f16a1567087ae3d Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Fri, 2 Sep 2022 10:18:48 +0200 Subject: [PATCH 53/74] webapp/nextcloud: use ini_file for php settings to not destror our zzz-evolinux-custom.ini --- .../files/zzz-apache2-evolinux-custom.ini | 20 ------- .../files/zzz-cli-evolinux-custom.ini | 4 -- webapps/nextcloud/tasks/apache-system.yml | 55 ++++++++++--------- 3 files changed, 29 insertions(+), 50 deletions(-) delete mode 100644 webapps/nextcloud/files/zzz-apache2-evolinux-custom.ini delete mode 100644 webapps/nextcloud/files/zzz-cli-evolinux-custom.ini diff --git a/webapps/nextcloud/files/zzz-apache2-evolinux-custom.ini b/webapps/nextcloud/files/zzz-apache2-evolinux-custom.ini deleted file mode 100644 index 361628c2..00000000 --- a/webapps/nextcloud/files/zzz-apache2-evolinux-custom.ini +++ /dev/null @@ -1,20 +0,0 @@ -; Put customized values here. -allow_url_fopen = On -disable_functions = exec,shell-exec,system,passthru,popen -disable_functions = -user_ini.filename = ".user.ini" -max_execution_time = 300 - -memory_limit = 512M - -opcache.enable=1 -opcache.enable_cli=1 -opcache.interned_strings_buffer=24 -opcache.max_accelerated_files=60000 -opcache.memory_consumption=512 -opcache.save_comments=1 -opcache.revalidate_freq=1 - - -upload_max_filesize = 2G -post_max_size = 2G \ No newline at end of file diff --git a/webapps/nextcloud/files/zzz-cli-evolinux-custom.ini b/webapps/nextcloud/files/zzz-cli-evolinux-custom.ini deleted file mode 100644 index f6785459..00000000 --- a/webapps/nextcloud/files/zzz-cli-evolinux-custom.ini +++ /dev/null @@ -1,4 +0,0 @@ -; Put customized values here. -; default_charset = "ISO-8859-1" -allow_url_fopen = On -apc.enable_cli=1 \ No newline at end of file diff --git a/webapps/nextcloud/tasks/apache-system.yml b/webapps/nextcloud/tasks/apache-system.yml index 38b85906..490d2f8d 100644 --- a/webapps/nextcloud/tasks/apache-system.yml +++ b/webapps/nextcloud/tasks/apache-system.yml @@ -1,30 +1,33 @@ --- -- name: Enable apache2 php configuration - copy: - src: "zzz-apache2-evolinux-custom.ini" - dest: "/etc/php/7.4/apache2/conf.d/zzz-evolinux-custom.ini" - mode: "0644" - owner: root - group: root - force: yes - notify: reload apache - tags: - - nextcloud +- name: "Get PHP Version" + shell: 'php -v | grep "PHP [0-9]." | sed -E "s/PHP ([0-9]\.[0-9]).*/\1/g;"' + register: shell_php + check_mode: no -- name: Enable cli php configuration - copy: - src: "zzz-cli-evolinux-custom.ini" - dest: "/etc/php/7.4/cli/conf.d/zzz-evolinux-custom.ini" - mode: "0644" - owner: root - group: root - force: yes - notify: reload apache - tags: - - nextcloud +- name: "Set variables" + set_fact: + php_version: "{{ shell_php.stdout }}" -# - name: Generate ssl config -# shell: -# cmd: "/usr/local/sbin/vhost-domains {{ nextcloud_instance_name }} | /usr/local/sbin/make-csr {{ nextcloud_instance_name }}" -# creates: "/etc/nginx/ssl/{{ nextcloud_instance_name }}.conf" \ No newline at end of file +- name: Apply specific PHP settings (apache) + ini_file: + path: "/etc/php/{{ php_version }}/apache2/conf.d/zzz-evolinux-custom.ini" + section: '' + option: "{{ item.option }}" + value: "{{ item.value }}" + notify: reload apache + with_items: + - {option: 'allow_url_fopen', value: 'On'} + - {option: 'disable_functions', value: ''} + - {option: 'max_execution_time', value: '300'} + - {option: 'memory_limit', value: '512M'} + +- name: Apply specific PHP settings (cli) + ini_file: + path: "/etc/php/{{ php_version }}/cli/conf.d/zzz-evolinux-custom.ini" + section: '' + option: "{{ item.option }}" + value: "{{ item.value }}" + with_items: + - {option: 'allow_url_fopen', value: 'On'} + - {option: 'apc.enable_cli', value: 'On'} From 18b450b8c3fbce34b68b6cdc54758a2dd76498f8 Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Fri, 2 Sep 2022 10:25:22 +0200 Subject: [PATCH 54/74] webapp/nextcloud: Updates on vhost - Add comments for SSL settinfs - Remove userlog --- .../nextcloud/templates/apache-vhost.conf.j2 | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/webapps/nextcloud/templates/apache-vhost.conf.j2 b/webapps/nextcloud/templates/apache-vhost.conf.j2 index 6844933d..ff9f621c 100644 --- a/webapps/nextcloud/templates/apache-vhost.conf.j2 +++ b/webapps/nextcloud/templates/apache-vhost.conf.j2 @@ -1,10 +1,14 @@ - + ServerName {{ nextcloud_domains[0] }} {% for domain_alias in nextcloud_domains[1:] %} ServerAlias {{ domain_alias }} {% endfor %} + # SSLEngine on + # SSLCertificateFile /etc/letsencrypt/live/{{ nextcloud_instance_name }}/fullchain.pem + # SSLCertificateKeyFile /etc/letsencrypt/live/{{ nextcloud_instance_name }}/privkey.pem + DocumentRoot {{ nextcloud_webroot }}/ @@ -17,16 +21,21 @@ - # user - group (thanks to sesse@debian.org) + # SSL Redirect + # RewriteEngine On + # RewriteCond %{HTTPS} !=on + # RewriteCond %{HTTP:X-Forwarded-Proto} !=https + # RewriteRule ^ https://%{HTTP:Host}%{REQUEST_URI} [L,R=permanent] + + # ITK AssignUserID {{ nextcloud_user }} {{ nextcloud_user }} # LOG CustomLog /var/log/apache2/access.log vhost_combined - CustomLog /home/{{ nextcloud_instance_name }}/log/access.log combined - ErrorLog /home/{{ nextcloud_instance_name }}/log/error.log + ErrorLog /var/log/apache2/error.log # PHP php_admin_value sendmail_path "/usr/sbin/sendmail -t -i -f {{ nextcloud_user }}" php_admin_value open_basedir "/usr/share/php:{{ nextcloud_home }}:/tmp" - + \ No newline at end of file From 6fa89e69a50d2bc86ace33d7e173dfa69331660b Mon Sep 17 00:00:00 2001 From: William Hirigoyen Date: Fri, 2 Sep 2022 15:48:05 +0200 Subject: [PATCH 55/74] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b6ead1b..5042ef48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * generate-ldif: Support any MariaDB version * openvpn: automate the initialization of the CA and the creation of the server certificate ; use openssl_dhparam module instead of a command * nagios-nrpe: Add check_domains +* generate-ldif: support any version of MariaDB (instead of only 10.0, 10.1 and 10.3) ### Fixed @@ -32,6 +33,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * varnish: make `-j ` the first argument on jessie/stretch as it has to be the first argument there. * redis: config directory must be owned by the user that runs the service (to be able to write tmp config files in it) * webapps/nextcloud: Add missing dependencies for imagick +* mysql: Add missing Munin conf for Debian 11 ### Removed From c28ded807d3f61df561ad1c02a3fdd350fcb50e6 Mon Sep 17 00:00:00 2001 From: Eric Morino Date: Mon, 5 Sep 2022 11:42:49 +0200 Subject: [PATCH 56/74] Fix command for generate password with mkpasswd --- proftpd/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proftpd/README.md b/proftpd/README.md index dae8abef..6e96e05a 100644 --- a/proftpd/README.md +++ b/proftpd/README.md @@ -41,5 +41,5 @@ proftpd_accounts: For generate the sha512 version of yours password : ~~~ -echo "test" | mkpasswd --method=sha-512 - +printf "test" | mkpasswd --stdin --method=sha-512 ~~~ From 7e979132f798109f9ced5796b5cc94631816282a Mon Sep 17 00:00:00 2001 From: William Hirigoyen Date: Mon, 5 Sep 2022 18:50:07 +0200 Subject: [PATCH 57/74] inspect-domains : add Nginx support --- inspect-domains/files/inspect-domains.py | 99 +++++++++++++++++++----- 1 file changed, 79 insertions(+), 20 deletions(-) diff --git a/inspect-domains/files/inspect-domains.py b/inspect-domains/files/inspect-domains.py index e1120994..8512b04c 100755 --- a/inspect-domains/files/inspect-domains.py +++ b/inspect-domains/files/inspect-domains.py @@ -17,6 +17,7 @@ import subprocess import threading import time import argparse +import json #import importlib.machinery #list_domains = importlib.machinery.SourceFileLoader('list_domains.py', list_domains_path).load_module() @@ -40,7 +41,7 @@ def get_my_ips(): stdout, stderr = execute('hostname -I') if not stdout: return [] - return stdout[0].strip().split() + return stdout[0].strip(' \t').split() def dig(domain): @@ -48,6 +49,12 @@ def dig(domain): stdout, stderr = execute('dig +short {}'.format(domain)) return stdout + +def strip_comments(string): + """Return string with any # comment removed.""" + return string.split('#')[0] + + def list_apache_domains(): """Return a dict containing : - key: Apache domain (from command "apache2ctl -D DUMP_VHOSTS"). @@ -56,24 +63,24 @@ def list_apache_domains(): domains = {} try: - stdout, stderr = execute("apache2ctl -D DUMP_VHOSTS") + stdout, stderr = execute('apache2ctl -D DUMP_VHOSTS') except: - # Apache is not on the server + # Apache is not present on the server return domains - vhost_infos = "" + vhost_infos = '' for line in stdout: - dom = "" - words = line.strip().split() + dom = '' + words = line.strip(' \t').split() - if "namevhost" in line and len(words) >= 5: + if 'namevhost' in line and len(words) >= 5: # line format: port namevhost (:) - dom = words[3] - vhost_infos = "apache:" + words[4].strip('()') + dom = words[3].strip() + vhost_infos = 'apache:' + words[4].strip('()') - elif "alias" in line and len(words) >= 2: + elif 'alias' in line and len(words) >= 2: # line format: alias - dom = words[1] # vhost_infos defined in previous lines + dom = words[1].strip() # vhost_infos defined in previous lines if dom: if dom not in domains: @@ -84,6 +91,54 @@ def list_apache_domains(): return domains +def list_nginx_domains(): + """Return a dict containing : + - key: Nginx domain (from command "nginx -T"). + - value: a list of strings "nginx::" + """ + domains = {} + + try: + stdout, stderr = execute('nginx -T') + except: + # Nginx is not present on the server + return domains + + line_number = 1 + config_file_path = '' + + for line in stdout: + if '# configuration file' in line: + # line format : # configuration file : + words = line.strip(' \t;').split() + config_file_path = words[3].strip(' :') + continue + + if 'server_name ' in line: + # TODO: améliorer le if (cas tabulation) + # line format : server_name [ Date: Tue, 6 Sep 2022 11:26:19 +0200 Subject: [PATCH 58/74] openvpn: Run OpenVPN with the \_openvpn user and group instead of nobody which is originally for NFS --- CHANGELOG.md | 1 + openvpn/tasks/debian.yml | 8 ++++++++ openvpn/templates/server.conf.j2 | 4 ++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5042ef48..4dcaa63d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * openvpn: automate the initialization of the CA and the creation of the server certificate ; use openssl_dhparam module instead of a command * nagios-nrpe: Add check_domains * generate-ldif: support any version of MariaDB (instead of only 10.0, 10.1 and 10.3) +* openvpn: Run OpenVPN with the \_openvpn user and group instead of nobody which is originally for NFS ### Fixed diff --git a/openvpn/tasks/debian.yml b/openvpn/tasks/debian.yml index d6b03ac9..55ca2f8e 100644 --- a/openvpn/tasks/debian.yml +++ b/openvpn/tasks/debian.yml @@ -12,6 +12,14 @@ - client - server +- name: Create the _openvpn user + user: + name: _openvpn + system: yes + create_home: no + home: "/nonexistent" + shell: "/usr/sbin/nologin" + - name: Create the shellpki user user: name: shellpki diff --git a/openvpn/templates/server.conf.j2 b/openvpn/templates/server.conf.j2 index 23ce3e2b..a41b9b22 100644 --- a/openvpn/templates/server.conf.j2 +++ b/openvpn/templates/server.conf.j2 @@ -1,5 +1,5 @@ -user nobody -group nogroup +user _openvpn +group _openvpn local {{ ansible_default_ipv4.address }} port 1194 From 3c1ec588fd3a5ec9e99bbda3b96545c47ab5fcfb Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Fri, 9 Sep 2022 16:09:45 +0200 Subject: [PATCH 59/74] minifirewall: use handlers to restart minifirewall --- CHANGELOG.md | 1 + minifirewall/handlers/main.yml | 16 ++++++++++ minifirewall/tasks/config.legacy.yml | 16 ++++------ minifirewall/tasks/config.yml | 8 ++--- minifirewall/tasks/main.yml | 45 ++++++++++++++++++---------- minifirewall/tasks/tail.legacy.yml | 36 ++++++++++++++-------- minifirewall/tasks/tail.yml | 36 ++++++++++++++-------- 7 files changed, 103 insertions(+), 55 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dcaa63d..c36e3de0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * evocheck: upstream release 22.08.1 * generate-ldif: Support any MariaDB version +* minifirewall: use handlers to restart minifirewall * openvpn: automate the initialization of the CA and the creation of the server certificate ; use openssl_dhparam module instead of a command * nagios-nrpe: Add check_domains * generate-ldif: support any version of MariaDB (instead of only 10.0, 10.1 and 10.3) diff --git a/minifirewall/handlers/main.yml b/minifirewall/handlers/main.yml index 5ba1926c..3c541de5 100644 --- a/minifirewall/handlers/main.yml +++ b/minifirewall/handlers/main.yml @@ -4,3 +4,19 @@ service: name: nagios-nrpe-server state: restarted + +- name: restart minifirewall (modern) + command: /etc/init.d/minifirewall restart + register: minifirewall_init_restart + failed_when: "'minifirewall failed' in minifirewall_init_restart.stdout" + +- name: restart minifirewall (legacy) + command: /etc/init.d/minifirewall restart + register: minifirewall_init_restart + failed_when: "'starting IPTables rules is now finish : OK' not in minifirewall_init_restart.stdout" + +- name: restart minifirewall (noop) + meta: noop + register: minifirewall_init_restart + failed_when: False + changed_when: False \ No newline at end of file diff --git a/minifirewall/tasks/config.legacy.yml b/minifirewall/tasks/config.legacy.yml index 8a7f5990..a151e76c 100644 --- a/minifirewall/tasks/config.legacy.yml +++ b/minifirewall/tasks/config.legacy.yml @@ -197,21 +197,15 @@ path: "{{ minifirewall_main_file }}" register: minifirewall_after -- name: restart minifirewall - command: /etc/init.d/minifirewall restart - register: minifirewall_init_restart - failed_when: "'starting IPTables rules is now finish : OK' not in minifirewall_init_restart.stdout" +- name: Schedule minifirewall restart (legacy) + command: /bin/true + notify: "restart minifirewall (legacy)" when: + - minifirewall_install_mode == 'legacy' - minifirewall_restart_if_needed | bool - minifirewall_is_running.rc == 0 - - minifirewall_before.stat.checksum != minifirewall_after.stat.checksum + - minifirewall_before.stat.checksum != minifirewall_after.stat.checksum or minifirewall_upgrade_script is changed or minifirewall_upgrade_config is changed -- name: restart minifirewall (noop) - meta: noop - register: minifirewall_init_restart - failed_when: False - changed_when: False - when: not (minifirewall_restart_if_needed | bool) - debug: var: minifirewall_init_restart diff --git a/minifirewall/tasks/config.yml b/minifirewall/tasks/config.yml index c11b83e8..b0a1d7a6 100644 --- a/minifirewall/tasks/config.yml +++ b/minifirewall/tasks/config.yml @@ -282,11 +282,11 @@ path: "/etc/default/minifirewall" register: minifirewall_after -- name: restart minifirewall - command: /etc/init.d/minifirewall restart - register: minifirewall_init_restart - failed_when: "'minifirewall failed' in minifirewall_init_restart.stdout" +- name: Schedule minifirewall restart (modern) + command: /bin/true + notify: "restart minifirewall (modern)" when: + - minifirewall_install_mode != 'legacy' - minifirewall_restart_if_needed | bool - minifirewall_is_running.rc == 0 - minifirewall_before.stat.checksum != minifirewall_after.stat.checksum or minifirewall_upgrade_script is changed or minifirewall_upgrade_config is changed diff --git a/minifirewall/tasks/main.yml b/minifirewall/tasks/main.yml index 483f8715..bc56b7dc 100644 --- a/minifirewall/tasks/main.yml +++ b/minifirewall/tasks/main.yml @@ -1,9 +1,5 @@ --- -- name: Compose minifirewall_restart_handler_name variable - set_fact: - minifirewall_restart_handler_name: "{{ minifirewall_restart_if_needed | bool | ternary('restart minifirewall', 'restart minifirewall (noop)') }}" - # Legacy or modern mode? ############################################## - name: Check minifirewall @@ -39,6 +35,25 @@ var: minifirewall_install_mode verbosity: 1 +- name: 'Set minifirewall_restart_handler_name to "noop"' + set_fact: + minifirewall_restart_handler_name: "restart minifirewall (noop)" + when: not (minifirewall_restart_if_needed | bool) + +- name: 'Set minifirewall_restart_handler_name to "legacy"' + set_fact: + minifirewall_restart_handler_name: "restart minifirewall (legacy)" + when: + - minifirewall_restart_if_needed | bool + - minifirewall_install_mode == 'legacy' + +- name: 'Set minifirewall_restart_handler_name to "modern"' + set_fact: + minifirewall_restart_handler_name: "restart minifirewall (modern)" + when: + - minifirewall_restart_if_needed | bool + - minifirewall_install_mode != 'legacy' + ####################################################################### - name: Fail if minifirewall_main_file is defined (legacy mode) @@ -106,18 +121,16 @@ var: minifirewall_restart_force | bool verbosity: 1 -- name: Force restart minifirewall (modern mode) - command: /etc/init.d/minifirewall restart - register: minifirewall_init_restart - failed_when: "'minifirewall failed' in minifirewall_init_restart.stdout" - when: - - minifirewall_install_mode != 'legacy' - - minifirewall_restart_force | bool - -- name: Force restart minifirewall (legacy mode) - command: /etc/init.d/minifirewall restart - register: minifirewall_init_restart - failed_when: "'starting IPTables rules is now finish : OK' not in minifirewall_init_restart.stdout" +- name: Force restart minifirewall (legacy) + command: /bin/true + notify: "restart minifirewall (legacy)" when: - minifirewall_install_mode == 'legacy' + - minifirewall_restart_force | bool + +- name: Force restart minifirewall (modern) + command: /bin/true + notify: "restart minifirewall (modern)" + when: + - minifirewall_install_mode != 'legacy' - minifirewall_restart_force | bool \ No newline at end of file diff --git a/minifirewall/tasks/tail.legacy.yml b/minifirewall/tasks/tail.legacy.yml index 7a13eefa..dc7fbdc9 100644 --- a/minifirewall/tasks/tail.legacy.yml +++ b/minifirewall/tasks/tail.legacy.yml @@ -1,4 +1,22 @@ --- + +- name: Stat minifirewall config file (before) + stat: + path: "/etc/default/minifirewall" + register: minifirewall_before + +- name: Check if minifirewall is running + shell: + cmd: /sbin/iptables -L -n | grep -E "^(DROP\s+udp|ACCEPT\s+icmp)\s+--\s+0\.0\.0\.0\/0\s+0\.0\.0\.0\/0\s*$" + changed_when: False + failed_when: False + check_mode: no + register: minifirewall_is_running + +- debug: + var: minifirewall_is_running + verbosity: 1 + - name: Add some rules at the end of minifirewall file template: src: "{{ item }}" @@ -30,20 +48,14 @@ var: minifirewall_tail_source verbosity: 1 -- name: restart minifirewall - command: /etc/init.d/minifirewall restart - register: minifirewall_init_restart - failed_when: "'starting IPTables rules is now finish : OK' not in minifirewall_init_restart.stdout" +- name: Schedule minifirewall restart (legacy) + command: /bin/true + notify: "restart minifirewall (legacy)" when: - - minifirewall_tail_template is changed + - minifirewall_install_mode == 'legacy' - minifirewall_restart_if_needed | bool - -- name: restart minifirewall (noop) - meta: noop - register: minifirewall_init_restart - failed_when: False - changed_when: False - when: not (minifirewall_restart_if_needed | bool) + - minifirewall_is_running.rc == 0 + - minifirewall_tail_template is changed - debug: var: minifirewall_init_restart diff --git a/minifirewall/tasks/tail.yml b/minifirewall/tasks/tail.yml index 1d708fa4..73d60d9c 100644 --- a/minifirewall/tasks/tail.yml +++ b/minifirewall/tasks/tail.yml @@ -1,4 +1,22 @@ --- + +- name: Stat minifirewall config file (before) + stat: + path: "/etc/default/minifirewall" + register: minifirewall_before + +- name: Check if minifirewall is running + shell: + cmd: /sbin/iptables -L -n | grep -E "^(DROP\s+udp|ACCEPT\s+icmp)\s+--\s+0\.0\.0\.0\/0\s+0\.0\.0\.0\/0\s*$" + changed_when: False + failed_when: False + check_mode: no + register: minifirewall_is_running + +- debug: + var: minifirewall_is_running + verbosity: 1 + - name: Add some rules at the end of minifirewall file template: src: "{{ item }}" @@ -18,20 +36,14 @@ var: minifirewall_tail_template verbosity: 1 -- name: restart minifirewall - command: /etc/init.d/minifirewall restart - register: minifirewall_init_restart - failed_when: "'minifirewall failed' in minifirewall_init_restart.stdout" +- name: Schedule minifirewall restart (modern) + command: /bin/true + notify: "restart minifirewall (modern)" when: - - minifirewall_tail_template is changed + - minifirewall_install_mode != 'legacy' - minifirewall_restart_if_needed | bool - -- name: restart minifirewall (noop) - meta: noop - register: minifirewall_init_restart - failed_when: False - changed_when: False - when: not (minifirewall_restart_if_needed | bool) + - minifirewall_is_running.rc == 0 + - minifirewall_tail_template is changed - debug: var: minifirewall_init_restart From 28276b5d6f739367d1c6cb4bd12f7d596665160b Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Mon, 12 Sep 2022 13:54:57 +0200 Subject: [PATCH 60/74] evolinux-base: update-evobackup-canary upstream release 22.06 --- CHANGELOG.md | 1 + ...ackup-canary.sh => update-evobackup-canary} | 6 +++--- evolinux-base/tasks/utils.yml | 18 +++++++++--------- 3 files changed, 13 insertions(+), 12 deletions(-) rename evolinux-base/files/{update-evobackup-canary.sh => update-evobackup-canary} (95%) diff --git a/CHANGELOG.md b/CHANGELOG.md index c36e3de0..340bfb99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Changed * evocheck: upstream release 22.08.1 +* evolinux-base: update-evobackup-canary upstream release 22.06 * generate-ldif: Support any MariaDB version * minifirewall: use handlers to restart minifirewall * openvpn: automate the initialization of the CA and the creation of the server certificate ; use openssl_dhparam module instead of a command diff --git a/evolinux-base/files/update-evobackup-canary.sh b/evolinux-base/files/update-evobackup-canary similarity index 95% rename from evolinux-base/files/update-evobackup-canary.sh rename to evolinux-base/files/update-evobackup-canary index 20fc1a57..868c3be6 100644 --- a/evolinux-base/files/update-evobackup-canary.sh +++ b/evolinux-base/files/update-evobackup-canary @@ -3,7 +3,7 @@ PROGNAME="update-evobackup-canary" REPOSITORY="https://gitea.evolix.org/evolix/evobackup" -VERSION="22.05" +VERSION="22.06" readonly VERSION # base functions @@ -44,8 +44,8 @@ main() { if [ -z "${canary_file:-}" ]; then canary_file="/zzz_evobackup_canary" fi - # This option is supported since (at least) Debian 8 - date=$(date --iso-8601=seconds) + # This option is supported both on OpenBSD which does not use GNU date and on Debian + date=$(date "+%FT%T%z") printf "%s %s\n" "${date}" "${who}" >> "${canary_file}" } diff --git a/evolinux-base/tasks/utils.yml b/evolinux-base/tasks/utils.yml index 8236bd92..2fd4b0c1 100644 --- a/evolinux-base/tasks/utils.yml +++ b/evolinux-base/tasks/utils.yml @@ -17,7 +17,7 @@ - name: update-evobackup-canary script is present copy: - src: "update-evobackup-canary.sh" + src: update-evobackup-canary dest: /usr/local/bin/update-evobackup-canary force: True owner: root @@ -30,11 +30,11 @@ path: /usr/local/sbin/update-evobackup-canary state: absent -- name: dir-check script is present - copy: - src: "dir-check.sh" - dest: /usr/local/bin/dir-check - force: True - owner: root - group: root - mode: "0755" \ No newline at end of file +# - name: dir-check script is present +# copy: +# src: "dir-check.sh" +# dest: /usr/local/bin/dir-check +# force: True +# owner: root +# group: root +# mode: "0755" \ No newline at end of file From 7c4a169fb8e276db0f3d8ff532609d82b192aabe Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Tue, 13 Sep 2022 16:26:10 +0200 Subject: [PATCH 61/74] proftpd: Add options to override configs --- CHANGELOG.md | 1 + proftpd/defaults/main.yml | 3 +++ proftpd/tasks/main.yml | 6 +++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 340bfb99..7064c1fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * webapps/nextcloud: Add compatibility with apache2, and apache2 mod_php. * inspect-domains: Add role * memcached: NRPE check for multi-instance setup +* proftpd: Add options to override configs ### Changed diff --git a/proftpd/defaults/main.yml b/proftpd/defaults/main.yml index 80edecd2..1f8cf006 100644 --- a/proftpd/defaults/main.yml +++ b/proftpd/defaults/main.yml @@ -3,12 +3,15 @@ proftpd_hostname: "{{ ansible_hostname }}" proftpd_fqdn: "{{ ansible_fqdn }}" proftpd_default_address: [] proftpd_ftp_enable: True +proftpd_ftp_override: False proftpd_port: 21 proftpd_ftps_enable: False +proftpd_ftps_override: False proftpd_ftps_port: 990 proftpd_ftps_cert: "/etc/ssl/certs/ssl-cert-snakeoil.pem" proftpd_ftps_key: "/etc/ssl/private/ssl-cert-snakeoil.key" proftpd_sftp_enable: False +proftpd_sftp_override: False proftpd_sftp_port: 22222 proftpd_accounts: [] proftpd_accounts_final: [] diff --git a/proftpd/tasks/main.yml b/proftpd/tasks/main.yml index 457887a1..ddb3faee 100644 --- a/proftpd/tasks/main.yml +++ b/proftpd/tasks/main.yml @@ -20,7 +20,7 @@ src: evolinux.conf.j2 dest: /etc/proftpd/conf.d/z-evolinux.conf mode: "0644" - force: no + force: "{{ proftpd_ftp_override }}" notify: restart proftpd when: proftpd_ftp_enable | bool tags: @@ -31,7 +31,7 @@ src: ftps.conf.j2 dest: /etc/proftpd/conf.d/ftps.conf mode: "0644" - force: no + force: "{{ proftpd_ftps_override }}" notify: restart proftpd when: proftpd_ftps_enable | bool tags: @@ -42,7 +42,7 @@ src: sftp.conf.j2 dest: /etc/proftpd/conf.d/sftp.conf mode: "0644" - force: no + force: "{{ proftpd_sftp_override }}" notify: restart proftpd when: proftpd_sftp_enable | bool tags: From 9631476a06cc5d3cc91c76731be4bef07dd8d06e Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Tue, 13 Sep 2022 16:29:59 +0200 Subject: [PATCH 62/74] proftpd: Allow user auth with ssh keys --- CHANGELOG.md | 1 + proftpd/defaults/main.yml | 1 + proftpd/tasks/accounts.yml | 15 +++++++++++++++ proftpd/tasks/main.yml | 14 ++++++++++++++ proftpd/templates/sftp.conf.j2 | 8 +++++++- 5 files changed, 38 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7064c1fb..dce6bf3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * inspect-domains: Add role * memcached: NRPE check for multi-instance setup * proftpd: Add options to override configs +* proftpd: Allow user auth with ssh keys ### Changed diff --git a/proftpd/defaults/main.yml b/proftpd/defaults/main.yml index 1f8cf006..25d60d5b 100644 --- a/proftpd/defaults/main.yml +++ b/proftpd/defaults/main.yml @@ -12,6 +12,7 @@ proftpd_ftps_cert: "/etc/ssl/certs/ssl-cert-snakeoil.pem" proftpd_ftps_key: "/etc/ssl/private/ssl-cert-snakeoil.key" proftpd_sftp_enable: False proftpd_sftp_override: False +proftpd_sftp_use_publickeys: False proftpd_sftp_port: 22222 proftpd_accounts: [] proftpd_accounts_final: [] diff --git a/proftpd/tasks/accounts.yml b/proftpd/tasks/accounts.yml index 756e0ff0..0ff57272 100644 --- a/proftpd/tasks/accounts.yml +++ b/proftpd/tasks/accounts.yml @@ -60,3 +60,18 @@ when: proftpd_sftp_enable | bool tags: - proftpd + +- name: Allow keys for SFTP account + blockinfile: + dest: "/etc/proftpd/sftp.authorized_keys/{{ item.name }}" + state: present + block: "{{ item.sshkeys }}" + create: yes + mode: 0600 + loop: "{{ proftpd_accounts_final }}" + notify: restart proftpd + when: + - proftpd_sftp_enable | bool + - proftpd_sftp_use_publickeys | bool + tags: + - proftpd diff --git a/proftpd/tasks/main.yml b/proftpd/tasks/main.yml index ddb3faee..9ddb6273 100644 --- a/proftpd/tasks/main.yml +++ b/proftpd/tasks/main.yml @@ -48,6 +48,20 @@ tags: - proftpd +- name: SFTP key folder exists if needed + file: + path: /etc/proftpd/sftp.authorized_keys/ + state: directory + mode: "0700" + owner: root + group: root + notify: restart proftpd + when: + - proftpd_sftp_enable | bool + - proftpd_sftp_use_publickeys | bool + tags: + - proftpd + - name: mod_tls_memcache is disabled replace: dest: /etc/proftpd/modules.conf diff --git a/proftpd/templates/sftp.conf.j2 b/proftpd/templates/sftp.conf.j2 index 432e9ba8..f54746f8 100644 --- a/proftpd/templates/sftp.conf.j2 +++ b/proftpd/templates/sftp.conf.j2 @@ -13,8 +13,14 @@ SFTPLog /var/log/proftpd/sftp.log TransferLog /var/log/proftpd/xferlog - + +{% if proftpd_sftp_use_publickeys %} + SFTPAuthMethods publickey password + SFTPAuthorizedUserKeys file:/etc/proftpd/sftp.authorized_keys/%u +{% else %} SFTPAuthMethods password +{% endif %} + SFTPHostKey /etc/ssh/ssh_host_ecdsa_key SFTPHostKey /etc/ssh/ssh_host_rsa_key From cd46dd8320fb50d61781748bf786c285d059050b Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Tue, 13 Sep 2022 16:31:03 +0200 Subject: [PATCH 63/74] proftpd: Add a warning if config file was overriden --- CHANGELOG.md | 2 +- proftpd/templates/evolinux.conf.j2 | 4 ++++ proftpd/templates/ftps.conf.j2 | 4 ++++ proftpd/templates/sftp.conf.j2 | 4 ++++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dce6bf3a..be884139 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * webapps/nextcloud: Add compatibility with apache2, and apache2 mod_php. * inspect-domains: Add role * memcached: NRPE check for multi-instance setup -* proftpd: Add options to override configs +* proftpd: Add options to override configs (and add a warning if file was overriden) * proftpd: Allow user auth with ssh keys ### Changed diff --git a/proftpd/templates/evolinux.conf.j2 b/proftpd/templates/evolinux.conf.j2 index 08484714..8ad06927 100644 --- a/proftpd/templates/evolinux.conf.j2 +++ b/proftpd/templates/evolinux.conf.j2 @@ -1,5 +1,9 @@ # Evolix's specific configuration +{% if proftpd_ftp_override %} +# WARNING : **Probably** ansible managed +{% endif %} + LoadModule mod_ident.c diff --git a/proftpd/templates/ftps.conf.j2 b/proftpd/templates/ftps.conf.j2 index 2db74b37..f9826989 100644 --- a/proftpd/templates/ftps.conf.j2 +++ b/proftpd/templates/ftps.conf.j2 @@ -1,3 +1,7 @@ +{% if proftpd_ftps_override %} +# WARNING : **Probably** ansible managed +{% endif %} + LoadModule mod_tls.c diff --git a/proftpd/templates/sftp.conf.j2 b/proftpd/templates/sftp.conf.j2 index f54746f8..457f638b 100644 --- a/proftpd/templates/sftp.conf.j2 +++ b/proftpd/templates/sftp.conf.j2 @@ -1,3 +1,7 @@ +{% if proftpd_sftp_override %} +# WARNING : **Probably** ansible managed +{% endif %} + LoadModule mod_tls.c From 41e908da5c6e0304707cc82f88be8730ec522a4c Mon Sep 17 00:00:00 2001 From: William Hirigoyen Date: Wed, 14 Sep 2022 10:44:12 +0200 Subject: [PATCH 64/74] inspect-domains: Renamme inspect-domains to domains --- .../files/inspect-domains.py => domains/files/domains.py | 0 {inspect-domains => domains}/tasks/main.yml | 2 +- nagios-nrpe/files/plugins/check_domains | 8 ++++---- nagios-nrpe/tasks/configure_check_domains.yml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) rename inspect-domains/files/inspect-domains.py => domains/files/domains.py (100%) rename {inspect-domains => domains}/tasks/main.yml (74%) diff --git a/inspect-domains/files/inspect-domains.py b/domains/files/domains.py similarity index 100% rename from inspect-domains/files/inspect-domains.py rename to domains/files/domains.py diff --git a/inspect-domains/tasks/main.yml b/domains/tasks/main.yml similarity index 74% rename from inspect-domains/tasks/main.yml rename to domains/tasks/main.yml index f5d915fe..388f75ee 100644 --- a/inspect-domains/tasks/main.yml +++ b/domains/tasks/main.yml @@ -1,7 +1,7 @@ - name: Copy inspect-domains script to local sbin ansible.builtin.copy: src: inspect-domains.py - dest: /usr/local/sbin/inspect-domains + dest: /usr/local/sbin/domains mode: '0700' diff --git a/nagios-nrpe/files/plugins/check_domains b/nagios-nrpe/files/plugins/check_domains index 78db2914..98068a0b 100755 --- a/nagios-nrpe/files/plugins/check_domains +++ b/nagios-nrpe/files/plugins/check_domains @@ -1,14 +1,14 @@ #!/bin/bash # -# Check domains using script inspect-domains. +# Check domains using script domains. # # Written by Will # -if ! command -v inspect-domains >/dev/null; then - echo 'UNKNOWN - Missing dependency inspect-domains.' +if ! command -v domains >/dev/null; then + echo 'UNKNOWN - Missing dependency domains.' exit 3 fi -inspect-domains -o nrpe -a check-dns +domains -o nrpe -a check-dns diff --git a/nagios-nrpe/tasks/configure_check_domains.yml b/nagios-nrpe/tasks/configure_check_domains.yml index 0d81b652..2d5dd2fd 100644 --- a/nagios-nrpe/tasks/configure_check_domains.yml +++ b/nagios-nrpe/tasks/configure_check_domains.yml @@ -1,6 +1,6 @@ - name: Install check_domains dependency include_role: - name: inspect-domains + name: domains - name: Configure check_domains in /etc/nagios/nrpe.d/evolix.cfg ansible.builtin.lineinfile: From 25cedd2be9ba234972ee3286e39fb9e89c87a114 Mon Sep 17 00:00:00 2001 From: William Hirigoyen Date: Wed, 14 Sep 2022 10:47:52 +0200 Subject: [PATCH 65/74] domains: fix rename inspect-domains to domains --- domains/tasks/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domains/tasks/main.yml b/domains/tasks/main.yml index 388f75ee..f2a1ddb3 100644 --- a/domains/tasks/main.yml +++ b/domains/tasks/main.yml @@ -1,6 +1,6 @@ - name: Copy inspect-domains script to local sbin ansible.builtin.copy: - src: inspect-domains.py + src: domains.py dest: /usr/local/sbin/domains mode: '0700' From d8a2dccf36d5e20c8f0da17d381bce4a043f90f0 Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Wed, 14 Sep 2022 10:55:00 +0200 Subject: [PATCH 66/74] evocheck: upstream release 22.09 --- CHANGELOG.md | 2 +- evocheck/files/evocheck.sh | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be884139..2e46e8c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,7 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Changed -* evocheck: upstream release 22.08.1 +* evocheck: upstream release 22.09 * evolinux-base: update-evobackup-canary upstream release 22.06 * generate-ldif: Support any MariaDB version * minifirewall: use handlers to restart minifirewall diff --git a/evocheck/files/evocheck.sh b/evocheck/files/evocheck.sh index 2771c904..7c01da51 100644 --- a/evocheck/files/evocheck.sh +++ b/evocheck/files/evocheck.sh @@ -4,7 +4,7 @@ # Script to verify compliance of a Linux (Debian) server # powered by Evolix -VERSION="22.08.1" +VERSION="22.09" readonly VERSION # base functions @@ -1527,6 +1527,8 @@ main() { main_output_file=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.main.XXXXX") files_to_cleanup="${files_to_cleanup} ${main_output_file}" + MINIFW_FILE=$(minifirewall_file) + test "${IS_TMP_1777:=1}" = 1 && check_tmp_1777 test "${IS_ROOT_0700:=1}" = 1 && check_root_0700 test "${IS_USRSHARESCRIPTS:=1}" = 1 && check_usrsharescripts From 6ce30048180eb68d8da73c941405aaaaa4cb94e6 Mon Sep 17 00:00:00 2001 From: William Hirigoyen Date: Wed, 14 Sep 2022 11:03:49 +0200 Subject: [PATCH 67/74] domains: improve CLI user interface (messages, option names...). --- domains/files/domains.py | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/domains/files/domains.py b/domains/files/domains.py index 8512b04c..23dd28ee 100755 --- a/domains/files/domains.py +++ b/domains/files/domains.py @@ -236,7 +236,7 @@ def output_check_mode(timeout_domains, none_domains, outside_ips, ok_domains): sys.exit(1) if n_warnings else sys.exit(0) -def output_friendly_mode(doms, timeout_domains, none_domains, outside_ips): +def output_human_mode(doms, timeout_domains, none_domains, outside_ips): if timeout_domains or none_domains or outside_ips: if timeout_domains: print('\nTimeouts:') for d in timeout_domains: @@ -256,23 +256,23 @@ def output_friendly_mode(doms, timeout_domains, none_domains, outside_ips): def main(argv): parser = argparse.ArgumentParser() parser.add_argument('action', metavar='ACTION', help='Values: check-dns, list') - parser.add_argument('-o', '--output-style', help='Values: stdout (default), nrpe') + parser.add_argument('-o', '--output-style', help='Values: json (default for action list), human (default for action check-dns), nrpe') parser.add_argument('-a', '--all-domains', action='store_true', help='Include all domains (default).') parser.add_argument('-ap', '--apache-domains', action='store_true', help='Include Apache domains.') parser.add_argument('-ng', '--nginx-domains', action='store_true', help='Include Nginx domains.') - parser.add_argument('-ha', '--haproxy-domains', action='store_true', help='Include HaProxy domains.') + parser.add_argument('-ha', '--haproxy-domains', action='store_true', help='Include HaProxy domains (not supported yet).') args = parser.parse_args() if args.action not in ['check-dns', 'list']: if args.output_style == 'nrpe': - print('UNKNOWN - unkown {} action, use -h option for help.'.format(args.action)) + print('UNKNOWN - unknown {} action, use -h option for help.'.format(args.action)) sys.exit(3) else: - print('Unkown {} action, use -h option for help.'.format(args.action)) + print('Unknown {} action, use -h option for help.'.format(args.action)) sys.exit(1) if not (args.all_domains or args.apache_domains or args.nginx_domains or args.haproxy_domains): - print('Domains scope not specified, looking for all domains (default).') + print('Domains scope not specified, looking for all domains.') args.all_domains = True doms = {} @@ -292,7 +292,7 @@ def main(argv): if args.output_style == 'nrpe': print('UNKNOWN - No domain found on this server.') sys.exit(3) - else: + else: # == 'json' or 'human' print('No domain found on this server.') sys.exit(1) @@ -302,11 +302,23 @@ def main(argv): if args.output_style == 'nrpe': output_check_mode(timeout_domains, none_domains, outside_ips, ok_domains) - else: - output_friendly_mode(doms, timeout_domains, none_domains, outside_ips) + elif args.output_style == 'json': + print('Option --output-style json not implemented yet for action check-dns.') + + else: # args.output_style == 'human' + output_human_mode(doms, timeout_domains, none_domains, outside_ips) elif args.action == 'list': - print(json.dumps(doms, sort_keys=True, indent=4)) + + if args.output_style == 'nrpe': + print('Action list is not for --output-style nrpe.') + + elif args.output_style == 'json': + print(json.dumps(doms, sort_keys=True, indent=4)) + + else: + print('Option --output-style human not implemented yet for action list, fallback to --output-style json.') + print(json.dumps(doms, sort_keys=True, indent=4)) if __name__ == '__main__': From e0ba847e9cead9b40d80d28fe93a81c14acb2855 Mon Sep 17 00:00:00 2001 From: William Hirigoyen Date: Wed, 14 Sep 2022 12:19:55 +0200 Subject: [PATCH 68/74] nagios-nrpe: upgrade check_mongo --- nagios-nrpe/files/plugins/check_mongodb | 653 ++++++++++++++++-------- 1 file changed, 436 insertions(+), 217 deletions(-) mode change 100755 => 100644 nagios-nrpe/files/plugins/check_mongodb diff --git a/nagios-nrpe/files/plugins/check_mongodb b/nagios-nrpe/files/plugins/check_mongodb old mode 100755 new mode 100644 index bc6278ac..cce3a76d --- a/nagios-nrpe/files/plugins/check_mongodb +++ b/nagios-nrpe/files/plugins/check_mongodb @@ -17,24 +17,29 @@ # - Dag Stockstad # - @Andor on github # - Steven Richards - Captainkrtek on github -# - Max Vernimmen +# - Max Vernimmen - @mvernimmen-CG / @mvernimmen on github +# - Kris Nova - @kris@nivenly.com github.com/kris-nova +# - Jan Kantert - firstname@lastname.net # # USAGE # # See the README.md # +from __future__ import print_function +from __future__ import division import sys import time import optparse -import textwrap import re import os +import numbers +import socket try: import pymongo -except ImportError, e: - print e +except ImportError as e: + print(e) sys.exit(2) # As of pymongo v 1.9 the SON API is part of the BSON package, therefore attempt @@ -78,37 +83,35 @@ def performance_data(perf_data, params): def numeric_type(param): - if ((type(param) == float or type(param) == int or param == None)): - return True - return False + return param is None or isinstance(param, numbers.Real) def check_levels(param, warning, critical, message, ok=[]): if (numeric_type(critical) and numeric_type(warning)): if param >= critical: - print "CRITICAL - " + message + print("CRITICAL - " + message) sys.exit(2) elif param >= warning: - print "WARNING - " + message + print("WARNING - " + message) sys.exit(1) else: - print "OK - " + message + print("OK - " + message) sys.exit(0) else: if param in critical: - print "CRITICAL - " + message + print("CRITICAL - " + message) sys.exit(2) if param in warning: - print "WARNING - " + message + print("WARNING - " + message) sys.exit(1) if param in ok: - print "OK - " + message + print("OK - " + message) sys.exit(0) # unexpected param value - print "CRITICAL - Unexpected value : %d" % param + "; " + message + print("CRITICAL - Unexpected value : %d" % param + "; " + message) return 2 @@ -120,21 +123,32 @@ def get_server_status(con): data = con.admin.command(son.SON([('serverStatus', 1)])) return data +def split_host_port(string): + if not string.rsplit(':', 1)[-1].isdigit(): + return (string, None) + string = string.rsplit(':', 1) + host = string[0] # 1st index is always host + port = int(string[1]) + return (host, port) + def main(argv): p = optparse.OptionParser(conflict_handler="resolve", description="This Nagios plugin checks the health of mongodb.") p.add_option('-H', '--host', action='store', type='string', dest='host', default='127.0.0.1', help='The hostname you want to connect to') - p.add_option('-P', '--port', action='store', type='int', dest='port', default=27017, help='The port mongodb is runnung on') + p.add_option('-h', '--host-to-check', action='store', type='string', dest='host_to_check', default=None, help='The hostname you want to check (if this is different from the host you are connecting)') + p.add_option('--rdns-lookup', action='store_true', dest='rdns_lookup', default=False, help='RDNS(PTR) lookup on given host/host-to-check, to convert ip-address to fqdn') + p.add_option('-P', '--port', action='store', type='int', dest='port', default=27017, help='The port mongodb is running on') + p.add_option('--port-to-check', action='store', type='int', dest='port_to_check', default=None, help='The port you want to check (if this is different from the port you are connecting)') p.add_option('-u', '--user', action='store', type='string', dest='user', default=None, help='The username you want to login as') p.add_option('-p', '--pass', action='store', type='string', dest='passwd', default=None, help='The password you want to use for that user') - p.add_option('-W', '--warning', action='store', dest='warning', default=None, help='The warning threshold we want to set') - p.add_option('-C', '--critical', action='store', dest='critical', default=None, help='The critical threshold we want to set') + p.add_option('-W', '--warning', action='store', dest='warning', default=None, help='The warning threshold you want to set') + p.add_option('-C', '--critical', action='store', dest='critical', default=None, help='The critical threshold you want to set') p.add_option('-A', '--action', action='store', type='choice', dest='action', default='connect', help='The action you want to take', choices=['connect', 'connections', 'replication_lag', 'replication_lag_percent', 'replset_state', 'memory', 'memory_mapped', 'lock', - 'flushing', 'last_flush_time', 'index_miss_ratio', 'databases', 'collections', 'database_size', 'database_indexes', 'collection_indexes', 'collection_size', - 'queues', 'oplog', 'journal_commits_in_wl', 'write_data_files', 'journaled', 'opcounters', 'current_lock', 'replica_primary', 'page_faults', - 'asserts', 'queries_per_second', 'page_faults', 'chunks_balance', 'connect_primary', 'collection_state', 'row_count', 'replset_quorum']) + 'flushing', 'last_flush_time', 'index_miss_ratio', 'databases', 'collections', 'database_size', 'database_indexes', 'collection_documents', 'collection_indexes', 'collection_size', + 'collection_storageSize', 'queues', 'oplog', 'journal_commits_in_wl', 'write_data_files', 'journaled', 'opcounters', 'current_lock', 'replica_primary', + 'page_faults', 'asserts', 'queries_per_second', 'page_faults', 'chunks_balance', 'connect_primary', 'collection_state', 'row_count', 'replset_quorum']) p.add_option('--max-lag', action='store_true', dest='max_lag', default=False, help='Get max replication lag (for replication_lag action only)') p.add_option('--mapped-memory', action='store_true', dest='mapped_memory', default=False, help='Get mapped memory instead of resident (if resident memory can not be read)') p.add_option('-D', '--perf-data', action='store_true', dest='perf_data', default=False, help='Enable output of Nagios performance data') @@ -145,12 +159,28 @@ def main(argv): p.add_option('-q', '--querytype', action='store', dest='query_type', default='query', help='The query type to check [query|insert|update|delete|getmore|command] from queries_per_second') p.add_option('-c', '--collection', action='store', dest='collection', default='admin', help='Specify the collection to check') p.add_option('-T', '--time', action='store', type='int', dest='sample_time', default=1, help='Time used to sample number of pages faults') + p.add_option('-M', '--mongoversion', action='store', type='choice', dest='mongo_version', default='2', help='The MongoDB version you are talking with, either 2 or 3', + choices=['2','3']) + p.add_option('-a', '--authdb', action='store', type='string', dest='authdb', default='admin', help='The database you want to authenticate against') + p.add_option('--insecure', action='store_true', dest='insecure', default=False, help="Don't verify SSL/TLS certificates") + p.add_option('--ssl-ca-cert-file', action='store', type='string', dest='ssl_ca_cert_file', default=None, help='Path to Certificate Authority file for SSL') + p.add_option('-f', '--ssl-cert-file', action='store', type='string', dest='cert_file', default=None, help='Path to PEM encoded key and cert for client authentication') + p.add_option('-m','--auth-mechanism', action='store', type='choice', dest='auth_mechanism', default=None, help='Auth mechanism used for auth with mongodb', + choices=['MONGODB-X509','SCRAM-SHA-256','SCRAM-SHA-1']) + p.add_option('--disable_retry_writes', dest='retry_writes_disabled', default=False, action='callback', callback=optional_arg(True), help='Disable retryWrites feature') options, arguments = p.parse_args() host = options.host + host_to_check = options.host_to_check if options.host_to_check else options.host + rdns_lookup = options.rdns_lookup + if (rdns_lookup): + host_to_check = socket.getnameinfo((host_to_check, 0), 0)[0] port = options.port + port_to_check = options.port_to_check if options.port_to_check else options.port user = options.user passwd = options.passwd + authdb = options.authdb + query_type = options.query_type collection = options.collection sample_time = options.sample_time @@ -164,9 +194,15 @@ def main(argv): action = options.action perf_data = options.perf_data max_lag = options.max_lag + mongo_version = options.mongo_version database = options.database ssl = options.ssl replicaset = options.replicaset + insecure = options.insecure + ssl_ca_cert_file = options.ssl_ca_cert_file + cert_file = options.cert_file + auth_mechanism = options.auth_mechanism + retry_writes_disabled = options.retry_writes_disabled if action == 'replica_primary' and replicaset is None: return "replicaset must be passed in when using replica_primary check" @@ -177,31 +213,35 @@ def main(argv): # moving the login up here and passing in the connection # start = time.time() - err, con = mongo_connect(host, port, ssl, user, passwd, replicaset) + err, con = mongo_connect(host, port, ssl, user, passwd, replicaset, authdb, insecure, ssl_ca_cert_file, cert_file, auth_mechanism, retry_writes_disabled=retry_writes_disabled) + if err != 0: + return err + + # Autodetect mongo-version and force pymongo to let us know if it can connect or not. + err, mongo_version = check_version(con) if err != 0: return err conn_time = time.time() - start - conn_time = round(conn_time, 0) if action == "connections": return check_connections(con, warning, critical, perf_data) elif action == "replication_lag": - return check_rep_lag(con, host, port, warning, critical, False, perf_data, max_lag, user, passwd) + return check_rep_lag(con, host_to_check, port_to_check, rdns_lookup, warning, critical, False, perf_data, max_lag, ssl, user, passwd, replicaset, authdb, insecure, ssl_ca_cert_file, cert_file, auth_mechanism, retry_writes_disabled=retry_writes_disabled) elif action == "replication_lag_percent": - return check_rep_lag(con, host, port, warning, critical, True, perf_data, max_lag, user, passwd) + return check_rep_lag(con, host_to_check, port_to_check, rdns_lookup, warning, critical, True, perf_data, max_lag, ssl, user, passwd, replicaset, authdb, insecure, ssl_ca_cert_file, cert_file, auth_mechanism, retry_writes_disabled=retry_writes_disabled) elif action == "replset_state": return check_replset_state(con, perf_data, warning, critical) elif action == "memory": - return check_memory(con, warning, critical, perf_data, options.mapped_memory) + return check_memory(con, warning, critical, perf_data, options.mapped_memory, host) elif action == "memory_mapped": return check_memory_mapped(con, warning, critical, perf_data) elif action == "queues": return check_queues(con, warning, critical, perf_data) elif action == "lock": - return check_lock(con, warning, critical, perf_data) + return check_lock(con, warning, critical, perf_data, mongo_version) elif action == "current_lock": - return check_current_lock(con, host, warning, critical, perf_data) + return check_current_lock(con, host, port, warning, critical, perf_data) elif action == "flushing": return check_flushing(con, warning, critical, True, perf_data) elif action == "last_flush_time": @@ -223,22 +263,26 @@ def main(argv): return check_database_size(con, database, warning, critical, perf_data) elif action == "database_indexes": return check_database_indexes(con, database, warning, critical, perf_data) + elif action == "collection_documents": + return check_collection_documents(con, database, collection, warning, critical, perf_data) elif action == "collection_indexes": return check_collection_indexes(con, database, collection, warning, critical, perf_data) elif action == "collection_size": return check_collection_size(con, database, collection, warning, critical, perf_data) + elif action == "collection_storageSize": + return check_collection_storageSize(con, database, collection, warning, critical, perf_data) elif action == "journaled": return check_journaled(con, warning, critical, perf_data) elif action == "write_data_files": return check_write_to_datafiles(con, warning, critical, perf_data) elif action == "opcounters": - return check_opcounters(con, host, warning, critical, perf_data) + return check_opcounters(con, host, port, warning, critical, perf_data) elif action == "asserts": - return check_asserts(con, host, warning, critical, perf_data) + return check_asserts(con, host, port, warning, critical, perf_data) elif action == "replica_primary": - return check_replica_primary(con, host, warning, critical, perf_data, replicaset) + return check_replica_primary(con, host, warning, critical, perf_data, replicaset, mongo_version) elif action == "queries_per_second": - return check_queries_per_second(con, query_type, warning, critical, perf_data) + return check_queries_per_second(con, query_type, warning, critical, perf_data, mongo_version) elif action == "page_faults": check_page_faults(con, sample_time, warning, critical, perf_data) elif action == "chunks_balance": @@ -255,30 +299,73 @@ def main(argv): return check_connect(host, port, warning, critical, perf_data, user, passwd, conn_time) -def mongo_connect(host=None, port=None, ssl=False, user=None, passwd=None, replica=None): +def mongo_connect(host=None, port=None, ssl=False, user=None, passwd=None, replica=None, authdb="admin", insecure=False, ssl_ca_cert_file=None, ssl_cert=None, auth_mechanism=None, retry_writes_disabled=False): + from pymongo.errors import ConnectionFailure + from pymongo.errors import PyMongoError + import ssl as SSL + + con_args = dict() + + if ssl: + if insecure: + con_args['ssl_cert_reqs'] = SSL.CERT_NONE + else: + con_args['ssl_cert_reqs'] = SSL.CERT_REQUIRED + con_args['ssl'] = ssl + if ssl_ca_cert_file: + con_args['ssl_ca_certs'] = ssl_ca_cert_file + if ssl_cert: + con_args['ssl_certfile'] = ssl_cert + + if retry_writes_disabled: + con_args['retryWrites'] = False + try: # ssl connection for pymongo > 2.3 if pymongo.version >= "2.3": if replica is None: - con = pymongo.MongoClient(host, port) + con = pymongo.MongoClient(host, port, **con_args) else: - con = pymongo.Connection(host, port, read_preference=pymongo.ReadPreference.SECONDARY, ssl=ssl, replicaSet=replica, network_timeout=10) + con = pymongo.MongoClient(host, port, read_preference=pymongo.ReadPreference.SECONDARY, replicaSet=replica, **con_args) else: if replica is None: con = pymongo.Connection(host, port, slave_okay=True, network_timeout=10) else: con = pymongo.Connection(host, port, slave_okay=True, network_timeout=10) - #con = pymongo.Connection(host, port, slave_okay=True, replicaSet=replica, network_timeout=10) + + # we must authenticate the connection, otherwise we won't be able to perform certain operations + if ssl_cert and ssl_ca_cert_file and user and auth_mechanism == 'SCRAM-SHA-256': + con.the_database.authenticate(user, mechanism='SCRAM-SHA-256') + elif ssl_cert and ssl_ca_cert_file and user and auth_mechanism == 'SCRAM-SHA-1': + con.the_database.authenticate(user, mechanism='SCRAM-SHA-1') + elif ssl_cert and ssl_ca_cert_file and user and auth_mechanism == 'MONGODB-X509': + con.the_database.authenticate(user, mechanism='MONGODB-X509') + + try: + result = con.admin.command("ismaster") + except ConnectionFailure: + print("CRITICAL - Connection to Mongo server on %s:%s has failed" % (host, port) ) + sys.exit(2) + + if 'arbiterOnly' in result and result['arbiterOnly'] == True: + print("OK - State: 7 (Arbiter on port %s)" % (port)) + sys.exit(0) if user and passwd: - db = con["admin"] - if not db.authenticate(user, passwd): + db = con[authdb] + try: + db.authenticate(user, password=passwd) + except PyMongoError: sys.exit("Username/Password incorrect") - except Exception, e: + + # Ping to check that the server is responding. + con.admin.command("ping") + + except Exception as e: if isinstance(e, pymongo.errors.AutoReconnect) and str(e).find(" is an arbiter") != -1: # We got a pymongo AutoReconnect exception that tells us we connected to an Arbiter Server # This means: Arbiter is reachable and can answer requests/votes - this is all we need to know from an arbiter - print "OK - State: 7 (Arbiter)" + print("OK - State: 7 (Arbiter)") sys.exit(0) return exit_with_general_critical(e), None return 0, con @@ -288,7 +375,7 @@ def exit_with_general_warning(e): if isinstance(e, SystemExit): return e else: - print "WARNING - General MongoDB warning:", e + print("WARNING - General MongoDB warning:", e) return 1 @@ -296,19 +383,27 @@ def exit_with_general_critical(e): if isinstance(e, SystemExit): return e else: - print "CRITICAL - General MongoDB Error:", e + print("CRITICAL - General MongoDB Error:", e) return 2 def set_read_preference(db): - if pymongo.version >= "2.1": + if pymongo.version >= "2.2": + pymongo.read_preferences.Secondary + else: db.read_preference = pymongo.ReadPreference.SECONDARY +def check_version(con): + try: + server_info = con.server_info() + except Exception as e: + return exit_with_general_critical(e), None + return 0, int(server_info['version'].split('.')[0].strip()) def check_connect(host, port, warning, critical, perf_data, user, passwd, conn_time): warning = warning or 3 critical = critical or 6 - message = "Connection took %i seconds" % conn_time + message = "Connection took %.3f seconds" % conn_time message += performance_data(perf_data, [(conn_time, "connection_time", warning, critical)]) return check_levels(conn_time, warning, critical, message) @@ -330,13 +425,17 @@ def check_connections(con, warning, critical, perf_data): (available, "available_connections")]) return check_levels(used_percent, warning, critical, message) - except Exception, e: + except Exception as e: return exit_with_general_critical(e) -def check_rep_lag(con, host, port, warning, critical, percent, perf_data, max_lag, user, passwd): +def check_rep_lag(con, host, port, rdns_lookup, warning, critical, percent, perf_data, max_lag, ssl=False, user=None, passwd=None, replicaset=None, authdb="admin", insecure=None, ssl_ca_cert_file=None, cert_file=None, auth_mechanism=None, retry_writes_disabled=False): # Get mongo to tell us replica set member name when connecting locally if "127.0.0.1" == host: + if not "me" in list(con.admin.command("ismaster","1").keys()): + print("UNKNOWN - This is not replicated MongoDB") + return 3 + host = con.admin.command("ismaster","1")["me"].split(':')[0] if percent: @@ -348,16 +447,15 @@ def check_rep_lag(con, host, port, warning, critical, percent, perf_data, max_la rs_status = {} slaveDelays = {} try: - set_read_preference(con.admin) + #set_read_preference(con.admin) # Get replica set status try: rs_status = con.admin.command("replSetGetStatus") - except pymongo.errors.OperationFailure, e: - if e.code == None and str(e).find('failed: not running with --replSet"'): - print "OK - Not running with replSet" - return 0 - + except pymongo.errors.OperationFailure as e: + if ((e.code == None and str(e).find('failed: not running with --replSet"')) or (e.code == 76 and str(e).find('not running with --replSet"'))): + print("UNKNOWN - Not running with replSet") + return 3 serverVersion = tuple(con.server_info()['version'].split('.')) if serverVersion >= tuple("2.0.0".split(".")): # @@ -377,24 +475,32 @@ def check_rep_lag(con, host, port, warning, critical, percent, perf_data, max_la for member in rs_status["members"]: if member["stateStr"] == "PRIMARY": primary_node = member - if member["name"].split(':')[0] == host and int(member["name"].split(':')[1]) == port: + + # if rdns_lookup is true then lookup both values back to their rdns value so we can compare hostname vs fqdn + if rdns_lookup: + member_host, member_port = split_host_port(member.get('name')) + member_host = "{0}:{1}".format(socket.getnameinfo((member_host, 0), 0)[0], member_port) + if member_host == "{0}:{1}".format(socket.getnameinfo((host, 0), 0)[0], port): + host_node = member + # Exact match + elif member.get('name') == "{0}:{1}".format(host, port): host_node = member # Check if we're in the middle of an election and don't have a primary if primary_node is None: - print "WARNING - No primary defined. In an election?" + print("WARNING - No primary defined. In an election?") return 1 # Check if we failed to find the current host # below should never happen if host_node is None: - print "CRITICAL - Unable to find host '" + host + "' in replica set." + print("CRITICAL - Unable to find host '" + host + "' in replica set.") return 2 # Is the specified host the primary? if host_node["stateStr"] == "PRIMARY": if max_lag == False: - print "OK - This is the primary." + print("OK - This is the primary.") return 0 else: #get the maximal replication lag @@ -407,7 +513,7 @@ def check_rep_lag(con, host, port, warning, critical, percent, perf_data, max_la data = data + member['name'] + " lag=%d;" % replicationLag maximal_lag = max(maximal_lag, replicationLag) if percent: - err, con = mongo_connect(primary_node['name'].split(':')[0], int(primary_node['name'].split(':')[1]), False, user, passwd) + err, con = mongo_connect(split_host_port(primary_node['name'])[0], int(split_host_port(primary_node['name'])[1]), ssl, user, passwd, replicaset, authdb, insecure, ssl_ca_cert_file, cert_file, auth_mechanism, retry_writes_disabled=retry_writes_disabled) if err != 0: return err primary_timediff = replication_get_time_diff(con) @@ -419,8 +525,8 @@ def check_rep_lag(con, host, port, warning, critical, percent, perf_data, max_la message += performance_data(perf_data, [(maximal_lag, "replication_lag", warning, critical)]) return check_levels(maximal_lag, warning, critical, message) elif host_node["stateStr"] == "ARBITER": - print "OK - This is an arbiter" - return 0 + print("UNKNOWN - This is an arbiter") + return 3 # Find the difference in optime between current node and PRIMARY @@ -439,7 +545,7 @@ def check_rep_lag(con, host, port, warning, critical, percent, perf_data, max_la lag = float(optime_lag.seconds + optime_lag.days * 24 * 3600) if percent: - err, con = mongo_connect(primary_node['name'].split(':')[0], int(primary_node['name'].split(':')[1]), False, user, passwd) + err, con = mongo_connect(split_host_port(primary_node['name'])[0], int(split_host_port(primary_node['name'])[1]), ssl, user, passwd, replicaset, authdb, insecure, ssl_ca_cert_file, cert_file, auth_mechanism, retry_writes_disabled=retry_writes_disabled) if err != 0: return err primary_timediff = replication_get_time_diff(con) @@ -471,19 +577,19 @@ def check_rep_lag(con, host, port, warning, critical, percent, perf_data, max_la # Check if we're in the middle of an election and don't have a primary if primary_node is None: - print "WARNING - No primary defined. In an election?" + print("WARNING - No primary defined. In an election?") sys.exit(1) # Is the specified host the primary? if host_node["stateStr"] == "PRIMARY": - print "OK - This is the primary." + print("OK - This is the primary.") sys.exit(0) # Find the difference in optime between current node and PRIMARY optime_lag = abs(primary_node[1] - host_node["optimeDate"]) lag = optime_lag.seconds if percent: - err, con = mongo_connect(primary_node['name'].split(':')[0], int(primary_node['name'].split(':')[1])) + err, con = mongo_connect(split_host_port(primary_node['name'])[0], int(split_host_port(primary_node['name'])[1]), ssl, user, passwd, replicaset, authdb, insecure, ssl_ca_cert_file, cert_file, auth_mechanism, retry_writes_disabled=retry_writes_disabled) if err != 0: return err primary_timediff = replication_get_time_diff(con) @@ -495,26 +601,34 @@ def check_rep_lag(con, host, port, warning, critical, percent, perf_data, max_la message += performance_data(perf_data, [(lag, "replication_lag", warning, critical)]) return check_levels(lag, warning, critical, message) - except Exception, e: + except Exception as e: return exit_with_general_critical(e) - -def check_memory(con, warning, critical, perf_data, mapped_memory): - # - # These thresholds are basically meaningless, and must be customized to your system's ram - # - - # Get the total system merory and calculate based on that how much memory used by Mongodb is ok or not. +# +# Check the memory usage of mongo. Alerting on this may be hard to get right +# because it'll try to get as much memory as it can. And that's probably +# a good thing. +# +def check_memory(con, warning, critical, perf_data, mapped_memory, host): + # Get the total system memory of this system (This is totally bogus if you + # are running this command remotely) and calculate based on that how much + # memory used by Mongodb is ok or not. meminfo = open('/proc/meminfo').read() matched = re.search(r'^MemTotal:\s+(\d+)', meminfo) - if matched: + if matched: mem_total_kB = int(matched.groups()[0]) - # Old way - #critical = critical or 16 - # The new way. if using >80% then warn, if >90% then critical level - warning = warning or (mem_total_kB * 0.8) / 1024.0 / 1024.0 - critical = critical or (mem_total_kB * 0.9) / 1024.0 / 1024.0 + if host != "127.0.0.1" and not warning: + # Running remotely and value was not set by user, use hardcoded value + warning = 12 + else: + # running locally or user provided value + warning = warning or (mem_total_kB * 0.8) / 1024.0 / 1024.0 + + if host != "127.0.0.1" and not critical: + critical = 16 + else: + critical = critical or (mem_total_kB * 0.9) / 1024.0 / 1024.0 # debugging #print "mem total: {0}kb, warn: {1}GB, crit: {2}GB".format(mem_total_kB,warning, critical) @@ -522,7 +636,7 @@ def check_memory(con, warning, critical, perf_data, mapped_memory): try: data = get_server_status(con) if not data['mem']['supported'] and not mapped_memory: - print "OK - Platform not supported for memory info" + print("OK - Platform not supported for memory info") return 0 # # convert to gigs @@ -559,7 +673,7 @@ def check_memory(con, warning, critical, perf_data, mapped_memory): else: return check_levels(mem_resident, warning, critical, message) - except Exception, e: + except Exception as e: return exit_with_general_critical(e) @@ -572,7 +686,7 @@ def check_memory_mapped(con, warning, critical, perf_data): try: data = get_server_status(con) if not data['mem']['supported']: - print "OK - Platform not supported for memory info" + print("OK - Platform not supported for memory info") return 0 # # convert to gigs @@ -589,38 +703,45 @@ def check_memory_mapped(con, warning, critical, perf_data): message += " %.2fGB mappedWithJournal" % mem_mapped_journal except: mem_mapped_journal = 0 - message += performance_data(perf_data, [("%.2f" % mem_mapped, "memory_mapped"), ("%.2f" % mem_mapped_journal, "mappedWithJournal")]) + message += performance_data(perf_data, [("%.2f" % mem_mapped, "memory_mapped", warning, critical), ("%.2f" % mem_mapped_journal, "mappedWithJournal")]) if not mem_mapped == -1: return check_levels(mem_mapped, warning, critical, message) else: - print "OK - Server does not provide mem.mapped info" + print("OK - Server does not provide mem.mapped info") return 0 - except Exception, e: + except Exception as e: return exit_with_general_critical(e) -def check_lock(con, warning, critical, perf_data): +# +# Return the percentage of the time there was a global Lock +# +def check_lock(con, warning, critical, perf_data, mongo_version): warning = warning or 10 critical = critical or 30 - try: - data = get_server_status(con) - # - # calculate percentage - # - lockTime = data['globalLock']['lockTime'] - totalTime = data['globalLock']['totalTime'] - if lockTime > totalTime: - lock_percentage = 0.00 - else: - lock_percentage = float(lockTime) / float(totalTime) * 100 - message = "Lock Percentage: %.2f%%" % lock_percentage - message += performance_data(perf_data, [("%.2f" % lock_percentage, "lock_percentage", warning, critical)]) - return check_levels(lock_percentage, warning, critical, message) - - except Exception, e: - return exit_with_general_critical(e) + if mongo_version == 2: + try: + data = get_server_status(con) + lockTime = data['globalLock']['lockTime'] + totalTime = data['globalLock']['totalTime'] + # + # calculate percentage + # + if lockTime > totalTime: + lock_percentage = 0.00 + else: + lock_percentage = float(lockTime) / float(totalTime) * 100 + message = "Lock Percentage: %.2f%%" % lock_percentage + message += performance_data(perf_data, [("%.2f" % lock_percentage, "lock_percentage", warning, critical)]) + return check_levels(lock_percentage, warning, critical, message) + except Exception as e: + print("Couldn't get globalLock lockTime info from mongo, are you sure you're not using version 3? See the -M option.") + return exit_with_general_critical(e) + else: + print("OK - MongoDB version 3 doesn't report on global locks") + return 0 def check_flushing(con, warning, critical, avg, perf_data): @@ -632,19 +753,24 @@ def check_flushing(con, warning, critical, avg, perf_data): critical = critical or 15000 try: data = get_server_status(con) - if avg: - flush_time = float(data['backgroundFlushing']['average_ms']) - stat_type = "Average" - else: - flush_time = float(data['backgroundFlushing']['last_ms']) - stat_type = "Last" + try: + data['backgroundFlushing'] + if avg: + flush_time = float(data['backgroundFlushing']['average_ms']) + stat_type = "Average" + else: + flush_time = float(data['backgroundFlushing']['last_ms']) + stat_type = "Last" - message = "%s Flush Time: %.2fms" % (stat_type, flush_time) - message += performance_data(perf_data, [("%.2fms" % flush_time, "%s_flush_time" % stat_type.lower(), warning, critical)]) + message = "%s Flush Time: %.2fms" % (stat_type, flush_time) + message += performance_data(perf_data, [("%.2fms" % flush_time, "%s_flush_time" % stat_type.lower(), warning, critical)]) - return check_levels(flush_time, warning, critical, message) + return check_levels(flush_time, warning, critical, message) + except Exception: + print("OK - flushing stats not available for this storage engine") + return 0 - except Exception, e: + except Exception as e: return exit_with_general_critical(e) @@ -655,6 +781,7 @@ def index_miss_ratio(con, warning, critical, perf_data): data = get_server_status(con) try: + data['indexCounters'] serverVersion = tuple(con.server_info()['version'].split('.')) if serverVersion >= tuple("2.4.0".split(".")): miss_ratio = float(data['indexCounters']['missRatio']) @@ -662,19 +789,24 @@ def index_miss_ratio(con, warning, critical, perf_data): miss_ratio = float(data['indexCounters']['btree']['missRatio']) except KeyError: not_supported_msg = "not supported on this platform" - if data['indexCounters'].has_key('note'): - print "OK - MongoDB says: " + not_supported_msg + try: + data['indexCounters'] + if 'note' in data['indexCounters']: + print("OK - MongoDB says: " + not_supported_msg) + return 0 + else: + print("WARNING - Can't get counter from MongoDB") + return 1 + except Exception: + print("OK - MongoDB says: " + not_supported_msg) return 0 - else: - print "WARNING - Can't get counter from MongoDB" - return 1 message = "Miss Ratio: %.2f" % miss_ratio message += performance_data(perf_data, [("%.2f" % miss_ratio, "index_miss_ratio", warning, critical)]) return check_levels(miss_ratio, warning, critical, message) - except Exception, e: + except Exception as e: return exit_with_general_critical(e) def check_replset_quorum(con, perf_data): @@ -698,7 +830,7 @@ def check_replset_quorum(con, perf_data): message = "Cluster is not quorate and cannot operate" return check_levels(state, warning, critical, message) - except Exception, e: + except Exception as e: return exit_with_general_critical(e) @@ -713,44 +845,63 @@ def check_replset_state(con, perf_data, warning="", critical=""): except: critical = [8, 4, -1] - ok = range(-1, 8) # should include the range of all posiible values + ok = list(range(-1, 8)) # should include the range of all posiible values try: + worst_state = -2 + message = "" try: try: set_read_preference(con.admin) data = con.admin.command(pymongo.son_manipulator.SON([('replSetGetStatus', 1)])) except: data = con.admin.command(son.SON([('replSetGetStatus', 1)])) - state = int(data['myState']) - except pymongo.errors.OperationFailure, e: - if e.code == None and str(e).find('failed: not running with --replSet"'): - state = -1 + members = data['members'] + my_state = int(data['myState']) + worst_state = my_state + for member in members: + their_state = int(member['state']) + message += " %s: %i (%s)" % (member['name'], their_state, state_text(their_state)) + if state_is_worse(their_state, worst_state, warning, critical): + worst_state = their_state + message += performance_data(perf_data, [(my_state, "state")]) - if state == 8: - message = "State: %i (Down)" % state - elif state == 4: - message = "State: %i (Fatal error)" % state - elif state == 0: - message = "State: %i (Starting up, phase1)" % state - elif state == 3: - message = "State: %i (Recovering)" % state - elif state == 5: - message = "State: %i (Starting up, phase2)" % state - elif state == 1: - message = "State: %i (Primary)" % state - elif state == 2: - message = "State: %i (Secondary)" % state - elif state == 7: - message = "State: %i (Arbiter)" % state - elif state == -1: - message = "Not running with replSet" - else: - message = "State: %i (Unknown state)" % state - message += performance_data(perf_data, [(state, "state")]) - return check_levels(state, warning, critical, message, ok) - except Exception, e: + except pymongo.errors.OperationFailure as e: + if ((e.code == None and str(e).find('failed: not running with --replSet"')) or (e.code == 76 and str(e).find('not running with --replSet"'))): + worst_state = -1 + + return check_levels(worst_state, warning, critical, message, ok) + except Exception as e: return exit_with_general_critical(e) +def state_is_worse(state, worst_state, warning, critical): + if worst_state in critical: + return False + if worst_state in warning: + return state in critical + return (state in warning) or (state in critical) + +def state_text(state): + if state == 8: + return "Down" + elif state == 4: + return "Fatal error" + elif state == 0: + return "Starting up, phase1" + elif state == 3: + return "Recovering" + elif state == 5: + return "Starting up, phase2" + elif state == 1: + return "Primary" + elif state == 2: + return "Secondary" + elif state == 7: + return "Arbiter" + elif state == -1: + return "Not running with replSet" + else: + return "Unknown state" + def check_databases(con, warning, critical, perf_data=None): try: @@ -764,7 +915,7 @@ def check_databases(con, warning, critical, perf_data=None): message = "Number of DBs: %.0f" % count message += performance_data(perf_data, [(count, "databases", warning, critical, message)]) return check_levels(count, warning, critical, message) - except Exception, e: + except Exception as e: return exit_with_general_critical(e) @@ -786,7 +937,7 @@ def check_collections(con, warning, critical, perf_data=None): message += performance_data(perf_data, [(count, "collections", warning, critical, message)]) return check_levels(count, warning, critical, message) - except Exception, e: + except Exception as e: return exit_with_general_critical(e) @@ -823,21 +974,21 @@ def check_database_size(con, database, warning, critical, perf_data): try: set_read_preference(con.admin) data = con[database].command('dbstats') - storage_size = data['storageSize'] / 1024 / 1024 + storage_size = data['storageSize'] // 1024 // 1024 if perf_data: perfdata += " | database_size=%i;%i;%i" % (storage_size, warning, critical) #perfdata += " database=%s" %(database) if storage_size >= critical: - print "CRITICAL - Database size: %.0f MB, Database: %s%s" % (storage_size, database, perfdata) + print("CRITICAL - Database size: %.0f MB, Database: %s%s" % (storage_size, database, perfdata)) return 2 elif storage_size >= warning: - print "WARNING - Database size: %.0f MB, Database: %s%s" % (storage_size, database, perfdata) + print("WARNING - Database size: %.0f MB, Database: %s%s" % (storage_size, database, perfdata)) return 1 else: - print "OK - Database size: %.0f MB, Database: %s%s" % (storage_size, database, perfdata) + print("OK - Database size: %.0f MB, Database: %s%s" % (storage_size, database, perfdata)) return 0 - except Exception, e: + except Exception as e: return exit_with_general_critical(e) @@ -851,20 +1002,42 @@ def check_database_indexes(con, database, warning, critical, perf_data): try: set_read_preference(con.admin) data = con[database].command('dbstats') - index_size = data['indexSize'] / 1024 / 1024 + index_size = data['indexSize'] / 1024 // 1024 if perf_data: perfdata += " | database_indexes=%i;%i;%i" % (index_size, warning, critical) if index_size >= critical: - print "CRITICAL - %s indexSize: %.0f MB %s" % (database, index_size, perfdata) + print("CRITICAL - %s indexSize: %.0f MB %s" % (database, index_size, perfdata)) return 2 elif index_size >= warning: - print "WARNING - %s indexSize: %.0f MB %s" % (database, index_size, perfdata) + print("WARNING - %s indexSize: %.0f MB %s" % (database, index_size, perfdata)) return 1 else: - print "OK - %s indexSize: %.0f MB %s" % (database, index_size, perfdata) + print("OK - %s indexSize: %.0f MB %s" % (database, index_size, perfdata)) return 0 - except Exception, e: + except Exception as e: + return exit_with_general_critical(e) + + +def check_collection_documents(con, database, collection, warning, critical, perf_data): + perfdata = "" + try: + set_read_preference(con.admin) + data = con[database].command('collstats', collection) + documents = data['count'] + if perf_data: + perfdata += " | collection_documents=%i;%i;%i" % (documents, warning, critical) + + if documents >= critical: + print("CRITICAL - %s.%s documents: %s %s" % (database, collection, documents, perfdata)) + return 2 + elif documents >= warning: + print("WARNING - %s.%s documents: %s %s" % (database, collection, documents, perfdata)) + return 1 + else: + print("OK - %s.%s documents: %s %s" % (database, collection, documents, perfdata)) + return 0 + except Exception as e: return exit_with_general_critical(e) @@ -883,15 +1056,15 @@ def check_collection_indexes(con, database, collection, warning, critical, perf_ perfdata += " | collection_indexes=%i;%i;%i" % (total_index_size, warning, critical) if total_index_size >= critical: - print "CRITICAL - %s.%s totalIndexSize: %.0f MB %s" % (database, collection, total_index_size, perfdata) + print("CRITICAL - %s.%s totalIndexSize: %.0f MB %s" % (database, collection, total_index_size, perfdata)) return 2 elif total_index_size >= warning: - print "WARNING - %s.%s totalIndexSize: %.0f MB %s" % (database, collection, total_index_size, perfdata) + print("WARNING - %s.%s totalIndexSize: %.0f MB %s" % (database, collection, total_index_size, perfdata)) return 1 else: - print "OK - %s.%s totalIndexSize: %.0f MB %s" % (database, collection, total_index_size, perfdata) + print("OK - %s.%s totalIndexSize: %.0f MB %s" % (database, collection, total_index_size, perfdata)) return 0 - except Exception, e: + except Exception as e: return exit_with_general_critical(e) @@ -908,7 +1081,7 @@ def check_queues(con, warning, critical, perf_data): message += performance_data(perf_data, [(total_queues, "total_queues", warning, critical), (readers_queues, "readers_queues"), (writers_queues, "writers_queues")]) return check_levels(total_queues, warning, critical, message) - except Exception, e: + except Exception as e: return exit_with_general_critical(e) def check_collection_size(con, database, collection, warning, critical, perf_data): @@ -923,18 +1096,43 @@ def check_collection_size(con, database, collection, warning, critical, perf_dat perfdata += " | collection_size=%i;%i;%i" % (size, warning, critical) if size >= critical: - print "CRITICAL - %s.%s size: %.0f MB %s" % (database, collection, size, perfdata) + print("CRITICAL - %s.%s size: %.0f MB %s" % (database, collection, size, perfdata)) return 2 elif size >= warning: - print "WARNING - %s.%s size: %.0f MB %s" % (database, collection, size, perfdata) + print("WARNING - %s.%s size: %.0f MB %s" % (database, collection, size, perfdata)) return 1 else: - print "OK - %s.%s size: %.0f MB %s" % (database, collection, size, perfdata) + print("OK - %s.%s size: %.0f MB %s" % (database, collection, size, perfdata)) return 0 - except Exception, e: + except Exception as e: return exit_with_general_critical(e) -def check_queries_per_second(con, query_type, warning, critical, perf_data): + +def check_collection_storageSize(con, database, collection, warning, critical, perf_data): + warning = warning or 100 + critical = critical or 1000 + perfdata = "" + try: + set_read_preference(con.admin) + data = con[database].command('collstats', collection) + storageSize = data['storageSize'] / 1024 / 1024 + if perf_data: + perfdata += " | collection_storageSize=%i;%i;%i" % (storageSize, warning, critical) + + if storageSize >= critical: + print("CRITICAL - %s.%s storageSize: %.0f MB %s" % (database, collection, storageSize, perfdata)) + return 2 + elif storageSize >= warning: + print("WARNING - %s.%s storageSize: %.0f MB %s" % (database, collection, storageSize, perfdata)) + return 1 + else: + print("OK - %s.%s storageSize: %.0f MB %s" % (database, collection, storageSize, perfdata)) + return 0 + except Exception as e: + return exit_with_general_critical(e) + + +def check_queries_per_second(con, query_type, warning, critical, perf_data, mongo_version): warning = warning or 250 critical = critical or 500 @@ -955,10 +1153,17 @@ def check_queries_per_second(con, query_type, warning, critical, perf_data): diff_query = num - last_count['data'][query_type]['count'] diff_ts = ts - last_count['data'][query_type]['ts'] + if diff_ts == 0: + message = "diff_query = " + str(diff_query) + " diff_ts = " + str(diff_ts) + return check_levels(0, warning, critical, message) + query_per_sec = float(diff_query) / float(diff_ts) # update the count now - db.nagios_check.update({u'_id': last_count['_id']}, {'$set': {"data.%s" % query_type: {'count': num, 'ts': int(time.time())}}}) + if mongo_version == 2: + db.nagios_check.update({u'_id': last_count['_id']}, {'$set': {"data.%s" % query_type: {'count': num, 'ts': int(time.time())}}}) + else: + db.nagios_check.update_one({u'_id': last_count['_id']}, {'$set': {"data.%s" % query_type: {'count': num, 'ts': int(time.time())}}}) message = "Queries / Sec: %f" % query_per_sec message += performance_data(perf_data, [(query_per_sec, "%s_per_sec" % query_type, warning, critical, message)]) @@ -967,17 +1172,24 @@ def check_queries_per_second(con, query_type, warning, critical, perf_data): # since it is the first run insert it query_per_sec = 0 message = "First run of check.. no data" - db.nagios_check.update({u'_id': last_count['_id']}, {'$set': {"data.%s" % query_type: {'count': num, 'ts': int(time.time())}}}) + if mongo_version == 2: + db.nagios_check.update({u'_id': last_count['_id']}, {'$set': {"data.%s" % query_type: {'count': num, 'ts': int(time.time())}}}) + else: + db.nagios_check.update_one({u'_id': last_count['_id']}, {'$set': {"data.%s" % query_type: {'count': num, 'ts': int(time.time())}}}) + except TypeError: # # since it is the first run insert it query_per_sec = 0 message = "First run of check.. no data" - db.nagios_check.insert({'check': 'query_counts', 'data': {query_type: {'count': num, 'ts': int(time.time())}}}) + if mongo_version == 2: + db.nagios_check.insert({'check': 'query_counts', 'data': {query_type: {'count': num, 'ts': int(time.time())}}}) + else: + db.nagios_check.insert_one({'check': 'query_counts', 'data': {query_type: {'count': num, 'ts': int(time.time())}}}) return check_levels(query_per_sec, warning, critical, message) - except Exception, e: + except Exception as e: return exit_with_general_critical(e) @@ -1024,7 +1236,7 @@ def check_oplog(con, warning, critical, perf_data): message += performance_data(perf_data, [("%.2f" % hours_in_oplog, 'oplog_time', warning, critical), ("%.2f " % approx_level, 'oplog_time_100_percent_used')]) return check_levels(-approx_level, -warning, -critical, message) - except Exception, e: + except Exception as e: return exit_with_general_critical(e) @@ -1042,7 +1254,7 @@ Under very high write situations it is normal for this value to be nonzero. """ message += performance_data(perf_data, [(j_commits_in_wl, "j_commits_in_wl", warning, critical)]) return check_levels(j_commits_in_wl, warning, critical, message) - except Exception, e: + except Exception as e: return exit_with_general_critical(e) @@ -1058,7 +1270,7 @@ def check_journaled(con, warning, critical, perf_data): message += performance_data(perf_data, [("%.2f" % journaled, "journaled", warning, critical)]) return check_levels(journaled, warning, critical, message) - except Exception, e: + except Exception as e: return exit_with_general_critical(e) @@ -1075,11 +1287,11 @@ than the amount physically written to disk.""" message += performance_data(perf_data, [("%.2f" % writes, "write_to_data_files", warning, critical)]) return check_levels(writes, warning, critical, message) - except Exception, e: + except Exception as e: return exit_with_general_critical(e) -def get_opcounters(data, opcounters_name, host): +def get_opcounters(data, opcounters_name, host, port): try: insert = data[opcounters_name]['insert'] query = data[opcounters_name]['query'] @@ -1087,21 +1299,21 @@ def get_opcounters(data, opcounters_name, host): delete = data[opcounters_name]['delete'] getmore = data[opcounters_name]['getmore'] command = data[opcounters_name]['command'] - except KeyError, e: + except KeyError as e: return 0, [0] * 100 total_commands = insert + query + update + delete + getmore + command new_vals = [total_commands, insert, query, update, delete, getmore, command] - return maintain_delta(new_vals, host, opcounters_name) + return maintain_delta(new_vals, host, port, opcounters_name) -def check_opcounters(con, host, warning, critical, perf_data): +def check_opcounters(con, host, port, warning, critical, perf_data): """ A function to get all opcounters delta per minute. In case of a replication - gets the opcounters+opcountersRepl""" warning = warning or 10000 critical = critical or 15000 data = get_server_status(con) - err1, delta_opcounters = get_opcounters(data, 'opcounters', host) - err2, delta_opcounters_repl = get_opcounters(data, 'opcountersRepl', host) + err1, delta_opcounters = get_opcounters(data, 'opcounters', host, port) + err2, delta_opcounters_repl = get_opcounters(data, 'opcountersRepl', host, port) if err1 == 0 and err2 == 0: delta = [(x + y) for x, y in zip(delta_opcounters, delta_opcounters_repl)] delta[0] = delta_opcounters[0] # only the time delta shouldn't be summarized @@ -1109,14 +1321,14 @@ def check_opcounters(con, host, warning, critical, perf_data): message = "Test succeeded , old values missing" message = "Opcounters: total=%d,insert=%d,query=%d,update=%d,delete=%d,getmore=%d,command=%d" % tuple(per_minute_delta) message += performance_data(perf_data, ([(per_minute_delta[0], "total", warning, critical), (per_minute_delta[1], "insert"), - (per_minute_delta[2], "query"), (per_minute_delta[3], "update"), (per_minute_delta[5], "delete"), + (per_minute_delta[2], "query"), (per_minute_delta[3], "update"), (per_minute_delta[4], "delete"), (per_minute_delta[5], "getmore"), (per_minute_delta[6], "command")])) return check_levels(per_minute_delta[0], warning, critical, message) else: return exit_with_general_critical("problem reading data from temp file") -def check_current_lock(con, host, warning, critical, perf_data): +def check_current_lock(con, host, port, warning, critical, perf_data): """ A function to get current lock percentage and not a global one, as check_lock function does""" warning = warning or 10 critical = critical or 30 @@ -1125,7 +1337,7 @@ def check_current_lock(con, host, warning, critical, perf_data): lockTime = float(data['globalLock']['lockTime']) totalTime = float(data['globalLock']['totalTime']) - err, delta = maintain_delta([totalTime, lockTime], host, "locktime") + err, delta = maintain_delta([totalTime, lockTime], host, port, "locktime") if err == 0: lock_percentage = delta[2] / delta[1] * 100 # lockTime/totalTime*100 message = "Current Lock Percentage: %.2f%%" % lock_percentage @@ -1135,7 +1347,7 @@ def check_current_lock(con, host, warning, critical, perf_data): return exit_with_general_warning("problem reading data from temp file") -def check_page_faults(con, host, warning, critical, perf_data): +def check_page_faults(con, host, port, warning, critical, perf_data): """ A function to get page_faults per second from the system""" warning = warning or 10 critical = critical or 30 @@ -1147,7 +1359,7 @@ def check_page_faults(con, host, warning, critical, perf_data): # page_faults unsupported on the underlaying system return exit_with_general_critical("page_faults unsupported on the underlaying system") - err, delta = maintain_delta([page_faults], host, "page_faults") + err, delta = maintain_delta([page_faults], host, port, "page_faults") if err == 0: page_faults_ps = delta[1] / delta[0] message = "Page faults : %.2f ps" % page_faults_ps @@ -1157,7 +1369,7 @@ def check_page_faults(con, host, warning, critical, perf_data): return exit_with_general_warning("problem reading data from temp file") -def check_asserts(con, host, warning, critical, perf_data): +def check_asserts(con, host, port, warning, critical, perf_data): """ A function to get asserts from the system""" warning = warning or 1 critical = critical or 10 @@ -1172,7 +1384,7 @@ def check_asserts(con, host, warning, critical, perf_data): user = asserts['user'] rollovers = asserts['rollovers'] - err, delta = maintain_delta([regular, warning_asserts, msg, user, rollovers], host, "asserts") + err, delta = maintain_delta([regular, warning_asserts, msg, user, rollovers], host, port, "asserts") if err == 0: if delta[5] != 0: @@ -1206,7 +1418,7 @@ def get_stored_primary_server_name(db): return stored_primary_server -def check_replica_primary(con, host, warning, critical, perf_data, replicaset): +def check_replica_primary(con, host, warning, critical, perf_data, replicaset, mongo_version): """ A function to check if the primary server of a replica set has changed """ if warning is None and critical is None: warning = 1 @@ -1229,7 +1441,10 @@ def check_replica_primary(con, host, warning, critical, perf_data, replicaset): saved_primary = "None" if current_primary != saved_primary: last_primary_server_record = {"server": current_primary} - db.last_primary_server.update({"_id": "last_primary"}, {"$set": last_primary_server_record}, upsert=True, safe=True) + if mongo_version == 2: + db.last_primary_server.update({"_id": "last_primary"}, {"$set": last_primary_server_record}, upsert=True) + else: + db.last_primary_server.update_one({"_id": "last_primary"}, {"$set": last_primary_server_record}, upsert=True) message = "Primary server has changed from %s to %s" % (saved_primary, current_primary) primary_status = 1 return check_levels(primary_status, warning, critical, message) @@ -1251,9 +1466,9 @@ def check_page_faults(con, sample_time, warning, critical, perf_data): try: #on linux servers only - page_faults = (int(data2['extra_info']['page_faults']) - int(data1['extra_info']['page_faults'])) / sample_time + page_faults = (int(data2['extra_info']['page_faults']) - int(data1['extra_info']['page_faults'])) // sample_time except KeyError: - print "WARNING - Can't get extra_info.page_faults counter from MongoDB" + print("WARNING - Can't get extra_info.page_faults counter from MongoDB") sys.exit(1) message = "Page Faults: %i" % (page_faults) @@ -1261,7 +1476,7 @@ def check_page_faults(con, sample_time, warning, critical, perf_data): message += performance_data(perf_data, [(page_faults, "page_faults", warning, critical)]) check_levels(page_faults, warning, critical, message) - except Exception, e: + except Exception as e: exit_with_general_critical(e) @@ -1277,35 +1492,35 @@ def chunks_balance(con, database, collection, warning, critical): shards = col.distinct("shard") except: - print "WARNING - Can't get chunks infos from MongoDB" + print("WARNING - Can't get chunks infos from MongoDB") sys.exit(1) if nscount == 0: - print "WARNING - Namespace %s is not sharded" % (nsfilter) + print("WARNING - Namespace %s is not sharded" % (nsfilter)) sys.exit(1) - avgchunksnb = nscount / len(shards) - warningnb = avgchunksnb * warning / 100 - criticalnb = avgchunksnb * critical / 100 + avgchunksnb = nscount // len(shards) + warningnb = avgchunksnb * warning // 100 + criticalnb = avgchunksnb * critical // 100 for shard in shards: delta = abs(avgchunksnb - col.find({"ns": nsfilter, "shard": shard}).count()) message = "Namespace: %s, Shard name: %s, Chunk delta: %i" % (nsfilter, shard, delta) if delta >= criticalnb and delta > 0: - print "CRITICAL - Chunks not well balanced " + message + print("CRITICAL - Chunks not well balanced " + message) sys.exit(2) elif delta >= warningnb and delta > 0: - print "WARNING - Chunks not well balanced " + message + print("WARNING - Chunks not well balanced " + message) sys.exit(1) - print "OK - Chunks well balanced across shards" + print("OK - Chunks well balanced across shards") sys.exit(0) - except Exception, e: + except Exception as e: exit_with_general_critical(e) - print "OK - Chunks well balanced across shards" + print("OK - Chunks well balanced across shards") sys.exit(0) @@ -1321,7 +1536,7 @@ def check_connect_primary(con, warning, critical, perf_data): data = con.admin.command(son.SON([('isMaster', 1)])) if data['ismaster'] == True: - print "OK - This server is primary" + print("OK - This server is primary") return 0 phost = data['primary'].split(':')[0] @@ -1339,17 +1554,17 @@ def check_connect_primary(con, warning, critical, perf_data): return check_levels(pconn_time, warning, critical, message) - except Exception, e: + except Exception as e: return exit_with_general_critical(e) def check_collection_state(con, database, collection): try: con[database][collection].find_one() - print "OK - Collection %s.%s is reachable " % (database, collection) + print("OK - Collection %s.%s is reachable " % (database, collection)) return 0 - except Exception, e: + except Exception as e: return exit_with_general_critical(e) @@ -1361,14 +1576,18 @@ def check_row_count(con, database, collection, warning, critical, perf_data): return check_levels(count, warning, critical, message) - except Exception, e: + except Exception as e: return exit_with_general_critical(e) -def build_file_name(host, action): +def build_file_name(host, port, action): #done this way so it will work when run independently and from shell module_name = re.match('(.*//*)*(.*)\..*', __file__).group(2) - return "/tmp/" + module_name + "_data/" + host + "-" + action + ".data" + + if (port == 27017): + return "/tmp/" + module_name + "_data/" + host + "-" + action + ".data" + else: + return "/tmp/" + module_name + "_data/" + host + "-" + str(port) + "-" + action + ".data" def ensure_dir(f): @@ -1381,7 +1600,7 @@ def write_values(file_name, string): f = None try: f = open(file_name, 'w') - except IOError, e: + except IOError as e: #try creating if (e.errno == 2): ensure_dir(file_name) @@ -1400,11 +1619,11 @@ def read_values(file_name): data = f.read() f.close() return 0, data - except IOError, e: + except IOError as e: if (e.errno == 2): #no previous data return 1, '' - except Exception, e: + except Exception as e: return 2, None @@ -1420,8 +1639,8 @@ def calc_delta(old, new): return 0, delta -def maintain_delta(new_vals, host, action): - file_name = build_file_name(host, action) +def maintain_delta(new_vals, host, port, action): + file_name = build_file_name(host, port, action) err, data = read_values(file_name) old_vals = data.split(';') new_vals = [str(int(time.time()))] + new_vals @@ -1442,8 +1661,8 @@ def replication_get_time_diff(con): col = 'oplog.$main' firstc = local[col].find().sort("$natural", 1).limit(1) lastc = local[col].find().sort("$natural", -1).limit(1) - first = firstc.next() - last = lastc.next() + first = next(firstc) + last = next(lastc) tfirst = first["ts"] tlast = last["ts"] delta = tlast.time - tfirst.time From 55f694f051221b75e606532315acfc2ea9dce2e8 Mon Sep 17 00:00:00 2001 From: William Hirigoyen Date: Wed, 14 Sep 2022 12:21:13 +0200 Subject: [PATCH 69/74] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e46e8c9..32c1bc6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ The **patch** part changes is incremented if multiple releases happen the same m * nagios-nrpe: Add check_domains * generate-ldif: support any version of MariaDB (instead of only 10.0, 10.1 and 10.3) * openvpn: Run OpenVPN with the \_openvpn user and group instead of nobody which is originally for NFS +* nagios-nrpe: Upgrade check_mongo ### Fixed From 6f04a4155783dd54461904d7d592170b8ca9cfdf Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Thu, 15 Sep 2022 09:48:34 +0200 Subject: [PATCH 70/74] fail2ban: fix dovecot-evolix regex syntax --- CHANGELOG.md | 7 ++++--- fail2ban/files/dovecot-evolix.conf | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32c1bc6b..009f5625 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,11 +35,12 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Fixed +* fail2ban: fix dovecot-evolix regex syntax * haproxy: make it so that munin doesn't break if there is a non default `haproxy_stats_path` -* varnish: make `-j ` the first argument on jessie/stretch as it has to be the first argument there. -* redis: config directory must be owned by the user that runs the service (to be able to write tmp config files in it) -* webapps/nextcloud: Add missing dependencies for imagick * mysql: Add missing Munin conf for Debian 11 +* redis: config directory must be owned by the user that runs the service (to be able to write tmp config files in it) +* varnish: make `-j ` the first argument on jessie/stretch as it has to be the first argument there. +* webapps/nextcloud: Add missing dependencies for imagick ### Removed diff --git a/fail2ban/files/dovecot-evolix.conf b/fail2ban/files/dovecot-evolix.conf index 5ca484af..e1ef1a3f 100644 --- a/fail2ban/files/dovecot-evolix.conf +++ b/fail2ban/files/dovecot-evolix.conf @@ -1,3 +1,3 @@ -[Definition] -failregex = (?: pop3-login|imap-login): .*(?:Authentication failure|Aborted login \(auth failed|Aborted login \(tried to use disabled|Disconnected \(auth failed|Aborted login \(\d+ authentication attempts).*rip=(?P\S*),.* -ignoreregex = +[Definition] +failregex = (?: pop3-login|imap-login): .*(?:Authentication failure|Aborted login \(auth failed|Aborted login \(tried to use disabled|Disconnected \(auth failed|Aborted login \(\d+ authentication attempts).*rip=,.* +ignoreregex = From 0964865c4cb5d6297582ffd6bc970adca3b28639 Mon Sep 17 00:00:00 2001 From: William Hirigoyen Date: Thu, 15 Sep 2022 10:14:45 +0200 Subject: [PATCH 71/74] domains: integrate role into evolinux-base --- {domains => evolinux-base}/files/domains.py | 0 domains/tasks/main.yml => evolinux-base/tasks/domains.yml | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {domains => evolinux-base}/files/domains.py (100%) rename domains/tasks/main.yml => evolinux-base/tasks/domains.yml (100%) diff --git a/domains/files/domains.py b/evolinux-base/files/domains.py similarity index 100% rename from domains/files/domains.py rename to evolinux-base/files/domains.py diff --git a/domains/tasks/main.yml b/evolinux-base/tasks/domains.yml similarity index 100% rename from domains/tasks/main.yml rename to evolinux-base/tasks/domains.yml From c310482ba6d3e948d963bb8c3cf7355291e1debc Mon Sep 17 00:00:00 2001 From: William Hirigoyen Date: Thu, 15 Sep 2022 10:25:06 +0200 Subject: [PATCH 72/74] domains: revert commits moved to dev branch domains --- CHANGELOG.md | 2 - evolinux-base/files/domains.py | 325 ------------------ evolinux-base/tasks/domains.yml | 8 - nagios-nrpe/README.md | 6 - nagios-nrpe/files/plugins/check_domains | 14 - nagios-nrpe/tasks/configure_check_domains.yml | 25 -- nagios-nrpe/tasks/main.yml | 1 - nagios-nrpe/templates/evolix.cfg.j2 | 1 - 8 files changed, 382 deletions(-) delete mode 100755 evolinux-base/files/domains.py delete mode 100644 evolinux-base/tasks/domains.yml delete mode 100755 nagios-nrpe/files/plugins/check_domains delete mode 100644 nagios-nrpe/tasks/configure_check_domains.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 009f5625..067a2bf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,6 @@ The **patch** part changes is incremented if multiple releases happen the same m * php: install php-xml with recent PHP versions * vrrp: add an `ip.yml` task file to help create VRRP addresses * webapps/nextcloud: Add compatibility with apache2, and apache2 mod_php. -* inspect-domains: Add role * memcached: NRPE check for multi-instance setup * proftpd: Add options to override configs (and add a warning if file was overriden) * proftpd: Allow user auth with ssh keys @@ -28,7 +27,6 @@ The **patch** part changes is incremented if multiple releases happen the same m * generate-ldif: Support any MariaDB version * minifirewall: use handlers to restart minifirewall * openvpn: automate the initialization of the CA and the creation of the server certificate ; use openssl_dhparam module instead of a command -* nagios-nrpe: Add check_domains * generate-ldif: support any version of MariaDB (instead of only 10.0, 10.1 and 10.3) * openvpn: Run OpenVPN with the \_openvpn user and group instead of nobody which is originally for NFS * nagios-nrpe: Upgrade check_mongo diff --git a/evolinux-base/files/domains.py b/evolinux-base/files/domains.py deleted file mode 100755 index 23dd28ee..00000000 --- a/evolinux-base/files/domains.py +++ /dev/null @@ -1,325 +0,0 @@ -#!/usr/bin/python3 -# -# Vérifie si les domaines listés dans les configurations de Apache, -# Nginx et Haproxy pointent bien sur le serveur. -# -# Développé par Will -# - -list_domains_path = '/usr/local/sbin/list_domains.py' -excludes_path = '/etc/nagios/domains_exclude.list' -includes_path = '/etc/nagios/domains_include.list' - -import os -import sys -import re -import subprocess -import threading -import time -import argparse -import json - -#import importlib.machinery -#list_domains = importlib.machinery.SourceFileLoader('list_domains.py', list_domains_path).load_module() - - -def execute(cmd): - """Execute Bash command cmd. - Return stdout and stderr as arrays of UTF-8 strings.""" - - proc = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = proc.communicate() - - stdout_lines = stdout.decode('utf-8').splitlines() - stderr_lines = stderr.decode('utf-8').splitlines() - - return stdout_lines, stderr_lines - - -def get_my_ips(): - """Return localhost IPs.""" - stdout, stderr = execute('hostname -I') - if not stdout: - return [] - return stdout[0].strip(' \t').split() - - -def dig(domain): - """Return dig +short result on domain as a list.""" - stdout, stderr = execute('dig +short {}'.format(domain)) - return stdout - - -def strip_comments(string): - """Return string with any # comment removed.""" - return string.split('#')[0] - - -def list_apache_domains(): - """Return a dict containing : - - key: Apache domain (from command "apache2ctl -D DUMP_VHOSTS"). - - value: a list of strings "apache::" - """ - domains = {} - - try: - stdout, stderr = execute('apache2ctl -D DUMP_VHOSTS') - except: - # Apache is not present on the server - return domains - - vhost_infos = '' - for line in stdout: - dom = '' - words = line.strip(' \t').split() - - if 'namevhost' in line and len(words) >= 5: - # line format: port namevhost (:) - dom = words[3].strip() - vhost_infos = 'apache:' + words[4].strip('()') - - elif 'alias' in line and len(words) >= 2: - # line format: alias - dom = words[1].strip() # vhost_infos defined in previous lines - - if dom: - if dom not in domains: - domains[dom] = [] - if vhost_infos not in domains[dom]: - domains[dom].append(vhost_infos) - - return domains - - -def list_nginx_domains(): - """Return a dict containing : - - key: Nginx domain (from command "nginx -T"). - - value: a list of strings "nginx::" - """ - domains = {} - - try: - stdout, stderr = execute('nginx -T') - except: - # Nginx is not present on the server - return domains - - line_number = 1 - config_file_path = '' - - for line in stdout: - if '# configuration file' in line: - # line format : # configuration file : - words = line.strip(' \t;').split() - config_file_path = words[3].strip(' :') - continue - - if 'server_name ' in line: - # TODO: améliorer le if (cas tabulation) - # line format : server_name [ secs to DNS servers to answer in jobs threads - time.sleep(timeout) - - timeout_domains = [] - none_domains = [] - outside_ips = {} - ok_domains = [] - - for j in jobs: - if j.is_alive(): - timeout_domains.append(j.domain) - continue - - if not j.ips: - none_domains.append(j.domain) - continue - - is_outside = False - for ip in j.ips: - if ip not in my_ips: - is_outside = True - break - if is_outside: - outside_ips[j.domain] = j.ips - else: - ok_domains.append(j.domain) - - return timeout_domains, none_domains, outside_ips, ok_domains - - -def output_check_mode(timeout_domains, none_domains, outside_ips, ok_domains): - """Output result for check mode. - For now, consider everyting as warnings to avoid too much alerts. - """ - - n_ok = len(ok_domains) - n_warnings = len(timeout_domains) + len(none_domains) + len(outside_ips) - - msg = 'WARNING' if n_warnings else 'OK' - - print('{} - 0 UNK / 0 CRIT / {} WARN / {} OK \n'.format(msg, n_warnings, n_ok)) - - if timeout_domains or none_domains or outside_ips: - for d in timeout_domains: - print('WARNING - timeout resolving {}'.format(d)) - for d in none_domains: - print('WARNING - no resolution for {}'.format(d)) - for d in outside_ips: - print('WARNING - {} pointing elsewhere ({})'.format(d, ' '.join(outside_ips[d]))) - - sys.exit(1) if n_warnings else sys.exit(0) - - -def output_human_mode(doms, timeout_domains, none_domains, outside_ips): - if timeout_domains or none_domains or outside_ips: - if timeout_domains: print('\nTimeouts:') - for d in timeout_domains: - print('\t{} {}'.format(d, ' '.join(doms[d]))) - if none_domains: print('\nNo resolution:') - for d in none_domains: - print('\t{} {}'.format(d, ' '.join(doms[d]))) - if outside_ips: print('\nPointing elsewhere:') - for d in outside_ips: - print('\t{} {} -> [{}]'.format(d, ' '.join(doms[d]), ' '.join(outside_ips[d]))) - - sys.exit(1) - - print('Domains resolve to right IPs !') - - -def main(argv): - parser = argparse.ArgumentParser() - parser.add_argument('action', metavar='ACTION', help='Values: check-dns, list') - parser.add_argument('-o', '--output-style', help='Values: json (default for action list), human (default for action check-dns), nrpe') - parser.add_argument('-a', '--all-domains', action='store_true', help='Include all domains (default).') - parser.add_argument('-ap', '--apache-domains', action='store_true', help='Include Apache domains.') - parser.add_argument('-ng', '--nginx-domains', action='store_true', help='Include Nginx domains.') - parser.add_argument('-ha', '--haproxy-domains', action='store_true', help='Include HaProxy domains (not supported yet).') - args = parser.parse_args() - - if args.action not in ['check-dns', 'list']: - if args.output_style == 'nrpe': - print('UNKNOWN - unknown {} action, use -h option for help.'.format(args.action)) - sys.exit(3) - else: - print('Unknown {} action, use -h option for help.'.format(args.action)) - sys.exit(1) - - if not (args.all_domains or args.apache_domains or args.nginx_domains or args.haproxy_domains): - print('Domains scope not specified, looking for all domains.') - args.all_domains = True - - doms = {} - - if args.all_domains: - doms.update(list_apache_domains()) - - else: - if args.apache_domains: - doms.update(list_apache_domains()) - if args.nginx_domains: - doms.update(list_nginx_domains()) - if args.haproxy_domains: - print('Option --haproxy-domains not supported yet.') - - if not doms: - if args.output_style == 'nrpe': - print('UNKNOWN - No domain found on this server.') - sys.exit(3) - else: # == 'json' or 'human' - print('No domain found on this server.') - sys.exit(1) - - if args.action == 'check-dns': - timeout_domains, none_domains, outside_ips, ok_domains = run_check_domains(doms.keys()) - - if args.output_style == 'nrpe': - output_check_mode(timeout_domains, none_domains, outside_ips, ok_domains) - - elif args.output_style == 'json': - print('Option --output-style json not implemented yet for action check-dns.') - - else: # args.output_style == 'human' - output_human_mode(doms, timeout_domains, none_domains, outside_ips) - - elif args.action == 'list': - - if args.output_style == 'nrpe': - print('Action list is not for --output-style nrpe.') - - elif args.output_style == 'json': - print(json.dumps(doms, sort_keys=True, indent=4)) - - else: - print('Option --output-style human not implemented yet for action list, fallback to --output-style json.') - print(json.dumps(doms, sort_keys=True, indent=4)) - - -if __name__ == '__main__': - main(sys.argv[1:]) diff --git a/evolinux-base/tasks/domains.yml b/evolinux-base/tasks/domains.yml deleted file mode 100644 index f2a1ddb3..00000000 --- a/evolinux-base/tasks/domains.yml +++ /dev/null @@ -1,8 +0,0 @@ -- name: Copy inspect-domains script to local sbin - ansible.builtin.copy: - src: domains.py - dest: /usr/local/sbin/domains - mode: '0700' - - - diff --git a/nagios-nrpe/README.md b/nagios-nrpe/README.md index c52cab05..6d72920e 100644 --- a/nagios-nrpe/README.md +++ b/nagios-nrpe/README.md @@ -12,9 +12,3 @@ Everything is in the `tasks/main.yml` file. * `nagios_nrpe_force_update_allowed_hosts` : force update list of allowed hosts (default: `False`) The full list of variables (with default values) can be found in `defaults/main.yml`. - -## Available tags - -* `nagios-nrpe` : install Nagios and plugins (idempotent) -* `nagios-plugins` : install only plugins (idempotent) - diff --git a/nagios-nrpe/files/plugins/check_domains b/nagios-nrpe/files/plugins/check_domains deleted file mode 100755 index 98068a0b..00000000 --- a/nagios-nrpe/files/plugins/check_domains +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -# -# Check domains using script domains. -# -# Written by Will -# - -if ! command -v domains >/dev/null; then - echo 'UNKNOWN - Missing dependency domains.' - exit 3 -fi - -domains -o nrpe -a check-dns - diff --git a/nagios-nrpe/tasks/configure_check_domains.yml b/nagios-nrpe/tasks/configure_check_domains.yml deleted file mode 100644 index 2d5dd2fd..00000000 --- a/nagios-nrpe/tasks/configure_check_domains.yml +++ /dev/null @@ -1,25 +0,0 @@ -- name: Install check_domains dependency - include_role: - name: domains - -- name: Configure check_domains in /etc/nagios/nrpe.d/evolix.cfg - ansible.builtin.lineinfile: - path: /etc/nagios/nrpe.d/evolix.cfg - regexp: '^command\[check_domains\]=' - line: command[check_domains]=sudo {{ nagios_plugins_directory }}/check_domains - notify: restart nagios-nrpe-server - -- name: Is evolinux sudoers installed? - ansible.builtin.stat: - path: /etc/sudoers.d/evolinux - register: sudoers_evolinux - -- name: Allow nagios user to execute check_domains without sudo password - ansible.builtin.lineinfile: - path: /etc/sudoers.d/evolinux - regexp: 'check_domains' - line: 'nagios ALL = NOPASSWD: {{ nagios_plugins_directory }}/check_domains' - insertafter: '^nagios' - validate: "visudo -cf %s" - when: sudoers_evolinux.stat.exists - diff --git a/nagios-nrpe/tasks/main.yml b/nagios-nrpe/tasks/main.yml index 28ab11a9..77770020 100644 --- a/nagios-nrpe/tasks/main.yml +++ b/nagios-nrpe/tasks/main.yml @@ -22,7 +22,6 @@ - ansible_distribution == "Debian" - ansible_distribution_major_version is version('10', '>=') tags: - - nagios-nrpe - nagios-plugins - name: custom configuration is present diff --git a/nagios-nrpe/templates/evolix.cfg.j2 b/nagios-nrpe/templates/evolix.cfg.j2 index 7546f2bc..ae0e0abd 100644 --- a/nagios-nrpe/templates/evolix.cfg.j2 +++ b/nagios-nrpe/templates/evolix.cfg.j2 @@ -47,7 +47,6 @@ command[check_proxy]=/usr/lib/nagios/plugins/check_http -H {{ nagios_nrpe_check_ command[check_redis]=/usr/lib/nagios/plugins/check_tcp -p 6379 command[check_clamd]=/usr/lib/nagios/plugins/check_clamd -H /var/run/clamav/clamd.ctl -v command[check_clamav_db]=/usr/lib/nagios/plugins/check_file_age -w 86400 -c 172800 -f /var/lib/clamav/evolix.ndb -command[check_domains]=sudo {{ nagios_plugins_directory }}/check_domains command[check_ssl]=/usr/lib/nagios/plugins/check_http -f follow -I 127.0.0.1 -S -p 443 -H ssl.evolix.net -C 15,5 command[check_ssl_local]={{ nagios_plugins_directory }}/check_ssl_local command[check_elasticsearch]=/usr/lib/nagios/plugins/check_http -I 127.0.0.1 -u /_cat/health?h=st -p 9200 -r 'red' --invert-regex From a5402350775abd2f0f6bd31eb9aa509d3085d1c9 Mon Sep 17 00:00:00 2001 From: Ludovic Poujol Date: Thu, 15 Sep 2022 11:45:24 +0200 Subject: [PATCH 73/74] munin: Add ipmi_ plugins on dedicated hardware --- CHANGELOG.md | 2 ++ munin/tasks/main.yml | 25 +++++++++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 067a2bf2..e76f05ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,9 +17,11 @@ The **patch** part changes is incremented if multiple releases happen the same m * vrrp: add an `ip.yml` task file to help create VRRP addresses * webapps/nextcloud: Add compatibility with apache2, and apache2 mod_php. * memcached: NRPE check for multi-instance setup +* munin: Add ipmi_ plugins on dedicated hardware * proftpd: Add options to override configs (and add a warning if file was overriden) * proftpd: Allow user auth with ssh keys + ### Changed * evocheck: upstream release 22.09 diff --git a/munin/tasks/main.yml b/munin/tasks/main.yml index 4720fbe5..a4ea9a49 100644 --- a/munin/tasks/main.yml +++ b/munin/tasks/main.yml @@ -1,12 +1,13 @@ --- -- name: Ensure that Munin is installed +- name: Ensure that Munin (and useful dependencies) is installed apt: name: - munin - munin-node - munin-plugins-core - munin-plugins-extra + - gawk state: present tags: - munin @@ -79,16 +80,32 @@ tags: - munin -- name: Enable sensors plugin unless VM detected +- name: Enable sensors_ plugin on dedicated hardware file: src: /usr/share/munin/plugins/sensors_ - dest: /etc/munin/plugins/sensors_temp + dest: "/etc/munin/plugins/sensors_{{ item }}" state: link - when: ansible_virtualization_role != "guest" + with_items: + - fan + - temp + when: ansible_virtualization_role == "host" notify: restart munin-node tags: - munin +- name: Enable ipmi_ plugin on dedicated hardware + file: + src: /usr/share/munin/plugins/ipmi_ + dest: "/etc/munin/plugins/ipmi_{{ item }}" + state: link + when: ansible_virtualization_role == "host" + notify: restart munin-node + with_items: + - fans + - temp + - power + - volts + - name: adjustments for grsec kernel blockinfile: dest: /etc/munin/plugin-conf.d/munin-node From 8089d90bd16e444afe490d2eac2f88ca6195e66c Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Mon, 19 Sep 2022 17:06:25 +0200 Subject: [PATCH 74/74] Release 22.09 --- CHANGELOG.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e76f05ac..71f7be80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,18 @@ The **patch** part changes is incremented if multiple releases happen the same m ### Added +### Changed + +### Fixed + +### Removed + +### Security + +## [22.09] 2022-09-19 + +### Added + * evolinux_users: create only users who have a certain value for the `create` key (default: `always`). * php: install php-xml with recent PHP versions * vrrp: add an `ip.yml` task file to help create VRRP addresses @@ -47,8 +59,6 @@ The **patch** part changes is incremented if multiple releases happen the same m * evocheck: remove failure if deprecated variable is used * webapps/nextcloud: Drop support for Nginx -### Security - ## [22.07.1] 2022-07-28 ### Changed