diff --git a/CHANGELOG.md b/CHANGELOG.md
index 19a472e0..f305b5a4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,50 +6,165 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
This project does not follow semantic versioning.
The **major** part of the version is the year
-The **minor** part changes is the month
-The **patch** part changes is incremented if multiple releases happen the same month
+The **minor** part is the month
+The **patch** part is incremented if multiple releases happen the same month
## [Unreleased]
### Added
-* Preliminary work for php83
+### Changed
+
+* autosysadmin-agent: upstream release 24.03.1
+
+### Fixed
+
+* certbot: Fix HAProxy renewal hook
+* keepalived: Fix tasks that use file instead of copy
+* memcached: Fix conditions not properly writen (installation was always in multi-instance mode)
+
+### Removed
+
+### Security
+
+## [24.03] 2024-03-01
+
+### Added
+
+* autosysadmin-agent: upstream release 24.03
+* autosysadmin-restart_nrpe: add role
+* certbot: Renewal hook for NRPE
+* kvm-host: add minifirewall rules if DRBD interface is configured
+* proftpd: add whitelist ip
+
+### Changed
+
+* apt: add ftp.evolix.org as recognized system source
+* autosysadmin-agent: logs clearing is done weekly
+* autosysadmin-agent: rename /usr/share/scripts/autosysadmin/{auto,restart}
+* certbot: use pkey to test the key
+* evolinux-base: execute autosysadmin-agent and autosysadmin-restart_nrpe roles
+* lxc-php, php: Update sury PGP key
+* openvpn: earlier alert for CA expiration
+* redis: create sysfs config file if missing
+* nextcloud: use latest version by default
+
+### Removed
+
+* autosysadmin: replaced by autosysadmin-agent
+
+## [24.02.1] 2024-02-08
+
+### Fixed
+
+* fail2ban: fix Ansible syntax
+
+## [24.02] 2024-02-08
+
+### Added
+
+* Support for PHP 8.3 with bookworm LXC containers
+* apt: add task file to install ELTS repository (default: False)
+* autosysadmin: Add a role to automatically deploy autosysadmin on evolixisation
+* check_free_space: added role
+* etc-git: add /var/chroot-bind/etc/bind repo
+* fail2ban: add script unban_ip
+* generateldif: new Services for check_pressure_{cpu,io,mem}
+* kvm-host: Automatically add an LVM filter when LVM is present
+* lxc-php: Allow one to install php83 on Bookworm container
+* minifirewall: Fix nagios check for old versions of minifirewall
+* mongodb: add gpg key for 7.0
* nagios-nrpe: add check_sentinel for monitoring Redis Sentinel
+* nagios-nrpe: new check_pressure_{cpu,io,mem}
+* remount-usr: do not try to remount /usr RW if /usr is not a mounted partition
+* vrrpd: configure minifirewall
+* vrrpd: test if interface exists before deleting it
+* webapps/evoadmin-mail: package installed via public.evolix.org/evolix repo starting with Bookworm
+* webapps/nextcloud: Add condition for archive tasks
+* webapps/nextcloud: Add condition for config tasks
* webapps/nextcloud: Added var nextcloud_user_uid to enforce uid for nextcloud user
+* webapps/nextcloud: Set ownership and permissions of data directory
### Changed
* add-vm.sh: allow VM name max length > 20
+* amavis: make ldap_suffix mandatory
* apache : fix goaway pattern for bad bots
* apache : rename MaxRequestsPerChild to MaxConnectionsPerChild (new name)
-* evocheck: upstream release 23.10
+* apache: use backward compatible Redirect directive
+* apt: Disable archive repository for Debian 8
+* apt: Use the GPG version of the key for Debian 8-9
+* bind: Update role for Buster, Bullseye and Bookworm support
+* dovecot: add variables for LDAP
+* dovecot: Munin plugin conf path is now `/etc/munin/plugin-conf.d/zzz-dovecot` (instead of `z-evolinux-dovecot`)
+* evocheck: upstream release 24.01
* evolinux-base: dump-server-state upstream release 23.11
* evolinux-base: use separate default config file for rsyslog
+* kvmstats: use .capacity instead of .physical for disk size
+* ldap: make ldap_suffix mandatory
+* listupgrade : old-kernel-removal.sh upstream release 24.01
* log2mail: move custom config in separate file
+* lxc: init /etc git repository in lxc container
+* mysql: disable performance schema for Debian 8
+* nagios: add dockerd check in nrpe check template
+* nagios: cleaning nrpe check template
* nagios: rename var `nagios_nrpe_process_processes` into `nagios_nrpe_processes` and check systemd-timesyncd instead of ntpd in Debian 12
+* nagios: add option --full to check pressure IO and mem to avoid flaps
* proftpd: in SFTP vhost, enable SSH keys login, enable ed25549 host key for Debian >= 11
+* redis: manage config template inside a block, to allow custom modifications outside
+* spamassassin: Use spamd starting with Bookworm
+* squid: config directory seems to have changed from /etc/squid3 to /etc/squid in Debian 8
+* unbound: Add config file to allow configuration reload on Debian 11 and lower
+* unbound: Add munin configuration & setup plugin
+* unbound: Big cleanup
+* unbound: Move generated config file to `/etc/unbound/unbound.conf.d/evolinux.conf`
+* unbound: Use root hints provided by debian package dns-root-data instead of downloading them
+* vrrpd: replace switch script with custom one (fix MAC issue, use `ip(8)`, shell cleanup…)
+* vrrpd: variable to force update the switch script (default: false)
+* webapps/nextcloud: Add Ceph volume to fstab
+* webapps/nextcloud: Set home directory's mode
### Fixed
-* nginx: keep indentation
-* evoadmin-web: Fix PHP version for Bookworm
* Add php-fpm82 to LDAP when relevant
-* nagios: fix default file to monitor for check_clamav_db
-* php: Bullseye/Sury > Honor the php_version asked in the pub.evolix.org repository
-* webapps/nextcloud: fix missing gid
-* webapps/nextcloud: fix misplaced gid attribute
-* webapps/nextcloud: added check that nexctcloud uid is over 3000
-* ProFTPd: set missing default listen IP for SFTP
+* Check stat.exists before stat.isdir
* apache: fix MaxRequestsPerChild value to be sync with wiki.e.o
+* apt: use archive.debian.org with Stretch
+* certbot: fix hook for dovecot when more than one certificate is used (eg. different certificates for POP3 and IMAP)
+* dovecot: add missing LDAP conf iterate_filter to exclude disabled accounts in users list (caused « User no longer exists » errors in commands listing users like « doveadm user -u '*' » or « doveadm expunge -u "*" mailbox INBOX savedbefore 7d »).
+* dovecot: fix missing default mails
+* dovecot: fix plugin dovecot1
+* evoadmin-web: Fix PHP version for Bookworm
+* evolinux-base: fix hardware.yml (wrong repo, missing update cache)
+* evolinux-base: start to install linux-image-cloud-amd64 with Buster
+* fail2ban: fix template marker
+* minifirewall: ports 25, 53, 443, 993, 995 not opened publicly by default anymore, ports 20, 21, 110, 143 not opened semi-publicly by default anymore.
+* nagios: fix default file to monitor for check_clamav_db
+* nginx: add "when: not ansible_check_mode" in various tasks to prevent fail in check mode
+* nginx: fix mistake between "check_mode: no" and "when: not ansible_check_mode" (fail in check mode)
+* nginx: fix mistake between "check_mode: no" and "when: not ansible_check_mode" (fail in check mode)
+* nginx: keep indentation
+* nginx: take care of « already defined » and « not yet defined » server status suffix in check mode
+* php: Bullseye/Sury > Honor the php_version asked in the pub.evolix.org repository
+* php: drop apt_preferences(5) file for sury
+* postfix: remove dependency on evolinux_fqdn var
+* proftpd: set missing default listen IP for SFTP
+* roundcube: set default SMTP port to 25 instead of 587, which failed because of missing SSL conf (local connexion does not need SSL)
* ssl: no not execute haproxy tasks and reload if haproxy is disabled
+* unbound: Add a apt cache validity to enforce an apt update if needed
+* webapps/nextcloud: added check that nextcloud uid is over 3000
+* webapps/nextcloud: fix Add Ceph volume to fstab : missing UUID= in src
+* webapps/nextcloud: fix misplaced gid attribute
+* webapps/nextcloud: fix missing gid
+* webapps/roundcube & evoadminmail: make roles more idempotent (were failing when played twice)
+* amavis: Add variables for generate "ldap_suffix"
+* proftpd: fix error when no SSH key is provided
### Removed
* evolinux-base: no need to remove update-evobackup-canary from sbin anymore
* evolinux-base: no need to symlink backup-server-state to dump-server-state anymore
-### Security
-
## [23.10] 2023-10-14
### Added
@@ -416,7 +531,6 @@ The **patch** part changes is incremented if multiple releases happen the same m
### Changed
* evocheck: Upstream release 22.05
-* bind: Update role for Buster, Bullseye and Bookworm support
### Removed
diff --git a/amavis/defaults/main.yml b/amavis/defaults/main.yml
new file mode 100644
index 00000000..c353a3ba
--- /dev/null
+++ b/amavis/defaults/main.yml
@@ -0,0 +1,5 @@
+---
+
+ldap_hostname: "{{ ansible_hostname }}"
+ldap_domain: "{{ ansible_domain }}"
+ldap_suffix: "dc={{ ldap_hostname }},dc={{ ldap_domain.split('.')[-2] }},dc={{ ldap_domain.split('.')[-1] }}"
diff --git a/amavis/tasks/main.yml b/amavis/tasks/main.yml
index da46721e..e9f67b4d 100644
--- a/amavis/tasks/main.yml
+++ b/amavis/tasks/main.yml
@@ -6,7 +6,7 @@
- amavisd-new
state: present
tags:
- - amavis
+ - amavis
- name: configure Amavis
ansible.builtin.template:
@@ -15,7 +15,7 @@
mode: "0644"
notify: restart amavis
tags:
- - amavis
+ - amavis
- name: Install purge custom cron
ansible.builtin.copy:
@@ -23,5 +23,5 @@
dest: /etc/cron.daily/amavis_purge_virusmails
mode: "0755"
tags:
- - amavis
- - amavis_purge_cron
+ - amavis
+ - amavis_purge_cron
diff --git a/amavis/templates/amavis.conf.j2 b/amavis/templates/amavis.conf.j2
index cbe597a2..8bc9bae8 100644
--- a/amavis/templates/amavis.conf.j2
+++ b/amavis/templates/amavis.conf.j2
@@ -44,7 +44,7 @@ $max_servers = 2;
$enable_ldap = 1;
$default_ldap = {
hostname => '127.0.0.1', tls => 0,
- base => '{{ ldap_suffix }}', scope => 'sub',
+ base => '{{ ldap_suffix | mandatory }}', scope => 'sub',
query_filter => '(&(mailacceptinggeneralid=%m)(isActive=TRUE))'
};
diff --git a/apache/files/evolinux-defaults.conf b/apache/files/evolinux-defaults.conf
index 73b7f136..c05f77f2 100644
--- a/apache/files/evolinux-defaults.conf
+++ b/apache/files/evolinux-defaults.conf
@@ -48,17 +48,17 @@ MaxKeepAliveRequests 10
# We don't want to let the client know a file exist on the server,
# so we return 404 "Not found" instead of 403 "Forbidden".
- Redirect 404
+ Redirect 404 "-"
# File names starting with
- Redirect 404
+ Redirect 404 "-"
# File names ending with
- Redirect 404
+ Redirect 404 "-"
diff --git a/apache/tasks/ip_whitelist.yml b/apache/tasks/ip_whitelist.yml
index 5060f56e..bb7e8f46 100644
--- a/apache/tasks/ip_whitelist.yml
+++ b/apache/tasks/ip_whitelist.yml
@@ -5,6 +5,7 @@
dest: /etc/apache2/ipaddr_whitelist.conf
line: "Require ip {{ item }}"
state: present
+ create: yes
loop: "{{ apache_ipaddr_whitelist_present }}"
notify: reload apache
tags:
diff --git a/apt/defaults/main.yml b/apt/defaults/main.yml
index 3720d893..772a8fb9 100644
--- a/apt/defaults/main.yml
+++ b/apt/defaults/main.yml
@@ -14,6 +14,7 @@ apt_install_backports: False
apt_backports_components: "main"
apt_install_evolix_public: True
+apt_install_extended_lts: False
apt_clean_gandi_sourceslist: False
@@ -28,4 +29,4 @@ apt_check_hold_cron_weekday: "*"
apt_check_hold_cron_day: "*"
apt_check_hold_cron_month: "*"
-apt_keyring_dir: "{{ ansible_distribution_major_version is version('12', '<') | ternary('/etc/apt/trusted.gpg.d', '/etc/apt/keyrings') }}"
\ No newline at end of file
+apt_keyring_dir: "{{ ansible_distribution_major_version is version('12', '<') | ternary('/etc/apt/trusted.gpg.d', '/etc/apt/keyrings') }}"
diff --git a/apt/files/bookworm_backports_preferences b/apt/files/bookworm_backports_preferences
deleted file mode 100644
index eaf76d52..00000000
--- a/apt/files/bookworm_backports_preferences
+++ /dev/null
@@ -1,3 +0,0 @@
-Package: *
-Pin: release a=bookworm-backports
-Pin-Priority: 50
diff --git a/apt/files/bullseye_backports_preferences b/apt/files/bullseye_backports_preferences
deleted file mode 100644
index 3a667c93..00000000
--- a/apt/files/bullseye_backports_preferences
+++ /dev/null
@@ -1,3 +0,0 @@
-Package: *
-Pin: release a=bullseye-backports
-Pin-Priority: 50
diff --git a/apt/files/buster_backports_preferences b/apt/files/buster_backports_preferences
deleted file mode 100644
index 30fef48d..00000000
--- a/apt/files/buster_backports_preferences
+++ /dev/null
@@ -1,3 +0,0 @@
-Package: *
-Pin: release a=buster-backports
-Pin-Priority: 50
diff --git a/apt/files/deb822-migration.py b/apt/files/deb822-migration.py
index f8693b28..cb135972 100755
--- a/apt/files/deb822-migration.py
+++ b/apt/files/deb822-migration.py
@@ -1,5 +1,11 @@
#!/usr/bin/env python3
+##########
+# This script takes a multi-lines input of "oneliner-style" APT sources definitions.
+# It converts them into "deb822-style" sources.
+# Each generated file will have only one stanza, possibly with multiple Types/Suites/Components
+##########
+
import re
import sys
import os
@@ -10,11 +16,16 @@ import apt_pkg
# Order matters !
destinations = {
"debian-security": "security.sources",
+
".*-backports": "backports.sources",
+
".debian.org": "system.sources",
"mirror.evolix.org": "system.sources",
+ "ftp.evolix.org": "system.sources",
+
"pub.evolix.net": "evolix_public_old.sources.bak",
"pub.evolix.org": "evolix_public.sources",
+
"artifacts.elastic.co": "elastic.sources",
"download.docker.com": "docker.sources",
"downloads.linux.hpe.com": "hp.sources",
@@ -76,6 +87,11 @@ def prepare_sources(lines):
key, value = option.split("=")
options[key] = value
+ ### WARNING ###
+ # if there are multiple lines with different URIS for a given destination (eg. "system")
+ # each one will overwrite the previous one
+ # and the last evaluated will be what remains.
+
if dest in sources:
sources[dest]["Types"].add(matches["type"])
sources[dest]["URIs"] = matches["uri"]
diff --git a/apt/files/deb822-migration.sh b/apt/files/deb822-migration.sh
index 10fb7889..7a4fb787 100755
--- a/apt/files/deb822-migration.sh
+++ b/apt/files/deb822-migration.sh
@@ -1,5 +1,11 @@
#!/bin/sh
+##########
+# This script changes all "one-line" APT sources into "deb822" sources.
+# It is responsible for searching and processing the files.
+# The actual format migration is done by a python script.
+##########
+
deb822_migrate_script=$(command -v deb822-migration.py)
if [ -z "${deb822_migrate_script}" ]; then
@@ -46,4 +52,4 @@ for file in $(find /etc/apt/sources.list.d -mindepth 1 -maxdepth 1 -type f -name
done
echo "${count} file(s) migrated"
-exit ${rc}
\ No newline at end of file
+exit ${rc}
diff --git a/apt/files/freexian-archive-extended-lts.gpg b/apt/files/freexian-archive-extended-lts.gpg
new file mode 100644
index 00000000..819c10ff
Binary files /dev/null and b/apt/files/freexian-archive-extended-lts.gpg differ
diff --git a/apt/files/jessie_backports_preferences b/apt/files/jessie_backports_preferences
deleted file mode 100644
index dd3cef12..00000000
--- a/apt/files/jessie_backports_preferences
+++ /dev/null
@@ -1,3 +0,0 @@
-Package: *
-Pin: release a=jessie-backports
-Pin-Priority: 50
diff --git a/apt/files/stretch_backports_preferences b/apt/files/stretch_backports_preferences
deleted file mode 100644
index 6d5d03be..00000000
--- a/apt/files/stretch_backports_preferences
+++ /dev/null
@@ -1,3 +0,0 @@
-Package: *
-Pin: release a=stretch-backports
-Pin-Priority: 50
diff --git a/apt/tasks/backports.deb822.yml b/apt/tasks/backports.deb822.yml
index 0382892d..db117d94 100644
--- a/apt/tasks/backports.deb822.yml
+++ b/apt/tasks/backports.deb822.yml
@@ -10,19 +10,9 @@
tags:
- apt
-- name: Backports configuration
- ansible.builtin.copy:
- src: '{{ ansible_distribution_release }}_backports_preferences'
- dest: /etc/apt/preferences.d/0-backports-defaults
- force: true
- mode: "0640"
- register: apt_backports_config
- tags:
- - apt
-
- name: Apt update
ansible.builtin.apt:
update_cache: yes
- when: apt_backports_sources is changed or apt_backports_config is changed
+ when: apt_backports_sources is changed
tags:
- apt
diff --git a/apt/tasks/backports.oneline.yml b/apt/tasks/backports.oneline.yml
index 11de5c52..1630de19 100644
--- a/apt/tasks/backports.oneline.yml
+++ b/apt/tasks/backports.oneline.yml
@@ -17,16 +17,6 @@
tags:
- apt
-- name: Backports configuration
- ansible.builtin.copy:
- src: '{{ ansible_distribution_release }}_backports_preferences'
- dest: /etc/apt/preferences.d/0-backports-defaults
- force: true
- mode: "0640"
- register: apt_backports_config
- tags:
- - apt
-
- name: Archived backport are accepted (jessie)
ansible.builtin.lineinfile:
dest: '/etc/apt/apt.conf.d/99no-check-valid-until'
@@ -42,4 +32,4 @@
update_cache: yes
tags:
- apt
- when: apt_backports_list is changed or apt_backports_config is changed
+ when: apt_backports_list is changed
diff --git a/apt/tasks/evolix_public.deb822.yml b/apt/tasks/evolix_public.deb822.yml
index 0a91dddf..0e6639c3 100644
--- a/apt/tasks/evolix_public.deb822.yml
+++ b/apt/tasks/evolix_public.deb822.yml
@@ -24,10 +24,16 @@
owner: root
group: root
+- name: Set Evolix GPG key format to ASC
+ set_fact:
+ apt_evolix_public_key: "{{ apt_keyring_dir }}/pub_evolix.asc"
+ tags:
+ - apt
+
- name: Add Evolix GPG key
ansible.builtin.copy:
src: pub_evolix.asc
- dest: "{{ apt_keyring_dir }}/pub_evolix.asc"
+ dest: "{{ apt_evolix_public_key }}"
force: true
mode: "0644"
owner: root
diff --git a/apt/tasks/evolix_public.oneline.yml b/apt/tasks/evolix_public.oneline.yml
index 9501e595..165a7b93 100644
--- a/apt/tasks/evolix_public.oneline.yml
+++ b/apt/tasks/evolix_public.oneline.yml
@@ -24,10 +24,26 @@
owner: root
group: root
+- name: Set Evolix GPG key format to GPG (Debian < 9)
+ set_fact:
+ apt_evolix_public_key: "pub_evolix.gpg"
+ when:
+ - ansible_distribution_major_version is version('9', '<')
+ tags:
+ - apt
+
+- name: Set Evolix GPG key format to ASC (Debian >= 9)
+ set_fact:
+ apt_evolix_public_key: "pub_evolix.asc"
+ when:
+ - ansible_distribution_major_version is version('9', '>=')
+ tags:
+ - apt
+
- name: Add Evolix GPG key
ansible.builtin.copy:
- src: pub_evolix.asc
- dest: "{{ apt_keyring_dir }}/pub_evolix.asc"
+ src: "{{ apt_evolix_public_key }}"
+ dest: "{{ apt_keyring_dir }}/{{ apt_evolix_public_key }}"
force: true
mode: "0644"
owner: root
diff --git a/apt/tasks/extended-lts.oneline.yml b/apt/tasks/extended-lts.oneline.yml
new file mode 100644
index 00000000..09974684
--- /dev/null
+++ b/apt/tasks/extended-lts.oneline.yml
@@ -0,0 +1,37 @@
+---
+
+- name: "Ensure {{ apt_keyring_dir }} directory exists"
+ file:
+ path: "{{ apt_keyring_dir }}"
+ state: directory
+ mode: "755"
+ owner: root
+ group: root
+
+- name: Add Evolix GPG key
+ ansible.builtin.copy:
+ src: "freexian-archive-extended-lts.gpg"
+ dest: "{{ apt_keyring_dir }}/freexian-archive-extended-lts.gpg"
+ force: true
+ mode: "0644"
+ owner: root
+ group: root
+ tags:
+ - apt
+
+- name: ELTS list is installed
+ ansible.builtin.template:
+ src: "{{ ansible_distribution_release }}_extended-lts.list.j2"
+ dest: /etc/apt/sources.list.d/extended-lts.list
+ force: true
+ mode: "0640"
+ register: apt_extended_lts
+ tags:
+ - apt
+
+- name: Apt update
+ ansible.builtin.apt:
+ update_cache: yes
+ tags:
+ - apt
+ when: apt_extended_lts is changed
diff --git a/apt/tasks/main.yml b/apt/tasks/main.yml
index 4d357f8b..bc65d7b9 100644
--- a/apt/tasks/main.yml
+++ b/apt/tasks/main.yml
@@ -80,6 +80,14 @@
- apt_install_evolix_public | bool
- ansible_distribution_major_version is version('12', '>=')
+- name: Install Extended-LTS repositories (Debian < 10)
+ ansible.builtin.import_tasks: extended-lts.oneline.yml
+ tags:
+ - apt
+ when:
+ - apt_install_extended_lts | bool
+ - ansible_distribution_major_version is version('10', '<')
+
- name: Clean GANDI sources
ansible.builtin.file:
path: '{{ item }}'
@@ -126,4 +134,4 @@
upgrade: dist
when: apt_upgrade | bool
tags:
- - apt
\ No newline at end of file
+ - apt
diff --git a/apt/tasks/migrate-to-deb822.yml b/apt/tasks/migrate-to-deb822.yml
index e7339e8b..e79ddf82 100644
--- a/apt/tasks/migrate-to-deb822.yml
+++ b/apt/tasks/migrate-to-deb822.yml
@@ -31,6 +31,11 @@
tags:
- apt
+- name: Is system.sources present?
+ ansible.builtin.stat:
+ path: /etc/apt/sources.list.d/system.sources
+ register: _system_sources
+
- name: Add signed-by when relevant for bookworm
ansible.builtin.lineinfile:
dest: /etc/apt/sources.list.d/system.sources
@@ -39,6 +44,12 @@
state: present
tags:
- apt
+ when: _system_sources.stat.exists or not ansible_check_mode
+
+- name: Is security.sources present?
+ ansible.builtin.stat:
+ path: /etc/apt/sources.list.d/security.sources
+ register: _security_sources
- name: Add signed-by when relevant for bookworm-security
ansible.builtin.lineinfile:
@@ -48,3 +59,4 @@
state: present
tags:
- apt
+ when: _security_sources.stat.exists or not ansible_check_mode
diff --git a/apt/templates/bookworm_basics.sources.j2 b/apt/templates/bookworm_basics.sources.j2
index 948c4adf..747e2e53 100644
--- a/apt/templates/bookworm_basics.sources.j2
+++ b/apt/templates/bookworm_basics.sources.j2
@@ -3,6 +3,6 @@
Types: deb
URIs: http://mirror.evolix.org/debian
Suites: bookworm bookworm-updates
-Components: {{ apt_basics_components | mandatory }}
+Components: {{ apt_basics_components | mandatory }}
Enabled: yes
Signed-By: /usr/share/keyrings/debian-archive-bookworm-automatic.gpg
diff --git a/apt/templates/bookworm_security.sources.j2 b/apt/templates/bookworm_security.sources.j2
index 07f1345b..b70fcec1 100644
--- a/apt/templates/bookworm_security.sources.j2
+++ b/apt/templates/bookworm_security.sources.j2
@@ -3,6 +3,6 @@
Types: deb
URIs: https://security.debian.org/debian-security
Suites: bookworm-security
-Components: {{ apt_basics_components | mandatory }}
+Components: {{ apt_basics_components | mandatory }}
Enabled: yes
-Signed-By: /usr/share/keyrings/debian-archive-bookworm-security-automatic.gpg
\ No newline at end of file
+Signed-By: /usr/share/keyrings/debian-archive-bookworm-security-automatic.gpg
diff --git a/apt/templates/bullseye_basics.list.j2 b/apt/templates/bullseye_basics.list.j2
index 55f32b8d..d1820d0f 100644
--- a/apt/templates/bullseye_basics.list.j2
+++ b/apt/templates/bullseye_basics.list.j2
@@ -1,5 +1,5 @@
# {{ ansible_managed }}
deb http://mirror.evolix.org/debian bullseye {{ apt_basics_components | mandatory }}
-deb http://mirror.evolix.org/debian/ bullseye-updates {{ apt_basics_components | mandatory }}
+deb http://mirror.evolix.org/debian bullseye-updates {{ apt_basics_components | mandatory }}
deb http://security.debian.org/debian-security bullseye-security {{ apt_basics_components | mandatory }}
diff --git a/apt/templates/buster_basics.list.j2 b/apt/templates/buster_basics.list.j2
index 58209ba0..b392ce58 100644
--- a/apt/templates/buster_basics.list.j2
+++ b/apt/templates/buster_basics.list.j2
@@ -1,5 +1,5 @@
# {{ ansible_managed }}
deb http://mirror.evolix.org/debian buster {{ apt_basics_components | mandatory }}
-deb http://mirror.evolix.org/debian/ buster-updates {{ apt_basics_components | mandatory }}
+deb http://mirror.evolix.org/debian buster-updates {{ apt_basics_components | mandatory }}
deb http://security.debian.org/debian-security buster/updates {{ apt_basics_components | mandatory }}
diff --git a/apt/templates/evolix_public.list.j2 b/apt/templates/evolix_public.list.j2
index e00899e7..7ed18708 100644
--- a/apt/templates/evolix_public.list.j2
+++ b/apt/templates/evolix_public.list.j2
@@ -1,3 +1,3 @@
# {{ ansible_managed }}
-deb [signed-by={{ apt_keyring_dir }}/pub_evolix.asc] http://pub.evolix.org/evolix {{ ansible_distribution_release }} main
+deb [signed-by={{ apt_keyring_dir }}/{{ apt_evolix_public_key }}] http://pub.evolix.org/evolix {{ ansible_distribution_release }} main
diff --git a/apt/templates/evolix_public.sources.j2 b/apt/templates/evolix_public.sources.j2
index defd1282..76bea737 100644
--- a/apt/templates/evolix_public.sources.j2
+++ b/apt/templates/evolix_public.sources.j2
@@ -1,6 +1,6 @@
# {{ ansible_managed }}
-Types:deb
+Types: deb
URIs: http://pub.evolix.org/evolix
Suites: {{ ansible_distribution_release }}
Components: main
diff --git a/apt/templates/jessie_basics.list.j2 b/apt/templates/jessie_basics.list.j2
index 467e7f30..7d72bfbd 100644
--- a/apt/templates/jessie_basics.list.j2
+++ b/apt/templates/jessie_basics.list.j2
@@ -1,4 +1,5 @@
# {{ ansible_managed }}
-deb http://mirror.evolix.org/debian/ jessie {{ apt_basics_components | mandatory }}
-deb http://security.debian.org/ jessie/updates {{ apt_basics_components | mandatory }}
+### Those repositories are unusable. Move to ELTS (manually).
+# deb http://archive.debian.org/debian jessie {{ apt_basics_components | mandatory }}
+# deb http://archive.debian.org/debian-security jessie/updates {{ apt_basics_components | mandatory }}
diff --git a/apt/templates/jessie_extended-lts.list.j2 b/apt/templates/jessie_extended-lts.list.j2
new file mode 100644
index 00000000..c20be4e7
--- /dev/null
+++ b/apt/templates/jessie_extended-lts.list.j2
@@ -0,0 +1,4 @@
+# {{ ansible_managed }}
+
+deb [signed-by="{{ apt_keyring_dir }}/freexian-archive-extended-lts.gpg"] http://elts.evolix.org/extended-lts jessie main
+deb [signed-by="{{ apt_keyring_dir }}/freexian-archive-extended-lts.gpg"] http://elts.evolix.org/extended-lts jessie-lts main
diff --git a/apt/templates/stretch_basics.list.j2 b/apt/templates/stretch_basics.list.j2
index 2f0bf99e..f679e354 100644
--- a/apt/templates/stretch_basics.list.j2
+++ b/apt/templates/stretch_basics.list.j2
@@ -1,5 +1,4 @@
# {{ ansible_managed }}
-deb http://mirror.evolix.org/debian stretch {{ apt_basics_components | mandatory }}
-deb http://mirror.evolix.org/debian/ stretch-updates {{ apt_basics_components | mandatory }}
-deb http://security.debian.org/debian-security stretch/updates {{ apt_basics_components | mandatory }}
+deb http://archive.debian.org/debian stretch {{ apt_basics_components | mandatory }}
+deb http://archive.debian.org/debian-security stretch/updates {{ apt_basics_components | mandatory }}
diff --git a/apt/templates/stretch_extended-lts.list.j2 b/apt/templates/stretch_extended-lts.list.j2
new file mode 100644
index 00000000..374e571e
--- /dev/null
+++ b/apt/templates/stretch_extended-lts.list.j2
@@ -0,0 +1,4 @@
+# {{ ansible_managed }}
+
+deb [signed-by="{{ apt_keyring_dir }}/freexian-archive-extended-lts.gpg"] http://elts.evolix.org/extended-lts stretch main
+deb [signed-by="{{ apt_keyring_dir }}/freexian-archive-extended-lts.gpg"] http://elts.evolix.org/extended-lts stretch-lts main
diff --git a/autosysadmin-agent/defaults/main.yml b/autosysadmin-agent/defaults/main.yml
new file mode 100644
index 00000000..b223a683
--- /dev/null
+++ b/autosysadmin-agent/defaults/main.yml
@@ -0,0 +1,17 @@
+---
+
+general_scripts_dir: "/usr/share/scripts"
+
+autosysadmin_agent_bin_dir: "/usr/local/bin/autosysadmin"
+autosysadmin_agent_lib_dir: "/usr/local/lib/autosysadmin"
+autosysadmin_agent_auto_dir: "{{ general_scripts_dir }}/autosysadmin/restart"
+
+autosysadmin_agent_crontab_enabled: true
+autosysadmin_agent_log_retention_days: 365
+
+autosysadmin_config: []
+ ### All repair are disabled if set to 'off'
+ ### even if a specific repair value is 'on'
+ # repair_all: 'on'
+ ### Default values for checks
+ # repair_foo: 'off'
diff --git a/autosysadmin-agent/files/autosysadmin.logrotate.conf b/autosysadmin-agent/files/autosysadmin.logrotate.conf
new file mode 100644
index 00000000..41606de5
--- /dev/null
+++ b/autosysadmin-agent/files/autosysadmin.logrotate.conf
@@ -0,0 +1,13 @@
+/var/log/autosysadmin.log {
+ daily
+ missingok
+ rotate 365
+ compress
+ nodelaycompress
+ notifempty
+ dateext
+ dateformat .%Y-%m-%d
+ dateyesterday
+ copytruncate
+ create 0640 root adm
+}
diff --git a/autosysadmin-agent/files/autosysadmin.rsyslog.conf b/autosysadmin-agent/files/autosysadmin.rsyslog.conf
new file mode 100644
index 00000000..dd3c037f
--- /dev/null
+++ b/autosysadmin-agent/files/autosysadmin.rsyslog.conf
@@ -0,0 +1,3 @@
+$template autosysadmin, "/var/log/autosysadmin.log"
+if $programname contains 'autosysadmin' then ?autosysadmin
+& stop
diff --git a/autosysadmin-agent/files/upstream/bin/delete_old_logs.sh b/autosysadmin-agent/files/upstream/bin/delete_old_logs.sh
new file mode 100644
index 00000000..a39d9efe
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/bin/delete_old_logs.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+days=${1:-365}
+log_dir="/var/log/autosysadmin/"
+
+if [ -d "${log_dir}" ]; then
+ find_run_dirs() {
+ find "${log_dir}" \
+ -mindepth 1 \
+ -maxdepth 1 \
+ -type d \
+ -ctime "+${days}" \
+ -print0
+ }
+ log() {
+ /usr/bin/logger -p local0.notice -t autosysadmin "${1}"
+ }
+
+ while IFS= read -r -d '' run_dir; do
+ rm --recursive --force "${run_dir}"
+ log "Delete ${run_dir} (older than ${days} days)"
+ done < <(find_run_dirs)
+fi
+
+exit 0
diff --git a/autosysadmin-agent/files/upstream/lib/common.sh b/autosysadmin-agent/files/upstream/lib/common.sh
new file mode 100755
index 00000000..9a7c7e23
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/lib/common.sh
@@ -0,0 +1,907 @@
+#!/bin/bash
+
+VERSION="24.03.1"
+
+# Common functions for "repair" and "restart" scripts
+
+set -u
+
+# Initializes the program, context, configuration…
+initialize() {
+ PATH="${PATH}":/usr/sbin:/sbin
+
+ # Used in many places to refer to the program name.
+ # Examples: repair_mysql, restart_nrpe…
+ PROGNAME=$(basename "${0}")
+
+ # find out if running in interactive mode, or not
+ if [ -t 0 ]; then
+ INTERACTIVE=1
+ else
+ INTERACTIVE=0
+ fi
+ readonly INTERACTIVE
+
+ # Default empty value for Debug mode
+ DEBUG="${DEBUG:-""}"
+
+ # Repair scripts obey to the value of a variable named after the script
+ # You can set the value ("on" or "off") in /etc/evolinux/autosysadmin
+ # Here we set the default value to "on".
+ declare -g "${PROGNAME}"=on # dynamic variable assignment ($PROGNAME == repair_*)
+
+ PID=$$
+ readonly PID
+
+ # Each execution (run) gets a unique ID
+ RUN_ID="$(date +"%Y-%m-%d_%H-%M")_${PROGNAME}_${PID}"
+ readonly RUN_ID
+
+ # Main log directory
+ MAIN_LOG_DIR="/var/log/autosysadmin"
+ readonly MAIN_LOG_DIR
+ # shellcheck disable=SC2174
+ mkdir --mode=750 --parents "${MAIN_LOG_DIR}"
+ chgrp adm "${MAIN_LOG_DIR}"
+
+ # Each execution store some information
+ # in a unique directory based on the RUN_ID
+ RUN_LOG_DIR="${MAIN_LOG_DIR}/${RUN_ID}"
+ readonly RUN_LOG_DIR
+ # shellcheck disable=SC2174
+ mkdir --mode=750 --parents "${RUN_LOG_DIR}"
+ chgrp adm "${RUN_LOG_DIR}"
+
+ # This log file contains all events
+ RUN_LOG_FILE="${RUN_LOG_DIR}/autosysadmin.log"
+ readonly RUN_LOG_FILE
+
+ # This log file contains notable actions
+ ACTIONS_FILE="${RUN_LOG_DIR}/actions.log"
+ readonly ACTIONS_FILE
+ touch "${ACTIONS_FILE}"
+ # This log file contains abort reasons (if any)
+ ABORT_FILE="${RUN_LOG_DIR}/abort.log"
+ readonly ABORT_FILE
+ # touch "${ABORT_FILE}"
+
+ # Date format for log messages
+ DATE_FORMAT="%Y-%m-%d %H:%M:%S"
+
+ # This will contain lock, last-run markers…
+ # It's ok to lose the content after a reboot
+ RUN_DIR="/run/autosysadmin"
+ readonly RUN_DIR
+ mkdir -p "${RUN_DIR}"
+
+ # Only a singe instace of each script can run simultaneously
+ # We use a customizable lock name for this.
+ # By default it's the script's name
+ LOCK_NAME=${LOCK_NAME:-${PROGNAME}}
+ # If a lock is found, we can wait for it to disappear.
+ # The value must be understood by sleep(1)
+ LOCK_WAIT="0"
+
+ # Default values for email headers
+ EMAIL_FROM="equipe+autosysadmin@evolix.net"
+ EMAIL_INTERNAL="autosysadmin@evolix.fr"
+
+ LOCK_FILE="${RUN_DIR}/${LOCK_NAME}.lock"
+ readonly LOCK_FILE
+ # Remove lock file at exit
+ cleanup() {
+ # shellcheck disable=SC2317
+ rm -f "${LOCK_FILE}"
+ }
+ trap 'cleanup' 0
+
+ # Load configuration
+ # shellcheck disable=SC1091
+ test -f /etc/evolinux/autosysadmin && source /etc/evolinux/autosysadmin
+
+ log_all "Begin ${PROGNAME} RUN_ID: ${RUN_ID}"
+ log_all "Log directory is ${RUN_LOG_DIR}"
+}
+
+# Executes a list of tasks before exiting:
+# * prepare a summary of actions and possible abort reasons
+# * send emails
+# * do some cleanup
+quit() {
+ log_all "End ${PROGNAME} RUN_ID: ${RUN_ID}"
+
+ summary="RUN_ID: ${RUN_ID}"
+ if [ -s "${ABORT_FILE}" ]; then
+ # Add abort reasons to summary
+ summary="${summary}\n$(print_abort_reasons)"
+ hook_mail "abort"
+
+ return_code=1
+ else
+ if [ -s "${ACTIONS_FILE}" ]; then
+ # Add notable actions to summary
+ summary="${summary}\n$(print_actions "Aucune action")"
+ hook_mail "success"
+ fi
+
+ return_code=0
+ fi
+
+ hook_mail "internal"
+
+ if is_interactive; then
+ # shellcheck disable=SC2001
+ echo "${summary}" | sed -e 's/\\n/\n/g'
+ else
+ /usr/share/scripts/evomaintenance.sh --auto --user autosysadmin --message "${summary}" --no-commit --no-mail
+ fi
+
+ teardown
+
+ # shellcheck disable=SC2086
+ exit ${return_code}
+}
+
+teardown() {
+ :
+}
+
+# Return true/false
+is_interactive() {
+ test "${INTERACTIVE}" -eq "1"
+}
+
+save_server_state() {
+ DUMP_SERVER_STATE_BIN="$(command -v dump-server-state || command -v backup-server-state)"
+
+ if [ -z "${DUMP_SERVER_STATE_BIN}" ]; then
+ log_all "Warning: dump-server-state is not present. No server state recorded."
+ fi
+
+ if [ -x "${DUMP_SERVER_STATE_BIN}" ]; then
+ DUMP_DIR=$(file_path_in_log_dir "server-state")
+ # We don't want the logging to take too much time,
+ # so we kill it if it takes more than 20 seconds.
+ timeout --signal 9 20 \
+ "${DUMP_SERVER_STATE_BIN}" \
+ --dump-dir="${DUMP_DIR}" \
+ --df \
+ --dmesg \
+ --iptables \
+ --lxc \
+ --netcfg \
+ --netstat \
+ --uname \
+ --processes \
+ --systemctl \
+ --uptime \
+ --virsh \
+ --disks \
+ --mysql-processes \
+ --no-apt-states \
+ --no-apt-config \
+ --no-dpkg-full \
+ --no-dpkg-status \
+ --no-mount \
+ --no-packages \
+ --no-sysctl \
+ --no-etc
+
+ log_run "Server state saved in \`server-state' directory."
+ fi
+}
+
+is_debug() {
+ # first time: do the check…
+ # other times: pass
+ if [ -z "${DEBUG:-""}" ]; then
+ debug_file="/etc/evolinux/autosysadmin.debug"
+
+ if [ -e "${debug_file}" ]; then
+ last_change=$(stat -c %Z "${debug_file}")
+ limit_date=$(date --date "14400 seconds ago" +"%s")
+
+ if [ $(( last_change - limit_date )) -le "0" ]; then
+ log_run "Debug mode disabled; file is too old (%{last_change} seconds)."
+ rm "${debug_file}"
+ # Debug mode disabled
+ DEBUG="0"
+ else
+ log_run "Debug mode enabled."
+ # Debug mode enabled
+ DEBUG="1"
+ fi
+ else
+ # log_run "Debug mode disabled; file is absent."
+ # Debug mode disabled
+ DEBUG="0"
+ fi
+ fi
+ # return the value
+ test "${DEBUG}" -eq "1"
+}
+
+# Uses the who(1) definition of "active"
+currently_active_users() {
+ LC_ALL=C who --users | grep --extended-regexp "\s+\.\s+" | awk '{print $1}' | sort --human-numeric-sort | uniq
+}
+# Users active in the last 29 minutes
+recently_active_users() {
+ LC_ALL=C who --users | grep --extended-regexp "\s+00:(0|1|2)[0-9]\s+" | awk --field-separator ' ' '{print $1,$6}'
+}
+# Save the list of users to a file in the log directory
+save_active_users() {
+ LC_ALL=C who --users | save_in_log_dir "who-users"
+}
+
+# An autosysadmin must not perform actions if a user is active or was active recently.
+#
+# This can by bypassed in interactive mode.
+# It's OK to lose this data after a reboot.
+ensure_no_active_users_or_exit() {
+ # Save all active users
+ save_active_users
+
+ if is_debug; then
+ log_run "Debug mode enabled: continue without checking active users."
+ return 0;
+ fi
+
+ # Is there any currently active user?
+ currently_active_users=$(currently_active_users)
+ if [ -n "${currently_active_users}" ]; then
+ # shellcheck disable=SC2001
+ users_oneliner=$(echo "${currently_active_users}" | sed -e 's/\n/ /')
+ log_run "Currently active users: ${users_oneliner}"
+ if is_interactive; then
+ echo "Some users are currently active:"
+ # shellcheck disable=SC2001
+ echo "${currently_active_users}" | sed -e 's/\(.\+\)/* \1/'
+ answer=""
+ while :; do
+ printf "> Continue? [Y,n,?] "
+ read -r answer
+ case ${answer} in
+ [Yy]|"" )
+ log_run "Active users check bypassed manually in interactive mode."
+ return
+ ;;
+ [Nn] )
+ log_run "Active users check confirmed manually in interactive mode."
+ log_abort_and_quit "Active users detected: ${users_oneliner}"
+ ;;
+ * )
+ printf "y - yes, continue\n"
+ printf "n - no, exit\n"
+ printf "? - print this help\n"
+ ;;
+ esac
+ done
+ else
+ log_abort_and_quit "Currently active users detected: ${users_oneliner}."
+ fi
+ else
+ # or recently (the last 30 minutes) active user?
+ recently_active_users=$(recently_active_users)
+ if [ -n "${recently_active_users}" ]; then
+ # shellcheck disable=SC2001
+ users_oneliner=$(echo "${recently_active_users}" | sed -e 's/\n/ /')
+ log_run "Recently active users: ${users_oneliner}"
+ if is_interactive; then
+ echo "Some users were recently active:"
+ # shellcheck disable=SC2001
+ echo "${recently_active_users}" | sed -e 's/\(.\+\)/* \1/'
+ answer=""
+ while :; do
+ printf "> Continue? [Y,n,?] "
+ read -r answer
+ case ${answer} in
+ [Yy]|"" )
+ log_run "Active users check bypassed manually in interactive mode."
+ return
+ ;;
+ [Nn] )
+ log_run "Active users check confirmed manually in interactive mode."
+ log_abort_and_quit "Recently active users detected: ${users_oneliner}."
+ ;;
+ * )
+ printf "y - yes, continue\n"
+ printf "n - no, exit\n"
+ printf "? - print this help\n"
+ ;;
+ esac
+ done
+ else
+ log_abort_and_quit "Recently active users detected: ${users_oneliner}."
+ fi
+ fi
+ fi
+}
+
+# Takes an NRPE command name as 1st parameter,
+# and executes the full command if found in the configuration.
+# Return the result and the return code of the command.
+check_nrpe() {
+ check="$1"
+
+ nrpe_files=""
+
+ # Check if NRPE config is found
+ if [ -f "/etc/nagios/nrpe.cfg" ]; then
+ nrpe_files="${nrpe_files} /etc/nagios/nrpe.cfg"
+ else
+ msg="NRPE configuration not found: /etc/nagios/nrpe.cfg"
+ log_run "${msg}"
+ echo "${msg}"
+ return 3
+ fi
+
+ # Search for included files
+ # shellcheck disable=SC2086
+ while IFS= read -r include_file; do
+ nrpe_files="${nrpe_files} ${include_file}"
+ done < <(grep --extended-regexp '^\s*include=.+' ${nrpe_files} | cut -d = -f 2)
+
+ # Search for files in included directories
+ # shellcheck disable=SC2086
+ while IFS= read -r include_dir; do
+ nrpe_files="${nrpe_files} ${include_dir}/*.cfg"
+ done < <(grep --extended-regexp '^\s*include_dir=.+' ${nrpe_files} | cut -d = -f 2)
+
+ # Fetch uncommented commands in (sorted) config files
+ # shellcheck disable=SC2086
+ nrpe_commands=$(grep --no-filename --exclude=*~ --fixed-strings "[${check}]" ${nrpe_files} | grep --invert-match --extended-regexp '^\s*#\s*command' | cut -d = -f 2)
+ nrpe_commands_count=$(echo "${nrpe_commands}" | wc -l)
+
+ if is_debian_version "9" "<=" && [ "${nrpe_commands_count}" -gt "1" ]; then
+ # On Debian <= 9, NRPE loading was not sorted
+ # we need to raise an error if we have multiple defined commands
+ msg="Unable to determine which NRPE command to run"
+ log_run "${msg}"
+ echo "${msg}"
+ return 3
+ else
+ # On Debian > 9, use the last command
+ nrpe_command=$(echo "${nrpe_commands}" | tail -n 1)
+
+ nrpe_result=$(${nrpe_command})
+ nrpe_rc=$?
+
+ log_run "NRPE command (exited with ${nrpe_rc}): ${nrpe_command}"
+ log_run "${nrpe_result}"
+
+ echo "${nrpe_result}"
+ return "${nrpe_rc}"
+ fi
+}
+
+# An autosysadmin script must not run twice (or more) simultaneously.
+# We use a customizable (with LOCK_NAME) lock file to keep track of this.
+# A wait time can be configured.
+#
+# This can by bypassed in interactive mode.
+# It's OK to lose this data after a reboot.
+acquire_lock_or_exit() {
+ lock_file="${1:-${LOCK_FILE}}"
+ lock_wait="${2:-${LOCK_WAIT}}"
+
+ # lock_wait must be compatible with sleep(1), otherwise fallback to 0
+ if ! echo "${lock_wait}" | grep -Eq '^[0-9]+[smhd]?$'; then
+ log_run "Lock wait: incorrect value '${lock_wait}', fallback to 0."
+ lock_wait=0
+ fi
+
+ if [ "${lock_wait}" != "0" ] && [ -f "${lock_file}" ]; then
+ log_run "Lock file present. Let's wait ${lock_wait} and check again."
+ sleep "${lock_wait}"
+ fi
+
+ if [ -f "${lock_file}" ]; then
+ log_abort_and_quit "Lock file still present."
+ else
+ log_run "Lock file absent. Let's put one."
+ touch "${lock_file}"
+ fi
+}
+
+# If a script has been run in the ast 30 minutes, running it again won't fix the issue.
+# We use a /run/ausosysadmin/${PROGNAME}_lastrun file to keep track of this.
+#
+# This can by bypassed in interactive mode.
+# This is bypassed in debug mode.
+# It's OK to lose this data after a reboot.
+ensure_not_too_soon_or_exit() {
+ if is_debug; then
+ log_run "Debug mode enabled: continue without checking when was the last run."
+ return 0;
+ fi
+
+ lastrun_file="${RUN_DIR}/${PROGNAME}_lastrun"
+ if [ -f "${lastrun_file}" ]; then
+ lastrun_age="$(($(date +%s)-$(stat -c "%Y" "${lastrun_file}")))"
+ log_run "Last run was ${lastrun_age} seconds ago."
+ if [ "${lastrun_age}" -lt 1800 ]; then
+ if is_interactive; then
+ echo "${PROGNAME} was run ${lastrun_age} seconds ago."
+ answer=""
+ while :; do
+ printf "> Continue? [Y,n,?] "
+ read -r answer
+ case ${answer} in
+ [Yy]|"" )
+ log_run "Last run check bypassed manually in interactive mode."
+ break
+ ;;
+ [Nn] )
+ log_run "Last run check confirmed manually in interactive mode."
+ log_abort_and_quit 'Last run too recent.'
+ ;;
+ * )
+ printf "y - yes, continue\n"
+ printf "n - no, exit\n"
+ printf "? - print this help\n"
+ ;;
+ esac
+ done
+ else
+ log_abort_and_quit "Last run too recent."
+ fi
+ fi
+ fi
+ touch "${lastrun_file}"
+}
+
+# Populate DEBIAN_VERSION and DEBIAN_RELEASE variables
+# based on gathered information about the operating system
+detect_os() {
+ DEBIAN_RELEASE="unknown"
+ DEBIAN_VERSION="unknown"
+ LSB_RELEASE_BIN="$(command -v lsb_release)"
+
+ if [ -e /etc/debian_version ]; then
+ DEBIAN_VERSION="$(cut -d "." -f 1 < /etc/debian_version)"
+ if [ -x "${LSB_RELEASE_BIN}" ]; then
+ DEBIAN_RELEASE="$("${LSB_RELEASE_BIN}" --codename --short)"
+ else
+ case "${DEBIAN_VERSION}" in
+ 7) DEBIAN_RELEASE="wheezy" ;;
+ 8) DEBIAN_RELEASE="jessie" ;;
+ 9) DEBIAN_RELEASE="stretch" ;;
+ 10) DEBIAN_RELEASE="buster" ;;
+ 11) DEBIAN_RELEASE="bullseye" ;;
+ 12) DEBIAN_RELEASE="bookworm" ;;
+ 13) DEBIAN_RELEASE="trixie" ;;
+ esac
+ fi
+ # log_run "Detected OS: Debian version=${DEBIAN_VERSION} release=${DEBIAN_RELEASE}"
+ # else
+ # log_run "Detected OS: unknown (missing /etc/debian_version)"
+ fi
+}
+
+is_debian_wheezy() {
+ test "${DEBIAN_RELEASE}" = "wheezy"
+}
+is_debian_jessie() {
+ test "${DEBIAN_RELEASE}" = "jessie"
+}
+is_debian_stretch() {
+ test "${DEBIAN_RELEASE}" = "stretch"
+}
+is_debian_buster() {
+ test "${DEBIAN_RELEASE}" = "buster"
+}
+is_debian_bullseye() {
+ test "${DEBIAN_RELEASE}" = "bullseye"
+}
+is_debian_bookworm() {
+ test "${DEBIAN_RELEASE}" = "bookworm"
+}
+is_debian_trixie() {
+ test "${DEBIAN_RELEASE}" = "trixie"
+}
+is_debian_version() {
+ local version=$1
+ local relation=${2:-"eq"}
+
+ if [ -z "${DEBIAN_VERSION:-""}" ]; then
+ detect_os
+ fi
+
+ dpkg --compare-versions "${DEBIAN_VERSION}" "${relation}" "${version}"
+}
+
+# List systemd services (only names), even if stopped
+systemd_list_services() {
+ pattern=$1
+
+ systemctl list-units --all --no-legend --type=service "${pattern}" | grep --only-matching --extended-regexp '\S+\.service'
+}
+
+is_systemd_enabled() {
+ systemctl --quiet is-enabled "$1" 2> /dev/null
+}
+
+is_systemd_active() {
+ systemctl --quiet is-active "$1" 2> /dev/null
+}
+
+is_sysvinit_enabled() {
+ find /etc/rc2.d/ -name "$1" > /dev/null
+}
+
+get_fqdn() {
+ # shellcheck disable=SC2155
+ local system=$(uname -s)
+
+ if [ "${system}" = "Linux" ]; then
+ hostname --fqdn
+ elif [ "${system}" = "OpenBSD" ]; then
+ hostname
+ else
+ log_abort_and_quit "System '${system}' not recognized."
+ fi
+}
+
+get_complete_hostname() {
+ REAL_HOSTNAME="$(get_fqdn)"
+ if [ "${HOSTNAME}" = "${REAL_HOSTNAME}" ]; then
+ echo "${HOSTNAME}"
+ else
+ echo "${HOSTNAME} (${REAL_HOSTNAME})"
+ fi
+}
+# Fetch values from evomaintenance configuration
+get_evomaintenance_mail() {
+ grep "EVOMAINTMAIL=" /etc/evomaintenance.cf | cut -d '=' -f2
+}
+get_evomaintenance_emergency_mail() {
+ grep "URGENCYFROM=" /etc/evomaintenance.cf | cut -d '=' -f2
+}
+get_evomaintenance_emergency_tel() {
+ grep "URGENCYTEL=" /etc/evomaintenance.cf | cut -d '=' -f2
+}
+
+# Log a message to the log file in the log directory
+log_run() {
+ local msg="${1:-$(cat /dev/stdin)}"
+ # shellcheck disable=SC2155
+ local date=$(/bin/date +"${DATE_FORMAT}")
+
+ printf "[%s] %s[%s]: %s\\n" \
+ "${date}" "${PROGNAME}" "${PID}" "${msg}" \
+ >> "${RUN_LOG_FILE}"
+}
+# Log a message in the system log file (syslog or journald)
+log_global() {
+ local msg="${1:-$(cat /dev/stdin)}"
+
+ echo "${msg}" \
+ | /usr/bin/logger -p local0.notice -t autosysadmin
+}
+# Log a message in both places
+log_all() {
+ local msg="${1:-$(cat /dev/stdin)}"
+
+ log_global "${msg}"
+ log_run "${msg}"
+}
+# Log a notable action in regular places
+# and append it to the dedicated list
+log_action() {
+ log_all "$*"
+ append_action "$*"
+}
+# Append a line in the actions.log file in the log directory
+append_action() {
+ echo "$*" >> "${ACTIONS_FILE}"
+}
+# Print the content of the actions.log file
+# or a fallback content (1st parameter) if empty
+# shellcheck disable=SC2120
+print_actions() {
+ local fallback=${1:-""}
+ if [ -s "${ACTIONS_FILE}" ]; then
+ cat "${ACTIONS_FILE}"
+ elif [ -n "${fallback}" ]; then
+ echo "${fallback}"
+ fi
+}
+
+# Log a an abort reason in regular places
+# and append it to the dedicated list
+log_abort() {
+ log_all "$*"
+ append_abort_reason "$*"
+}
+# Append a line in the abort.log file in the log directory
+append_abort_reason() {
+ echo "$*" >> "${ABORT_FILE}"
+}
+# Print the content of the abort.log file
+# or a fallback content (1st parameter) if empty
+# shellcheck disable=SC2120
+print_abort_reasons() {
+ local fallback=${1:-""}
+ if [ -s "${ABORT_FILE}" ]; then
+ cat "${ABORT_FILE}"
+ elif [ -n "${fallback}" ]; then
+ echo "${fallback}"
+ fi
+}
+# Print the content of the main log from the log directory
+print_main_log() {
+ cat "${RUN_LOG_FILE}"
+}
+# Log an abort reason and quit the script
+log_abort_and_quit() {
+ log_abort "$*"
+ quit
+}
+
+# Store the content from standard inpu
+# into a file in the log directory named after the 1st parameter
+save_in_log_dir() {
+ local file_name=$1
+ local file_path="${RUN_LOG_DIR}/${file_name}"
+
+ cat /dev/stdin > "${file_path}"
+
+ log_run "Saved \`${file_name}' file."
+}
+# Return the full path of the file in log directory
+# based on the name in the 1st parameter
+file_path_in_log_dir() {
+ echo "${RUN_LOG_DIR}/${1}"
+}
+
+format_mail_success() {
+ cat <
+Content-Type: text/plain; charset=UTF-8
+MIME-Version: 1.0
+Content-Transfer-Encoding: 8bit
+X-Script: ${PROGNAME}
+X-RunId: ${RUN_ID}
+To: ${EMAIL_CLIENT:-alert5@evolix.fr}
+Cc: ${EMAIL_INTERNAL}
+Subject: [autosysadmin] Intervention automatisée sur ${HOSTNAME_TEXT}
+
+Bonjour,
+
+Une intervention automatisée vient de se terminer.
+
+Nom du serveur : ${HOSTNAME_TEXT}
+Heure d'intervention : $(LC_ALL=fr_FR.utf8 date)
+Script déclenché : ${PROGNAME}
+
+### Actions réalisées
+
+$(print_actions "Aucune")
+
+### Réagir à cette intervention
+
+Vous pouvez répondre à ce message (${EMAIL_FROM}).
+
+En cas d'urgence, utilisez l'adresse ${EMERGENCY_MAIL}
+ou notre ligne d'astreinte (${EMERGENCY_TEL})
+
+--
+Votre AutoSysadmin
+EOTEMPLATE
+}
+
+format_mail_abort() {
+ cat <
+Content-Type: text/plain; charset=UTF-8
+MIME-Version: 1.0
+Content-Transfer-Encoding: 8bit
+X-Script: ${PROGNAME}
+X-RunId: ${RUN_ID}
+To: ${EMAIL_CLIENT:-alert5@evolix.fr}
+Cc: ${EMAIL_INTERNAL}
+Subject: [autosysadmin] Intervention automatisée interrompue sur ${HOSTNAME_TEXT}
+
+Bonjour,
+
+Une intervention automatisée a été déclenchée mais s'est interrompue.
+
+Nom du serveur : ${HOSTNAME_TEXT}
+Heure d'intervention : $(LC_ALL=fr_FR.utf8 date)
+Script déclenché : ${PROGNAME}
+
+### Actions réalisées
+
+$(print_actions "Aucune")
+
+### Raison(s) de l'interruption
+
+$(print_abort_reasons "Inconnue")
+
+### Réagir à cette intervention
+
+Vous pouvez répondre à ce message (${EMAIL_FROM}).
+
+En cas d'urgence, utilisez l'adresse ${EMERGENCY_MAIL}
+ou notre ligne d'astreinte (${EMERGENCY_TEL})
+
+--
+Votre AutoSysadmin
+EOTEMPLATE
+}
+
+# shellcheck disable=SC2028
+print_report_information() {
+ echo "**Uptime**"
+ echo ""
+ uptime
+
+ echo ""
+ echo "**Utilisateurs récents**"
+ echo ""
+ who_file=$(file_path_in_log_dir "who-users")
+ if [ -s "${who_file}" ]; then
+ cat "${who_file}"
+ else
+ who --users
+ fi
+
+ echo ""
+ echo "**Espace disque**"
+ echo ""
+ df_file=$(file_path_in_log_dir "server-state/df.txt")
+ if [ -s "${df_file}" ]; then
+ cat "${df_file}"
+ else
+ df -h
+ fi
+
+ echo ""
+ echo "**Dmesg**"
+ echo ""
+ dmesg_file=$(file_path_in_log_dir "server-state/dmesg.txt")
+ if [ -s "${dmesg_file}" ]; then
+ tail -n 5 "${dmesg_file}"
+ else
+ dmesg | tail -n 5
+ fi
+
+ echo ""
+ echo "**systemd failed services**"
+ echo ""
+ failed_services_file=$(file_path_in_log_dir "server-state/systemctl-failed-services.txt")
+ if [ -s "${failed_services_file}" ]; then
+ cat "${failed_services_file}"
+ else
+ systemctl --no-legend --state=failed --type=service
+ fi
+
+ if command -v lxc-ls > /dev/null 2>&1; then
+ echo ""
+ echo "**LXC containers**"
+ echo ""
+ lxc_ls_file=$(file_path_in_log_dir "server-state/lxc-list.txt")
+ if [ -s "${lxc_ls_file}" ]; then
+ cat "${lxc_ls_file}"
+ else
+ lxc-ls --fancy
+ fi
+ fi
+
+ apache_errors_file=$(file_path_in_log_dir "apache-errors.log")
+ if [ -f "${apache_errors_file}" ]; then
+ echo ""
+ echo "**Apache errors**"
+ echo ""
+ cat "${apache_errors_file}"
+ fi
+
+ nginx_errors_file=$(file_path_in_log_dir "nginx-errors.log")
+ if [ -f "${nginx_errors_file}" ]; then
+ echo ""
+ echo "**Nginx errors**"
+ echo ""
+ cat "${nginx_errors_file}"
+ fi
+}
+
+format_mail_internal() {
+ cat <
+Content-Type: text/plain; charset=UTF-8
+MIME-Version: 1.0
+Content-Transfer-Encoding: 8bit
+X-Script: ${PROGNAME}
+X-RunId: ${RUN_ID}
+To: ${EMAIL_INTERNAL}
+Subject: [autosysadmin] Rapport interne d'intervention sur ${HOSTNAME_TEXT}
+
+Bonjour,
+
+Une intervention automatique vient de se terminer.
+
+Nom du serveur : ${HOSTNAME_TEXT}
+Heure d'intervention : $(LC_ALL=fr_FR.utf8 date)
+Script déclenché : ${PROGNAME}
+
+### Actions réalisées
+
+$(print_actions "Aucune")
+
+### Raison(s) de l'interruption
+
+$(print_abort_reasons "Aucune")
+
+### Log autosysadmin
+
+$(print_main_log)
+
+### Informations additionnelles
+
+$(print_report_information)
+
+--
+Votre AutoSysadmin
+EOTEMPLATE
+}
+
+# Generic function to send emails at the end of the script.
+# Takes a template as 1st parameter
+hook_mail() {
+ if is_debug; then
+ log_run "Debug mode enabled: continue without sending mail."
+ return 0;
+ fi
+
+ HOSTNAME="${HOSTNAME:-"$(get_fqdn)"}"
+ HOSTNAME_TEXT="$(get_complete_hostname)"
+ EMAIL_CLIENT="$(get_evomaintenance_mail)"
+ EMERGENCY_MAIL="$(get_evomaintenance_emergency_mail)"
+ EMERGENCY_TEL="$(get_evomaintenance_emergency_tel)"
+
+ MAIL_CONTENT="$(format_mail_"$1")"
+
+ SENDMAIL_BIN="$(command -v sendmail)"
+
+ if [ -z "${SENDMAIL_BIN}" ]; then
+ log_global "ERROR: No \`sendmail' command has been found, can't send mail."
+ fi
+ if [ -x "${SENDMAIL_BIN}" ]; then
+ echo "${MAIL_CONTENT}" | "${SENDMAIL_BIN}" -oi -t -f "equipe@evolix.fr"
+ log_global "Sent '$1' mail for RUN_ID: ${RUN_ID}"
+ fi
+}
+
+is_holiday() {
+ # gcal mark today as a holiday by surrounding with < and > the day
+ # of the month of that holiday line. For example if today is 2022-05-01 we'll
+ # get among other lines:
+ # Fête du Travail (FR) + Di, < 1>Mai 2022
+ # Jour de la Victoire (FR) + Di, : 8:Mai 2022 = +7 jours
+ LANGUAGE=fr_FR.UTF-8 TZ=Europe/Paris gcal --cc-holidays=fr --holiday-list=short | grep -E '<[0-9 ]{2}>' --quiet
+}
+
+is_weekend() {
+ day_of_week=$(date +%u)
+ if [ "${day_of_week}" != 6 ] && [ "${day_of_week}" != 7 ]; then
+ return 1
+ fi
+}
+
+is_workday() {
+ if is_holiday || is_weekend; then
+ return 1
+ fi
+}
+
+is_worktime() {
+ if ! is_workday; then
+ return 1
+ fi
+
+ hour=$(date +%H)
+ if [ "${hour}" -lt 9 ] || { [ "${hour}" -ge 12 ] && [ "${hour}" -lt 14 ] ; } || [ "${hour}" -ge 18 ]; then
+ return 1
+ fi
+}
diff --git a/autosysadmin-agent/files/upstream/lib/repair.sh b/autosysadmin-agent/files/upstream/lib/repair.sh
new file mode 100644
index 00000000..ddd243b5
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/lib/repair.sh
@@ -0,0 +1,112 @@
+#!/bin/bash
+
+# Specific functions for "repair" scripts
+
+is_all_repair_disabled() {
+ # Fetch values from the config
+ # and if it is not defined or has no value, then assign "on"
+
+ local status=${repair_all:=on}
+
+
+ test "${status}" = "off" || test "${status}" = "0"
+}
+
+is_current_repair_disabled() {
+ # Fetch values from the config
+ # and if it is not defined or has no value, then assign "on"
+
+ local status=${!PROGNAME:=on}
+
+ test "${status}" = "off" || test "${status}" = "0"
+}
+
+ensure_not_disabled_or_exit() {
+ if is_all_repair_disabled; then
+ log_global 'All repair scripts are disabled.'
+ exit 0
+ fi
+ if is_current_repair_disabled; then
+ log_global "Current repair script (${PROGNAME}) is disabled."
+ exit 0
+ fi
+}
+
+# Set of actions to do at the begining of a "repair" script
+pre_repair() {
+ initialize
+
+ # Are we supposed to run?
+ ensure_not_disabled_or_exit
+
+ # Has it recently been run?
+ ensure_not_too_soon_or_exit
+
+ # Can we acquire a lock?
+ acquire_lock_or_exit
+
+ # Is there any active user?
+ ensure_no_active_users_or_exit
+
+ # Save important information
+ save_server_state
+}
+
+# Set of actions to do at the end of a "repair" script
+post_repair() {
+ quit
+}
+
+repair_lxc_php() {
+ container_name=$1
+
+ if is_systemd_enabled 'lxc.service'; then
+ lxc_path=$(lxc-config lxc.lxcpath)
+ if lxc-info --name "${container_name}" > /dev/null; then
+ rootfs="${lxc_path}/${container_name}/rootfs"
+ case "${container_name}" in
+ php56) fpm_log_file="${rootfs}/var/log/php5-fpm.log" ;;
+ php70) fpm_log_file="${rootfs}/var/log/php7.0-fpm.log" ;;
+ php73) fpm_log_file="${rootfs}/var/log/php7.3-fpm.log" ;;
+ php74) fpm_log_file="${rootfs}/var/log/php7.4-fpm.log" ;;
+ php80) fpm_log_file="${rootfs}/var/log/php8.0-fpm.log" ;;
+ php81) fpm_log_file="${rootfs}/var/log/php8.1-fpm.log" ;;
+ php82) fpm_log_file="${rootfs}/var/log/php8.2-fpm.log" ;;
+ php83) fpm_log_file="${rootfs}/var/log/php8.3-fpm.log" ;;
+ *)
+ log_abort_and_quit "Unknown container '${container_name}'"
+ ;;
+ esac
+
+ # Determine FPM Pool path
+ php_path_pool=$(find "${lxc_path}/${container_name}/" -type d -name "pool.d")
+
+ # Save LXC info (before restart)
+ lxc-info --name "${container_name}" | save_in_log_dir "lxc-${container_name}.before.status"
+ # Save last lines of FPM log (before restart)
+ tail "${fpm_log_file}" | save_in_log_dir "$(basename "${fpm_log_file}" | sed -e 's/.log/.before.log/')"
+ # Save NRPE check (before restart)
+ /usr/local/lib/nagios/plugins/check_phpfpm_multi "${php_path_pool}" | save_in_log_dir "check_fpm_${container_name}.before.out"
+
+ lxc-stop --timeout 20 --name "${container_name}"
+ lxc-start --daemon --name "${container_name}"
+ rc=$?
+ if [ "${rc}" -eq "0" ]; then
+ log_all "Restart LXC container '${container_name}: OK"
+ else
+ log_all "Restart LXC container '${container_name}: failed"
+ fi
+
+ # Save LXC info (after restart)
+ lxc-info --name "${container_name}" | save_in_log_dir "lxc-${container_name}.after.status"
+ # Save last lines of FPM log (after restart)
+ tail "${fpm_log_file}" | save_in_log_dir "$(basename "${fpm_log_file}" | sed -e 's/.log/.after.log/')"
+ # Save NRPE check (after restart)
+ /usr/local/lib/nagios/plugins/check_phpfpm_multi "${php_path_pool}" | save_in_log_dir "check_fpm_${container_name}.after.out"
+ else
+ log_abort_and_quit "LXC container '${container_name}' doesn't exist."
+ fi
+ else
+ log_abort_and_quit 'LXC not found.'
+ fi
+}
diff --git a/autosysadmin-agent/files/upstream/lib/restart.sh b/autosysadmin-agent/files/upstream/lib/restart.sh
new file mode 100644
index 00000000..78be5bb0
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/lib/restart.sh
@@ -0,0 +1,76 @@
+#!/bin/bash
+
+# Specific functions for "restart" scripts
+
+running_custom() {
+ # Placeholder that returns 1, to prevent running if not redefined
+ log_global "running_custom() function has not been redefined! Let's quit."
+ return 1
+}
+
+# Examine RUNNING variable and decide if the script should run or not
+is_supposed_to_run() {
+ if is_debug; then return 0; fi
+
+ case ${RUNNING} in
+ never)
+ # log_global "is_supposed_to_run: no (never)"
+ return 1
+ ;;
+ always)
+ # log_global "is_supposed_to_run: yes (always)"
+ return 0
+ ;;
+ nwh-fr)
+ ! is_worktime
+ rc=$?
+ # if [ ${rc} -eq 0 ]; then
+ # log_global "is_supposed_to_run: yes (nwh-fr returned ${rc})"
+ # else
+ # log_global "is_supposed_to_run: no (nwh-fr returned ${rc})"
+ # fi
+ return ${rc}
+ ;;
+ nwh-ca)
+ # Not implemented yet
+ return 0
+ ;;
+ custom)
+ running_custom
+ rc=$?
+ # if [ ${rc} -eq 0 ]; then
+ # log_global "is_supposed_to_run: yes (custom returned ${rc})"
+ # else
+ # log_global "is_supposed_to_run: no (custom returned ${rc})"
+ # fi
+ return ${rc}
+ ;;
+ esac
+}
+
+ensure_supposed_to_run_or_exit() {
+ if ! is_supposed_to_run; then
+ # simply quit (no logging, no notifications…)
+ # log_global "${PROGNAME} is not supposed to run (RUNNING=${RUNNING})."
+ exit 0
+ fi
+}
+
+# Set of actions to do at the begining of a "restart" script
+pre_restart() {
+ initialize
+
+ # Has it recently been run?
+ ensure_not_too_soon_or_exit
+
+ # Can we acquire a lock?
+ acquire_lock_or_exit
+
+ # Save important information
+ save_server_state
+}
+
+# Set of actions to do at the end of a "restart" script
+post_restart() {
+ quit
+}
diff --git a/autosysadmin-agent/files/upstream/repair/repair_disk b/autosysadmin-agent/files/upstream/repair/repair_disk
new file mode 100755
index 00000000..70ed28a6
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/repair/repair_disk
@@ -0,0 +1,157 @@
+#!/bin/bash
+
+: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
+source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
+source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
+
+pre_repair
+
+
+# We always keep some reserved blocks to avoid missing some logs
+# https://gitea.evolix.org/evolix/autosysadmin/issues/22
+RESERVED_BLOCKS_MIN=1
+
+get_mountpoints() {
+ # the $(...) get the check_disk1 command
+ # the cut command selects the critical part of the check_disk1 output
+ # the grep command extracts the mountpoints and available disk space
+ # the last cut command selects the mountpoints
+ check_disk1_command=$(grep check_disk1 /etc/nagios/nrpe.d/evolix.cfg | cut -d'=' -f2-)
+
+ ${check_disk1_command} -e | cut -d'|' -f1 | grep --extended-regexp --only-matching '/[[:graph:]]* [0-9]+ [A-Z][A-Z]' | cut -d' ' -f1
+}
+
+is_reserved_blocks_nominal() {
+ partition=${1}
+
+ fs_type="$(findmnt -n --output=fstype "${partition}")"
+ if [ "${fs_type}" = "ext4" ]; then
+ device="$(findmnt -n --output=source "${partition}")"
+ reserved_block_count="$(tune2fs -l "${device}" | grep 'Reserved block count' | awk -F':' '{ gsub (" ", "", $0); print $2}')"
+ block_count="$(tune2fs -l "${device}" | grep 'Block count' | awk -F':' '{ gsub (" ", "", $0); print $2}')"
+ percentage=$(awk "BEGIN { pc=100*${reserved_block_count}/${block_count}; i=int(pc); print (pc-i<0.5)?i:i+1 }")
+
+ log_run "Reserved blocks for ${partition} is currently at ${percentage}%"
+ if [ "${percentage}" -gt "${RESERVED_BLOCKS_MIN}" ]; then
+ log_run "Allowing tune2fs action to reduce the number of reserved blocks"
+ return 0
+ else
+ log_run "Reserved blocks already at or bellow ${RESERVED_BLOCKS_MIN}%, no automatic action possible"
+ return 1
+ fi
+ else
+ log_run "Filesystem for ${partition} (${fs_type}) is incompatible with reserved block reduction."
+ return 1
+ fi
+}
+
+reduce_reserved_blocks() {
+ partition=${1}
+
+ device=$(findmnt -n --output=source "${partition}")
+ tune2fs -m "${RESERVED_BLOCKS_MIN}" "${device}"
+ log_action "Reserved blocks for ${partition} changed to ${RESERVED_BLOCKS_MIN} percent"
+}
+
+is_tmp_to_delete() {
+ size="$(find /var/log/ -type f -ctime +1 -exec du {} \+ | awk '{s+=$1}END{print s / 1024}')"
+ if [ -n "${size}" ]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+is_log_to_delete() {
+ size="$(find /var/log/ -type f -mtime +365 -exec du {} \+ | awk '{s+=$1}END{print s / 1024}')"
+ if [ -n "${size}" ]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+clean_apt_cache() {
+ for container in $(lxc-ls -1); do
+ if [ -e "$(lxc-config lxc.lxcpath)/${container}/rootfs/var/cache" ]; then
+ lxc-attach --name "${container}" -- apt-get clean
+ log_action "Clean apt cache in LXC container ${container}";
+ fi
+ done
+
+ # NOTE: "head -n 1" might be superfluous, but let's be sure to have only the first returned value
+ biggest_subdir=$(du --summarize --one-file-system "/var/*" | sort --numeric-sort --reverse | sed 's/^[0-9]\+[[:space:]]\+//;q' | head -n 1)
+ case "${biggest_subdir}" in
+ '/var/cache')
+ apt-get clean
+ log_action 'Clean apt cache'
+ ;;
+ esac
+}
+
+clean_amavis_virusmails() {
+ if du --inodes /var/lib/* | sort --numeric-sort | tail -n 3 | grep --quiet 'virusmails$'; then
+ find /var/lib/amavis/virusmails/ -type f -atime +30 -delete
+ log_action 'Clean amavis infected mails'
+ fi
+}
+
+critical_mountpoints=$(get_mountpoints)
+
+if [ -z "${critical_mountpoints}" ]; then
+ log_abort_and_quit "No partition is in critical state, nothing left to do."
+else
+ for mountpoint in ${critical_mountpoints}; do
+ case "${mountpoint}" in
+ /var)
+ #if is_log_to_delete
+ #then
+ # find /var/log/ -type f -mtime +365 -delete
+ # log_action "$size Mo of disk space freed in /var"
+ #fi
+ if is_reserved_blocks_nominal /var; then
+ reduce_reserved_blocks /var
+ clean_apt_cache
+ clean_amavis_virusmails
+ fi
+ ;;
+ /tmp)
+ #if is_tmp_to_delete
+ #then
+ # find /tmp/ -type f -ctime +1 -delete
+ # log_action "$size Mo of disk space freed in /tmp"
+ #fi
+ if is_reserved_blocks_nominal /tmp; then
+ reduce_reserved_blocks /tmp
+ fi
+ ;;
+ /home)
+ if is_reserved_blocks_nominal /home; then
+ reduce_reserved_blocks /home
+ fi
+ ;;
+ /srv)
+ if is_reserved_blocks_nominal /srv; then
+ reduce_reserved_blocks /srv
+ fi
+ ;;
+ /filer)
+ if is_reserved_blocks_nominal /filer; then
+ reduce_reserved_blocks /filer
+ fi
+ ;;
+ /)
+ if is_reserved_blocks_nominal /; then
+ reduce_reserved_blocks /
+ # Suggest remove old kernel ?
+ fi
+ ;;
+ *)
+ # unknown
+ log_run 'Unknown partition (or weird case) or nothing to do'
+ ;;
+ esac
+ done
+fi
+
+post_repair
diff --git a/autosysadmin-agent/files/upstream/repair/repair_elasticsearch b/autosysadmin-agent/files/upstream/repair/repair_elasticsearch
new file mode 100755
index 00000000..5baffaaa
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/repair/repair_elasticsearch
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
+source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
+source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
+
+pre_repair
+
+service="elasticsearch.service"
+service_name="elasticsearch"
+
+if is_systemd_enabled "${service}"; then
+ if is_systemd_active "${service}"; then
+ log_abort_and_quit "${service} is active, nothing left to do."
+ else
+ # Save service status before restart
+ systemctl status "${service}" | save_in_log_dir "${service_name}.before.status"
+
+ # Try to restart
+ timeout 20 systemctl restart "${service}" > /dev/null
+ rc=$?
+ if [ "${rc}" -eq "0" ]; then
+ log_action "Restart ${service_name}: OK"
+ else
+ log_action "Restart ${service_name}: failed"
+ fi
+
+ # Save service status after restart
+ systemctl status "${service}" | save_in_log_dir "${service_name}.after.status"
+ fi
+else
+ log_abort_and_quit "${service} is disabled (or missing), nothing left to do."
+fi
+
+post_repair
diff --git a/autosysadmin-agent/files/upstream/repair/repair_http b/autosysadmin-agent/files/upstream/repair/repair_http
new file mode 100755
index 00000000..1c6fa5c7
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/repair/repair_http
@@ -0,0 +1,131 @@
+#!/bin/bash
+
+: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
+source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
+source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
+
+pre_repair
+
+## Apache
+
+service="apache2.service"
+service_name="apache2"
+
+if is_systemd_enabled "${service}"; then
+ if is_systemd_active "${service}"; then
+ log_all "${service} is active. Skip."
+ else
+ # Save service status before restart
+ systemctl status "${service}" | save_in_log_dir "${service_name}.before.status"
+
+ # check syntax
+ if apache2ctl -t > /dev/null 2>&1; then
+ # Try to restart
+ timeout 20 systemctl restart "${service}" > /dev/null
+ rc=$?
+ if [ "${rc}" -eq "0" ]; then
+ log_action "Restart ${service_name}: OK"
+ else
+ log_action "Restart ${service_name}: failed"
+ fi
+
+ # Save service status after restart
+ systemctl status "${service}" | save_in_log_dir "${service_name}.after.status"
+
+ # Save error logs
+ date=$(LANG=en_US.UTF-8 date '+%b %d')
+ grep "${date}" /home/*/log/error.log /var/log/apache2/*error.log \
+ | grep -v \
+ -e "Got error 'PHP message:" \
+ -e "No matching DirectoryIndex" \
+ -e "client denied by server configuration" \
+ -e "server certificate does NOT include an ID which matches the server name" \
+ | save_in_log_dir "apache-errors.log"
+ else
+ log_action "Restart ${service_name}: skip (invalid configuration)"
+ fi
+ fi
+else
+ log_all "${service} is disabled (or missing). Skip."
+fi
+
+## Nginx
+
+service="nginx.service"
+service_name="nginx"
+
+if is_systemd_enabled "${service}"; then
+ if is_systemd_active "${service}"; then
+ log_all "${service} is active. Skip."
+ else
+ # Save service status before restart
+ systemctl status "${service}" | save_in_log_dir "${service_name}.before.status"
+
+ # check syntax
+ if nginx -t > /dev/null 2>&1; then
+ # Try to restart
+ timeout 20 systemctl restart "${service}" > /dev/null
+ rc=$?
+ if [ "${rc}" -eq "0" ]; then
+ log_action "Restart ${service_name}: OK"
+ else
+ log_action "Restart ${service_name}: failed"
+ fi
+
+ # Save service status after restart
+ systemctl status "${service}" | save_in_log_dir "${service_name}.after.status"
+
+ # Save error logs
+ ### Consider doing for Nginx the same as Apache
+ else
+ log_action "Restart ${service_name}: skip (invalid configuration)"
+ fi
+ fi
+else
+ log_all "${service} is disabled (or missing). Skip."
+fi
+
+## LXC
+
+if is_systemd_enabled 'lxc.service'; then
+ for container in $(lxc-ls -1 | grep --fixed-strings 'php' | grep --extended-regexp --invert-match --regexp '\bold\b' --regexp '\bdisabled\b'); do
+ repair_lxc_php "${container}"
+ done
+else
+ log_all "LXC is disabled (or missing). Skip."
+fi
+
+## FPM
+
+fpm_services=$(systemd_list_services 'php*-fpm*')
+if [ -n "${fpm_services}" ]; then
+ for service in ${fpm_services}; do
+ service_name="${service//.service/}"
+ if is_systemd_enabled "${service}"; then
+ if is_systemd_active "${service}"; then
+ log_all "${service} is active. Skip."
+ else
+ # Save service status before restart
+ systemctl status "${service}" | save_in_log_dir "${service_name}.before.status"
+
+ # Try to restart
+ timeout 20 systemctl restart "${service}" > /dev/null
+ rc=$?
+ if [ "${rc}" -eq "0" ]; then
+ log_action "Restart ${service_name}: OK"
+ else
+ log_action "Restart ${service_name}: failed"
+ fi
+
+ # Save service status after restart
+ systemctl status "${service}" | save_in_log_dir "${service_name}.after.status"
+ fi
+ else
+ log_all "${service} is disabled (or missing). Skip."
+ fi
+ done
+else
+ log_all "PHP FPM not found. Skip."
+fi
+
+post_repair
diff --git a/autosysadmin-agent/files/upstream/repair/repair_mysql b/autosysadmin-agent/files/upstream/repair/repair_mysql
new file mode 100755
index 00000000..eb176743
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/repair/repair_mysql
@@ -0,0 +1,69 @@
+#!/bin/bash
+
+: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
+source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
+source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
+
+pre_repair
+
+if is_debian_version "8" "<="; then
+
+ if is_sysvinit_enabled '*mysql*'; then
+ if ! pgrep -u mysql mysqld > /dev/null; then
+
+ # Save service status before restart
+ timeout 2 mysqladmin status 2>&1 | save_in_log_dir "mysql.before.status"
+
+ timeout 20 /etc/init.d/mysql restart > /dev/null
+ rc=$?
+ if [ "${rc}" -eq "0" ]; then
+ log_action "Restart mysql: OK"
+ else
+ log_action "Restart mysql: failed"
+ fi
+
+ # Save service status after restart
+ timeout 2 mysqladmin status 2>&1 | save_in_log_dir "mysql.after.status"
+ else
+ log_abort_and_quit "mysqld process alive. Aborting"
+ fi
+ else
+ log_abort_and_quit "MySQL not enabled. Aborting"
+ fi
+
+else
+
+ if is_debian_version "12" ">="; then
+ service="mariadb.service"
+ service_name="mariadb"
+ else
+ service="mysql.service"
+ service_name="mysql"
+ fi
+
+ if is_systemd_enabled "${service}"; then
+ if is_systemd_active "${service}"; then
+ log_abort_and_quit "${service} is active, nothing left to do."
+ else
+ # Save service status before restart
+ systemctl status "${service}" | save_in_log_dir "${service_name}.before.status"
+
+ # Try to restart
+ timeout 20 systemctl restart "${service}" > /dev/null
+ rc=$?
+ if [ "${rc}" -eq "0" ]; then
+ log_action "Restart ${service_name}: OK"
+ else
+ log_action "Restart ${service_name}: failed"
+ fi
+
+ # Save service status after restart
+ systemctl status "${service}" | save_in_log_dir "${service_name}.after.status"
+ fi
+ else
+ log_abort_and_quit "${service} is disabled (or missing), nothing left to do."
+ fi
+
+fi
+
+post_repair
diff --git a/autosysadmin-agent/files/upstream/repair/repair_opendkim b/autosysadmin-agent/files/upstream/repair/repair_opendkim
new file mode 100755
index 00000000..ab06d01d
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/repair/repair_opendkim
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
+source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
+source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
+
+pre_repair
+
+service="opendkim.service"
+service_name="opendkim"
+
+if is_systemd_enabled "${service}"; then
+ if is_systemd_active "${service}"; then
+ log_abort_and_quit "${service} is active, nothing left to do."
+ else
+ # Save service status before restart
+ systemctl status "${service}" | save_in_log_dir "${service_name}.before.status"
+
+ # Try to restart
+ timeout 20 systemctl restart "${service}" > /dev/null
+ rc=$?
+ if [ "${rc}" -eq "0" ]; then
+ log_action "Restart ${service_name}: OK"
+ else
+ log_action "Restart ${service_name}: failed"
+ fi
+
+ # Save service status after restart
+ systemctl status "${service}" | save_in_log_dir "${service_name}.after.status"
+ fi
+else
+ log_abort_and_quit "${service} is disabled (or missing). Abort."
+fi
+
+post_repair
diff --git a/autosysadmin-agent/files/upstream/repair/repair_php_fpm56 b/autosysadmin-agent/files/upstream/repair/repair_php_fpm56
new file mode 100755
index 00000000..db2ed9d4
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/repair/repair_php_fpm56
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
+source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
+source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
+
+LOCK_WAIT="15s"
+LOCK_NAME="repair_http"
+
+pre_repair
+
+repair_lxc_php php56
+
+post_repair
diff --git a/autosysadmin-agent/files/upstream/repair/repair_php_fpm70 b/autosysadmin-agent/files/upstream/repair/repair_php_fpm70
new file mode 100755
index 00000000..324acadb
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/repair/repair_php_fpm70
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
+source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
+source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
+
+LOCK_WAIT="15s"
+LOCK_NAME="repair_http"
+
+pre_repair
+
+repair_lxc_php php70
+
+post_repair
diff --git a/autosysadmin-agent/files/upstream/repair/repair_php_fpm73 b/autosysadmin-agent/files/upstream/repair/repair_php_fpm73
new file mode 100755
index 00000000..9089aa6e
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/repair/repair_php_fpm73
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
+source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
+source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
+
+LOCK_WAIT="15s"
+LOCK_NAME="repair_http"
+
+pre_repair
+
+repair_lxc_php php73
+
+post_repair
diff --git a/autosysadmin-agent/files/upstream/repair/repair_php_fpm74 b/autosysadmin-agent/files/upstream/repair/repair_php_fpm74
new file mode 100755
index 00000000..6d7f49bb
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/repair/repair_php_fpm74
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
+source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
+source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
+
+LOCK_WAIT="15s"
+LOCK_NAME="repair_http"
+
+pre_repair
+
+repair_lxc_php php74
+
+post_repair
diff --git a/autosysadmin-agent/files/upstream/repair/repair_php_fpm80 b/autosysadmin-agent/files/upstream/repair/repair_php_fpm80
new file mode 100755
index 00000000..f61f45e6
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/repair/repair_php_fpm80
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
+source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
+source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
+
+LOCK_WAIT="15s"
+LOCK_NAME="repair_http"
+
+pre_repair
+
+repair_lxc_php php80
+
+post_repair
diff --git a/autosysadmin-agent/files/upstream/repair/repair_php_fpm81 b/autosysadmin-agent/files/upstream/repair/repair_php_fpm81
new file mode 100755
index 00000000..ec9b20c0
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/repair/repair_php_fpm81
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
+source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
+source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
+
+LOCK_WAIT="15s"
+LOCK_NAME="repair_http"
+
+pre_repair
+
+repair_lxc_php php81
+
+post_repair
diff --git a/autosysadmin-agent/files/upstream/repair/repair_php_fpm82 b/autosysadmin-agent/files/upstream/repair/repair_php_fpm82
new file mode 100755
index 00000000..8af2217e
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/repair/repair_php_fpm82
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
+source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
+source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
+
+LOCK_WAIT="15s"
+LOCK_NAME="repair_http"
+
+pre_repair
+
+repair_lxc_php php82
+
+post_repair
diff --git a/autosysadmin-agent/files/upstream/repair/repair_php_fpm83 b/autosysadmin-agent/files/upstream/repair/repair_php_fpm83
new file mode 100755
index 00000000..7584e69c
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/repair/repair_php_fpm83
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
+source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
+source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
+
+LOCK_WAIT="15s"
+LOCK_NAME="repair_http"
+
+pre_repair
+
+repair_lxc_php php83
+
+post_repair
diff --git a/autosysadmin-agent/files/upstream/repair/repair_redis b/autosysadmin-agent/files/upstream/repair/repair_redis
new file mode 100755
index 00000000..3873d16f
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/repair/repair_redis
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
+source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
+source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
+
+pre_repair
+
+for service in $(systemd_list_services 'redis-server*'); do
+ service_name="${service//.service/}"
+
+ if is_systemd_active "${service}"; then
+ log_all "${service} is active. Skip."
+ else
+ # Save service status before restart
+ systemctl status "${service}" | save_in_log_dir "${service_name}.before.status"
+
+ # Try to restart
+ timeout 20 systemctl restart "${service}" > /dev/null
+ rc=$?
+ if [ "${rc}" -eq "0" ]; then
+ log_action "Restart ${service_name}: OK."
+ else
+ log_action "Restart ${service_name}: failed."
+ fi
+
+ # Save service status after restart
+ systemctl status "${service}" | save_in_log_dir "${service_name}.after.status"
+ fi
+done
+
+post_repair
diff --git a/autosysadmin-agent/files/upstream/repair/repair_tomcat_instance b/autosysadmin-agent/files/upstream/repair/repair_tomcat_instance
new file mode 100755
index 00000000..8cc76ae4
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/repair/repair_tomcat_instance
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
+source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
+source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
+
+pre_repair
+
+repair_tomcat_instance_handle_tomcat() {
+
+ if /bin/su - "${1}" -c "/bin/systemctl --quiet --user is-active tomcat.service" ; then
+ if ! /bin/su - "${1}" -c "/usr/bin/timeout 20 /bin/systemctl --quiet --user restart tomcat.service"
+ then
+ log_abort_and_quit "Echec de redémarrage instance tomcat utilisateur ${1}"
+ else
+ log_action "Redémarrage instance tomcat utilisateur ${1}"
+ fi
+ elif /bin/systemctl --quiet is-active "${1}".service ; then
+ if ! /usr/bin/timeout 20 systemctl --quiet restart "${1}".service
+ then
+ log_abort_and_quit "Echec de redémarrage instance tomcat ${1}"
+ else
+ log_action "Redémarrage instance tomcat ${1}"
+ fi
+ fi
+
+}
+
+for instance in $( /usr/local/lib/nagios/plugins/check_tomcat_instance.sh |grep CRITICAL |awk '{print $3}' |sed '1d') ;
+do
+ repair_tomcat_instance_handle_tomcat "${instance}"
+done
+
+post_repair
diff --git a/autosysadmin-agent/files/upstream/repair/zzz-repair_example.template b/autosysadmin-agent/files/upstream/repair/zzz-repair_example.template
new file mode 100755
index 00000000..668d4d02
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/repair/zzz-repair_example.template
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
+source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
+source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
+
+## Custom lock wait and/or lock name
+# LOCK_WAIT="15s"
+# LOCK_NAME="repair_http"
+
+pre_repair
+
+## The name of the service, mainly for logging
+service_name="example"
+## The systemd service name
+systemd_service="${service_name}.service"
+
+if is_systemd_enabled "${systemd_service}"; then
+ if is_systemd_active "${systemd_service}"; then
+ log_abort_and_quit "${systemd_service} is active, nothing left to do."
+ else
+ # Save service status before restart
+ systemctl status "${systemd_service}" | save_in_log_dir "${service_name}.before.status"
+
+ # Try to restart
+ timeout 20 systemctl restart "${systemd_service}" > /dev/null
+ rc=$?
+ if [ "${rc}" -eq "0" ]; then
+ log_action "Restart ${service_name}: OK"
+ else
+ log_action "Restart ${service_name}: failed"
+ fi
+
+ # Save service status after restart
+ systemctl status "${systemd_service}" | save_in_log_dir "${service_name}.after.status"
+ fi
+else
+ log_abort_and_quit "${service_name} is disabled (or missing), nothing left to do."
+fi
+
+post_repair
diff --git a/autosysadmin-agent/files/upstream/restart/README b/autosysadmin-agent/files/upstream/restart/README
new file mode 100644
index 00000000..83a3a9a2
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/restart/README
@@ -0,0 +1,19 @@
+Autosysadmin "restart auto" scripts
+===================================
+
+In this directory you can place scripts that will be executed automatically by a cron job (stored in `/etc/cron.d/autosysadmin`).
+
+They must satisfy the default `run-parts(8)` constraints :
+
+* be "executable"
+* belong to the Debian cron script namespace (`^[a-zA-Z0-9_-]+$`), example: `restart_amavis`
+
+Warning: scripts that do not satisfy those criteria will NOT be run (silently)!
+
+You can print the names of the scripts which would be run, without actually running them, with this command :
+
+```
+$ run-parts --test /usr/share/scripts/autosysadmin/restart
+```
+
+You can use `zzz-restart_example.template` as boilerplate code to make your own "restart" script.
diff --git a/autosysadmin-agent/files/upstream/restart/zzz-restart_example.template b/autosysadmin-agent/files/upstream/restart/zzz-restart_example.template
new file mode 100644
index 00000000..1051d132
--- /dev/null
+++ b/autosysadmin-agent/files/upstream/restart/zzz-restart_example.template
@@ -0,0 +1,120 @@
+#!/bin/bash
+
+: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
+source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
+source "${AUTOSYSADMIN_LIB}/restart.sh" || exit 1
+
+# shellcheck disable=SC2034
+RUNNING="nwh-fr"
+
+## Possible values for RUNNING :
+## never => disabled
+## always => enabled
+## nwh-fr => enabled during non-working-hours in France
+## nwh-ca => enabled during non-working-hours in Canada (not supported yet)
+## custom => enabled if `running_custom()` function returns 0, otherwise disabled.
+
+## Uncomment and customize this method if you want to have a special logic :
+##
+## return 1 if we should not run
+## return 0 if we should run
+##
+## Some available functions :
+## is_weekend() : Saturday or Sunday
+## is_holiday() : holiday in France (based on `gcal(1)`)
+## is_workday() : not weekend and not holiday
+## is_worktime() : work day between 9-12h and 14-18h
+#
+# running_custom() {
+# # implement your own custom method to decide if we should run or not
+# }
+
+## The name of the service, mainly for logging
+service_name="example"
+## The SysVinit script name
+sysvinit_script="${service_name}"
+## The systemd service name
+systemd_service="${service_name}.service"
+
+is_service_alive() {
+ ## this must return 0 if the service is alive, otherwise return 1
+ ## Example:
+ pgrep -u USER PROCESS_NAME > /dev/null
+}
+
+## Action for SysVinit system
+sysvinit_action() {
+ # Save service status before restart
+ timeout 2 "/etc/init.d/${sysvinit_script}" status | save_in_log_dir "${service_name}.before.status"
+
+ # Try to restart
+ timeout 20 "/etc/init.d/${sysvinit_script}" restart > /dev/null
+ rc=$?
+ if [ "${rc}" -eq "0" ]; then
+ log_action "Restart ${service_name}: OK"
+ else
+ log_action "Restart ${service_name}: failed"
+ fi
+
+ # Save service status after restart
+ timeout 2 "/etc/init.d/${sysvinit_script}" status | save_in_log_dir "${service_name}.after.status"
+}
+
+## Action for systemd system
+systemd_action() {
+ # Save service status before restart
+ systemctl status "${systemd_service}" | save_in_log_dir "${service_name}.before.status"
+
+ # Try to restart
+ # systemctl (only for NRPE ?) sometimes returns 0 even if the service has failed to start
+ # so we check the status explicitly
+ timeout 20 systemctl restart "${systemd_service}" > /dev/null \
+ && sleep 1 \
+ && systemctl status "${systemd_service}" > /dev/null
+ rc=$?
+ if [ "${rc}" -eq "0" ]; then
+ log_action "Restart ${service_name}: OK"
+ else
+ log_action "Restart ${service_name}: failed"
+ fi
+
+ # Save service status after restart
+ systemctl status "${systemd_service}" | save_in_log_dir "${service_name}.after.status"
+}
+
+# Should we run?
+if ! is_supposed_to_run; then
+ # log_global "${PROGNAME} is not supposed to run (RUNNING=${RUNNING})."
+ exit 0
+fi
+if is_service_alive; then
+ # log_global "${service_name} process alive. Aborting"
+ exit 0
+fi
+
+# Yes we do, so check for sysvinit or systemd
+if is_debian_version "8" "<="; then
+ if ! is_sysvinit_enabled "*${sysvinit_script}*"; then
+ # log_global "${service_name} not enabled. Aborting"
+ exit 0
+ fi
+
+ # Let's finally do the action
+ pre_restart
+ sysvinit_action
+ post_restart
+else
+ if ! is_systemd_enabled "${systemd_service}"; then
+ # log_global "${service_name} is disabled (or missing), nothing left to do."
+ exit 0
+ fi
+ if is_systemd_active "${systemd_service}"; then
+ # log_global "${service_name} is active, nothing left to do."
+ exit 0
+ fi
+
+ # Let's finally do the action
+ pre_restart
+ systemd_action
+ post_restart
+fi
diff --git a/autosysadmin-agent/handlers/main.yml b/autosysadmin-agent/handlers/main.yml
new file mode 100644
index 00000000..f192d587
--- /dev/null
+++ b/autosysadmin-agent/handlers/main.yml
@@ -0,0 +1,16 @@
+---
+
+- name: restart nagios-nrpe-server
+ service:
+ name: nagios-nrpe-server
+ state: restarted
+
+- name: restart nrpe
+ service:
+ name: nrpe
+ state: restarted
+
+- name: restart rsyslog
+ service:
+ name: rsyslog
+ state: restarted
diff --git a/autosysadmin-agent/tasks/crontab.yml b/autosysadmin-agent/tasks/crontab.yml
new file mode 100644
index 00000000..1fa090ab
--- /dev/null
+++ b/autosysadmin-agent/tasks/crontab.yml
@@ -0,0 +1,25 @@
+---
+
+- name: "Add begin marker if missing"
+ ansible.builtin.lineinfile:
+ path: "/etc/cron.d/autosysadmin"
+ line: "# BEGIN ANSIBLE MANAGED SECTION FOR AUTOSYSADMIN"
+ insertbefore: BOF
+ create: yes
+
+- name: "Add end marker if missing"
+ ansible.builtin.lineinfile:
+ path: "/etc/cron.d/autosysadmin"
+ line: "# END ANSIBLE MANAGED SECTION FOR AUTOSYSADMIN"
+ insertbefore: "EOF"
+ create: yes
+
+- name: "Create config if missing"
+ ansible.builtin.blockinfile:
+ path: "/etc/cron.d/autosysadmin"
+ marker: "# {mark} ANSIBLE MANAGED SECTION FOR AUTOSYSADMIN"
+ block: "{{ lookup('ansible.builtin.template', '../templates/autosysadmin.cron.j2') }}"
+ owner: root
+ group: root
+ mode: "0750"
+ create: yes
diff --git a/autosysadmin-agent/tasks/dependencies.yml b/autosysadmin-agent/tasks/dependencies.yml
new file mode 100644
index 00000000..4f120944
--- /dev/null
+++ b/autosysadmin-agent/tasks/dependencies.yml
@@ -0,0 +1,4 @@
+---
+- name: Install gcal
+ ansible.builtin.apt:
+ name: gcal
diff --git a/autosysadmin-agent/tasks/install.yml b/autosysadmin-agent/tasks/install.yml
new file mode 100644
index 00000000..b8ecd752
--- /dev/null
+++ b/autosysadmin-agent/tasks/install.yml
@@ -0,0 +1,114 @@
+---
+- name: "Remount /usr if needed"
+ ansible.builtin.include_role:
+ name: remount-usr
+
+- name: Previous autosysadmin restart directory is renamed
+ command:
+ cmd: mv "/usr/share/scripts/autosysadmin/auto" "{{ autosysadmin_agent_auto_dir }}"
+ removes: "/usr/share/scripts/autosysadmin/auto"
+ creates: "{{ autosysadmin_agent_auto_dir }}"
+
+- name: Create autosysadmin directories
+ ansible.builtin.file:
+ path: "{{ item }}"
+ state: directory
+ owner: "root"
+ group: "root"
+ mode: "0750"
+ loop:
+ - "{{ autosysadmin_agent_bin_dir }}"
+ - "{{ autosysadmin_agent_lib_dir }}"
+ - "{{ autosysadmin_agent_auto_dir }}"
+
+- name: Copy libraries
+ ansible.builtin.copy:
+ src: "upstream/lib/"
+ dest: "{{ autosysadmin_agent_lib_dir }}/"
+ owner: root
+ group: root
+ mode: "0750"
+
+- name: Copy repair scripts
+ ansible.builtin.copy:
+ src: "upstream/repair/"
+ dest: "{{ autosysadmin_agent_bin_dir }}/"
+ owner: root
+ group: root
+ mode: "0750"
+
+- name: Copy other utilities
+ ansible.builtin.copy:
+ src: "upstream/bin/"
+ dest: "{{ autosysadmin_agent_bin_dir }}/"
+ owner: root
+ group: root
+ mode: "0750"
+
+### WARNING: thos files are explicitly marked as non-executable
+### to prevent them from being run automatically by run-parts
+
+- name: Copy restart scripts
+ ansible.builtin.copy:
+ src: "upstream/restart/"
+ dest: "{{ autosysadmin_agent_auto_dir }}/"
+ owner: root
+ group: root
+ mode: "0640"
+
+- name: Ensure /etc/evolinux folder exists
+ ansible.builtin.file:
+ path: "/etc/evolinux"
+ state: directory
+ owner: "root"
+ group: "root"
+ mode: "0700"
+
+- name: Copy the configuration file if missing
+ ansible.builtin.template:
+ src: "autosysadmin.cf.j2"
+ dest: "/etc/evolinux/autosysadmin"
+ owner: root
+ group: root
+ mode: "0640"
+ force: no
+
+# Repair scripts are supposed to be 'on' by default
+# A line "repair_XXX=off" is added to the file only if the script is to be disabled.
+# That's why all the ternary logic for the state is reversed.
+- name: Update value per variable
+ ansible.builtin.lineinfile:
+ dest: "/etc/evolinux/autosysadmin"
+ line: "{{ item }}={{ autosysadmin_config[item] | default(true) | bool | ternary('on', 'off') }}"
+ regexp: '^(#\s*)?{{ item }}=.*'
+ state: "{{ autosysadmin_config[item] | default(true) | bool | ternary('absent', 'present') }}"
+ register: _line
+ loop: "{{ autosysadmin_repair_scripts | union(['repair_all']) }}"
+
+- name: Ensure restart folder exists
+ ansible.builtin.file:
+ path: "auto"
+ state: directory
+ owner: "root"
+ group: "root"
+ mode: "0700"
+
+- name: Legacy scripts are removed
+ ansible.builtin.file:
+ path: "{{ general_scripts_dir }}/autosysadmin/{{ item }}"
+ state: absent
+ loop:
+ - repair_amavis.sh
+ - repair_disk.sh
+ - repair_elasticsearch.sh
+ - repair_http.sh
+ - repair_mysql.sh
+ - repair_opendkim.sh
+ - repair_php_fpm56.sh
+ - repair_php_fpm70.sh
+ - repair_php_fpm73.sh
+ - repair_php_fpm74.sh
+ - repair_php_fpm80.sh
+ - repair_php_fpm81.sh
+ - repair_redis.sh
+ - repair_tomcat_instance.sh
diff --git a/autosysadmin-agent/tasks/logrotate.yml b/autosysadmin-agent/tasks/logrotate.yml
new file mode 100644
index 00000000..bf1e55b4
--- /dev/null
+++ b/autosysadmin-agent/tasks/logrotate.yml
@@ -0,0 +1,8 @@
+---
+- name: Copy logrotate configuration for autosysadmin
+ ansible.builtin.copy:
+ src: "files/autosysadmin.logrotate.conf"
+ dest: "/etc/logrotate.d/autosysadmin"
+ owner: root
+ group: root
+ mode: "0644"
diff --git a/autosysadmin-agent/tasks/main.yml b/autosysadmin-agent/tasks/main.yml
new file mode 100644
index 00000000..9ac8a7b6
--- /dev/null
+++ b/autosysadmin-agent/tasks/main.yml
@@ -0,0 +1,31 @@
+---
+
+- name: The list of all repair scripts is composed.
+ set_fact:
+ autosysadmin_repair_scripts: "{{ lookup('ansible.builtin.fileglob', '../../../autosysadmin/agent/repair/repair_*', wantlist=True) | map('basename') | sort }}"
+
+- name: Install dependencies
+ ansible.builtin.include_tasks: dependencies.yml
+
+- name: Install autosysadmin
+ ansible.builtin.include_tasks: install.yml
+
+- name: Crontab configuration
+ ansible.builtin.include_tasks: crontab.yml
+
+- name: NRPE configuration
+ ansible.builtin.include_tasks: nrpe.yml
+
+- name: sudo configuration
+ ansible.builtin.include_tasks: sudo.yml
+
+- name: rsyslog configuration
+ ansible.builtin.include_tasks: rsyslog.yml
+
+- name: logrotate configuration
+ ansible.builtin.include_tasks: logrotate.yml
+
+- name: Install latest version of dump-server-state
+ ansible.builtin.include_role:
+ name: evolinux-base
+ tasks_from: dump-server-state.yml
diff --git a/autosysadmin-agent/tasks/nrpe.yml b/autosysadmin-agent/tasks/nrpe.yml
new file mode 100644
index 00000000..b5a31922
--- /dev/null
+++ b/autosysadmin-agent/tasks/nrpe.yml
@@ -0,0 +1,9 @@
+---
+- name: custom configuration is present
+ ansible.builtin.template:
+ src: autosysadmin.nrpe.cfg.j2
+ dest: /etc/nagios/nrpe.d/autosysadmin.cfg
+ group: nagios
+ mode: "0640"
+ force: yes
+ notify: restart nagios-nrpe-server
diff --git a/autosysadmin-agent/tasks/rsyslog.yml b/autosysadmin-agent/tasks/rsyslog.yml
new file mode 100644
index 00000000..bb57f24a
--- /dev/null
+++ b/autosysadmin-agent/tasks/rsyslog.yml
@@ -0,0 +1,9 @@
+---
+- name: Copy rsyslog configuration for autosysadmin
+ ansible.builtin.copy:
+ src: "files/autosysadmin.rsyslog.conf"
+ dest: "/etc/rsyslog.d/autosysadmin.conf"
+ owner: root
+ group: root
+ mode: "0644"
+ notify: restart rsyslog
diff --git a/autosysadmin-agent/tasks/sudo.yml b/autosysadmin-agent/tasks/sudo.yml
new file mode 100644
index 00000000..a4fd35be
--- /dev/null
+++ b/autosysadmin-agent/tasks/sudo.yml
@@ -0,0 +1,7 @@
+---
+- name: Add autosysadmin sudoers file
+ ansible.builtin.template:
+ src: autosysadmin.sudoers.j2
+ dest: /etc/sudoers.d/autosysadmin
+ mode: "0600"
+ validate: "visudo -cf %s"
diff --git a/autosysadmin-agent/templates/autosysadmin.cf.j2 b/autosysadmin-agent/templates/autosysadmin.cf.j2
new file mode 100644
index 00000000..763958ba
--- /dev/null
+++ b/autosysadmin-agent/templates/autosysadmin.cf.j2
@@ -0,0 +1,12 @@
+# This configuration is partially managed by Ansible
+# You can change specific values manually, but they may be overridden by Ansible
+#
+# To be safe, update the hosts_vars/group_vars in the autosysadmin project
+# https://gitea.evolix.org/evolix/autosysadmin/src/branch/master
+# then use the "agent" playbook to deploy.
+#
+# Configuration for autosysadmin
+# Use this file to change configuration values defined in repair scripts
+# To disable all repair scripts : repair_all=off
+# To disable "repair_http" : repair_http=off
+#
\ No newline at end of file
diff --git a/autosysadmin-agent/templates/autosysadmin.cron.j2 b/autosysadmin-agent/templates/autosysadmin.cron.j2
new file mode 100644
index 00000000..90823d5e
--- /dev/null
+++ b/autosysadmin-agent/templates/autosysadmin.cron.j2
@@ -0,0 +1,7 @@
+PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
+
+# Run each enabled script
+*/5 * * * * root run-parts /usr/share/scripts/autosysadmin/restart
+
+# Clean run log files
+@weekly root {{ autosysadmin_agent_bin_dir | mandatory }}/delete_old_logs.sh {{ autosysadmin_agent_log_retention_days | default('365') }}
diff --git a/autosysadmin-agent/templates/autosysadmin.nrpe.cfg.j2 b/autosysadmin-agent/templates/autosysadmin.nrpe.cfg.j2
new file mode 100644
index 00000000..c3e1a40c
--- /dev/null
+++ b/autosysadmin-agent/templates/autosysadmin.nrpe.cfg.j2
@@ -0,0 +1,8 @@
+#
+# Ansible managed - DO NOT MODIFY, your changes will be overwritten !
+#
+
+# Autosysadmin repair commands
+{% for script in lookup('ansible.builtin.fileglob', '../../../autosysadmin/agent/repair/repair_*', wantlist=True) | map("basename") | sort %}
+command[{{ script }}]=sudo {{ autosysadmin_agent_bin_dir }}/{{ script }}
+{% endfor %}
\ No newline at end of file
diff --git a/autosysadmin-agent/templates/autosysadmin.sudoers.j2 b/autosysadmin-agent/templates/autosysadmin.sudoers.j2
new file mode 100644
index 00000000..f182bb84
--- /dev/null
+++ b/autosysadmin-agent/templates/autosysadmin.sudoers.j2
@@ -0,0 +1,7 @@
+#
+# Ansible managed - DO NOT MODIFY, your changes will be overwritten !
+#
+
+{% for script in lookup('ansible.builtin.fileglob', '../../../autosysadmin/agent/repair/repair_*', wantlist=True) | map("basename") | sort %}
+nagios ALL = NOPASSWD: {{ autosysadmin_agent_bin_dir }}/{{ script }}
+{% endfor %}
\ No newline at end of file
diff --git a/autosysadmin-restart_nrpe/defaults/main.yml b/autosysadmin-restart_nrpe/defaults/main.yml
new file mode 100644
index 00000000..3d743a1b
--- /dev/null
+++ b/autosysadmin-restart_nrpe/defaults/main.yml
@@ -0,0 +1,8 @@
+---
+
+general_scripts_dir: "/usr/share/scripts"
+
+restart_nrpe_path: "{{ general_scripts_dir }}/autosysadmin/restart/restart_nrpe"
+
+# Change this to customize the RUNNING value in the script
+restart_nrpe_running: Null
diff --git a/autosysadmin-restart_nrpe/files/upstream/restart_nrpe b/autosysadmin-restart_nrpe/files/upstream/restart_nrpe
new file mode 100755
index 00000000..b2dd7f44
--- /dev/null
+++ b/autosysadmin-restart_nrpe/files/upstream/restart_nrpe
@@ -0,0 +1,105 @@
+#!/bin/bash
+
+: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
+source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
+source "${AUTOSYSADMIN_LIB}/restart.sh" || exit 1
+
+## Possible values for RUNNING :
+## never => disabled
+## always => enabled
+## nwh-fr => enabled during non-working-hours in France
+## nwh-ca => enabled during non-working-hours in Canada (not supported yet)
+## custom => enabled if `running_custom()` function return 0, otherwise disabled.
+
+# shellcheck disable=SC2034
+RUNNING="nwh-fr"
+
+## The name of the service, mainly for logging
+service_name="nagios-nrpe-server"
+## The SysVinit script name
+sysvinit_script="${service_name}"
+## The systemd service name
+systemd_service="${service_name}.service"
+
+is_service_alive() {
+ ## this must return 0 if the service is alive, otherwise return 1
+ ## Example:
+ pgrep -u nagios nrpe > /dev/null
+}
+
+## Action for SysVinit system
+sysvinit_action() {
+ # Save service status before restart
+ timeout 2 "/etc/init.d/${sysvinit_script}" status | save_in_log_dir "${service_name}.before.status"
+
+ # Try to restart
+ timeout 20 "/etc/init.d/${sysvinit_script}" restart > /dev/null
+ rc=$?
+ if [ "${rc}" -eq "0" ]; then
+ log_action "Restart ${service_name}: OK"
+ else
+ log_action "Restart ${service_name}: failed"
+ fi
+
+ # Save service status after restart
+ timeout 2 "/etc/init.d/${sysvinit_script}" status | save_in_log_dir "${service_name}.after.status"
+}
+
+## Action for systemd system
+systemd_action() {
+ # Save service status before restart
+ systemctl status "${systemd_service}" | save_in_log_dir "${service_name}.before.status"
+
+ # Try to restart
+ # systemctl (only for NRPE ?) sometimes returns 0 even if the service has failed to start
+ # so we check the status explicitly
+ timeout 20 systemctl restart "${systemd_service}" > /dev/null \
+ && sleep 1 \
+ && systemctl status "${systemd_service}" > /dev/null
+ rc=$?
+ if [ "${rc}" -eq "0" ]; then
+ log_action "Restart ${service_name}: OK"
+ else
+ log_action "Restart ${service_name}: failed"
+ fi
+
+ # Save service status after restart
+ systemctl status "${systemd_service}" | save_in_log_dir "${service_name}.after.status"
+}
+
+# Should we run?
+if ! is_supposed_to_run; then
+ # log_global "${PROGNAME} is not supposed to run (RUNNING=${RUNNING})."
+ exit 0
+fi
+if is_service_alive; then
+ # log_global "${service_name} process alive. Aborting"
+ exit 0
+fi
+
+# Yes we do, so check for sysvinit or systemd
+if is_debian_version "8" "<="; then
+ if ! is_sysvinit_enabled "*${sysvinit_script}*"; then
+ # log_global "${service_name} not enabled. Aborting"
+ exit 0
+ fi
+
+ # Let's finally do the action
+ pre_restart
+ sysvinit_action
+ post_restart
+else
+ if ! is_systemd_enabled "${systemd_service}"; then
+ # log_global "${service_name} is disabled (or missing), nothing left to do."
+ exit 0
+ fi
+ if is_systemd_active "${systemd_service}"; then
+ # log_global "${service_name} is active, nothing left to do."
+ exit 0
+ fi
+
+ # Let's finally do the action
+ pre_restart
+ systemd_action
+ post_restart
+fi
diff --git a/autosysadmin-restart_nrpe/tasks/main.yml b/autosysadmin-restart_nrpe/tasks/main.yml
new file mode 100644
index 00000000..7a8ad5b0
--- /dev/null
+++ b/autosysadmin-restart_nrpe/tasks/main.yml
@@ -0,0 +1,24 @@
+---
+
+ - name: "Remount /usr if needed"
+ ansible.builtin.include_role:
+ name: remount-usr
+
+ - name: "Copy restart_nrpe"
+ ansible.builtin.copy:
+ src: upstream/restart_nrpe
+ dest: "{{ restart_nrpe_path }}"
+ owner: "root"
+ group: "root"
+ mode: "0750"
+
+ - name: "Customize RUNNING value"
+ ansible.builtin.lineinfile:
+ path: "{{ restart_nrpe_path }}"
+ line: "RUNNING=\"{{ restart_nrpe_running }}\""
+ regexp: "^ *RUNNING="
+ create: False
+ when:
+ - restart_nrpe_running is defined
+ - restart_nrpe_running != None
+ - restart_nrpe_running | length > 0
diff --git a/bind/files/bind-reload-zone.sh b/bind/files/bind-reload-zone.sh
new file mode 100755
index 00000000..550e5b64
--- /dev/null
+++ b/bind/files/bind-reload-zone.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+#
+# Script utilitaire pour tester et recharger facilement une zone dans Bind
+#
+
+usage() {
+ echo "Usage: bind-reload-zone "
+ echo " bind-reload-zone -h|--help"
+}
+
+if [ $# -ne 1 ] ; then
+ usage
+ exit 1
+fi
+
+while :; do
+ case $1 in
+ -h|--help)
+ usage
+ exit 0
+ ;;
+ *)
+ zone=$1
+ break
+ ;;
+ esac
+ shift
+done
+
+if ! [ -f "/etc/bind/db.${zone}" ]; then
+ >&2 echo "Error: zone for ${zone} not found."
+ usage
+ exit 1
+fi
+
+named-checkzone "${zone}" /etc/bind/db."${zone}" && rndc reload "${zone}"
+
diff --git a/bind/files/bind-reload-zone_completion.sh b/bind/files/bind-reload-zone_completion.sh
new file mode 100644
index 00000000..2e87b12c
--- /dev/null
+++ b/bind/files/bind-reload-zone_completion.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+
+_bind_reload_zone_dynamic_completion() {
+ local cur;
+ cur=${COMP_WORDS[COMP_CWORD]};
+ COMPREPLY=();
+ COMPREPLY=( $( compgen -W '$(grep -v -h '"'"'//'"'"' /etc/bind/named.conf* | grep -B1 "type master" | grep zone | grep -v arpa | awk '"'"'{gsub(/"/, "", $2); print $2}'"'"' | sort | uniq)' -- $cur ) );
+
+ # reverse ipv4 :
+ #grep -v -h '//' /etc/bind/named.conf* | grep -B1 "type master" | grep zone | grep arpa | grep -v ip6 | awk '{gsub(/"/, "", $2); gsub(/.in-addr.arpa/, "", $2); print $2}' | sort | uniq | awk -F'.' '{ for (i=NF; i>1; i--) printf("%s.",$i); print $1 }'
+
+ # reveres ipv6 : je bloque sur l'inversion 4 par 4
+ #grep -v -h '//' /etc/bind/named.conf* | grep -B1 "type master" | grep zone | grep arpa | grep ip6 | awk '{gsub(/"/, "", $2); gsub(/.ip6.arpa/, "", $2); print $2}' | sort | uniq | awk -F'.' '{ for (i=NF; i>1; i--) { if ($i % 4 == 0) printf("%s.",$i); else printf("%s",$i); } print $1 }'
+
+}
+
+complete -F _bind_reload_zone_dynamic_completion bind-reload-zone
+
diff --git a/bind/files/reload-zone b/bind/files/reload-zone
deleted file mode 100755
index b9acc449..00000000
--- a/bind/files/reload-zone
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/bash
-#
-# Script utilitaire pour tester et recharger facilement un domaine dans Bind
-# Usage : reload-zone
-#
-# TODO:
-# - renommer le script (par ex bind-safe-reload)
-# - vérifier le serial
-# - ajouter un -h --help
-# - prendre en charge plusieurs zones (ou aucune)
-# - ajouter le script dans le role bind
-
-named-checkzone "$1" /etc/bind/db."$1" && rndc reload "$1"
-
diff --git a/bind/handlers/main.yml b/bind/handlers/main.yml
index 5461579d..85eaa680 100644
--- a/bind/handlers/main.yml
+++ b/bind/handlers/main.yml
@@ -3,7 +3,6 @@
ansible.builtin.systemd:
daemon-reload: yes
-
- name: restart apparmor
ansible.builtin.systemd:
name: apparmor
diff --git a/bind/meta/main.yml b/bind/meta/main.yml
index 6cf180b1..533f4335 100644
--- a/bind/meta/main.yml
+++ b/bind/meta/main.yml
@@ -14,6 +14,8 @@ galaxy_info:
- jessie
- stretch
- buster
+ - bullseye
+ - bookworm
galaxy_tags: []
# Be sure to remove the '[]' above if you add dependencies
diff --git a/certbot/files/hooks/deploy/dovecot.sh b/certbot/files/hooks/deploy/dovecot.sh
index 56e5b5ae..1ed4ab5d 100644
--- a/certbot/files/hooks/deploy/dovecot.sh
+++ b/certbot/files/hooks/deploy/dovecot.sh
@@ -16,7 +16,7 @@ config_check() {
${doveconf_bin} > /dev/null 2>&1
}
letsencrypt_used() {
- ${doveconf_bin} | grep -E "^ssl_cert[^_]" | grep -q "letsencrypt"
+ ${doveconf_bin} | grep -E "^[[:blank:]]*ssl_cert[^_]" | grep -q "letsencrypt"
}
main() {
if daemon_found_and_running; then
diff --git a/certbot/files/hooks/deploy/hapee.sh b/certbot/files/hooks/deploy/hapee.sh
index 89b04452..d39da25b 100644
--- a/certbot/files/hooks/deploy/hapee.sh
+++ b/certbot/files/hooks/deploy/hapee.sh
@@ -39,8 +39,8 @@ concat_files() {
chown root: "${hapee_cert_file}"
}
cert_and_key_mismatch() {
- hapee_cert_md5=$(openssl x509 -noout -modulus -in "${hapee_cert_file}" | openssl md5)
- hapee_key_md5=$(openssl rsa -noout -modulus -in "${hapee_cert_file}" | openssl md5)
+ hapee_cert_md5=$(openssl x509 -noout -pubkey -in "${hapee_cert_file}" | openssl md5)
+ hapee_key_md5=$(openssl pkey -noout -pubout -in "${hapee_cert_file}" | openssl md5)
test "${hapee_cert_md5}" != "${hapee_key_md5}"
}
diff --git a/certbot/files/hooks/deploy/haproxy.sh b/certbot/files/hooks/deploy/haproxy.sh
index 932a3e90..36a09262 100644
--- a/certbot/files/hooks/deploy/haproxy.sh
+++ b/certbot/files/hooks/deploy/haproxy.sh
@@ -29,8 +29,8 @@ concat_files() {
chown root: "${haproxy_cert_file}"
}
cert_and_key_mismatch() {
- haproxy_cert_md5=$(openssl x509 -noout -modulus -in "${haproxy_cert_file}" | openssl md5)
- haproxy_key_md5=$(openssl rsa -noout -modulus -in "${haproxy_cert_file}" | openssl md5)
+ haproxy_cert_md5=$(openssl x509 -noout -pubkey -in "${haproxy_cert_file}" | openssl md5)
+ haproxy_key_md5=$(openssl pkey -pubout -in "${haproxy_cert_file}" | openssl md5)
test "${haproxy_cert_md5}" != "${haproxy_key_md5}"
}
diff --git a/certbot/files/hooks/deploy/nrpe.sh b/certbot/files/hooks/deploy/nrpe.sh
new file mode 100644
index 00000000..578d6764
--- /dev/null
+++ b/certbot/files/hooks/deploy/nrpe.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+error() {
+ >&2 echo "${PROGNAME}: $1"
+ exit 1
+}
+debug() {
+ if [ "${VERBOSE}" = "1" ] && [ "${QUIET}" != "1" ]; then
+ >&2 echo "${PROGNAME}: $1"
+ fi
+}
+daemon_found_and_running() {
+ test -n "$(pidof nrpe)"
+}
+letsencrypt_lineaged_used() {
+ grep -r "^ssl_cert_file" /etc/nagios/ | grep "letsencrypt" | grep -q "$(basename "${RENEWED_LINEAGE}")"
+}
+copy_letsencrypt_cert() {
+ DEST_CERTIFICATE=$(grep -r "^ssl_cert_file" /etc/nagios/ | awk -F'=' '{print $2}')
+ DEST_PRIVATE_KEY=$(grep -r "^ssl_privatekey_file" /etc/nagios/ | awk -F'=' '{print $2}')
+
+ install --mode 440 --group nagios ${RENEWED_LINEAGE}/fullchain.pem ${DEST_CERTIFICATE}
+ install --mode 440 --group nagios ${RENEWED_LINEAGE}/privkey.pem ${DEST_PRIVATE_KEY}
+}
+main() {
+ if daemon_found_and_running; then
+ if letsencrypt_lineaged_used; then
+ debug "NRPE detected... Copying certificates to the right place & permissions"
+ copy_letsencrypt_cert
+ debug "Restarting NRPE"
+ systemctl restart nagios-nrpe-server
+ else
+ debug "NRPE doesn't use the given Let's Encrypt certificate. Skip."
+ fi
+ else
+ debug "NRPE is not running or missing. Skip."
+ fi
+}
+
+readonly PROGNAME=$(basename "$0")
+readonly VERBOSE=${VERBOSE:-"0"}
+readonly QUIET=${QUIET:-"0"}
+
+main
\ No newline at end of file
diff --git a/certbot/tasks/main.yml b/certbot/tasks/main.yml
index 3dcb1334..a32aa630 100644
--- a/certbot/tasks/main.yml
+++ b/certbot/tasks/main.yml
@@ -21,6 +21,8 @@
- ansible.builtin.include: acme-challenge.yml
+# This is always going to mark a "change".
+# Couldn't figure out why !
- name: Deploy hooks are present
ansible.builtin.copy:
src: hooks/deploy/
diff --git a/check_free_space/defaults/main.yml b/check_free_space/defaults/main.yml
new file mode 100644
index 00000000..c699ad91
--- /dev/null
+++ b/check_free_space/defaults/main.yml
@@ -0,0 +1,6 @@
+---
+check_free_space_partitions:
+ - "/home"
+ - "/srv"
+check_free_space_max_percent: 70
+check_free_space_mailto: Null
diff --git a/check_free_space/files/check_free_space.sh b/check_free_space/files/check_free_space.sh
new file mode 100755
index 00000000..f1b89d8c
--- /dev/null
+++ b/check_free_space/files/check_free_space.sh
@@ -0,0 +1,166 @@
+#!/bin/sh
+
+# This script verifies if the specified partitions on a machine are filled
+# at more than x%.
+#
+# If so, it sends a mail to the admin of that machine, warning him/her
+# that mesures should be taken.
+#
+# Two outputs are provided to the recipient of the mail:
+# * some general infos with `df`
+# * a more indepth inspection with `duc`
+#
+# This script takes 3 (mandatory) arguments:
+# * a list of the partitions to check (space separated)
+# * the maximum allowed percentage
+# * the email template to use
+#
+# This script should be ran by cron @daily.
+#
+#
+# Copyright (C) 2016 Louis-Philippe Véronneau
+#
+# This program is licensed under GPLv3 +
+
+
+# Check argument sanity
+
+PID_FILE='/var/run/check_free_space.pid'
+
+if test -f "$PID_FILE"
+then
+ pid=$(cat "$PID_FILE")
+ ps -p "$pid" > /dev/null
+ if test $? -eq 0
+ then
+ echo "$0 already run !" >&2
+ exit 1
+ else
+ rm $PID_FILE
+ fi
+fi
+
+echo $$ > $PID_FILE
+
+if test -z "$1" || test -z "$2" || test -z "$3" # is non null
+then
+ echo "Some arguments are missing. Please issue a partition list, a" \
+ "maximum percentage and an email template."
+ exit 1
+elif ! [ "$2" -le 100 -a "$2" -ge 0 ] # is a percentage
+then
+ echo "Please enter a maximum percentage value between 0 and 100."
+ exit 1
+fi
+
+# Argument processing
+
+partition_list=$1
+max_percentage=$((100-$2))
+email_template=$3
+
+HOSTNAME=$(hostname)
+debian_version=$(lsb_release -c)
+
+check_disk='/usr/lib/nagios/plugins/check_disk'
+
+test -f /etc/evomaintenance.cf && . /etc/evomaintenance.cf
+
+
+# Test what version of df we have
+
+old_df=false
+
+case "$debian_version" in
+ *squeeze* ) old_df=true ;;
+ *wheezy* ) old_df=true ;;
+esac
+
+
+# Check disk space
+
+df_options="size,avail,pcent,itotal,iavail,ipcent"
+
+for partition in $partition_list
+do
+ if ! $check_disk -w $max_percentage% -W $max_percentage% $partition > /dev/null
+ then
+ # the 'newline' is a hack to make sed behave
+ PARTITION_DATA="$PARTITION_DATA newline $partition newline"
+ if [ $old_df ]
+ then
+ PARTITION_DATA="$PARTITION_DATA $(/bin/df -h $partition) newline"
+ PARTITION_DATA="$PARTITION_DATA newline $(df -ih $partition) newlinenewline"
+ else
+ PARTITION_DATA="$PARTITION_DATA $(/bin/df -h --output=$df_options $partition) newline"
+ fi
+ full_partitions="$full_partitions $partition"
+ partname=$(echo $partition|tr -s '/' '-')
+ graph_list="$graph_list -a /home/duc${partname}.png"
+ fi
+done
+
+
+# Exit if everything is OK
+
+if test -z "$PARTITION_DATA"
+then
+ exit 0
+fi
+
+
+# If there is indeed a problem, get more infos with duc
+
+/usr/bin/ionice -c3 /usr/bin/duc index -H -d /home/duc.idx -x $full_partitions -q
+
+for partition in $full_partitions
+do
+ duc_temp=$(/usr/bin/duc ls -d /home/duc.idx -Fg $partition)
+ duc_temp=$(printf "$duc_temp" | sed -e "s@]@]newline@" | grep -v "lost+found")
+ DUC_OUTPUT="$DUC_OUTPUT newline$partition newline$duc_temp"
+ partname=$(echo $partition|tr -s '/' '-')
+ duc graph -d /home/duc.idx -o /home/duc${partname}.png -l8 -s 1024 $partition
+done
+
+
+# Replace placeholders & send the mail !
+
+PARTITION_DATA="$(echo "$PARTITION_DATA"|tr -d $'\n')" # make sed accept the input
+DUC_OUTPUT="$(echo "$DUC_OUTPUT"|tr -d $'\n')"
+
+if [ $old_df ]
+then
+ sed -e "s/__TO__/$EVOMAINTMAIL/" \
+ -e "s/__HOSTNAME__/$HOSTNAME/" \
+ -e "s@__PARTITION_DATA__@$PARTITION_DATA@" \
+ -e "s@__DUC_OUTPUT__@$DUC_OUTPUT@" \
+ -e "s/newline/\n/g" \
+ -e "s/IUse%/IUse%\n/g" \
+ -e "s/ Use%/ Use%\n/g" \
+ -e "s@Filesystem \{12\}@@g" \
+ -e "s@Mounted on\/dev\/[a-z]\{3\}[0-9]\+ \{13\}@@g" \
+ -e "s@% \/[a-z]\+@%@g" \
+ -e "s/__MAX_PERCENTAGE__/$max_percentage/" \
+ -e "s/__FULLFROM__/$FULLFROM/" \
+ -e "s/__FROM__/$FROM/" \
+ -e "s/__URGENCYFROM__/$URGENCYFROM/" \
+ -e "s/__URGENCYTEL__/$URGENCYTEL/" \
+ $email_template | \
+ /usr/bin/mutt -H - $graph_list
+else
+ sed -e "s/__TO__/$EVOMAINTMAIL/" \
+ -e "s/__HOSTNAME__/$HOSTNAME/" \
+ -e "s@__PARTITION_DATA__@$PARTITION_DATA@" \
+ -e "s@__DUC_OUTPUT__@$DUC_OUTPUT@" \
+ -e "s/newline/\n/g" \
+ -e "s/IUse%/IUse%\n/g" \
+ -e "s/__MAX_PERCENTAGE__/$max_percentage/" \
+ -e "s/__FULLFROM__/$FULLFROM/" \
+ -e "s/__FROM__/$FROM/" \
+ -e "s/__URGENCYFROM__/$URGENCYFROM/" \
+ -e "s/__URGENCYTEL__/$URGENCYTEL/" \
+ $email_template | \
+ /usr/bin/mutt -H - $graph_list
+fi
+
+rm -f $PID_FILE
diff --git a/check_free_space/files/check_free_space.tpl b/check_free_space/files/check_free_space.tpl
new file mode 100644
index 00000000..15ce5635
--- /dev/null
+++ b/check_free_space/files/check_free_space.tpl
@@ -0,0 +1,24 @@
+From: __FULLFROM__
+Content-Type: text/plain; charset=UTF-8
+MIME-Version: 1.0
+Content-Transfer-Encoding: 8bit
+To: __TO__
+Subject: [WARNING] Espace disque faible sur __HOSTNAME__
+
+Bonjour,
+
+Ceci est un message automatique pour vous informer qu'il y a un
+souci d'espace disque sur votre serveur __HOSTNAME__
+
+Voici les informations sur l'espace disque qui pose problème :
+__PARTITION_DATA__
+Détails sur les partitions problématiques :
+__DUC_OUTPUT__
+Un graphe par partition problématique est disponible en pièce jointe.
+
+Nous vous recommandons d'effectuer du ménage pour maintenir
+chaque partition avec un minimum de __MAX_PERCENTAGE__% d'espace disque libre.
+
+Cordialement,
+--
+__FULLFROM__
diff --git a/check_free_space/tasks/main.yml b/check_free_space/tasks/main.yml
new file mode 100644
index 00000000..b2b4aa07
--- /dev/null
+++ b/check_free_space/tasks/main.yml
@@ -0,0 +1,37 @@
+---
+- ansible.builtin.include_role:
+ name: evolix/remount-usr
+
+- name: Copy check_free_space.sh script
+ ansible.builtin.copy:
+ src: files/check_free_space.sh
+ dest: /usr/share/scripts/check_free_space
+ owner: root
+ group: root
+ mode: "0750"
+
+- name: Copy email template
+ ansible.builtin.copy:
+ src: files/check_free_space.tpl
+ dest: /usr/share/scripts/check_free_space.tpl
+ owner: root
+ group: root
+ mode: "0644"
+
+# not using the cron_module for this since it is buggy
+- name: check_free_space.sh is run by cron
+ ansible.builtin.template:
+ src: templates/cron_check_free_space.j2
+ dest: /etc/cron.d/check_free_space
+ owner: root
+ group: root
+ mode: "0644"
+ force: false
+
+- name: Duc and Mutt are installed
+ ansible.builtin.apt:
+ pkg:
+ - mutt
+ - duc
+ state: present
+
diff --git a/check_free_space/tasks/shell_script.yml b/check_free_space/tasks/shell_script.yml
new file mode 100644
index 00000000..716304a1
--- /dev/null
+++ b/check_free_space/tasks/shell_script.yml
@@ -0,0 +1,30 @@
+---
+
+- include_role:
+ name: evolix/remount-usr
+
+- name: shell script
+ copy:
+ src: files/check_free_space.sh
+ dest: /usr/share/scripts/check_free_space
+ owner: root
+ group: root
+ mode: "0750"
+
+- name: email template
+ copy:
+ src: files/check_free_space.tpl
+ dest: /usr/share/scripts/check_free_space.tpl
+ owner: root
+ group: root
+ mode: "0644"
+
+# not using the cron_module for this since it is buggy
+- name: cron
+ template:
+ src: templates/cron_check_free_space.j2
+ dest: /etc/cron.d/check_free_space
+ owner: root
+ group: root
+ mode: "0644"
+ force: false
diff --git a/check_free_space/templates/cron_check_free_space.j2 b/check_free_space/templates/cron_check_free_space.j2
new file mode 100644
index 00000000..5017a67b
--- /dev/null
+++ b/check_free_space/templates/cron_check_free_space.j2
@@ -0,0 +1,4 @@
+{% if check_free_space_mailto and check_free_space_mailto != "" %}
+MAILTO={{ check_free_space_mailto }}
+{% endif %}
+30 4 * * 1 root /usr/share/scripts/check_free_space "{{ check_free_space_partitions | join(' ') }}" {{ check_free_space_max_percent }} /usr/share/scripts/check_free_space.tpl
diff --git a/docker-host/tasks/main.yml b/docker-host/tasks/main.yml
index 556570f5..ec3781e7 100644
--- a/docker-host/tasks/main.yml
+++ b/docker-host/tasks/main.yml
@@ -119,4 +119,4 @@
cmd: "{{ docker_tls_path }}/shellpki.sh init"
when:
- docker_tls_enabled | bool
- - not tls_certs_stat.stat.isdir
+ - not (tls_certs_stat.stat.exists and tls_certs_stat.stat.isdir)
diff --git a/dovecot/defaults/main.yml b/dovecot/defaults/main.yml
index 52e06bda..e190adb6 100644
--- a/dovecot/defaults/main.yml
+++ b/dovecot/defaults/main.yml
@@ -1,4 +1,12 @@
---
+general_alert_email: "root@localhost"
+log2mail_alert_email: Null
+
dovecot_vmail_uid: 5000
dovecot_vmail_gid: 5000
+
+ldap_hostname: "{{ ansible_hostname }}"
+ldap_domain: "{{ ansible_domain }}"
+ldap_suffix: "dc={{ ldap_hostname }},dc={{ ldap_domain.split('.')[-2] }},dc={{ ldap_domain.split('.')[-1] }}"
+ldap_enabled: False
diff --git a/dovecot/files/munin_plugin_dovecot1 b/dovecot/files/munin_plugin_dovecot1
old mode 100644
new mode 100755
index 83f4d897..27139b73
--- a/dovecot/files/munin_plugin_dovecot1
+++ b/dovecot/files/munin_plugin_dovecot1
@@ -53,15 +53,17 @@ if ( $ARGV[0] and $ARGV[0] eq "autoconf" ) {
exit 0;
}
-if (-f "$logfile.0") {
- $rotlogfile = $logfile . ".0";
-} elsif (-f "$logfile.1") {
- $rotlogfile = $logfile . ".1";
-} elsif (-f "$logfile.01") {
- $rotlogfile = $logfile . ".01";
-} else {
- $rotlogfile = $logfile . ".0";
-}
+# Disable rotated log inpection because name is not deterministic across systems
+# and data loss is may 5 min
+#if (-f "$logfile.0") {
+# $rotlogfile = $logfile . ".0";
+#} elsif (-f "$logfile.1") {
+# $rotlogfile = $logfile . ".1";
+#} elsif (-f "$logfile.01") {
+# $rotlogfile = $logfile . ".01";
+#} else {
+# $rotlogfile = $logfile . ".0";
+#}
if ( $ARGV[0] and $ARGV[0] eq "config" ) {
print "multigraph dovecot_connections\n";
@@ -179,7 +181,9 @@ if (!defined $pos) {
if ($startsize < $pos) {
# Log rotated
- parseDovecotfile ($rotlogfile, $pos, (stat $rotlogfile)[7]);
+ # Disable rotated log inpection because name is not deterministic across systems
+ # and data loss is may 5 min
+ #parseDovecotfile ($rotlogfile, $pos, (stat $rotlogfile)[7]);
$pos = 0;
}
diff --git a/dovecot/files/z-evolinux-dovecot.conf b/dovecot/files/munin_plugins.conf
similarity index 100%
rename from dovecot/files/z-evolinux-dovecot.conf
rename to dovecot/files/munin_plugins.conf
diff --git a/dovecot/tasks/main.yml b/dovecot/tasks/main.yml
index adb81238..8589a701 100644
--- a/dovecot/tasks/main.yml
+++ b/dovecot/tasks/main.yml
@@ -1,3 +1,5 @@
+---
+
- name: ensure packages are installed
ansible.builtin.apt:
name:
@@ -8,7 +10,7 @@
- dovecot-managesieved
state: present
tags:
- - dovecot
+ - dovecot
- name: Generate 4096 bits Diffie-Hellman parameters (may take several minutes)
community.crypto.openssl_dhparam:
@@ -21,7 +23,7 @@
regexp: "[^#]!include auth-system.conf.ext"
replace: "#!include auth-system.conf.ext"
tags:
- - dovecot
+ - dovecot
- name: update ldap auth
ansible.builtin.lineinfile:
@@ -33,14 +35,15 @@
- { key: 'hosts', value: '127.0.0.1' }
- { key: 'auth_bind', value: 'yes' }
- { key: 'ldap_version', value: 3 }
- - { key: 'base', value: "{{ ldap_suffix }}" }
+ - { key: 'base', value: "{{ ldap_suffix | mandatory }}" }
- { key: 'user_attrs', value: 'homeDirectory=home' }
- { key: 'user_filter', value: '(&(isActive=TRUE)(uid=%u))' }
- { key: 'pass_attrs', value: 'uid=user,userPassword=password' }
- when: ldap_suffix is defined
+ - { key: 'iterate_filter', value: '(&(isActive=TRUE))' }
+ when: ldap_enabled | bool | default(False)
notify: reload dovecot
tags:
- - dovecot
+ - dovecot
- name: create vmail group
ansible.builtin.group:
@@ -48,7 +51,7 @@
gid: "{{ dovecot_vmail_gid }}"
system: True
tags:
- - dovecot
+ - dovecot
- name: create vmail user
ansible.builtin.user:
@@ -58,16 +61,16 @@
shell: /bin/false
system: True
tags:
- - dovecot
+ - dovecot
-- name: deploy evolix config
+- name: deploy evolix config for Dovecot
ansible.builtin.template:
src: z-evolinux-defaults.conf.j2
dest: /etc/dovecot/conf.d/z-evolinux-defaults.conf
mode: "0644"
notify: reload dovecot
tags:
- - dovecot
+ - dovecot
- name: deploy file for custom configuration
ansible.builtin.template:
@@ -76,7 +79,7 @@
mode: "0644"
notify: reload dovecot
tags:
- - dovecot
+ - dovecot
- ansible.builtin.include: munin.yml
tags:
@@ -86,7 +89,8 @@
ansible.builtin.apt:
name: log2mail
state: present
- tags: dovecot
+ tags:
+ - dovecot
- name: dovecot is configured in log2mail
ansible.builtin.blockinfile:
@@ -101,5 +105,6 @@
mailto = {{ log2mail_alert_email or general_alert_email | mandatory }}
template = /etc/log2mail/mail
notify: restart log2mail
- tags: dovecot
+ tags:
+ - dovecot
diff --git a/dovecot/tasks/munin.yml b/dovecot/tasks/munin.yml
index 7227e991..4c3daf4a 100644
--- a/dovecot/tasks/munin.yml
+++ b/dovecot/tasks/munin.yml
@@ -9,15 +9,18 @@
- name: Munin plugins are present and configured
block:
- - name: Disable dovecot plugin
+ - name: Disable Dovecot plugin
ansible.builtin.file:
path: /etc/munin/plugins/dovecot
state: absent
- - name: Remove dovecot plugin conf
+ - name: Remove old Dovecot plugin conf
ansible.builtin.file:
- path: /etc/munin/plugin-conf.d/dovecot
+ path: "/etc/munin/plugin-conf.d/{{ item }}"
state: absent
+ loop:
+ - dovecot
+ - z-evolinux-dovecot
- name: "Remount /usr if needed"
ansible.builtin.include_role:
@@ -46,8 +49,8 @@
- name: Copy Munin config
ansible.builtin.copy:
- src: z-evolinux-dovecot.conf
- dest: /etc/munin/plugin-conf.d/z-evolinux-dovecot
+ src: munin_plugins.conf
+ dest: /etc/munin/plugin-conf.d/zzz-dovecot
mode: '0644'
notify: restart munin-node
diff --git a/etc-git/tasks/repositories.yml b/etc-git/tasks/repositories.yml
index 6c76d265..7745183d 100644
--- a/etc-git/tasks/repositories.yml
+++ b/etc-git/tasks/repositories.yml
@@ -24,14 +24,36 @@
- ansible.builtin.include_role:
name: evolix/remount-usr
when:
- - _usr_share_scripts.stat.isdir
+ - _usr_share_scripts.stat.exists and _usr_share_scripts.stat.isdir
- ansible.builtin.import_tasks: repository.yml
vars:
repository_path: "/usr/share/scripts"
gitignore_items: []
when:
- - _usr_share_scripts.stat.isdir
+ - _usr_share_scripts.stat.exists and _usr_share_scripts.stat.isdir
- ansible_distribution_major_version is version('10', '>=')
tags:
- - etc-git
\ No newline at end of file
+ - etc-git
+
+
+- name: verify /var/chroot-bind/ presence
+ ansible.builtin.stat:
+ path: /var/chroot-bind
+ register: _var_chroot_bind
+ tags:
+ - etc-git
+
+- name: /var/chroot-bind/etc/bind is a safe directory
+ ansible.builtin.shell: git config --global --add safe.directory /var/chroot-bind/etc/bind
+
+- ansible.builtin.import_tasks: repository.yml
+ vars:
+ repository_path: "/var/chroot-bind/etc/bind"
+ gitignore_items: []
+ when:
+ - _var_chroot_bind.stat.exists and _var_chroot_bind.stat.isdir
+ - ansible_distribution_major_version is version('8', '>=')
+ tags:
+ - etc-git
+
diff --git a/evocheck/files/evocheck.jessie.sh b/evocheck/files/evocheck.jessie.sh
index fba55fd5..585dd735 100755
--- a/evocheck/files/evocheck.jessie.sh
+++ b/evocheck/files/evocheck.jessie.sh
@@ -4,7 +4,7 @@
# Script to verify compliance of a Linux (Debian) server
# powered by Evolix
-VERSION="23.10"
+VERSION="24.01"
readonly VERSION
# base functions
diff --git a/evocheck/files/evocheck.sh b/evocheck/files/evocheck.sh
index 89f17aba..f125e713 100755
--- 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="23.10"
+VERSION="24.01"
readonly VERSION
# base functions
@@ -68,6 +68,8 @@ detect_os() {
10) DEBIAN_RELEASE="buster";;
11) DEBIAN_RELEASE="bullseye";;
12) DEBIAN_RELEASE="bookworm";;
+ 13) DEBIAN_RELEASE="trixie";;
+ 14) DEBIAN_RELEASE="forky";;
esac
fi
fi
@@ -85,6 +87,12 @@ is_debian_bullseye() {
is_debian_bookworm() {
test "${DEBIAN_RELEASE}" = "bookworm"
}
+is_debian_trixie() {
+ test "${DEBIAN_RELEASE}" = "trixie"
+}
+is_debian_forky() {
+ test "${DEBIAN_RELEASE}" = "forky"
+}
is_pack_web(){
test -e /usr/share/scripts/web-add.sh || test -e /usr/share/scripts/evoadmin/web-add.sh
@@ -148,13 +156,13 @@ check_dpkgwarning() {
# Check if localhost, localhost.localdomain and localhost.$mydomain are set in Postfix mydestination option.
check_postfix_mydestination() {
# shellcheck disable=SC2016
- if ! grep mydestination /etc/postfix/main.cf | grep --quiet -E 'localhost([[:blank:]]|$)'; then
+ if ! grep mydestination /etc/postfix/main.cf | grep --quiet --extended-regexp 'localhost([[:blank:]]|$)'; then
failed "IS_POSTFIX_MYDESTINATION" "'localhost' is missing in Postfix mydestination option."
fi
- if ! grep mydestination /etc/postfix/main.cf | grep --quiet 'localhost\.localdomain'; then
+ if ! grep mydestination /etc/postfix/main.cf | grep --quiet --fixed-strings 'localhost.localdomain'; then
failed "IS_POSTFIX_MYDESTINATION" "'localhost.localdomain' is missing in Postfix mydestination option."
fi
- if ! grep mydestination /etc/postfix/main.cf | grep --quiet 'localhost\.\$mydomain'; then
+ if ! grep mydestination /etc/postfix/main.cf | grep --quiet --fixed-strings 'localhost.$mydomain'; then
failed "IS_POSTFIX_MYDESTINATION" "'localhost.\$mydomain' is missing in Postfix mydestination option."
fi
}
@@ -193,11 +201,40 @@ check_debiansecurity() {
apt-cache policy | grep "\bl=Debian-Security\b" | grep "\bo=Debian\b" | grep --quiet "\bc=main\b"
test $? -eq 0 || failed "IS_DEBIANSECURITY" "missing Debian-Security repository"
}
+check_debiansecurity_lxc() {
+ if is_installed lxc; then
+ container_list=$(lxc-ls)
+ for container in $container_list; do
+ DEBIAN_LXC_VERSION=$(cut -d "." -f 1 < /var/lib/lxc/${container}/rootfs/etc/debian_version)
+ if [ $DEBIAN_LXC_VERSION -ge 9 ]; then
+ lxc-attach --name $container apt-cache policy | grep "\bl=Debian-Security\b" | grep "\bo=Debian\b" | grep --quiet "\bc=main\b"
+ test $? -eq 0 || failed "IS_DEBIANSECURITY_LXC" "missing Debian-Security repository in container ${container}"
+ fi
+ done
+ fi
+}
+check_backports_version() {
+ # Look for enabled "Debian Backports" sources from the "Debian" origin
+ apt-cache policy | grep "\bl=Debian Backports\b" | grep "\bo=Debian\b" | grep --quiet "\bc=main\b"
+ test $? -eq 1 || ( \
+ apt-cache policy | grep "\bl=Debian Backports\b" | grep --quiet "\bn=${DEBIAN_RELEASE}-backports\b" && \
+ test $? -eq 0 || failed "IS_BACKPORTS_VERSION" "Debian Backports enabled for another release than ${DEBIAN_RELEASE}" )
+}
check_oldpub() {
# Look for enabled pub.evolix.net sources (supersed by pub.evolix.org since Stretch)
apt-cache policy | grep --quiet pub.evolix.net
test $? -eq 1 || failed "IS_OLDPUB" "Old pub.evolix.net repository is still enabled"
}
+check_oldpub_lxc() {
+ # Look for enabled pub.evolix.net sources (supersed by pub.evolix.org since Buster as Sury safeguard)
+ if is_installed lxc; then
+ container_list=$(lxc-ls)
+ for container in $container_list; do
+ lxc-attach --name $container apt-cache policy | grep --quiet pub.evolix.net
+ test $? -eq 1 || failed "IS_OLDPUB_LXC" "Old pub.evolix.net repository is still enabled in container ${container}"
+ done
+ fi
+}
check_newpub() {
# Look for enabled pub.evolix.org sources
apt-cache policy | grep "\bl=Evolix\b" | grep --quiet -v php
@@ -208,7 +245,19 @@ check_sury() {
apt-cache policy | grep --quiet packages.sury.org
if [ $? -eq 0 ]; then
apt-cache policy | grep "\bl=Evolix\b" | grep php --quiet
- test $? -eq 0 || failed "IS_SURY" "packages.sury.org is present but our safeguard pub.evolix.org repository is missing"
+ test $? -eq 0 || failed "IS_SURY" "packages.sury.org is present but our safeguard pub.evolix.org repository is missing"
+ fi
+}
+check_sury_lxc() {
+ if is_installed lxc; then
+ container_list=$(lxc-ls)
+ for container in $container_list; do
+ lxc-attach --name $container apt-cache policy | grep --quiet packages.sury.org
+ if [ $? -eq 0 ]; then
+ lxc-attach --name $container apt-cache policy | grep "\bl=Evolix\b" | grep php --quiet
+ test $? -eq 0 || failed "IS_SURY_LXC" "packages.sury.org is present but our safeguard pub.evolix.org repository is missing in container ${container}"
+ fi
+ done
fi
}
check_aptitude() {
@@ -249,8 +298,15 @@ check_customcrontab() {
test "$found_lines" = 4 && failed "IS_CUSTOMCRONTAB" "missing custom field in crontab"
}
check_sshallowusers() {
- grep -E -qir "(AllowUsers|AllowGroups)" /etc/ssh/sshd_config /etc/ssh/sshd_config.d \
- || failed "IS_SSHALLOWUSERS" "missing AllowUsers or AllowGroups directive in sshd_config"
+ if is_debian_bookworm; then
+ grep -E -qir "(AllowUsers|AllowGroups)" /etc/ssh/sshd_config.d \
+ || failed "IS_SSHALLOWUSERS" "missing AllowUsers or AllowGroups directive in sshd_config.d/*"
+ grep -E -qir "(AllowUsers|AllowGroups)" /etc/ssh/sshd_config \
+ && failed "IS_SSHALLOWUSERS" "AllowUsers or AllowGroups directive present in sshd_config"
+ else
+ grep -E -qir "(AllowUsers|AllowGroups)" /etc/ssh/sshd_config /etc/ssh/sshd_config.d \
+ || failed "IS_SSHALLOWUSERS" "missing AllowUsers or AllowGroups directive in sshd_config"
+ fi
}
check_diskperf() {
perfFile="/root/disk-perf.txt"
@@ -307,7 +363,7 @@ check_minifw() {
} || failed "IS_MINIFW" "minifirewall seems not started"
}
check_minifw_includes() {
- if is_debian_bullseye; then
+ if { ! is_debian_stretch && ! is_debian_buster ; }; then
if grep -q -e '/sbin/iptables' -e '/sbin/ip6tables' "/etc/default/minifirewall"; then
failed "IS_MINIFWINCLUDES" "minifirewall has direct iptables invocations in /etc/default/minifirewall that should go in /etc/minifirewall.d/"
fi
@@ -334,13 +390,13 @@ check_nrpedisks() {
test "$NRPEDISKS" = "$DFDISKS" || failed "IS_NRPEDISKS" "there must be $DFDISKS check_disk in nrpe.cfg"
}
check_nrpepid() {
- if { is_debian_bullseye || is_debian_bookworm ; }; then
+ if { is_debian_stretch || is_debian_buster ; }; then
{ test -e /etc/nagios/nrpe.cfg \
- && grep -q "^pid_file=/run/nagios/nrpe.pid" /etc/nagios/nrpe.cfg;
+ && grep -q "^pid_file=/var/run/nagios/nrpe.pid" /etc/nagios/nrpe.cfg;
} || failed "IS_NRPEPID" "missing or wrong pid_file directive in nrpe.cfg"
else
{ test -e /etc/nagios/nrpe.cfg \
- && grep -q "^pid_file=/var/run/nagios/nrpe.pid" /etc/nagios/nrpe.cfg;
+ && grep -q "^pid_file=/run/nagios/nrpe.pid" /etc/nagios/nrpe.cfg;
} || failed "IS_NRPEPID" "missing or wrong pid_file directive in nrpe.cfg"
fi
}
@@ -550,14 +606,10 @@ check_evobackup_exclude_mount() {
# then we verify that every mount is excluded
if ! grep -q -- "^\s*--one-file-system" "${evobackup_file}"; then
# old releases of evobackups don't have version
- if grep -q "^VERSION=" "${evobackup_file}"; then
- evobackup_version=$(sed -E -n 's/VERSION="(.*)"/\1/p' "${evobackup_file}")
- # versions over 22.12 use a new syntax to exclude rsync files
- if dpkg --compare-versions "$evobackup_version" ge 22.12 ; then
- sed -En '/RSYNC_EXCLUDES="/,/"/ {s/(RSYNC_EXCLUDES=|")//g;p}' > "${excludes_file}"
- else
- grep -- "--exclude " "${evobackup_file}" | grep -E -o "\"[^\"]+\"" | tr -d '"' > "${excludes_file}"
- fi
+ if grep -q "^VERSION=" "${evobackup_file}" && dpkg --compare-versions "$(sed -E -n 's/VERSION="(.*)"/\1/p' "${evobackup_file}")" ge 22.12 ; then
+ sed -En '/RSYNC_EXCLUDES="/,/"/ {s/(RSYNC_EXCLUDES=|")//g;p}' "${evobackup_file}" > "${excludes_file}"
+ else
+ grep -- "--exclude " "${evobackup_file}" | grep -E -o "\"[^\"]+\"" | tr -d '"' > "${excludes_file}"
fi
not_excluded=$(findmnt --type nfs,nfs4,fuse.sshfs, -o target --noheadings | grep -v -f "${excludes_file}")
for mount in ${not_excluded}; do
@@ -611,7 +663,7 @@ check_apacheipinallow() {
check_muninapacheconf() {
muninconf="/etc/apache2/conf-available/munin.conf"
if is_installed apache2; then
- test -e $muninconf && grep -vEq "^( |\t)*#" "$muninconf" \
+ test -e $muninconf && grep --invert-match --extended-regexp --quiet "^( |\t)*#" "$muninconf" \
&& failed "IS_MUNINAPACHECONF" "default munin configuration may be commented or disabled"
fi
}
@@ -620,17 +672,17 @@ check_phpmyadminapacheconf() {
phpmyadminconf0="/etc/apache2/conf-available/phpmyadmin.conf"
phpmyadminconf1="/etc/apache2/conf-enabled/phpmyadmin.conf"
if is_installed apache2; then
- test -e $phpmyadminconf0 && grep -vEq "^( |\t)*#" "$phpmyadminconf0" \
- && failed "IS_PHPMYADMINAPACHECONF" "default phpmyadmin configuration ($phpmyadminconf0) may be commented or disabled"
- test -e $phpmyadminconf1 && grep -vEq "^( |\t)*#" "$phpmyadminconf1" \
- && failed "IS_PHPMYADMINAPACHECONF" "default phpmyadmin configuration ($phpmyadminconf1) may be commented or disabled"
+ test -e $phpmyadminconf0 && grep --invert-match --extended-regexp --quiet "^( |\t)*#" "$phpmyadminconf0" \
+ && failed "IS_PHPMYADMINAPACHECONF" "default phpmyadmin configuration ($phpmyadminconf0) should be commented or disabled"
+ test -e $phpmyadminconf1 && grep --invert-match --extended-regexp --quiet "^( |\t)*#" "$phpmyadminconf1" \
+ && failed "IS_PHPMYADMINAPACHECONF" "default phpmyadmin configuration ($phpmyadminconf1) should be commented or disabled"
fi
}
# Verification si le système doit redémarrer suite màj kernel.
check_kerneluptodate() {
if is_installed linux-image*; then
# shellcheck disable=SC2012
- kernel_installed_at=$(date -d "$(ls --full-time -lcrt /boot | tail -n1 | awk '{print $6}')" +%s)
+ kernel_installed_at=$(date -d "$(ls --full-time -lcrt /boot/*lin* | tail -n1 | awk '{print $6}')" +%s)
last_reboot_at=$(($(date +%s) - $(cut -f1 -d '.' /proc/uptime)))
if [ "$kernel_installed_at" -gt "$last_reboot_at" ]; then
failed "IS_KERNELUPTODATE" "machine is running an outdated kernel, reboot advised"
@@ -697,6 +749,16 @@ check_etcgit() {
git rev-parse --is-inside-work-tree > /dev/null 2>&1 \
|| failed "IS_ETCGIT" "/etc is not a git repository"
}
+check_etcgit_lxc() {
+ if is_installed lxc; then
+ container_list=$(lxc-ls)
+ for container in $container_list; do
+ export GIT_DIR="/var/lib/lxc/${container}/rootfs/etc/.git" GIT_WORK_TREE="/var/lib/lxc/${container}/rootfs/etc"
+ git rev-parse --is-inside-work-tree > /dev/null 2>&1 \
+ || failed "IS_ETCGIT_LXC" "/etc is not a git repository in container ${container}"
+ done
+ fi
+}
# Check if /etc/.git/ has read/write permissions for root only.
check_gitperms() {
GIT_DIR="/etc/.git"
@@ -706,6 +768,19 @@ check_gitperms() {
[ "$expected" = "$actual" ] || failed "IS_GITPERMS" "$GIT_DIR must be $expected"
fi
}
+check_gitperms_lxc() {
+ if is_installed lxc; then
+ container_list=$(lxc-ls)
+ for container in $container_list; do
+ GIT_DIR="/var/lib/lxc/${container}/rootfs/etc/.git"
+ if test -d $GIT_DIR; then
+ expected="700"
+ actual=$(stat -c "%a" $GIT_DIR)
+ [ "$expected" = "$actual" ] || failed "IS_GITPERMS_LXC" "$GIT_DIR must be $expected (in container ${container})"
+ fi
+ done
+ fi
+}
# Check if no package has been upgraded since $limit.
check_notupgraded() {
last_upgrade=0
@@ -813,7 +888,7 @@ check_drbd_two_primaries() {
failed "IS_DRBDTWOPRIMARIES" "Some DRBD ressources have two primaries, you risk a split brain!"
fi
elif command -v drbdadm >/dev/null; then
- if drbdadm status | grep Primary -A2 | grep peer | grep -q Primary; then
+ if drbdadm role all 2>&1 | grep -q 'Primary/Primary'; then
failed "IS_DRBDTWOPRIMARIES" "Some DRBD ressources have two primaries, you risk a split brain!"
fi
fi
@@ -824,7 +899,7 @@ check_broadcomfirmware() {
if [ -x "${LSPCI_BIN}" ]; then
if ${LSPCI_BIN} | grep -q 'NetXtreme II'; then
{ is_installed firmware-bnx2 \
- && grep -q "^deb http://mirror.evolix.org/debian.* non-free" /etc/apt/sources.list;
+ && apt-cache policy | grep "\bl=Debian\b" | grep --quiet -v "\b,c=non-free\b"
} || failed "IS_BROADCOMFIRMWARE" "missing non-free repository"
fi
else
@@ -1000,6 +1075,7 @@ check_phpevolinuxconf() {
is_debian_stretch && phpVersion="7.0"
is_debian_buster && phpVersion="7.3"
is_debian_bullseye && phpVersion="7.4"
+ is_debian_bookworm && phpVersion="8.2"
if is_installed php; then
{ test -f "/etc/php/${phpVersion}/cli/conf.d/z-evolinux-defaults.ini" \
&& test -f "/etc/php/${phpVersion}/cli/conf.d/zzz-evolinux-custom.ini"
@@ -1131,16 +1207,10 @@ check_usrsharescripts() {
test "$expected" = "$actual" || failed "IS_USRSHARESCRIPTS" "/usr/share/scripts must be $expected"
}
check_sshpermitrootno() {
- sshd_args="-C addr=,user=,host=,laddr=,lport=0"
- if is_debian_stretch; then
- # Noop, we'll use the default $sshd_args
- :
- elif is_debian_buster; then
+ # You could change the SSH port in /etc/evocheck.cf
+ sshd_args="-C addr=,user=,host=,laddr=,lport=${SSH_PORT:-22}"
+ if is_debian_buster; then
sshd_args="${sshd_args},rdomain="
- else
- # NOTE: From Debian Bullseye 11 onward, with OpenSSH 8.1, the argument
- # -T doesn't require the additional -C.
- sshd_args=
fi
# shellcheck disable=SC2086
if ! (sshd -T ${sshd_args} 2> /dev/null | grep -qi 'permitrootlogin no'); then
@@ -1261,7 +1331,7 @@ check_lxc_container_resolv_conf() {
container_list=$(lxc-ls)
current_resolvers=$(grep nameserver /etc/resolv.conf | sed 's/nameserver//g' )
- for container in $container_list; do
+ for container in $container_list; do
if [ -f "/var/lib/lxc/${container}/rootfs/etc/resolv.conf" ]; then
while read -r resolver; do
@@ -1307,6 +1377,34 @@ check_lxc_php_fpm_service_umask_set() {
fi
fi
}
+# Check that LXC containers have the proper Debian version.
+check_lxc_php_bad_debian_version() {
+ if is_installed lxc; then
+ php_containers_list=$(lxc-ls --filter php)
+ missing_umask=""
+ for container in $php_containers_list; do
+ if [ "$container" = "php56" ]; then
+ grep --quiet 'VERSION_ID="8"' /var/lib/lxc/${container}/rootfs/etc/os-release || failed "IS_LXC_PHP_BAD_DEBIAN_VERSION" "Container ${container} should use Jessie"
+ elif [ "$container" = "php70" ]; then
+ grep --quiet 'VERSION_ID="9"' /var/lib/lxc/${container}/rootfs/etc/os-release || failed "IS_LXC_PHP_BAD_DEBIAN_VERSION" "Container ${container} should use Stretch"
+ elif [ "$container" = "php73" ]; then
+ grep --quiet 'VERSION_ID="10"' /var/lib/lxc/${container}/rootfs/etc/os-release || failed "IS_LXC_PHP_BAD_DEBIAN_VERSION" "Container ${container} should use Buster"
+ elif [ "$container" = "php74" ]; then
+ grep --quiet 'VERSION_ID="11"' /var/lib/lxc/${container}/rootfs/etc/os-release || failed "IS_LXC_PHP_BAD_DEBIAN_VERSION" "Container ${container} should use Bullseye"
+ elif [ "$container" = "php82" ]; then
+ grep --quiet 'VERSION_ID="12"' /var/lib/lxc/${container}/rootfs/etc/os-release || failed "IS_LXC_PHP_BAD_DEBIAN_VERSION" "Container ${container} should use Bookworm"
+ fi
+ done
+ fi
+}
+check_lxc_openssh() {
+ if is_installed lxc; then
+ container_list=$(lxc-ls)
+ for container in $container_list; do
+ test -e /var/lib/lxc/${container}/rootfs/usr/sbin/sshd && failed "IS_LXC_OPENSSH" "openssh-server should not be installed in container ${container}"
+ done
+ fi
+}
download_versions() {
local file
@@ -1460,9 +1558,13 @@ main() {
test "${IS_LOGROTATECONF:=1}" = 1 && check_logrotateconf
test "${IS_SYSLOGCONF:=1}" = 1 && check_syslogconf
test "${IS_DEBIANSECURITY:=1}" = 1 && check_debiansecurity
+ test "${IS_DEBIANSECURITY_LXC:=1}" = 1 && check_debiansecurity_lxc
+ test "${IS_BACKPORTS_VERSION:=1}" = 1 && check_backports_version
test "${IS_OLDPUB:=1}" = 1 && check_oldpub
+ test "${IS_OLDPUB_LXC:=1}" = 1 && check_oldpub_lxc
test "${IS_NEWPUB:=1}" = 1 && check_newpub
test "${IS_SURY:=1}" = 1 && check_sury
+ test "${IS_SURY_LXC:=1}" = 1 && check_sury_lxc
test "${IS_APTITUDE:=1}" = 1 && check_aptitude
test "${IS_APTGETBAK:=1}" = 1 && check_aptgetbak
test "${IS_USRRO:=1}" = 1 && check_usrro
@@ -1515,7 +1617,9 @@ main() {
test "${IS_MUNINRUNNING:=1}" = 1 && check_muninrunning
test "${IS_BACKUPUPTODATE:=1}" = 1 && check_backupuptodate
test "${IS_ETCGIT:=1}" = 1 && check_etcgit
+ test "${IS_ETCGIT_LXC:=1}" = 1 && check_etcgit_lxc
test "${IS_GITPERMS:=1}" = 1 && check_gitperms
+ test "${IS_GITPERMS_LXC:=1}" = 1 && check_gitperms_lxc
test "${IS_NOTUPGRADED:=1}" = 1 && check_notupgraded
test "${IS_TUNE2FS_M5:=1}" = 1 && check_tune2fs_m5
test "${IS_EVOLINUXSUDOGROUP:=1}" = 1 && check_evolinuxsudogroup
@@ -1557,6 +1661,8 @@ main() {
test "${IS_LXC_CONTAINER_RESOLV_CONF:=1}" = 1 && check_lxc_container_resolv_conf
test "${IS_NO_LXC_CONTAINER:=1}" = 1 && check_no_lxc_container
test "${IS_LXC_PHP_FPM_SERVICE_UMASK_SET:=1}" = 1 && check_lxc_php_fpm_service_umask_set
+ test "${IS_LXC_PHP_BAD_DEBIAN_VERSION:=1}" = 1 && check_lxc_php_bad_debian_version
+ test "${IS_LXC_OPENSSH:=1}" = 1 && check_lxc_openssh
test "${IS_CHECK_VERSIONS:=1}" = 1 && check_versions
if [ -f "${main_output_file}" ]; then
@@ -1572,7 +1678,7 @@ main() {
}
cleanup() {
# Cleanup tmp files
- # shellcheck disable=SC2086,SC2317
+ # shellcheck disable=SC2068,SC2317
rm -f ${files_to_cleanup[@]}
log "$PROGNAME exit."
diff --git a/evocheck/files/evocheck.wheezy.sh b/evocheck/files/evocheck.wheezy.sh
index 3bbcc1f1..726a364f 100755
--- a/evocheck/files/evocheck.wheezy.sh
+++ b/evocheck/files/evocheck.wheezy.sh
@@ -4,7 +4,7 @@
# Script to verify compliance of a Linux (Debian) server
# powered by Evolix
-VERSION="23.10"
+VERSION="24.01"
readonly VERSION
# base functions
diff --git a/evolinux-base/defaults/main.yml b/evolinux-base/defaults/main.yml
index f92fa90b..97f5540e 100644
--- a/evolinux-base/defaults/main.yml
+++ b/evolinux-base/defaults/main.yml
@@ -159,12 +159,10 @@ evolinux_root_disable_ssh: False
# postfix
evolinux_postfix_include: True
-
-evolinux_postfix_packages: True
+evolinux_mail_aliases_include: True
evolinux_postfix_users_alias_root: True
evolinux_postfix_mailer_alias_root: True
evolinux_postfix_root_alias: True
-evolinux_postfix_purge_exim: True
# logs
@@ -211,6 +209,10 @@ evolinux_munin_include: True
evolinux_nagios_nrpe_include: True
+# check_free_space
+
+evolinux_check_free_space_include: True
+
# fail2ban
evolinux_fail2ban_include: False
@@ -235,3 +237,6 @@ evolinux_motd_include: True
# Utils
evolinux_utils_include: True
+
+# Autosysadmin
+evolinux_autosysadmin_include: false
diff --git a/evolinux-base/files/cert.sh b/evolinux-base/files/cert.sh
new file mode 100644
index 00000000..f43a9dad
--- /dev/null
+++ b/evolinux-base/files/cert.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+#
+# Shortcut to show certificate content or enddate.
+#
+
+usage() {
+ echo "Usage : cert [date] "
+}
+
+if [ "$#" -eq 1 ]; then
+ cert_path=$1
+ if [ -f "${cert_path}" ]; then
+ openssl x509 -noout -in "${cert_path}" -text
+ else
+ >&2 echo "Error, file ${cert_path} does not exist."
+ fi
+
+elif [ "$#" -eq 2 ]; then
+ if [ "$1" = "date" ]; then
+ cert_path=$2
+ if [ -f "${cert_path}" ]; then
+ openssl x509 -noout -in "$cert_path" -enddate
+ else
+ >&2 echo "Error, file ${cert_path} does not exist."
+ fi
+ else
+ >&2 echo "Error, two arguments provided but 'date' is only allowed as first."
+ usage
+ exit 1
+ fi
+
+else
+ >&2 echo "Error, more than two arguments provided."
+ usage
+ exit 1
+fi
+
diff --git a/evolinux-base/tasks/hardware.yml b/evolinux-base/tasks/hardware.yml
index 30badf70..b4280e09 100644
--- a/evolinux-base/tasks/hardware.yml
+++ b/evolinux-base/tasks/hardware.yml
@@ -6,11 +6,11 @@
tags:
- packages
-- name: firmware-non-free components are installed (Debian 12+)
+- name: non-free-firmware components are installed (Debian 12+)
ansible.builtin.replace:
dest: /etc/apt/sources.list.d/system.sources
- regexp: '^(Components: ((?!\bfirmware-non-free\b).)*)$'
- replace: '\1 firmware-non-free'
+ regexp: '^(Components: ((?!\bnon-free-firmware\b).)*)$'
+ replace: '\1 non-free-firmware'
when:
- ansible_distribution_major_version is version('12', '>=')
@@ -48,6 +48,7 @@
- firmware-linux-nonfree
- intel-microcode
state: present
+ update_cache: True
tags:
- packages
diff --git a/evolinux-base/tasks/kernel.yml b/evolinux-base/tasks/kernel.yml
index 231ec02f..148c72df 100644
--- a/evolinux-base/tasks/kernel.yml
+++ b/evolinux-base/tasks/kernel.yml
@@ -9,6 +9,7 @@
- ansible_machine == "x86_64"
- ansible_virtualization_role == "guest"
- evolinux_kernel_cloud_auto | bool
+ - ansible_distribution_major_version is version('10', '>=')
- name: "Remove non-Cloud kernel on virtual servers"
ansible.builtin.apt:
diff --git a/evolinux-base/tasks/postfix.yml b/evolinux-base/tasks/mail_aliases.yml
similarity index 52%
rename from evolinux-base/tasks/postfix.yml
rename to evolinux-base/tasks/mail_aliases.yml
index d9dba3e2..4007d415 100644
--- a/evolinux-base/tasks/postfix.yml
+++ b/evolinux-base/tasks/mail_aliases.yml
@@ -1,36 +1,5 @@
---
-- name: Postfix packages are installed
- ansible.builtin.apt:
- name:
- - postfix
- - mailgraph
- state: present
- tags:
- - packages
- - postfix
- when: evolinux_postfix_packages | bool
-
-- name: configure postfix myhostname
- ansible.builtin.lineinfile:
- dest: /etc/postfix/main.cf
- state: present
- line: "myhostname = {{ evolinux_fqdn }}"
- regexp: '^myhostname'
- notify: reload postfix
- tags:
- - postfix
-
-- name: configure postfix mynetworks
- ansible.builtin.lineinfile:
- dest: /etc/postfix/main.cf
- state: present
- line: "mydestination = {{ [evolinux_fqdn, evolinux_internal_fqdn] | unique | join(' ') }} localhost.localdomain localhost localhost.$mydomain"
- regexp: '^mydestination'
- notify: reload postfix
- tags:
- - postfix
-
- name: fetch users list
ansible.builtin.shell:
cmd: "set -o pipefail && getent passwd | cut -d':' -f 1 | grep -v root"
@@ -81,18 +50,3 @@
- ansible.builtin.meta: flush_handlers
-- name: exim4 is absent
- ansible.builtin.apt:
- name:
- - exim4
- - exim4-base
- - exim4-config
- - exim4-daemon-light
- purge: yes
- state: absent
- tags:
- - packages
- - postfix
- when: evolinux_postfix_purge_exim | bool
-
-- ansible.builtin.meta: flush_handlers
diff --git a/evolinux-base/tasks/main.yml b/evolinux-base/tasks/main.yml
index 582bcfe0..456207df 100644
--- a/evolinux-base/tasks/main.yml
+++ b/evolinux-base/tasks/main.yml
@@ -81,9 +81,16 @@
ansible.builtin.import_tasks: root.yml
when: evolinux_root_include | bool
-- name: Postfix
- ansible.builtin.import_tasks: postfix.yml
+- name: Postfix role
+ ansible.builtin.include_role:
+ name: evolix/postfix
when: evolinux_postfix_include | bool
+ tags:
+ - postfix
+
+- name: Configure /etc/aliases
+ ansible.builtin.import_tasks: mail_aliases.yml
+ when: evolinux_mail_aliases_include | bool
- name: Logs management
ansible.builtin.import_tasks: logs.yml
@@ -127,6 +134,29 @@
name: evolix/nagios-nrpe
when: evolinux_nagios_nrpe_include | bool
+- name: check_free_space
+ ansible.builtin.include_role:
+ name: evolix/check_free_space
+ when: evolinux_check_free_space_include | bool
+
+# postfix role must be after nagios-nrpe role
+- name: Postfix role
+ ansible.builtin.include_role:
+ name: evolix/postfix
+ when: evolinux_postfix_include | bool
+ tags:
+ - postfix
+
+- name: Autosysadmin (agent)
+ ansible.builtin.include_role:
+ name: 'evolix/autosysadmin-agent'
+ when: evolinux_autosysadmin_include | bool
+
+- name: Autosysadmin (restart_nrpe)
+ ansible.builtin.include_role:
+ name: 'evolix/autosysadmin-restart_nrpe'
+ when: evolinux_autosysadmin_include | bool
+
- name: fail2ban
ansible.builtin.include_role:
name: evolix/fail2ban
diff --git a/evolinux-base/tasks/system.yml b/evolinux-base/tasks/system.yml
index 52766796..96a77a70 100644
--- a/evolinux-base/tasks/system.yml
+++ b/evolinux-base/tasks/system.yml
@@ -214,3 +214,16 @@
- grep_hotplug_eni.rc == 0
- ansible.builtin.meta: flush_handlers
+
+# Htop / top config
+
+- name: Deploy htop configuration
+ ansible.builtin.copy:
+ src: htoprc
+ dest: /etc/htoprc
+ mode: "0644"
+
+- name: Deploy top configuration file
+ ansible.builtin.file:
+ path: /etc/topdefaultrc
+ state: absent
\ No newline at end of file
diff --git a/evolinux-base/tasks/utils.yml b/evolinux-base/tasks/utils.yml
index e3477d08..b9b76e3b 100644
--- a/evolinux-base/tasks/utils.yml
+++ b/evolinux-base/tasks/utils.yml
@@ -23,14 +23,3 @@
owner: root
group: root
mode: "0755"
-
-- name: Deploy htop configuration
- ansible.builtin.copy:
- src: htoprc
- dest: /etc/htoprc
- mode: "0644"
-
-- name: Deploy top configuration file
- ansible.builtin.file:
- path: /etc/topdefaultrc
- state: absent
diff --git a/evolinux-base/templates/hardware/hwraid.le-vert.net.sources.j2 b/evolinux-base/templates/hardware/hwraid.le-vert.net.sources.j2
index 9d424a5b..8fbc2d84 100644
--- a/evolinux-base/templates/hardware/hwraid.le-vert.net.sources.j2
+++ b/evolinux-base/templates/hardware/hwraid.le-vert.net.sources.j2
@@ -4,5 +4,5 @@ Types: deb
URIs: http://hwraid.le-vert.net/debian
Suites: {{ ansible_distribution_release }}
Components: main
-Signed-by: {{ apt_keyring_dir }}/hwraid.le-vert.net.asc]
+Signed-by: {{ apt_keyring_dir }}/hwraid.le-vert.net.asc
Enabled: yes
diff --git a/evolinux-base/templates/log2mail/evolinux-defaults.j2 b/evolinux-base/templates/log2mail/evolinux-defaults.j2
index c030ed41..e5e15d10 100644
--- a/evolinux-base/templates/log2mail/evolinux-defaults.j2
+++ b/evolinux-base/templates/log2mail/evolinux-defaults.j2
@@ -8,4 +8,9 @@ template = /etc/log2mail/mail
file = /var/log/syslog
pattern = "memory read error"
mailto = {{ log2mail_alert_email or general_alert_email | mandatory }}
-template = /etc/log2mail/mail
\ No newline at end of file
+template = /etc/log2mail/mail
+
+file = /var/log/cron.log
+pattern = "Syntax error"
+mailto = {{ log2mail_alert_email or general_alert_email | mandatory }}
+template = /etc/log2mail/mail
diff --git a/evolinux-users/templates/sudoers.j2 b/evolinux-users/templates/sudoers.j2
index 60b5b782..0e8471bf 100644
--- a/evolinux-users/templates/sudoers.j2
+++ b/evolinux-users/templates/sudoers.j2
@@ -15,6 +15,7 @@ nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_phpfpm_multi
nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_phpfpm_multi /var/lib/lxc/php80/rootfs/etc/php/8.0/fpm/pool.d/
nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_phpfpm_multi /var/lib/lxc/php81/rootfs/etc/php/8.1/fpm/pool.d/
nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_phpfpm_multi /var/lib/lxc/php82/rootfs/etc/php/8.2/fpm/pool.d/
+nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_phpfpm_multi /var/lib/lxc/php83/rootfs/etc/php/8.3/fpm/pool.d/
nagios ALL = NOPASSWD: /usr/sbin/megaclisas-status --nagios
nagios ALL = NOPASSWD: /usr/lib/nagios/plugins/check_ipmi_sensor
nagios ALL = NOPASSWD: /sbin/dmsetup status --noflush
diff --git a/fail2ban/files/unban_ip.sh b/fail2ban/files/unban_ip.sh
new file mode 100644
index 00000000..c13f2ecd
--- /dev/null
+++ b/fail2ban/files/unban_ip.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+function version_gt() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; }
+
+IP="$1"
+if [ "$IP" == "" ]; then
+ echo
+ echo -e "\033${TERM_COLOR_LIGHT_RED}Usage: $FUNCNAME \033${TERM_COLOR_NORMAL}"
+ echo
+ cat <&1 | grep -v "$IP is not banned";
+ else
+ iptables -D f2b-$JAIL -s $IP -j DROP 2>&1 | grep -v 'iptables: Bad rule' && sleep 5 || echo "$IP is not banned";
+ fi
+done
+
+exit 0
+
diff --git a/fail2ban/tasks/main.yml b/fail2ban/tasks/main.yml
index 1629a02a..eabd0f36 100644
--- a/fail2ban/tasks/main.yml
+++ b/fail2ban/tasks/main.yml
@@ -94,7 +94,7 @@
- name: "Extend dbpurgeage if recidive jail is enabled"
ansible.builtin.blockinfile:
dest: /etc/fail2ban/fail2ban.d/recidive_dbpurgeage
- marker: "# ANSIBLE MANAGED"
+ marker: "# {mark} ANSIBLE MANAGED"
block: |
[DEFAULT]
dbpurgeage = {{ fail2ban_recidive_bantime }}
@@ -111,3 +111,12 @@
- ansible_distribution_release == "stretch" or ansible_distribution_release == "buster"
tags:
- fail2ban
+
+- name: Script unban_ip is installed
+ ansible.builtin.copy:
+ src: unban_ip.sh
+ dest: /usr/local/sbin/unban_ip
+ mode: '0700'
+ tags:
+ - fail2ban
+
diff --git a/filebeat/handlers/main.yml b/filebeat/handlers/main.yml
index 8456ee33..c5f7001f 100644
--- a/filebeat/handlers/main.yml
+++ b/filebeat/handlers/main.yml
@@ -4,4 +4,3 @@
ansible.builtin.systemd:
name: filebeat
state: restarted
- when: not ansible_check_mode
diff --git a/generate-ldif/templates/generateldif.sh.j2 b/generate-ldif/templates/generateldif.sh.j2
index 7e35ff5a..39fc30cf 100755
--- a/generate-ldif/templates/generateldif.sh.j2
+++ b/generate-ldif/templates/generateldif.sh.j2
@@ -14,6 +14,7 @@ get_pkg_version() {
sed 's/[~+-].\+//' | sed 's/.\+://' | sed 's/p.*//' | cut -d'.' -f1,2
}
+debianVersion=$(cut -d "." -f 1 < /etc/debian_version)
clientNumber="{{ client_number | mandatory }}"
monitoringMode="{{ monitoring_mode | mandatory }}"
monitoringType="{{ monitoring_type | mandatory }}"
@@ -699,6 +700,20 @@ ServiceVersion: PHP-FPM 8.2 (multiphp)
EOT
fi
+if lxc-ls | grep -q php83 ; then
+ cat <> "${ldif_file}"
+
+dn: ServiceName=php-fpm83,${computer_dn}
+NagiosEnabled: TRUE
+ipServiceProtocol: tcp
+objectClass: EvoService
+ServiceName: php-fpm83
+ipServicePort: 443
+ServiceType: web
+ServiceVersion: PHP-FPM 8.3 (multiphp)
+EOT
+fi
+
fi
# END - LXC (multiphp)
@@ -749,6 +764,32 @@ ServiceVersion: Undefined
EOT
fi
+# Check pressure
+if [ "${debianVersion}" -ge 12 ]; then
+ cat <> "${ldif_file}"
+
+dn: ServiceName=pressure_cpu,${computer_dn}
+objectClass: EvoService
+NagiosEnabled: TRUE
+ServiceName: pressure_cpu
+ServiceType: pressure
+ServiceVersion: Undefined
+
+dn: ServiceName=pressure_io,${computer_dn}
+objectClass: EvoService
+NagiosEnabled: TRUE
+ServiceName: pressure_io
+ServiceType: pressure
+ServiceVersion: Undefined
+
+dn: ServiceName=pressure_mem,${computer_dn}
+objectClass: EvoService
+NagiosEnabled: TRUE
+ServiceName: pressure_mem
+ServiceType: pressure
+ServiceVersion: Undefined
+EOT
+fi
# test if we have a stdout
if [ -t 1 ]; then
diff --git a/keepalived/tasks/main.yml b/keepalived/tasks/main.yml
index 30f9557a..3f436d0e 100644
--- a/keepalived/tasks/main.yml
+++ b/keepalived/tasks/main.yml
@@ -8,7 +8,7 @@
- keepalived
- name: Add notify.sh script for NRPE check
- ansible.builtin.file:
+ ansible.builtin.copy:
src: notify.sh
dest: /etc/keepalived/notify.sh
mode: "0755"
@@ -21,7 +21,7 @@
- nrpe
- name: check_keepalived is installed
- ansible.builtin.file:
+ ansible.builtin.copy:
src: check_keepalived
dest: /usr/local/lib/nagios/plugins/check_keepalived
mode: "0755"
diff --git a/kvm-host/defaults/main.yml b/kvm-host/defaults/main.yml
index 574c249f..981f2429 100644
--- a/kvm-host/defaults/main.yml
+++ b/kvm-host/defaults/main.yml
@@ -3,4 +3,12 @@ kvm_custom_libvirt_images_path: ''
kvm_install_drbd: True
kvm_scripts_dir: /usr/local/sbin
-kvm_pair: null
\ No newline at end of file
+kvm_pair: null
+
+# A "r|.*/|" is always added in order to make this an allowlist
+# Default = all sata/scsi disks + all nvme + all md (+partitions)
+lvm_filter:
+ - '"a|^/dev/sd[a-zA-Z]+[0-9]*$|"'
+ - '"a|^/dev/nvme[0-9]+(n[0-9]+)?(p[0-9]+)?$|"'
+ - '"a|^/dev/md[0-9]+$|"'
+kvm_drbd_interface: null
diff --git a/kvm-host/files/add-vm.sh b/kvm-host/files/add-vm.sh
index 6ded1103..2dbe0ff2 100755
--- a/kvm-host/files/add-vm.sh
+++ b/kvm-host/files/add-vm.sh
@@ -231,7 +231,7 @@ EOT
if ! isDryRun; then
sleep 5
- drbdadm status | tail -4
+ ( drbdadm status || drbd-overview ) 2>/dev/null | tail -4
drbdDiskPath="/dev/drbd/by-res/${vmName}/0"
if ! [ -b "${drbdDiskPath}" ]; then
diff --git a/kvm-host/files/kvmstats.sh b/kvm-host/files/kvmstats.sh
index 0258b322..d8e27b81 100755
--- a/kvm-host/files/kvmstats.sh
+++ b/kvm-host/files/kvmstats.sh
@@ -57,7 +57,7 @@ BEGIN {
if (!mem)
mem = $2
}
-/block\.[0-9]+\.physical/ {
+/block\.[0-9]+\.capacity/ {
disksize += $2
}
/state\.state/ {
diff --git a/kvm-host/handlers/main.yml b/kvm-host/handlers/main.yml
index 5ca5295a..963105f9 100644
--- a/kvm-host/handlers/main.yml
+++ b/kvm-host/handlers/main.yml
@@ -3,3 +3,11 @@
ansible.builtin.service:
name: munin-node
state: restarted
+
+- name: Update initramfs
+ ansible.builtin.command:
+ argv:
+ - '/usr/sbin/update-initramfs'
+ - '-k'
+ - 'all'
+ - '-u'
\ No newline at end of file
diff --git a/kvm-host/tasks/firewall.yml b/kvm-host/tasks/firewall.yml
new file mode 100644
index 00000000..328d045c
--- /dev/null
+++ b/kvm-host/tasks/firewall.yml
@@ -0,0 +1,9 @@
+---
+- name: Allow all traffic through DRBD interface
+ ansible.builtin.lineinfile:
+ path: /etc/minifirewall.d/drbd
+ line: "/sbin/iptables -I INPUT -p tcp -i {{ kvm_drbd_interface }} -j ACCEPT"
+ create: yes
+ when:
+ - kvm_drbd_interface is defined
+ - kvm_drbd_interface | length > 0
diff --git a/kvm-host/tasks/lvm.yml b/kvm-host/tasks/lvm.yml
new file mode 100644
index 00000000..41b12b2d
--- /dev/null
+++ b/kvm-host/tasks/lvm.yml
@@ -0,0 +1,37 @@
+---
+
+- name: 'Figure out if /etc/lvm/lvm.conf exists'
+ ansible.builtin.stat:
+ path: '/etc/lvm/lvm.conf'
+ follow: true
+ get_checksum: false
+ get_mime: false
+ get_attributes: false
+ ignore_errors: true
+ register: lvm_conf_stat
+
+- name: Add LVM filter
+ ansible.builtin.lineinfile:
+ path: '/etc/lvm/lvm.conf'
+ insertafter: '# Configuration option devices/filter.'
+ regexp: '^\s*(#\s*)?filter\s*=\s*\[.*\]'
+ line: " filter = [ {{ lvm_filter | list | join(', ') }}, \"r|.*/|\" ]"
+ state: present
+ firstmatch: true
+ notify: 'Update initramfs'
+ when:
+ - lvm_conf_stat is succeeded
+ - lvm_conf_stat.stat.exists | bool
+
+- name: Add LVM global_filter
+ ansible.builtin.lineinfile:
+ path: '/etc/lvm/lvm.conf'
+ insertafter: '# Configuration option devices/global_filter.'
+ regexp: '^\s*(#\s*)?global_filter\s*=\s*\[.*\]'
+ line: " global_filter = [ {{ lvm_filter | list | join(', ') }}, \"r|.*/|\" ]"
+ state: present
+ firstmatch: true
+ notify: 'Update initramfs'
+ when:
+ - lvm_conf_stat is succeeded
+ - lvm_conf_stat.stat.exists | bool
diff --git a/kvm-host/tasks/main.yml b/kvm-host/tasks/main.yml
index c6004b7b..ae0108cd 100644
--- a/kvm-host/tasks/main.yml
+++ b/kvm-host/tasks/main.yml
@@ -4,6 +4,8 @@
name: evolix/drbd
when: kvm_install_drbd
+- ansible.builtin.import_tasks: lvm.yml
+
## TODO: check why it's disabled
- ansible.builtin.include: ssh.yml
@@ -14,3 +16,5 @@
- ansible.builtin.include: images.yml
- ansible.builtin.include: tools.yml
+
+- ansible.builtin.include: firewall.yml
diff --git a/ldap/tasks/nagios.yml b/ldap/tasks/nagios.yml
index 58120baa..1fa17241 100644
--- a/ldap/tasks/nagios.yml
+++ b/ldap/tasks/nagios.yml
@@ -50,8 +50,8 @@
mode: "0640"
loop:
- { option: 'hostname', value: '127.0.0.1' }
- - { option: 'base', value: "{{ ldap_suffix }}" }
- - { option: 'bind', value: "cn=nagios,ou=ldapusers,{{ ldap_suffix }}" }
+ - { option: 'base', value: "{{ ldap_suffix | mandatory }}" }
+ - { option: 'bind', value: "cn=nagios,ou=ldapusers,{{ ldap_suffix | mandatory }}" }
- { option: 'pass', value: "{{ ldap_nagios_password }}" }
when: not nagios_monitoring_plugins_path.stat.exists
@@ -73,4 +73,4 @@
ansible.builtin.command:
cmd: "slappasswd -s {{ ldap_nagios_password }}"
register: ldap_nagios_password_ssha
- changed_when: False
\ No newline at end of file
+ changed_when: False
diff --git a/listupgrade/files/old-kernel-autoremoval.sh b/listupgrade/files/old-kernel-autoremoval.sh
index ce1c6002..6ad762e1 100644
--- a/listupgrade/files/old-kernel-autoremoval.sh
+++ b/listupgrade/files/old-kernel-autoremoval.sh
@@ -4,7 +4,7 @@
# fork by reg from /etc/kernel/postinst.d/apt-auto-removal script
-VERSION="21.10"
+VERSION="24.01"
readonly VERSION
PROGNAME=$(basename "$0")
@@ -13,7 +13,7 @@ show_version() {
cat <,
+Copyright 2018-2024 Evolix ,
Gregory Colpart ,
Romain Dessort ,
Ludovic Poujol ,
@@ -105,7 +105,7 @@ main() {
echo "BEFORE"
dpkg -l | grep linux-image
- dpkg --get-selections | tr '\t' ' ' | cut -d" " -f1 | grep '^linux-image-[234]' | grep -v -E "(${kernels})" | xargs --no-run-if-empty ${APT} -o Dir::State::Lists="${listupgrade_state_dir}" -y purge
+ dpkg --get-selections | tr '\t' ' ' | cut -d" " -f1 | grep '^linux-image-[0-9]' | grep -v -E "(${kernels})" | xargs --no-run-if-empty ${APT} -o Dir::State::Lists="${listupgrade_state_dir}" -y purge
echo "
AFTER"
diff --git a/listupgrade/tasks/main.yml b/listupgrade/tasks/main.yml
index dec4881d..9261b3fa 100644
--- a/listupgrade/tasks/main.yml
+++ b/listupgrade/tasks/main.yml
@@ -45,6 +45,12 @@
owner: root
group: root
+- name: Remove old lisupgrade typo
+ ansible.builtin.cron:
+ name: "lisupgrade.sh"
+ cron_file: "listupgrade"
+ state: absent
+
- name: Enable listupgrade cron
ansible.builtin.cron:
name: "listupgrade.sh"
diff --git a/lxc-php/defaults/main.yml b/lxc-php/defaults/main.yml
index c0612f4e..561a11f3 100644
--- a/lxc-php/defaults/main.yml
+++ b/lxc-php/defaults/main.yml
@@ -13,6 +13,7 @@ php_conf_mysql_socket_dir: /mysqld
php_conf_mysql_default_socket: "{{ php_conf_mysql_socket_dir }}/mysqld.sock"
lxc_php_version: Null
+lxc_php_container_name: "{{ lxc_php_version }}"
lxc_php_container_releases:
php56: "jessie"
@@ -22,6 +23,7 @@ lxc_php_container_releases:
php80: "bullseye"
php81: "bullseye"
php82: "bookworm"
+ php83: "bookworm"
lxc_php_services:
php56: 'php5-fpm.service'
@@ -31,6 +33,7 @@ lxc_php_services:
php80: 'php8.0-fpm.service'
php81: 'php8.1-fpm.service'
php82: 'php8.2-fpm.service'
+ php83: 'php8.3-fpm.service'
apt_keyring_dir: "{{ ansible_distribution_major_version is version('12', '<') | ternary('/etc/apt/trusted.gpg.d', '/etc/apt/keyrings') }}"
apt_basics_components: "{{ (ansible_virtualization_role == 'host') | ternary('main contrib non-free', 'main') }}"
diff --git a/lxc-php/files/munin_php-fpm b/lxc-php/files/munin_php-fpm
new file mode 100755
index 00000000..3647767d
--- /dev/null
+++ b/lxc-php/files/munin_php-fpm
@@ -0,0 +1,234 @@
+#!/usr/bin/php
+
+ 0,
+ 'memory' => 0,
+ 'cpu' => 0,
+ 'time' => 0
+ );
+ }
+
+ //add values
+ $groups[$groupName]['count']++;
+ $groups[$groupName]['cpu'] += $cpu;
+ $groups[$groupName]['time'] += timeToSeconds($time);
+ $groups[$groupName]['memory'] += $ram / 1024;
+}
+foreach ($php_inactive_pools_list as $line) {
+ //split fields
+ $line = trim($line);
+ $groupName = $line;
+ //add group
+ if (!isset($groups[$groupName])) {
+ $groups[$groupName] = array(
+ 'count' => 0,
+ 'memory' => 0,
+ 'cpu' => 0,
+ 'time' => 0
+ );
+ }
+}
+
+//check args
+if(!isset($argv) || !isset($argv[0])) {
+ die("Error: No Plugin name provided\n");
+}
+
+$isConfig = isset($argv[1]) && $argv[1] == 'config';
+
+//which plugin?
+switch ($plugin_output) {
+// ------------------------------------------------------
+ case 'memory':
+// ------------------------------------------------------
+ $elements = array();
+ foreach ($groups as $name=>$array) {
+ $ramMb = 0;
+ if($array['count'] !== 0){
+ $ramMb = $array['memory'] / $array['count'];
+ }
+ $label = 'Pool ' . $name;
+ $elements[$name] = array(
+ 'label' => $label,
+ 'type' => 'GAUGE',
+ 'value' => $ramMb
+ );
+ }
+ $config = array(
+ 'params' => array(
+ 'graph_title' => "$php_container PHP-FPM Average Process Memory",
+ 'graph_vlabel' => 'MB'
+ ),
+ 'elements' => $elements
+ );
+ break;
+// ------------------------------------------------------
+ case 'cpu':
+// ------------------------------------------------------
+ $elements = array();
+ foreach ($groups as $name=>$array) {
+ $cpu = $array['cpu'];
+ $label = 'Pool ' . $name;
+ $elements[$name] = array(
+ 'label' => $label,
+ 'type' => 'GAUGE',
+ 'value' => $cpu
+ );
+ }
+ $config = array(
+ 'params' => array(
+ 'graph_title' => "$php_container PHP-FPM CPU",
+ 'graph_vlabel' => '%',
+ 'graph_scale' => 'no'
+ ),
+ 'elements' => $elements
+ );
+ break;
+// ------------------------------------------------------
+ case 'count':
+// ------------------------------------------------------
+ $elements = array();
+ foreach ($groups as $name=>$array) {
+ $label = 'Pool ' . $name;
+ $elements[$name] = array(
+ 'label' => $label,
+ 'type' => 'GAUGE',
+ 'value' => $array['count']
+ );
+ }
+ $config = array(
+ 'params' => array(
+ 'graph_title' => "$php_container PHP-FPM Processes",
+ 'graph_vlabel' => 'processes'
+ ),
+ 'elements' => $elements
+ );
+ break;
+// ------------------------------------------------------
+ case 'time':
+// ------------------------------------------------------
+ $elements = array();
+ foreach ($groups as $name=>$array) {
+ $time=0;
+ if( $array['count'] !== 0){
+ $time = round($array['time'] / $array['count']);
+ }
+ $label = 'Pool ' . $name;
+ $elements[$name] = array(
+ 'label' => $label,
+ 'type' => 'GAUGE',
+ 'value' => $time
+ );
+ }
+ $config = array(
+ 'params' => array(
+ 'graph_title' => "$php_container PHP-FPM Average Process Age",
+ 'graph_vlabel' => 'seconds',
+ 'graph_scale' => 'no'
+ ),
+ 'elements' => $elements
+ );
+ break;
+// ------------------------------------------------------
+ default:
+ die("Error: Unrecognized Plugin output name $plugin_output\n");
+}
+
+//output
+ksort($config['elements']);
+if ($isConfig) {
+ //graph params
+ echo "graph_category $php_container PHP-FPM\n";
+ foreach($config['params'] as $key=>$value) {
+ echo $key . ' ' . $value . "\n";
+ }
+
+ //element params
+ foreach($config['elements'] as $element=>$data) {
+ foreach ($data as $key=>$value) {
+ if ($key == 'value') continue;
+ echo $element . '.' . $key . ' ' . $value . "\n";
+ }
+ }
+} else {
+ //element values
+ foreach ($config['elements'] as $pool=>$element) {
+ echo $pool . '.value ' . $element['value'] . "\n";
+ }
+}
+
+//functions
+function timeToSeconds ($time) {
+ $seconds = 0;
+
+ //days
+ $parts = explode('-', $time);
+ if(count($parts) == 2) {
+ $seconds += $parts[0] * 86400;
+ $time = $parts[1];
+ }
+
+ //hours
+ $parts = explode(':', $time);
+ if(count($parts) == 3) {
+ $seconds += array_shift($parts) * 3600;
+ }
+
+ //minutes/seconds
+ $seconds += $parts[0] * 60 + $parts[1];
+ return $seconds;
+}
diff --git a/lxc-php/files/sury.gpg b/lxc-php/files/sury.gpg
index 384771a0..28043b0a 100644
Binary files a/lxc-php/files/sury.gpg and b/lxc-php/files/sury.gpg differ
diff --git a/lxc-php/handlers/main.yml b/lxc-php/handlers/main.yml
index b703933b..c1f58f92 100644
--- a/lxc-php/handlers/main.yml
+++ b/lxc-php/handlers/main.yml
@@ -10,6 +10,11 @@
name: "{{ lxc_php_version }}"
container_command: "systemctl restart {{ lxc_php_services[lxc_php_version] }}"
+- name: Reload php83-fpm
+ community.general.lxc_container:
+ name: "{{ lxc_php_version }}"
+ container_command: "systemctl reload php8.3-fpm"
+
- name: Reload php82-fpm
community.general.lxc_container:
name: "{{ lxc_php_version }}"
diff --git a/lxc-php/tasks/mail_opensmtpd.yml b/lxc-php/tasks/mail_opensmtpd.yml
index 35d0e75b..f532e8e8 100644
--- a/lxc-php/tasks/mail_opensmtpd.yml
+++ b/lxc-php/tasks/mail_opensmtpd.yml
@@ -1,11 +1,11 @@
---
-- name: "{{ lxc_php_version }} - Install opensmtpd"
+- name: "{{ lxc_php_container_name }} - Install opensmtpd"
community.general.lxc_container:
- name: "{{ lxc_php_version }}"
+ name: "{{ lxc_php_container_name }}"
container_command: "DEBIAN_FRONTEND=noninteractive apt install --no-install-recommends -y opensmtpd"
-- name: "{{ lxc_php_version }} - Configure opensmtpd (in the container)"
+- name: "{{ lxc_php_container_name }} - Configure opensmtpd (in the container)"
ansible.builtin.template:
src: smtpd.conf.j2
dest: "{{ lxc_rootfs }}/etc/smtpd.conf"
@@ -14,7 +14,7 @@
when: lxc_php_container_releases[lxc_php_version] in ["jessie", "stretch", "buster"]
-- name: "{{ lxc_php_version }} - Configure opensmtpd (in the container)"
+- name: "{{ lxc_php_container_name }} - Configure opensmtpd (in the container)"
ansible.builtin.template:
src: smtpd.conf.bullseye.j2
dest: "{{ lxc_rootfs }}/etc/smtpd.conf"
diff --git a/lxc-php/tasks/mail_ssmtp.yml b/lxc-php/tasks/mail_ssmtp.yml
index 07b54118..62066b2e 100644
--- a/lxc-php/tasks/mail_ssmtp.yml
+++ b/lxc-php/tasks/mail_ssmtp.yml
@@ -1,11 +1,11 @@
---
-- name: "{{ lxc_php_version }} - Install ssmtp"
+- name: "{{ lxc_php_container_name }} - Install ssmtp"
community.general.lxc_container:
- name: "{{ lxc_php_version }}"
+ name: "{{ lxc_php_container_name }}"
container_command: "DEBIAN_FRONTEND=noninteractive apt install --no-install-recommends --yes --force-yes ssmtp "
-- name: "{{ lxc_php_version }} - Configure ssmtp"
+- name: "{{ lxc_php_container_name }} - Configure ssmtp"
ansible.builtin.template:
src: ssmtp.conf.j2
dest: "{{ lxc_rootfs }}/etc/ssmtp/ssmtp.conf"
diff --git a/lxc-php/tasks/main.yml b/lxc-php/tasks/main.yml
index 035bfe15..770031fa 100644
--- a/lxc-php/tasks/main.yml
+++ b/lxc-php/tasks/main.yml
@@ -9,16 +9,16 @@
name: evolix/lxc
vars:
lxc_containers:
- - { name: "{{ lxc_php_version }}", release: "{{ lxc_php_container_releases[lxc_php_version] }}" }
+ - { name: "{{ lxc_php_container_name }}", release: "{{ lxc_php_container_releases[lxc_php_version] }}" }
when: lxc_php_version is defined
- name: set LXC rootfs
ansible.builtin.set_fact:
- lxc_rootfs: "/var/lib/lxc/{{ lxc_php_version }}/rootfs"
+ lxc_rootfs: "/var/lib/lxc/{{ lxc_php_container_name }}/rootfs"
-- name: "Update APT cache in container {{ lxc_php_version }}"
+- name: "Update APT cache in container {{ lxc_php_container_name }}"
community.general.lxc_container:
- name: "{{ lxc_php_version }}"
+ name: "{{ lxc_php_container_name }}"
container_command: "apt-get update"
- ansible.builtin.import_tasks: "php56.yml"
@@ -42,6 +42,9 @@
- ansible.builtin.import_tasks: "php82.yml"
when: lxc_php_version == "php82"
+- ansible.builtin.import_tasks: "php83.yml"
+ when: lxc_php_version == "php83"
+
- ansible.builtin.import_tasks: "umask.yml"
- ansible.builtin.import_tasks: "misc.yml"
diff --git a/lxc-php/tasks/misc.yml b/lxc-php/tasks/misc.yml
index 248aa8e2..7fc4575e 100644
--- a/lxc-php/tasks/misc.yml
+++ b/lxc-php/tasks/misc.yml
@@ -1,31 +1,31 @@
---
-- name: "{{ lxc_php_version }} - Configure timezone for the container"
+- name: "{{ lxc_php_container_name }} - Configure timezone for the container"
ansible.builtin.copy:
remote_src: yes
src: "/etc/timezone"
dest: "{{ lxc_rootfs }}/etc/timezone"
-- name: "{{ lxc_php_version }} - Ensure container's root directory is 755"
+- name: "{{ lxc_php_container_name }} - Ensure container's root directory is 755"
ansible.builtin.file:
path: "{{ lxc_rootfs }}"
state: directory
mode: '0755'
-- name: "{{ lxc_php_version }} - Configure mailname for the container"
+- name: "{{ lxc_php_container_name }} - Configure mailname for the container"
ansible.builtin.copy:
content: "{{ evolinux_hostname }}.{{ evolinux_domain }}\n"
dest: "{{ lxc_rootfs }}/etc/mailname"
notify: "Restart opensmtpd"
-- name: "{{ lxc_php_version }} - Install misc packages"
+- name: "{{ lxc_php_container_name }} - Install misc packages"
community.general.lxc_container:
- name: "{{ lxc_php_version }}"
+ name: "{{ lxc_php_container_name }}"
container_command: "DEBIAN_FRONTEND=noninteractive apt install -y cron logrotate git zip unzip"
-- name: "{{ lxc_php_version }} - Add MySQL socket to container default mounts"
+- name: "{{ lxc_php_container_name }} - Add MySQL socket to container default mounts"
community.general.lxc_container:
- name: "{{ lxc_php_version }}"
+ name: "{{ lxc_php_container_name }}"
container_config:
- "lxc.mount.entry = /run/mysqld {{ php_conf_mysql_socket_dir | replace('/', '', 1) }} none bind,create=dir 0 0"
when:
diff --git a/lxc-php/tasks/php73.yml b/lxc-php/tasks/php73.yml
index ade67b97..1335e8a1 100644
--- a/lxc-php/tasks/php73.yml
+++ b/lxc-php/tasks/php73.yml
@@ -1,11 +1,11 @@
---
-- name: "{{ lxc_php_version }} - Install PHP packages"
+- name: "{{ lxc_php_container_name }} - Install PHP packages"
community.general.lxc_container:
- name: "{{ lxc_php_version }}"
+ name: "{{ lxc_php_container_name }}"
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-gettext php-curl php-ssh2 php-zip php-mbstring php-zip composer libphp-phpmailer"
-- name: "{{ lxc_php_version }} - Copy evolinux PHP configuration"
+- name: "{{ lxc_php_container_name }} - Copy evolinux PHP configuration"
ansible.builtin.template:
src: z-evolinux-defaults.ini.j2
dest: "{{ line_item }}"
diff --git a/lxc-php/tasks/php83.yml b/lxc-php/tasks/php83.yml
new file mode 100644
index 00000000..80c33eb6
--- /dev/null
+++ b/lxc-php/tasks/php83.yml
@@ -0,0 +1,91 @@
+---
+
+- name: set APT keyring
+ ansible.builtin.set_fact:
+ lxc_apt_keyring_dir: /etc/apt/trusted.gpg.d
+
+- name: "{{ lxc_php_version }} - Install dependency packages"
+ community.general.lxc_container:
+ name: "{{ lxc_php_version }}"
+ container_command: "DEBIAN_FRONTEND=noninteractive apt install -y wget gnupg"
+
+- name: "{{ lxc_php_version }} - delete sources.list bookworm repository"
+ ansible.builtin.file:
+ path: "{{ lxc_rootfs }}/etc/apt/sources.list"
+ state: absent
+
+- name: "{{ lxc_php_version }} - system bookworm repository"
+ ansible.builtin.template:
+ src: bookworm_basics.sources.j2
+ dest: "{{ lxc_rootfs }}/etc/apt/sources.list.d/system.sources"
+ force: true
+ mode: "0644"
+
+- name: "{{ lxc_php_version }} - security bookworm repository"
+ ansible.builtin.template:
+ src: bookworm_security.sources.j2
+ dest: "{{ lxc_rootfs }}/etc/apt/sources.list.d/security.sources"
+ force: true
+ mode: "0644"
+
+- name: "{{ lxc_php_version }} - Add sury repo"
+ ansible.builtin.template:
+ src: sury.sources.j2
+ dest: "{{ lxc_rootfs }}/etc/apt/sources.list.d/sury.sources"
+ force: true
+ mode: "0644"
+
+- name: "{{ lxc_php_version }} - Add sury failsafe repo"
+ ansible.builtin.template:
+ src: evolix_sury.sources.j2
+ dest: "{{ lxc_rootfs }}/etc/apt/sources.list.d/evolix_sury.sources"
+ force: true
+ mode: "0644"
+
+- name: "Ensure {{ lxc_rootfs }}{{ lxc_apt_keyring_dir }} directory exists"
+ file:
+ path: "{{ lxc_rootfs }}{{ lxc_apt_keyring_dir }}"
+ state: directory
+ mode: "755"
+ owner: root
+ group: root
+
+- name: copy pub.evolix.org GPG key
+ ansible.builtin.copy:
+ src: pub_evolix.asc
+ dest: "{{ lxc_rootfs }}{{ lxc_apt_keyring_dir }}/pub_evolix.asc"
+ mode: "0644"
+ owner: root
+ group: root
+
+- name: copy packages.sury.org GPG Key
+ ansible.builtin.copy:
+ src: sury.gpg
+ dest: "{{ lxc_rootfs }}{{ lxc_apt_keyring_dir }}/sury.gpg"
+ mode: "0644"
+ owner: root
+ group: root
+
+- name: "{{ lxc_php_version }} - Update APT cache"
+ community.general.lxc_container:
+ name: "{{ lxc_php_version }}"
+ container_command: "DEBIAN_FRONTEND=noninteractive apt update"
+
+- name: "{{ lxc_php_version }} - Install PHP packages"
+ community.general.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-xml php-zip composer libphp-phpmailer"
+
+- name: "{{ lxc_php_version }} - Copy evolinux PHP configuration"
+ ansible.builtin.template:
+ src: z-evolinux-defaults.ini.j2
+ dest: "{{ line_item }}"
+ mode: "0644"
+ notify: "Reload {{ lxc_php_version }}-fpm"
+ loop:
+ - "{{ lxc_rootfs }}/etc/php/8.3/fpm/conf.d/z-evolinux-defaults.ini"
+ - "{{ lxc_rootfs }}/etc/php/8.3/cli/conf.d/z-evolinux-defaults.ini"
+ loop_control:
+ loop_var: line_item
+
+- ansible.builtin.include: "mail_opensmtpd.yml"
diff --git a/lxc-php/templates/bookworm_basics.sources.j2 b/lxc-php/templates/bookworm_basics.sources.j2
index 948c4adf..8599143d 100644
--- a/lxc-php/templates/bookworm_basics.sources.j2
+++ b/lxc-php/templates/bookworm_basics.sources.j2
@@ -2,7 +2,7 @@
Types: deb
URIs: http://mirror.evolix.org/debian
-Suites: bookworm bookworm-updates
+Suites: {{ lxc_php_container_releases[lxc_php_version] }} {{ lxc_php_container_releases[lxc_php_version] }}-updates
Components: {{ apt_basics_components | mandatory }}
Enabled: yes
Signed-By: /usr/share/keyrings/debian-archive-bookworm-automatic.gpg
diff --git a/lxc-php/templates/bookworm_security.sources.j2 b/lxc-php/templates/bookworm_security.sources.j2
index c98d5671..a3ccc581 100644
--- a/lxc-php/templates/bookworm_security.sources.j2
+++ b/lxc-php/templates/bookworm_security.sources.j2
@@ -2,7 +2,7 @@
Types: deb
URIs: https://security.debian.org/debian-security
-Suites: bookworm-security
+Suites: {{ lxc_php_container_releases[lxc_php_version] }}-security
Components: {{ apt_basics_components | mandatory }}
Enabled: yes
Signed-By: /usr/share/keyrings/debian-archive-bookworm-security-automatic.gpg
diff --git a/lxc-php/templates/evolix_sury.sources.j2 b/lxc-php/templates/evolix_sury.sources.j2
new file mode 100644
index 00000000..ee09a474
--- /dev/null
+++ b/lxc-php/templates/evolix_sury.sources.j2
@@ -0,0 +1,8 @@
+# {{ ansible_managed }}
+
+Types:deb
+URIs: http://pub.evolix.org/evolix
+Suites: {{ lxc_php_container_releases[lxc_php_version] }}-{{ lxc_php_version }}
+Components: main
+Signed-by: {{ apt_keyring_dir }}/pub_evolix.asc
+Enabled: yes
diff --git a/lxc-php/templates/sury.sources.j2 b/lxc-php/templates/sury.sources.j2
index 22725a58..2c17ef9d 100644
--- a/lxc-php/templates/sury.sources.j2
+++ b/lxc-php/templates/sury.sources.j2
@@ -2,7 +2,7 @@
Types: deb
URIs: https://packages.sury.org/php/
-Suites: {{ ansible_distribution_release }}
+Suites: {{ lxc_php_container_releases[lxc_php_version] }}
Components: main
Signed-by: {{ lxc_apt_keyring_dir }}/sury.gpg
-Enabled: yes
\ No newline at end of file
+Enabled: yes
diff --git a/lxc/tasks/create-container.yml b/lxc/tasks/create-container.yml
index 4d3851b6..45f7270b 100644
--- a/lxc/tasks/create-container.yml
+++ b/lxc/tasks/create-container.yml
@@ -58,13 +58,13 @@
name: "{{ name }}"
state: started
-- name: "Ensure /etc/profile.d exists in container"
+- name: "Ensure /etc/profile.d exists in container {{ name }}"
ansible.builtin.file:
path: "/var/lib/lxc/{{ name }}/rootfs/etc/profile.d"
mode: '0755'
state: directory
-- name: "Copy host /etc/profile.d/evolinux into container"
+- name: "Copy host /etc/profile.d/evolinux into container {{ name }}"
ansible.builtin.copy:
src: "/etc/profile.d/evolinux.sh"
remote_src: true
@@ -75,3 +75,22 @@
community.general.lxc_container:
name: "{{ name }}"
container_command: "DEBIAN_FRONTEND=noninteractive apt-get purge -y openssh-server"
+
+- name: "Init /etc git repository in container {{ name }}"
+ ansible.builtin.include_role:
+ name: 'etc-git'
+ tasks_from: 'repository.yml'
+ apply:
+ vars:
+ gitignore_items:
+ - "aliases.db"
+ - "*.swp"
+ - "postfix/sa-blacklist.access"
+ - "postfix/*.db"
+ - "postfix/spamd.cidr"
+ - "evobackup/.keep-*"
+ - "letsencrypt/.certbot.lock"
+ become: yes
+ loop: ["/var/lib/lxc/{{ name }}/rootfs/etc/"]
+ loop_control:
+ loop_var: 'repository_path'
diff --git a/memcached/tasks/main.yml b/memcached/tasks/main.yml
index 96060d4a..05455c0b 100644
--- a/memcached/tasks/main.yml
+++ b/memcached/tasks/main.yml
@@ -6,10 +6,10 @@
- memcached
- ansible.builtin.include: instance-default.yml
- when: memcached_instance_name is undefined
+ when: memcached_instance_name | length == 0
- ansible.builtin.include: instance-multi.yml
- when: memcached_instance_name is defined
+ when: memcached_instance_name | length > 0
- ansible.builtin.include: munin.yml
diff --git a/memcached/tasks/munin.yml b/memcached/tasks/munin.yml
index b25b9275..f4b262a9 100644
--- a/memcached/tasks/munin.yml
+++ b/memcached/tasks/munin.yml
@@ -2,7 +2,7 @@
- name: Choose packages (Oracle)
ansible.builtin.set_fact:
multi: "multi_"
- when: memcached_instance_name is defined
+ when: memcached_instance_name | length > 0
- name: is Munin present ?
ansible.builtin.stat:
diff --git a/memcached/tasks/nrpe.yml b/memcached/tasks/nrpe.yml
index aba43da6..70c69c00 100644
--- a/memcached/tasks/nrpe.yml
+++ b/memcached/tasks/nrpe.yml
@@ -36,7 +36,7 @@
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
+ when: memcached_instance_name | length == 0
- name: Add NRPE check (multi instance)
ansible.builtin.lineinfile:
@@ -44,6 +44,6 @@
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: memcached_instance_name | length > 0
when: nrpe_evolix_config.stat.exists
diff --git a/minifirewall/defaults/main.yml b/minifirewall/defaults/main.yml
index 18d7d5b3..edb849b9 100644
--- a/minifirewall/defaults/main.yml
+++ b/minifirewall/defaults/main.yml
@@ -34,9 +34,9 @@ minifirewall_privilegied_ips: []
minifirewall_protected_ports_tcp: [22]
minifirewall_protected_ports_udp: []
-minifirewall_public_ports_tcp: [25, 53, 443, 993, 995, 22222]
-minifirewall_public_ports_udp: [53]
-minifirewall_semipublic_ports_tcp: [20, 21, 22, 80, 110, 143]
+minifirewall_public_ports_tcp: [22222]
+minifirewall_public_ports_udp: []
+minifirewall_semipublic_ports_tcp: [22, 80, 443]
minifirewall_semipublic_ports_udp: []
minifirewall_private_ports_tcp: [5666]
minifirewall_private_ports_udp: []
diff --git a/minifirewall/files/check_minifirewall b/minifirewall/files/check_minifirewall
index fc034de4..565a912d 100644
--- a/minifirewall/files/check_minifirewall
+++ b/minifirewall/files/check_minifirewall
@@ -87,7 +87,7 @@ main() {
append_details "configuration is up-to-date"
summary_ok "minifirewall is started and configuration is up-to-date"
else
- if echo "${check_result}" | grep --quiet --regexp 'usage'; then
+ if echo "${check_result}" | grep --ignore-case --quiet --regexp 'usage'; then
append_details "minifirewall is too old to check active configuration"
else
case "${check_rc}" in
diff --git a/mongodb/files/server-7.0.asc b/mongodb/files/server-7.0.asc
new file mode 100644
index 00000000..7f4911ae
--- /dev/null
+++ b/mongodb/files/server-7.0.asc
@@ -0,0 +1,30 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1
+
+mQINBGPILWABEACqeWP/ktugdlWEyk7YTXo3n19+5Om4AlSdIyKv49vAlKtzCfMA
+QkZq3mfvjXiKMuLnL2VeElAJQIYcPoqnHf6tJbdrNv4AX2uI1cTsvGW7YS/2WNwJ
+C/+vBa4o+yA2CG/MVWZRbtOjkFF/W07yRFtNHAcgdmpIjdWgSnPQr9eIqLuWXIhy
+H7EerKsba227Vd/HfvKnAy30Unlsdywy7wi1FupzGJck0TPoOVGmsSpSyIQu9A4Z
+uC6TE/NcJHvaN0JuHwM+bQo9oWirGsZ1NCoVqSY8/sasdUc7T9r90MbUcH674YAR
+8OKYVBzU0wch4VTFhfHZecKHQnZf+V4dmP9oXnu4fY0/0w3l4jaew7Ind7kPg3yN
+hvgAkBK8yRAbSu1NOtHDNiRoHGEQFgct6trVOvCqHbN/VToLNtGk0rhKGOp8kuSF
+OJ02PJPxF3/zHGP8n8khCjUJcrilYPqRghZC8ZWnCj6GJVg6WjwLi+hPwNMi8xK6
+cjKhRW3eCy5Wcn73PzVBX9f7fSeFDJec+IfS47eNkxunHAOUMXa2+D+1xSWgEfK0
+PClfyWPgLIXY2pGQ6v8l3A6P5gJv4o38/E1h1RTcO3H1Z6cgZLIORZHPyAj50SPQ
+cjzftEcz56Pl/Cyw3eMYC3qlbABBgsdeb6KB6G5dkNxI4or3MgmxcwfnkwARAQAB
+tDdNb25nb0RCIDcuMCBSZWxlYXNlIFNpZ25pbmcgS2V5IDxwYWNrYWdpbmdAbW9u
+Z29kYi5jb20+iQI+BBMBAgAoBQJjyC1gAhsDBQkJZgGABgsJCAcDAgYVCAIJCgsE
+FgIDAQIeAQIXgAAKCRAWDSa7F4W6OM+eD/sE7KbJyRNWyPCRTqqJXrXvyPqZtbFX
+8sio0lQ8ghn4f7lmb7LnFroUsmBeWaYirM8O3b2+iQ9oj4GeR3gbRZsEhFXQfL54
+SfrmG9hrWWpJllgPP7Six+jrzcjvkf1TENqw4jRP+cJhuihH1Gfizo9ktwwoN9Yr
+m7vgh+focEEmx8dysS38ApLxKlUEfTsE9bYsClgqyY1yrt3v4IpGbf66yfyBHNgY
+sObR3sngDRVbap7PwNyREGsuAFfKr/Dr37HfrjY7nsn3vH7hbDpSBh+H7a0b/chS
+mM60aaG4biWpvmSC7uxA/t0gz+NQuC4HL+qyNPUxvyIO+TwlaXfCI6ixazyrH+1t
+F7Bj5mVsne7oeWjRrSz85jK3Tpn9tj3Fa7PCDA6auAlPK8Upbhuoajev4lIydNd2
+70yO0idm/FtpX5a8Ck7KSHDvEnXpN70imayoB4Fs2Kigi2BdZOOdib16o5F/9cx9
+piNa7HotHCLTfR6xRmelGEPWKspU1Sm7u2A5vWgjfSab99hiNQ89n+I7BcK1M3R1
+w/ckl6qBtcxz4Py+7jYIJL8BYz2tdreWbdzWzjv+XQ8ZgOaMxhL9gtlfyYqeGfnp
+hYW8LV7a9pavxV2tLuVjMM+05ut/d38IkTV7OSJgisbSGcmycXIzxsipyXJVGMZt
+MFw3quqJhQMRsA==
+=gbRM
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/mysql/defaults/main.yml b/mysql/defaults/main.yml
index af43f495..871dd599 100644
--- a/mysql/defaults/main.yml
+++ b/mysql/defaults/main.yml
@@ -59,5 +59,5 @@ mysql_binlog_format: mixed
mysql_server_id: null
mysql_bind_address: null
mysql_repl_password: ''
-mysql_read_only: 0
+mysql_read_only: False
diff --git a/mysql/tasks/config_jessie.yml b/mysql/tasks/config_jessie.yml
index 3d8c494d..364ee175 100644
--- a/mysql/tasks/config_jessie.yml
+++ b/mysql/tasks/config_jessie.yml
@@ -2,6 +2,7 @@
- ansible.builtin.set_fact:
mysql_config_directory: /etc/mysql/conf.d
+ mysql_performance_schema: False
- name: "Copy MySQL defaults config file (jessie)"
ansible.builtin.copy:
diff --git a/mysql/templates/evolinux-custom.cnf.j2 b/mysql/templates/evolinux-custom.cnf.j2
index 119943a1..cc66df94 100644
--- a/mysql/templates/evolinux-custom.cnf.j2
+++ b/mysql/templates/evolinux-custom.cnf.j2
@@ -38,7 +38,7 @@ lower_case_table_names = {{ mysql_lower_case_table_names }}
{% if mysql_innodb_log_file_size %}
innodb_log_file_size = {{ mysql_innodb_log_file_size }}
{% endif %}
-read_only = {{ mysql_read_only }}
+read_only = {{ mysql_read_only | bool | ternary('1','0') }}
{% if mysql_performance_schema %}
performance_schema = ON
performance-schema-instrument='stage/%=ON'
diff --git a/nagios-nrpe/defaults/main.yml b/nagios-nrpe/defaults/main.yml
index 8ac9c3f4..c8695bc8 100644
--- a/nagios-nrpe/defaults/main.yml
+++ b/nagios-nrpe/defaults/main.yml
@@ -8,8 +8,17 @@ nagios_nrpe_default_ntp_server: "pool.ntp.org"
nagios_nrpe_ntp_server: Null
# Use nagios_nrpe_processes to override
-nagios_nrpe_processes_default_before_debian_12: [ cron rsyslogd ntpd munin-node ]
-nagios_nrpe_processes_default: [ cron rsyslogd systemd-timesyn munin-node ]
+nagios_nrpe_processes_default_before_debian_12:
+ - cron
+ - rsyslogd
+ - ntpd
+ - munin-node
+nagios_nrpe_processes_default:
+ - cron
+ - rsyslogd
+ - systemd-timesyn
+ - munin-node
+
# Built dynamically :
nagios_nrpe_processes: Null
diff --git a/nagios-nrpe/files/plugins/check_phpfpm_multi b/nagios-nrpe/files/plugins/check_phpfpm_multi
index b02fc7e2..e21ecf87 100644
--- a/nagios-nrpe/files/plugins/check_phpfpm_multi
+++ b/nagios-nrpe/files/plugins/check_phpfpm_multi
@@ -19,14 +19,21 @@ nb_ok=0
nb_unchk=0
output=""
-readonly POOL_FOLDER=${1:-$(detect_pool_dir)}
+# We want globbing to be expanded here
+# shellcheck disable=SC2206
+readonly POOL_FOLDER=( ${1:-$(detect_pool_dir)} )
-if [[ ! -d "$POOL_FOLDER" ]]; then
- echo "CRITICAL - $POOL_FOLDER does not exists"
+if [ "${#POOL_FOLDER[@]}" -gt 1 ]; then
+ echo "CRITICAL - '${POOL_FOLDER[*]}' contains more than one directories"
+ exit 2
+fi;
+
+if [[ ! -d "${POOL_FOLDER[0]}" ]]; then
+ echo "CRITICAL - ${POOL_FOLDER[0]} does not exists"
exit 2
fi;
-readonly POOL_FILES=$(find "$POOL_FOLDER" -name "*.conf")
+readonly POOL_FILES=$(find "${POOL_FOLDER[0]}" -name "*.conf")
for pool_file in $POOL_FILES; do
diff --git a/nagios-nrpe/templates/evolix.cfg.j2 b/nagios-nrpe/templates/evolix.cfg.j2
index de495868..d725bb3b 100644
--- a/nagios-nrpe/templates/evolix.cfg.j2
+++ b/nagios-nrpe/templates/evolix.cfg.j2
@@ -48,7 +48,6 @@ 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/daily.cld
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 8891
@@ -59,6 +58,9 @@ command[check_bkctld]=sudo /usr/sbin/bkctld check
command[check_postgrey]=/usr/lib/nagios/plugins/check_tcp -p10023
command[check_influxdb]=/usr/lib/nagios/plugins/check_http -I 127.0.0.1 -u /health -p 8086 -r '"status":"pass"'
command[check_dhcpd]=/usr/lib/nagios/plugins/check_procs -c1:1 -C dhcpd -t 60
+command[check_ipmi_sensors]=sudo /usr/lib/nagios/plugins/check_ipmi_sensor
+command[check_raid_status]=/usr/lib/nagios/plugins/check_raid
+command[check_dockerd]=/usr/lib/nagios/plugins/check_tcp -H /var/run/docker.sock --escape -s "GET /_ping HTTP/1.1\nHost: http\n\n" -e OK
# Local checks (not packaged)
command[check_mem]={{ nagios_plugins_directory }}/check_mem -f -C -w 20 -c 10
@@ -85,9 +87,12 @@ command[check_php-fpm74]=sudo {{ nagios_plugins_directory }}/check_phpfpm_multi
command[check_php-fpm80]=sudo {{ nagios_plugins_directory }}/check_phpfpm_multi /var/lib/lxc/php80/rootfs/etc/php/8.0/fpm/pool.d/
command[check_php-fpm81]=sudo {{ nagios_plugins_directory }}/check_phpfpm_multi /var/lib/lxc/php81/rootfs/etc/php/8.1/fpm/pool.d/
command[check_php-fpm82]=sudo {{ nagios_plugins_directory }}/check_phpfpm_multi /var/lib/lxc/php82/rootfs/etc/php/8.2/fpm/pool.d/
-command[check_ipmi_sensors]=sudo /usr/lib/nagios/plugins/check_ipmi_sensor
-command[check_raid_status]=/usr/lib/nagios/plugins/check_raid
+command[check_php-fpm83]=sudo {{ nagios_plugins_directory }}/check_phpfpm_multi /var/lib/lxc/php83/rootfs/etc/php/8.3/fpm/pool.d/
command[check_dhcp_pool]={{ nagios_plugins_directory }}/check_dhcp_pool
+command[check_ssl_local]={{ nagios_plugins_directory }}/check_ssl_local
+command[check_pressure_cpu]=/usr/lib/nagios/plugins/check_pressure --cpu -w 100000 -c 500000
+command[check_pressure_mem]=/usr/lib/nagios/plugins/check_pressure --mem --full -w 100000 -c 500000
+command[check_pressure_io]=/usr/lib/nagios/plugins/check_pressure --io --full -w 100000 -c 500000
# Check HTTP "many". Use this to check many websites (http, https, ports, sockets and SSL certificates).
# Beware! All checks must not take more than 10s!
diff --git a/nginx/tasks/ip_whitelist.yml b/nginx/tasks/ip_whitelist.yml
index fc4fd2d2..537e4a66 100644
--- a/nginx/tasks/ip_whitelist.yml
+++ b/nginx/tasks/ip_whitelist.yml
@@ -5,6 +5,7 @@
dest: /etc/nginx/snippets/ipaddr_whitelist
line: "allow {{ item }};"
state: present
+ create: yes
loop: "{{ nginx_ipaddr_whitelist_present }}"
notify: reload nginx
tags:
diff --git a/nginx/tasks/main.yml b/nginx/tasks/main.yml
index 57a036d4..e8009804 100644
--- a/nginx/tasks/main.yml
+++ b/nginx/tasks/main.yml
@@ -20,20 +20,22 @@
- name: customize worker_connections
ansible.builtin.lineinfile:
dest: /etc/nginx/nginx.conf
- regexp: '^(\s*)(worker_connections)\s+.+;'
+ regexp: '^(\s*)worker_connections\s+.+;'
line: '\1worker_connections 1024;'
insertafter: 'events \{'
backrefs: yes
+ when: not ansible_check_mode
tags:
- nginx
- name: use epoll
ansible.builtin.lineinfile:
dest: /etc/nginx/nginx.conf
- regexp: '^(\s*)(use)\s+.+;'
+ regexp: '^(\s*)use\s+.+;'
line: '\1use epoll;'
insertafter: 'events \{'
backrefs: yes
+ when: not ansible_check_mode
tags:
- nginx
@@ -145,6 +147,7 @@
name: nginx
enabled: yes
state: started
+ when: not ansible_check_mode
tags:
- nginx
diff --git a/nginx/tasks/munin_vhost.yml b/nginx/tasks/munin_vhost.yml
index 98cc8672..2c9261f4 100644
--- a/nginx/tasks/munin_vhost.yml
+++ b/nginx/tasks/munin_vhost.yml
@@ -30,10 +30,14 @@
ansible.builtin.copy:
src: systemd/spawn-fcgi-munin-graph.service
dest: /etc/systemd/system/spawn-fcgi-munin-graph.service
+ force: yes
+# WARN: there is no (apparent) way to check if the service exists
+# so we disable this task in check mode.
- name: Systemd unit for Munin-fcgi is started
ansible.builtin.systemd:
name: spawn-fcgi-munin-graph
daemon_reload: yes
enabled: yes
state: started
+ when: not ansible_check_mode
diff --git a/nginx/tasks/server_status_read.yml b/nginx/tasks/server_status_read.yml
index d6cecbe3..eddc3fe8 100644
--- a/nginx/tasks/server_status_read.yml
+++ b/nginx/tasks/server_status_read.yml
@@ -18,20 +18,27 @@
- name: generate random string for server-status suffix
ansible.builtin.shell:
- cmd: "apg -a 1 -M N -n 1 > {{ nginx_serverstatus_suffix_file }}"
- args:
+ cmd: "apg -a 1 -M N -n 1 | tee {{ nginx_serverstatus_suffix_file }}"
creates: "{{ nginx_serverstatus_suffix_file }}"
+ register: generated_nginx_serverstatus_suffix
+
+- name: check if nginx suffix file exists
+ ansible.builtin.stat:
+ path: "{{ nginx_serverstatus_suffix_file }}"
+ register: nginx_serverstatus_suffix_file_check
- name: read nginx server status suffix
ansible.builtin.command:
cmd: "tail -n 1 {{ nginx_serverstatus_suffix_file }}"
changed_when: False
check_mode: no
- register: new_nginx_serverstatus_suffix
+ when: nginx_serverstatus_suffix_file_check.stat.exists
+ register: read_nginx_serverstatus_suffix
+# If the file exists and the read value is not empty, then use it, otherwhise use the generated value
- name: overwrite nginx_serverstatus_suffix
ansible.builtin.set_fact:
- nginx_serverstatus_suffix: "{{ new_nginx_serverstatus_suffix.stdout }}"
+ nginx_serverstatus_suffix: "{{ (nginx_serverstatus_suffix_file_check.stat.exists and (read_nginx_serverstatus_suffix.stdout | length > 0)) | ternary(read_nginx_serverstatus_suffix.stdout, generated_nginx_serverstatus_suffix.stdout) }}"
- ansible.builtin.debug:
var: nginx_serverstatus_suffix
diff --git a/nginx/tasks/server_status_write.yml b/nginx/tasks/server_status_write.yml
index dbed56cb..08031635 100644
--- a/nginx/tasks/server_status_write.yml
+++ b/nginx/tasks/server_status_write.yml
@@ -17,4 +17,5 @@
dest: /etc/nginx/sites-available/evolinux-default.conf
regexp: 'location /server-status-? {'
replace: 'location /server-status-{{ nginx_serverstatus_suffix }} {'
+ when: not ansible_check_mode
notify: reload nginx
diff --git a/openvpn/files/check_openvpn_certificates.sh b/openvpn/files/check_openvpn_certificates.sh
index 26808868..1ec3aaed 100644
--- a/openvpn/files/check_openvpn_certificates.sh
+++ b/openvpn/files/check_openvpn_certificates.sh
@@ -35,6 +35,7 @@ fi
# Dates in seconds
_15_days="1296000"
_30_days="2592000"
+_60_days="5184000"
current_date=$($date_cmd +"%s")
# Trying to define the OpenVPN conf file location - default to /etc/openvpn/server.conf
@@ -90,15 +91,15 @@ test_ca_expiration() {
if [ $current_date -ge $1 ]; then
CA_ECHO="CRITICAL - The server CA has expired on $formated_ca_expiration_date"
CA_STATE=$STATE_CRITICAL
- # Expiration in 15 days or less - CA file
- elif [ $((current_date+_15_days)) -ge $1 ]; then
- CA_ECHO="CRITICAL - The server CA expires in 15 days or less : $formated_ca_expiration_date"
- CA_STATE=$STATE_CRITICAL
# Expiration in 30 days or less - CA file
elif [ $((current_date+_30_days)) -ge $1 ]; then
- CA_ECHO="WARNING - The server CA expires in 30 days or less : $formated_ca_expiration_date"
+ CA_ECHO="CRITICAL - The server CA expires in 30 days or less : $formated_ca_expiration_date"
+ CA_STATE=$STATE_CRITICAL
+ # Expiration in 60 days or less - CA file
+ elif [ $((current_date+_60_days)) -ge $1 ]; then
+ CA_ECHO="WARNING - The server CA expires in 60 days or less : $formated_ca_expiration_date"
CA_STATE=$STATE_WARNING
- # Expiration in more than 30 days - CA file
+ # Expiration in more than 60 days - CA file
else
CA_ECHO="OK - The server CA expires on $formated_ca_expiration_date"
CA_STATE=$STATE_OK
@@ -193,8 +194,8 @@ main() {
echo $RESTART_ECHO
exit $CERT_STATE
else
- echo $CERT_ECHO
echo $CA_ECHO
+ echo $CERT_ECHO
echo $RESTART_ECHO
exit $CERT_STATE
fi
diff --git a/php/files/munin_php-fpm b/php/files/munin_php-fpm
new file mode 100755
index 00000000..3647767d
--- /dev/null
+++ b/php/files/munin_php-fpm
@@ -0,0 +1,234 @@
+#!/usr/bin/php
+
+ 0,
+ 'memory' => 0,
+ 'cpu' => 0,
+ 'time' => 0
+ );
+ }
+
+ //add values
+ $groups[$groupName]['count']++;
+ $groups[$groupName]['cpu'] += $cpu;
+ $groups[$groupName]['time'] += timeToSeconds($time);
+ $groups[$groupName]['memory'] += $ram / 1024;
+}
+foreach ($php_inactive_pools_list as $line) {
+ //split fields
+ $line = trim($line);
+ $groupName = $line;
+ //add group
+ if (!isset($groups[$groupName])) {
+ $groups[$groupName] = array(
+ 'count' => 0,
+ 'memory' => 0,
+ 'cpu' => 0,
+ 'time' => 0
+ );
+ }
+}
+
+//check args
+if(!isset($argv) || !isset($argv[0])) {
+ die("Error: No Plugin name provided\n");
+}
+
+$isConfig = isset($argv[1]) && $argv[1] == 'config';
+
+//which plugin?
+switch ($plugin_output) {
+// ------------------------------------------------------
+ case 'memory':
+// ------------------------------------------------------
+ $elements = array();
+ foreach ($groups as $name=>$array) {
+ $ramMb = 0;
+ if($array['count'] !== 0){
+ $ramMb = $array['memory'] / $array['count'];
+ }
+ $label = 'Pool ' . $name;
+ $elements[$name] = array(
+ 'label' => $label,
+ 'type' => 'GAUGE',
+ 'value' => $ramMb
+ );
+ }
+ $config = array(
+ 'params' => array(
+ 'graph_title' => "$php_container PHP-FPM Average Process Memory",
+ 'graph_vlabel' => 'MB'
+ ),
+ 'elements' => $elements
+ );
+ break;
+// ------------------------------------------------------
+ case 'cpu':
+// ------------------------------------------------------
+ $elements = array();
+ foreach ($groups as $name=>$array) {
+ $cpu = $array['cpu'];
+ $label = 'Pool ' . $name;
+ $elements[$name] = array(
+ 'label' => $label,
+ 'type' => 'GAUGE',
+ 'value' => $cpu
+ );
+ }
+ $config = array(
+ 'params' => array(
+ 'graph_title' => "$php_container PHP-FPM CPU",
+ 'graph_vlabel' => '%',
+ 'graph_scale' => 'no'
+ ),
+ 'elements' => $elements
+ );
+ break;
+// ------------------------------------------------------
+ case 'count':
+// ------------------------------------------------------
+ $elements = array();
+ foreach ($groups as $name=>$array) {
+ $label = 'Pool ' . $name;
+ $elements[$name] = array(
+ 'label' => $label,
+ 'type' => 'GAUGE',
+ 'value' => $array['count']
+ );
+ }
+ $config = array(
+ 'params' => array(
+ 'graph_title' => "$php_container PHP-FPM Processes",
+ 'graph_vlabel' => 'processes'
+ ),
+ 'elements' => $elements
+ );
+ break;
+// ------------------------------------------------------
+ case 'time':
+// ------------------------------------------------------
+ $elements = array();
+ foreach ($groups as $name=>$array) {
+ $time=0;
+ if( $array['count'] !== 0){
+ $time = round($array['time'] / $array['count']);
+ }
+ $label = 'Pool ' . $name;
+ $elements[$name] = array(
+ 'label' => $label,
+ 'type' => 'GAUGE',
+ 'value' => $time
+ );
+ }
+ $config = array(
+ 'params' => array(
+ 'graph_title' => "$php_container PHP-FPM Average Process Age",
+ 'graph_vlabel' => 'seconds',
+ 'graph_scale' => 'no'
+ ),
+ 'elements' => $elements
+ );
+ break;
+// ------------------------------------------------------
+ default:
+ die("Error: Unrecognized Plugin output name $plugin_output\n");
+}
+
+//output
+ksort($config['elements']);
+if ($isConfig) {
+ //graph params
+ echo "graph_category $php_container PHP-FPM\n";
+ foreach($config['params'] as $key=>$value) {
+ echo $key . ' ' . $value . "\n";
+ }
+
+ //element params
+ foreach($config['elements'] as $element=>$data) {
+ foreach ($data as $key=>$value) {
+ if ($key == 'value') continue;
+ echo $element . '.' . $key . ' ' . $value . "\n";
+ }
+ }
+} else {
+ //element values
+ foreach ($config['elements'] as $pool=>$element) {
+ echo $pool . '.value ' . $element['value'] . "\n";
+ }
+}
+
+//functions
+function timeToSeconds ($time) {
+ $seconds = 0;
+
+ //days
+ $parts = explode('-', $time);
+ if(count($parts) == 2) {
+ $seconds += $parts[0] * 86400;
+ $time = $parts[1];
+ }
+
+ //hours
+ $parts = explode(':', $time);
+ if(count($parts) == 3) {
+ $seconds += array_shift($parts) * 3600;
+ }
+
+ //minutes/seconds
+ $seconds += $parts[0] * 60 + $parts[1];
+ return $seconds;
+}
diff --git a/php/files/sury.gpg b/php/files/sury.gpg
index 384771a0..28043b0a 100644
Binary files a/php/files/sury.gpg and b/php/files/sury.gpg differ
diff --git a/php/files/sury.preferences b/php/files/sury.preferences
deleted file mode 100644
index adcc5918..00000000
--- a/php/files/sury.preferences
+++ /dev/null
@@ -1,7 +0,0 @@
-Package: php* libapache2-mod-php* libpcre2* libzip4* libgd* libpcre3*
-Pin: origin packages.sury.org
-Pin-Priority: 999
-
-Package: *
-Pin: origin packages.sury.org
-Pin-Priority: 50
diff --git a/php/handlers/main.yml b/php/handlers/main.yml
index b333fe9b..d2b96b99 100644
--- a/php/handlers/main.yml
+++ b/php/handlers/main.yml
@@ -34,3 +34,8 @@
ansible.builtin.service:
name: php8.2-fpm
state: restarted
+
+- name: restart php8.3-fpm
+ ansible.builtin.service:
+ name: php8.3-fpm
+ state: restarted
diff --git a/php/tasks/sury_pre.yml b/php/tasks/sury_pre.yml
index a0640e4c..599f9425 100644
--- a/php/tasks/sury_pre.yml
+++ b/php/tasks/sury_pre.yml
@@ -27,15 +27,6 @@
repo: "deb [signed-by={{ apt_keyring_dir }}/pub_evolix.asc] http://pub.evolix.org/evolix {{ ansible_distribution_release }}-php{{ php_version | replace('.', '')}} main"
filename: evolix-php
state: present
- when:
- - ansible_distribution_release == "bullseye"
-
-- name: Setup deb.sury.org repository - Add preferences file
- ansible.builtin.copy:
- src: sury.preferences
- dest: /etc/apt/preferences.d/z-sury
- when:
- - ansible_distribution_release != "bullseye"
- name: Setup deb.sury.org repository - Add GPG key
ansible.builtin.copy:
diff --git a/postfix/defaults/main.yml b/postfix/defaults/main.yml
index 55ab72cd..53ae5360 100644
--- a/postfix/defaults/main.yml
+++ b/postfix/defaults/main.yml
@@ -1,5 +1,7 @@
---
-postfix_hostname: "{{ ansible_fqdn }}"
+postfix_hostname: "{{ evolinux_fqdn }}"
postfix_force_main_cf: False
postfix_packmail: False
-postfix_slow_transport_include: "{{ postfix_packmail }}"
+postfix_slow_transport_include: False
+postfix_purge_exim: True
+
diff --git a/postfix/files/spam.sh b/postfix/files/spam.sh
index 29dc0b40..b8685f85 100644
--- a/postfix/files/spam.sh
+++ b/postfix/files/spam.sh
@@ -40,7 +40,7 @@ function cleanup {
}
# Postfix
-postfix_dbs="client.access sender.access recipient.access header_kill sa-blacklist.access spamd.cidr"
+postfix_dbs="client.access sender.access recipient.access header_kill"
for db in ${postfix_dbs}; do
if is_new "${db}"; then
download "${db}"
diff --git a/postfix/tasks/common.yml b/postfix/tasks/common.yml
index 29e6dd07..b2a09398 100644
--- a/postfix/tasks/common.yml
+++ b/postfix/tasks/common.yml
@@ -1,11 +1,32 @@
----
-- name: check if main.cf is default
+- name: Postfix packages are installed
+ ansible.builtin.apt:
+ name:
+ - postfix
+ - mailgraph
+ state: present
+ tags:
+ - postfix
+
+- name: exim4 is absent
+ ansible.builtin.apt:
+ name:
+ - exim4
+ - exim4-base
+ - exim4-config
+ - exim4-daemon-light
+ purge: yes
+ state: absent
+ tags:
+ - postfix
+ when: postfix_purge_exim | bool
+
+- name: compute main.cf SHA1 checksum
ansible.builtin.shell:
- cmd: 'grep -v -E "^(myhostname|mydestination|mailbox_command)" /etc/postfix/main.cf | md5sum -'
+ cmd: 'grep -v -E "^(myhostname|mydestination|mailbox_command)" /etc/postfix/main.cf | sha1sum | cut -d " " -f1'
changed_when: False
check_mode: no
- register: default_main_cf
+ register: main_cf_checksum
tags:
- postfix
diff --git a/postfix/tasks/minimal.yml b/postfix/tasks/minimal.yml
index 36327b3e..b7bd29d0 100644
--- a/postfix/tasks/minimal.yml
+++ b/postfix/tasks/minimal.yml
@@ -1,10 +1,8 @@
---
-- name: ensure packages are installed
- ansible.builtin.apt:
- name: postfix
- state: present
- tags:
- - postfix
+
+- name: display checksums of known main.cf files
+ debug:
+ var: main_cf_known_checksums
- name: create minimal main.cf
ansible.builtin.template:
@@ -15,6 +13,6 @@
mode: "0644"
force: true
notify: restart postfix
- when: (postfix_force_main_cf | bool) or (postfix_maincf_md5_jessie in default_main_cf.stdout) or (postfix_maincf_md5_stretch in default_main_cf.stdout)
+ when: (postfix_force_main_cf | bool) or (main_cf_checksum.stdout in main_cf_known_checksums)
tags:
- postfix
diff --git a/postfix/tasks/packmail-spam.yml b/postfix/tasks/packmail-spam.yml
index 114be769..f90f8cae 100644
--- a/postfix/tasks/packmail-spam.yml
+++ b/postfix/tasks/packmail-spam.yml
@@ -1,8 +1,6 @@
---
-- name: "mount /usr in rw"
- ansible.builtin.command:
- cmd: 'mount -o remount,rw /usr'
- changed_when: False
+- ansible.builtin.include_role:
+ name: evolix/remount-usr
tags: postfix
- name: copy spam.sh script
diff --git a/postfix/tasks/packmail.yml b/postfix/tasks/packmail.yml
index 6562e0d3..692024fa 100644
--- a/postfix/tasks/packmail.yml
+++ b/postfix/tasks/packmail.yml
@@ -1,11 +1,9 @@
---
-- name: ensure packages are installed
+- name: Complementary packmail packages are installed
ansible.builtin.apt:
name:
- - postfix
- postfix-ldap
- postfix-policyd-spf-python
- - mailgraph
state: present
tags:
- postfix
@@ -24,6 +22,10 @@
enabled: yes
state: started
+- name: display checksums of known main.cf files
+ debug:
+ var: main_cf_known_checksums
+
- name: create packmail main.cf
ansible.builtin.template:
src: packmail_main.cf.j2
@@ -33,7 +35,7 @@
mode: "0644"
force: true
notify: restart postfix
- when: (postfix_force_main_cf | bool) or (postfix_maincf_md5_jessie in default_main_cf.stdout) or (postfix_maincf_md5_stretch in default_main_cf.stdout)
+ when: (postfix_force_main_cf | bool) or (main_cf_checksum.stdout in main_cf_known_checksums)
tags:
- postfix
diff --git a/postfix/templates/packmail_main.cf.j2 b/postfix/templates/packmail_main.cf.j2
index 65c95866..4bcbb2dd 100644
--- a/postfix/templates/packmail_main.cf.j2
+++ b/postfix/templates/packmail_main.cf.j2
@@ -66,7 +66,7 @@ smtpd_banner = $myhostname ESMTP mail server
# Indique le nom d'hote pleinement qualifie ou se trouve postfix [OBLIGATOIRE]
#par defaut, = [retour de la commande Unix hostname]
-myhostname = {{ ansible_fqdn }}
+myhostname = {{ postfix_hostname }}
# Variable indiquant le domaine dans lequel se trouve la machine
#par defaut, = [partie domain de la variable $myhostname]
diff --git a/postfix/vars/main.yml b/postfix/vars/main.yml
index e8a773c9..8d612f2e 100644
--- a/postfix/vars/main.yml
+++ b/postfix/vars/main.yml
@@ -1,5 +1,9 @@
---
-## MD5 hash of default main.cf filter, obtained with this command :
-# grep -v -E "^(myhostname|mydestination|mailbox_command)" /etc/postfix/main.cf | md5sum -
-postfix_maincf_md5_jessie: "5450c05d65878e99dad696c7c722e511"
-postfix_maincf_md5_stretch: "30022953f1f61f002bfb72e163ecb27e"
+# Output of default main.cf:
+# grep -v -E "^(myhostname|mydestination|mailbox_command)" /etc/postfix/main.cf | sha1sum | cut -d " " -f1
+main_cf_known_checksums:
+ - 72bd6999f053ea89b359e233cf252616ee6e2fbb # bookworm
+ - efd078215285ad520addee5b11af869717627b95 # bullseye
+ - c7d1e008120565927b213be1bf646fddfa949dc6 # buster
+ - 8b4de47321a9c003bf414a683c0d056b4469b325 # stretch
+ - f72feb50754830a7d8ae46f28e86d758881bcfc3 # jessie
diff --git a/proftpd/tasks/accounts.yml b/proftpd/tasks/accounts.yml
index 99b036c9..11b2f60d 100644
--- a/proftpd/tasks/accounts.yml
+++ b/proftpd/tasks/accounts.yml
@@ -61,6 +61,27 @@
tags:
- proftpd
+- name: Whitelist ip for users (SFTP)
+ ansible.builtin.blockinfile:
+ dest: /etc/proftpd/conf.d/sftp.conf
+ marker: "# {mark} ANSIBLE MANAGED BLOCK - Whitelist ip for users"
+ block: |
+ {% for user in proftpd_accounts_final %}
+ {% if user.group is defined %}
+
+
+ {% for ip in proftpd_sftp_ips_whitelist[user.group] %}
+ Allow from {{ ip }}
+ {% endfor %}
+ DenyAll
+
+
+ {% endif %}
+ {% endfor %}
+ insertbefore: ""
+ notify: restart proftpd
+ when: proftpd_sftp_enable_user_whitelist | bool
+
- name: Allow keys for SFTP account
ansible.builtin.template:
dest: "/etc/proftpd/sftp.authorized_keys/{{ _proftpd_account.name }}"
@@ -73,5 +94,6 @@
when:
- proftpd_sftp_enable | bool
- proftpd_sftp_use_publickeys | bool
+ - _proftpd_account.sshkeys is defined
tags:
- proftpd
diff --git a/redis/defaults/main.yml b/redis/defaults/main.yml
index b5547597..dc5a5d06 100644
--- a/redis/defaults/main.yml
+++ b/redis/defaults/main.yml
@@ -3,6 +3,8 @@ redis_systemd_name: redis-server
redis_conf_dir_prefix: /etc/redis
+redis_conf_marker_label: "ANSIBLE MANAGED CONFIGURATION"
+
redis_force_instance_port: False
redis_port: 6379
diff --git a/redis/files/munin_redis b/redis/files/munin_redis
index 55474435..ef3b61ad 100644
--- a/redis/files/munin_redis
+++ b/redis/files/munin_redis
@@ -1,243 +1,439 @@
#!/usr/bin/perl -w
-#
-## Copyright (C) 2009 Gleb Voronich
-##
-## This program is free software; you can redistribute it and/or
-## modify it under the terms of the GNU General Public License
-## as published by the Free Software Foundation; version 2 dated June,
-## 1991.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-##
-##
-## $Log$
-##
-## Based on Redis module code v0.08 2009/from http://svn.rot13.org/index.cgi/Redis
-##
-## Installation process:
-##
-## 1. Download the plugin to your plugins directory (e.g. /usr/share/munin/plugins)
-## 2. Create 3 symlinks at the directory that us used by munin for plugins detection (e.g. /etc/munin/plugins): redis_connected_clients, redis_per_sec and and redis_used_memory
-## 3. Edit plugin-conf.d/munin-node if it is needed (env.host and env.port variables are accepted; set env.password for password protected Redis server)
-## 4. Restart munin-node service
-##
-## Magic Markers
-#%# family=auto
-#%# capabilities=autoconf suggest
+=head CONFIGURATION
+
+ Based on Redis module code v0.08 2009/from http://svn.rot13.org/index.cgi/Redis
+
+ Installation process:
+
+ 1. Download the plugin to your plugins directory (e.g. /usr/share/munin/plugins)
+ 2. Symlink it to your configuration directory (e.g. ln -s /usr/share/munin/plugins/redis /etc/munin/plugins/redis)
+ 3. Edit plugin-conf.d/munin-node with the options to connect to your redis instances (see below for an example)
+ 4. Restart munin-node service
+
+ Example config
+ [redis]
+ env.host1 127.0.0.1
+ env.port1 6379
+ env.password1 password
+ env.title_prefix1 redis-1
+ env.host2 /run/redis.sock
+ env.title_prefix2 redis-2
+
+ Each host should be specified with at least a host or unixsocket variable suffixed with
+ a number, the first being 1, the second being 2 etc. They must be in sequence.
+ Other options are:
+ * port - the redis port to connect to
+ * password - the password to use with the AUTH command
+ * title_prefix - a prefix to put before the title of the graph, this is strongly recommended for multiple instances
+
+ Graphs:
+ This generates multigraphs for:
+ * Connected clients
+ * Key Hit vs Miss ratio
+ * Keys per second, hits/misses/expirations/evictions
+ * Replication backlog
+ * Replication lag
+ * Request per second
+ * Total number of keys and keys with expires
+ * Used memory
+
+=head COPYRIGHT
+
+ Copyright (C) 2020 Rowan Wookey
+ Copyright (C) 2009 Gleb Voronich
+
+=head LICENSE
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; version 2 dated June,
+ 1991.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+=head MAGIC MARKERS
+
+ #%# family=auto
+ #%# capabilities=autoconf
+
+=cut
use strict;
use IO::Socket::INET;
use IO::Socket::UNIX;
-use Switch;
-my $HOST = exists $ENV{'host'} ? $ENV{'host'} : "127.0.0.1";
-my $UNIX_SOCKET = exists $ENV{'unixsocket'} ? $ENV{'unixsocket'} : ''; # path to Redis Unix sock file
-my $PORT = exists $ENV{'port'} ? $ENV{'port'} : 6379;
-my $PASSWORD = exists $ENV{'password'} ? $ENV{'password'} : undef;
-my $TITLE_PREFIX = exists $ENV{'title_prefix'} ? $ENV{'title_prefix'} . ": " : "";
+my %INSTANCES;
+my $HOST;
+my $PORT;
+my $PASSWORD;
+
+for (my $i = 1; $ENV{"host$i"}; $i++)
+{
+ $HOST = exists $ENV{"host$i"} ? $ENV{"host$i"} : "127.0.0.1";
+ $PORT = exists $ENV{"port$i"} ? $ENV{"port$i"} : 6379;
+ $PASSWORD = exists $ENV{"password$i"} ? $ENV{"password$i"} : undef;
+ my $TITLE_PREFIX = exists $ENV{"title_prefix$i"} ? $ENV{"title_prefix$i"} . ": " : "";
+ my $SOCK = &get_conn();
+ $INSTANCES{"instance$i"} = {
+ HOST => $HOST,
+ PORT => $PORT,
+ PASSWORD => $PASSWORD,
+ TITLE_PREFIX => $TITLE_PREFIX,
+ SOCK => $SOCK
+ };
+}
+
-my $sock = &get_conn();
my $config = ( defined $ARGV[0] and $ARGV[0] eq "config" );
my $autoconf = ( defined $ARGV[0] and $ARGV[0] eq "autoconf" );
if ( $autoconf ) {
- if ( defined( $sock ) ) {
+ if (!%INSTANCES) {
+ print "no (no redis instances configured)\n";
+ exit 0;
+ }
+ my $err = '';
+ for my $INSTANCE (keys %INSTANCES) {
+ if (! defined( $INSTANCES{$INSTANCE}{'SOCK'} ) ) {
+ $err = "no (unable to connect to ".$INSTANCES{$INSTANCE}{'HOST'}."\[:". $INSTANCES{$INSTANCE}{'PORT'}."\])\n";
+ }
+ }
+ if ($err) {
+ print $err;
+ } else {
print "yes\n";
- exit 0;
- } else {
- print "no (unable to connect to $HOST\[:$PORT\])\n";
- exit 0;
- }
-}
-my $suggest = ( defined $ARGV[0] and $ARGV[0] eq "suggest" );
-if ( $suggest ) {
- if ( defined( $sock ) ) {
- my @plugins = ('connected_clients', 'key_ratio', 'keys_per_sec', 'per_sec', 'used_keys', 'used_memory');
- foreach my $plugin (@plugins) {
- print "$plugin\n";
- }
- exit 0;
- } else {
- print "no (unable to connect to $HOST\[:$PORT\])\n";
- exit 0;
}
+ exit 0;
}
-my $hash=&get_info();
+my $total = 0;
-$0 =~ s/(.+)redis_//g;
+my $multi_graph_output = '';
+my $instance_graph_output = '';
-switch ($0) {
- case "connected_clients" {
- if ( $config ) {
- my $maxclients= get_config("maxclients")->{"maxclients"};
- print "graph_title ${TITLE_PREFIX}Connected clients\n";
- print "graph_vlabel Connected clients\n";
- print "graph_category search\n";
- print "graph_args -l 0\n";
- print "connected_clients.line $maxclients:ff0000:Limit\n";
- print "connected_clients.label connected clients\n";
- exit 0;
+my $connected_clients = 0;
+my $keyspace_hits = 0;
+my $keyspace_misses = 0;
+my $expired_keys = 0;
+my $evicted_keys = 0;
+my $total_commands_processed = 0;
+my $total_connections_received = 0;
+my $repl_backlog_size = 0;
+my $used_memory = 0;
+my $used_memory_rss = 0;
+my $used_memory_peak = 0;
+my $total_keys = 0;
+my $total_expires = 0;
+foreach my $INSTANCE (keys %INSTANCES) {
+
+ my $sock = $INSTANCES{$INSTANCE}{'SOCK'};
+ my $TITLE_PREFIX = $INSTANCES{$INSTANCE}{'TITLE_PREFIX'};
+ my $hash = get_info($sock);
+
+ my $dbs;
+ foreach my $key (keys %{$hash}) {
+ if ( $key =~ /^db\d+$/ && $hash->{$key} =~ /keys=(\d+),expires=(\d+)/ ) {
+ $total_keys += $1;
+ $total_expires += $2;
+ $dbs->{$key} = [ $1, $2 ];
}
-
- print "connected_clients.value " . $hash->{'connected_clients'} . "\n";
}
-
- case "keys_per_sec" {
- if ( $config ) {
- print "graph_title ${TITLE_PREFIX}Keys Per Second\n";
- print "graph_vlabel per \${graph_period}\n";
- print "graph_category search\n";
- print "graph_args -l 0\n";
- print "hits.label hits\n";
- print "hits.type COUNTER\n";
- print "misses.label misses\n";
- print "misses.type COUNTER\n";
- print "expired.label expirations\n";
- print "expired.type COUNTER\n";
- print "evictions.label evictions\n";
- print "evictions.type COUNTER\n";
- exit 0;
+ if ( $config ) {
+ my $ret = get_config("maxclients", $sock);
+ # if the CONFIG command is disabled we don't show the max clients
+ my $maxclients = defined $ret ? $ret->{"maxclients"} : 0;
+ $instance_graph_output .= "multigraph redis_connected_clients.$INSTANCE\n";
+ $instance_graph_output .= "graph_title ${TITLE_PREFIX}Connected clients\n";
+ $instance_graph_output .= "graph_vlabel Connected clients\n";
+ $instance_graph_output .= "graph_category db\n";
+ $instance_graph_output .= "graph_args -l 0\n";
+ if ($maxclients) {
+ $instance_graph_output .= "connected_clients.line $maxclients:ff0000:Limit\n";
}
-
- print "hits.value " . $hash->{'keyspace_hits'} . "\n";
- print "misses.value " . $hash->{'keyspace_misses'} . "\n";
- print "expired.value " . $hash->{'expired_keys'} . "\n";
- print "evictions.value " . $hash->{'evicted_keys'} . "\n";
- }
-
- case "key_ratio" {
- if ( $config ) {
- print "graph_title ${TITLE_PREFIX}Key Hit vs Miss Ratio\n";
- print "graph_vlabel per \${graph_period}\n";
- print "graph_category search\n";
- print "graph_args -u 100 -l 0 -r --base 1000\n";
- print "hitratio.label hit ratio\n";
- print "hitratio.type GAUGE\n";
- print "hitratio.draw AREA\n";
- print "missratio.label miss ratio\n";
- print "missratio.type GAUGE\n";
- print "missratio.draw STACK\n";
- exit 0;
- }
-
- my $total = $hash->{'keyspace_hits'} + $hash->{'keyspace_misses'};
- my $hitratio = 0;
- my $missratio = 0;
- if ($total > 0) {
- $hitratio = $hash->{'keyspace_hits'} / $total * 100;
- $missratio = $hash->{'keyspace_misses'} / $total * 100;
- }
- printf("hitratio.value %.2f\n", $hitratio);
- printf("missratio.value %.2f\n", $missratio);
- }
-
-
- case "per_sec" {
- if ( $config ) {
- print "graph_title ${TITLE_PREFIX}Per second\n";
- print "graph_vlabel per \${graph_period}\n";
- print "graph_category search\n";
- print "graph_args -l 0\n";
- print "requests.label requests\n";
- print "requests.type COUNTER\n";
- print "connections.label connections\n";
- print "connections.type COUNTER\n";
- exit 0;
- }
-
- print "requests.value ". $hash->{'total_commands_processed'} ."\n";
- print "connections.value ". $hash->{'total_connections_received'} ."\n";
- }
-
-
- case "used_memory" {
- if ( $config ) {
- my $maxmemory = get_config("maxmemory")->{"maxmemory"};
- print "graph_title ${TITLE_PREFIX}Used memory\n";
- print "graph_vlabel Used memory\n";
- print "graph_category search\n";
- print "graph_args -l 0 --base 1024\n";
- print "used_memory.line $maxmemory:ff0000:Limit\n";
- print "used_memory.label used memory\n";
- print "used_memory_peak.label used memory in peak\n";
- print "used_memory_rss.label Resident set size memory usage\n";
- exit 0;
- }
-
- print "used_memory.value ". $hash->{'used_memory'} ."\n";
- print "used_memory_rss.value ". $hash->{'used_memory_rss'} ."\n";
- print "used_memory_peak.value ". $hash->{'used_memory_peak'} ."\n";
- }
-
- case "used_keys" {
- my $dbs;
- foreach my $key (keys %{$hash}) {
- if ( $key =~ /^db\d+$/ && $hash->{$key} =~ /keys=(\d+),expires=(\d+)/ ) {
- $dbs->{$key} = [ $1, $2 ];
- }
- }
-
- if ( $config ) {
- print "graph_title ${TITLE_PREFIX}Used keys\n";
- print "graph_vlabel Used keys\n";
- print "graph_category search\n";
- print "graph_args -l 0\n";
-
- foreach my $db (keys %{$dbs}) {
- printf "%s_keys.label %s keys\n", $db, $db;
- printf "%s_expires.label %s expires\n", $db, $db;
- }
-
- exit 0;
+ $instance_graph_output .= "connected_clients.label connected clients\n";
+ $instance_graph_output .= "multigraph keys_per_sec.$INSTANCE\n";
+ $instance_graph_output .= "graph_title ${TITLE_PREFIX}Keys Per Second\n";
+ $instance_graph_output .= "graph_vlabel per \${graph_period}\n";
+ $instance_graph_output .= "graph_category db\n";
+ $instance_graph_output .= "graph_args -l 0\n";
+ $instance_graph_output .= "hits.label hits\n";
+ $instance_graph_output .= "hits.type COUNTER\n";
+ $instance_graph_output .= "misses.label misses\n";
+ $instance_graph_output .= "misses.type COUNTER\n";
+ $instance_graph_output .= "expired.label expirations\n";
+ $instance_graph_output .= "expired.type COUNTER\n";
+ $instance_graph_output .= "evicted_keys.label evictions\n";
+ $instance_graph_output .= "evicted_keys.type COUNTER\n";
+ $instance_graph_output .= "multigraph redis_key_ratio.$INSTANCE\n";
+ $instance_graph_output .= "graph_title ${TITLE_PREFIX}Key Hit vs Miss Ratio\n";
+ $instance_graph_output .= "graph_vlabel per \${graph_period}\n";
+ $instance_graph_output .= "graph_category db\n";
+ $instance_graph_output .= "graph_args -u 100 -l 0 -r --base 1000\n";
+ $instance_graph_output .= "hitratio.label hit ratio\n";
+ $instance_graph_output .= "hitratio.type GAUGE\n";
+ $instance_graph_output .= "hitratio.draw AREA\n";
+ $instance_graph_output .= "missratio.label miss ratio\n";
+ $instance_graph_output .= "missratio.type GAUGE\n";
+ $instance_graph_output .= "missratio.draw STACK\n";
+ $instance_graph_output .= "multigraph redis_per_sec.$INSTANCE\n";
+ $instance_graph_output .= "graph_title ${TITLE_PREFIX}Requests Per second\n";
+ $instance_graph_output .= "graph_vlabel per \${graph_period}\n";
+ $instance_graph_output .= "graph_category db\n";
+ $instance_graph_output .= "graph_args -l 0\n";
+ $instance_graph_output .= "requests.label requests\n";
+ $instance_graph_output .= "requests.type COUNTER\n";
+ $instance_graph_output .= "connections.label connections\n";
+ $instance_graph_output .= "connections.type COUNTER\n";
+ $instance_graph_output .= "multigraph redis_repl_backlog_size.$INSTANCE\n";
+ $instance_graph_output .= "graph_title ${TITLE_PREFIX}replication backlog\n";
+ $instance_graph_output .= "graph_vlabel replication backlog\n";
+ $instance_graph_output .= "graph_category db\n";
+ $instance_graph_output .= "graph_args -l 0\n";
+ $instance_graph_output .= "repl_backlog_size.label bytes behind master\n";
+ $instance_graph_output .= "multigraph redis_repl_lag.$INSTANCE\n";
+ $instance_graph_output .= "graph_title ${TITLE_PREFIX}replication lag\n";
+ $instance_graph_output .= "graph_vlabel replication lag\n";
+ $instance_graph_output .= "graph_category db\n";
+ $instance_graph_output .= "graph_args -l 0\n";
+ $instance_graph_output .= "repl_backlog_size.label amount behind master\n";
+ # if the CONFIG command is disabled we don't show maxmemory
+ $ret = get_config("maxmemory", $sock);
+ my $maxmemory = defined $ret ? $ret->{"maxmemory"} : 0;
+ $instance_graph_output .= "multigraph redis_used_memory.$INSTANCE\n";
+ $instance_graph_output .= "graph_title ${TITLE_PREFIX}Used memory\n";
+ $instance_graph_output .= "graph_vlabel Used memory\n";
+ $instance_graph_output .= "graph_category db\n";
+ $instance_graph_output .= "graph_args -l 0 --base 1024\n";
+ if ($maxmemory) {
+ $instance_graph_output .= "used_memory.line $maxmemory:ff0000:Limit\n";
}
+ $instance_graph_output .= "used_memory.label used memory\n";
+ $instance_graph_output .= "used_memory_peak.label used memory in peak\n";
+ $instance_graph_output .= "used_memory_rss.label Resident set size memory usage\n";
+ $instance_graph_output .= "multigraph redis_used_keys.$INSTANCE\n";
+ $instance_graph_output .= "graph_title ${TITLE_PREFIX}Used keys\n";
+ $instance_graph_output .= "graph_vlabel Used keys\n";
+ $instance_graph_output .= "graph_category db\n";
+ $instance_graph_output .= "graph_args -l 0\n";
foreach my $db (keys %{$dbs}) {
- printf "%s_keys.value %d\n", $db, $dbs->{$db}[0];
- printf "%s_expires.value %d\n", $db, $dbs->{$db}[1];
+ $instance_graph_output .= sprintf "%s_keys.label %s keys\n", $db, $db;
+ $instance_graph_output .= sprintf "%s_expires.label %s expires\n", $db, $db;
}
+
+ next;
}
+
+ $instance_graph_output .= "multigraph redis_connected_clients.$INSTANCE\n";
+ $instance_graph_output .= "connected_clients.value " . $hash->{'connected_clients'} . "\n";
+ $connected_clients += $hash->{'connected_clients'};
+ $instance_graph_output .= "multigraph keys_per_sec.$INSTANCE\n";
+ $instance_graph_output .= "hits.value " . $hash->{'keyspace_hits'} . "\n";
+ $keyspace_hits += $hash->{'keyspace_hits'};
+ $instance_graph_output .= "misses.value " . $hash->{'keyspace_misses'} . "\n";
+ $keyspace_misses += $hash->{'keyspace_misses'};
+ $instance_graph_output .= "expired.value " . $hash->{'expired_keys'} . "\n";
+ $expired_keys += $hash->{'expired_keys'};
+ $instance_graph_output .= "evicted_keys.value " . $hash->{'evicted_keys'} . "\n";
+ $evicted_keys += $hash->{'evicted_keys'};
+ $instance_graph_output .= "multigraph redis_key_ratio.$INSTANCE\n";
+ my $total = $hash->{'keyspace_hits'} + $hash->{'keyspace_misses'};
+ my $hitratio = 0;
+ my $missratio = 0;
+ if ($total > 0) {
+ $hitratio = $hash->{'keyspace_hits'} / $total * 100;
+ $missratio = $hash->{'keyspace_misses'} / $total * 100;
+ }
+ $instance_graph_output .= sprintf("hitratio.value %.2f\n", $hitratio);
+ $instance_graph_output .= sprintf("missratio.value %.2f\n", $missratio);
+ $instance_graph_output .= "multigraph redis_per_sec.$INSTANCE\n";
+ $instance_graph_output .= "requests.value ". $hash->{'total_commands_processed'} ."\n";
+ $total_commands_processed += $hash->{'total_commands_processed'};
+ $instance_graph_output .= "connections.value ". $hash->{'total_connections_received'} ."\n";
+ $total_connections_received += $hash->{'total_connections_received'};
+ $instance_graph_output .= "multigraph redis_repl_backlog_size.$INSTANCE\n";
+ $instance_graph_output .= "repl_backlog_size.value " . $hash->{'repl_backlog_size'} . "\n";
+ $repl_backlog_size += $hash->{'repl_backlog_size'};
+
+ $instance_graph_output .= "multigraph redis_repl_lag.$INSTANCE\n";
+ if (exists $hash->{slave0} && $hash->{slave0} =~ /lag=(\d+)/) {
+ $repl_backlog_size += $1;
+ $instance_graph_output .= "repl_backlog_size.value " . $1 . "\n";
+ } else {
+ $instance_graph_output .= "repl_backlog_size.value 0\n";
+ }
+
+
+ $instance_graph_output .= "multigraph redis_used_memory.$INSTANCE\n";
+ $instance_graph_output .= "used_memory.value ". $hash->{'used_memory'} ."\n";
+
+ $used_memory += $hash->{'used_memory'};
+ $instance_graph_output .= "used_memory_rss.value ". $hash->{'used_memory_rss'} ."\n";
+ $used_memory_rss += $hash->{'used_memory_rss'};
+ $instance_graph_output .= "used_memory_peak.value ". $hash->{'used_memory_peak'} ."\n";
+ $used_memory_peak += $hash->{'used_memory_peak'};
+
+ $instance_graph_output .= "multigraph redis_used_keys.$INSTANCE\n";
+ foreach my $db (keys %{$dbs}) {
+ $instance_graph_output .= sprintf "%s_keys.value %d\n", $db, $dbs->{$db}[0];
+ $instance_graph_output .= sprintf "%s_expires.value %d\n", $db, $dbs->{$db}[1];
+ }
+ close ($sock);
}
-close ($sock);
+# multigraph output
+if ($config) {
+ $multi_graph_output .= "multigraph redis_connected_clients\n";
+ $multi_graph_output .= "graph_title Connected clients\n";
+ $multi_graph_output .= "graph_vlabel Connected clients\n";
+ $multi_graph_output .= "graph_category db\n";
+ $multi_graph_output .= "graph_args -l 0\n";
+ $multi_graph_output .= "connected_clients.label connected clients\n";
+ $multi_graph_output .= "multigraph keys_per_sec\n";
+ $multi_graph_output .= "graph_title Keys Per Second\n";
+ $multi_graph_output .= "graph_vlabel per \${graph_period}\n";
+ $multi_graph_output .= "graph_category db\n";
+ $multi_graph_output .= "graph_args -l 0\n";
+ $multi_graph_output .= "hits.label hits\n";
+ $multi_graph_output .= "hits.type COUNTER\n";
+ $multi_graph_output .= "misses.label misses\n";
+ $multi_graph_output .= "misses.type COUNTER\n";
+ $multi_graph_output .= "expired.label expirations\n";
+ $multi_graph_output .= "expired.type COUNTER\n";
+ $multi_graph_output .= "evicted_keys.label evictions\n";
+ $multi_graph_output .= "evicted_keys.type COUNTER\n";
+ $multi_graph_output .= "multigraph redis_key_ratio\n";
+ $multi_graph_output .= "graph_title Key Hit vs Miss Ratio\n";
+ $multi_graph_output .= "graph_vlabel per \${graph_period}\n";
+ $multi_graph_output .= "graph_category db\n";
+ $multi_graph_output .= "graph_args -u 100 -l 0 -r --base 1000\n";
+ $multi_graph_output .= "hitratio.label hit ratio\n";
+ $multi_graph_output .= "hitratio.type GAUGE\n";
+ $multi_graph_output .= "hitratio.draw AREA\n";
+ $multi_graph_output .= "missratio.label miss ratio\n";
+ $multi_graph_output .= "missratio.type GAUGE\n";
+ $multi_graph_output .= "missratio.draw STACK\n";
+ $multi_graph_output .= "multigraph redis_per_sec\n";
+ $multi_graph_output .= "graph_title Requests Per second\n";
+ $multi_graph_output .= "graph_vlabel per \${graph_period}\n";
+ $multi_graph_output .= "graph_category db\n";
+ $multi_graph_output .= "graph_args -l 0\n";
+ $multi_graph_output .= "requests.label requests\n";
+ $multi_graph_output .= "requests.type COUNTER\n";
+ $multi_graph_output .= "connections.label connections\n";
+ $multi_graph_output .= "connections.type COUNTER\n";
+ $multi_graph_output .= "multigraph redis_repl_backlog_size\n";
+ $multi_graph_output .= "graph_title replication backlog\n";
+ $multi_graph_output .= "graph_vlabel replication backlog\n";
+ $multi_graph_output .= "graph_category db\n";
+ $multi_graph_output .= "graph_args -l 0\n";
+ $multi_graph_output .= "repl_backlog_size.label bytes behind master\n";
+ $multi_graph_output .= "multigraph redis_repl_lag\n";
+ $multi_graph_output .= "graph_title replication lag\n";
+ $multi_graph_output .= "graph_vlabel replication lag\n";
+ $multi_graph_output .= "graph_category db\n";
+ $multi_graph_output .= "graph_args -l 0\n";
+ $multi_graph_output .= "repl_backlog_size.label amount behind master\n";
+ $multi_graph_output .= "multigraph redis_used_memory\n";
+ $multi_graph_output .= "graph_title Used memory\n";
+ $multi_graph_output .= "graph_vlabel Used memory\n";
+ $multi_graph_output .= "graph_category db\n";
+ $multi_graph_output .= "graph_args -l 0 --base 1024\n";
+ $multi_graph_output .= "used_memory.label used memory\n";
+ $multi_graph_output .= "used_memory_peak.label used memory in peak\n";
+ $multi_graph_output .= "used_memory_rss.label Resident set size memory usage\n";
+ $multi_graph_output .= "multigraph redis_used_keys\n";
+ $multi_graph_output .= "graph_title Used keys\n";
+ $multi_graph_output .= "graph_vlabel Used keys\n";
+ $multi_graph_output .= "graph_category db\n";
+ $multi_graph_output .= "graph_args -l 0\n";
+ $multi_graph_output .= "total_keys.label Total keys\n";
+ $multi_graph_output .= "total_expires.label Total expires\n";
+} else {
+
+ $multi_graph_output .= "multigraph redis_connected_clients\n";
+ $multi_graph_output .= "connected_clients.value " . $connected_clients . "\n";
+ $multi_graph_output .= "multigraph keys_per_sec\n";
+ $multi_graph_output .= "hits.value " . $keyspace_hits . "\n";
+ $multi_graph_output .= "misses.value " . $keyspace_misses . "\n";
+ $multi_graph_output .= "expired.value " . $expired_keys . "\n";
+ $multi_graph_output .= "evicted_keys.value " . $evicted_keys . "\n";
+ $multi_graph_output .= "multigraph redis_key_ratio\n";
+ my $total = $keyspace_hits + $keyspace_misses;
+ my $hitratio = 0;
+ my $missratio = 0;
+ if ($total > 0) {
+ $hitratio = $keyspace_hits / $total * 100;
+ $missratio = $keyspace_misses / $total * 100;
+ }
+ $multi_graph_output .= sprintf("hitratio.value %.2f\n", $hitratio);
+ $multi_graph_output .= sprintf("missratio.value %.2f\n", $missratio);
+ $multi_graph_output .= "multigraph redis_per_sec\n";
+ $multi_graph_output .= "requests.value ". $total_commands_processed ."\n";
+ $multi_graph_output .= "connections.value ". $total_connections_received ."\n";
+ $multi_graph_output .= "multigraph redis_repl_backlog_size\n";
+ $multi_graph_output .= "repl_backlog_size.value " . $repl_backlog_size . "\n";
+
+ $multi_graph_output .= "multigraph redis_repl_lag\n";
+ $multi_graph_output .= "repl_backlog_size.value " . $repl_backlog_size . "\n";
+
+
+ $multi_graph_output .= "multigraph redis_used_memory\n";
+ $multi_graph_output .= "used_memory.value ". $used_memory ."\n";
+
+ $multi_graph_output .= "used_memory_rss.value ". $used_memory_rss ."\n";
+ $multi_graph_output .= "used_memory_peak.value ". $used_memory_peak ."\n";
+
+ $multi_graph_output .= "multigraph redis_used_keys\n";
+ $multi_graph_output .= "total_keys.value $total_keys\n";
+ $multi_graph_output .= "total_expires.value $total_expires\n";
+
+}
+print $multi_graph_output;
+print $instance_graph_output;
sub get_conn {
-
+
my $sock;
-
- if( $UNIX_SOCKET && -S $UNIX_SOCKET ){
-
- $sock = IO::Socket::UNIX->new(
- Type => SOCK_STREAM(),
- Peer => $UNIX_SOCKET,
- );
-
+
+ if(-S $HOST ){
+
+ $sock = IO::Socket::UNIX->new(
+ Type => SOCK_STREAM(),
+ Peer => $HOST,
+ );
}else{
-
- $sock = IO::Socket::INET->new(
- PeerAddr => $HOST,
- PeerPort => $PORT,
- Timeout => 10,
- Proto => 'tcp'
- );
+
+ $sock = IO::Socket::INET->new(
+ PeerAddr => $HOST,
+ PeerPort => $PORT,
+ Timeout => 10,
+ Proto => 'tcp'
+ );
}
-
+
+ if (! defined($sock)) {
+ die "can't read socket: $!";
+ }
+
if ( defined( $PASSWORD ) ) {
print $sock "AUTH ", $PASSWORD, "\r\n";
my $result = <$sock> || die "can't read socket: $!";
}
+
return $sock;
}
sub get_info{
+ my $sock = $_[0];
print $sock "INFO\r\n";
my $result = <$sock> || die "can't read socket: $!";
@@ -257,13 +453,12 @@ sub get_info{
# This subroutine returns configuration matched to supplied as object
sub get_config{
-
+ my $sock = $_[1];
print $sock "*3\r\n\$6\r\nCONFIG\r\n\$3\r\nGET\r\n\$".length($_[0])."\r\n".$_[0]."\r\n";
# Response will look like like
# *2\r\n$9\r\nmaxmemory\r\n$10\r\n3221225472\r\n
my $type = <$sock> || die "can't read socket: $!";
-
my $conf;
if( substr($type,0,1) ne "*" ) {
return $conf;
diff --git a/redis/tasks/default-server.yml b/redis/tasks/default-server.yml
index 89a664e6..89ba641e 100644
--- a/redis/tasks/default-server.yml
+++ b/redis/tasks/default-server.yml
@@ -1,12 +1,32 @@
---
-- name: Redis is configured.
- ansible.builtin.template:
- src: redis.conf.j2
- dest: "{{ redis_conf_dir }}/redis.conf"
+- name: "Add begin marker if missing"
+ ansible.builtin.lineinfile:
+ path: "{{ redis_conf_dir }}/redis.conf"
+ line: "# BEGIN {{ redis_conf_marker_label }}"
+ insertbefore: BOF
+ create: yes
+ tags:
+ - redis
+
+- name: "Add end marker if missing"
+ ansible.builtin.lineinfile:
+ path: "{{ redis_conf_dir }}/redis.conf"
+ line: "# END {{ redis_conf_marker_label }}"
+ insertbefore: "Generated by CONFIG REWRITE"
+ create: yes
+ tags:
+ - redis
+
+- name: "Create config if missing"
+ ansible.builtin.blockinfile:
+ path: "{{ redis_conf_dir }}/redis.conf"
+ marker: "# {mark} {{ redis_conf_marker_label }}"
+ block: "{{ lookup('ansible.builtin.template', '../templates/redis.conf.j2') }}"
mode: "0640"
owner: redis
group: redis
+ create: yes
notify: "{{ redis_restart_handler_name }}"
tags:
- redis
diff --git a/redis/tasks/instance-server.yml b/redis/tasks/instance-server.yml
index 42dc1876..b5f11053 100644
--- a/redis/tasks/instance-server.yml
+++ b/redis/tasks/instance-server.yml
@@ -118,14 +118,33 @@
tags:
- redis
+- name: "Add begin marker if missing"
+ ansible.builtin.lineinfile:
+ path: "{{ redis_conf_dir }}/redis.conf"
+ line: "# BEGIN {{ redis_conf_marker_label }}"
+ insertbefore: BOF
+ create: yes
+ tags:
+ - redis
-- name: "Instance '{{ redis_instance_name }}' configuration file is present"
- ansible.builtin.template:
- src: redis.conf.j2
- dest: "{{ redis_conf_dir }}/redis.conf"
+- name: "Add end marker if missing"
+ ansible.builtin.lineinfile:
+ path: "{{ redis_conf_dir }}/redis.conf"
+ line: "# END {{ redis_conf_marker_label }}"
+ insertbefore: "# Generated by CONFIG REWRITE"
+ create: yes
+ tags:
+ - redis
+
+- name: "Create config if missing"
+ ansible.builtin.blockinfile:
+ path: "{{ redis_conf_dir }}/redis.conf"
+ marker: "# {mark} {{ redis_conf_marker_label }}"
+ block: "{{ lookup('ansible.builtin.template', '../templates/redis.conf.j2') }}"
mode: "0640"
owner: redis-{{ redis_instance_name }}
group: redis-{{ redis_instance_name }}
+ create: yes
notify: "{{ redis_restart_handler_name }}"
tags:
- redis
diff --git a/redis/tasks/thp.yml b/redis/tasks/thp.yml
index 7a215788..133466b7 100644
--- a/redis/tasks/thp.yml
+++ b/redis/tasks/thp.yml
@@ -23,6 +23,7 @@
path: /etc/sysfs.conf
line: kernel/mm/transparent_hugepage/enabled = {{ redis_sysctl_transparent_hugepage_enabled }}
regexp: "kernel/mm/transparent_hugepage/enabled"
+ create: yes
tags:
- redis
- kernel
@@ -32,4 +33,4 @@
cmd: "echo '{{ redis_sysctl_transparent_hugepage_enabled }}' >> /sys/kernel/mm/transparent_hugepage/enabled"
tags:
- redis
- - kernel
\ No newline at end of file
+ - kernel
diff --git a/remount-usr/tasks/main.yml b/remount-usr/tasks/main.yml
index eb5c0109..034a66f5 100644
--- a/remount-usr/tasks/main.yml
+++ b/remount-usr/tasks/main.yml
@@ -1,17 +1,18 @@
---
# findmnt returns 0 on hit, 1 on miss
# If the return code is higher than 1, it's a blocking failure
+
- name: "check if /usr is a read-only partition"
ansible.builtin.command:
cmd: 'findmnt /usr --noheadings --options ro'
changed_when: False
failed_when: usr_partition.rc > 1
- check_mode: no
register: usr_partition
+ check_mode: False
- name: "mount /usr in rw"
ansible.builtin.command:
- cmd: 'mount -o remount,rw /usr'
- changed_when: False
+ cmd: 'mount --options remount,rw /usr'
when: usr_partition.rc == 0
notify: remount usr
+ changed_when: False
diff --git a/spamassasin/handlers/main.yml b/spamassasin/handlers/main.yml
index 78597a37..7dbc9c7f 100644
--- a/spamassasin/handlers/main.yml
+++ b/spamassasin/handlers/main.yml
@@ -3,3 +3,8 @@
ansible.builtin.service:
name: spamassassin
state: restarted
+
+- name: restart spamd
+ ansible.builtin.service:
+ name: spamd
+ state: restarted
diff --git a/spamassasin/tasks/main.yml b/spamassasin/tasks/main.yml
index 9f2889ca..0ee6f76a 100644
--- a/spamassasin/tasks/main.yml
+++ b/spamassasin/tasks/main.yml
@@ -1,29 +1,47 @@
---
-- name: install SpamAssasin
+
+- name: For Debian < 12
+ set_fact:
+ spamassassin_restart_handler: restart spamassassin
+ spamassassin_package_name: spamassassin
+ tags:
+ - spamassassin
+ when: ansible_distribution_major_version is version('12', '<')
+
+# the package is called "spamd" after Debian 12
+- name: For Debian >= 12
+ set_fact:
+ spamassassin_restart_handler: restart spamd
+ spamassassin_package_name: spamd
+ tags:
+ - spamassassin
+ when: ansible_distribution_major_version is version('12', '>=')
+
+- name: Install SpamAssassin
ansible.builtin.apt:
name:
- - spamassassin
+ - "{{ spamassassin_package_name }}"
state: present
tags:
- spamassassin
-- name: configure SpamAssasin
+- name: Configure SpamAssassin
ansible.builtin.copy:
src: spamassassin.cf
dest: /etc/spamassassin/local_evolix.cf
mode: "0644"
- notify: restart spamassassin
+ notify: "{{ spamassassin_restart_handler }}"
tags:
- spamassassin
-- name: enable SpamAssasin
+- name: Enable SpamAssassin
ansible.builtin.replace:
dest: /etc/default/spamassassin
regexp: 'ENABLED=0'
replace: 'ENABLED=1'
- notify: restart spamassassin
tags:
- spamassassin
+ when: ansible_distribution_major_version is version('12', '<')
- name: add amavis user to debian-spamd group
ansible.builtin.user:
@@ -97,5 +115,15 @@
name: spamassassin
state: started
enabled: True
+ when: ansible_distribution_major_version is version('12', '<')
+ tags:
+ - spamassassin
+
+- name: ensure spamd is started and enabled
+ ansible.builtin.systemd:
+ name: spamd
+ state: started
+ enabled: True
+ when: ansible_distribution_major_version is version('12', '>=')
tags:
- spamassassin
diff --git a/squid/README.md b/squid/README.md
index 8811a91f..aba25b4d 100644
--- a/squid/README.md
+++ b/squid/README.md
@@ -6,7 +6,7 @@ Installation and configuration of Squid
Everything is in the `tasks/main.yml` file.
-A blank file is created at `/etc/squid3/whitelist-custom.conf` to add addresses in the whitelist.
+A blank file is created at `/etc/squid/whitelist-custom.conf` to add addresses in the whitelist.
## Available variables
diff --git a/squid/tasks/main.yml b/squid/tasks/main.yml
index 2f0e94aa..965be04b 100644
--- a/squid/tasks/main.yml
+++ b/squid/tasks/main.yml
@@ -38,14 +38,14 @@
- name: "squid.conf is present (jessie)"
ansible.builtin.template:
src: squid.conf.j2
- dest: /etc/squid3/squid.conf
+ dest: /etc/squid/squid.conf
notify: "restart squid3"
when: ansible_distribution_release == "jessie"
- name: "evolix whitelist is present (jessie)"
ansible.builtin.copy:
src: whitelist-evolinux.conf
- dest: /etc/squid3/whitelist.conf
+ dest: /etc/squid/whitelist.conf
force: false
notify: "reload squid3"
when: ansible_distribution_release == "jessie"
@@ -135,7 +135,7 @@
- name: add some URL in whitelist (Debian 8)
ansible.builtin.lineinfile:
insertafter: EOF
- dest: /etc/squid3/whitelist.conf
+ dest: /etc/squid/whitelist.conf
line: "{{ item }}"
state: present
loop: '{{ squid_whitelist_items }}'
diff --git a/squid/templates/squid.conf.j2 b/squid/templates/squid.conf.j2
index 108a3bc1..4c89a777 100644
--- a/squid/templates/squid.conf.j2
+++ b/squid/templates/squid.conf.j2
@@ -8,7 +8,7 @@ acl localhost src 127.0.0.0/32
acl INTERNE src {{ squid_address }}/32 127.0.0.0/8
acl Safe_ports port 80 # http
acl SSL_ports port 443 563
-acl WHITELIST url_regex "/etc/squid3/whitelist.conf"
+acl WHITELIST url_regex "/etc/squid/whitelist.conf"
http_access deny !WHITELIST
http_access allow INTERNE
http_access deny all
diff --git a/timesyncd/templates/timesyncd.conf.j2 b/timesyncd/templates/timesyncd.conf.j2
index 8aebc1be..f58f81ee 100644
--- a/timesyncd/templates/timesyncd.conf.j2
+++ b/timesyncd/templates/timesyncd.conf.j2
@@ -1,3 +1,3 @@
# {{ ansible_managed }}
[Time]
-NTP="{{ timesyncd_ntp_servers | join(' ') }}"
+NTP={{ timesyncd_ntp_servers | join(' ') }}
diff --git a/unbound/defaults/main.yml b/unbound/defaults/main.yml
index 86f51822..0d7807c1 100644
--- a/unbound/defaults/main.yml
+++ b/unbound/defaults/main.yml
@@ -1,9 +1,11 @@
---
+
unbound_interfaces:
-- '127.0.0.1'
-- '::1'
+ - '127.0.0.1'
+ - '::1'
+
unbound_acls:
-- '0.0.0.0/0 refuse'
-- '127.0.0.0/8 allow_snoop'
-- '::0/0 refuse'
-- '::1 allow_snoop'
+ - '0.0.0.0/0 refuse'
+ - '127.0.0.0/8 allow_snoop'
+ - '::0/0 refuse'
+ - '::1 allow_snoop'
diff --git a/unbound/files/munin-plugin.conf b/unbound/files/munin-plugin.conf
new file mode 100644
index 00000000..cf008d48
--- /dev/null
+++ b/unbound/files/munin-plugin.conf
@@ -0,0 +1,5 @@
+[unbound*]
+user root
+env.statefile /tmp/munin-unbound-state
+env.unbound_conf /etc/unbound/unbound.conf
+env.unbound_control /usr/sbin/unbound-control
diff --git a/unbound/handlers/main.yml b/unbound/handlers/main.yml
index 7c801751..fdb9a629 100644
--- a/unbound/handlers/main.yml
+++ b/unbound/handlers/main.yml
@@ -1,5 +1,15 @@
---
-- name: reload unbound
+- name: Restart unbound
+ ansible.builtin.service:
+ name: unbound
+ state: restarted
+
+- name: Reload unbound
ansible.builtin.service:
name: unbound
state: reloaded
+
+- name: Restart munin-node
+ ansible.builtin.service:
+ name: munin-node
+ state: restarted
diff --git a/unbound/tasks/main.yml b/unbound/tasks/main.yml
index 976c6386..acc24812 100644
--- a/unbound/tasks/main.yml
+++ b/unbound/tasks/main.yml
@@ -1,38 +1,74 @@
---
- name: Install Unbound package
ansible.builtin.apt:
- name: unbound
+ name:
+ - unbound
+ - unbound-anchor
+ - dns-root-data
state: present
- when: ansible_distribution == "Debian"
+ cache_valid_time: 3600
tags:
- - unbound
-
-- name: Retrieve list of root DNS servers
- ansible.builtin.get_url:
- url: https://www.internic.net/domain/named.cache
- dest: /etc/unbound/root.hints
- force: true
- mode: "0644"
- notify: reload unbound
- tags:
- - unbound
+ - unbound
- name: Copy Unbound config
ansible.builtin.template:
- src: unbound.conf.j2
- dest: /etc/unbound/unbound.conf
+ src: evolinux.conf.j2
+ dest: /etc/unbound/unbound.conf.d/evolinux.conf
owner: root
group: root
mode: "0644"
- when: ansible_distribution == "Debian"
- notify: reload unbound
+ notify: Reload unbound
tags:
- - unbound
+ - unbound
+
+- name: Copy Unbound config for reloading (Debian 11 and older)
+ ansible.builtin.template:
+ src: evolinux-reload.conf.j2
+ dest: /etc/unbound/unbound.conf.d/evolinux-reload.conf
+ owner: root
+ group: root
+ mode: "0644"
+ when:
+ - ansible_distribution_major_version is version('11', '<=')
+ notify: Restart unbound
+ tags:
+ - unbound
+
+- name: Copy munin plugin config
+ ansible.builtin.copy:
+ src: munin-plugin.conf
+ dest: /etc/munin/plugin-conf.d/unbound
+ owner: root
+ group: root
+ mode: "0644"
+ tags:
+ - unbound
+
+- name: Enable unbound munin plugin
+ ansible.builtin.file:
+ src: /usr/share/munin/plugins/unbound_munin_
+ dest: "/etc/munin/plugins/unbound_munin_{{ plugin_name }}"
+ state: link
+ loop:
+ - hits
+ - queue
+ - memory
+ - by_type
+ - by_class
+ - by_opcode
+ - by_rcode
+ - by_flags
+ - histogram
+ loop_control:
+ loop_var: plugin_name
+ notify: Restart munin-node
+ tags:
+ - unbound
- name: Starting and enabling Unbound
ansible.builtin.service:
name: unbound
- enabled: yes
+ enabled: true
state: started
tags:
- - unbound
+ - unbound
diff --git a/unbound/templates/evolinux-reload.conf.j2 b/unbound/templates/evolinux-reload.conf.j2
new file mode 100644
index 00000000..f2f395ae
--- /dev/null
+++ b/unbound/templates/evolinux-reload.conf.j2
@@ -0,0 +1,7 @@
+# {{ ansible_managed }}
+
+remote-control:
+ control-enable: yes
+ # by default the control interface is is 127.0.0.1 and ::1 and port 8953
+ # it is possible to use a unix socket too
+ control-interface: /run/unbound.ctl
diff --git a/unbound/templates/evolinux.conf.j2 b/unbound/templates/evolinux.conf.j2
new file mode 100644
index 00000000..339dfe45
--- /dev/null
+++ b/unbound/templates/evolinux.conf.j2
@@ -0,0 +1,53 @@
+server:
+ #interface: X.X.X.X
+ #interface: 127.0.0.1@5353 # listen on alternative port
+{% for interface in unbound_interfaces %}
+ interface: {{ interface }}
+{% endfor %}
+
+{% for acl in unbound_acls %}
+ access-control: {{ acl }}
+{% endfor %}
+
+ hide-identity: yes
+ hide-version: yes
+
+ root-hints: "/usr/share/dns/root.hints"
+
+ # Uncomment to enable DNSSEC validation.
+ #auto-trust-anchor-file: "/etc/unbound/root.key"
+
+ # Enable extended stats for munin plugin
+ extended-statistics: yes
+ statistics-cumulative: no
+ statistics-interval: 0
+
+
+ # Serve zones authoritatively from Unbound to resolver clients.
+ # Not for external service.
+
+ #local-zone: "local." static
+ #local-data: "mycomputer.local. IN A 192.0.2.51"
+ #local-zone: "2.0.192.in-addr.arpa." static
+ #local-data-ptr: "192.0.2.51 mycomputer.local
+ # UDP EDNS reassembly buffer advertised to peers. Default 4096.
+ # May need lowering on broken networks with fragmentation/MTU issues,
+ # particularly if validating DNSSEC.
+
+ #edns-buffer-size: 1480
+ # Use TCP for "forward-zone" requests. Useful if you are making
+ # DNS requests over an SSH port forwarding.
+ #tcp-upstream: yes
+
+
+# Use an upstream forwarder (recursive resolver) for specific zones.
+# Example addresses given below are public resolvers valid as of 2014/03.
+#
+#forward-zone:
+# name: "." # use for ALL queries
+# forward-addr: 74.82.42.42 # he.net
+# forward-addr: 2001:470:20::2 # he.net v6
+# forward-addr: 8.8.8.8 # google.com
+# forward-addr: 2001:4860:4860::8888 # google.com v6
+# forward-addr: 208.67.222.222 # opendns.com
+# forward-first: yes # try direct if forwarder fails
diff --git a/unbound/templates/unbound.conf.j2 b/unbound/templates/unbound.conf.j2
deleted file mode 100644
index a97e725d..00000000
--- a/unbound/templates/unbound.conf.j2
+++ /dev/null
@@ -1,45 +0,0 @@
-server:
- #interface: X.X.X.X
- #interface: 127.0.0.1@5353 # listen on alternative port
-{% for interface in unbound_interfaces %}
- interface: {{ interface }}
-{% endfor %}
- #do-ip6: no
-
-{% for acl in unbound_acls %}
- access-control: {{ acl }}
-{% endfor %}
-
- hide-identity: yes
- hide-version: yes
-
- root-hints: "/etc/unbound/root.hints"
- # Uncomment to enable DNSSEC validation.
- #auto-trust-anchor-file: "/etc/unbound/root.key"
- # Serve zones authoritatively from Unbound to resolver clients.
- # Not for external service.
-
- #local-zone: "local." static
- #local-data: "mycomputer.local. IN A 192.0.2.51"
- #local-zone: "2.0.192.in-addr.arpa." static
- #local-data-ptr: "192.0.2.51 mycomputer.local
- # UDP EDNS reassembly buffer advertised to peers. Default 4096.
- # May need lowering on broken networks with fragmentation/MTU issues,
- # particularly if validating DNSSEC.
-
- #edns-buffer-size: 1480
- # Use TCP for "forward-zone" requests. Useful if you are making
- # DNS requests over an SSH port forwarding.
- #tcp-upstream: yes
-
-# Use an upstream forwarder (recursive resolver) for specific zones.
-# Example addresses given below are public resolvers valid as of 2014/03.
-#
-#forward-zone:
-# name: "." # use for ALL queries
-# forward-addr: 74.82.42.42 # he.net
-# forward-addr: 2001:470:20::2 # he.net v6
-# forward-addr: 8.8.8.8 # google.com
-# forward-addr: 2001:4860:4860::8888 # google.com v6
-# forward-addr: 208.67.222.222 # opendns.com
-# forward-first: yes # try direct if forwarder fails
diff --git a/vrrpd/defaults/main.yml b/vrrpd/defaults/main.yml
index f5950a14..1c7abb10 100644
--- a/vrrpd/defaults/main.yml
+++ b/vrrpd/defaults/main.yml
@@ -1,4 +1,5 @@
---
+vrrp_force_update_switch_script: false
vrrp_addresses: []
# - {
@@ -10,4 +11,7 @@ vrrp_addresses: []
# 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
+# }
+
+minifirewall_restart_if_needed: True
+minifirewall_restart_force: False
diff --git a/vrrpd/files/vrrp_switch.sh b/vrrpd/files/vrrp_switch.sh
new file mode 100644
index 00000000..8806a7fe
--- /dev/null
+++ b/vrrpd/files/vrrp_switch.sh
@@ -0,0 +1,89 @@
+#!/bin/sh
+
+set -u
+set -e
+
+# Input values
+STATE=$1
+VRID=$2
+VIRTUAL_IP=$3
+INTERFACE_NAME=$4
+LABEL=$5
+PRIORITY=$6
+ADVERT_INT=$7
+PREEMPT=$8
+OTHER=${9:-}
+
+LOG_DIR=/var/log/vrrpd/
+[ ! -d "${LOG_DIR}" ] && mkdir -p "${LOG_DIR}"
+LOG_FILE="${LOG_DIR}/state.${VRID}"
+
+STATE_DIR=/var/run/vrrpd/
+[ ! -d "${STATE_DIR}" ] && mkdir -p "${STATE_DIR}"
+STATE_FILE="${STATE_DIR}/vrrp-${LABEL}"
+
+# Log state change to file
+printf "%s %s %s %s %s %s %s %s : %s\n" \
+ "${STATE}" \
+ "${VIRTUAL_IP}" \
+ "${INTERFACE_NAME}" \
+ "${LABEL}" \
+ "${PRIORITY}" \
+ "${ADVERT_INT}" \
+ "${PREEMPT}" \
+ "${OTHER}" \
+ "$(date)" \
+ >> "${LOG_FILE}"
+
+# Replace information in state file
+{
+ echo "VRRP - ${LABEL}"
+ echo "Group ${VRID}"
+ echo "State is ${STATE}"
+ echo "Virtual IP address is ${VIRTUAL_IP}"
+} > "${STATE_FILE}"
+
+# Choose virtual interface name (limited in size)
+INTERFACE_PREFIX="vrrp_${VRID}_"
+INTERFACE_PREFIX_LEN=${#INTERFACE_PREFIX}
+INTERFACE_LEN=$(( ${#INTERFACE_PREFIX} + ${#INTERFACE_NAME} ))
+INTERFACE_MAX_LEN=15
+
+if [ ${INTERFACE_LEN} -gt ${INTERFACE_MAX_LEN} ]; then
+ INTERFACE_SUFFIX=$(echo "${INTERFACE_NAME}" | tail -c $(( INTERFACE_MAX_LEN + 1 - INTERFACE_PREFIX_LEN )))
+else
+ INTERFACE_SUFFIX="${INTERFACE_NAME}"
+fi
+VIRTUAL_INTERFACE_NAME="${INTERFACE_PREFIX}${INTERFACE_SUFFIX}"
+
+# Apply state
+case "${STATE}" in
+
+ "master" )
+ # Choose a MAC address
+ MAC_SUFFIX=$(printf %02x "${VRID}")
+ MAC="00:00:5e:00:01:${MAC_SUFFIX}"
+ # Create macvlan interface
+ ip link add link "${INTERFACE_NAME}" address "${MAC}" "${VIRTUAL_INTERFACE_NAME}" type macvlan
+ # Add IP to interface
+ ip address add "${VIRTUAL_IP}" dev "${VIRTUAL_INTERFACE_NAME}"
+ # Enable interface
+ ip link set dev "${VIRTUAL_INTERFACE_NAME}" up
+ ;;
+
+ "slave" )
+ # Delete interface if it exists
+ if ip link show "${VIRTUAL_INTERFACE_NAME}" >/dev/null 2>&1; then
+ ip link delete "${VIRTUAL_INTERFACE_NAME}"
+ fi
+ ;;
+
+ * )
+ # Error on unknown value for state
+ echo "Unknown state '${STATE}'" >&2
+ exit 1
+ ;;
+
+esac
+
+exit 0
diff --git a/vrrpd/handlers/main.yml b/vrrpd/handlers/main.yml
new file mode 100644
index 00000000..63cfcd86
--- /dev/null
+++ b/vrrpd/handlers/main.yml
@@ -0,0 +1,15 @@
+---
+
+- name: restart minifirewall
+ ansible.builtin.command:
+ cmd: /etc/init.d/minifirewall restart
+ register: minifirewall_init_restart
+ failed_when:
+ - "'starting IPTables rules is now finish : OK' not in minifirewall_init_restart.stdout"
+ - "'minifirewall started' not in minifirewall_init_restart.stdout"
+
+- name: restart minifirewall (noop)
+ ansible.builtin.meta: noop
+ register: minifirewall_init_restart
+ failed_when: False
+ changed_when: False
diff --git a/vrrpd/tasks/ip.yml b/vrrpd/tasks/ip.yml
index b46a8954..81c9f08f 100644
--- a/vrrpd/tasks/ip.yml
+++ b/vrrpd/tasks/ip.yml
@@ -18,5 +18,40 @@
enabled: yes
state: "{{ vrrp_address.state }}"
when:
- - vrrp_systemd_unit is changed
- - not ansible_check_mode
\ No newline at end of file
+ - vrrp_systemd_unit is changed
+ - not ansible_check_mode
+
+- name: Check if a recent minifirewall is present
+ ansible.builtin.stat:
+ path: /etc/minifirewall.d/
+ register: _minifirewall_dir
+
+- ansible.builtin.set_fact:
+ minifirewall_restart_handler_name: "{{ minifirewall_restart_if_needed | bool | ternary('restart minifirewall', 'restart minifirewall (noop)') }}"
+
+- name: VRRP output is authorized in minifirewall
+ lineinfile:
+ path: /etc/minifirewall.d/vrrpd
+ line: "/sbin/iptables -A OUTPUT -o {{ vrrp_address.interface }} -p 112 -j ACCEPT # Allow VRRP output on {{ vrrp_address.interface }}"
+ regexp: "# Allow VRRP output on {{ vrrp_address.interface }}$"
+ create: yes
+ mode: "0600"
+ owner: "root"
+ group: "root"
+ notify: "{{ minifirewall_restart_handler_name }}"
+ when: _minifirewall_dir.stat.exists
+
+- name: VRRP input is authorized in minifirewall
+ lineinfile:
+ path: /etc/minifirewall.d/vrrpd
+ line: "/sbin/iptables -A INPUT -i {{ vrrp_address.interface }} -s {{ peer }} -d 224.0.0.0/8 -j ACCEPT # Allow VRRP input on {{ vrrp_address.interface }} from {{ peer }} for VRID {{ vrrp_address.id }}"
+ regexp: "# Allow VRRP input on {{ vrrp_address.interface }} from {{ peer }} for VRID {{ vrrp_address.id }}"
+ create: yes
+ mode: "0600"
+ owner: "root"
+ group: "root"
+ loop: "{{ vrrp_address.peers | default([]) }}"
+ loop_control:
+ loop_var: peer
+ notify: "{{ minifirewall_restart_handler_name }}"
+ when: _minifirewall_dir.stat.exists
diff --git a/vrrpd/tasks/main.yml b/vrrpd/tasks/main.yml
index 605fb0fd..78b0ee3b 100644
--- a/vrrpd/tasks/main.yml
+++ b/vrrpd/tasks/main.yml
@@ -1,4 +1,5 @@
---
+
- name: Install Evolix public repositry
ansible.builtin.include_role:
name: evolix/apt
@@ -14,6 +15,15 @@
tags:
- vrrpd
+- name: install custom switch script
+ ansible.builtin.copy:
+ src: vrrp_switch.sh
+ dest: /etc/vrrpd/vrrp_switch
+ mode: "0700"
+ owner: "root"
+ group: "root"
+ force: "{{ vrrp_force_update_switch_script | bool | ternary('yes','no') }}"
+
- name: Adjust sysctl config (except rp_filter)
ansible.posix.sysctl:
name: "{{ item.name }}"
@@ -62,4 +72,4 @@
ansible.builtin.include: ip.yml
loop: "{{ vrrp_addresses }}"
loop_control:
- loop_var: "vrrp_address"
\ No newline at end of file
+ loop_var: "vrrp_address"
diff --git a/webapps/evoadmin-mail/tasks/apache.yml b/webapps/evoadmin-mail/tasks/apache.yml
index 26c2b53b..87eb3d2a 100644
--- a/webapps/evoadmin-mail/tasks/apache.yml
+++ b/webapps/evoadmin-mail/tasks/apache.yml
@@ -12,6 +12,7 @@
src: "/etc/apache2/sites-available/evoadminmail.conf"
dest: "/etc/apache2/sites-enabled/evoadminmail.conf"
state: link
+ force: true
notify: reload apache2
when: evoadminmail_enable_vhost | bool
tags:
diff --git a/webapps/evoadmin-mail/tasks/main.yml b/webapps/evoadmin-mail/tasks/main.yml
index a1018eca..76b1b8f6 100644
--- a/webapps/evoadmin-mail/tasks/main.yml
+++ b/webapps/evoadmin-mail/tasks/main.yml
@@ -6,8 +6,17 @@
- name: Install evoadmin-mail package
ansible.builtin.apt:
- deb: /tmp/evoadmin-mail.deb
+ deb: https://pub.evolix.org/evolix/pool/main/e/evoadmin-mail/evoadmin-mail_1.0.9-2_all.deb
state: present
+ when: ansible_distribution_major_version is version('12', '<')
+ tags:
+ - evoadmin-mail
+
+- name: Install evoadmin-mail package
+ ansible.builtin.apt:
+ name: evoadmin-mail
+ state: present
+ when: ansible_distribution_major_version is version('12', '>=')
tags:
- evoadmin-mail
diff --git a/webapps/nextcloud/defaults/main.yml b/webapps/nextcloud/defaults/main.yml
index 72ce812d..2c70832c 100644
--- a/webapps/nextcloud/defaults/main.yml
+++ b/webapps/nextcloud/defaults/main.yml
@@ -1,5 +1,5 @@
---
-nextcloud_version: "latest-24"
+nextcloud_version: "latest"
nextcloud_archive_name: "{{ nextcloud_version }}.tar.bz2"
nextcloud_releases_baseurl: "https://download.nextcloud.com/server/releases/"
@@ -17,3 +17,6 @@ nextcloud_db_name: "{{ nextcloud_instance_name }}"
nextcloud_admin_login: "admin"
nextcloud_admin_password: ""
+
+nextcloud_get_archive: True
+nextcloud_do_config: True
diff --git a/webapps/nextcloud/tasks/main.yml b/webapps/nextcloud/tasks/main.yml
index 02304334..9bbab5b5 100644
--- a/webapps/nextcloud/tasks/main.yml
+++ b/webapps/nextcloud/tasks/main.yml
@@ -48,9 +48,11 @@
- ansible.builtin.include: user.yml
- ansible.builtin.include: archive.yml
+ when: nextcloud_get_archive
- ansible.builtin.include: apache-vhost.yml
- ansible.builtin.include: mysql-user.yml
- ansible.builtin.include: config.yml
+ when: nextcloud_do_config
diff --git a/webapps/nextcloud/tasks/user.yml b/webapps/nextcloud/tasks/user.yml
index c0ce5172..e9a398b9 100644
--- a/webapps/nextcloud/tasks/user.yml
+++ b/webapps/nextcloud/tasks/user.yml
@@ -26,6 +26,11 @@
tags:
- nextcloud
+- name: Set mode for home directory
+ ansible.builtin.file:
+ path: "{{ nextcloud_home }}"
+ mode: "0701"
+
- name: Create top-level directories
ansible.builtin.file:
dest: "{{ item }}"
@@ -43,7 +48,14 @@
- name: Mount up Ceph volume by UUID
ansible.posix.mount:
path: "{{ nextcloud_data }}"
- src: "{{ nextcloud_data_uuid }}"
+ src: "UUID={{ nextcloud_data_uuid }}"
fstype: ext4
opts: defaults,noexec,nosuid,nodev,relatime,lazytime
- state: present
+ state: mounted
+
+- name: Set volume's root permissions and ownership
+ ansible.builtin.file:
+ path: "{{ nextcloud_data }}"
+ owner: "{{ nextcloud_user }}"
+ group: "{{ nextcloud_user }}"
+ mode: "0700"
diff --git a/webapps/roundcube/tasks/main.yml b/webapps/roundcube/tasks/main.yml
index 17422246..a0fd25b9 100644
--- a/webapps/roundcube/tasks/main.yml
+++ b/webapps/roundcube/tasks/main.yml
@@ -58,7 +58,7 @@
tags:
- roundcube
-- name: configure roudcube imap port
+- name: configure roundcube imap port
ansible.builtin.lineinfile:
dest: /etc/roundcube/config.inc.php
regexp: "\\$config\\['default_port'\\]"
@@ -67,6 +67,15 @@
tags:
- roundcube
+- name: configure roundcube smtp port
+ ansible.builtin.lineinfile:
+ dest: /etc/roundcube/config.inc.php
+ regexp: "\\$config\\['smtp_port'\\]"
+ insertafter: "\\$config\\['smtp_port'\\]"
+ line: "$config['smtp_port'] = 25;"
+ tags:
+ - roundcube
+
- name: configure managesieve plugin
ansible.builtin.copy:
src: /usr/share/roundcube/plugins/managesieve/config.inc.php.dist
@@ -99,6 +108,7 @@
src: /etc/apache2/sites-available/roundcube.conf
dest: /etc/apache2/sites-enabled/roundcube.conf
state: link
+ force: true
notify: reload apache2
when: roundcube_webserver == "apache"
tags: