Merge branch 'unstable' into bullseye-swap-top
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/pr Build was killed

This commit is contained in:
Jérémy Lecour 2022-01-25 15:13:10 +01:00
commit 8f8c024163
144 changed files with 4245 additions and 715 deletions

View file

@ -4,52 +4,105 @@ All notable changes to this project will be documented in this file.
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 aligned with the stable version of Debian.
The **minor** part changes with big changes (probably incompatible).
The **patch** part changes incrementally at each release.
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
## [Unreleased]
### Added
* Preliminary support for Debian 11 « Bullseye »
* apache: new variable for mpm mode (+ updated default config accordingly)
### Changed
### Fixed
### Removed
### Security
## [22.01] 2022-01-25
### Added
* Support for Debian 11 « Bullseye » (with possible remaining blind spots)
* apache: new variable for MPM mode (+ updated default config accordingly)
* apache: prevent accessing Git or "env" related files
* certbot: add script for manual deploy hooks execution
* docker-host: install additional dependencies
* dovecot: switch to TLS 1.2+ and external DH params
* etc-git: centralize cron jobs in dedicated crontab
* etc-git: manage commits with an optimized shell script instead of many slow Ansible tasks
* evolinux-base: add script backup-server-state
* evolinux-base: install molly-guard by default
* generate-ldif: detect RAID controller
* generate-ldif: detect mdadm
* listupgrade: crontab is configurable
* logstash: logging to syslog is configurable (default: True)
* mongodb: create munin plugins directory if missing
* munin: systemd override to unprotect home directory
* mysql: add evomariabackup 21.11
* mysql: improve Bullseye compatibility
* mysql: script "mysql_connections" to display a compact list of connections
* mysql: script "mysql-queries-killer.sh" to kill MySQL queries
* nagios-nrpe + evolinux-users: new check for ipmi
* nagios-nrpe + evolinux-users: new check for RAID (soft + hard)
* nagios-nrpe + evolinux-users: new checks for bkctld
* nagios-nrpe: new check influxdb
* openvpn: new role (beta)
* redis: instance service for Debian 11
* squid: add *.o.lencr.org to default whitelist
### Changed
* Use python3 modules for Debian 11 and later
* Change version pattern
* Install python 2 or 3 libraries according to running python version
* Remove embedded GPG keys only if legacy keyring is present
* apt: remove workaround for Evolix public repositories with Debian 11
* apt: use the new security repository for Bullseye
* certbot: silence letsencrypt deprecation warnings
* elasticsearch: 7.x by default
* elasticsearch: elastic_stack_version = 7.x
* evoacme: exclude renewal-hooks directory from cron
* evoadmin-web: simpler PHP packages lists
* evocheck: upstream release 21.07
* evocheck: upstream release 21.10.4
* evolinux-base: alert5 comes after the network
* evolinux-base: force Debian version to buster for Evolix repository (temporary)
* kibana: 7.x by default
* evolinux-base: install freeipmi by default on dedicated hw
* evolinux-base: logs are rotated with dateext by default
* evolinux-base: split dpkg logrotate configuration
* evolinux-users + nagios-nrpe: Add support for php-fpm80 in lxc
* evomaintenance: extract a config.yml tasks file
* evomaintenance: upstream release 22.01
* filebeat/metricbeat: elastic_stack_version = 7.x
* kibana: elastic_stack_version = 7.x
* listupgrade: old-kernel-removal version 21.10
* listupgrade: upstream release 21.06.3
* mysql: mariadb-client-10.5 on Debian 11
* mysql: use python3 with Debian 11 and later
* logstash: elastic_stack_version = 7.x
* mongodb: Allow to specify a mongodb version for buster & bullseye
* mongodb: Deny the install on Debian 11 « Bullseye » when the version is unsupported
* mongodb: Support version 5.0 (for buster)
* mysql: use python3 and mariadb-client-10.5 with Debian 11 and later
* nodejs: default to version 16 LTS
* php: enforce Debian version with assert instead of fail
* squid: improve default whitelist (more specific patterns)
* squid: must be started in foreground mode for systemd
* squid: remove obsolete variable on Squid 4
### Fixed
* evolinux-base: fix alert5.service dependency syntax
* certbot: sync_remote excludes itself
* lxc-php: fix config for opensmtpd on bullseye containers
* mysql : Create a default ~root/.my.cnf for compatibility reasons
* nginx : fix variable name and debug to actually use nginx-light
* packweb-apache : Support php 8.0
* nagios-nrpe: Fix check_nfsserver for buster and bullseye
### Removed
* evocheck: package install is not supported anymore
* logstash: no more dependency on Java
* php: remove php-gettext for 7.4
### Security
## [10.6.0] 2021-06-28
### Added

View file

@ -48,12 +48,23 @@ MaxKeepAliveRequests 10
Deny from env=GoAway
</Directory>
<DirectoryMatch "/\.git">
# 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
</DirectoryMatch>
<Files ~ "\.(inc|bak)$">
Require all denied
</Files>
# File names starting with
<FilesMatch "^\.(git|env)">
Redirect 404
</FilesMatch>
# File names ending with
<FilesMatch "\.(inc|bak)$">
Redirect 404
</FilesMatch>
<LocationMatch "^/evolinux_fpm_status-.*">
Require all denied
</LocationMatch>

View file

@ -14,8 +14,15 @@ debug() {
found_renewed_lineage() {
test -f "${RENEWED_LINEAGE}/fullchain.pem" && test -f "${RENEWED_LINEAGE}/privkey.pem"
}
cert_content() {
openssl x509 -text -in "${RENEWED_LINEAGE}/fullchain.pem"
}
domain_from_cert() {
openssl x509 -noout -subject -in "${RENEWED_LINEAGE}/fullchain.pem" | sed 's/^.*CN\ *=\ *//'
if cert_content | grep -q "X509v3 Subject Alternative Name:" && cert_content | grep -q "DNS:"; then
cert_content | grep "DNS:" | sed -e 's/\s\+//g' -e 's/DNS://g'
else
cert_content | sed 's/^.*CN\ *=\ *//'
fi
}
main() {
if [ -z "${RENEWED_LINEAGE}" ]; then
@ -44,7 +51,7 @@ main() {
|| error "Couldn't sync hooks on ${server}"
# shellcheck disable=SC2029
ssh "${remote_host}" "export RENEWED_LINEAGE=\"${remote_lineage}/\" RENEWED_DOMAINS=${RENEWED_DOMAINS}; find ${remote_dir}/hooks/ -mindepth 1 -maxdepth 1 -type f -executable -exec {} \;" \
ssh "${remote_host}" "export RENEWED_LINEAGE=\"${remote_lineage}/\" RENEWED_DOMAINS=\"${RENEWED_DOMAINS}\"; find ${remote_dir}/hooks/ -mindepth 1 -maxdepth 1 -type f -executable -exec {} \;" \
|| error "Something went wrong on ${server} for deploy hooks"
done
else

View file

@ -56,5 +56,5 @@
dest: "/etc/letsencrypt/cli.ini"
section: null
option: "no-self-upgrade"
value: 0
value: "no"
state: present

View file

@ -7,17 +7,17 @@
- ansible_distribution_major_version is version('8', '>=')
msg: only compatible with Debian 9+
- name: Install legacy script on Debian 8 and 9
- name: Install legacy script on Debian 8
include: install-legacy.yml
when:
- ansible_distribution == "Debian"
- ansible_distribution_major_version is version('10', '<')
- ansible_distribution_major_version is version('9', '<')
- name: Install package on Debian 10+
- name: Install package on Debian 9+
include: install-package.yml
when:
- ansible_distribution == "Debian"
- ansible_distribution_major_version is version('10', '>=')
- ansible_distribution_major_version is version('9', '>=')
- include: acme-challenge.yml

View file

@ -6,48 +6,48 @@
value: "{{ item.value }}"
vtype: "{{ item.type }}"
loop:
- { key: 'clamav-daemon/debconf', type: 'boolean', value: 'true' }
- { key: 'clamav-daemon/MaxHTMLNormalize', type: 'string', value: '10M' }
- { key: 'clamav-daemon/StatsPEDisabled', type: 'boolean', value: 'true' }
- { key: 'clamav-daemon/FollowDirectorySymlinks', type: 'boolean', value: 'false' }
- { key: 'clamav-daemon/StreamMaxLength', type: 'string', value: '25' }
- { key: 'clamav-daemon/ReadTimeout', type: 'string', value: '180' }
- { key: 'clamav-daemon/StatsEnabled', type: 'boolean', value: 'false' }
- { key: 'clamav-daemon/MaxConnectionQueueLength', type: 'string', value: '15' }
- { key: 'clamav-daemon/LogRotate', type: 'boolean', value: 'true' }
- { key: 'clamav-daemon/AllowAllMatchScan', type: 'boolean', value: 'true' }
- { key: 'clamav-daemon/ScanOnAccess', type: 'boolean', value: 'false' }
- { key: 'clamav-daemon/LogFile', type: 'string', value: '/var/log/clamav/clamav.log' }
- { key: 'clamav-daemon/ScanMail', type: 'boolean', value: 'true' }
- { key: 'clamav-daemon/BytecodeTimeout', type: 'string', value: '60000' }
- { key: 'clamav-daemon/LogTime', type: 'boolean', value: 'true' }
- { key: 'clamav-daemon/OnAccessMaxFileSize', type: 'string', value: '5M' }
- { key: 'clamav-daemon/TcpOrLocal', type: 'select', value: 'UNIX' }
- { key: 'clamav-daemon/MaxEmbeddedPE', type: 'string', value: '10M' }
- { key: 'clamav-daemon/FixStaleSocket', type: 'boolean', value: 'true' }
- { key: 'clamav-daemon/User', type: 'string', value: 'clamav' }
- { key: 'clamav-daemon/BytecodeSecurity', type: 'select', value: 'TrustSigned' }
- { key: 'clamav-daemon/ScanSWF', type: 'boolean', value: 'true' }
- { key: 'clamav-daemon/MaxDirectoryRecursion', type: 'string', value: '0' }
- { key: 'clamav-daemon/MaxThreads', type: 'string', value: '12' }
- { key: 'clamav-daemon/LocalSocketGroup', type: 'string', value: 'clamav' }
- { key: 'clamav-daemon/MaxScriptNormalize', type: 'string', value: '5M' }
- { key: 'clamav-daemon/ForceToDisk', type: 'boolean', value: 'false' }
- { key: 'clamav-daemon/StatsHostID', type: 'string', value: 'auto' }
- { key: 'clamav-daemon/FollowFileSymlinks', type: 'boolean', value: 'false' }
- { key: 'clamav-daemon/TCPSocket', type: 'string', value: '3310' }
- { key: 'clamav-daemon/TCPAddr', type: 'string', value: 'any' }
- { key: 'clamav-daemon/DisableCertCheck', type: 'boolean', value: 'false' }
- { key: 'clamav-daemon/SelfCheck', type: 'string', value: '3600' }
- { key: 'clamav-daemon/LocalSocket', type: 'string', value: '/var/run/clamav/clamd.ctl' }
- { key: 'clamav-daemon/LocalSocketMode', type: 'string', value: '666' }
- { key: 'clamav-daemon/StatsTimeout', type: 'string', value: '10' }
- { key: 'clamav-daemon/MaxZipTypeRcg', type: 'string', value: '1M' }
- { key: 'clamav-daemon/MaxHTMLNoTags', type: 'string', value: '2M' }
- { key: 'clamav-daemon/LogSyslog', type: 'boolean', value: 'false' }
- { key: 'clamav-daemon/AddGroups', type: 'string', value: '' }
- { key: 'clamav-daemon/Bytecode', type: 'boolean', value: 'true' }
- { key: 'clamav-daemon/ScanArchive', type: 'boolean', value: 'true' }
- { key: 'clamav-daemon/debconf', type: 'boolean', value: 'true' }
- { key: 'clamav-daemon/MaxHTMLNormalize', type: 'string', value: '10M' }
- { key: 'clamav-daemon/StatsPEDisabled', type: 'boolean', value: 'true' }
- { key: 'clamav-daemon/FollowDirectorySymlinks', type: 'boolean', value: 'false' }
- { key: 'clamav-daemon/StreamMaxLength', type: 'string', value: '25' }
- { key: 'clamav-daemon/ReadTimeout', type: 'string', value: '180' }
- { key: 'clamav-daemon/StatsEnabled', type: 'boolean', value: 'false' }
- { key: 'clamav-daemon/MaxConnectionQueueLength', type: 'string', value: '15' }
- { key: 'clamav-daemon/LogRotate', type: 'boolean', value: 'true' }
- { key: 'clamav-daemon/AllowAllMatchScan', type: 'boolean', value: 'true' }
- { key: 'clamav-daemon/ScanOnAccess', type: 'boolean', value: 'false' }
- { key: 'clamav-daemon/LogFile', type: 'string', value: '/var/log/clamav/clamav.log' }
- { key: 'clamav-daemon/ScanMail', type: 'boolean', value: 'true' }
- { key: 'clamav-daemon/BytecodeTimeout', type: 'string', value: '60000' }
- { key: 'clamav-daemon/LogTime', type: 'boolean', value: 'true' }
- { key: 'clamav-daemon/OnAccessMaxFileSize', type: 'string', value: '5M' }
- { key: 'clamav-daemon/TcpOrLocal', type: 'select', value: 'UNIX' }
- { key: 'clamav-daemon/MaxEmbeddedPE', type: 'string', value: '10M' }
- { key: 'clamav-daemon/FixStaleSocket', type: 'boolean', value: 'true' }
- { key: 'clamav-daemon/User', type: 'string', value: 'clamav' }
- { key: 'clamav-daemon/BytecodeSecurity', type: 'select', value: 'TrustSigned' }
- { key: 'clamav-daemon/ScanSWF', type: 'boolean', value: 'true' }
- { key: 'clamav-daemon/MaxDirectoryRecursion', type: 'string', value: '0' }
- { key: 'clamav-daemon/MaxThreads', type: 'string', value: '12' }
- { key: 'clamav-daemon/LocalSocketGroup', type: 'string', value: 'clamav' }
- { key: 'clamav-daemon/MaxScriptNormalize', type: 'string', value: '5M' }
- { key: 'clamav-daemon/ForceToDisk', type: 'boolean', value: 'false' }
- { key: 'clamav-daemon/StatsHostID', type: 'string', value: 'auto' }
- { key: 'clamav-daemon/FollowFileSymlinks', type: 'boolean', value: 'false' }
- { key: 'clamav-daemon/TCPSocket', type: 'string', value: '3310' }
- { key: 'clamav-daemon/TCPAddr', type: 'string', value: 'any' }
- { key: 'clamav-daemon/DisableCertCheck', type: 'boolean', value: 'false' }
- { key: 'clamav-daemon/SelfCheck', type: 'string', value: '3600' }
- { key: 'clamav-daemon/LocalSocket', type: 'string', value: '/var/run/clamav/clamd.ctl' }
- { key: 'clamav-daemon/LocalSocketMode', type: 'string', value: '666' }
- { key: 'clamav-daemon/StatsTimeout', type: 'string', value: '10' }
- { key: 'clamav-daemon/MaxZipTypeRcg', type: 'string', value: '1M' }
- { key: 'clamav-daemon/MaxHTMLNoTags', type: 'string', value: '2M' }
- { key: 'clamav-daemon/LogSyslog', type: 'boolean', value: 'false' }
- { key: 'clamav-daemon/AddGroups', type: 'string', value: '' }
- { key: 'clamav-daemon/Bytecode', type: 'boolean', value: 'true' }
- { key: 'clamav-daemon/ScanArchive', type: 'boolean', value: 'true' }
tags:
- clamav
@ -58,17 +58,17 @@
value: "{{ item.value }}"
vtype: "{{ item.type }}"
loop:
- { key: 'clamav-freshclam/autoupdate_freshclam', type: 'select', value: 'daemon' }
- { key: 'clamav-freshclam/proxy_user', type: 'string', value: '' }
- { key: 'clamav-freshclam/NotifyClamd', type: 'boolean', value: 'true' }
- { key: 'clamav-freshclam/local_mirror', type: 'select', value: 'db.fr.clamav.net' }
- { key: 'clamav-freshclam/http_proxy', type: 'string', value: '' }
- { key: 'clamav-freshclam/LogRotate', type: 'boolean', value: 'true' }
- { key: 'clamav-freshclam/Bytecode', type: 'boolean', value: 'true' }
- { key: 'clamav-freshclam/update_interval', type: 'string', value: '24' }
- { key: 'clamav-freshclam/SafeBrowsing', type: 'boolean', value: 'false' }
- { key: 'clamav-freshclam/PrivateMirror', type: 'string', value: '' }
- { key: 'clamav-freshclam/internet_interface', type: 'string', value: '' }
- { key: 'clamav-freshclam/autoupdate_freshclam', type: 'select', value: 'daemon' }
- { key: 'clamav-freshclam/proxy_user', type: 'string', value: '' }
- { key: 'clamav-freshclam/NotifyClamd', type: 'boolean', value: 'true' }
- { key: 'clamav-freshclam/local_mirror', type: 'select', value: 'db.fr.clamav.net' }
- { key: 'clamav-freshclam/http_proxy', type: 'string', value: '' }
- { key: 'clamav-freshclam/LogRotate', type: 'boolean', value: 'true' }
- { key: 'clamav-freshclam/Bytecode', type: 'boolean', value: 'true' }
- { key: 'clamav-freshclam/update_interval', type: 'string', value: '24' }
- { key: 'clamav-freshclam/SafeBrowsing', type: 'boolean', value: 'false' }
- { key: 'clamav-freshclam/PrivateMirror', type: 'string', value: '' }
- { key: 'clamav-freshclam/internet_interface', type: 'string', value: '' }
tags:
- clamav

View file

@ -36,23 +36,25 @@
owner: root
group: root
- name: Install docker and python-docker
- name: Install Docker
apt:
name:
- docker-ce
- docker-ce-cli
- containerd.io
update_cache: yes
- name: python-docker is installed
apt:
name: python-docker
state: present
when: ansible_distribution_major_version is version('10', '<=')
when: ansible_python_version is version('3', '<')
- name: python3-docker is installed
apt:
name: python3-docker
state: present
when: ansible_distribution_major_version is version('10', '>')
when: ansible_python_version is version('3', '>=')
- name: Copy Docker daemon configuration file
template:

View file

@ -10,6 +10,11 @@
tags:
- dovecot
- name: Generate 4096 bits Diffie-Hellman parameters (may take several minutes)
openssl_dhparam:
path: /etc/ssl/dhparams.pem
size: 4096
- name: disable pam auth
replace:
dest: /etc/dovecot/conf.d/10-auth.conf

View file

@ -35,12 +35,27 @@ service login {
}
mail_max_userip_connections = 42
# Configuration pour stats dovecot
service stats {
unix_listener stats-reader {
user = vmail
group = vmail
mode = 0660
}
unix_listener stats-writer {
user = vmail
group = vmail
mode = 0660
}
}
# SSL/TLS
ssl = yes
ssl_prefer_server_ciphers = yes
ssl_dh_parameters_length = 2048
ssl_dh=</etc/ssl/dhparams.pem
ssl_options = no_compression no_ticket
ssl_protocols = !TLSv1 !TLSv1.1
ssl_min_protocol = TLSv1.2
ssl_cipher_list = ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
ssl_cert = </etc/ssl/certs/ssl-cert-snakeoil.pem
ssl_key = </etc/ssl/private/ssl-cert-snakeoil.key

View file

@ -1,4 +1,6 @@
---
commit_message: Ansible run
etc_git_default_commit_message: Ansible run
etc_git_monitor_status: True
etc_git_purge_index_lock_enabled: True
etc_git_purge_index_lock_age: 86400

View file

@ -0,0 +1,11 @@
#!/bin/sh
set -u
repositories="/etc /etc/bind/ /usr/share/scripts"
for repository in ${repositories}; do
if [ -d "${repository}/.git" ]; then
git --git-dir="${repository}/.git" gc --quiet
fi
done

View file

@ -0,0 +1,11 @@
#!/bin/sh
set -u
repositories="/etc /etc/bind/ /usr/share/scripts"
for repository in ${repositories}; do
if [ -d "${repository}/.git" ]; then
git --git-dir="${repository}/.git" --work-tree="${repository}" status --short
fi
done

265
etc-git/files/evocommit Normal file
View file

@ -0,0 +1,265 @@
#!/bin/sh
set -u
VERSION="21.10"
show_version() {
cat <<END
evocommit version ${VERSION}
Copyright 2021 Evolix <info@evolix.fr>,
Jérémy Lecour <jlecour@evolix.fr>
and others.
evocommit comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
See the GNU General Public Licence for details.
END
}
show_help() {
cat <<END
evocommit helps properly committing changes in a repository
END
show_usage
}
show_usage() {
cat <<END
Usage: evocommit --repository /path/to/repository --message "add new host"
Options
--repository PATH set the path for the repository
--message MESSAGE set the commit message
-V, --version print version number
-v, --verbose increase verbosity
-n, --dry-run actions are not executed
--help print this message and exit
--version print version and exit
END
}
syslog() {
if [ -x "${LOGGER_BIN}" ]; then
${LOGGER_BIN} -t "evocommit" "$1"
fi
}
get_system() {
uname -s
}
is_repository_readonly() {
if [ "$(get_system)" = "OpenBSD" ]; then
partition=$(stat -f '%Sd' $1)
mount | grep "${partition}" | grep -q "read-only"
elif command -v findmnt >/dev/null; then
mountpoint=$(stat -c '%m' $1)
findmnt "${mountpoint}" --noheadings --output OPTIONS -O ro
else
grep /usr /proc/mounts | grep -E '\bro\b'
fi
}
remount_repository_readwrite() {
if [ "$(get_system)" = "OpenBSD" ]; then
partition=$(stat -f '%Sd' $1)
mount -u -w /dev/${partition} 2>/dev/null
else
mountpoint=$(stat -c '%m' $1)
mount -o remount,rw ${mountpoint}
syslog "Re-mount ${mountpoint} as read-write to commit in repository $1"
fi
}
remount_repository_readonly() {
if [ "$(get_system)" = "OpenBSD" ]; then
partition=$(stat -f '%Sd' $1)
mount -u -r /dev/${partition} 2>/dev/null
else
mountpoint=$(stat -c '%m' $1)
mount -o remount,ro ${mountpoint} 2>/dev/null
syslog "Re-mount ${mountpoint} as read-only after commit to repository $1"
fi
}
is_dry_run() {
test "${DRY_RUN}" = "1"
}
is_verbose() {
test "${VERBOSE}" = "1"
}
is_ansible() {
test "${ANSIBLE}" = "1"
}
main() {
rc=0
lock="${GIT_DIR}/index.lock"
if [ -f "${lock}" ]; then
limit=$(date +"%s" -d "now - 1 hour")
updated_at=$(stat -c "%Y" "${lock}")
if [ "$updated_at" -lt "$limit" ]; then
rm -f "${lock}"
fi
fi
git_status=$(${GIT_BIN} status --porcelain)
if [ -n "${git_status}" ]; then
if is_dry_run; then
${GIT_BIN} status
else
readonly_orig=0
# remount mount point read-write if currently readonly
if is_repository_readonly "${REPOSITORY}"; then
readonly_orig=1;
remount_repository_readwrite "${REPOSITORY}";
fi
author=$(logname)
email=$(git config --get user.email)
email=${email:-"${author}@evolix.net"}
# commit changes
git_add_result=$(${GIT_BIN} add --all)
git_add_rc=$?
if is_ansible; then
if [ ${git_add_rc} -ne 0 ]; then
printf "FAILED: %s\n%s" "can't add changes in ${REPOSITORY}" "${git_add_result}"
rc=1
fi
fi
git_commit_result=$(${GIT_BIN} commit --message "${MESSAGE}" --author "${author} <${email}>")
git_commit_rc=$?
if is_ansible; then
if [ ${git_commit_rc} -eq 0 ]; then
printf "CHANGED: %s\n" "commit done in ${REPOSITORY} with \`${MESSAGE}'"
else
printf "FAILED: %s\n%s" "can't commit in ${REPOSITORY} \`${MESSAGE}'" "${git_commit_result}"
rc=1
fi
fi
# remount mount point read-only if it was before
if [ ${readonly_orig} -eq 1 ]; then
remount_repository_readonly "${REPOSITORY}"
fi
fi
else
if is_ansible; then
printf "INFO: %s\n" "no commit in ${REPOSITORY}'"
fi
fi
unset GIT_DIR
unset GIT_WORK_TREE
exit ${rc}
}
# Parse options
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
while :; do
case ${1:-''} in
-h|-\?|--help)
show_help
exit 0
;;
-V|--version)
show_version
exit 0
;;
--message)
# message options, with value speparated by space
if [ -n "$2" ]; then
MESSAGE=$2
shift
else
printf 'ERROR: "--message" requires a non-empty option argument.\n' >&2
exit 1
fi
;;
--message=?*)
# message options, with value speparated by =
MESSAGE=${1#*=}
;;
--message=)
# message options, without value
printf 'ERROR: "--message" requires a non-empty option argument.\n' >&2
exit 1
;;
--repository)
# repository options, with value speparated by space
if [ -n "$2" ]; then
REPOSITORY=$2
shift
else
printf 'ERROR: "--repository" requires a non-empty option argument.\n' >&2
exit 1
fi
;;
--repository=?*)
# repository options, with value speparated by =
REPOSITORY=${1#*=}
;;
--repository=)
# repository options, without value
printf 'ERROR: "--repository" requires a non-empty option argument.\n' >&2
exit 1
;;
-n|--dry-run)
# disable actual commands
DRY_RUN=1
;;
-v|--verbose)
# print verbose information
VERBOSE=1
;;
--ansible)
# print information for Ansible
ANSIBLE=1
;;
--)
# End of all options.
shift
break
;;
-?*|[[:alnum:]]*)
# ignore unknown options
printf 'WARN: Unknown option (ignored): %s\n' "$1" >&2
;;
*)
# Default case: If no more options then break out of the loop.
break
;;
esac
shift
done
if [ -z "${MESSAGE}" ]; then
echo "Error: missing message parameter" >&2
show_usage
exit 1
fi
if [ -z "${REPOSITORY}" ]; then
echo "Error: missing repository parameter" >&2
show_usage
exit 1
fi
DRY_RUN=${DRY_RUN:-0}
VERBOSE=${VERBOSE:-0}
ANSIBLE=${ANSIBLE:-0}
GIT_BIN=$(command -v git)
readonly GIT_BIN
LOGGER_BIN=$(command -v logger)
readonly LOGGER_BIN
export GIT_DIR="${REPOSITORY}/.git"
export GIT_WORK_TREE="${REPOSITORY}"
if [ -d "${GIT_DIR}" ]; then
main
else
echo "There is no Git repository in '${REPOSITORY}'" >&2
exit 1
fi

View file

@ -1,3 +0,0 @@
#!/bin/sh
git --git-dir /etc/.git gc --quiet

View file

@ -1,25 +1,52 @@
---
# /etc
- name: Is /etc a git repository
stat:
path: /etc/.git
register: _etc_git
- include: do_commit.yml
vars:
git_folder: "/etc"
- name: "evocommit /etc"
command: "/usr/local/bin/evocommit --ansible --repository /etc --message \"{{ commit_message | mandatory }}\""
changed_when:
- _etc_git_commit.stdout
- "'CHANGED:' in _etc_git_commit.stdout"
ignore_errors: yes
register: _etc_git_commit
when:
- _etc_git.stat.exists
- _etc_git.stat.isdir
# /etc/bind
- name: Is /etc/bind a git repository
stat:
path: /etc/bind/.git
register: _etc_bind_git
- name: "evocommit /etc/bind"
command: "/usr/local/bin/evocommit --ansible --repository /etc/bind --message \"{{ commit_message | mandatory }}\""
changed_when:
- _etc_bind_git_commit.stdout
- "'CHANGED:' in _etc_bind_git_commit.stdout"
ignore_errors: yes
register: _etc_bind_git_commit
when:
- _etc_bind_git.stat.exists
- _etc_bind_git.stat.isdir
# /usr/share/scripts
- name: Is /usr/share/scripts a git repository
stat:
path: /usr/share/scripts/.git
register: _usr_share_scripts_git
- include: do_commit.yml
vars:
git_folder: "/usr/share/scripts"
- name: "evocommit /usr/share/scripts"
command: "/usr/local/bin/evocommit --ansible --repository /usr/share/scripts --message \"{{ commit_message | mandatory }}\""
changed_when:
- _usr_share_scripts_git_commit.stdout
- "'CHANGED:' in _usr_share_scripts_git_commit.stdout"
ignore_errors: yes
register: _usr_share_scripts_git_commit
when:
- _usr_share_scripts_git.stat.exists
- _usr_share_scripts_git.stat.isdir

View file

@ -1,63 +0,0 @@
---
- name: "Remount /usr if needed"
include_role:
name: remount-usr
when: git_folder is match('/usr/.*')
- name: "is {{ git_folder }} clean?"
command: git status --porcelain
args:
chdir: "{{ git_folder }}"
changed_when: False
register: git_status
when: not ansible_check_mode
ignore_errors: yes
tags:
- etc-git
- commit
- debug:
var: git_status
verbosity: 3
tags:
- etc-git
- commit
- name: fetch current Git user.email
git_config:
name: user.email
repo: "{{ git_folder }}"
register: git_config_user_email
ignore_errors: yes
tags:
- etc-git
- commit
- name: "set commit author"
set_fact:
commit_author: '{% if ansible_env.SUDO_USER is not defined %}root{% else %}{{ ansible_env.SUDO_USER }}{% endif %}'
commit_email: '{% if git_config_user_email.config_value is not defined or not git_config_user_email.config_value %}root@localhost{% else %}{{ git_config_user_email.config_value }}{% endif %}' # noqa 204
tags:
- etc-git
- commit
- name: "{{ git_folder }} modifications are committed"
shell: "git add -A . && git commit -m \"{{ commit_message | mandatory }}\" --author \"{{ commit_author | mandatory }} <{{ commit_email | mandatory }}>\""
args:
chdir: "{{ git_folder }}"
register: commit_end_run
when:
- not ansible_check_mode
- git_status.stdout | length > 0
ignore_errors: yes
tags:
- etc-git
- commit
- debug:
var: commit_end_run
verbosity: 4
tags:
- etc-git
- commit

View file

@ -7,6 +7,18 @@
tags:
- etc-git
- include_role:
name: evolix/remount-usr
- name: "evocommit script is installed"
copy:
src: evocommit
dest: /usr/local/bin/evocommit
mode: "0755"
force: yes
tags:
- etc-git
- include: repository.yml
vars:
repository_path: "/etc"
@ -32,6 +44,24 @@
- _usr_share_scripts.stat.isdir
- ansible_distribution_major_version is version('10', '>=')
- name: "etc-git-optimize script is installed"
copy:
src: etc-git-optimize
dest: /usr/share/scripts/etc-git-optimize
mode: "0755"
force: yes
tags:
- etc-git
- name: "etc-git-status script is installed"
copy:
src: etc-git-status
dest: /usr/share/scripts/etc-git-status
mode: "0755"
force: yes
tags:
- etc-git
- name: Check if cron is installed
shell: "set -o pipefail && dpkg -l cron 2>/dev/null | grep -q -E '^(i|h)i'"
args:
@ -41,29 +71,44 @@
check_mode: no
register: is_cron_installed
- name: Optimize script is installed in monthly crontab
copy:
src: optimize-etc-git
dest: /etc/cron.monthly/optimize-etc-git
mode: "0750"
force: no
- block:
- name: Legacy cron jobs for /etc/.git status are absent
file:
dest: "{{ item }}"
state: absent
loop:
- /etc/cron.monthly/optimize-etc-git
- /etc/cron.d/etc-git-status
- name: Cron job for monthly git optimization
cron:
name: "Monthly optimization"
cron_file: etc-git
special_time: "monthly"
user: root
job: "/usr/share/scripts/etc-git-optimize"
- name: Cron job for hourly git status
cron:
name: "Hourly warning for unclean Git repository if nobody is connected"
cron_file: etc-git
special_time: "hourly"
user: root
job: "who > /dev/null || /usr/share/scripts/etc-git-status"
state: "{{ etc_git_monitor_status | bool | ternary('present','absent') }}"
- name: Cron job for daily git status
cron:
name: "Daily warning for unclean Git repository"
cron_file: etc-git
user: root
job: "/usr/share/scripts/etc-git-status"
minute: "21"
hour: "21"
weekday: "*"
day: "*"
month: "*"
state: "{{ etc_git_monitor_status | bool | ternary('present','absent') }}"
when: is_cron_installed.rc == 0
tags:
- etc-git
- name: Cron job for /etc/.git status is installed
template:
src: etc-git-status.j2
dest: /etc/cron.d/etc-git-status
mode: "0644"
when: is_cron_installed.rc == 0 and etc_git_monitor_status
tags:
- etc-git
- name: Cron job for /etc/.git status is removed
file:
dest: /etc/cron.d/etc-git-status
state: absent
when: is_cron_installed.rc == 0 and not etc_git_monitor_status
tags:
- etc-git
- etc-git

View file

@ -70,4 +70,4 @@
register: git_commit
when: git_log.rc != 0 or (git_init is defined and git_init is changed)
tags:
- etc-git
- etc-git

View file

@ -1,4 +0,0 @@
# {{ ansible_managed }}
@hourly root who > /dev/null || git --git-dir=/etc/.git --work-tree=/etc status --short
21 21 * * * root git --git-dir=/etc/.git --work-tree=/etc status --short

View file

@ -15,12 +15,13 @@ find "${CRT_DIR}" \
-maxdepth 1 \
-mindepth 1 \
-type d \
! -path "*accounts" \
! -path "*archive" \
! -path "*csr" \
! -path "*hooks" \
! -path "*keys" \
! -path "*live" \
! -path "*renewal" \
! -path "${CRT_DIR}/accounts" \
! -path "${CRT_DIR}/archive" \
! -path "${CRT_DIR}/csr" \
! -path "${CRT_DIR}/hooks" \
! -path "${CRT_DIR}/keys" \
! -path "${CRT_DIR}/live" \
! -path "${CRT_DIR}/renewal" \
! -path "${CRT_DIR}/renewal-hooks" \
-printf "%f\n" \
| xargs --max-args=1 --no-run-if-empty evoacme

View file

@ -16,6 +16,4 @@ A separate `exec.yml` file can be imported manually in playbooks or roles to exe
## Variables
We can force install via :
* `evocheck_force_install: local` : will copy the script provided by the role
* `evocheck_force_install: package` : will install the package via repositories
* `evocheck_update_crontab` : will update the crontab (default: `True`)

View file

@ -1,4 +1,4 @@
---
evocheck_force_install: False
evocheck_update_crontab: True
evocheck_bin_dir: /usr/share/scripts

View file

@ -4,7 +4,7 @@
# Script to verify compliance of a Debian/OpenBSD server
# powered by Evolix
VERSION="21.07"
VERSION="21.10.4"
readonly VERSION
# base functions
@ -74,7 +74,7 @@ detect_os() {
}
is_debian() {
test -n "${DEBIAN_RELEASE}"
test -n "${DEBIAN_RELEASE}"
}
is_debian_lenny() {
test "${DEBIAN_RELEASE}" = "lenny"
@ -220,7 +220,6 @@ check_vartmpfs() {
else
df /var/tmp | grep -q tmpfs || failed "IS_VARTMPFS" "/var/tmp is not a tmpfs"
fi
}
check_serveurbase() {
is_installed serveur-base || failed "IS_SERVEURBASE" "serveur-base package is not installed"
@ -233,8 +232,19 @@ check_syslogconf() {
|| failed "IS_SYSLOGCONF" "syslog evolix config file missing"
}
check_debiansecurity() {
grep -q "^deb.*security" /etc/apt/sources.list \
|| failed "IS_DEBIANSECURITY" "missing debian security repository"
if is_debian_bullseye; then
# https://www.debian.org/releases/bullseye/amd64/release-notes/ch-information.html#security-archive
pattern="^deb https://deb\.debian\.org/debian-security/? bullseye-security main"
elif is_debian_buster; then
pattern="^deb http://security\.debian\.org/debian-security/? buster/updates main"
elif is_debian_stretch; then
pattern="^deb http://security\.debian\.org/debian-security/? stretch/updates main"
else
pattern="^deb.*security"
fi
source_file="/etc/apt/sources.list"
grep -qE "${pattern}" "${source_file}" || failed "IS_DEBIANSECURITY" "missing debian security repository"
}
check_aptitudeonly() {
if is_debian_squeeze || is_debian_wheezy; then
@ -305,7 +315,7 @@ check_customcrontab() {
test "$found_lines" = 4 && failed "IS_CUSTOMCRONTAB" "missing custom field in crontab"
}
check_sshallowusers() {
grep -E -qi "(AllowUsers|AllowGroups)" /etc/ssh/sshd_config \
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"
}
check_diskperf() {
@ -345,6 +355,13 @@ check_minifw() {
/sbin/iptables -L -n | grep -q -E "^ACCEPT\s*all\s*--\s*31\.170\.8\.4\s*0\.0\.0\.0/0\s*$" \
|| failed "IS_MINIFW" "minifirewall seems not starded"
}
check_minifw_includes() {
if is_debian_bullseye; then
if grep -q -e '/sbin/iptables' -e '/sbin/ip6tables' "${MINIFW_FILE}"; then
failed "IS_MINIFWINCLUDES" "minifirewall has direct iptables invocations in ${MINIFW_FILE} that should go in /etc/minifirewall.d/"
fi
fi
}
check_nrpeperms() {
if [ -d /etc/nagios ]; then
nagiosDir="/etc/nagios"
@ -405,17 +422,20 @@ check_apachemunin() {
check_mysqlutils() {
MYSQL_ADMIN=${MYSQL_ADMIN:-mysqladmin}
if is_installed mysql-server; then
# You can configure MYSQL_ADMIN in evocheck.cf
if ! grep -qs "$MYSQL_ADMIN" /root/.my.cnf; then
failed "IS_MYSQLUTILS" "mysqladmin missing in /root/.my.cnf"
# With Debian 11 and later, root can connect to MariaDB with the socket
if is_debian_wheezy || is_debian_jessie || is_debian_stretch || is_debian_buster; then
# You can configure MYSQL_ADMIN in evocheck.cf
if ! grep -qs "^user *= *${MYSQL_ADMIN}" /root/.my.cnf; then
failed "IS_MYSQLUTILS" "${MYSQL_ADMIN} missing in /root/.my.cnf"
fi
fi
if ! test -x /usr/bin/mytop; then
if ! test -x /usr/local/bin/mytop; then
failed "IS_MYSQLUTILS" "mytop binary missing"
fi
fi
if ! grep -qs debian-sys-maint /root/.mytop; then
failed "IS_MYSQLUTILS" "debian-sys-maint missing in /root/.mytop"
if ! grep -qs '^user *=' /root/.mytop; then
failed "IS_MYSQLUTILS" "credentials missing in /root/.mytop"
fi
fi
}
@ -457,7 +477,8 @@ check_squid() {
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -d $host -j ACCEPT" "$MINIFW_FILE" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -d 127.0.0.(1|0/8) -j ACCEPT" "$MINIFW_FILE" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port.* $http_port" "$MINIFW_FILE";
} || failed "IS_SQUID" "missing squid rules in minifirewall"
} || grep -qE "^PROXY='?on'?" "$MINIFW_FILE" \
|| failed "IS_SQUID" "missing squid rules in minifirewall"
fi
}
check_evomaintenance_fw() {
@ -582,6 +603,7 @@ check_evobackup_exclude_mount() {
failed "IS_EVOBACKUP_EXCLUDE_MOUNT" "${mount} is not excluded from ${evobackup_file} backup script"
done
done
rm -rf "${excludes_file}"
}
# Verification de la presence du userlogrotate
check_userlogrotate() {
@ -1018,7 +1040,7 @@ check_phpevolinuxconf() {
check_squidlogrotate() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
if is_installed squid; then
grep -q monthly /etc/logrotate.d/squid \
grep -q -e monthly -e daily /etc/logrotate.d/squid \
|| failed "IS_SQUIDLOGROTATE" "missing squid logrotate file"
fi
fi
@ -1331,6 +1353,133 @@ check_lxc_container_resolv_conf() {
done
fi
}
download_versions() {
local file
file=${1:-}
## The file is supposed to list programs : each on a line, then its latest version number
## Examples:
# evoacme 21.06
# evomaintenance 0.6.4
if is_debian; then
versions_url="https://upgrades.evolix.org/versions-${DEBIAN_RELEASE}"
elif is_openbsd; then
versions_url="https://upgrades.evolix.org/versions-${OPENBSD_RELEASE}"
else
failed "IS_VERSIONS_CHECK" "error determining os release"
fi
# fetch timeout, in seconds
timeout=10
if command -v curl > /dev/null; then
curl --max-time ${timeout} --fail --silent --output "${versions_file}" "${versions_url}"
elif command -v wget > /dev/null; then
wget --timeout=${timeout} --quiet "${versions_url}" -O "${versions_file}"
elif command -v GET; then
GET -t ${timeout}s "${versions_url}" > "${versions_file}"
else
failed "IS_VERSIONS_CHECK" "failed to find curl, wget or GET"
fi
test "$?" -eq 0 || failed "IS_VERSIONS_CHECK" "failed to download ${versions_url} to ${versions_file}"
}
get_command() {
local program
program=${1:-}
case "${program}" in
## Special cases where the program name is different than the command name
evocheck) echo "${0}" ;;
evomaintenance) command -v "evomaintenance.sh" ;;
listupgrade) command -v "evolistupgrade.sh" ;;
old-kernel-autoremoval) command -v "old-kernel-autoremoval.sh" ;;
mysql-queries-killer) command -v "mysql-queries-killer.sh" ;;
## General case, where the program name is the same as the command name
*) command -v "${program}" ;;
esac
}
get_version() {
local program
local command
program=${1:-}
command=${2:-}
case "${program}" in
## Special case if `command --version => 'command` is not the standard way to get the version
# my_command)
# /path/to/my_command --get-version
# ;;
add-vm)
grep '^VERSION=' "${command}" | head -1 | cut -d '=' -f 2
;;
## Let's try the --version flag before falling back to grep for the constant
kvmstats)
if ${command} --version > /dev/null 2> /dev/null; then
${command} --version 2> /dev/null | head -1 | cut -d ' ' -f 3
else
grep '^VERSION=' "${command}" | head -1 | cut -d '=' -f 2
fi
;;
## General case to get the version
*) ${command} --version 2> /dev/null | head -1 | cut -d ' ' -f 3 ;;
esac
}
check_version() {
local program
local expected_version
program=${1:-}
expected_version=${2:-}
command=$(get_command "${program}")
if [ -n "${command}" ]; then
# shellcheck disable=SC2086
actual_version=$(get_version "${program}" "${command}")
# printf "program:%s expected:%s actual:%s\n" "${program}" "${expected_version}" "${actual_version}"
if [ -z "${actual_version}" ]; then
failed "IS_VERSIONS_CHECK" "failed to lookup actual version of ${program}"
elif dpkg --compare-versions "${actual_version}" lt "${expected_version}"; then
failed "IS_VERSIONS_CHECK" "${program} version ${actual_version} is older than expected version ${expected_version}"
elif dpkg --compare-versions "${actual_version}" gt "${expected_version}"; then
failed "IS_VERSIONS_CHECK" "${program} version ${actual_version} is newer than expected version ${expected_version}, you should update tour index."
else
: # Version check OK
fi
fi
}
add_to_path() {
local new_path
new_path=${1:-}
echo "$PATH" | grep -qF "${new_path}" || export PATH="${PATH}:${new_path}"
}
check_versions() {
versions_file=$(mktemp --tmpdir=/tmp "evocheck-versions.XXXXX")
# shellcheck disable=SC2064
trap "rm -f ${versions_file}" 0
download_versions "${versions_file}"
add_to_path "/usr/share/scripts"
grep -v '^ *#' < "${versions_file}" | while IFS= read -r line; do
local program
local version
program=$(echo "${line}" | cut -d ' ' -f 1)
version=$(echo "${line}" | cut -d ' ' -f 2)
if [ -n "${program}" ]; then
if [ -n "${version}" ]; then
check_version "${program}" "${version}"
else
failed "IS_VERSIONS_CHECK" "failed to lookup expected version for ${program}"
fi
fi
done
rm -f "${versions_file}"
}
main() {
# Default return code : 0 = no error
@ -1386,6 +1535,8 @@ main() {
test "${IS_ALERT5MINIFW:=1}" = 1 && test "${IS_MINIFW:=1}" = 1 && check_minifw
test "${IS_NRPEPERMS:=1}" = 1 && check_nrpeperms
test "${IS_MINIFWPERMS:=1}" = 1 && check_minifwperms
# Enable when minifirewall is released
test "${IS_MINIFWINCLUDES:=0}" = 1 && check_minifw_includes
test "${IS_NRPEDISKS:=0}" = 1 && check_nrpedisks
test "${IS_NRPEPID:=1}" = 1 && check_nrpepid
test "${IS_GRSECPROCS:=1}" = 1 && check_grsecprocs
@ -1459,6 +1610,7 @@ main() {
test "${IS_CHROOTED_BINARY_UPTODATE:=1}" = 1 && check_chrooted_binary_uptodate
test "${IS_NGINX_LETSENCRYPT_UPTODATE:=1}" = 1 && check_nginx_letsencrypt_uptodate
test "${IS_LXC_CONTAINER_RESOLV_CONF:=1}" = 1 && check_lxc_container_resolv_conf
test "${IS_CHECK_VERSIONS:=1}" = 1 && check_versions
fi
#-----------------------------------------------------------
@ -1598,6 +1750,7 @@ while :; do
IS_KERNELUPTODATE=0
IS_UPTIME=0
IS_MELTDOWN_SPECTRE=0
IS_CHECK_VERSIONS=0
;;
-v|--verbose)
VERBOSE=1

View file

@ -1,5 +0,0 @@
---
- name: install evocheck from package
apt:
name: evocheck
state: present

View file

@ -1,10 +1,13 @@
---
- include: install_local.yml
when: evocheck_force_install == "local"
- name: Package install is not supported anymore
fail:
msg: Package install is not supported anymore
when:
- evocheck_force_install is defined
- evocheck_force_install == "package"
- include: install_package.yml
when: evocheck_force_install == "package"
- include: install.yml
- include: cron.yml
when: evocheck_update_crontab | bool

View file

@ -89,6 +89,7 @@ evolinux_packages_invalid_mta: True
evolinux_packages_delete_nfs: True
evolinux_packages_listchanges: True
evolinux_packages_logcheck_recipient: False
evolinux_packages_delete_aptlistchanges: True
# system
@ -164,8 +165,10 @@ evolinux_logs_include: True
evolinux_logs_logrotate_confs: True
evolinux_logs_default_rotate: True
evolinux_logs_default_dateext : True
evolinux_logs_disable_logrotate_rsyslog: True
evolinux_logs_rsyslog_conf: True
evolinux_logrotate_dateformat: "-%Y%m%d%H"
# default www
@ -206,7 +209,6 @@ evolinux_fail2ban_include: False
# Evocheck
evolinux_evocheck_include: True
evolinux_evocheck_force_install: "local"
# Listupgrade
@ -218,3 +220,6 @@ evolinux_generateldif_include: True
# Cron check_hpraid
evolinux_cron_checkhpraid_frequency: daily
# Motd
evolinux_motd_include: True

View file

@ -1,10 +1,10 @@
[Unit]
Description=Evolix alert5 script
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/share/scripts/alert5.sh
[Install]
WantedBy=multi-user.target
After=network.target
WantedBy=multi-user.target

View file

@ -0,0 +1,635 @@
#!/bin/sh
PROGNAME="backup-server-state"
VERSION="22.01"
readonly VERSION
backup_dir=
rc=0
# base functions
show_version() {
cat <<END
${PROGNAME} version ${VERSION}
Copyright 2018-2021 Evolix <info@evolix.fr>,
Jérémy Lecour <jlecour@evolix.fr>
and others.
${PROGNAME} comes with ABSOLUTELY NO WARRANTY.This is free software,
and you are welcome to redistribute it under certain conditions.
See the GNU General Public License v3.0 for details.
END
}
show_help() {
cat <<END
${PROGNAME} is making backup copies of information related to the state of the server.
Usage: ${PROGNAME} --backup-dir=/path/to/backup/directory [OPTIONS]
Options
-d, --backup-dir path to the directory where the backup will be stored
--etc backup copy of /etc
--no-etc no backup copy of /etc (default)
--dpkg backup copy of /var/lib/dpkg
--no-dpkg no backup copy of /var/lib/dpkg (default)
--apt backup copy of apt extended states (default)
--no-apt no backup copy of apt extended states
--packages backup copy of dpkg selections (default)
--no-packages no backup copy of dpkg selections
--processes backup copy of process list (default)
--no-processes no backup copy of process list
--uptime backup of uptime value (default)
--no-uptime no backup of uptime value
--netstat backup copy of netstat (default)
--no-netstat no backup copy of netstat
--netcfg backup copy of network configuration (default)
--no-netcfg no backup copy of network configuration
--iptables backup copy of iptables (default)
--no-iptables no backup copy of iptables
--sysctl backup copy of sysctl values (default)
--no-sysctl no backup copy of sysctl values
--virsh backup copy of virsh list (default)
--no-virsh no backup copy of virsh list
--lxc backup copy of lxc list (default)
--no-lxc no backup copy of lxc list
--mount backup copy of mount points (default)
--no-mount no backup copy of mount points
--df backup copy of disk usage (default)
--no-df no backup copy of disk usage
-v, --verbose print details about backup steps
-V, --version print version and exit
-h, --help print this message and exit
END
}
debug() {
if [ "${VERBOSE}" = "1" ]; then
echo "$1"
fi
}
create_backup_dir() {
debug "Create ${backup_dir}"
last_result=$(mkdir -p "${backup_dir}" && chmod -R 755 "${backup_dir}")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* mkdir/chmod OK"
else
debug "* mkdir/chmod ERROR :"
debug "${last_result}"
rc=10
fi
}
backup_etc() {
debug "Backup /etc"
last_result=$(rsync -ah --itemize-changes --exclude=.git /etc "${backup_dir}/")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* rsync OK"
else
debug "* rsync ERROR :"
debug "${last_result}"
rc=10
fi
}
backup_apt() {
if [ -f /var/lib/apt/extended_states ]; then
debug "Backup APT states"
last_result=$(mkdir -p "${backup_dir}/var/lib/apt" && chmod -R 755 "${backup_dir}/var/lib/apt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* mkdir/chmod OK"
else
debug "* mkdir/chmod ERROR"
debug "${last_result}"
rc=10
fi
last_result=$(rsync -ah /var/lib/apt/extended_states "${backup_dir}/var/lib/apt/")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* rsync OK"
else
debug "* rsync ERROR :"
debug "${last_result}"
rc=10
fi
fi
}
backup_dpkg() {
debug "Backup DPkg"
last_result=$(mkdir -p "${backup_dir}/var/lib" && chmod -R 755 "${backup_dir}/var/lib")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* mkdir/chmod OK"
else
debug "* mkdir/chmod ERROR"
debug "${last_result}"
rc=10
fi
last_result=$(rsync -ah --itemize-changes /var/lib/dpkg "${backup_dir}/var/lib/")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* rsync OK"
else
debug "* rsync ERROR"
debug "${last_result}"
rc=10
fi
}
backup_packages() {
debug "Backup list of installed package"
last_result=$(dpkg --get-selections "*" > "${backup_dir}/current_packages.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* dpkg OK"
else
debug "* dpkg ERROR :"
debug "${last_result}"
rc=10
fi
}
backup_uptime() {
debug "Backup uptime"
last_result=$(uptime > "${backup_dir}/uptime.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* uptime OK"
else
debug "* uptime ERROR"
debug "${last_result}"
rc=10
fi
}
backup_processes() {
debug "Backup process list"
last_result=$(ps fauxw > "${backup_dir}/ps.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* ps OK"
else
debug "* ps ERROR"
debug "${last_result}"
rc=10
fi
pstree_bin=$(command -v pstree)
if [ -z "${pstree_bin}" ]; then
last_result=$(pstree -pan > "${backup_dir}/pstree.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* pstree OK"
else
debug "* pstree ERROR"
debug "${last_result}"
rc=10
fi
fi
}
backup_netstat() {
debug "Backup network status"
ss_bin=$(command -v ss)
if [ -z "${ss_bin}" ]; then
last_result=$(${ss_bin} -tanpul > "${backup_dir}/netstat-ss.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* ss OK"
else
debug "* ss ERROR"
debug "${last_result}"
rc=10
fi
fi
netstat_bin=$(command -v netstat)
if [ -z "${netstat_bin}" ]; then
last_result=$(netstat -laputen > "${backup_dir}/netstat-legacy.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* netstat OK"
else
debug "* netstat ERROR"
debug "${last_result}"
rc=10
fi
fi
}
backup_netcfg() {
debug "Backup network configuration"
last_result=$(ip address show > "${backup_dir}/ip-address.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* ip address OK"
else
debug "* ip address ERROR"
debug "${last_result}"
rc=10
fi
last_result=$(ip route show > "${backup_dir}/ip-route.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* ip route OK"
else
debug "* ip route ERROR"
debug "${last_result}"
rc=10
fi
}
backup_iptables() {
debug "Backup iptables"
last_result=$({ /sbin/iptables -L -n -v; /sbin/iptables -t filter -L -n -v; } > "${backup_dir}/iptables.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* iptables OK"
else
debug "* iptables ERROR"
debug "${last_result}"
rc=10
fi
}
backup_sysctl() {
debug "Backup sysctl values"
last_result=$(sysctl -a | sort -h > "${backup_dir}/sysctl.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* sysctl OK"
else
debug "* sysctl ERROR"
debug "${last_result}"
rc=10
fi
}
backup_virsh() {
debug "Backup virsh list"
virsh_bin=$(command -v virsh)
if [ -n "${virsh_bin}" ]; then
last_result=$(${virsh_bin} list --all > "${backup_dir}/virsh-list.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* virsh list OK"
else
debug "* virsh list ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* virsh not installed"
fi
}
backup_lxc() {
debug "Backup lxc list"
lxc_ls_bin=$(command -v lxc-ls)
if [ -n "${lxc_ls_bin}" ]; then
last_result=$(${lxc_ls_bin} --fancy > "${backup_dir}/lxc-list.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* lxc list OK"
else
debug "* lxc list ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* lxc-ls not installed"
fi
}
backup_mount() {
debug "Backup mount points"
findmnt_bin=$(command -v findmnt)
mount_bin=$(command -v mount)
if [ -n "${findmnt_bin}" ]; then
last_result=$(${findmnt_bin} > "${backup_dir}/mount.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* mount points OK"
else
debug "* mount points ERROR"
debug "${last_result}"
rc=10
fi
elif [ -n "${mount_bin}" ]; then
last_result=$(${mount_bin} > "${backup_dir}/mount.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* mount points OK"
else
debug "* mount points ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* findmnt and mount not installed"
fi
}
backup_df() {
debug "Backup df"
df_bin=$(command -v df)
if [ -n "${df_bin}" ]; then
last_result=$(${df_bin} --portability > "${backup_dir}/df.txt")
last_rc=$?
if [ ${last_rc} -eq 0 ]; then
debug "* df OK"
else
debug "* df ERROR"
debug "${last_result}"
rc=10
fi
else
debug "* df not installed"
fi
}
main() {
if [ -z "${backup_dir}" ]; then
echo "ERROR: You must provide the --backup-dir argument" >&2
exit 1
fi
if [ -d "${backup_dir}" ]; then
echo "ERROR: The backup directory ${backup_dir} already exists. Delete it first." >&2
exit 2
else
create_backup_dir
fi
if [ "${DO_ETC}" -eq 1 ]; then
backup_etc
fi
if [ "${DO_DPKG}" -eq 1 ]; then
backup_dpkg
fi
if [ "${DO_APT}" -eq 1 ]; then
backup_apt
fi
if [ "${DO_PACKAGES}" -eq 1 ]; then
backup_packages
fi
if [ "${DO_PROCESSES}" -eq 1 ]; then
backup_processes
fi
if [ "${DO_UPTIME}" -eq 1 ]; then
backup_uptime
fi
if [ "${DO_NETSTAT}" -eq 1 ]; then
backup_netstat
fi
if [ "${DO_NETCFG}" -eq 1 ]; then
backup_netcfg
fi
if [ "${DO_IPTABLES}" -eq 1 ]; then
backup_iptables
fi
if [ "${DO_SYSCTL}" -eq 1 ]; then
backup_sysctl
fi
if [ "${DO_VIRSH}" -eq 1 ]; then
backup_virsh
fi
if [ "${DO_LXC}" -eq 1 ]; then
backup_lxc
fi
if [ "${DO_MOUNT}" -eq 1 ]; then
backup_mount
fi
if [ "${DO_DF}" -eq 1 ]; then
backup_df
fi
debug "=> Your backup is available at ${backup_dir}"
exit ${rc}
}
# parse options
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
while :; do
case $1 in
-h|-\?|--help)
show_help
exit 0
;;
-V|--version)
show_version
exit 0
;;
-v|--verbose)
VERBOSE=1
;;
-d|--backup-dir)
# with value separated by space
if [ -n "$2" ]; then
backup_dir=$2
shift
else
printf 'ERROR: "-d|--backup-dir" requires a non-empty option argument.\n' >&2
exit 1
fi
;;
--backup-dir=?*)
# with value speparated by =
backup_dir=${1#*=}
;;
--backup-dir=)
# without value
printf 'ERROR: "--backup-dir" requires a non-empty option argument.\n' >&2
exit 1
;;
--etc)
DO_ETC=1
;;
--no-etc)
DO_ETC=0
;;
--dpkg)
DO_DPKG=1
;;
--no-dpkg)
DO_DPKG=0
;;
--apt)
DO_APT=1
;;
--no-apt)
DO_APT=0
;;
--packages)
DO_PACKAGES=1
;;
--no-packages)
DO_PACKAGES=0
;;
--processes)
DO_PROCESSES=1
;;
--no-processes)
DO_PROCESSES=0
;;
--uptime)
DO_UPTIME=1
;;
--no-uptime)
DO_UPTIME=0
;;
--netstat)
DO_NETSTAT=1
;;
--no-netstat)
DO_NETSTAT=0
;;
--netcfg)
DO_NETCFG=1
;;
--no-netcfg)
DO_NETCFG=0
;;
--iptables)
DO_IPTABLES=1
;;
--no-iptables)
DO_IPTABLES=0
;;
--sysctl)
DO_SYSCTL=1
;;
--no-sysctl)
DO_SYSCTL=0
;;
--virsh)
DO_VIRSH=1
;;
--no-virsh)
DO_VIRSH=0
;;
--lxc)
DO_LXC=1
;;
--no-lxc)
DO_LXC=0
;;
--mount)
DO_MOUNT=1
;;
--no-mount)
DO_MOUNT=0
;;
--df)
DO_DF=1
;;
--no-df)
DO_DF=0
;;
--)
# End of all options.
shift
break
;;
-?*)
# ignore unknown options
printf 'WARN: Unknown option : %s\n' "$1" >&2
exit 1
;;
*)
# Default case: If no more options then break out of the loop.
break
;;
esac
shift
done
# Default values
: "${VERBOSE:=0}"
: "${DO_ETC:=0}"
: "${DO_DPKG:=0}"
: "${DO_APT:=1}"
: "${DO_PACKAGES:=1}"
: "${DO_PROCESSES:=1}"
: "${DO_UPTIME:=1}"
: "${DO_NETSTAT:=1}"
: "${DO_NETCFG:=1}"
: "${DO_IPTABLES:=1}"
: "${DO_SYSCTL:=1}"
: "${DO_VIRSH:=1}"
: "${DO_LXC:=1}"
: "${DO_MOUNT:=1}"
: "${DO_DF:=1}"
export LC_ALL=C
set -u
main

View file

@ -0,0 +1,9 @@
/var/log/alternatives.log {
monthly
rotate 120
compress
delaycompress
missingok
notifempty
create 644 root root
}

View file

@ -6,14 +6,4 @@
missingok
notifempty
create 644 root root
}
/var/log/alternatives.log {
monthly
rotate 120
compress
delaycompress
missingok
notifempty
create 644 root root
}
}

View file

@ -2,8 +2,8 @@
weekly
missingok
rotate 3
compress
notifempty
compress
notifempty
create 640 root adm
}

View file

@ -1,11 +1,7 @@
/var/log/procmail.log {
daily
rotate 365
dateext
dateyesterday
dateformat .%Y%m%d
missingok
rotate 365
create 640 root adm
}

View file

@ -1,5 +1,6 @@
---
# TODO: trouver comment faire une copie initiale de /etc/fstab
# - piste : paramètre "backup" du module mount https://docs.ansible.com/ansible/latest/collections/ansible/posix/mount_module.html
# TODO: try to use the custom mount_uuid module for a different approach
- name: Fetch fstab content

View file

@ -30,13 +30,25 @@
- packages
when: broadcom_netextreme_search.rc == 0
## Dedicated hardware
- name: Install freepmi when it's dedicated hardware
apt:
name:
- libipc-run-perl
- freeipmi
state: present
tags:
- packages
when: ansible_virtualization_role == "host"
## RAID
# Dell and others: MegaRAID SAS
# HP gen <10: Hewlett-Packard Company Smart Array
# HP gen >=10: Adaptec Smart Storage PQI
- name: Detect if RAID is installed
shell:
cmd: "set -o pipefail && lspci -q | grep -e 'RAID bus controller' -e 'Serial Attached SCSI controller'"
shell:
cmd: "lspci -q | grep -e 'RAID bus controller' -e 'Serial Attached SCSI controller'"
executable: /bin/bash
check_mode: no
register: raidmodel

View file

@ -8,8 +8,8 @@
state: present
reload: yes
loop:
- { name: kernel.panic_on_oops, value: 1 }
- { name: kernel.panic, value: 60 }
- { name: kernel.panic_on_oops, value: 1 }
- { name: kernel.panic, value: 60 }
when: evolinux_kernel_reboot_after_panic | bool
- name: Don't reboot after panic
@ -19,8 +19,8 @@
state: absent
reload: yes
loop:
- kernel.panic_on_oops
- kernel.panic
- kernel.panic_on_oops
- kernel.panic
when: not evolinux_kernel_reboot_after_panic | bool
- name: Disable net.ipv4.tcp_timestamps

View file

@ -30,11 +30,34 @@
dest: /etc/logrotate.d/zsyslog
when: evolinux_logs_logrotate_confs | bool
- name: Configure logrotate.conf
- name: Configure logrotate.conf default rotate value
replace:
dest: /etc/logrotate.conf
regexp: "rotate [0-9]+"
replace: "rotate 12"
when: evolinux_logs_default_rotate | bool
- name: Enable logrotate.conf dateext option
lineinfile:
dest: /etc/logrotate.conf
line: "dateext"
regexp: "^#?\\s*dateext"
when: evolinux_logs_default_dateext | bool
- name: Enable logrotate.conf dateformat option
lineinfile:
dest: /etc/logrotate.conf
line: "dateformat {{ evolinux_logrotate_dateformat | mandatory }}"
regexp: "^#?\\s*dateformat.*"
insertafter: 'dateext'
when: evolinux_logs_default_dateext | bool
- name: Disable logrotate.conf dateyesterday option
lineinfile:
dest: /etc/logrotate.conf
line: "# dateyesterday"
regexp: "^\\s*dateyesterday"
insertafter: 'dateext'
when: evolinux_logs_default_dateext | bool
- meta: flush_handlers

View file

@ -97,6 +97,9 @@
when: evolinux_log2mail_include | bool
- include: motd.yml
when: evolinux_motd_include | bool
- include: utils.yml
- name: Munin
include_role:
@ -116,8 +119,6 @@
- name: Evocheck
include_role:
name: evolix/evocheck
vars:
evocheck_force_install: "{{ evolinux_evocheck_force_install }}"
when: evolinux_evocheck_include | bool
- name: Listupgrade

View file

@ -16,6 +16,7 @@
- ssl-cert
- ca-certificates
- rename
- dmidecode
when: evolinux_packages_system | bool
- name: Install/Update diagnostic tools
@ -34,6 +35,7 @@
- telnet
- traceroute
- man
- molly-guard
when: evolinux_packages_diagnostic | bool
- name: Install/Update hardware tools
@ -143,5 +145,6 @@
when:
- ansible_distribution == "Debian"
- ansible_distribution_major_version is version('9', '>=')
- evolinux_packages_delete_aptlistchanges
- meta: flush_handlers

View file

@ -119,10 +119,10 @@
regexp: "{{ item.regexp }}"
replace: "{{ item.replace }}"
loop:
- { regexp: '^17((\s*\*){4})', replace: '{{ 59|random(start=1) }}\1' }
- { regexp: '^25\s*6((\s*\*){3})', replace: '{{ 59|random(start=1) }} {{ [0,1,3,4,5,6,7]|random }}\1' }
- { regexp: '^47\s*6((\s*\*){2}\s*7)', replace: '{{ 59|random(start=1) }} {{ [0,1,3,4,5,6,7]|random }}\1' }
- { regexp: '^52\s*6(\s*1(\s*\*){2})', replace: '{{ 59|random(start=1) }} {{ [0,1,3,4,5,6,7]|random }}\1' }
- { regexp: '^17((\s*\*){4})', replace: '{{ 59|random(start=1) }}\1' }
- { regexp: '^25\s*6((\s*\*){3})', replace: '{{ 59|random(start=1) }} {{ [0,1,3,4,5,6,7]|random }}\1' }
- { regexp: '^47\s*6((\s*\*){2}\s*7)', replace: '{{ 59|random(start=1) }} {{ [0,1,3,4,5,6,7]|random }}\1' }
- { regexp: '^52\s*6(\s*1(\s*\*){2})', replace: '{{ 59|random(start=1) }} {{ [0,1,3,4,5,6,7]|random }}\1' }
when:
- is_cron_installed.rc == 0
- evolinux_system_cron_random | bool
@ -182,6 +182,7 @@
- evolinux_system_alert5_init | bool
- evolinux_system_alert5_enable | bool
- ansible_distribution_major_version is version('10', '>=')
- not ansible_check_mode
## network interfaces

View file

@ -0,0 +1,13 @@
---
- include_role:
name: evolix/remount-usr
- name: backup-server-state script is present
copy:
src: "backup-server-state.sh"
dest: /usr/local/sbin/backup-server-state
force: True
owner: root
group: root
mode: "0750"

View file

@ -1,8 +1,13 @@
# Custom EvoLinux
create 640 root adm
{% if not evolinux_logs_default_dateext %}
# BEGIN legacy setting
# … when global dateext and dateformat are not enabled
dateext
dateyesterday
dateformat .%Y%m%d
# END legacy setting
{% endif %}
missingok
notifempty
delaycompress

View file

@ -7,6 +7,8 @@ nagios ALL = NOPASSWD: /usr/lib/nagios/plugins/check_procs
nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_minifirewall
nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_haproxy_stats
nagios ALL = NOPASSWD: /usr/sbin/bkctld check
nagios ALL = NOPASSWD: /usr/sbin/bkctld check-jails
nagios ALL = NOPASSWD: /usr/sbin/bkctld check-setup
nagios ALL = (clamav) NOPASSWD: /usr/bin/clamscan /tmp/safe.txt
ADMINS ALL = (ALL:ALL) ALL

View file

@ -6,10 +6,22 @@ nagios ALL = NOPASSWD: /usr/lib/nagios/plugins/check_procs
nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_minifirewall
nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_haproxy_stats
nagios ALL = NOPASSWD: /usr/sbin/bkctld check
nagios ALL = NOPASSWD: /usr/sbin/bkctld check-jails
nagios ALL = NOPASSWD: /usr/sbin/bkctld check-setup
nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_phpfpm_multi /var/lib/lxc/php56/rootfs/etc/php5/fpm/pool.d/
nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_phpfpm_multi /var/lib/lxc/php70/rootfs/etc/php/7.0/fpm/pool.d/
nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_phpfpm_multi /var/lib/lxc/php73/rootfs/etc/php/7.3/fpm/pool.d/
nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_phpfpm_multi /var/lib/lxc/php74/rootfs/etc/php/7.4/fpm/pool.d/
nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_phpfpm_multi /var/lib/lxc/php74/rootfs/etc/php/8.0/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
nagios ALL = NOPASSWD: /sbin/megacli -PDList -aALL -NoLog
nagios ALL = NOPASSWD: /sbin/megacli -LdInfo -Lall -aALL -NoLog
nagios ALL = NOPASSWD: /sbin/megacli -AdpBbuCmd -GetBbuStatus -aALL -NoLog
nagios ALL = NOPASSWD: /sbin/ssacli controller all show status
nagios ALL = NOPASSWD: /sbin/ssacli controller slot=0 logicaldrive all show
nagios ALL = (clamav) NOPASSWD: /usr/bin/clamscan /tmp/safe.txt
%{{ evolinux_sudo_group }} ALL=(ALL:ALL) ALL

View file

@ -4,16 +4,16 @@
# Dependencies (all OS): git postgresql-client
# Dependencies (Debian): sudo
# Copyright 2007-2021 Evolix <info@evolix.fr>, Gregory Colpart <reg@evolix.fr>,
# Copyright 2007-2022 Evolix <info@evolix.fr>, Gregory Colpart <reg@evolix.fr>,
# Jérémy Lecour <jlecour@evolix.fr> and others.
VERSION="0.6.4"
VERSION="22.01"
show_version() {
cat <<END
evomaintenance version ${VERSION}
Copyright 2007-2021 Evolix <info@evolix.fr>,
Copyright 2007-2022 Evolix <info@evolix.fr>,
Gregory Colpart <reg@evolix.fr>,
Jérémy Lecour <jlecour@evolix.fr>
and others.
@ -303,6 +303,9 @@ From: ${FULLFROM}
Content-Type: text/plain; charset=UTF-8
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-Evomaintenance-Version: ${VERSION}
X-Evomaintenance-Host: ${HOSTNAME_TEXT}
X-Evomaintenance-User: ${USER}
To: ${EVOMAINTMAIL}
Subject: [evomaintenance] Intervention sur ${HOSTNAME_TEXT} (${USER})

View file

@ -0,0 +1,18 @@
---
- assert:
that:
- evomaintenance_api_endpoint is not none
- evomaintenance_api_key is not none
msg: evomaintenance api variables must be set
- name: Configuration is installed
template:
src: evomaintenance.j2
dest: /etc/evomaintenance.cf
owner: root
group: root
mode: "0600"
force: "{{ evomaintenance_force_config | bool }}"
tags:
- evomaintenance

View file

@ -12,15 +12,4 @@
name: evomaintenance
allow_unauthenticated: yes
tags:
- evomaintenance
- name: Configuration is installed
template:
src: evomaintenance.j2
dest: /etc/evomaintenance.cf
owner: root
group: root
mode: "0600"
force: "{{ evomaintenance_force_config | bool }}"
tags:
- evomaintenance
- evomaintenance

View file

@ -46,15 +46,4 @@
- { src: 'evomaintenance.sh', dest: '/usr/share/scripts/', mode: '0700' }
- { src: 'evomaintenance.tpl', dest: '/usr/share/scripts/', mode: '0600' }
tags:
- evomaintenance
- name: Configuration is installed
template:
src: evomaintenance.j2
dest: /etc/evomaintenance.cf
owner: root
group: root
mode: "0600"
force: "{{ evomaintenance_force_config | bool }}"
tags:
- evomaintenance
- evomaintenance

View file

@ -1,14 +1,5 @@
---
- set_fact:
minifirewall_restart_handler_name: "{{ minifirewall_restart_if_needed | bool | ternary('restart minifirewall', 'restart minifirewall (noop)') }}"
- assert:
that:
- evomaintenance_api_endpoint is not none
- evomaintenance_api_key is not none
msg: evomaintenance api variables must be set
- include: install_package_debian.yml
when:
- not (evomaintenance_install_vendor | bool)
@ -19,6 +10,8 @@
- evomaintenance_install_vendor | bool
- ansible_distribution == "Debian"
- include: config.yml
- include: minifirewall.yml
when:
- evomaintenance_hook_db | bool

View file

@ -1,5 +1,8 @@
---
- set_fact:
minifirewall_restart_handler_name: "{{ minifirewall_restart_if_needed | bool | ternary('restart minifirewall', 'restart minifirewall (noop)') }}"
- name: Is minifirewall installed?
stat:
path: /etc/default/minifirewall

View file

@ -1,5 +1,5 @@
---
elastic_stack_version: "6.x"
elastic_stack_version: "7.x"
filebeat_logstash_plugin: False

View file

@ -4,3 +4,4 @@
systemd:
name: filebeat
state: restarted
when: not ansible_check_mode

View file

@ -62,6 +62,7 @@
name: filebeat
enabled: yes
notify: restart filebeat
when: not ansible_check_mode
- name: is logstash-plugin available?
stat:
@ -140,7 +141,9 @@
when:
- filebeat_elasticsearch_auth_username | length > 0
- filebeat_elasticsearch_auth_password | length > 0
when: not (filebeat_use_config_template | bool)
when:
- not (filebeat_use_config_template | bool)
- not ansible_check_mode
- name: Filebeat api_key for Elasticsearch are configured
lineinfile:

View file

@ -31,17 +31,30 @@ computerKernel=$(uname -r)
HardwareSerial=$(dmidecode -s system-serial-number | grep -v '^#')
type="baremetal"
lscpu | grep -q KVM && type="kvm"
lscpu | grep "Hypervisor vendor:" | grep -q KVM && type="kvm"
lscpu | grep "Hypervisor vendor:" | grep -q VMware && type="vmware"
lscpu | grep -q Oracle && type="virtualbox"
if [ "$type" = "kvm" ]; then
ComputerType="VM"
HardwareMark="KVM"
HardwareModel="Virtual Machine"
cpuMark=$(lscpu | grep Vendor | tr -s '\t' ' ' | cut -d' ' -f3)
cpuModel="Virtual $(lscpu | grep "Model name" | tr -s '\t' ' ' | cut -d' ' -f3-), $(nproc) vCPU"
cpuFreq="$(lscpu | grep "CPU MHz" | tr -s '\t' ' ' | cut -d' ' -f3-)MHz"
elif [ "$type" = "vmware" ]; then
ComputerType="VM"
HardwareMark="VMWare"
HardwareModel="Virtual Machine"
cpuMark=$(lscpu | grep Vendor | tr -s '\t' ' ' | cut -d' ' -f3)
cpuModel="Virtual $(lscpu | grep "Model name" | tr -s '\t' ' ' | cut -d' ' -f3-), $(nproc) vCPU"
cpuFreq="$(lscpu | grep "CPU MHz" | tr -s '\t' ' ' | cut -d' ' -f3-)MHz"
elif [ "$type" = "virtualbox" ]; then
ComputerType="VM"
HardwareMark="VirtualBox"
HardwareModel="Virtual Machine"
@ -49,6 +62,7 @@ elif [ "$type" = "virtualbox" ]; then
cpuModel="Virtual $(lscpu | grep "Model name" | tr -s '\t' ' ' | cut -d' ' -f3-), $(nproc) vCPU"
cpuFreq="$(lscpu | grep "CPU MHz" | tr -s '\t' ' ' | cut -d' ' -f3-)MHz"
else
ComputerType="Baremetal"
HardwareModel=$(dmidecode -s system-product-name | grep -v '^#')
cpuMark=$(dmidecode -s processor-manufacturer | grep -v '^#' | head -1)
@ -115,6 +129,7 @@ NagiosEnabled: ${NagiosEnabled}
NagiosComments: ${monitoringType},${monitoringMode},${monitoringTimeout}
HardwareSerial: ${HardwareSerial}
clientNumber: ${clientNumber}
ComputerType: ${ComputerType}
EOT
# CPU
@ -174,6 +189,19 @@ NagiosEnabled: TRUE
EOT
fi
# raid hardware
if [ -n "${raidModel}" ]; then
cat <<EOT >> "${ldif_file}"
dn: HardwareName=raid_card,${computer_dn}
objectClass: EvoHardware
HardwareName: raid_card
HardwareType: disk
HardwareModel: ${raidModel}
NagiosEnabled: TRUE
EOT
fi
# Swap
swap=$(free -h | grep Swap: | tr -s ' ' | cut -d ' ' -f2)
if [ -n "${swap}" ]; then
@ -570,10 +598,27 @@ objectClass: EvoService
ServiceName: postgresql
ipServicePort: 5432
ServiceType: database
ServiceVersion: PostgreSQL ${elasticsearch_version}
ServiceVersion: PostgreSQL ${postgresql_version}
EOT
fi
# mdadm
if is_pkg_installed mdadm; then
mdadm_version=$(get_pkg_version mdadm)
fi
if [ -n "${mdadm_version}" ]; then
cat <<EOT >> "${ldif_file}"
dn: ServiceName=mdadm,${computer_dn}
NagiosEnabled: TRUE
objectClass: EvoService
ServiceName: mdadm
ServiceType: raid
ServiceVersion: mdadm ${mdadm_version}
EOT
fi
# test if we have a stdout
if [ -t 1 ]; then
echo "Output is in ${ldif_file}"

View file

@ -14,9 +14,9 @@
state: directory
mode: "0777"
loop:
- /srv/java-package
- /srv/java-package/src
- /srv/java-package/tmp
- /srv/java-package
- /srv/java-package/src
- /srv/java-package/tmp
tags:
- java

View file

@ -10,6 +10,8 @@
# Bash strict mode
set -euo pipefail
VERSION="21.10"
isDryRun() {
test "${doDryRun}" = "true"
}

View file

@ -1,96 +1,202 @@
#!/bin/sh
VERSION="21.10"
PROGNAME=$(basename "$0")
show_version() {
cat <<END
${PROGNAME} version ${VERSION}
Copyright 2018-2021 Evolix <info@evolix.fr>,
Alexis Ben Miloud--Josselin <abenmiloud@evolix.fr>,
Jérémy Lecour <jlecour@evolix.fr>
and others.
${PROGNAME} comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
See the GNU General Public Licence for details.
END
}
show_help() {
cat <<END
${PROGNAME} print stats about configured virtal servers
END
show_usage
}
show_usage() {
cat <<END
Usage: ${PROGNAME} --all
or ${PROGNAME} --output <human|html|csv>
or ${PROGNAME} --units <k|m|g>
END
}
error () {
echo "$0": "$@" >&2
exit 1
}
usage () {
echo 'usage:' "$0" '[-a] [-u k|m|g] [-o human|html|csv]' >&2
exit 1
main() {
for VM in $(virsh list --name --all | sed '/^$/d' | sort)
do
echo "$VM"
# cpu
virsh vcpucount --current "$VM"
# mem
# libvirt stores memory in KiB, POW must be lowered by 1
virsh dommemstat "$VM" 2>/dev/null | awk 'BEGIN{ret=1}$1~/^actual$/{print $2 / '$((POW / 1024))';ret=0}END{exit ret}' ||
virsh dumpxml "$VM" | awk -F'[<>]' '$2~/^memory unit/{print $3/'$((POW / 1024))'}'
# disk
for BLK in $(virsh domblklist "$VM" | sed '1,2d;/-$/d;/^$/d' | awk '{print $1}')
do
virsh domblkinfo "$VM" "$BLK" 2>/dev/null
done | awk '/Physical:/ { size += $2 } END { print int(size / '${POW}') }'
# state
virsh domstate "$VM" | grep -q '^running$' && echo yes || echo no
done | xargs -n5 | {
echo vm vcpu ram disk running
awk '{ print } /yes$/ { vcpu += $2; ram += $3; disk += $4; running++ } END { print "TOTAL(running)", vcpu, ram, disk, running }'
test "$SHOW_AVAIL" && {
nproc
awk '/^MemTotal:/ { print int($2 / '$((POW / 1024))' ) }' /proc/meminfo
} | xargs -r printf 'AVAILABLE %s %s %s %s\n'
} | case "$FMT" in
'human')
column -t
;;
'html')
awk 'BEGIN{print "<html><body>\n<table>"}{printf "<tr>";for(i=1;i<=NF;i++)printf "<td>%s</td>", $i;print "</tr>"}END{print "</table>\n</body></html>"}'
;;
'csv')
tr ' ' ','
;;
esac
}
parse_units() {
case "$1" in
'k')
POW="$(echo '1024 ^ 1' | bc)"
;;
'm')
POW="$(echo '1024 ^ 2' | bc)"
;;
'g')
POW="$(echo '1024 ^ 3' | bc)"
;;
*)
printf 'ERROR: Unknown unit value: %s. Possible values: %s\n' "$1" "k, m, g" >&2
echo "" >&2
show_usage >&2
exit 1
;;
esac
}
parse_output() {
case "$1" in
'csv'|'html'|'human')
FMT="$1"
;;
*)
printf 'ERROR: Unknown output value : %s. Possible values: %s\n' "$1" "csv, html, human" >&2
echo "" >&2
show_usage >&2
exit 1
;;
esac
}
# Check dependencies
for DEP in bc virsh
do
command -v "$DEP" > /dev/null || error "$DEP" 'command not found'
done
# default values
POW="$(echo '1024 ^ 3' | bc)"
FMT='human'
while [ "$#" -ne 0 ]
do
case "$1" in
'-a')
SHOW_AVAIL='y'
;;
'-o')
case "$2" in
'csv'|'html'|'human')
FMT="$2"
# Parse options
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
while :; do
case $1 in
-h|-\?|--help)
show_help
exit 0
;;
-V|--version)
show_version
exit 0
;;
-a|--all)
SHOW_AVAIL='y'
;;
-u|--units)
# with value separated by space
if [ -n "$2" ]; then
parse_units "$2"
shift
else
printf 'ERROR: "-u|--units" requires a non-empty option argument.\n' >&2
exit 1
fi
;;
--units=?*)
# with value speparated by =
parse_units ${1#*=}
;;
--units=)
# without value
printf 'ERROR: "--units" requires a non-empty option argument.\n' >&2
exit 1
;;
-o|--output)
# with value separated by space
if [ -n "$2" ]; then
parse_output "$2"
shift
else
printf 'ERROR: "-o|--output" requires a non-empty option argument.\n' >&2
exit 1
fi
;;
--output=?*)
# with value speparated by =
parse_output ${1#*=}
;;
--output=)
# without value
printf 'ERROR: "--output" requires a non-empty option argument.\n' >&2
exit 1
;;
--)
# End of all options.
shift
break
;;
-?*|[[:alnum:]]*)
# ignore unknown options
printf 'ERROR: Unknown option : %s\n' "$1" >&2
echo "" >&2
show_usage >&2
exit 1
;;
*)
usage
# Default case: If no more options then break out of the loop.
break
;;
esac
shift
;;
'-u')
case "$2" in
'k')
POW="$(echo '1024 ^ 1' | bc)"
;;
'm')
POW="$(echo '1024 ^ 2' | bc)"
;;
'g')
POW="$(echo '1024 ^ 3' | bc)"
;;
*)
usage
esac
shift
;;
*)
usage
esac
shift
done
for VM in $(virsh list --name --all)
do
echo "$VM"
# cpu
virsh vcpucount --current "$VM"
# mem
# libvirt stores memory in KiB, POW must be lowered by 1
virsh dommemstat "$VM" 2>/dev/null | awk 'BEGIN{ret=1}$1~/^actual$/{print $2 / '$((POW / 1024))';ret=0}END{exit ret}' ||
virsh dumpxml "$VM" | awk -F'[<>]' '$2~/^memory unit/{print $3/'$((POW / 1024))'}'
# disk
for BLK in $(virsh domblklist "$VM" | sed '1,2d;/-$/d;/^$/d' | awk '{print $1}')
do
virsh domblkinfo "$VM" "$BLK" 2>/dev/null
done | awk '/Physical:/ { size += $2 } END { print int(size / '${POW}') }'
# state
virsh domstate "$VM" | grep -q '^running$' && echo yes || echo no
done | xargs -n5 | {
echo vm vcpu ram disk running
awk '{ print } /yes$/ { vcpu += $2; ram += $3; disk += $4; running++ } END { print "TOTAL(running)", vcpu, ram, disk, running }'
test "$SHOW_AVAIL" && {
nproc
awk '/^MemTotal:/ { print int($2 / '$((POW / 1024))' ) }' /proc/meminfo
} | xargs -r printf 'AVAILABLE %s %s %s %s\n'
} | case "$FMT" in
'human')
column -t
;;
'html')
awk 'BEGIN{print "<html><body>\n<table>"}{printf "<tr>";for(i=1;i<=NF;i++)printf "<td>%s</td>", $i;print "</tr>"}END{print "</table>\n</body></html>"}'
;;
'csv')
tr ' ' ','
;;
esac
main

View file

@ -5,7 +5,7 @@
when: kvm_install_drbd
## TODO: check why it's disabled
#- include: ssh.yml
- include: ssh.yml
- include: packages.yml

View file

@ -15,36 +15,34 @@
debug:
msg: "{{ ssh_keys.stdout }}"
- name: Autorize other kvm ssh key
authorized_key:
user: root
state: present
key: "{{ item[0] }}"
delegate_to: "{{ item[1] }}"
loop: "{{ _keys | product(_servers) | list }}"
vars:
_keys: ssh_keys.stdout
_servers: groups['hypervisors']
when: item[1] != inventory_hostname
#- name: Autorize other kvm ssh key
# authorized_key:
# user: root
# state: present
# key: "{{ item[0] }}"
# delegate_to: "{{ item[1] }}"
# loop: "{{ _keys | product(_servers) | list }}"
# vars:
# _keys: ssh_keys.stdout
# _servers: groups['hypervisors']
# when: item[1] != inventory_hostname
- name: Crontab for sync libvirt xml file
cron:
name: "sync libvirt xml on {{ item }}"
name: "sync libvirt xml on {{ kvm_pair }}"
state: present
special_time: "hourly"
user: root
job: "rsync -a --delete /etc/libvirt/qemu/ {{ hostvars[item]['ansible_hostname'] }}:/root/libvirt-{{ inventory_hostname }}/"
loop:
- "{{ groups['hypervisors'] }}"
when: item != inventory_hostname
job: "rsync -a --delete /etc/libvirt/qemu/*xml {{ hostvars[kvm_pair]['lan.ip'] }}:/root/libvirt-{{ inventory_hostname }}/"
when: kvm_pair != inventory_hostname
tags: crontab
- name: Crontab for sync list of running vm
cron:
name: "sync list of libvirt running vm on {{ item }}"
name: "sync list of libvirt running vm on {{ kvm_pair }}"
state: present
special_time: "daily"
user: root
job: "virsh list --all | ssh {{ hostvars[item]['ansible_hostname'] }} 'cat >/root/libvirt-{{ inventory_hostname }}/virsh-list.txt'"
loop:
- "{{ groups['hypervisors'] }}"
when: item != inventory_hostname
job: "virsh list --all | tee /root/virsh-list.txt | ssh {{ hostvars[kvm_pair]['lan.ip'] }} 'cat >/root/libvirt-{{ inventory_hostname }}/virsh-list.txt'"
when: kvm_pair != inventory_hostname
tags: crontab

View file

@ -4,13 +4,36 @@
# fork by reg from /etc/kernel/postinst.d/apt-auto-removal script
VERSION="21.06.3"
VERSION="21.10"
readonly VERSION
set -e
PROGNAME=$(basename "$0")
# shellcheck disable=SC2046
eval $(apt-config shell DPKG Dir::bin::dpkg/f)
DPKG="${DPKG:-/usr/bin/dpkg}"
show_version() {
cat <<END
${PROGNAME} version ${VERSION}
Copyright 2018-2021 Evolix <info@evolix.fr>,
Gregory Colpart <reg@evolix.fr>,
Romain Dessort <rdessort@evolix.fr>,
Ludovic Poujol <lpoujol@evolix.fr>,
Jérémy Lecour <jlecour@evolix.fr>
and others.
${PROGNAME} comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
See the GNU General Public Licence for details.
END
}
show_help() {
cat <<END
${PROGNAME} removes old kernels.
Options
-h, --help print this message and exit
--version print version and exit
END
}
# Detect which one of apt/aptitude we should use.
# shellcheck disable=SC2120
@ -27,57 +50,103 @@ get_apt_binary() {
fi
}
listupgrade_state_dir="${listupgrade_state_dir:-/var/lib/listupgrade}"
main() {
specifc_kernel="$1"
APT=$(get_apt_binary)
# shellcheck disable=SC2046
eval $(apt-config shell DPKG Dir::bin::dpkg/f)
DPKG="${DPKG:-/usr/bin/dpkg}"
list="$("${DPKG}" -l | awk '/^[ih][^nc][ ]+(linux|kfreebsd|gnumach)-image-[0-9]+\./ && $2 !~ /-dbg(:.*)?$/ && $2 !~ /-dbgsym(:.*)?$/ { print $2,$3; }' \
| sed -e 's#^\(linux\|kfreebsd\|gnumach\)-image-##' -e 's#:[^:]\+ # #')"
debverlist="$(echo "${list}" | cut -d' ' -f 2 | sort --unique --reverse --version-sort)"
listupgrade_state_dir="${listupgrade_state_dir:-/var/lib/listupgrade}"
if [ -n "$1" ]; then
installed_version="$(echo "$list" | awk "\$1 == \"$1\" { print \$2;exit; }")"
fi
unamer="$(uname -r | tr '[:upper:]' '[:lower:]')"
if [ -n "${unamer}" ]; then
running_version="$(echo "${list}" | awk "\$1 == \"${unamer}\" { print \$2;exit; }")"
fi
# ignore the currently running version if attempting a reproducible build
if [ -n "${SOURCE_DATE_EPOCH}" ]; then
unamer=""
running_version=""
fi
latest_version="$(echo "${debverlist}" | sed -n 1p)"
previous_version="$(echo "${debverlist}" | sed -n 2p)"
APT=$(get_apt_binary)
debkernels="$(echo "${latest_version}
${installed_version}
${running_version}" | sort -u | sed -e '/^$/ d')"
kernels="$( (echo "$1
${unamer}"; for deb in ${debkernels}; do echo "${list}" | awk "\$2 == \"${deb}\" { print \$1; }"; done; ) \
| sed -e 's#\([\.\+]\)#\\\1#g' -e '/^$/ d' | sort -u|tr '\n' '|' | sed -e 's/|$//')"
list="$("${DPKG}" -l | awk '/^[ih][^nc][ ]+(linux|kfreebsd|gnumach)-image-[0-9]+\./ && $2 !~ /-dbg(:.*)?$/ && $2 !~ /-dbgsym(:.*)?$/ { print $2,$3; }' \
| sed -e 's#^\(linux\|kfreebsd\|gnumach\)-image-##' -e 's#:[^:]\+ # #')"
debverlist="$(echo "${list}" | cut -d' ' -f 2 | sort --unique --reverse --version-sort)"
if [ -n "${specifc_kernel}" ]; then
installed_version="$(echo "$list" | awk "\$1 == \"${specifc_kernel}\" { print \$2;exit; }")"
fi
unamer="$(uname -r | tr '[:upper:]' '[:lower:]')"
if [ -n "${unamer}" ]; then
running_version="$(echo "${list}" | awk "\$1 == \"${unamer}\" { print \$2;exit; }")"
fi
# ignore the currently running version if attempting a reproducible build
if [ -n "${SOURCE_DATE_EPOCH}" ]; then
unamer=""
running_version=""
fi
latest_version="$(echo "${debverlist}" | sed -n 1p)"
previous_version="$(echo "${debverlist}" | sed -n 2p)"
debkernels="$(echo "${latest_version}
${installed_version}
${running_version}" | sort -u | sed -e '/^$/ d')"
kernels="$( (echo "${specifc_kernel}
${unamer}"; for deb in ${debkernels}; do echo "${list}" | awk "\$2 == \"${deb}\" { print \$1; }"; done; ) \
| sed -e 's#\([\.\+]\)#\\\1#g' -e '/^$/ d' | sort -u|tr '\n' '|' | sed -e 's/|$//')"
echo "
List of installed kernel packages:
$list
echo "
List of installed kernel packages:
$list
# Running kernel: ${running_version:-ignored} (${unamer:-ignored})
# Last kernel: ${latest_version}
# Previous kernel: ${previous_version}
# Kernel versions list to keep:
${debkernels}
# Running kernel: ${running_version:-ignored} (${unamer:-ignored})
# Last kernel: ${latest_version}
# Previous kernel: ${previous_version}
# Kernel versions list to keep:
${debkernels}
# Kernel packages (version part) to protect:
${kernels}
"
# Kernel packages (version part) to protect:
${kernels}
"
echo "BEFORE"
dpkg -l | grep linux-image
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-[234]' | grep -v -E "(${kernels})" | xargs --no-run-if-empty ${APT} -o Dir::State::Lists="${listupgrade_state_dir}" -y purge
echo "
AFTER"
dpkg -l | grep linux-image
echo ""
echo "
AFTER"
dpkg -l | grep linux-image
echo ""
}
# Parse options
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
while :; do
case $1 in
-h|-\?|--help)
show_help
exit 0
;;
-V|--version)
show_version
exit 0
;;
--)
# End of all options.
shift
break
;;
-?*|[[:alnum:]]*)
# ignore unknown options
if [ "${QUIET}" != 1 ]; then
printf 'WARN: Unknown option (ignored): %s\n' "$1" >&2
fi
;;
*)
# Default case: If no more options then break out of the loop.
break
;;
esac
shift
done
set -e
main "${@}"

View file

@ -1,8 +1,10 @@
---
elastic_stack_version: "6.x"
elastic_stack_version: "7.x"
logstash_jvm_xms: 256m
logstash_jvm_xmx: 512g
logstash_log_rotate_days: 365
logstash_custom_tmpdir: Null
logstash_default_tmpdir: /var/lib/logstash/tmp
logstash_log_syslog_enabled: True
logstash_config_force: True

View file

@ -0,0 +1,10 @@
---
- name: restart logstash
systemd:
name: logstash
state: restarted
daemon_reload: yes
- name: reload systemd
command: systemctl daemon-reload

View file

@ -24,5 +24,4 @@ galaxy_info:
# NOTE: A tag is limited to a single word comprised of
# alphanumeric characters. Maximum 20 tags per role.
dependencies:
- { role: evolix/java, java_alternative: 'openjdk', java_version: 8 }
dependencies: []

View file

@ -16,3 +16,26 @@
group: root
mode: "0750"
when: is_cron_installed.rc == 0
- name: "Create a system config directory for systemd overrides"
file:
path: /etc/systemd/system/logstash.service.d
state: directory
- name: "disable syslog"
ini_file:
path: /etc/systemd/system/logstash.service.d/override.conf
section: Service
option: "{{ item.option }}"
value: "{{ item.value }}"
owner: root
group: root
mode: "0644"
create: yes
no_extra_spaces: yes
state: "{{ logstash_log_syslog_enabled | bool | ternary('absent','present') }}"
loop:
- { option: "StandardOutput", value: "null" }
- { option: "StandardError", value: "null" }
notify:
- restart logstash

View file

@ -88,7 +88,7 @@
owner: logstash
group: logstash
mode: "0640"
force: yes
force: "{{ logstash_config_force | bool }}"
loop: "{{ query('first_found', templates) }}"
vars:
templates:

View file

@ -19,3 +19,4 @@ lxc_php_container_releases:
php70: "stretch"
php73: "buster"
php74: "bullseye"
php80: "bullseye"

View file

@ -1,4 +1,9 @@
---
- name: Reload php80-fpm
lxc_container:
name: "{{ lxc_php_version }}"
container_command: "systemctl reload php8.0-fpm"
- name: Reload php74-fpm
lxc_container:
name: "{{ lxc_php_version }}"

View file

@ -11,3 +11,13 @@
dest: "/var/lib/lxc/{{ lxc_php_version }}/rootfs/etc/smtpd.conf"
mode: "0644"
notify: "Restart opensmtpd"
when: lxc_php_container_releases[lxc_php_version] in ["jessie", "stretch", "buster"]
- name: "{{ lxc_php_version }} - Configure opensmtpd (in the container)"
template:
src: smtpd.conf.bullseye.j2
dest: "/var/lib/lxc/{{ lxc_php_version }}/rootfs/etc/smtpd.conf"
mode: "0644"
notify: "Restart opensmtpd"
when: not lxc_php_container_releases[lxc_php_version] in ["jessie", "stretch", "buster"]

View file

@ -21,4 +21,7 @@
- include: "php74.yml"
when: lxc_php_version == "php74"
- include: "php80.yml"
when: lxc_php_version == "php80"
- include: "misc.yml"

View file

@ -1,42 +1,5 @@
---
- name: "{{ lxc_php_version }} - Install dependency packages"
lxc_container:
name: "{{ lxc_php_version }}"
container_command: "DEBIAN_FRONTEND=noninteractive apt install -y wget apt-transport-https gnupg"
- name: "{{ lxc_php_version }} - Add sury repo"
lineinfile:
dest: "/var/lib/lxc/{{ lxc_php_version }}/rootfs/etc/apt/sources.list.d/sury.list"
line: "{{ item }}"
state: present
create: yes
mode: "0644"
loop:
- "deb https://packages.sury.org/php/ bullseye main"
- "deb http://pub.evolix.net/ bullseye-php74/"
- name: copy pub.evolix.net GPG key
copy:
src: reg.asc
dest: /var/lib/lxc/{{ lxc_php_version }}/rootfs/etc/apt/trusted.gpg.d/reg.asc
mode: "0644"
owner: root
group: root
- name: copy packages.sury.org GPG Key
copy:
src: sury.gpg
dest: /var/lib/lxc/{{ lxc_php_version }}/rootfs/etc/apt/trusted.gpg.d/sury.gpg
mode: "0644"
owner: root
group: root
- name: "{{ lxc_php_version }} - Update APT cache"
lxc_container:
name: "{{ lxc_php_version }}"
container_command: "DEBIAN_FRONTEND=noninteractive apt update"
- name: "{{ lxc_php_version }} - Install PHP packages"
lxc_container:
name: "{{ lxc_php_version }}"

57
lxc-php/tasks/php80.yml Normal file
View file

@ -0,0 +1,57 @@
---
- name: "{{ lxc_php_version }} - Install dependency packages"
lxc_container:
name: "{{ lxc_php_version }}"
container_command: "DEBIAN_FRONTEND=noninteractive apt install -y wget apt-transport-https gnupg"
- name: "{{ lxc_php_version }} - Add sury repo"
lineinfile:
dest: "/var/lib/lxc/{{ lxc_php_version }}/rootfs/etc/apt/sources.list.d/sury.list"
line: "{{ item }}"
state: present
create: yes
mode: "0644"
loop:
- "deb https://packages.sury.org/php/ bullseye main"
- "deb http://pub.evolix.net/ bullseye-php74/"
- name: copy pub.evolix.net GPG key
copy:
src: reg.asc
dest: /var/lib/lxc/{{ lxc_php_version }}/rootfs/etc/apt/trusted.gpg.d/reg.asc
mode: "0644"
owner: root
group: root
- name: copy packages.sury.org GPG Key
copy:
src: sury.gpg
dest: /var/lib/lxc/{{ lxc_php_version }}/rootfs/etc/apt/trusted.gpg.d/sury.gpg
mode: "0644"
owner: root
group: root
- name: "{{ lxc_php_version }} - Update APT cache"
lxc_container:
name: "{{ lxc_php_version }}"
container_command: "DEBIAN_FRONTEND=noninteractive apt update"
- name: "{{ lxc_php_version }} - Install PHP packages"
lxc_container:
name: "{{ lxc_php_version }}"
container_command: "DEBIAN_FRONTEND=noninteractive apt install -y php-fpm php-cli php-gd php-intl php-imap php-ldap php-mysql php-pgsql php-sqlite3 php-curl php-zip php-mbstring php-zip composer libphp-phpmailer"
- name: "{{ lxc_php_version }} - Copy evolinux PHP configuration"
template:
src: z-evolinux-defaults.ini.j2
dest: "{{ line_item }}"
mode: "0644"
notify: "Reload {{ lxc_php_version }}-fpm"
loop:
- "/var/lib/lxc/{{ lxc_php_version }}/rootfs/etc/php/8.0/fpm/conf.d/z-evolinux-defaults.ini"
- "/var/lib/lxc/{{ lxc_php_version }}/rootfs/etc/php/8.0/cli/conf.d/z-evolinux-defaults.ini"
loop_control:
loop_var: line_item
- include: "mail_opensmtpd.yml"

View file

@ -0,0 +1 @@
{{ansible_fqdn}}

View file

@ -0,0 +1,17 @@
# This is the smtpd server system-wide configuration file.
# See smtpd.conf(5) for more information.
# To accept external mail, replace with: listen on all
#listen on localhost
# If you edit the file, you have to run "smtpctl update table aliases"
table aliases file:/etc/aliases
action "mbox" mbox alias <aliases>
action "relay" relay host "smtp://127.0.0.1"
# Uncomment the following to accept external mail for domain "example.org"
#match from any for domain "example.org" action "mbox"
match for local action "mbox"
match for any action "relay"

View file

@ -8,9 +8,7 @@
path: "/var/lib/lxc/{{ item.name }}/rootfs"
state: directory
mode: '0755'
loop:
- "{{ lxc_containers }}"
loop: "{{ lxc_containers }}"
- include: "solr.yml name={{item.name}} solr_version={{item.solr_version}} solr_port={{item.solr_port}}"
loop:
- "{{ lxc_containers }}"
loop: "{{ lxc_containers }}"

View file

@ -6,19 +6,19 @@
- debootstrap
- xz-utils
- name: python-lxc is installed
- name: python-lxc is installed (Debian <= 10)
apt:
name: python-lxc
state: present
when: ansible_distribution_major_version is version('10', '<=')
when: ansible_python_version is version('3', '<')
- name: python3-lxc is installed
- name: python3-lxc is installed (Debian >= 10)
apt:
name: python3-lxc
state: present
when: ansible_distribution_major_version is version('10', '>')
when: ansible_python_version is version('3', '>=')
- name: Install additional packages on Buster
- name: Install additional packages (Debian >= 10)
apt:
name:
- apparmor
@ -43,6 +43,12 @@
- lxc_unprivilegied_containers | bool
- root_subuids.rc != 0
- name: Check if /var has not mount options nodev or noexec
shell: findmnt | grep -E "/var[^/]" | grep -e nodev -e noexec
register: check_var
changed_when: false
failed_when: "check_var.rc == 0"
- name: Create containers
include: create-container.yml
vars:

View file

@ -1,5 +1,5 @@
---
elastic_stack_version: "6.x"
elastic_stack_version: "7.x"
metricbeat_elasticsearch_hosts:
- "localhost:9200"

View file

@ -6,3 +6,5 @@ mongodb_bind: 127.0.0.1
# Warning: config must not be overwritten by default
# otherwise it can disable important settings, like authorization :/
mongodb_force_config: False
mongodb_version: 4.4

View file

@ -0,0 +1,29 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBGAsKNUBEAClMqPCvvqm6gFmbiorEN9qp00GI8oaECkwbxtGGbqX9sqMSrKe
AB3sGI7kqG2Fl0K+xmmiq1QDjhNgFDA1jjXq+Bd66RNPtvu747IRxVs+9fX7bk67
8Bruha7U3M5l4193x5oYLlbcZL9aC7RSJE2mggTyS6LarmF6vKQN9LMXDicnageV
KCPpF2i3jkZaGnLPzAisW/pOjPQpWCbatTVqKOKvtOyP3Fz1spYd4obu6ELu1PXa
gmhSfvWJYt1irpchOl29LWZfcmXuJszmb00bqm4gLcK12VrnK191iXv46A8h2hSO
f3eQqrkc+pF/kw4RyG54EV7QtHXyTe9TVCbJUfgtliWIQt/bCoJYfPLHJaWIMs83
bzA6ZvOjCKIfMS0CY5ZJyVaBfiI3wURSjgZIYFZAXVwbreQIfOKKuik7UVVn3xUO
nWpmQ2zyI0W7cJMquxwLNjkI+RckPhIqxWFo5iNSV4v6pzrlHD1WmIfFGBKEn7m+
edwVyHG53fNIFZjxyShO6Pf1vgb9Js/XmXB4lxYnNyx1tB+hQhXTjLlY6N5gPpw5
Z/PWQc7vfYekUZGQMXhTyRxU0QTwmdEeKcb+fb9r23OH59bbAfzE10xTMzhqCd2L
lgSozMBvMmkHb1xs1x6FFuv/U/X7LjHTrHIf4M//DNwdP4l4I1jhPlTAxwARAQAB
tDdNb25nb0RCIDUuMCBSZWxlYXNlIFNpZ25pbmcgS2V5IDxwYWNrYWdpbmdAbW9u
Z29kYi5jb20+iQI+BBMBAgAoBQJgLCjVAhsDBQkJZgGABgsJCAcDAgYVCAIJCgsE
FgIDAQIeAQIXgAAKCRCwCgvR4sY8EawdD/0ewkyx3yE99K9n3y7gdvh5+2U8BsqU
7SWEfup7kPpf+4pF5xWqMaciEV/wRAGt7TiKlfVyAv3Q9iNsaLFN+s3kMaIcKhwD
8+q/iGfziIuOSTeo20dAxn9vF6YqrKGc7TbHdXf9AtYuJCfIU5j02uVZiupx+P9+
rG39dEnjOXm3uY0Fv3pRGCpuGubDlWB1DYh0R5O481kDVGoMqBxmc3iTALu14L/u
g+AKxFYfT4DmgdzPVMDhppgywfyd/IOWxoOCl4laEhVjUt5CygBa7w07qdKwWx2w
gTd9U0KGHxnnSmvQYxrRrS5RX3ILPJShivTSZG+rMqnUe6RgCwBrKHCRU1L728Yv
1B3ZFJLxB1TlVT2Hjr+oigp0RY9W1FCIdO2uhb9GImpaJ1Y0ZZqUkt/d9D8U2wcw
SW6/6WYeO7wAi/zlJ25hrBwhxS2+88gM6wJ1yL9yrM9v8JUb7Kq0rCGsEO5kqscV
AmX90wsF2cZ6gHR53eGIDbAJK0MO5RHR73aQ4bpTivPnoTx4HTj5fyhW9z8yCSOe
BlQABoFFqFvOS7KBxoyIS3pxlDetWOSc6yQrvA1CwxnkB81OHNmJfWAbNbEtZkLm
xs2c8CIh2R81yi6HUzAaxyDH7mrThbwX3hUe/wsaD1koV91G6bDD4Xx3zpa9DG/O
HyB98+e983gslg==
=IQQF
-----END PGP PUBLIC KEY BLOCK-----

View file

@ -1,10 +1,5 @@
---
# - fail:
# msg: only compatible with Debian 8
# when:
# - ansible_distribution != "Debian" or ansible_distribution_release != "jessie"
- include: main_jessie.yml
when: ansible_distribution_release == "jessie"

View file

@ -1,9 +1,11 @@
---
- name: Look for legacy apt keyring
stat:
path: /etc/apt/trusted.gpg
register: _trusted_gpg_keyring
- fail:
msg: Not compatible with Debian 11 (Bullseye)
when:
- ansible_distribution_release == "bullseye"
- mongodb_version is version_compare('5.0', '<=')
- name: MongoDB embedded GPG key is absent
apt_key:
@ -14,8 +16,8 @@
- name: Add MongoDB GPG key
copy:
src: server-4.4.asc
dest: /etc/apt/trusted.gpg.d/mongodb-server-4.4.asc
src: "server-{{mongodb_version}}.asc"
dest: "/etc/apt/trusted.gpg.d/mongodb-server-{{mongodb_version}}.asc"
force: yes
mode: "0644"
owner: root
@ -23,9 +25,9 @@
- name: enable APT sources list
apt_repository:
repo: deb http://repo.mongodb.org/apt/debian buster/mongodb-org/4.4 main
repo: "deb http://repo.mongodb.org/apt/debian buster/mongodb-org/{{mongodb_version}} main"
state: present
filename: mongodb-org-4.4
filename: "mongodb-org-{{mongodb_version}}"
update_cache: yes
- name: Install packages
@ -40,30 +42,39 @@
name: mongod
enabled: yes
state: started
when: _mongodb_install_package.changed
when: _mongodb_install_package is changed
- name: install dependency for monitoring
apt:
name: python3-pymongo
name: python-pymongo
state: present
- name: Custom configuration
template:
src: mongodb_bullseye.conf.j2
src: mongodb_buster.conf.j2
dest: "/etc/mongod.conf"
force: "{{ mongodb_force_config | bool | ternary('yes', 'no') }}"
notify: restart mongod
- name: Configure logrotate
template:
src: logrotate_bullseye.j2
src: logrotate_buster.j2
dest: /etc/logrotate.d/mongodb
force: yes
backup: no
- name: Munin plugins local directory exists
- include_role:
name: evolix/remount-usr
- name: Create plugin directory
file:
dest: /usr/local/share/munin/plugins/
name: /usr/local/share/munin/
state: directory
mode: "0755"
- name: Create plugin directory
file:
name: /usr/local/share/munin/plugins/
state: directory
mode: "0755"
@ -72,7 +83,7 @@
src: "munin/{{ item }}"
dest: '/usr/local/share/munin/plugins/{{ item }}'
force: yes
with_items:
loop:
- mongo_btree
- mongo_collections
- mongo_conn
@ -88,7 +99,7 @@
src: '/usr/local/share/munin/plugins/{{ item }}'
dest: /etc/munin/plugins/{{ item }}
state: link
with_items:
loop:
- mongo_btree
- mongo_collections
- mongo_conn

View file

@ -14,8 +14,8 @@
- name: Add MongoDB GPG key
copy:
src: server-4.2.asc
dest: /etc/apt/trusted.gpg.d/mongodb-server-4.2.asc
src: "server-{{mongodb_version}}.asc"
dest: "/etc/apt/trusted.gpg.d/mongodb-server-{{mongodb_version}}.asc"
force: yes
mode: "0644"
owner: root
@ -23,9 +23,9 @@
- name: enable APT sources list
apt_repository:
repo: deb http://repo.mongodb.org/apt/debian buster/mongodb-org/4.2 main
repo: "deb http://repo.mongodb.org/apt/debian buster/mongodb-org/{{mongodb_version}} main"
state: present
filename: mongodb-org-4.2
filename: "mongodb-org-{{mongodb_version}}"
update_cache: yes
- name: Install packages
@ -61,6 +61,9 @@
force: yes
backup: no
- include_role:
name: evolix/remount-usr
- name: Create plugin directory
file:
name: /usr/local/share/munin/

View file

@ -1,4 +1,5 @@
---
- name: restart munin-node
service:
name: munin-node
@ -8,3 +9,7 @@
service:
name: munin_node
state: restarted
- name: systemd daemon-reload
systemd:
daemon_reload: yes

View file

@ -88,3 +88,20 @@
[swap]
user root
when: ansible_kernel is search("-grs-")
- name: Create override directory for munin-node unit
file:
name: /etc/systemd/system/munin-node.service.d/
state: directory
mode: "0755"
- name: Override is present for protected home
ini_file:
dest: "/etc/systemd/system/munin-node.service.d/override.conf"
section: "Service"
option: "ProtectHome"
value: "false"
state: present
notify:
- systemd daemon-reload
- restart munin-node

View file

@ -1,22 +1,24 @@
---
# dependency for mysql_user and mysql_db
- name: python-mysqldb is installed (Ansible dependency)
- name: Python2 dependencies for Ansible are installed
apt:
name: python-mysqldb
name:
- python-mysqldb
- python-pymysql
state: present
when: ansible_distribution_major_version is version('10', '<=')
tags:
- mysql
when: ansible_python_version is version('3', '<')
# dependency for mysql_user and mysql_db
- name: python3-mysqldb is installed (Ansible dependency)
- name: Python3 dependencies for Ansible are installed
apt:
name: python3-mysqldb
name:
- python3-mysqldb
- python3-pymysql
state: present
when: ansible_distribution_major_version is version('10', '>')
tags:
- mysql
when: ansible_python_version is version('3', '>=')
- name: create a password for mysqladmin
command: "apg -n 1 -m 16 -M lcN"

View file

@ -0,0 +1,554 @@
#!/bin/sh
VERSION="21.11"
show_version() {
cat <<END
evomariabackup version ${VERSION}
Copyright 2004-2021 Evolix <info@evolix.fr>,
Éric Morino <emorino@evolix.fr>,
Jérémy Lecour <jlecour@evolix.fr>
and others.
evomariabackup comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
See the GNU Affero General Public License v3.0 for details.
END
}
show_help() {
cat <<EOF
Usage: evomariabackup --backup-dir /path/to/mariabackup-target --compress-file /path/to/compressed.tgz
Options
--backup-dir mariabackup target directory
--compress-file File name for the compressed version
--backup Force backup phase
--no-backup Skip backup phase
--compress Force compress phase
--no-compress Skip compress phase
--log-file Log file to send messages
--verbose Output much more information (to stdout/stderr or the log file)
--quiet Ouput only the most critical information
--lock-file Specify which lock file to use (default: /run/lock/mariabackup.lock)
--max-age Lock file is ignored if older than this (default: 1d)
-h|--help|-? Display help
-V|--version Display version, authors and license
Example usage for a backup then compress :
# /usr/local/bin/evomariabackup --verbose \
--backup-dir /backup/mariabackup/current \
--compress-file /backup/mariabackup/compressed/$(date +%H).tgz \
--log-file /var/log/evomariabackup.log
max-age possible values:
Xd = X days
X or Xh = X hours
Xm = X minutes
Xs = X seconds
EOF
}
log_date() {
date +"%Y-%m-%d %H:%M:%S"
}
is_log_file() {
test -n "${log_file}"
}
is_verbose() {
test "${verbose}" = "1"
}
is_quiet() {
test "${quiet}" = "1"
}
log_line() {
level=$1
msg=$2
printf "[%s] %s: %s\n" "$(log_date)" "${level}" "${msg}"
}
log_debug() {
level="DEBUG"
msg=$1
if ! is_quiet && is_verbose; then
if is_log_file; then
log_line "${level}" "${msg}" >> "${log_file}"
else
log_line "${level}" "${msg}" >&2
fi
fi
}
log_info() {
level="INFO"
msg=$1
if ! is_quiet; then
if is_log_file; then
log_line "${level}" "${msg}" >> "${log_file}"
else
log_line "${level}" "${msg}" >&2
fi
fi
}
log_warning() {
level="WARNING"
msg=$1
if ! is_quiet; then
if is_log_file; then
log_line "${level}" "${msg}" >> "${log_file}"
else
log_line "${level}" "${msg}" >&2
fi
fi
}
log_error() {
level="ERROR"
msg=$1
if ! is_quiet; then
if is_log_file; then
log_line "${level}" "${msg}" >> "${log_file}"
if tty -s; then
printf "%s\n" "${msg}" >&2
fi
else
log_line "${level}" "${msg}" >&2
fi
fi
}
log_fatal() {
level="FATAL"
msg=$1
if is_log_file; then
log_line "${level}" "${msg}" >> "${log_file}"
if tty -s; then
printf "%s\n" "${msg}" >&2
fi
else
log_line "${level}" "${msg}" >&2
fi
}
duration_in_seconds() {
if echo "${1}" | grep -E -q '^([0-9]+[wdhms])+$'; then
duration=$(echo "${1}" | sed 's/w/ * 604800 + /g; s/d/ * 86400 + /g; s/h/ * 3600 + /g; s/m/ * 60 + /g; s/s/ + /g; s/+ $//' | xargs expr)
elif echo "${1}" | grep -E -q '^[0-9]+$'; then
duration=$(echo "${1} * 3600" | xargs expr)
else
return 1
fi
log_debug "Duration \`${1}' translated to ${duration} seconds"
echo "${duration}"
}
lock_file_created_at() {
created_at=$(stat -c %Z "${lock_file}")
log_debug "Lock file ${lock_file} created at ${created_at}"
echo "${created_at}"
}
lock_file_age() {
last_change=$(lock_file_created_at)
now=$(date +"%s")
age=$(( now - last_change ))
log_debug "Lock file ${lock_file} is ${age} seconds old"
echo "${created_at}"
}
is_lock_file_too_old() {
test "$(lock_file_age)" -ge "${max_age}"
}
kill_or_clean_lockfile() {
lock_file=${1:-}
if [ -f "${lock_file}" ]; then
# Get Process ID from the lock file
pid=$(cat "${lock_file}")
if [ -n "${pid}" ]; then
log_debug "Found pid ${pid} in ${lock_file}"
if kill -0 "${pid}" 2> /dev/null; then
log_debug "Found process with pid ${pid}"
lock_file_created_at_human=$(date --date "@$(lock_file_created_at)" +"%Y-%m-%d %H:%M:%S")
if is_lock_file_too_old ; then
# Kill the children
pkill -9 --parent "${pid}"
# Kill the parent
kill -9 "${pid}"
# Only one process can run in parallel
log_warning "Process \`${pid}' (started at ${lock_file_created_at_human}) has been killed by \`$$'"
else
log_info "Process \`${pid}' (started at ${lock_file_created_at_human}) has precedence. Let's leave it work."
# make sure that this exit doesn't remove the existing lockfile !!
exit 0
fi
else
log_warning "Process not found at PID \`${pid}'. Ignoring lock file \`${lock_file}'."
fi
else
log_warning "Empty lockfile \`${lock_file}'. It should contain a PID."
fi
# Remove the lock file
rm -f "${lock_file}"
log_debug "Lock file ${lock_file} has been removed"
fi
}
new_lock_file() {
lock_file=${1:-}
lock_dir=$(dirname "${lock_file}")
if mkdir --parents "${lock_dir}"; then
echo $$ > "${lock_file}"
log_debug "Lock file '${lock_file}' has been created"
else
log_fatal "Failed to acquire lock file '${lock_file}'. Abort."
exit 1
fi
}
is_mariabackup_directory() {
directory=${1:-}
find "${directory}" -name 'ibdata*' -o -name 'ib_logfile*' -o -name 'xtrabackup_*' > /dev/null
}
check_backup_dir() {
if [ -d "${backup_dir:?}" ]; then
if [ "$(ls -A "${backup_dir:?}")" ]; then
if is_mariabackup_directory "${backup_dir:?}"; then
log_debug "The backup directory ${backup_dir:?} is not empty but looks like a mariabackup target. Let's clear it."
rm -rf "${backup_dir:?}"
else
log_fatal "The backup directory ${backup_dir:?} is not empty and doesn't look like a mariabackup target. Please verify and clear the directory if you are sure."
exit 1
fi
else
log_debug "The backup directory ${backup_dir:?} exists but is empty. Let's proceed."
fi
else
log_debug "The backup directory ${backup_dir:?} doesn't exist. Let's proceed."
fi
mkdir -p "${backup_dir:?}"
}
check_compress_dir() {
if [ -d "${compress_dir:?}" ]; then
log_debug "The compress_dir directory ${compress_dir:?} exists. Let's proceed."
else
log_debug "The compress_dir directory ${compress_dir:?} doesn't exist. Let's proceed."
fi
mkdir -p "${compress_dir:?}"
}
backup() {
if [ -z "${backup_dir}" ]; then
log_fatal "backup-dir option is empty"
else
check_backup_dir
fi
mariabackup_bin=$(command -v mariabackup)
if [ -z "${mariabackup_bin}" ]; then
log_fatal "Couldn't find mariabackup.\nUse 'apt install mariadb-backup'."
exit 1
fi
backup_command="${mariabackup_bin} --backup --slave-info --target-dir=${backup_dir:?}"
if ! is_quiet; then
log_debug "${backup_command}"
log_info "BEGIN mariabackup backup phase"
fi
if is_quiet || ! is_verbose ; then
${backup_command} >/dev/null 2>&1
backup_rc=$?
elif ! is_quiet; then
if is_log_file; then
${backup_command} >>"${log_file}" 2>&1
backup_rc=$?
else
${backup_command}
backup_rc=$?
fi
fi
if [ ${backup_rc} -ne 0 ]; then
log_fatal "Error executing mariabackup --backup"
exit 1
elif ! is_quiet; then
log_info "END mariabackup backup phase"
fi
prepare_command="${mariabackup_bin} --prepare --target-dir=${backup_dir:?}"
if ! is_quiet; then
log_debug "${prepare_command}"
log_info "BEGIN mariabackup prepare phase"
fi
if is_quiet || ! is_verbose ; then
${prepare_command} >/dev/null 2>&1
prepare_rc=$?
elif ! is_quiet; then
if is_log_file; then
${prepare_command} >>"${log_file}" 2>&1
prepare_rc=$?
else
${prepare_command}
prepare_rc=$?
fi
fi
if [ ${prepare_rc} -ne 0 ]; then
log_fatal "Error executing mariabackup --prepare"
exit 1
elif ! is_quiet; then
log_info "END mariabackup prepare phase"
fi
}
compress() {
compress_dir=$(dirname "${compress_file}")
if [ -z "${backup_dir}" ]; then
log_fatal "backup-dir option is empty"
exit 1
elif [ -e "${backup_dir}" ] && [ ! -d "${backup_dir}" ]; then
log_fatal "backup directory '${backup_dir}' exists but is not a directory"
exit 1
fi
if [ -z "${compress_file}" ]; then
log_fatal "compress-file option is empty"
exit 1
fi
if [ -n "${compress_dir}" ]; then
check_compress_dir
fi
pigz_bin=$(command -v pigz)
gzip_bin=$(command -v gzip)
if [ -n "${pigz_bin}" ]; then
compress_program="${pigz_bin} --keep -6"
elif [ -n "${gzip_bin}" ]; then
compress_program="${gzip_bin} -6"
else
log_fatal "Couldn't find pigz nor gzip.\nUse 'apt install pigz' or 'apt install gzip'."
exit 1
fi
if ! is_quiet; then
log_debug "Compression of ${backup_dir} to ${compress_file} using \`${compress_program}'"
log_info "BEGIN compression phase"
fi
if is_quiet || ! is_verbose ; then
tar --use-compress-program="${compress_program}" -cf "${compress_file}" "${backup_dir}" >/dev/null 2>&1
tar_rc=$?
elif ! is_quiet; then
if is_log_file; then
tar --use-compress-program="${compress_program}" -cf "${compress_file}" "${backup_dir}" >>"${log_file}" 2>&1
tar_rc=$?
else
tar --use-compress-program="${compress_program}" -cf "${compress_file}" "${backup_dir}"
tar_rc=$?
fi
fi
if [ ${tar_rc} -ne 0 ]; then
log_fatal "An error occured while compressing ${backup_dir} to ${compress_file}"
exit 1
elif ! is_quiet; then
log_info "END compression phase"
fi
}
main() {
kill_or_clean_lockfile "${lock_file}"
# shellcheck disable=SC2064
trap "rm -f ${lock_file};" 0
new_lock_file "${lock_file}"
if [ "${do_backup}" = "1" ] && [ -n "${backup_dir}" ]; then
backup "${backup_dir}"
fi
if [ "${do_compress}" = "1" ] && [ -n "${compress_file}" ]; then
compress "${backup_dir}" "${compress_file}"
fi
}
# Declare variables
lock_file=""
log_file=""
verbose=""
quiet=""
max_age=""
max_age=""
do_backup=""
backup_dir=""
do_compress=""
compress_file=""
# Parse options
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
while :; do
case $1 in
-h|-\?|--help)
show_help
exit 0
;;
-V|--version)
show_version
exit 0
;;
-m|--max-age)
# with value separated by space
if [ -n "$2" ]; then
max_age=$(duration_in_seconds "$2")
shift
else
log_fatal 'ERROR: "-m|--max-age" requires a non-empty option argument.'
fi
;;
--max-age=?*)
# with value speparated by =
max_age=$(duration_in_seconds "${1#*=}")
;;
--max-age=)
# without value
log_fatal 'ERROR: "--max-age" requires a non-empty option argument.'
;;
--backup)
do_backup=1
;;
--no-backup)
do_backup=0
;;
--backup-dir)
# with value separated by space
if [ -n "$2" ]; then
backup_dir="$2"
shift
else
log_fatal 'ERROR: "--backup-dir" requires a non-empty option argument.'
fi
;;
--backup-dir=?*)
# with value speparated by =
backup_dir=${1#*=}
;;
--backup-dir=)
# without value
log_fatal '"--backup-dir" requires a non-empty option argument.'
;;
--compress)
do_compress=1
;;
--no-compress)
do_compress=0
;;
--compress-file)
# with value separated by space
if [ -n "$2" ]; then
compress_file="$2"
if [ -z "${do_compress}" ]; then
do_compress=1
fi
shift
else
log_fatal '"--compress-file" requires a non-empty option argument.'
fi
;;
--compress-file=?*)
# with value speparated by =
compress_file=${1#*=}
if [ -z "${do_compress}" ]; then
do_compress=1
fi
;;
--compress-file=)
# without value
log_fatal '"--compress-file" requires a non-empty option argument.'
;;
--lock-file)
# with value separated by space
if [ -n "$2" ]; then
lock_file="$2"
shift
else
log_fatal '"--lock-file" requires a non-empty option argument.'
fi
;;
--lock-file=?*)
# with value speparated by =
lock_file=${1#*=}
;;
--lock-file=)
# without value
log_fatal '"--lock-file" requires a non-empty option argument.'
;;
--log-file)
# with value separated by space
if [ -n "$2" ]; then
log_file="$2"
shift
else
log_fatal '"--log-file" requires a non-empty option argument.'
fi
;;
--log-file=?*)
# with value speparated by =
log_file=${1#*=}
;;
--log-file=)
# without value
log_fatal '"--log-file" requires a non-empty option argument.'
;;
-v|--verbose)
verbose=1
;;
--quiet)
quiet=1
verbose=0
;;
--)
# End of all options.
shift
break
;;
-?*|[[:alnum:]]*)
# ignore unknown options
if tty -s; then
printf 'Unknown option : %s\n' "$1" >&2
echo "" >&2
show_usage >&2
exit 1
else
log_fatal 'Unknown option : %s\n' "$1" >&2
fi
;;
*)
# Default case: If no more options then break out of the loop.
break
;;
esac
shift
done
# Default values
lock_file="${lock_file:-/run/lock/evomariabackup.lock}"
verbose=${verbose:-0}
quiet=${quiet:-0}
max_age="${max_age:-86400}"
do_backup="${do_backup:-1}"
do_compress="${do_compress:-0}"
main

View file

@ -0,0 +1,197 @@
#!/bin/sh
VERSION="21.08"
show_version() {
cat <<END
mysql-queries-killer version ${VERSION}
Copyright 2018-2021 Evolix <info@evolix.fr>,
Jérémy Lecour <jlecour@evolix.fr>
and others.
mysql-queries-killer comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
See the GNU General Public Licence for details.
END
}
show_help() {
cat <<END
mysql-queries-killer can list/kill SQL queries
END
show_usage
}
show_usage() {
cat <<END
Usage: mysql-queries-killer [--instance <instance>] --list [--time <time>]
or mysql-queries-killer [--instance <instance>] --kill [--time <time>]
Options
--instance MySQL instance name (see below)
--time query busy time, in seconds (default: 600)
--list list matching queries (default action)
--kill kill connexions related to matching queries
--help Print this message and exit
--version Print version and exit
If an instance parameter is provided, pt-kill will look for a configuration
file at ~/.pt-kill.<instance>.cnf
If no instance parameter is provided, pt-kill will use the conventional
configuration files.
END
}
error() {
>&2 echo "mysql-queries-killer: $1"
exit
}
kill_connexions() {
cmd="${PTKILL_BIN}"
if [ -n "${config_file}" ]; then
cmd="${cmd} --config ${config_file}"
fi
cmd="${cmd} --busy-time ${time} --run-time 1 --interval 1 --victims all --print --kill"
${cmd}
}
list_queries() {
cmd="${PTKILL_BIN}"
if [ -n "${config_file}" ]; then
cmd="${cmd} --config ${config_file}"
fi
cmd="${cmd} --busy-time ${time} --run-time 1 --interval 1 --victims all --print"
${cmd}
}
set_config_file() {
config_file=""
if [ -n "${instance}" ]; then
file="${HOME}/.pt-kill.${instance}.cnf"
if [ ! -f "${file}" ]; then
error "The config file \`${file}' doesn't exist." 2
else
config_file="${file}"
fi
fi
}
main() {
case ${action} in
kill)
kill_connexions
;;
list)
list_queries
;;
*)
list_queries
;;
esac
}
if command -v pt-kill >/dev/null; then
PTKILL_BIN=$(command -v pt-kill)
else
error "The command \`pt-kill' couldn't be found. It is available in the \`percona-toolkit' package." 1
fi
# Parse options
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
while :; do
case $1 in
-h|-\?|--help)
show_help
exit 0
;;
-V|--version)
show_version
exit 0
;;
--kill)
action="kill"
;;
--list)
action="list"
;;
--instance)
# with value separated by space
if [ -n "$2" ]; then
instance=$2
shift
else
printf 'ERROR: "--instance" requires a non-empty option argument.\n' >&2
exit 1
fi
;;
--instance=?*)
# with value speparated by =
instance=${1#*=}
;;
--instance=)
# without value
printf 'ERROR: "--instance" requires a non-empty option argument.\n' >&2
exit 1
;;
--time)
# with value separated by space
if [ -n "$2" ]; then
time=$2
shift
else
printf 'ERROR: "--time" requires a non-empty option argument.\n' >&2
exit 1
fi
;;
--time=?*)
# with value speparated by =
time=${1#*=}
;;
--time=)
# without value
printf 'ERROR: "--time" requires a non-empty option argument.\n' >&2
exit 1
;;
--)
# End of all options.
shift
break
;;
-?*|[[:alnum:]]*)
# ignore unknown options
printf 'ERROR: Unknown option : %s\n' "$1" >&2
echo "" >&2
show_usage >&2
exit 1
;;
*)
# Default case: If no more options then break out of the loop.
break
;;
esac
shift
done
# Initial values
action=${action:-}
time=${time:-"600"}
instance=${instance:-""}
set_config_file
set -u
set -e
main
exit 0

View file

@ -10,8 +10,15 @@
- include: packages_jessie.yml
when: ansible_distribution_release == "jessie"
## There is nothing to do with users on Debian 11 - yet we need a /root/.my.cnf for compatibility
- include: users_bullseye.yml
when: ansible_distribution_release == "bullseye"
- include: users_buster.yml
when: ansible_distribution_release == "buster"
- include: users_stretch.yml
when: ansible_distribution_major_version is version('9', '>=')
when: ansible_distribution_release == "stretch"
- include: users_jessie.yml
when: ansible_distribution_release == "jessie"

View file

@ -10,12 +10,20 @@
- munin
- block:
- name: Install perl libraries for Munin
- name: "Install perl libraries for Munin (Debian < 11)"
apt:
name:
- libdbd-mysql-perl
- libcache-cache-perl
state: present
when: ansible_distribution_major_version is version('11', '<')
- name: "Install perl libraries for Munin (Debian >= 11)"
apt:
name:
- libcache-cache-perl
- libdbd-mariadb-perl
when: ansible_distribution_major_version is version('11', '>=')
- name: Enable core Munin plugins
file:
@ -55,6 +63,7 @@
- sorts
- table_locks
- tmp_tables
- replication
notify: restart munin-node
- name: verify Munin configuration for mysql

View file

@ -50,3 +50,11 @@
tags:
- mysql
- packages
- name: Python dependencies for Ansible are installed
apt:
name: python-mysqldb
state: present
tags:
- mysql
- packages

View file

@ -36,3 +36,25 @@
tags:
- mysql
- packages
- name: Python2 dependencies for Ansible are installed
apt:
name:
- python-mysqldb
- python-pymysql
state: present
tags:
- mysql
- packages
when: ansible_python_version is version('3', '<')
- name: Python3 dependencies for Ansible are installed
apt:
name:
- python3-mysqldb
- python3-pymysql
state: present
tags:
- mysql
- packages
when: ansible_python_version is version('3', '>=')

View file

@ -0,0 +1,15 @@
---
- name: Populate the .my.cnf of root with default user
ini_file:
dest: /root/.my.cnf
mode: "0600"
section: client
option: '{{ item.option }}'
value: '{{ item.value }}'
create: yes
loop:
- { option: 'user', value: 'root' }
- { option: 'socket', value: '/run/mysqld/mysqld.sock' }
tags:
- mysql

View file

@ -0,0 +1,83 @@
---
- name: create a password for mysqladmin
command: "apg -n 1 -m 16 -M lcN"
register: mysql_admin_password
changed_when: False
check_mode: False
tags:
- mysql
- name: there is a mysqladmin user
mysql_user:
name: mysqladmin
password: '{{ mysql_admin_password.stdout }}'
priv: "*.*:ALL,GRANT"
update_password: on_create
state: present
config_file: "/etc/mysql/debian.cnf"
register: create_mysqladmin_user
tags:
- mysql
- name: mysqladmin is the default user
ini_file:
dest: /root/.my.cnf
mode: "0600"
section: client
option: '{{ item.option }}'
value: '{{ item.value }}'
create: yes
loop:
- { option: 'user', value: 'mysqladmin' }
- { option: 'password', value: '{{ mysql_admin_password.stdout }}' }
when: create_mysqladmin_user is changed
tags:
- mysql
- name: create a password for debian-sys-maint
command: "apg -n 1 -m 16 -M lcN"
register: mysql_debian_password
changed_when: False
check_mode: False
tags:
- mysql
- name: there is a debian-sys-maint user
mysql_user:
name: debian-sys-maint
password: '{{ mysql_debian_password.stdout }}'
priv: "*.*:ALL,GRANT"
update_password: on_create
state: present
config_file: "/root/.my.cnf"
register: create_debian_user
tags:
- mysql
- name: store debian-sys-maint user credentials
ini_file:
dest: /etc/mysql/debian.cnf
mode: "0600"
section: "{{ item[0] }}"
option: '{{ item[1].option }}'
value: '{{ item[1].value }}'
create: yes
loop: "{{ _sections | product(_credentials) | list }}"
vars:
_sections: [ 'client', 'mysql_upgrade' ]
_credentials:
- { option: 'user', value: 'debian-sys-maint' }
- { option: 'password', value: '{{ mysql_debian_password.stdout }}' }
when: create_debian_user is changed
tags:
- mysql
- name: root user is absent
mysql_user:
name: root
host_all: yes
config_file: "/root/.my.cnf"
state: absent
tags:
- mysql

View file

@ -5,31 +5,13 @@
msg: "We can't create other users with 'debian-sys-maint' on Debian 8 with MariaDB.\nWe must give it the GRANT privilege before continuing."
when: mysql_variant == "mariadb"
# dependency for mysql_user and mysql_db
- name: python-mysqldb is installed (Ansible dependency)
apt:
name: python-mysqldb
state: present
when: ansible_distribution_major_version is version('10', '<=')
tags:
- mysql
# dependency for mysql_user and mysql_db
- name: python3-mysqldb is installed (Ansible dependency)
apt:
name: python3-mysqldb
state: present
when: ansible_distribution_major_version is version('10', '>')
tags:
- mysql
- name: create a password for mysqladmin
command: "apg -n 1 -m 16 -M lcN"
register: mysql_admin_password
changed_when: False
check_mode: no
tags:
- mysql
- mysql
- name: there is a mysqladmin user
mysql_user:
@ -41,7 +23,7 @@
config_file: "/etc/mysql/debian.cnf"
register: create_mysqladmin_user
tags:
- mysql
- mysql
- name: mysqladmin is the default user
ini_file:
@ -56,13 +38,13 @@
- { option: 'password', value: '{{ mysql_admin_password.stdout }}' }
when: create_mysqladmin_user is changed
tags:
- mysql
- mysql
- name: remove root user
- name: root user is absent
mysql_user:
name: root
host_all: yes
config_file: "/root/.my.cnf"
state: absent
tags:
- mysql
- mysql

View file

@ -1,30 +1,12 @@
---
# dependency for mysql_user and mysql_db
- name: python-mysqldb is installed (Ansible dependency)
apt:
name: python-mysqldb
state: present
when: ansible_distribution_major_version is version('10', '<=')
tags:
- mysql
# dependency for mysql_user and mysql_db
- name: python3-mysqldb is installed (Ansible dependency)
apt:
name: python3-mysqldb
state: present
when: ansible_distribution_major_version is version('10', '>')
tags:
- mysql
- name: create a password for mysqladmin
command: "apg -n 1 -m 16 -M lcN"
register: mysql_admin_password
changed_when: False
check_mode: False
tags:
- mysql
- mysql
- name: there is a mysqladmin user
mysql_user:
@ -36,7 +18,7 @@
config_file: "/etc/mysql/debian.cnf"
register: create_mysqladmin_user
tags:
- mysql
- mysql
- name: mysqladmin is the default user
ini_file:
@ -51,8 +33,7 @@
- { option: 'password', value: '{{ mysql_admin_password.stdout }}' }
when: create_mysqladmin_user is changed
tags:
- mysql
- mysql
- name: create a password for debian-sys-maint
command: "apg -n 1 -m 16 -M lcN"
@ -60,7 +41,7 @@
changed_when: False
check_mode: False
tags:
- mysql
- mysql
- name: there is a debian-sys-maint user
mysql_user:
@ -92,7 +73,7 @@
tags:
- mysql
- name: remove root user
- name: root user is absent
mysql_user:
name: root
host_all: yes

View file

@ -49,17 +49,19 @@
- mariadb-client-10.5
- libconfig-inifiles-perl
- libterm-readkey-perl
- libdbd-mariadb-perl
when: ansible_distribution_major_version is version('11', '>=')
- name: Read debian-sys-maint password
- name: Read debian-sys-maint password (Debian < 11)
shell: 'cat /etc/mysql/debian.cnf | grep -m1 "password = .*" | cut -d" " -f3'
register: mysql_debian_password
changed_when: False
check_mode: no
tags:
- mysql
when: ansible_distribution_major_version is version('11', '<')
- name: Configure mytop
- name: Configure mytop (Debian < 11)
template:
src: mytop.j2
dest: /root/.mytop
@ -68,6 +70,18 @@
tags:
- mytop
- mysql
when: ansible_distribution_major_version is version('11', '<')
- name: Configure mytop (Debian >= 11)
template:
src: mytop.bullseye.j2
dest: /root/.mytop
mode: "0600"
force: yes
tags:
- mytop
- mysql
when: ansible_distribution_major_version is version('11', '>=')
# mysqltuner
@ -208,3 +222,21 @@
force: no
tags:
- mysql
- name: "Install mysql-queries-killer.sh"
copy:
src: mysql-queries-killer.sh
dest: "{{ _mysql_scripts_dir }}/mysql-queries-killer.sh"
mode: "0755"
force: no
tags:
- mysql
- name: "Install evomariabackup"
copy:
src: evomariabackup.sh
dest: "{{ _mysql_scripts_dir }}/evomariabackup"
mode: "0755"
force: no
tags:
- mysql

View file

@ -0,0 +1,3 @@
user = root
socket = /var/run/mysqld/mysqld.sock
db = mysql

View file

@ -0,0 +1,213 @@
#!/bin/bash
### WARNING #######################################
# THIS IS A WORK IN PROGRESS AND IT IS NOT USABLE #
###################################################
VERSION="21.04"
readonly VERSION
# base functions
show_version() {
cat <<END
check_async version ${VERSION}
Copyright 2018-2021 Evolix <info@evolix.fr>,
Jérémy Lecour <jlecour@evolix.fr>
and others.
check_async comes with ABSOLUTELY NO WARRANTY.This is free software,
and you are welcome to redistribute it under certain conditions.
See the GNU General Public License v3.0 for details.
END
}
show_help() {
cat <<END
check_async is supposed to wrap an NRPE command and overrides the return code.
Usage: check_async --max-age=1d --name=check_name
or check_async --name=check_name
Options
-m, --max-age max age of the "check file" ;
can be "1d" for 1 day, "5m" for 5 minutes…
or more complex expressions like "1w2d10m42s"
-n, --name check name
-h, --help print this message and exit
-V, --version print version and exit
END
}
time_in_seconds() {
if echo "${1}" | grep -E -q '^([0-9]+[wdhms])+$'; then
echo "${1}" | sed 's/w/ * 604800 + /g; s/d/ * 86400 + /g; s/h/ * 3600 + /g; s/m/ * 60 + /g; s/s/ + /g; s/+ $//' | xargs expr
elif echo "${1}" | grep -E -q '^([0-9]+$)'; then
echo "${1} * 3600" | xargs expr
else
return 1
fi
}
delay_from_check_file() {
last_change=$(stat -c %Z "${check_file}")
limit_seconds=$(time_in_seconds "${wrapper_limit}" || time_in_seconds "${wrapper_limit_default}")
limit_date=$(date --date "${limit_seconds} seconds ago" +"%s")
echo $(( last_change - limit_date ))
}
enable_check() {
if [ "$(id -u)" -eq "0" ] ; then
/usr/share/scripts/alerts_switch enable "${check_name}"
else
sudo /usr/share/scripts/alerts_switch enable "${check_name}"
fi
}
main() {
${check_command} > "${check_stdout}"
check_rc=$?
readonly check_rc
delay=0
if [ -e "${check_file}" ]; then
delay=$(delay_from_check_file)
if [ "${delay}" -le "0" ]; then
enable_check
fi
fi
if [ -e "${check_file}" ]; then
formatted_last_change=$(date --date "@$(stat -c %Z "${check_file}")" +'%c')
readonly formatted_last_change
echo "ALERTS DISABLED for ${check_name} (since ${formatted_last_change}, delay: ${delay} sec) - $(cat "${check_stdout}")"
if [ ${check_rc} = 0 ]; then
# Nagios OK
exit 0
else
# Nagios WARNING
exit 1
fi
else
cat "${check_stdout}"
exit ${check_rc}
fi
}
# Default: 1 day before re-enabling the check
wrapper_limit_default="1d"
readonly wrapper_limit_default
if [[ "${1}" =~ -.* ]]; then
# parse options
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
while :; do
case $1 in
-h|-\?|--help)
show_help
exit 0
;;
-V|--version)
show_version
exit 0
;;
--limit)
# with value separated by space
if [ -n "$2" ]; then
wrapper_limit=$2
shift
else
printf 'ERROR: "--limit" requires a non-empty option argument.\n' >&2
exit 1
fi
;;
--limit=?*)
# with value speparated by =
wrapper_limit=${1#*=}
;;
--limit=)
# without value
printf 'ERROR: "--limit" requires a non-empty option argument.\n' >&2
exit 1
;;
--name)
# with value separated by space
if [ -n "$2" ]; then
check_name=$2
shift
else
printf 'ERROR: "--name" requires a non-empty option argument.\n' >&2
exit 1
fi
;;
--name=?*)
# with value speparated by =
check_name=${1#*=}
;;
--name=)
# without value
printf 'ERROR: "--name" requires a non-empty option argument.\n' >&2
exit 1
;;
--)
# End of all options.
shift
break
;;
-?*)
# ignore unknown options
printf 'WARN: Unknown option : %s\n' "$1" >&2
exit 1
;;
*)
# Default case: If no more options then break out of the loop.
break
;;
esac
shift
done
# The rest is the command
check_command="$*"
else
# no option is passed (backward compatibility with previous version)
# treat the first argument as check_name and the rest as the command
check_name="${1}"
shift
check_command="$*"
fi
# Default values or errors
if [ -z "${wrapper_limit}" ]; then
wrapper_limit="${wrapper_limit_default}"
fi
if [ -z "${check_name}" ]; then
printf 'ERROR: You must specify a check name, with --name.\n' >&2
exit 1
fi
if [ -z "${check_command}" ]; then
printf 'ERROR: You must specify a command to execute.\n' >&2
exit 1
fi
readonly check_name
readonly check_command
readonly wrapper_limit
check_file="/var/lib/misc/${check_name}_alerts_disabled"
readonly check_file
check_stdout=$(mktemp --tmpdir=/tmp "${check_name}_stdout.XXXX")
readonly check_stdout
# shellcheck disable=SC2064
trap "rm ${check_stdout}" EXIT
main

View file

@ -1,12 +1,12 @@
#!/bin/sh
# Check if nfs server is running using rpcinfo
rpcinfo -u localhost nfs
rpcinfo -T udp localhost nfs 3
if [ $? -ne 0 ]; then
exit 2
fi
rpcinfo -t localhost nfs
rpcinfo -T tcp localhost nfs
if [ $? -ne 0 ]; then
exit 2
fi

View file

@ -33,7 +33,11 @@ for pool_file in $POOL_FILES; do
pool_name=$(grep "^\[" "$pool_file" | sed -E 's/^\[(.*)\].*$/\1/g')
pool_status_path=$(grep -E "^pm.status_path\s?=" "$pool_file" | sed -E "s/.*=\s?'?([^']*)'?\s?$/\1/g")
pool_listen=$(grep -E "^listen\s?=" "$pool_file" | sed -E 's/.*=\s?(.*)\s?$/\1/g')
pool_max_children=$(grep -E "^pm.max_children" "$pool_file" | sed -E 's/.*=\s?(.*)\s?$/\1/g' )
pool_crit_procs=$(expr $pool_max_children \* 85 / 100)
pool_warn_procs=$(expr $pool_max_children \* 55 / 100)
if [[ "$pool_status_path" == '' ]]; then
nb_unchk=$((nb_unchk + 1))
output="${output}UNCHK - ${pool_name} (missing pm.status_path definition)\n"
@ -47,7 +51,7 @@ for pool_file in $POOL_FILES; do
target=(-H "$(echo "$pool_listen" | cut -d':' -f1)" -p "$(echo "$pool_listen" | cut -d':' -f2 )")
fi
result=$(perl /usr/local/lib/nagios/plugins/check_phpfpm_status.pl "${target[@]}" -u "$pool_status_path")
result=$(perl /usr/local/lib/nagios/plugins/check_phpfpm_status.pl -t 5 "${target[@]}" -u "$pool_status_path" -c "$pool_crit_procs" -w "$pool_warn_procs" )
ret="${?}"
if [ "${ret}" -ge 2 ]; then
@ -80,3 +84,4 @@ printf "%b" "${output}" | grep -E "OK"
printf "%b" "${output}" | grep -E "^UNCHK"
exit "${return}"

View file

@ -38,6 +38,8 @@ my $o_user= undef; # user for auth
my $o_pass= ''; # password for auth
my $o_realm= ''; # password for auth
my $o_version= undef; # print version
my $o_warn_a_level= -1; # Max number of active workers that will cause a warning
my $o_crit_a_level= -1; # Max number of active workers that will cause an error
my $o_warn_p_level= -1; # Min number of idle workers that will cause a warning
my $o_crit_p_level= -1; # Min number of idle workersthat will cause an error
my $o_warn_q_level= -1; # Number of Max Queue Reached that will cause a warning
@ -130,17 +132,19 @@ sub help {
-X, --cacert
Full path to the cacert.pem certificate authority used to verify ssl certificates (use with --verifyssl).
if not given the cacert from Mozilla::CA cpan plugin will be used.
-w, --warn=MIN_AVAILABLE_PROCESSES,PROC_MAX_REACHED,QUEUE_MAX_REACHED
-w, --warn=MAX_ACTIVE_PROCESSES,MIN_AVAILABLE_PROCESSES,PROC_MAX_REACHED,QUEUE_MAX_REACHED
number of available workers, or max states reached that will cause a warning
-1 for no warning
-c, --critical=MIN_AVAILABLE_PROCESSES,PROC_MAX_REACHED,QUEUE_MAX_REACHED
-c, --critical=MAX_ACTIVE_PROCESSES,MIN_AVAILABLE_PROCESSES,PROC_MAX_REACHED,QUEUE_MAX_REACHED
number of available workers, or max states reached that will cause an error
-1 for no CRITICAL
-V, --version
prints version number
Note :
3 items can be managed on this check, this is why -w and -c parameters are using 3 values thresholds
4 items can be managed on this check, this is why -w and -c parameters are using 3 values thresholds
- MAX_ACTIVE_PROCESSES: Working with the number of available (Idle) and working processes (Busy).
Generating WARNING and CRITICAL if you do have too many Active processes.
- MIN_AVAILABLE_PROCESSES: Working with the number of available (Idle) and working processes (Busy).
Generating WARNING and CRITICAL if you do not have enough Idle processes.
- PROC_MAX_REACHED: the fpm-status report will show us how many times the max processes were reached since start,
@ -231,12 +235,12 @@ sub check_options {
};
if (defined($o_warn_threshold)) {
($o_warn_p_level,$o_warn_m_level,$o_warn_q_level) = split(',', $o_warn_threshold);
($o_warn_a_level,$o_warn_p_level,$o_warn_m_level,$o_warn_q_level) = split(',', $o_warn_threshold);
} else {
$o_warn_threshold = 'undefined'
}
if (defined($o_crit_threshold)) {
($o_crit_p_level,$o_crit_m_level,$o_crit_q_level) = split(',', $o_crit_threshold);
($o_crit_a_level,$o_crit_p_level,$o_crit_m_level,$o_crit_q_level) = split(',', $o_crit_threshold);
} else {
$o_crit_threshold = 'undefined'
}
@ -247,20 +251,24 @@ sub check_options {
$o_fastcgi = 1;
}
if (defined($o_debug)) {
print("\nDEBUG thresholds: \nWarning: ($o_warn_threshold) => Min Idle: $o_warn_p_level Max Reached :$o_warn_m_level MaxQueue: $o_warn_q_level");
print("\nCritical ($o_crit_threshold) => : Min Idle: $o_crit_p_level Max Reached: $o_crit_m_level MaxQueue : $o_crit_q_level\n");
print("\nDEBUG thresholds: \nWarning: ($o_warn_threshold) => Max Active: $o_warn_a_level Min Idle: $o_warn_p_level Max Reached :$o_warn_m_level MaxQueue: $o_warn_q_level");
print("\nCritical ($o_crit_threshold) => Max Active: $o_crit_a_level Min Idle: $o_crit_p_level Max Reached: $o_crit_m_level MaxQueue : $o_crit_q_level\n");
}
if ((defined($o_warn_a_level) && defined($o_crit_a_level)) &&
(($o_warn_a_level != -1) && ($o_crit_a_level != -1) && ($o_warn_a_level <= $o_crit_p_level)) ) {
nagios_exit($phpfpm,"UNKNOWN","Check warning and critical values for ActiveProcess (1st part of threshold), warning level must be > crit level!");
}
if ((defined($o_warn_p_level) && defined($o_crit_p_level)) &&
(($o_warn_p_level != -1) && ($o_crit_p_level != -1) && ($o_warn_p_level <= $o_crit_p_level)) ) {
nagios_exit($phpfpm,"UNKNOWN","Check warning and critical values for IdleProcesses (1st part of threshold), warning level must be > crit level!");
nagios_exit($phpfpm,"UNKNOWN","Check warning and critical values for IdleProcesses (2nd part of threshold), warning level must be > crit level!");
}
if ((defined($o_warn_m_level) && defined($o_crit_m_level)) &&
(($o_warn_m_level != -1) && ($o_crit_m_level != -1) && ($o_warn_m_level >= $o_crit_m_level)) ) {
nagios_exit($phpfpm,"UNKNOWN","Check warning and critical values for MaxProcesses (2nd part of threshold), warning level must be < crit level!");
nagios_exit($phpfpm,"UNKNOWN","Check warning and critical values for MaxProcesses (3rd part of threshold), warning level must be < crit level!");
}
if ((defined($o_warn_q_level) && defined($o_crit_q_level)) &&
(($o_warn_q_level != -1) && ($o_crit_q_level != -1) && ($o_warn_q_level >= $o_crit_q_level)) ) {
nagios_exit($phpfpm,"UNKNOWN","Check warning and critical values for MaxQueue (3rd part of threshold), warning level must be < crit level!");
nagios_exit($phpfpm,"UNKNOWN","Check warning and critical values for MaxQueue (4th part of threshold), warning level must be < crit level!");
}
# Check compulsory attributes
if (!defined($o_host)) {
@ -654,6 +662,9 @@ if ($response->is_success) {
if (defined($o_crit_p_level) && (-1!=$o_crit_p_level) && ($IdleProcesses <= $o_crit_p_level)) {
nagios_exit($phpfpm,"CRITICAL", "Idle workers are critically low " . $InfoData,$PerfData);
}
if (defined($o_crit_a_level) && (-1!=$o_crit_a_level) && ($ActiveProcesses >= $o_crit_a_level)) {
nagios_exit($phpfpm,"CRITICAL", "Active workers are critically high " . $InfoData,$PerfData);
}
# Then WARNING exits by priority
if (defined($o_warn_q_level) && (-1!=$o_warn_q_level) && ($MaxListenQueueNew >= $o_warn_q_level)) {
nagios_exit($phpfpm,"WARNING", "Max queue reached is high " . $InfoData,$PerfData);
@ -664,6 +675,9 @@ if ($response->is_success) {
if (defined($o_warn_p_level) && (-1!=$o_warn_p_level) && ($IdleProcesses <= $o_warn_p_level)) {
nagios_exit($phpfpm,"WARNING", "Idle workers are low " . $InfoData,$PerfData);
}
if (defined($o_warn_a_level) && (-1!=$o_warn_a_level) && ($ActiveProcesses >= $o_warn_a_level)) {
nagios_exit($phpfpm,"WARNING", "Active workers are high " . $InfoData,$PerfData);
}
nagios_exit($phpfpm,"OK",$InfoData,$PerfData);
@ -733,3 +747,5 @@ sub header() {
}
return 0;
}

Some files were not shown because too many files have changed in this diff Show more