Compare commits
66 commits
Author | SHA1 | Date | |
---|---|---|---|
Jérémy Lecour | 145b279a12 | ||
Jérémy Lecour | 6ee1e609ac | ||
Jérémy Lecour | 2ad2ae8521 | ||
Jérémy Lecour | e3746d18fb | ||
Jérémy Lecour | 1d5415237c | ||
Jérémy Lecour | e5bbb601d3 | ||
Mathieu Trossevin | 4c2548b21d | ||
Ludovic Poujol | 5d11468327 | ||
Ludovic Poujol | a41e78b556 | ||
Jérémy Lecour | 8cd887ee21 | ||
Jérémy Lecour | 42ad242aaf | ||
Jérémy Lecour | f8e92d2eeb | ||
Jérémy Lecour | 9a65312190 | ||
Jérémy Dubois | 16394060c9 | ||
Jérémy Dubois | f4e6aabe8a | ||
0ec343766d | |||
d1410e38a1 | |||
mgauthier | 7272106bce | ||
d11cf4987b | |||
Jérémy Lecour | 2a264dd2bc | ||
5708e7205d | |||
4bbe2f4f72 | |||
Jérémy Lecour | 7a9be8d6fa | ||
5acb1956f5 | |||
96504b1deb | |||
56eef89084 | |||
b30b7c884a | |||
fe66ad9c4f | |||
96c1017b5d | |||
23f4f9690f | |||
Jérémy Lecour | d758afdd4b | ||
Ludovic Poujol | ae2e447bc4 | ||
8e3724d5e7 | |||
ff19df2444 | |||
eda69725d5 | |||
bc9609ce48 | |||
Ludovic Poujol | aca146adbc | ||
ccff3b2105 | |||
2fe0d25277 | |||
Jérémy Lecour | 501f5e7577 | ||
8b68f03910 | |||
Jérémy Lecour | 78326e43e8 | ||
Jérémy Lecour | 2a856d579e | ||
Jérémy Lecour | beea53aa64 | ||
Jérémy Lecour | 342380876a | ||
Jérémy Lecour | 24cbbf2f54 | ||
Jérémy Lecour | 56237bb3c6 | ||
Jérémy Lecour | abd329b9c1 | ||
Jérémy Lecour | 037ec9d376 | ||
Jérémy Lecour | c333970606 | ||
Jérémy Lecour | 10b507adc4 | ||
Jérémy Lecour | b2e22413bc | ||
bec868009c | |||
aea710cb25 | |||
Ludovic Poujol | b0ba70f06c | ||
Jérémy Dubois | 0a4a220bdf | ||
Jérémy Lecour | 282dcb28f4 | ||
a0fc763a0c | |||
a56e8c27ee | |||
Jérémy Lecour | 56db6e1fbc | ||
Jérémy Lecour | 015cac688e | ||
Jérémy Lecour | c12c581f63 | ||
7c2fd5e394 | |||
Jérémy Lecour | 9402458304 | ||
Jérémy Lecour | cf0fab1e22 | ||
Jérémy Lecour | 13284645de |
75
CHANGELOG.md
75
CHANGELOG.md
|
@ -6,8 +6,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
|
|||
|
||||
This project does not follow semantic versioning.
|
||||
The **major** part of the version is the year
|
||||
The **minor** part changes is the month
|
||||
The **patch** part changes is incremented if multiple releases happen the same month
|
||||
The **minor** part is the month
|
||||
The **patch** part is incremented if multiple releases happen the same month
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
|
@ -21,6 +21,76 @@ The **patch** part changes is incremented if multiple releases happen the same m
|
|||
|
||||
### Security
|
||||
|
||||
## [24.04] 2024-04-30
|
||||
|
||||
### Added
|
||||
|
||||
proftpd: optional configuration of IP whitelists per groups of users
|
||||
|
||||
### Changed
|
||||
|
||||
* autosysadmin-agent: upstream release 24.03.2
|
||||
* evobackup-client: replace non-functional role with install tasks
|
||||
* evobackup-client: upstream release 24.04.1
|
||||
* evolinux-base: Add new variable to disable global customisation of bash config
|
||||
* evolinux-base: Disable logcheck monitoring of journald only if journald.logfiles exists
|
||||
* evolinux-users: Add sudo mvcli for nagios user
|
||||
* haproxy: support bookworm for backport packages
|
||||
* nrpe: !disk1 exclude filesystem type overlay
|
||||
* postfix/amavis: max servers is now 3 (previously 2)
|
||||
* roundcube: Use /var/log/roundcube directly
|
||||
* vrrpd: configure and restart minifirewall before starting VRRP
|
||||
* vrrpd: configure minifirewall with blocks instead of lines
|
||||
|
||||
### Fixed
|
||||
|
||||
* certbot: Fix HAPEE renewal hook
|
||||
* certbot: Fix HAProxy renewal hook
|
||||
* evolinux-base/logcheck: fix conf patch, journal check was not disabled when asked
|
||||
* fail2ban: SQLite purge script didn't vacuum as expected + error when vacuum cannot be done
|
||||
* keepalived: Fix tasks that use file instead of copy
|
||||
* memcached: Fix conditions not properly writen (installation was always in multi-instance mode)
|
||||
* nagios-nrpe: create /etc/bash_completion.d if missing
|
||||
* openvpn: install packages manually, because openbsd_pkg module is broken since OpenBSD 7.4 with the version of Ansible we currently use
|
||||
* packweb: fix old bug (2017!) .orig file created by module patch and taken in account by ProFTPd
|
||||
* redis: replace inline argument with environment variable for the password
|
||||
|
||||
### Removed
|
||||
|
||||
* docker-host: Removed `docker_conf_use_iptables` variable (iptable usage forced to true)
|
||||
|
||||
## [24.03] 2024-03-01
|
||||
|
||||
### Added
|
||||
|
||||
* autosysadmin-agent: upstream release 24.03
|
||||
* autosysadmin-restart_nrpe: add role
|
||||
* certbot: Renewal hook for NRPE
|
||||
* kvm-host: add minifirewall rules if DRBD interface is configured
|
||||
* proftpd: add whitelist ip
|
||||
|
||||
### Changed
|
||||
|
||||
* apt: add ftp.evolix.org as recognized system source
|
||||
* autosysadmin-agent: logs clearing is done weekly
|
||||
* autosysadmin-agent: rename /usr/share/scripts/autosysadmin/{auto,restart}
|
||||
* certbot: use pkey to test the key
|
||||
* evolinux-base: execute autosysadmin-agent and autosysadmin-restart_nrpe roles
|
||||
* lxc-php, php: Update sury PGP key
|
||||
* openvpn: earlier alert for CA expiration
|
||||
* redis: create sysfs config file if missing
|
||||
* nextcloud: use latest version by default
|
||||
|
||||
### Removed
|
||||
|
||||
* autosysadmin: replaced by autosysadmin-agent
|
||||
|
||||
## [24.02.1] 2024-02-08
|
||||
|
||||
### Fixed
|
||||
|
||||
* fail2ban: fix Ansible syntax
|
||||
|
||||
## [24.02] 2024-02-08
|
||||
|
||||
### Added
|
||||
|
@ -71,6 +141,7 @@ The **patch** part changes is incremented if multiple releases happen the same m
|
|||
* nagios: add dockerd check in nrpe check template
|
||||
* nagios: cleaning nrpe check template
|
||||
* nagios: rename var `nagios_nrpe_process_processes` into `nagios_nrpe_processes` and check systemd-timesyncd instead of ntpd in Debian 12
|
||||
* nagios: add option --full to check pressure IO and mem to avoid flaps
|
||||
* proftpd: in SFTP vhost, enable SSH keys login, enable ed25549 host key for Debian >= 11
|
||||
* redis: manage config template inside a block, to allow custom modifications outside
|
||||
* spamassassin: Use spamd starting with Bookworm
|
||||
|
|
|
@ -39,7 +39,7 @@ $sa_spam_subject_tag = '[SPAM]';
|
|||
$log_level = 2;
|
||||
|
||||
# En fonction besoin/ressources, on a juste le nbre de process
|
||||
$max_servers = 2;
|
||||
$max_servers = 3;
|
||||
|
||||
$enable_ldap = 1;
|
||||
$default_ldap = {
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
##########
|
||||
# This script takes a multi-lines input of "oneliner-style" APT sources definitions.
|
||||
# It converts them into "deb822-style" sources.
|
||||
# Each generated file will have only one stanza, possibly with multiple Types/Suites/Components
|
||||
##########
|
||||
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
|
@ -10,11 +16,16 @@ import apt_pkg
|
|||
# Order matters !
|
||||
destinations = {
|
||||
"debian-security": "security.sources",
|
||||
|
||||
".*-backports": "backports.sources",
|
||||
|
||||
".debian.org": "system.sources",
|
||||
"mirror.evolix.org": "system.sources",
|
||||
"ftp.evolix.org": "system.sources",
|
||||
|
||||
"pub.evolix.net": "evolix_public_old.sources.bak",
|
||||
"pub.evolix.org": "evolix_public.sources",
|
||||
|
||||
"artifacts.elastic.co": "elastic.sources",
|
||||
"download.docker.com": "docker.sources",
|
||||
"downloads.linux.hpe.com": "hp.sources",
|
||||
|
@ -76,6 +87,11 @@ def prepare_sources(lines):
|
|||
key, value = option.split("=")
|
||||
options[key] = value
|
||||
|
||||
### WARNING ###
|
||||
# if there are multiple lines with different URIS for a given destination (eg. "system")
|
||||
# each one will overwrite the previous one
|
||||
# and the last evaluated will be what remains.
|
||||
|
||||
if dest in sources:
|
||||
sources[dest]["Types"].add(matches["type"])
|
||||
sources[dest]["URIs"] = matches["uri"]
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
#!/bin/sh
|
||||
|
||||
##########
|
||||
# This script changes all "one-line" APT sources into "deb822" sources.
|
||||
# It is responsible for searching and processing the files.
|
||||
# The actual format migration is done by a python script.
|
||||
##########
|
||||
|
||||
deb822_migrate_script=$(command -v deb822-migration.py)
|
||||
|
||||
if [ -z "${deb822_migrate_script}" ]; then
|
||||
|
|
17
autosysadmin-agent/defaults/main.yml
Normal file
17
autosysadmin-agent/defaults/main.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
|
||||
general_scripts_dir: "/usr/share/scripts"
|
||||
|
||||
autosysadmin_agent_bin_dir: "/usr/local/bin/autosysadmin"
|
||||
autosysadmin_agent_lib_dir: "/usr/local/lib/autosysadmin"
|
||||
autosysadmin_agent_auto_dir: "{{ general_scripts_dir }}/autosysadmin/restart"
|
||||
|
||||
autosysadmin_agent_crontab_enabled: true
|
||||
autosysadmin_agent_log_retention_days: 365
|
||||
|
||||
autosysadmin_config: []
|
||||
### All repair are disabled if set to 'off'
|
||||
### even if a specific repair value is 'on'
|
||||
# repair_all: 'on'
|
||||
### Default values for checks
|
||||
# repair_foo: 'off'
|
25
autosysadmin-agent/files/upstream/bin/delete_old_logs.sh
Normal file
25
autosysadmin-agent/files/upstream/bin/delete_old_logs.sh
Normal file
|
@ -0,0 +1,25 @@
|
|||
#!/bin/bash
|
||||
|
||||
days=${1:-365}
|
||||
log_dir="/var/log/autosysadmin/"
|
||||
|
||||
if [ -d "${log_dir}" ]; then
|
||||
find_run_dirs() {
|
||||
find "${log_dir}" \
|
||||
-mindepth 1 \
|
||||
-maxdepth 1 \
|
||||
-type d \
|
||||
-ctime "+${days}" \
|
||||
-print0
|
||||
}
|
||||
log() {
|
||||
/usr/bin/logger -p local0.notice -t autosysadmin "${1}"
|
||||
}
|
||||
|
||||
while IFS= read -r -d '' run_dir; do
|
||||
rm --recursive --force "${run_dir}"
|
||||
log "Delete ${run_dir} (older than ${days} days)"
|
||||
done < <(find_run_dirs)
|
||||
fi
|
||||
|
||||
exit 0
|
907
autosysadmin-agent/files/upstream/lib/common.sh
Executable file
907
autosysadmin-agent/files/upstream/lib/common.sh
Executable file
|
@ -0,0 +1,907 @@
|
|||
#!/bin/bash
|
||||
|
||||
VERSION="24.03.2"
|
||||
|
||||
# Common functions for "repair" and "restart" scripts
|
||||
|
||||
set -u
|
||||
|
||||
# Initializes the program, context, configuration…
|
||||
initialize() {
|
||||
PATH="${PATH}":/usr/sbin:/sbin
|
||||
|
||||
# Used in many places to refer to the program name.
|
||||
# Examples: repair_mysql, restart_nrpe…
|
||||
PROGNAME=$(basename "${0}")
|
||||
|
||||
# find out if running in interactive mode, or not
|
||||
if [ -t 0 ]; then
|
||||
INTERACTIVE=1
|
||||
else
|
||||
INTERACTIVE=0
|
||||
fi
|
||||
readonly INTERACTIVE
|
||||
|
||||
# Default empty value for Debug mode
|
||||
DEBUG="${DEBUG:-""}"
|
||||
|
||||
# Repair scripts obey to the value of a variable named after the script
|
||||
# You can set the value ("on" or "off") in /etc/evolinux/autosysadmin
|
||||
# Here we set the default value to "on".
|
||||
declare -g "${PROGNAME}"=on # dynamic variable assignment ($PROGNAME == repair_*)
|
||||
|
||||
PID=$$
|
||||
readonly PID
|
||||
|
||||
# Each execution (run) gets a unique ID
|
||||
RUN_ID="$(date +"%Y-%m-%d_%H-%M")_${PROGNAME}_${PID}"
|
||||
readonly RUN_ID
|
||||
|
||||
# Main log directory
|
||||
MAIN_LOG_DIR="/var/log/autosysadmin"
|
||||
readonly MAIN_LOG_DIR
|
||||
# shellcheck disable=SC2174
|
||||
mkdir --mode=750 --parents "${MAIN_LOG_DIR}"
|
||||
chgrp adm "${MAIN_LOG_DIR}"
|
||||
|
||||
# Each execution store some information
|
||||
# in a unique directory based on the RUN_ID
|
||||
RUN_LOG_DIR="${MAIN_LOG_DIR}/${RUN_ID}"
|
||||
readonly RUN_LOG_DIR
|
||||
# shellcheck disable=SC2174
|
||||
mkdir --mode=750 --parents "${RUN_LOG_DIR}"
|
||||
chgrp adm "${RUN_LOG_DIR}"
|
||||
|
||||
# This log file contains all events
|
||||
RUN_LOG_FILE="${RUN_LOG_DIR}/autosysadmin.log"
|
||||
readonly RUN_LOG_FILE
|
||||
|
||||
# This log file contains notable actions
|
||||
ACTIONS_FILE="${RUN_LOG_DIR}/actions.log"
|
||||
readonly ACTIONS_FILE
|
||||
touch "${ACTIONS_FILE}"
|
||||
# This log file contains abort reasons (if any)
|
||||
ABORT_FILE="${RUN_LOG_DIR}/abort.log"
|
||||
readonly ABORT_FILE
|
||||
# touch "${ABORT_FILE}"
|
||||
|
||||
# Date format for log messages
|
||||
DATE_FORMAT="%Y-%m-%d %H:%M:%S"
|
||||
|
||||
# This will contain lock, last-run markers…
|
||||
# It's ok to lose the content after a reboot
|
||||
RUN_DIR="/run/autosysadmin"
|
||||
readonly RUN_DIR
|
||||
mkdir -p "${RUN_DIR}"
|
||||
|
||||
# Only a singe instace of each script can run simultaneously
|
||||
# We use a customizable lock name for this.
|
||||
# By default it's the script's name
|
||||
LOCK_NAME=${LOCK_NAME:-${PROGNAME}}
|
||||
# If a lock is found, we can wait for it to disappear.
|
||||
# The value must be understood by sleep(1)
|
||||
LOCK_WAIT="0"
|
||||
|
||||
# Default values for email headers
|
||||
EMAIL_FROM="equipe+autosysadmin@evolix.net"
|
||||
EMAIL_INTERNAL="autosysadmin@evolix.fr"
|
||||
|
||||
LOCK_FILE="${RUN_DIR}/${LOCK_NAME}.lock"
|
||||
readonly LOCK_FILE
|
||||
# Remove lock file at exit
|
||||
cleanup() {
|
||||
# shellcheck disable=SC2317
|
||||
rm -f "${LOCK_FILE}"
|
||||
}
|
||||
trap 'cleanup' 0
|
||||
|
||||
# Load configuration
|
||||
# shellcheck disable=SC1091
|
||||
test -f /etc/evolinux/autosysadmin && source /etc/evolinux/autosysadmin
|
||||
|
||||
log_all "Begin ${PROGNAME} RUN_ID: ${RUN_ID}"
|
||||
log_all "Log directory is ${RUN_LOG_DIR}"
|
||||
}
|
||||
|
||||
# Executes a list of tasks before exiting:
|
||||
# * prepare a summary of actions and possible abort reasons
|
||||
# * send emails
|
||||
# * do some cleanup
|
||||
quit() {
|
||||
log_all "End ${PROGNAME} RUN_ID: ${RUN_ID}"
|
||||
|
||||
summary="RUN_ID: ${RUN_ID}"
|
||||
if [ -s "${ABORT_FILE}" ]; then
|
||||
# Add abort reasons to summary
|
||||
summary="${summary}\n$(print_abort_reasons)"
|
||||
hook_mail "abort"
|
||||
|
||||
return_code=1
|
||||
else
|
||||
if [ -s "${ACTIONS_FILE}" ]; then
|
||||
# Add notable actions to summary
|
||||
summary="${summary}\n$(print_actions "Aucune action")"
|
||||
hook_mail "success"
|
||||
fi
|
||||
|
||||
return_code=0
|
||||
fi
|
||||
|
||||
hook_mail "internal"
|
||||
|
||||
if is_interactive; then
|
||||
# shellcheck disable=SC2001
|
||||
echo "${summary}" | sed -e 's/\\n/\n/g'
|
||||
else
|
||||
/usr/share/scripts/evomaintenance.sh --auto --user autosysadmin --message "${summary}" --no-commit --no-mail
|
||||
fi
|
||||
|
||||
teardown
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
exit ${return_code}
|
||||
}
|
||||
|
||||
teardown() {
|
||||
:
|
||||
}
|
||||
|
||||
# Return true/false
|
||||
is_interactive() {
|
||||
test "${INTERACTIVE}" -eq "1"
|
||||
}
|
||||
|
||||
save_server_state() {
|
||||
DUMP_SERVER_STATE_BIN="$(command -v dump-server-state || command -v backup-server-state)"
|
||||
|
||||
if [ -z "${DUMP_SERVER_STATE_BIN}" ]; then
|
||||
log_all "Warning: dump-server-state is not present. No server state recorded."
|
||||
fi
|
||||
|
||||
if [ -x "${DUMP_SERVER_STATE_BIN}" ]; then
|
||||
DUMP_DIR=$(file_path_in_log_dir "server-state")
|
||||
# We don't want the logging to take too much time,
|
||||
# so we kill it if it takes more than 20 seconds.
|
||||
timeout --signal 9 20 \
|
||||
"${DUMP_SERVER_STATE_BIN}" \
|
||||
--dump-dir="${DUMP_DIR}" \
|
||||
--df \
|
||||
--dmesg \
|
||||
--iptables \
|
||||
--lxc \
|
||||
--netcfg \
|
||||
--netstat \
|
||||
--uname \
|
||||
--processes \
|
||||
--systemctl \
|
||||
--uptime \
|
||||
--virsh \
|
||||
--disks \
|
||||
--mysql-processes \
|
||||
--no-apt-states \
|
||||
--no-apt-config \
|
||||
--no-dpkg-full \
|
||||
--no-dpkg-status \
|
||||
--no-mount \
|
||||
--no-packages \
|
||||
--no-sysctl \
|
||||
--no-etc
|
||||
|
||||
log_run "Server state saved in \`server-state' directory."
|
||||
fi
|
||||
}
|
||||
|
||||
is_debug() {
|
||||
# first time: do the check…
|
||||
# other times: pass
|
||||
if [ -z "${DEBUG:-""}" ]; then
|
||||
debug_file="/etc/evolinux/autosysadmin.debug"
|
||||
|
||||
if [ -e "${debug_file}" ]; then
|
||||
last_change=$(stat -c %Z "${debug_file}")
|
||||
limit_date=$(date --date "14400 seconds ago" +"%s")
|
||||
|
||||
if [ $(( last_change - limit_date )) -le "0" ]; then
|
||||
log_run "Debug mode disabled; file is too old (%{last_change} seconds)."
|
||||
rm "${debug_file}"
|
||||
# Debug mode disabled
|
||||
DEBUG="0"
|
||||
else
|
||||
log_run "Debug mode enabled."
|
||||
# Debug mode enabled
|
||||
DEBUG="1"
|
||||
fi
|
||||
else
|
||||
# log_run "Debug mode disabled; file is absent."
|
||||
# Debug mode disabled
|
||||
DEBUG="0"
|
||||
fi
|
||||
fi
|
||||
# return the value
|
||||
test "${DEBUG}" -eq "1"
|
||||
}
|
||||
|
||||
# Uses the who(1) definition of "active"
|
||||
currently_active_users() {
|
||||
LC_ALL=C who --users | grep --extended-regexp "\s+\.\s+" | awk '{print $1}' | sort --human-numeric-sort | uniq
|
||||
}
|
||||
# Users active in the last 29 minutes
|
||||
recently_active_users() {
|
||||
LC_ALL=C who --users | grep --extended-regexp "\s+00:(0|1|2)[0-9]\s+" | awk --field-separator ' ' '{print $1,$6}'
|
||||
}
|
||||
# Save the list of users to a file in the log directory
|
||||
save_active_users() {
|
||||
LC_ALL=C who --users | save_in_log_dir "who-users"
|
||||
}
|
||||
|
||||
# An autosysadmin must not perform actions if a user is active or was active recently.
|
||||
#
|
||||
# This can by bypassed in interactive mode.
|
||||
# It's OK to lose this data after a reboot.
|
||||
ensure_no_active_users_or_exit() {
|
||||
# Save all active users
|
||||
save_active_users
|
||||
|
||||
if is_debug; then
|
||||
log_run "Debug mode enabled: continue without checking active users."
|
||||
return 0;
|
||||
fi
|
||||
|
||||
# Is there any currently active user?
|
||||
currently_active_users=$(currently_active_users)
|
||||
if [ -n "${currently_active_users}" ]; then
|
||||
# shellcheck disable=SC2001
|
||||
users_oneliner=$(echo "${currently_active_users}" | sed -e 's/\n/ /')
|
||||
log_run "Currently active users: ${users_oneliner}"
|
||||
if is_interactive; then
|
||||
echo "Some users are currently active:"
|
||||
# shellcheck disable=SC2001
|
||||
echo "${currently_active_users}" | sed -e 's/\(.\+\)/* \1/'
|
||||
answer=""
|
||||
while :; do
|
||||
printf "> Continue? [Y,n,?] "
|
||||
read -r answer
|
||||
case ${answer} in
|
||||
[Yy]|"" )
|
||||
log_run "Active users check bypassed manually in interactive mode."
|
||||
return
|
||||
;;
|
||||
[Nn] )
|
||||
log_run "Active users check confirmed manually in interactive mode."
|
||||
log_abort_and_quit "Active users detected: ${users_oneliner}"
|
||||
;;
|
||||
* )
|
||||
printf "y - yes, continue\n"
|
||||
printf "n - no, exit\n"
|
||||
printf "? - print this help\n"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
else
|
||||
log_abort_and_quit "Currently active users detected: ${users_oneliner}."
|
||||
fi
|
||||
else
|
||||
# or recently (the last 30 minutes) active user?
|
||||
recently_active_users=$(recently_active_users)
|
||||
if [ -n "${recently_active_users}" ]; then
|
||||
# shellcheck disable=SC2001
|
||||
users_oneliner=$(echo "${recently_active_users}" | sed -e 's/\n/ /')
|
||||
log_run "Recently active users: ${users_oneliner}"
|
||||
if is_interactive; then
|
||||
echo "Some users were recently active:"
|
||||
# shellcheck disable=SC2001
|
||||
echo "${recently_active_users}" | sed -e 's/\(.\+\)/* \1/'
|
||||
answer=""
|
||||
while :; do
|
||||
printf "> Continue? [Y,n,?] "
|
||||
read -r answer
|
||||
case ${answer} in
|
||||
[Yy]|"" )
|
||||
log_run "Active users check bypassed manually in interactive mode."
|
||||
return
|
||||
;;
|
||||
[Nn] )
|
||||
log_run "Active users check confirmed manually in interactive mode."
|
||||
log_abort_and_quit "Recently active users detected: ${users_oneliner}."
|
||||
;;
|
||||
* )
|
||||
printf "y - yes, continue\n"
|
||||
printf "n - no, exit\n"
|
||||
printf "? - print this help\n"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
else
|
||||
log_abort_and_quit "Recently active users detected: ${users_oneliner}."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Takes an NRPE command name as 1st parameter,
|
||||
# and executes the full command if found in the configuration.
|
||||
# Return the result and the return code of the command.
|
||||
check_nrpe() {
|
||||
check="$1"
|
||||
|
||||
nrpe_files=""
|
||||
|
||||
# Check if NRPE config is found
|
||||
if [ -f "/etc/nagios/nrpe.cfg" ]; then
|
||||
nrpe_files="${nrpe_files} /etc/nagios/nrpe.cfg"
|
||||
else
|
||||
msg="NRPE configuration not found: /etc/nagios/nrpe.cfg"
|
||||
log_run "${msg}"
|
||||
echo "${msg}"
|
||||
return 3
|
||||
fi
|
||||
|
||||
# Search for included files
|
||||
# shellcheck disable=SC2086
|
||||
while IFS= read -r include_file; do
|
||||
nrpe_files="${nrpe_files} ${include_file}"
|
||||
done < <(grep --extended-regexp '^\s*include=.+' ${nrpe_files} | cut -d = -f 2)
|
||||
|
||||
# Search for files in included directories
|
||||
# shellcheck disable=SC2086
|
||||
while IFS= read -r include_dir; do
|
||||
nrpe_files="${nrpe_files} ${include_dir}/*.cfg"
|
||||
done < <(grep --extended-regexp '^\s*include_dir=.+' ${nrpe_files} | cut -d = -f 2)
|
||||
|
||||
# Fetch uncommented commands in (sorted) config files
|
||||
# shellcheck disable=SC2086
|
||||
nrpe_commands=$(grep --no-filename --exclude=*~ --fixed-strings "[${check}]" ${nrpe_files} | grep --invert-match --extended-regexp '^\s*#\s*command' | cut -d = -f 2)
|
||||
nrpe_commands_count=$(echo "${nrpe_commands}" | wc -l)
|
||||
|
||||
if is_debian_version "9" "<=" && [ "${nrpe_commands_count}" -gt "1" ]; then
|
||||
# On Debian <= 9, NRPE loading was not sorted
|
||||
# we need to raise an error if we have multiple defined commands
|
||||
msg="Unable to determine which NRPE command to run"
|
||||
log_run "${msg}"
|
||||
echo "${msg}"
|
||||
return 3
|
||||
else
|
||||
# On Debian > 9, use the last command
|
||||
nrpe_command=$(echo "${nrpe_commands}" | tail -n 1)
|
||||
|
||||
nrpe_result=$(${nrpe_command})
|
||||
nrpe_rc=$?
|
||||
|
||||
log_run "NRPE command (exited with ${nrpe_rc}): ${nrpe_command}"
|
||||
log_run "${nrpe_result}"
|
||||
|
||||
echo "${nrpe_result}"
|
||||
return "${nrpe_rc}"
|
||||
fi
|
||||
}
|
||||
|
||||
# An autosysadmin script must not run twice (or more) simultaneously.
|
||||
# We use a customizable (with LOCK_NAME) lock file to keep track of this.
|
||||
# A wait time can be configured.
|
||||
#
|
||||
# This can by bypassed in interactive mode.
|
||||
# It's OK to lose this data after a reboot.
|
||||
acquire_lock_or_exit() {
|
||||
lock_file="${1:-${LOCK_FILE}}"
|
||||
lock_wait="${2:-${LOCK_WAIT}}"
|
||||
|
||||
# lock_wait must be compatible with sleep(1), otherwise fallback to 0
|
||||
if ! echo "${lock_wait}" | grep -Eq '^[0-9]+[smhd]?$'; then
|
||||
log_run "Lock wait: incorrect value '${lock_wait}', fallback to 0."
|
||||
lock_wait=0
|
||||
fi
|
||||
|
||||
if [ "${lock_wait}" != "0" ] && [ -f "${lock_file}" ]; then
|
||||
log_run "Lock file present. Let's wait ${lock_wait} and check again."
|
||||
sleep "${lock_wait}"
|
||||
fi
|
||||
|
||||
if [ -f "${lock_file}" ]; then
|
||||
log_abort_and_quit "Lock file still present."
|
||||
else
|
||||
log_run "Lock file absent. Let's put one."
|
||||
touch "${lock_file}"
|
||||
fi
|
||||
}
|
||||
|
||||
# If a script has been run in the ast 30 minutes, running it again won't fix the issue.
|
||||
# We use a /run/ausosysadmin/${PROGNAME}_lastrun file to keep track of this.
|
||||
#
|
||||
# This can by bypassed in interactive mode.
|
||||
# This is bypassed in debug mode.
|
||||
# It's OK to lose this data after a reboot.
|
||||
ensure_not_too_soon_or_exit() {
|
||||
if is_debug; then
|
||||
log_run "Debug mode enabled: continue without checking when was the last run."
|
||||
return 0;
|
||||
fi
|
||||
|
||||
lastrun_file="${RUN_DIR}/${PROGNAME}_lastrun"
|
||||
if [ -f "${lastrun_file}" ]; then
|
||||
lastrun_age="$(($(date +%s)-$(stat -c "%Y" "${lastrun_file}")))"
|
||||
log_run "Last run was ${lastrun_age} seconds ago."
|
||||
if [ "${lastrun_age}" -lt 1800 ]; then
|
||||
if is_interactive; then
|
||||
echo "${PROGNAME} was run ${lastrun_age} seconds ago."
|
||||
answer=""
|
||||
while :; do
|
||||
printf "> Continue? [Y,n,?] "
|
||||
read -r answer
|
||||
case ${answer} in
|
||||
[Yy]|"" )
|
||||
log_run "Last run check bypassed manually in interactive mode."
|
||||
break
|
||||
;;
|
||||
[Nn] )
|
||||
log_run "Last run check confirmed manually in interactive mode."
|
||||
log_abort_and_quit 'Last run too recent.'
|
||||
;;
|
||||
* )
|
||||
printf "y - yes, continue\n"
|
||||
printf "n - no, exit\n"
|
||||
printf "? - print this help\n"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
else
|
||||
log_abort_and_quit "Last run too recent."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
touch "${lastrun_file}"
|
||||
}
|
||||
|
||||
# Populate DEBIAN_VERSION and DEBIAN_RELEASE variables
|
||||
# based on gathered information about the operating system
|
||||
detect_os() {
|
||||
DEBIAN_RELEASE="unknown"
|
||||
DEBIAN_VERSION="unknown"
|
||||
LSB_RELEASE_BIN="$(command -v lsb_release)"
|
||||
|
||||
if [ -e /etc/debian_version ]; then
|
||||
DEBIAN_VERSION="$(cut -d "." -f 1 < /etc/debian_version)"
|
||||
if [ -x "${LSB_RELEASE_BIN}" ]; then
|
||||
DEBIAN_RELEASE="$("${LSB_RELEASE_BIN}" --codename --short)"
|
||||
else
|
||||
case "${DEBIAN_VERSION}" in
|
||||
7) DEBIAN_RELEASE="wheezy" ;;
|
||||
8) DEBIAN_RELEASE="jessie" ;;
|
||||
9) DEBIAN_RELEASE="stretch" ;;
|
||||
10) DEBIAN_RELEASE="buster" ;;
|
||||
11) DEBIAN_RELEASE="bullseye" ;;
|
||||
12) DEBIAN_RELEASE="bookworm" ;;
|
||||
13) DEBIAN_RELEASE="trixie" ;;
|
||||
esac
|
||||
fi
|
||||
# log_run "Detected OS: Debian version=${DEBIAN_VERSION} release=${DEBIAN_RELEASE}"
|
||||
# else
|
||||
# log_run "Detected OS: unknown (missing /etc/debian_version)"
|
||||
fi
|
||||
}
|
||||
|
||||
is_debian_wheezy() {
|
||||
test "${DEBIAN_RELEASE}" = "wheezy"
|
||||
}
|
||||
is_debian_jessie() {
|
||||
test "${DEBIAN_RELEASE}" = "jessie"
|
||||
}
|
||||
is_debian_stretch() {
|
||||
test "${DEBIAN_RELEASE}" = "stretch"
|
||||
}
|
||||
is_debian_buster() {
|
||||
test "${DEBIAN_RELEASE}" = "buster"
|
||||
}
|
||||
is_debian_bullseye() {
|
||||
test "${DEBIAN_RELEASE}" = "bullseye"
|
||||
}
|
||||
is_debian_bookworm() {
|
||||
test "${DEBIAN_RELEASE}" = "bookworm"
|
||||
}
|
||||
is_debian_trixie() {
|
||||
test "${DEBIAN_RELEASE}" = "trixie"
|
||||
}
|
||||
is_debian_version() {
|
||||
local version=$1
|
||||
local relation=${2:-"eq"}
|
||||
|
||||
if [ -z "${DEBIAN_VERSION:-""}" ]; then
|
||||
detect_os
|
||||
fi
|
||||
|
||||
dpkg --compare-versions "${DEBIAN_VERSION}" "${relation}" "${version}"
|
||||
}
|
||||
|
||||
# List systemd services (only names), even if stopped
|
||||
systemd_list_services() {
|
||||
pattern=$1
|
||||
|
||||
systemctl list-units --all --no-legend --type=service "${pattern}" | grep --only-matching --extended-regexp '\S+\.service'
|
||||
}
|
||||
|
||||
is_systemd_enabled() {
|
||||
systemctl --quiet is-enabled "$1" 2> /dev/null
|
||||
}
|
||||
|
||||
is_systemd_active() {
|
||||
systemctl --quiet is-active "$1" 2> /dev/null
|
||||
}
|
||||
|
||||
is_sysvinit_enabled() {
|
||||
find /etc/rc2.d/ -name "$1" > /dev/null
|
||||
}
|
||||
|
||||
get_fqdn() {
|
||||
# shellcheck disable=SC2155
|
||||
local system=$(uname -s)
|
||||
|
||||
if [ "${system}" = "Linux" ]; then
|
||||
hostname --fqdn
|
||||
elif [ "${system}" = "OpenBSD" ]; then
|
||||
hostname
|
||||
else
|
||||
log_abort_and_quit "System '${system}' not recognized."
|
||||
fi
|
||||
}
|
||||
|
||||
get_complete_hostname() {
|
||||
REAL_HOSTNAME="$(get_fqdn)"
|
||||
if [ "${HOSTNAME}" = "${REAL_HOSTNAME}" ]; then
|
||||
echo "${HOSTNAME}"
|
||||
else
|
||||
echo "${HOSTNAME} (${REAL_HOSTNAME})"
|
||||
fi
|
||||
}
|
||||
# Fetch values from evomaintenance configuration
|
||||
get_evomaintenance_mail() {
|
||||
grep "EVOMAINTMAIL=" /etc/evomaintenance.cf | cut -d '=' -f2
|
||||
}
|
||||
get_evomaintenance_emergency_mail() {
|
||||
grep "URGENCYFROM=" /etc/evomaintenance.cf | cut -d '=' -f2
|
||||
}
|
||||
get_evomaintenance_emergency_tel() {
|
||||
grep "URGENCYTEL=" /etc/evomaintenance.cf | cut -d '=' -f2
|
||||
}
|
||||
|
||||
# Log a message to the log file in the log directory
|
||||
log_run() {
|
||||
local msg="${1:-$(cat /dev/stdin)}"
|
||||
# shellcheck disable=SC2155
|
||||
local date=$(/bin/date +"${DATE_FORMAT}")
|
||||
|
||||
printf "[%s] %s[%s]: %s\\n" \
|
||||
"${date}" "${PROGNAME}" "${PID}" "${msg}" \
|
||||
>> "${RUN_LOG_FILE}"
|
||||
}
|
||||
# Log a message in the system log file (syslog or journald)
|
||||
log_global() {
|
||||
local msg="${1:-$(cat /dev/stdin)}"
|
||||
|
||||
echo "${msg}" \
|
||||
| /usr/bin/logger -p local0.notice -t autosysadmin
|
||||
}
|
||||
# Log a message in both places
|
||||
log_all() {
|
||||
local msg="${1:-$(cat /dev/stdin)}"
|
||||
|
||||
log_global "${msg}"
|
||||
log_run "${msg}"
|
||||
}
|
||||
# Log a notable action in regular places
|
||||
# and append it to the dedicated list
|
||||
log_action() {
|
||||
log_all "$*"
|
||||
append_action "$*"
|
||||
}
|
||||
# Append a line in the actions.log file in the log directory
|
||||
append_action() {
|
||||
echo "$*" >> "${ACTIONS_FILE}"
|
||||
}
|
||||
# Print the content of the actions.log file
|
||||
# or a fallback content (1st parameter) if empty
|
||||
# shellcheck disable=SC2120
|
||||
print_actions() {
|
||||
local fallback=${1:-""}
|
||||
if [ -s "${ACTIONS_FILE}" ]; then
|
||||
cat "${ACTIONS_FILE}"
|
||||
elif [ -n "${fallback}" ]; then
|
||||
echo "${fallback}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Log a an abort reason in regular places
|
||||
# and append it to the dedicated list
|
||||
log_abort() {
|
||||
log_all "$*"
|
||||
append_abort_reason "$*"
|
||||
}
|
||||
# Append a line in the abort.log file in the log directory
|
||||
append_abort_reason() {
|
||||
echo "$*" >> "${ABORT_FILE}"
|
||||
}
|
||||
# Print the content of the abort.log file
|
||||
# or a fallback content (1st parameter) if empty
|
||||
# shellcheck disable=SC2120
|
||||
print_abort_reasons() {
|
||||
local fallback=${1:-""}
|
||||
if [ -s "${ABORT_FILE}" ]; then
|
||||
cat "${ABORT_FILE}"
|
||||
elif [ -n "${fallback}" ]; then
|
||||
echo "${fallback}"
|
||||
fi
|
||||
}
|
||||
# Print the content of the main log from the log directory
|
||||
print_main_log() {
|
||||
cat "${RUN_LOG_FILE}"
|
||||
}
|
||||
# Log an abort reason and quit the script
|
||||
log_abort_and_quit() {
|
||||
log_abort "$*"
|
||||
quit
|
||||
}
|
||||
|
||||
# Store the content from standard inpu
|
||||
# into a file in the log directory named after the 1st parameter
|
||||
save_in_log_dir() {
|
||||
local file_name=$1
|
||||
local file_path="${RUN_LOG_DIR}/${file_name}"
|
||||
|
||||
cat /dev/stdin > "${file_path}"
|
||||
|
||||
log_run "Saved \`${file_name}' file."
|
||||
}
|
||||
# Return the full path of the file in log directory
|
||||
# based on the name in the 1st parameter
|
||||
file_path_in_log_dir() {
|
||||
echo "${RUN_LOG_DIR}/${1}"
|
||||
}
|
||||
|
||||
format_mail_success() {
|
||||
cat <<EOTEMPLATE
|
||||
From: AutoSysadmin Evolix <${EMAIL_FROM}>
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 8bit
|
||||
X-Script: ${PROGNAME}
|
||||
X-RunId: ${RUN_ID}
|
||||
To: ${EMAIL_CLIENT:-alert5@evolix.fr}
|
||||
Cc: ${EMAIL_INTERNAL}
|
||||
Subject: [autosysadmin] Intervention automatisée sur ${HOSTNAME_TEXT}
|
||||
|
||||
Bonjour,
|
||||
|
||||
Une intervention automatisée vient de se terminer.
|
||||
|
||||
Nom du serveur : ${HOSTNAME_TEXT}
|
||||
Heure d'intervention : $(LC_ALL=fr_FR.utf8 date)
|
||||
Script déclenché : ${PROGNAME}
|
||||
|
||||
### Actions réalisées
|
||||
|
||||
$(print_actions "Aucune")
|
||||
|
||||
### Réagir à cette intervention
|
||||
|
||||
Vous pouvez répondre à ce message (${EMAIL_FROM}).
|
||||
|
||||
En cas d'urgence, utilisez l'adresse ${EMERGENCY_MAIL}
|
||||
ou notre ligne d'astreinte (${EMERGENCY_TEL})
|
||||
|
||||
--
|
||||
Votre AutoSysadmin
|
||||
EOTEMPLATE
|
||||
}
|
||||
|
||||
format_mail_abort() {
|
||||
cat <<EOTEMPLATE
|
||||
From: AutoSysadmin Evolix <${EMAIL_FROM}>
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 8bit
|
||||
X-Script: ${PROGNAME}
|
||||
X-RunId: ${RUN_ID}
|
||||
To: ${EMAIL_CLIENT:-alert5@evolix.fr}
|
||||
Cc: ${EMAIL_INTERNAL}
|
||||
Subject: [autosysadmin] Intervention automatisée interrompue sur ${HOSTNAME_TEXT}
|
||||
|
||||
Bonjour,
|
||||
|
||||
Une intervention automatisée a été déclenchée mais s'est interrompue.
|
||||
|
||||
Nom du serveur : ${HOSTNAME_TEXT}
|
||||
Heure d'intervention : $(LC_ALL=fr_FR.utf8 date)
|
||||
Script déclenché : ${PROGNAME}
|
||||
|
||||
### Actions réalisées
|
||||
|
||||
$(print_actions "Aucune")
|
||||
|
||||
### Raison(s) de l'interruption
|
||||
|
||||
$(print_abort_reasons "Inconnue")
|
||||
|
||||
### Réagir à cette intervention
|
||||
|
||||
Vous pouvez répondre à ce message (${EMAIL_FROM}).
|
||||
|
||||
En cas d'urgence, utilisez l'adresse ${EMERGENCY_MAIL}
|
||||
ou notre ligne d'astreinte (${EMERGENCY_TEL})
|
||||
|
||||
--
|
||||
Votre AutoSysadmin
|
||||
EOTEMPLATE
|
||||
}
|
||||
|
||||
# shellcheck disable=SC2028
|
||||
print_report_information() {
|
||||
echo "**Uptime**"
|
||||
echo ""
|
||||
uptime
|
||||
|
||||
echo ""
|
||||
echo "**Utilisateurs récents**"
|
||||
echo ""
|
||||
who_file=$(file_path_in_log_dir "who-users")
|
||||
if [ -s "${who_file}" ]; then
|
||||
cat "${who_file}"
|
||||
else
|
||||
who --users
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "**Espace disque**"
|
||||
echo ""
|
||||
df_file=$(file_path_in_log_dir "server-state/df.txt")
|
||||
if [ -s "${df_file}" ]; then
|
||||
cat "${df_file}"
|
||||
else
|
||||
df -h
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "**Dmesg**"
|
||||
echo ""
|
||||
dmesg_file=$(file_path_in_log_dir "server-state/dmesg.txt")
|
||||
if [ -s "${dmesg_file}" ]; then
|
||||
tail -n 5 "${dmesg_file}"
|
||||
else
|
||||
dmesg | tail -n 5
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "**systemd failed services**"
|
||||
echo ""
|
||||
failed_services_file=$(file_path_in_log_dir "server-state/systemctl-failed-services.txt")
|
||||
if [ -s "${failed_services_file}" ]; then
|
||||
cat "${failed_services_file}"
|
||||
else
|
||||
systemctl --no-legend --state=failed --type=service
|
||||
fi
|
||||
|
||||
if command -v lxc-ls > /dev/null 2>&1; then
|
||||
echo ""
|
||||
echo "**LXC containers**"
|
||||
echo ""
|
||||
lxc_ls_file=$(file_path_in_log_dir "server-state/lxc-list.txt")
|
||||
if [ -s "${lxc_ls_file}" ]; then
|
||||
cat "${lxc_ls_file}"
|
||||
else
|
||||
lxc-ls --fancy
|
||||
fi
|
||||
fi
|
||||
|
||||
apache_errors_file=$(file_path_in_log_dir "apache-errors.log")
|
||||
if [ -f "${apache_errors_file}" ]; then
|
||||
echo ""
|
||||
echo "**Apache errors**"
|
||||
echo ""
|
||||
cat "${apache_errors_file}"
|
||||
fi
|
||||
|
||||
nginx_errors_file=$(file_path_in_log_dir "nginx-errors.log")
|
||||
if [ -f "${nginx_errors_file}" ]; then
|
||||
echo ""
|
||||
echo "**Nginx errors**"
|
||||
echo ""
|
||||
cat "${nginx_errors_file}"
|
||||
fi
|
||||
}
|
||||
|
||||
format_mail_internal() {
|
||||
cat <<EOTEMPLATE
|
||||
From: AutoSysadmin Evolix <${EMAIL_FROM}>
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 8bit
|
||||
X-Script: ${PROGNAME}
|
||||
X-RunId: ${RUN_ID}
|
||||
To: ${EMAIL_INTERNAL}
|
||||
Subject: [autosysadmin] Rapport interne d'intervention sur ${HOSTNAME_TEXT}
|
||||
|
||||
Bonjour,
|
||||
|
||||
Une intervention automatique vient de se terminer.
|
||||
|
||||
Nom du serveur : ${HOSTNAME_TEXT}
|
||||
Heure d'intervention : $(LC_ALL=fr_FR.utf8 date)
|
||||
Script déclenché : ${PROGNAME}
|
||||
|
||||
### Actions réalisées
|
||||
|
||||
$(print_actions "Aucune")
|
||||
|
||||
### Raison(s) de l'interruption
|
||||
|
||||
$(print_abort_reasons "Aucune")
|
||||
|
||||
### Log autosysadmin
|
||||
|
||||
$(print_main_log)
|
||||
|
||||
### Informations additionnelles
|
||||
|
||||
$(print_report_information)
|
||||
|
||||
--
|
||||
Votre AutoSysadmin
|
||||
EOTEMPLATE
|
||||
}
|
||||
|
||||
# Generic function to send emails at the end of the script.
|
||||
# Takes a template as 1st parameter
|
||||
hook_mail() {
|
||||
if is_debug; then
|
||||
log_run "Debug mode enabled: continue without sending mail."
|
||||
return 0;
|
||||
fi
|
||||
|
||||
HOSTNAME="${HOSTNAME:-"$(get_fqdn)"}"
|
||||
HOSTNAME_TEXT="$(get_complete_hostname)"
|
||||
EMAIL_CLIENT="$(get_evomaintenance_mail)"
|
||||
EMERGENCY_MAIL="$(get_evomaintenance_emergency_mail)"
|
||||
EMERGENCY_TEL="$(get_evomaintenance_emergency_tel)"
|
||||
|
||||
MAIL_CONTENT="$(format_mail_"$1")"
|
||||
|
||||
SENDMAIL_BIN="$(command -v sendmail)"
|
||||
|
||||
if [ -z "${SENDMAIL_BIN}" ]; then
|
||||
log_global "ERROR: No \`sendmail' command has been found, can't send mail."
|
||||
fi
|
||||
if [ -x "${SENDMAIL_BIN}" ]; then
|
||||
echo "${MAIL_CONTENT}" | "${SENDMAIL_BIN}" -oi -t -f "equipe@evolix.fr"
|
||||
log_global "Sent '$1' mail for RUN_ID: ${RUN_ID}"
|
||||
fi
|
||||
}
|
||||
|
||||
is_holiday() {
|
||||
# gcal mark today as a holiday by surrounding with < and > the day
|
||||
# of the month of that holiday line. For example if today is 2022-05-01 we'll
|
||||
# get among other lines:
|
||||
# Fête du Travail (FR) + Di, < 1>Mai 2022
|
||||
# Jour de la Victoire (FR) + Di, : 8:Mai 2022 = +7 jours
|
||||
LANGUAGE=fr_FR.UTF-8 TZ=Europe/Paris gcal --cc-holidays=fr --holiday-list=short | grep -E '<[0-9 ]{2}>' --quiet
|
||||
}
|
||||
|
||||
is_weekend() {
|
||||
day_of_week=$(date +%u)
|
||||
if [ "${day_of_week}" != 6 ] && [ "${day_of_week}" != 7 ]; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
is_workday() {
|
||||
if is_holiday || is_weekend; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
is_worktime() {
|
||||
if ! is_workday; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
hour=$(date +%H)
|
||||
if [ "${hour}" -lt 9 ] || { [ "${hour}" -ge 12 ] && [ "${hour}" -lt 14 ] ; } || [ "${hour}" -ge 18 ]; then
|
||||
return 1
|
||||
fi
|
||||
}
|
112
autosysadmin-agent/files/upstream/lib/repair.sh
Normal file
112
autosysadmin-agent/files/upstream/lib/repair.sh
Normal file
|
@ -0,0 +1,112 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Specific functions for "repair" scripts
|
||||
|
||||
is_all_repair_disabled() {
|
||||
# Fetch values from the config
|
||||
# and if it is not defined or has no value, then assign "on"
|
||||
|
||||
local status=${repair_all:=on}
|
||||
|
||||
|
||||
test "${status}" = "off" || test "${status}" = "0"
|
||||
}
|
||||
|
||||
is_current_repair_disabled() {
|
||||
# Fetch values from the config
|
||||
# and if it is not defined or has no value, then assign "on"
|
||||
|
||||
local status=${!PROGNAME:=on}
|
||||
|
||||
test "${status}" = "off" || test "${status}" = "0"
|
||||
}
|
||||
|
||||
ensure_not_disabled_or_exit() {
|
||||
if is_all_repair_disabled; then
|
||||
log_global 'All repair scripts are disabled.'
|
||||
exit 0
|
||||
fi
|
||||
if is_current_repair_disabled; then
|
||||
log_global "Current repair script (${PROGNAME}) is disabled."
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Set of actions to do at the begining of a "repair" script
|
||||
pre_repair() {
|
||||
initialize
|
||||
|
||||
# Are we supposed to run?
|
||||
ensure_not_disabled_or_exit
|
||||
|
||||
# Has it recently been run?
|
||||
ensure_not_too_soon_or_exit
|
||||
|
||||
# Can we acquire a lock?
|
||||
acquire_lock_or_exit
|
||||
|
||||
# Is there any active user?
|
||||
ensure_no_active_users_or_exit
|
||||
|
||||
# Save important information
|
||||
save_server_state
|
||||
}
|
||||
|
||||
# Set of actions to do at the end of a "repair" script
|
||||
post_repair() {
|
||||
quit
|
||||
}
|
||||
|
||||
repair_lxc_php() {
|
||||
container_name=$1
|
||||
|
||||
if is_systemd_enabled 'lxc.service'; then
|
||||
lxc_path=$(lxc-config lxc.lxcpath)
|
||||
if lxc-info --name "${container_name}" > /dev/null; then
|
||||
rootfs="${lxc_path}/${container_name}/rootfs"
|
||||
case "${container_name}" in
|
||||
php56) fpm_log_file="${rootfs}/var/log/php5-fpm.log" ;;
|
||||
php70) fpm_log_file="${rootfs}/var/log/php7.0-fpm.log" ;;
|
||||
php73) fpm_log_file="${rootfs}/var/log/php7.3-fpm.log" ;;
|
||||
php74) fpm_log_file="${rootfs}/var/log/php7.4-fpm.log" ;;
|
||||
php80) fpm_log_file="${rootfs}/var/log/php8.0-fpm.log" ;;
|
||||
php81) fpm_log_file="${rootfs}/var/log/php8.1-fpm.log" ;;
|
||||
php82) fpm_log_file="${rootfs}/var/log/php8.2-fpm.log" ;;
|
||||
php83) fpm_log_file="${rootfs}/var/log/php8.3-fpm.log" ;;
|
||||
*)
|
||||
log_abort_and_quit "Unknown container '${container_name}'"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Determine FPM Pool path
|
||||
php_path_pool=$(find "${lxc_path}/${container_name}/" -type d -name "pool.d")
|
||||
|
||||
# Save LXC info (before restart)
|
||||
lxc-info --name "${container_name}" | save_in_log_dir "lxc-${container_name}.before.status"
|
||||
# Save last lines of FPM log (before restart)
|
||||
tail "${fpm_log_file}" | save_in_log_dir "$(basename "${fpm_log_file}" | sed -e 's/.log/.before.log/')"
|
||||
# Save NRPE check (before restart)
|
||||
/usr/local/lib/nagios/plugins/check_phpfpm_multi "${php_path_pool}" | save_in_log_dir "check_fpm_${container_name}.before.out"
|
||||
|
||||
lxc-stop --timeout 20 --name "${container_name}"
|
||||
lxc-start --daemon --name "${container_name}"
|
||||
rc=$?
|
||||
if [ "${rc}" -eq "0" ]; then
|
||||
log_action "Restart LXC container '${container_name}: OK"
|
||||
else
|
||||
log_action "Restart LXC container '${container_name}: failed"
|
||||
fi
|
||||
|
||||
# Save LXC info (after restart)
|
||||
lxc-info --name "${container_name}" | save_in_log_dir "lxc-${container_name}.after.status"
|
||||
# Save last lines of FPM log (after restart)
|
||||
tail "${fpm_log_file}" | save_in_log_dir "$(basename "${fpm_log_file}" | sed -e 's/.log/.after.log/')"
|
||||
# Save NRPE check (after restart)
|
||||
/usr/local/lib/nagios/plugins/check_phpfpm_multi "${php_path_pool}" | save_in_log_dir "check_fpm_${container_name}.after.out"
|
||||
else
|
||||
log_abort_and_quit "LXC container '${container_name}' doesn't exist."
|
||||
fi
|
||||
else
|
||||
log_abort_and_quit 'LXC not found.'
|
||||
fi
|
||||
}
|
76
autosysadmin-agent/files/upstream/lib/restart.sh
Normal file
76
autosysadmin-agent/files/upstream/lib/restart.sh
Normal file
|
@ -0,0 +1,76 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Specific functions for "restart" scripts
|
||||
|
||||
running_custom() {
|
||||
# Placeholder that returns 1, to prevent running if not redefined
|
||||
log_global "running_custom() function has not been redefined! Let's quit."
|
||||
return 1
|
||||
}
|
||||
|
||||
# Examine RUNNING variable and decide if the script should run or not
|
||||
is_supposed_to_run() {
|
||||
if is_debug; then return 0; fi
|
||||
|
||||
case ${RUNNING} in
|
||||
never)
|
||||
# log_global "is_supposed_to_run: no (never)"
|
||||
return 1
|
||||
;;
|
||||
always)
|
||||
# log_global "is_supposed_to_run: yes (always)"
|
||||
return 0
|
||||
;;
|
||||
nwh-fr)
|
||||
! is_worktime
|
||||
rc=$?
|
||||
# if [ ${rc} -eq 0 ]; then
|
||||
# log_global "is_supposed_to_run: yes (nwh-fr returned ${rc})"
|
||||
# else
|
||||
# log_global "is_supposed_to_run: no (nwh-fr returned ${rc})"
|
||||
# fi
|
||||
return ${rc}
|
||||
;;
|
||||
nwh-ca)
|
||||
# Not implemented yet
|
||||
return 0
|
||||
;;
|
||||
custom)
|
||||
running_custom
|
||||
rc=$?
|
||||
# if [ ${rc} -eq 0 ]; then
|
||||
# log_global "is_supposed_to_run: yes (custom returned ${rc})"
|
||||
# else
|
||||
# log_global "is_supposed_to_run: no (custom returned ${rc})"
|
||||
# fi
|
||||
return ${rc}
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
ensure_supposed_to_run_or_exit() {
|
||||
if ! is_supposed_to_run; then
|
||||
# simply quit (no logging, no notifications…)
|
||||
# log_global "${PROGNAME} is not supposed to run (RUNNING=${RUNNING})."
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Set of actions to do at the begining of a "restart" script
|
||||
pre_restart() {
|
||||
initialize
|
||||
|
||||
# Has it recently been run?
|
||||
ensure_not_too_soon_or_exit
|
||||
|
||||
# Can we acquire a lock?
|
||||
acquire_lock_or_exit
|
||||
|
||||
# Save important information
|
||||
save_server_state
|
||||
}
|
||||
|
||||
# Set of actions to do at the end of a "restart" script
|
||||
post_restart() {
|
||||
quit
|
||||
}
|
157
autosysadmin-agent/files/upstream/repair/repair_disk
Executable file
157
autosysadmin-agent/files/upstream/repair/repair_disk
Executable file
|
@ -0,0 +1,157 @@
|
|||
#!/bin/bash
|
||||
|
||||
: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
|
||||
source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
|
||||
source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
|
||||
|
||||
pre_repair
|
||||
|
||||
|
||||
# We always keep some reserved blocks to avoid missing some logs
|
||||
# https://gitea.evolix.org/evolix/autosysadmin/issues/22
|
||||
RESERVED_BLOCKS_MIN=1
|
||||
|
||||
get_mountpoints() {
|
||||
# the $(...) get the check_disk1 command
|
||||
# the cut command selects the critical part of the check_disk1 output
|
||||
# the grep command extracts the mountpoints and available disk space
|
||||
# the last cut command selects the mountpoints
|
||||
check_disk1_command=$(grep check_disk1 /etc/nagios/nrpe.d/evolix.cfg | cut -d'=' -f2-)
|
||||
|
||||
${check_disk1_command} -e | cut -d'|' -f1 | grep --extended-regexp --only-matching '/[[:graph:]]* [0-9]+ [A-Z][A-Z]' | cut -d' ' -f1
|
||||
}
|
||||
|
||||
is_reserved_blocks_nominal() {
|
||||
partition=${1}
|
||||
|
||||
fs_type="$(findmnt -n --output=fstype "${partition}")"
|
||||
if [ "${fs_type}" = "ext4" ]; then
|
||||
device="$(findmnt -n --output=source "${partition}")"
|
||||
reserved_block_count="$(tune2fs -l "${device}" | grep 'Reserved block count' | awk -F':' '{ gsub (" ", "", $0); print $2}')"
|
||||
block_count="$(tune2fs -l "${device}" | grep 'Block count' | awk -F':' '{ gsub (" ", "", $0); print $2}')"
|
||||
percentage=$(awk "BEGIN { pc=100*${reserved_block_count}/${block_count}; i=int(pc); print (pc-i<0.5)?i:i+1 }")
|
||||
|
||||
log_run "Reserved blocks for ${partition} is currently at ${percentage}%"
|
||||
if [ "${percentage}" -gt "${RESERVED_BLOCKS_MIN}" ]; then
|
||||
log_run "Allowing tune2fs action to reduce the number of reserved blocks"
|
||||
return 0
|
||||
else
|
||||
log_run "Reserved blocks already at or bellow ${RESERVED_BLOCKS_MIN}%, no automatic action possible"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
log_run "Filesystem for ${partition} (${fs_type}) is incompatible with reserved block reduction."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
reduce_reserved_blocks() {
|
||||
partition=${1}
|
||||
|
||||
device=$(findmnt -n --output=source "${partition}")
|
||||
tune2fs -m "${RESERVED_BLOCKS_MIN}" "${device}"
|
||||
log_action "Reserved blocks for ${partition} changed to ${RESERVED_BLOCKS_MIN} percent"
|
||||
}
|
||||
|
||||
is_tmp_to_delete() {
|
||||
size="$(find /var/log/ -type f -ctime +1 -exec du {} \+ | awk '{s+=$1}END{print s / 1024}')"
|
||||
if [ -n "${size}" ]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
is_log_to_delete() {
|
||||
size="$(find /var/log/ -type f -mtime +365 -exec du {} \+ | awk '{s+=$1}END{print s / 1024}')"
|
||||
if [ -n "${size}" ]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
clean_apt_cache() {
|
||||
for container in $(lxc-ls -1); do
|
||||
if [ -e "$(lxc-config lxc.lxcpath)/${container}/rootfs/var/cache" ]; then
|
||||
lxc-attach --name "${container}" -- apt-get clean
|
||||
log_action "Clean apt cache in LXC container ${container}";
|
||||
fi
|
||||
done
|
||||
|
||||
# NOTE: "head -n 1" might be superfluous, but let's be sure to have only the first returned value
|
||||
biggest_subdir=$(du --summarize --one-file-system "/var/*" | sort --numeric-sort --reverse | sed 's/^[0-9]\+[[:space:]]\+//;q' | head -n 1)
|
||||
case "${biggest_subdir}" in
|
||||
'/var/cache')
|
||||
apt-get clean
|
||||
log_action 'Clean apt cache'
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
clean_amavis_virusmails() {
|
||||
if du --inodes /var/lib/* | sort --numeric-sort | tail -n 3 | grep --quiet 'virusmails$'; then
|
||||
find /var/lib/amavis/virusmails/ -type f -atime +30 -delete
|
||||
log_action 'Clean amavis infected mails'
|
||||
fi
|
||||
}
|
||||
|
||||
critical_mountpoints=$(get_mountpoints)
|
||||
|
||||
if [ -z "${critical_mountpoints}" ]; then
|
||||
log_abort_and_quit "No partition is in critical state, nothing left to do."
|
||||
else
|
||||
for mountpoint in ${critical_mountpoints}; do
|
||||
case "${mountpoint}" in
|
||||
/var)
|
||||
#if is_log_to_delete
|
||||
#then
|
||||
# find /var/log/ -type f -mtime +365 -delete
|
||||
# log_action "$size Mo of disk space freed in /var"
|
||||
#fi
|
||||
if is_reserved_blocks_nominal /var; then
|
||||
reduce_reserved_blocks /var
|
||||
clean_apt_cache
|
||||
clean_amavis_virusmails
|
||||
fi
|
||||
;;
|
||||
/tmp)
|
||||
#if is_tmp_to_delete
|
||||
#then
|
||||
# find /tmp/ -type f -ctime +1 -delete
|
||||
# log_action "$size Mo of disk space freed in /tmp"
|
||||
#fi
|
||||
if is_reserved_blocks_nominal /tmp; then
|
||||
reduce_reserved_blocks /tmp
|
||||
fi
|
||||
;;
|
||||
/home)
|
||||
if is_reserved_blocks_nominal /home; then
|
||||
reduce_reserved_blocks /home
|
||||
fi
|
||||
;;
|
||||
/srv)
|
||||
if is_reserved_blocks_nominal /srv; then
|
||||
reduce_reserved_blocks /srv
|
||||
fi
|
||||
;;
|
||||
/filer)
|
||||
if is_reserved_blocks_nominal /filer; then
|
||||
reduce_reserved_blocks /filer
|
||||
fi
|
||||
;;
|
||||
/)
|
||||
if is_reserved_blocks_nominal /; then
|
||||
reduce_reserved_blocks /
|
||||
# Suggest remove old kernel ?
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# unknown
|
||||
log_run 'Unknown partition (or weird case) or nothing to do'
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
post_repair
|
35
autosysadmin-agent/files/upstream/repair/repair_elasticsearch
Executable file
35
autosysadmin-agent/files/upstream/repair/repair_elasticsearch
Executable file
|
@ -0,0 +1,35 @@
|
|||
#!/bin/bash
|
||||
|
||||
: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
|
||||
source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
|
||||
source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
|
||||
|
||||
pre_repair
|
||||
|
||||
service="elasticsearch.service"
|
||||
service_name="elasticsearch"
|
||||
|
||||
if is_systemd_enabled "${service}"; then
|
||||
if is_systemd_active "${service}"; then
|
||||
log_abort_and_quit "${service} is active, nothing left to do."
|
||||
else
|
||||
# Save service status before restart
|
||||
systemctl status "${service}" | save_in_log_dir "${service_name}.before.status"
|
||||
|
||||
# Try to restart
|
||||
timeout 20 systemctl restart "${service}" > /dev/null
|
||||
rc=$?
|
||||
if [ "${rc}" -eq "0" ]; then
|
||||
log_action "Restart ${service_name}: OK"
|
||||
else
|
||||
log_action "Restart ${service_name}: failed"
|
||||
fi
|
||||
|
||||
# Save service status after restart
|
||||
systemctl status "${service}" | save_in_log_dir "${service_name}.after.status"
|
||||
fi
|
||||
else
|
||||
log_abort_and_quit "${service} is disabled (or missing), nothing left to do."
|
||||
fi
|
||||
|
||||
post_repair
|
131
autosysadmin-agent/files/upstream/repair/repair_http
Executable file
131
autosysadmin-agent/files/upstream/repair/repair_http
Executable file
|
@ -0,0 +1,131 @@
|
|||
#!/bin/bash
|
||||
|
||||
: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
|
||||
source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
|
||||
source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
|
||||
|
||||
pre_repair
|
||||
|
||||
## Apache
|
||||
|
||||
service="apache2.service"
|
||||
service_name="apache2"
|
||||
|
||||
if is_systemd_enabled "${service}"; then
|
||||
if is_systemd_active "${service}"; then
|
||||
log_all "${service} is active. Skip."
|
||||
else
|
||||
# Save service status before restart
|
||||
systemctl status "${service}" | save_in_log_dir "${service_name}.before.status"
|
||||
|
||||
# check syntax
|
||||
if apache2ctl -t > /dev/null 2>&1; then
|
||||
# Try to restart
|
||||
timeout 20 systemctl restart "${service}" > /dev/null
|
||||
rc=$?
|
||||
if [ "${rc}" -eq "0" ]; then
|
||||
log_action "Restart ${service_name}: OK"
|
||||
else
|
||||
log_action "Restart ${service_name}: failed"
|
||||
fi
|
||||
|
||||
# Save service status after restart
|
||||
systemctl status "${service}" | save_in_log_dir "${service_name}.after.status"
|
||||
|
||||
# Save error logs
|
||||
date=$(LANG=en_US.UTF-8 date '+%b %d')
|
||||
grep "${date}" /home/*/log/error.log /var/log/apache2/*error.log \
|
||||
| grep -v \
|
||||
-e "Got error 'PHP message:" \
|
||||
-e "No matching DirectoryIndex" \
|
||||
-e "client denied by server configuration" \
|
||||
-e "server certificate does NOT include an ID which matches the server name" \
|
||||
| save_in_log_dir "apache-errors.log"
|
||||
else
|
||||
log_action "Restart ${service_name}: skip (invalid configuration)"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
log_all "${service} is disabled (or missing). Skip."
|
||||
fi
|
||||
|
||||
## Nginx
|
||||
|
||||
service="nginx.service"
|
||||
service_name="nginx"
|
||||
|
||||
if is_systemd_enabled "${service}"; then
|
||||
if is_systemd_active "${service}"; then
|
||||
log_all "${service} is active. Skip."
|
||||
else
|
||||
# Save service status before restart
|
||||
systemctl status "${service}" | save_in_log_dir "${service_name}.before.status"
|
||||
|
||||
# check syntax
|
||||
if nginx -t > /dev/null 2>&1; then
|
||||
# Try to restart
|
||||
timeout 20 systemctl restart "${service}" > /dev/null
|
||||
rc=$?
|
||||
if [ "${rc}" -eq "0" ]; then
|
||||
log_action "Restart ${service_name}: OK"
|
||||
else
|
||||
log_action "Restart ${service_name}: failed"
|
||||
fi
|
||||
|
||||
# Save service status after restart
|
||||
systemctl status "${service}" | save_in_log_dir "${service_name}.after.status"
|
||||
|
||||
# Save error logs
|
||||
### Consider doing for Nginx the same as Apache
|
||||
else
|
||||
log_action "Restart ${service_name}: skip (invalid configuration)"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
log_all "${service} is disabled (or missing). Skip."
|
||||
fi
|
||||
|
||||
## LXC
|
||||
|
||||
if is_systemd_enabled 'lxc.service'; then
|
||||
for container in $(lxc-ls -1 | grep --fixed-strings 'php' | grep --extended-regexp --invert-match --regexp '\bold\b' --regexp '\bdisabled\b'); do
|
||||
repair_lxc_php "${container}"
|
||||
done
|
||||
else
|
||||
log_all "LXC is disabled (or missing). Skip."
|
||||
fi
|
||||
|
||||
## FPM
|
||||
|
||||
fpm_services=$(systemd_list_services 'php*-fpm*')
|
||||
if [ -n "${fpm_services}" ]; then
|
||||
for service in ${fpm_services}; do
|
||||
service_name="${service//.service/}"
|
||||
if is_systemd_enabled "${service}"; then
|
||||
if is_systemd_active "${service}"; then
|
||||
log_all "${service} is active. Skip."
|
||||
else
|
||||
# Save service status before restart
|
||||
systemctl status "${service}" | save_in_log_dir "${service_name}.before.status"
|
||||
|
||||
# Try to restart
|
||||
timeout 20 systemctl restart "${service}" > /dev/null
|
||||
rc=$?
|
||||
if [ "${rc}" -eq "0" ]; then
|
||||
log_action "Restart ${service_name}: OK"
|
||||
else
|
||||
log_action "Restart ${service_name}: failed"
|
||||
fi
|
||||
|
||||
# Save service status after restart
|
||||
systemctl status "${service}" | save_in_log_dir "${service_name}.after.status"
|
||||
fi
|
||||
else
|
||||
log_all "${service} is disabled (or missing). Skip."
|
||||
fi
|
||||
done
|
||||
else
|
||||
log_all "PHP FPM not found. Skip."
|
||||
fi
|
||||
|
||||
post_repair
|
69
autosysadmin-agent/files/upstream/repair/repair_mysql
Executable file
69
autosysadmin-agent/files/upstream/repair/repair_mysql
Executable file
|
@ -0,0 +1,69 @@
|
|||
#!/bin/bash
|
||||
|
||||
: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
|
||||
source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
|
||||
source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
|
||||
|
||||
pre_repair
|
||||
|
||||
if is_debian_version "8" "<="; then
|
||||
|
||||
if is_sysvinit_enabled '*mysql*'; then
|
||||
if ! pgrep -u mysql mysqld > /dev/null; then
|
||||
|
||||
# Save service status before restart
|
||||
timeout 2 mysqladmin status 2>&1 | save_in_log_dir "mysql.before.status"
|
||||
|
||||
timeout 20 /etc/init.d/mysql restart > /dev/null
|
||||
rc=$?
|
||||
if [ "${rc}" -eq "0" ]; then
|
||||
log_action "Restart mysql: OK"
|
||||
else
|
||||
log_action "Restart mysql: failed"
|
||||
fi
|
||||
|
||||
# Save service status after restart
|
||||
timeout 2 mysqladmin status 2>&1 | save_in_log_dir "mysql.after.status"
|
||||
else
|
||||
log_abort_and_quit "mysqld process alive. Aborting"
|
||||
fi
|
||||
else
|
||||
log_abort_and_quit "MySQL not enabled. Aborting"
|
||||
fi
|
||||
|
||||
else
|
||||
|
||||
if is_debian_version "12" ">="; then
|
||||
service="mariadb.service"
|
||||
service_name="mariadb"
|
||||
else
|
||||
service="mysql.service"
|
||||
service_name="mysql"
|
||||
fi
|
||||
|
||||
if is_systemd_enabled "${service}"; then
|
||||
if is_systemd_active "${service}"; then
|
||||
log_abort_and_quit "${service} is active, nothing left to do."
|
||||
else
|
||||
# Save service status before restart
|
||||
systemctl status "${service}" | save_in_log_dir "${service_name}.before.status"
|
||||
|
||||
# Try to restart
|
||||
timeout 20 systemctl restart "${service}" > /dev/null
|
||||
rc=$?
|
||||
if [ "${rc}" -eq "0" ]; then
|
||||
log_action "Restart ${service_name}: OK"
|
||||
else
|
||||
log_action "Restart ${service_name}: failed"
|
||||
fi
|
||||
|
||||
# Save service status after restart
|
||||
systemctl status "${service}" | save_in_log_dir "${service_name}.after.status"
|
||||
fi
|
||||
else
|
||||
log_abort_and_quit "${service} is disabled (or missing), nothing left to do."
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
post_repair
|
35
autosysadmin-agent/files/upstream/repair/repair_opendkim
Executable file
35
autosysadmin-agent/files/upstream/repair/repair_opendkim
Executable file
|
@ -0,0 +1,35 @@
|
|||
#!/bin/bash
|
||||
|
||||
: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
|
||||
source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
|
||||
source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
|
||||
|
||||
pre_repair
|
||||
|
||||
service="opendkim.service"
|
||||
service_name="opendkim"
|
||||
|
||||
if is_systemd_enabled "${service}"; then
|
||||
if is_systemd_active "${service}"; then
|
||||
log_abort_and_quit "${service} is active, nothing left to do."
|
||||
else
|
||||
# Save service status before restart
|
||||
systemctl status "${service}" | save_in_log_dir "${service_name}.before.status"
|
||||
|
||||
# Try to restart
|
||||
timeout 20 systemctl restart "${service}" > /dev/null
|
||||
rc=$?
|
||||
if [ "${rc}" -eq "0" ]; then
|
||||
log_action "Restart ${service_name}: OK"
|
||||
else
|
||||
log_action "Restart ${service_name}: failed"
|
||||
fi
|
||||
|
||||
# Save service status after restart
|
||||
systemctl status "${service}" | save_in_log_dir "${service_name}.after.status"
|
||||
fi
|
||||
else
|
||||
log_abort_and_quit "${service} is disabled (or missing). Abort."
|
||||
fi
|
||||
|
||||
post_repair
|
14
autosysadmin-agent/files/upstream/repair/repair_php_fpm56
Executable file
14
autosysadmin-agent/files/upstream/repair/repair_php_fpm56
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
|
||||
source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
|
||||
source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
|
||||
|
||||
LOCK_WAIT="15s"
|
||||
LOCK_NAME="repair_http"
|
||||
|
||||
pre_repair
|
||||
|
||||
repair_lxc_php php56
|
||||
|
||||
post_repair
|
14
autosysadmin-agent/files/upstream/repair/repair_php_fpm70
Executable file
14
autosysadmin-agent/files/upstream/repair/repair_php_fpm70
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
|
||||
source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
|
||||
source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
|
||||
|
||||
LOCK_WAIT="15s"
|
||||
LOCK_NAME="repair_http"
|
||||
|
||||
pre_repair
|
||||
|
||||
repair_lxc_php php70
|
||||
|
||||
post_repair
|
14
autosysadmin-agent/files/upstream/repair/repair_php_fpm73
Executable file
14
autosysadmin-agent/files/upstream/repair/repair_php_fpm73
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
|
||||
source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
|
||||
source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
|
||||
|
||||
LOCK_WAIT="15s"
|
||||
LOCK_NAME="repair_http"
|
||||
|
||||
pre_repair
|
||||
|
||||
repair_lxc_php php73
|
||||
|
||||
post_repair
|
14
autosysadmin-agent/files/upstream/repair/repair_php_fpm74
Executable file
14
autosysadmin-agent/files/upstream/repair/repair_php_fpm74
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
|
||||
source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
|
||||
source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
|
||||
|
||||
LOCK_WAIT="15s"
|
||||
LOCK_NAME="repair_http"
|
||||
|
||||
pre_repair
|
||||
|
||||
repair_lxc_php php74
|
||||
|
||||
post_repair
|
14
autosysadmin-agent/files/upstream/repair/repair_php_fpm80
Executable file
14
autosysadmin-agent/files/upstream/repair/repair_php_fpm80
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
|
||||
source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
|
||||
source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
|
||||
|
||||
LOCK_WAIT="15s"
|
||||
LOCK_NAME="repair_http"
|
||||
|
||||
pre_repair
|
||||
|
||||
repair_lxc_php php80
|
||||
|
||||
post_repair
|
14
autosysadmin-agent/files/upstream/repair/repair_php_fpm81
Executable file
14
autosysadmin-agent/files/upstream/repair/repair_php_fpm81
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
|
||||
source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
|
||||
source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
|
||||
|
||||
LOCK_WAIT="15s"
|
||||
LOCK_NAME="repair_http"
|
||||
|
||||
pre_repair
|
||||
|
||||
repair_lxc_php php81
|
||||
|
||||
post_repair
|
14
autosysadmin-agent/files/upstream/repair/repair_php_fpm82
Executable file
14
autosysadmin-agent/files/upstream/repair/repair_php_fpm82
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
|
||||
source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
|
||||
source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
|
||||
|
||||
LOCK_WAIT="15s"
|
||||
LOCK_NAME="repair_http"
|
||||
|
||||
pre_repair
|
||||
|
||||
repair_lxc_php php82
|
||||
|
||||
post_repair
|
14
autosysadmin-agent/files/upstream/repair/repair_php_fpm83
Executable file
14
autosysadmin-agent/files/upstream/repair/repair_php_fpm83
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
|
||||
source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
|
||||
source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
|
||||
|
||||
LOCK_WAIT="15s"
|
||||
LOCK_NAME="repair_http"
|
||||
|
||||
pre_repair
|
||||
|
||||
repair_lxc_php php83
|
||||
|
||||
post_repair
|
32
autosysadmin-agent/files/upstream/repair/repair_redis
Executable file
32
autosysadmin-agent/files/upstream/repair/repair_redis
Executable file
|
@ -0,0 +1,32 @@
|
|||
#!/bin/bash
|
||||
|
||||
: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
|
||||
source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
|
||||
source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
|
||||
|
||||
pre_repair
|
||||
|
||||
for service in $(systemd_list_services 'redis-server*'); do
|
||||
service_name="${service//.service/}"
|
||||
|
||||
if is_systemd_active "${service}"; then
|
||||
log_all "${service} is active. Skip."
|
||||
else
|
||||
# Save service status before restart
|
||||
systemctl status "${service}" | save_in_log_dir "${service_name}.before.status"
|
||||
|
||||
# Try to restart
|
||||
timeout 20 systemctl restart "${service}" > /dev/null
|
||||
rc=$?
|
||||
if [ "${rc}" -eq "0" ]; then
|
||||
log_action "Restart ${service_name}: OK."
|
||||
else
|
||||
log_action "Restart ${service_name}: failed."
|
||||
fi
|
||||
|
||||
# Save service status after restart
|
||||
systemctl status "${service}" | save_in_log_dir "${service_name}.after.status"
|
||||
fi
|
||||
done
|
||||
|
||||
post_repair
|
33
autosysadmin/files/scripts/repair_tomcat_instance.sh → autosysadmin-agent/files/upstream/repair/repair_tomcat_instance
Normal file → Executable file
33
autosysadmin/files/scripts/repair_tomcat_instance.sh → autosysadmin-agent/files/upstream/repair/repair_tomcat_instance
Normal file → Executable file
|
@ -1,43 +1,24 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Source functions file
|
||||
# shellcheck source=./functions.sh
|
||||
source /usr/share/scripts/autosysadmin/functions.sh
|
||||
: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
|
||||
source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
|
||||
source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
|
||||
|
||||
init_autosysadmin
|
||||
load_conf
|
||||
|
||||
test "${repair_tomcat_instance:=off}" = off && log_error_exit 'Script disabled, nothing to do here!'
|
||||
|
||||
# Has it recently been run?
|
||||
is_too_soon
|
||||
|
||||
lockfile="/run/lock/repair_tomcat_instance"
|
||||
cleanup() {
|
||||
rm -f "${lockfile}"
|
||||
}
|
||||
trap 'cleanup' 0
|
||||
acquire_lock_or_exit "${lockfile}"
|
||||
|
||||
ensure_no_active_users_or_exit
|
||||
|
||||
# The actual work starts below !
|
||||
|
||||
log_system_status
|
||||
pre_repair
|
||||
|
||||
repair_tomcat_instance_handle_tomcat() {
|
||||
|
||||
if /bin/su - "${1}" -c "/bin/systemctl --quiet --user is-active tomcat.service" ; then
|
||||
if ! /bin/su - "${1}" -c "/usr/bin/timeout 20 /bin/systemctl --quiet --user restart tomcat.service"
|
||||
then
|
||||
log_error_exit "Echec de redémarrage instance tomcat utilisateur ${1}"
|
||||
log_abort_and_quit "Echec de redémarrage instance tomcat utilisateur ${1}"
|
||||
else
|
||||
log_action "Redémarrage instance tomcat utilisateur ${1}"
|
||||
fi
|
||||
elif /bin/systemctl --quiet is-active "${1}".service ; then
|
||||
if ! /usr/bin/timeout 20 systemctl --quiet restart "${1}".service
|
||||
then
|
||||
log_error_exit "Echec de redémarrage instance tomcat ${1}"
|
||||
log_abort_and_quit "Echec de redémarrage instance tomcat ${1}"
|
||||
else
|
||||
log_action "Redémarrage instance tomcat ${1}"
|
||||
fi
|
||||
|
@ -50,4 +31,4 @@ do
|
|||
repair_tomcat_instance_handle_tomcat "${instance}"
|
||||
done
|
||||
|
||||
AUTOSYSADMIN=1 /usr/share/scripts/evomaintenance.sh -m "$0: done" --no-commit --no-mail
|
||||
post_repair
|
41
autosysadmin-agent/files/upstream/repair/zzz-repair_example.template
Executable file
41
autosysadmin-agent/files/upstream/repair/zzz-repair_example.template
Executable file
|
@ -0,0 +1,41 @@
|
|||
#!/bin/bash
|
||||
|
||||
: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
|
||||
source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
|
||||
source "${AUTOSYSADMIN_LIB}/repair.sh" || exit 1
|
||||
|
||||
## Custom lock wait and/or lock name
|
||||
# LOCK_WAIT="15s"
|
||||
# LOCK_NAME="repair_http"
|
||||
|
||||
pre_repair
|
||||
|
||||
## The name of the service, mainly for logging
|
||||
service_name="example"
|
||||
## The systemd service name
|
||||
systemd_service="${service_name}.service"
|
||||
|
||||
if is_systemd_enabled "${systemd_service}"; then
|
||||
if is_systemd_active "${systemd_service}"; then
|
||||
log_abort_and_quit "${systemd_service} is active, nothing left to do."
|
||||
else
|
||||
# Save service status before restart
|
||||
systemctl status "${systemd_service}" | save_in_log_dir "${service_name}.before.status"
|
||||
|
||||
# Try to restart
|
||||
timeout 20 systemctl restart "${systemd_service}" > /dev/null
|
||||
rc=$?
|
||||
if [ "${rc}" -eq "0" ]; then
|
||||
log_action "Restart ${service_name}: OK"
|
||||
else
|
||||
log_action "Restart ${service_name}: failed"
|
||||
fi
|
||||
|
||||
# Save service status after restart
|
||||
systemctl status "${systemd_service}" | save_in_log_dir "${service_name}.after.status"
|
||||
fi
|
||||
else
|
||||
log_abort_and_quit "${service_name} is disabled (or missing), nothing left to do."
|
||||
fi
|
||||
|
||||
post_repair
|
19
autosysadmin-agent/files/upstream/restart/README
Normal file
19
autosysadmin-agent/files/upstream/restart/README
Normal file
|
@ -0,0 +1,19 @@
|
|||
Autosysadmin "restart auto" scripts
|
||||
===================================
|
||||
|
||||
In this directory you can place scripts that will be executed automatically by a cron job (stored in `/etc/cron.d/autosysadmin`).
|
||||
|
||||
They must satisfy the default `run-parts(8)` constraints :
|
||||
|
||||
* be "executable"
|
||||
* belong to the Debian cron script namespace (`^[a-zA-Z0-9_-]+$`), example: `restart_amavis`
|
||||
|
||||
Warning: scripts that do not satisfy those criteria will NOT be run (silently)!
|
||||
|
||||
You can print the names of the scripts which would be run, without actually running them, with this command :
|
||||
|
||||
```
|
||||
$ run-parts --test /usr/share/scripts/autosysadmin/restart
|
||||
```
|
||||
|
||||
You can use `zzz-restart_example.template` as boilerplate code to make your own "restart" script.
|
|
@ -0,0 +1,120 @@
|
|||
#!/bin/bash
|
||||
|
||||
: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
|
||||
source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
|
||||
source "${AUTOSYSADMIN_LIB}/restart.sh" || exit 1
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
RUNNING="nwh-fr"
|
||||
|
||||
## Possible values for RUNNING :
|
||||
## never => disabled
|
||||
## always => enabled
|
||||
## nwh-fr => enabled during non-working-hours in France
|
||||
## nwh-ca => enabled during non-working-hours in Canada (not supported yet)
|
||||
## custom => enabled if `running_custom()` function returns 0, otherwise disabled.
|
||||
|
||||
## Uncomment and customize this method if you want to have a special logic :
|
||||
##
|
||||
## return 1 if we should not run
|
||||
## return 0 if we should run
|
||||
##
|
||||
## Some available functions :
|
||||
## is_weekend() : Saturday or Sunday
|
||||
## is_holiday() : holiday in France (based on `gcal(1)`)
|
||||
## is_workday() : not weekend and not holiday
|
||||
## is_worktime() : work day between 9-12h and 14-18h
|
||||
#
|
||||
# running_custom() {
|
||||
# # implement your own custom method to decide if we should run or not
|
||||
# }
|
||||
|
||||
## The name of the service, mainly for logging
|
||||
service_name="example"
|
||||
## The SysVinit script name
|
||||
sysvinit_script="${service_name}"
|
||||
## The systemd service name
|
||||
systemd_service="${service_name}.service"
|
||||
|
||||
is_service_alive() {
|
||||
## this must return 0 if the service is alive, otherwise return 1
|
||||
## Example:
|
||||
pgrep -u USER PROCESS_NAME > /dev/null
|
||||
}
|
||||
|
||||
## Action for SysVinit system
|
||||
sysvinit_action() {
|
||||
# Save service status before restart
|
||||
timeout 2 "/etc/init.d/${sysvinit_script}" status | save_in_log_dir "${service_name}.before.status"
|
||||
|
||||
# Try to restart
|
||||
timeout 20 "/etc/init.d/${sysvinit_script}" restart > /dev/null
|
||||
rc=$?
|
||||
if [ "${rc}" -eq "0" ]; then
|
||||
log_action "Restart ${service_name}: OK"
|
||||
else
|
||||
log_action "Restart ${service_name}: failed"
|
||||
fi
|
||||
|
||||
# Save service status after restart
|
||||
timeout 2 "/etc/init.d/${sysvinit_script}" status | save_in_log_dir "${service_name}.after.status"
|
||||
}
|
||||
|
||||
## Action for systemd system
|
||||
systemd_action() {
|
||||
# Save service status before restart
|
||||
systemctl status "${systemd_service}" | save_in_log_dir "${service_name}.before.status"
|
||||
|
||||
# Try to restart
|
||||
# systemctl (only for NRPE ?) sometimes returns 0 even if the service has failed to start
|
||||
# so we check the status explicitly
|
||||
timeout 20 systemctl restart "${systemd_service}" > /dev/null \
|
||||
&& sleep 1 \
|
||||
&& systemctl status "${systemd_service}" > /dev/null
|
||||
rc=$?
|
||||
if [ "${rc}" -eq "0" ]; then
|
||||
log_action "Restart ${service_name}: OK"
|
||||
else
|
||||
log_action "Restart ${service_name}: failed"
|
||||
fi
|
||||
|
||||
# Save service status after restart
|
||||
systemctl status "${systemd_service}" | save_in_log_dir "${service_name}.after.status"
|
||||
}
|
||||
|
||||
# Should we run?
|
||||
if ! is_supposed_to_run; then
|
||||
# log_global "${PROGNAME} is not supposed to run (RUNNING=${RUNNING})."
|
||||
exit 0
|
||||
fi
|
||||
if is_service_alive; then
|
||||
# log_global "${service_name} process alive. Aborting"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Yes we do, so check for sysvinit or systemd
|
||||
if is_debian_version "8" "<="; then
|
||||
if ! is_sysvinit_enabled "*${sysvinit_script}*"; then
|
||||
# log_global "${service_name} not enabled. Aborting"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Let's finally do the action
|
||||
pre_restart
|
||||
sysvinit_action
|
||||
post_restart
|
||||
else
|
||||
if ! is_systemd_enabled "${systemd_service}"; then
|
||||
# log_global "${service_name} is disabled (or missing), nothing left to do."
|
||||
exit 0
|
||||
fi
|
||||
if is_systemd_active "${systemd_service}"; then
|
||||
# log_global "${service_name} is active, nothing left to do."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Let's finally do the action
|
||||
pre_restart
|
||||
systemd_action
|
||||
post_restart
|
||||
fi
|
16
autosysadmin-agent/handlers/main.yml
Normal file
16
autosysadmin-agent/handlers/main.yml
Normal file
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
|
||||
- name: restart nagios-nrpe-server
|
||||
service:
|
||||
name: nagios-nrpe-server
|
||||
state: restarted
|
||||
|
||||
- name: restart nrpe
|
||||
service:
|
||||
name: nrpe
|
||||
state: restarted
|
||||
|
||||
- name: restart rsyslog
|
||||
service:
|
||||
name: rsyslog
|
||||
state: restarted
|
25
autosysadmin-agent/tasks/crontab.yml
Normal file
25
autosysadmin-agent/tasks/crontab.yml
Normal file
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
|
||||
- name: "Add begin marker if missing"
|
||||
ansible.builtin.lineinfile:
|
||||
path: "/etc/cron.d/autosysadmin"
|
||||
line: "# BEGIN ANSIBLE MANAGED SECTION FOR AUTOSYSADMIN"
|
||||
insertbefore: BOF
|
||||
create: yes
|
||||
|
||||
- name: "Add end marker if missing"
|
||||
ansible.builtin.lineinfile:
|
||||
path: "/etc/cron.d/autosysadmin"
|
||||
line: "# END ANSIBLE MANAGED SECTION FOR AUTOSYSADMIN"
|
||||
insertbefore: "EOF"
|
||||
create: yes
|
||||
|
||||
- name: "Create config if missing"
|
||||
ansible.builtin.blockinfile:
|
||||
path: "/etc/cron.d/autosysadmin"
|
||||
marker: "# {mark} ANSIBLE MANAGED SECTION FOR AUTOSYSADMIN"
|
||||
block: "{{ lookup('ansible.builtin.template', '../templates/autosysadmin.cron.j2') }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0750"
|
||||
create: yes
|
114
autosysadmin-agent/tasks/install.yml
Normal file
114
autosysadmin-agent/tasks/install.yml
Normal file
|
@ -0,0 +1,114 @@
|
|||
---
|
||||
- name: "Remount /usr if needed"
|
||||
ansible.builtin.include_role:
|
||||
name: remount-usr
|
||||
|
||||
- name: Previous autosysadmin restart directory is renamed
|
||||
command:
|
||||
cmd: mv "/usr/share/scripts/autosysadmin/auto" "{{ autosysadmin_agent_auto_dir }}"
|
||||
removes: "/usr/share/scripts/autosysadmin/auto"
|
||||
creates: "{{ autosysadmin_agent_auto_dir }}"
|
||||
|
||||
- name: Create autosysadmin directories
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0750"
|
||||
loop:
|
||||
- "{{ autosysadmin_agent_bin_dir }}"
|
||||
- "{{ autosysadmin_agent_lib_dir }}"
|
||||
- "{{ autosysadmin_agent_auto_dir }}"
|
||||
|
||||
- name: Copy libraries
|
||||
ansible.builtin.copy:
|
||||
src: "upstream/lib/"
|
||||
dest: "{{ autosysadmin_agent_lib_dir }}/"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0750"
|
||||
|
||||
- name: Copy repair scripts
|
||||
ansible.builtin.copy:
|
||||
src: "upstream/repair/"
|
||||
dest: "{{ autosysadmin_agent_bin_dir }}/"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0750"
|
||||
|
||||
- name: Copy other utilities
|
||||
ansible.builtin.copy:
|
||||
src: "upstream/bin/"
|
||||
dest: "{{ autosysadmin_agent_bin_dir }}/"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0750"
|
||||
|
||||
### WARNING: thos files are explicitly marked as non-executable
|
||||
### to prevent them from being run automatically by run-parts
|
||||
|
||||
- name: Copy restart scripts
|
||||
ansible.builtin.copy:
|
||||
src: "upstream/restart/"
|
||||
dest: "{{ autosysadmin_agent_auto_dir }}/"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0640"
|
||||
|
||||
- name: Ensure /etc/evolinux folder exists
|
||||
ansible.builtin.file:
|
||||
path: "/etc/evolinux"
|
||||
state: directory
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0700"
|
||||
|
||||
- name: Copy the configuration file if missing
|
||||
ansible.builtin.template:
|
||||
src: "autosysadmin.cf.j2"
|
||||
dest: "/etc/evolinux/autosysadmin"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0640"
|
||||
force: no
|
||||
|
||||
# Repair scripts are supposed to be 'on' by default
|
||||
# A line "repair_XXX=off" is added to the file only if the script is to be disabled.
|
||||
# That's why all the ternary logic for the state is reversed.
|
||||
- name: Update value per variable
|
||||
ansible.builtin.lineinfile:
|
||||
dest: "/etc/evolinux/autosysadmin"
|
||||
line: "{{ item }}={{ autosysadmin_config[item] | default(true) | bool | ternary('on', 'off') }}"
|
||||
regexp: '^(#\s*)?{{ item }}=.*'
|
||||
state: "{{ autosysadmin_config[item] | default(true) | bool | ternary('absent', 'present') }}"
|
||||
register: _line
|
||||
loop: "{{ autosysadmin_repair_scripts | union(['repair_all']) }}"
|
||||
|
||||
- name: Ensure restart folder exists
|
||||
ansible.builtin.file:
|
||||
path: "auto"
|
||||
state: directory
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0700"
|
||||
|
||||
- name: Legacy scripts are removed
|
||||
ansible.builtin.file:
|
||||
path: "{{ general_scripts_dir }}/autosysadmin/{{ item }}"
|
||||
state: absent
|
||||
loop:
|
||||
- repair_amavis.sh
|
||||
- repair_disk.sh
|
||||
- repair_elasticsearch.sh
|
||||
- repair_http.sh
|
||||
- repair_mysql.sh
|
||||
- repair_opendkim.sh
|
||||
- repair_php_fpm56.sh
|
||||
- repair_php_fpm70.sh
|
||||
- repair_php_fpm73.sh
|
||||
- repair_php_fpm74.sh
|
||||
- repair_php_fpm80.sh
|
||||
- repair_php_fpm81.sh
|
||||
- repair_redis.sh
|
||||
- repair_tomcat_instance.sh
|
|
@ -1,10 +1,8 @@
|
|||
---
|
||||
- name: Copy logrotate configuration for autosysadmin
|
||||
ansible.builtin.copy:
|
||||
src: "files/logrotate_autosysadmin.conf"
|
||||
src: "files/autosysadmin.logrotate.conf"
|
||||
dest: "/etc/logrotate.d/autosysadmin"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
tags:
|
||||
- autosysadmin
|
31
autosysadmin-agent/tasks/main.yml
Normal file
31
autosysadmin-agent/tasks/main.yml
Normal file
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
|
||||
- name: The list of all repair scripts is composed.
|
||||
set_fact:
|
||||
autosysadmin_repair_scripts: "{{ lookup('ansible.builtin.fileglob', '../../../autosysadmin/agent/repair/repair_*', wantlist=True) | map('basename') | sort }}"
|
||||
|
||||
- name: Install dependencies
|
||||
ansible.builtin.include_tasks: dependencies.yml
|
||||
|
||||
- name: Install autosysadmin
|
||||
ansible.builtin.include_tasks: install.yml
|
||||
|
||||
- name: Crontab configuration
|
||||
ansible.builtin.include_tasks: crontab.yml
|
||||
|
||||
- name: NRPE configuration
|
||||
ansible.builtin.include_tasks: nrpe.yml
|
||||
|
||||
- name: sudo configuration
|
||||
ansible.builtin.include_tasks: sudo.yml
|
||||
|
||||
- name: rsyslog configuration
|
||||
ansible.builtin.include_tasks: rsyslog.yml
|
||||
|
||||
- name: logrotate configuration
|
||||
ansible.builtin.include_tasks: logrotate.yml
|
||||
|
||||
- name: Install latest version of dump-server-state
|
||||
ansible.builtin.include_role:
|
||||
name: evolinux-base
|
||||
tasks_from: dump-server-state.yml
|
9
autosysadmin-agent/tasks/nrpe.yml
Normal file
9
autosysadmin-agent/tasks/nrpe.yml
Normal file
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
- name: custom configuration is present
|
||||
ansible.builtin.template:
|
||||
src: autosysadmin.nrpe.cfg.j2
|
||||
dest: /etc/nagios/nrpe.d/autosysadmin.cfg
|
||||
group: nagios
|
||||
mode: "0640"
|
||||
force: yes
|
||||
notify: restart nagios-nrpe-server
|
|
@ -1,11 +1,9 @@
|
|||
---
|
||||
- name: Copy rsyslog configuration for autosysadmin
|
||||
ansible.builtin.copy:
|
||||
src: "files/rsyslog_autosysadmin.conf"
|
||||
src: "files/autosysadmin.rsyslog.conf"
|
||||
dest: "/etc/rsyslog.d/autosysadmin.conf"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
notify: Restart rsyslog
|
||||
tags:
|
||||
- autosysadmin
|
||||
notify: restart rsyslog
|
|
@ -1,9 +1,7 @@
|
|||
---
|
||||
- name: Add autosysadmin sudoers file
|
||||
ansible.builtin.template:
|
||||
src: sudoers.j2
|
||||
src: autosysadmin.sudoers.j2
|
||||
dest: /etc/sudoers.d/autosysadmin
|
||||
mode: "0600"
|
||||
validate: "visudo -cf %s"
|
||||
tags:
|
||||
- autosysadmin
|
12
autosysadmin-agent/templates/autosysadmin.cf.j2
Normal file
12
autosysadmin-agent/templates/autosysadmin.cf.j2
Normal file
|
@ -0,0 +1,12 @@
|
|||
# This configuration is partially managed by Ansible
|
||||
# You can change specific values manually, but they may be overridden by Ansible
|
||||
#
|
||||
# To be safe, update the hosts_vars/group_vars in the autosysadmin project
|
||||
# https://gitea.evolix.org/evolix/autosysadmin/src/branch/master
|
||||
# then use the "agent" playbook to deploy.
|
||||
#
|
||||
# Configuration for autosysadmin
|
||||
# Use this file to change configuration values defined in repair scripts
|
||||
# To disable all repair scripts : repair_all=off
|
||||
# To disable "repair_http" : repair_http=off
|
||||
#
|
7
autosysadmin-agent/templates/autosysadmin.cron.j2
Normal file
7
autosysadmin-agent/templates/autosysadmin.cron.j2
Normal file
|
@ -0,0 +1,7 @@
|
|||
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
|
||||
# Run each enabled script
|
||||
*/5 * * * * root run-parts /usr/share/scripts/autosysadmin/restart
|
||||
|
||||
# Clean run log files
|
||||
@weekly root {{ autosysadmin_agent_bin_dir | mandatory }}/delete_old_logs.sh {{ autosysadmin_agent_log_retention_days | default('365') }}
|
8
autosysadmin-agent/templates/autosysadmin.nrpe.cfg.j2
Normal file
8
autosysadmin-agent/templates/autosysadmin.nrpe.cfg.j2
Normal file
|
@ -0,0 +1,8 @@
|
|||
#
|
||||
# Ansible managed - DO NOT MODIFY, your changes will be overwritten !
|
||||
#
|
||||
|
||||
# Autosysadmin repair commands
|
||||
{% for script in lookup('ansible.builtin.fileglob', '../../../autosysadmin/agent/repair/repair_*', wantlist=True) | map("basename") | sort %}
|
||||
command[{{ script }}]=sudo {{ autosysadmin_agent_bin_dir }}/{{ script }}
|
||||
{% endfor %}
|
7
autosysadmin-agent/templates/autosysadmin.sudoers.j2
Normal file
7
autosysadmin-agent/templates/autosysadmin.sudoers.j2
Normal file
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
# Ansible managed - DO NOT MODIFY, your changes will be overwritten !
|
||||
#
|
||||
|
||||
{% for script in lookup('ansible.builtin.fileglob', '../../../autosysadmin/agent/repair/repair_*', wantlist=True) | map("basename") | sort %}
|
||||
nagios ALL = NOPASSWD: {{ autosysadmin_agent_bin_dir }}/{{ script }}
|
||||
{% endfor %}
|
8
autosysadmin-restart_nrpe/defaults/main.yml
Normal file
8
autosysadmin-restart_nrpe/defaults/main.yml
Normal file
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
|
||||
general_scripts_dir: "/usr/share/scripts"
|
||||
|
||||
restart_nrpe_path: "{{ general_scripts_dir }}/autosysadmin/restart/restart_nrpe"
|
||||
|
||||
# Change this to customize the RUNNING value in the script
|
||||
restart_nrpe_running: Null
|
105
autosysadmin-restart_nrpe/files/upstream/restart_nrpe
Executable file
105
autosysadmin-restart_nrpe/files/upstream/restart_nrpe
Executable file
|
@ -0,0 +1,105 @@
|
|||
#!/bin/bash
|
||||
|
||||
: "${AUTOSYSADMIN_LIB:=/usr/local/lib/autosysadmin}"
|
||||
source "${AUTOSYSADMIN_LIB}/common.sh" || exit 1
|
||||
source "${AUTOSYSADMIN_LIB}/restart.sh" || exit 1
|
||||
|
||||
## Possible values for RUNNING :
|
||||
## never => disabled
|
||||
## always => enabled
|
||||
## nwh-fr => enabled during non-working-hours in France
|
||||
## nwh-ca => enabled during non-working-hours in Canada (not supported yet)
|
||||
## custom => enabled if `running_custom()` function return 0, otherwise disabled.
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
RUNNING="nwh-fr"
|
||||
|
||||
## The name of the service, mainly for logging
|
||||
service_name="nagios-nrpe-server"
|
||||
## The SysVinit script name
|
||||
sysvinit_script="${service_name}"
|
||||
## The systemd service name
|
||||
systemd_service="${service_name}.service"
|
||||
|
||||
is_service_alive() {
|
||||
## this must return 0 if the service is alive, otherwise return 1
|
||||
## Example:
|
||||
pgrep -u nagios nrpe > /dev/null
|
||||
}
|
||||
|
||||
## Action for SysVinit system
|
||||
sysvinit_action() {
|
||||
# Save service status before restart
|
||||
timeout 2 "/etc/init.d/${sysvinit_script}" status | save_in_log_dir "${service_name}.before.status"
|
||||
|
||||
# Try to restart
|
||||
timeout 20 "/etc/init.d/${sysvinit_script}" restart > /dev/null
|
||||
rc=$?
|
||||
if [ "${rc}" -eq "0" ]; then
|
||||
log_action "Restart ${service_name}: OK"
|
||||
else
|
||||
log_action "Restart ${service_name}: failed"
|
||||
fi
|
||||
|
||||
# Save service status after restart
|
||||
timeout 2 "/etc/init.d/${sysvinit_script}" status | save_in_log_dir "${service_name}.after.status"
|
||||
}
|
||||
|
||||
## Action for systemd system
|
||||
systemd_action() {
|
||||
# Save service status before restart
|
||||
systemctl status "${systemd_service}" | save_in_log_dir "${service_name}.before.status"
|
||||
|
||||
# Try to restart
|
||||
# systemctl (only for NRPE ?) sometimes returns 0 even if the service has failed to start
|
||||
# so we check the status explicitly
|
||||
timeout 20 systemctl restart "${systemd_service}" > /dev/null \
|
||||
&& sleep 1 \
|
||||
&& systemctl status "${systemd_service}" > /dev/null
|
||||
rc=$?
|
||||
if [ "${rc}" -eq "0" ]; then
|
||||
log_action "Restart ${service_name}: OK"
|
||||
else
|
||||
log_action "Restart ${service_name}: failed"
|
||||
fi
|
||||
|
||||
# Save service status after restart
|
||||
systemctl status "${systemd_service}" | save_in_log_dir "${service_name}.after.status"
|
||||
}
|
||||
|
||||
# Should we run?
|
||||
if ! is_supposed_to_run; then
|
||||
# log_global "${PROGNAME} is not supposed to run (RUNNING=${RUNNING})."
|
||||
exit 0
|
||||
fi
|
||||
if is_service_alive; then
|
||||
# log_global "${service_name} process alive. Aborting"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Yes we do, so check for sysvinit or systemd
|
||||
if is_debian_version "8" "<="; then
|
||||
if ! is_sysvinit_enabled "*${sysvinit_script}*"; then
|
||||
# log_global "${service_name} not enabled. Aborting"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Let's finally do the action
|
||||
pre_restart
|
||||
sysvinit_action
|
||||
post_restart
|
||||
else
|
||||
if ! is_systemd_enabled "${systemd_service}"; then
|
||||
# log_global "${service_name} is disabled (or missing), nothing left to do."
|
||||
exit 0
|
||||
fi
|
||||
if is_systemd_active "${systemd_service}"; then
|
||||
# log_global "${service_name} is active, nothing left to do."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Let's finally do the action
|
||||
pre_restart
|
||||
systemd_action
|
||||
post_restart
|
||||
fi
|
24
autosysadmin-restart_nrpe/tasks/main.yml
Normal file
24
autosysadmin-restart_nrpe/tasks/main.yml
Normal file
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
|
||||
- name: "Remount /usr if needed"
|
||||
ansible.builtin.include_role:
|
||||
name: remount-usr
|
||||
|
||||
- name: "Copy restart_nrpe"
|
||||
ansible.builtin.copy:
|
||||
src: upstream/restart_nrpe
|
||||
dest: "{{ restart_nrpe_path }}"
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0750"
|
||||
|
||||
- name: "Customize RUNNING value"
|
||||
ansible.builtin.lineinfile:
|
||||
path: "{{ restart_nrpe_path }}"
|
||||
line: "RUNNING=\"{{ restart_nrpe_running }}\""
|
||||
regexp: "^ *RUNNING="
|
||||
create: False
|
||||
when:
|
||||
- restart_nrpe_running is defined
|
||||
- restart_nrpe_running != None
|
||||
- restart_nrpe_running | length > 0
|
|
@ -1,22 +0,0 @@
|
|||
---
|
||||
|
||||
general_scripts_dir: "/usr/share/scripts"
|
||||
autosysadmin_dir: "{{ general_scripts_dir }}/autosysadmin"
|
||||
|
||||
# Default values for enabled checks
|
||||
repair_amavis: 'on'
|
||||
repair_disk: 'on'
|
||||
repair_elasticsearch: 'on'
|
||||
repair_http: 'on'
|
||||
repair_mysql: 'on'
|
||||
repair_opendkim: 'off'
|
||||
repair_php_fpm56: 'off'
|
||||
repair_php_fpm70: 'off'
|
||||
repair_php_fpm73: 'off'
|
||||
repair_php_fpm74: 'off'
|
||||
repair_php_fpm80: 'off'
|
||||
repair_php_fpm81: 'off'
|
||||
repair_php_fpm82: 'off'
|
||||
repair_php_fpm83: 'off'
|
||||
repair_redis: 'off'
|
||||
repair_tomcat_instance: 'off'
|
|
@ -1,478 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
get_system() {
|
||||
uname -s
|
||||
}
|
||||
|
||||
get_fqdn() {
|
||||
if [ "$(get_system)" = "Linux" ]; then
|
||||
hostname --fqdn
|
||||
elif [ "$(get_system)" = "OpenBSD" ]; then
|
||||
hostname
|
||||
else
|
||||
log_error_exit "OS not detected!"
|
||||
fi
|
||||
}
|
||||
|
||||
get_complete_hostname() {
|
||||
REAL_HOSTNAME="$(get_fqdn)"
|
||||
if [ "${HOSTNAME}" = "${REAL_HOSTNAME}" ]; then
|
||||
echo "${HOSTNAME}"
|
||||
else
|
||||
echo "${HOSTNAME} (${REAL_HOSTNAME})"
|
||||
fi
|
||||
}
|
||||
|
||||
get_evomaintenance_mail() {
|
||||
email="$(grep "EVOMAINTMAIL=" /etc/evomaintenance.cf | cut -d '=' -f2)"
|
||||
|
||||
if [[ -z "$email" ]]; then
|
||||
email='alert5@evolix.fr'
|
||||
fi
|
||||
|
||||
echo "${email}"
|
||||
}
|
||||
|
||||
arguments="${*}"
|
||||
|
||||
get_argument() {
|
||||
no_found=1
|
||||
for argument in ${arguments} ; do
|
||||
if [ "${argument}" = "${1}" ] ;
|
||||
then
|
||||
no_found=0
|
||||
fi
|
||||
done
|
||||
return ${no_found}
|
||||
}
|
||||
|
||||
internal_info() {
|
||||
INTERNAL_INFO="$(printf '%b\n%s' "${INTERNAL_INFO}" "$*")"
|
||||
}
|
||||
|
||||
log_action() {
|
||||
log "Action : $*"
|
||||
ACTIONS="$(printf '%s\n%s' "${ACTIONS}" "$*")"
|
||||
}
|
||||
|
||||
log() {
|
||||
INTERNAL_LOG="$(printf '%s\n%s %s %s %s' "${INTERNAL_LOG}" "$(date -Isec)" "$(hostname)" "$(basename "$0")" "$*")"
|
||||
printf '%s %s %s %s\n' "$(date -Isec)" "$(hostname)" "$(basename "$0")" "$*" | tee -a "${LOG_DIR}/autosysadmin.log"
|
||||
echo "$*" | /usr/bin/logger -p local0.notice -t autosysadmin."$0"
|
||||
}
|
||||
|
||||
log_error_exit() {
|
||||
log "ERROR : $*"
|
||||
AUTOSYSADMIN=1 /usr/share/scripts/evomaintenance.sh -m "$0: $*" --no-commit --no-mail
|
||||
exit 1
|
||||
}
|
||||
|
||||
log_check_php_fpm() {
|
||||
|
||||
# Extraire seulement les chiffres du nom du script exécuté
|
||||
# ./repair_php_fpm81.sh ==> 81
|
||||
PHP_VERSION="${0//[^0-9]/}"
|
||||
|
||||
PHP_PATH_POOL=$(find /var/lib/lxc/php"${PHP_VERSION}"/ -type d -name "pool.d")
|
||||
/usr/local/lib/nagios/plugins/check_phpfpm_multi "${PHP_PATH_POOL}" > "${LOG_DIR}/nrpe.txt"
|
||||
}
|
||||
|
||||
log_system_status() {
|
||||
DUMP_SERVER_STATE_BIN="$(command -v dump-server-state || command -v backup-server-state)"
|
||||
|
||||
if [ -z "${DUMP_SERVER_STATE_BIN}" ]; then
|
||||
log "Warning: dump-server-state is not present. No server state recorded...."
|
||||
fi
|
||||
|
||||
if [ -x "${DUMP_SERVER_STATE_BIN}" ]; then
|
||||
|
||||
# NOTE We don't want the logging to take too much time, so we kill it
|
||||
# if it take more than 20 seconds.
|
||||
timeout --signal 9 20 \
|
||||
"${DUMP_SERVER_STATE_BIN}" \
|
||||
--dump-dir="$LOG_DIR" \
|
||||
--df \
|
||||
--dmesg \
|
||||
--iptables \
|
||||
--lxc \
|
||||
--netcfg \
|
||||
--netstat \
|
||||
--uname \
|
||||
--processes \
|
||||
--systemctl \
|
||||
--uptime \
|
||||
--virsh \
|
||||
--disks \
|
||||
--mysql-processes \
|
||||
--no-apt-states \
|
||||
--no-apt-config \
|
||||
--no-dpkg-full \
|
||||
--no-dpkg-status \
|
||||
--no-mount \
|
||||
--no-packages \
|
||||
--no-sysctl \
|
||||
--no-etc
|
||||
|
||||
log "System status logged in ${LOG_DIR}"
|
||||
fi
|
||||
}
|
||||
|
||||
read_log_system_status(){
|
||||
files="df.txt dmesg.txt lxc-list.txt netstat-legacy.txt netstat-ss.txt pstree.txt ps.txt systemctl-failed-services.txt"
|
||||
echo -e "\n\n#### Détails de dump-server-state"
|
||||
for file in ${files} ; do
|
||||
echo -e "\n### cat ${LOG_DIR}/${file} :"
|
||||
tail -n 1000 "${LOG_DIR}"/"${file}"
|
||||
done
|
||||
}
|
||||
|
||||
ensure_no_active_users_or_exit() {
|
||||
if is_debug; then return; fi
|
||||
|
||||
# Is there any active user ?
|
||||
for user in $(LC_ALL=C who --users|awk '{print $1}'); do
|
||||
idle_time="$(LC_ALL=C who --users | grep "${user}" | awk '{ print $6}')"
|
||||
for sameusertime in $(LC_ALL=C who --users | grep "${user}" | awk '{ print $6}'); do
|
||||
if is_active_user "$sameusertime"; then
|
||||
hook_mail abort_active_users
|
||||
log_error_exit 'At least one user was recently active. That requires human intervention. Nothing to do here!'
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
is_active_user() {
|
||||
# Check if a user was active in the last 30 minutes
|
||||
idle_time="$1"
|
||||
|
||||
if [ "${idle_time}" = "old" ];
|
||||
then
|
||||
return 1
|
||||
elif [ "${idle_time}" = "." ];
|
||||
then
|
||||
return 0
|
||||
else
|
||||
hh="$(echo "${idle_time}" | awk -F':' '{print $1}')"
|
||||
mm="$(echo "${idle_time}" | awk -F':' '{print $2}')"
|
||||
idle_minutes="$(( 60 * "${hh}" + "${mm}" ))"
|
||||
if [ "${idle_minutes}" -ge 30 ];
|
||||
then
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
is_debug() {
|
||||
debug_file="/etc/evolinux/autosysadmin.debug"
|
||||
|
||||
if [ -e "${debug_file}" ]; then
|
||||
last_change=$(stat -c %Z "${debug_file}")
|
||||
limit_date=$(date --date "14400 seconds ago" +"%s")
|
||||
|
||||
if [ $(( last_change - limit_date )) -le "0" ]; then
|
||||
rm "${debug_file}"
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
check_nrpe() {
|
||||
check="$1"
|
||||
list_command_nrpe=$( grep --exclude=*~ -E "\[${check}\]" -r /etc/nagios/ | grep -v '#command' )
|
||||
command_nrpe_primary=$( echo "${list_command_nrpe}" | grep "/etc/nagios/nrpe.d/evolix.cfg" | cut -d'=' -f2- )
|
||||
command_nrpe_secondary=$( echo "${list_command_nrpe}" | head -n1 | cut -d'=' -f2- )
|
||||
|
||||
if [ -z "${command_nrpe_primary}" ] && [ -z "${command_nrpe_secondary}" ]
|
||||
then
|
||||
return 1
|
||||
else
|
||||
if [ -n "${command_nrpe_primary}" ]
|
||||
then
|
||||
${command_nrpe_primary}
|
||||
else
|
||||
${command_nrpe_secondary}
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
acquire_lock_or_exit() {
|
||||
lockfile="$1"
|
||||
waittime="$2"
|
||||
|
||||
# si le temps d’attente n’est pas compréhensible par sleep(1), il vaut 0
|
||||
if ! echo "${waittime}" | grep -Eq '^[0-9]+[smhd]?$'
|
||||
then
|
||||
waittime=0
|
||||
fi
|
||||
|
||||
# si le temps d’attente est supérieur à 0 et si le lock existe, on attend
|
||||
if test "${waittime}" -gt 0 && test -f "${lockfile}"
|
||||
then
|
||||
sleep "${waittime}"
|
||||
fi
|
||||
|
||||
# si le lock existe, on s’arrête
|
||||
if test -f "${lockfile}"
|
||||
then
|
||||
log_error_exit "lock file ${lockfile} exists"
|
||||
fi
|
||||
touch "${lockfile}"
|
||||
}
|
||||
|
||||
is_too_soon() {
|
||||
if is_debug; then return; fi
|
||||
|
||||
witness="/tmp/autosysadmin_witness_$(basename "$0")"
|
||||
if test -f "${witness}"
|
||||
then
|
||||
compare="$(($(date +%s)-$(stat -c "%Y" "${witness}")))"
|
||||
if [ "${compare}" -lt 1800 ];
|
||||
then
|
||||
log_error_exit 'already executed less than 30 minutes ago'
|
||||
fi
|
||||
rm "${witness}"
|
||||
fi
|
||||
touch "${witness}"
|
||||
}
|
||||
|
||||
init_autosysadmin() {
|
||||
PATH="${PATH}":/usr/sbin:/sbin↩
|
||||
unset ACTIONS
|
||||
|
||||
SCRIPTNAME=$(basename "$0")
|
||||
PROGNAME=${SCRIPTNAME%.sh}
|
||||
|
||||
RUN_ID="$(date +"%Y-%m-%d_%H-%M")_${SCRIPTNAME}_$(openssl rand -hex 6)"
|
||||
LOG_DIR="/var/log/autosysadmin/${RUN_ID}"
|
||||
mkdir -p "${LOG_DIR}"
|
||||
|
||||
log "Autosysadmin : Script ${SCRIPTNAME} triggered"
|
||||
|
||||
# Detect operating system name, version and release↩
|
||||
detect_os
|
||||
}
|
||||
|
||||
load_conf() {
|
||||
# Load conf and enable script by default.
|
||||
# To disable script locally, set "$PROGNAME"=off in /etc/evolinux/autosysadmin.
|
||||
# To disable script globally, set "$PROGNAME"=off in the script, after load_conf() call.
|
||||
declare -g "$PROGNAME"=on # dynamic variable assignment ($PROGNAME == repair_*)
|
||||
|
||||
# Source configuration file
|
||||
# shellcheck source=../roles/deploy_autosysadmin/templates/autosysadmin.cfg.j2
|
||||
test -f /etc/evolinux/autosysadmin && source /etc/evolinux/autosysadmin
|
||||
}
|
||||
|
||||
detect_os() {
|
||||
# OS detection
|
||||
DEBIAN_RELEASE=""
|
||||
LSB_RELEASE_BIN="$(command -v lsb_release)"
|
||||
|
||||
if [ -e /etc/debian_version ]; then
|
||||
DEBIAN_VERSION="$(cut -d "." -f 1 < /etc/debian_version)"
|
||||
if [ -x "${LSB_RELEASE_BIN}" ]; then
|
||||
DEBIAN_RELEASE="$("${LSB_RELEASE_BIN}" --codename --short)"
|
||||
else
|
||||
case "${DEBIAN_VERSION}" in
|
||||
8) DEBIAN_RELEASE="jessie";;
|
||||
9) DEBIAN_RELEASE="stretch";;
|
||||
10) DEBIAN_RELEASE="buster";;
|
||||
11) DEBIAN_RELEASE="bullseye";;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
is_debian_jessie() {
|
||||
test "${DEBIAN_RELEASE}" = "jessie"
|
||||
}
|
||||
is_debian_stretch() {
|
||||
test "${DEBIAN_RELEASE}" = "stretch"
|
||||
}
|
||||
is_debian_buster() {
|
||||
test "${DEBIAN_RELEASE}" = "buster"
|
||||
}
|
||||
is_debian_bullseye() {
|
||||
test "${DEBIAN_RELEASE}" = "bullseye"
|
||||
}
|
||||
|
||||
systemd_list_service_failed() {
|
||||
systemctl list-units --failed --no-legend --full --type=service "$1" |
|
||||
awk '{print $1}'
|
||||
}
|
||||
|
||||
systemd_list_units_enabled() {
|
||||
list_units_enabled=$(systemctl list-unit-files --state=enabled --no-legend | awk "/$1/{print \$1}")
|
||||
if [ -z "${list_units_enabled}" ]
|
||||
then
|
||||
return 1
|
||||
else
|
||||
echo "${list_units_enabled}"
|
||||
fi
|
||||
}
|
||||
|
||||
format_mail_success() {
|
||||
cat <<EOTEMPLATE
|
||||
From: AutoSysadmin Evolix <equipe+autosysadmin@evolix.net>
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 8bit
|
||||
X-Script: $(basename "$0")
|
||||
X-RunId: ${RUN_ID}
|
||||
To: ${EMAIL_CLIENT:-alert5@evolix.fr}
|
||||
Cc: autosysadmin@evolix.fr
|
||||
Subject: [autosysadmin] Intervention sur ${HOSTNAME_TEXT}
|
||||
|
||||
Bonjour,
|
||||
|
||||
Une intervention automatique vient de se terminer.
|
||||
|
||||
Nom du serveur : ${HOSTNAME_TEXT}
|
||||
Heure d'intervention : $(LC_ALL=fr_FR.utf8 date)
|
||||
|
||||
### Renseignements sur l'intervention
|
||||
|
||||
${ACTIONS}
|
||||
|
||||
### Réagir à cette intervention
|
||||
|
||||
Vous pouvez répondre à ce message (sur l'adresse mail equipe@evolix.net).
|
||||
En cas d'urgence, utilisez l'adresse maintenance@evolix.fr ou
|
||||
notre téléphone portable d'astreinte (04.26.99.99.26)
|
||||
|
||||
--
|
||||
Votre AutoSysadmin
|
||||
EOTEMPLATE
|
||||
}
|
||||
|
||||
format_mail_abort_active_users() {
|
||||
cat <<EOTEMPLATE
|
||||
From: AutoSysadmin Evolix <equipe+autosysadmin@evolix.net>
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 8bit
|
||||
X-Script: $(basename "$0")
|
||||
X-RunId: ${RUN_ID}
|
||||
To: ${EMAIL_CLIENT:-alert5@evolix.fr}
|
||||
Cc: autosysadmin@evolix.fr
|
||||
Subject: [autosysadmin] Intervention interrompue sur ${HOSTNAME_TEXT}
|
||||
|
||||
Bonjour,
|
||||
|
||||
Une intervention automatique a été interrompue en raison
|
||||
d'un utilisateur actuellement actif sur le serveur.
|
||||
|
||||
Nom du serveur : ${HOSTNAME_TEXT}
|
||||
Heure d'intervention : $(LC_ALL=fr_FR.utf8 date)
|
||||
|
||||
### Utilisateur(s) connecté(s)
|
||||
$(w)
|
||||
|
||||
--
|
||||
Votre AutoSysadmin
|
||||
EOTEMPLATE
|
||||
}
|
||||
|
||||
format_mail_internal_info() {
|
||||
cat <<EOTEMPLATE
|
||||
From: AutoSysadmin Evolix <equipe+autosysadmin@evolix.net>
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 8bit
|
||||
X-Script: $(basename "$0")
|
||||
X-RunId: ${RUN_ID}
|
||||
To: autosysadmin@evolix.fr
|
||||
Subject: [autosysadmin] Complements (interne) - Intervention sur ${HOSTNAME_TEXT}
|
||||
|
||||
Bonjour,
|
||||
|
||||
Une intervention automatique vient de se terminer.
|
||||
|
||||
Nom du serveur : ${HOSTNAME_TEXT}
|
||||
Heure d'intervention : $(LC_ALL=fr_FR.utf8 date)
|
||||
Script déclenché : $(basename "$0")
|
||||
|
||||
### Actions effectuées
|
||||
|
||||
${ACTIONS}
|
||||
|
||||
### Logs autosysadmin
|
||||
|
||||
${INTERNAL_LOG}
|
||||
|
||||
### Utilisateur(s) connecté(s)
|
||||
|
||||
$(w)
|
||||
|
||||
### Informations additionnelles données par le script $(basename "$0")
|
||||
|
||||
${INTERNAL_INFO}
|
||||
|
||||
--
|
||||
Votre AutoSysadmin
|
||||
EOTEMPLATE
|
||||
}
|
||||
|
||||
hook_mail() {
|
||||
if is_debug; then return; fi
|
||||
|
||||
HOSTNAME="${HOSTNAME:-"$(get_fqdn)"}"
|
||||
HOSTNAME_TEXT="$(get_complete_hostname)"
|
||||
EMAIL_CLIENT="$(get_evomaintenance_mail)"
|
||||
|
||||
MAIL_CONTENT="$(format_mail_"$1")"
|
||||
|
||||
SENDMAIL_BIN="$(command -v sendmail)"
|
||||
|
||||
if [ -z "${SENDMAIL_BIN}" ]; then
|
||||
log "No \`sendmail' command has been found, can't send mail."
|
||||
fi
|
||||
|
||||
if [ -x "${SENDMAIL_BIN}" ]; then
|
||||
echo "${MAIL_CONTENT}" | "${SENDMAIL_BIN}" -oi -t -f "equipe@evolix.net"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
|
||||
# We need stable output for gcal, so we force some language environment variables
|
||||
export TZ=Europe/Paris
|
||||
export LANGUAGE=fr_FR.UTF-8
|
||||
|
||||
is_holiday() {
|
||||
# gcal mark today as a holiday by surrounding with < and > the day
|
||||
# of the month of that holiday line. For exemple if today is 2022-05-01 we'll
|
||||
# get among other lines:
|
||||
# Fête du Travail (FR) + Di, < 1>Mai 2022
|
||||
# Jour de la Victoire (FR) + Di, : 8:Mai 2022 = +7 jours
|
||||
gcal --cc-holidays=fr --holiday-list=short | grep -E '<[0-9 ]{2}>' --quiet
|
||||
}
|
||||
|
||||
is_weekend() {
|
||||
day_of_week=$(date +%u)
|
||||
if [ "$day_of_week" != 6 ] && [ "$day_of_week" != 7 ]; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
is_workday() {
|
||||
if is_holiday || is_weekend; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
is_worktime() {
|
||||
if ! is_workday; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
hour=$(date +%H)
|
||||
if [ "${hour}" -lt 9 ] || { [ "${hour}" -ge 12 ] && [ "${hour}" -lt 14 ] ; } || [ "${hour}" -ge 18 ]; then
|
||||
return 1
|
||||
fi
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Source functions file
|
||||
# shellcheck source=./functions.sh
|
||||
source /usr/share/scripts/autosysadmin/functions.sh
|
||||
# shellcheck source=./restart_amavis.sh
|
||||
source /usr/share/scripts/autosysadmin/restart_amavis.sh
|
||||
|
||||
init_autosysadmin
|
||||
load_conf
|
||||
|
||||
test "${repair_amavis:=off}" = off && log_error_exit 'Script disabled, nothing to do here!'
|
||||
|
||||
# Verify if check_nrpe are not OK
|
||||
check_nrpe "check_amavis" && log_error_exit 'check_amavis is OK, nothing to do here!'
|
||||
|
||||
# Has it recently been run?
|
||||
get_argument "--no-delay" || is_too_soon
|
||||
|
||||
lockfile="/run/lock/repair_amavis"
|
||||
cleanup() {
|
||||
rm -f "${lockfile}"
|
||||
}
|
||||
trap 'cleanup' 0
|
||||
acquire_lock_or_exit "${lockfile}"
|
||||
|
||||
ensure_no_active_users_or_exit
|
||||
|
||||
# The actual work starts below !
|
||||
restart_amavis
|
||||
|
||||
hook_mail success
|
||||
AUTOSYSADMIN=1 /usr/share/scripts/evomaintenance.sh -m "$0: done" --no-commit --no-mail
|
|
@ -1,173 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Source functions file
|
||||
# shellcheck source=./functions.sh
|
||||
source /usr/share/scripts/autosysadmin/functions.sh
|
||||
|
||||
init_autosysadmin
|
||||
load_conf
|
||||
|
||||
test "${repair_disk:=off}" = off && log_error_exit 'Script disabled, nothing to do here!'
|
||||
|
||||
# Has it recently been run?
|
||||
is_too_soon
|
||||
|
||||
lockfile="/run/lock/repair_disk"
|
||||
cleanup() {
|
||||
rm -f "${lockfile}"
|
||||
}
|
||||
trap 'cleanup' 0
|
||||
acquire_lock_or_exit "${lockfile}"
|
||||
|
||||
ensure_no_active_users_or_exit
|
||||
|
||||
# The actual work starts below !
|
||||
|
||||
get_mountpoints() {
|
||||
# the $(...) get the check_disk1 command
|
||||
# the cut command selects the critical part of the check_disk1 output
|
||||
# the grep command extracts the mountpoints and available disk space
|
||||
# the last cut command selects the mountpoints
|
||||
$(grep check_disk1 /etc/nagios/nrpe.d/evolix.cfg | cut -d'=' -f2-) -e | cut -d'|' -f1 | grep -Eo '/[[:graph:]]* [0-9]+ [A-Z][A-Z]' | cut -f1 -d' '
|
||||
}
|
||||
|
||||
is_reserved-blocks() {
|
||||
fs_type="$(findmnt -n --output=fstype "$1")"
|
||||
if [ "${fs_type}" = "ext4" ];
|
||||
then
|
||||
device="$(findmnt -n --output=source "$1")"
|
||||
reserved_block_count="$(tune2fs -l "${device}" | grep 'Reserved block count' | awk -F':' '{ gsub (" ", "", $0); print $2}')"
|
||||
block_count="$(tune2fs -l "${device}" | grep 'Block count' | awk -F':' '{ gsub (" ", "", $0); print $2}')"
|
||||
percentage=$(awk "BEGIN { pc=100*${reserved_block_count}/${block_count}; i=int(pc); print (pc-i<0.5)?i:i+1 }")
|
||||
|
||||
log "Reserved blocks for $1 is curently at $percentage%"
|
||||
if [ "${percentage}" -gt "1" ]
|
||||
then
|
||||
log "Allowing tune2fs action to reduce the number of reserved blocks"
|
||||
return 0
|
||||
else
|
||||
log "Reserved blocks already at or bellow 1%, no automatic action possible"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
log "Filesystem for $1 partition is not ext4"
|
||||
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
change_reserved-blocks() {
|
||||
# We alwasy keep some reserved blocks to avoid missing some logs
|
||||
# https://gitea.evolix.org/evolix/autosysadmin/issues/22
|
||||
tune2fs -m 1 "$(findmnt -n --output=source "$1")"
|
||||
log_action "Reserved blocks for $1 changed to 1 percent"
|
||||
}
|
||||
|
||||
is_tmp_to_delete() {
|
||||
size="$(find /var/log/ -type f -ctime +1 -exec du {} \+ | awk '{s+=$1}END{print s / 1024}')"
|
||||
if [ -n "${size}" ]
|
||||
then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
is_log_to_delete() {
|
||||
size="$(find /var/log/ -type f -mtime +365 -exec du {} \+ | awk '{s+=$1}END{print s / 1024}')"
|
||||
if [ -n "${size}" ]
|
||||
then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
clean_apt_cache() {
|
||||
for lxc in $(du -ax /var | sort -nr | head -n10 | grep -E '/var/lib/lxc/php[0-9]+/rootfs/var/cache$' | grep -Eo 'php[0-9]+')
|
||||
do
|
||||
lxc-attach --name "${lxc}" -- apt-get clean
|
||||
log_action '[lxc/'"${lxc}"'] Clean apt cache'
|
||||
done
|
||||
case "$(du -sx /var/* | sort -rn | sed 's/^[0-9]\+[[:space:]]\+//;q')" in
|
||||
'/var/cache')
|
||||
apt-get clean
|
||||
log_action 'Clean apt cache'
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
clean_amavis_virusmails() {
|
||||
if du --inodes /var/lib/* | sort -n | tail -n3 | grep -q 'virusmails$'
|
||||
then
|
||||
find /var/lib/amavis/virusmails/ -type f -atime +30 -delete
|
||||
log_action 'Clean /var/lib/amavis/virusmails'
|
||||
fi
|
||||
}
|
||||
|
||||
for mountpoint in $(get_mountpoints)
|
||||
do
|
||||
case "${mountpoint}" in
|
||||
/var)
|
||||
#if is_log_to_delete
|
||||
#then
|
||||
# find /var/log/ -type f -mtime +365 -delete
|
||||
# log_action "$size Mo of disk space freed in /var"
|
||||
#fi
|
||||
if is_reserved-blocks /var
|
||||
then
|
||||
change_reserved-blocks /var
|
||||
clean_apt_cache
|
||||
clean_amavis_virusmails
|
||||
hook_mail success
|
||||
fi
|
||||
;;
|
||||
/tmp)
|
||||
#if is_tmp_to_delete
|
||||
#then
|
||||
# find /tmp/ -type f -ctime +1 -delete
|
||||
# log_action "$size Mo of disk space freed in /tmp"
|
||||
#fi
|
||||
if is_reserved-blocks /tmp
|
||||
then
|
||||
change_reserved-blocks /tmp
|
||||
hook_mail success
|
||||
fi
|
||||
;;
|
||||
/home)
|
||||
if is_reserved-blocks /home
|
||||
then
|
||||
change_reserved-blocks /home
|
||||
hook_mail success
|
||||
fi
|
||||
;;
|
||||
/srv)
|
||||
if is_reserved-blocks /srv
|
||||
then
|
||||
change_reserved-blocks /srv
|
||||
hook_mail success
|
||||
fi
|
||||
;;
|
||||
/filer)
|
||||
if is_reserved-blocks /filer
|
||||
then
|
||||
change_reserved-blocks /filer
|
||||
hook_mail success
|
||||
fi
|
||||
;;
|
||||
/)
|
||||
if is_reserved-blocks /
|
||||
then
|
||||
change_reserved-blocks /
|
||||
hook_mail success
|
||||
# Suggest remove old kernel ?
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# unknown
|
||||
log 'Unknown partition (or weird case) or nothing to do'
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
AUTOSYSADMIN=1 /usr/share/scripts/evomaintenance.sh -m "$0: done" --no-commit --no-mail
|
|
@ -1,57 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Source functions file
|
||||
# shellcheck source=./functions.sh
|
||||
source /usr/share/scripts/autosysadmin/functions.sh
|
||||
|
||||
init_autosysadmin
|
||||
load_conf
|
||||
|
||||
test "${repair_elasticsearch:=off}" = off && log_error_exit 'Script disabled, nothing to do here!'
|
||||
|
||||
# Has it recently been run?
|
||||
is_too_soon
|
||||
|
||||
lockfile="/run/lock/repair_elasticsearch"
|
||||
cleanup() {
|
||||
rm -f "${lockfile}"
|
||||
}
|
||||
trap 'cleanup' 0
|
||||
acquire_lock_or_exit "${lockfile}"
|
||||
|
||||
ensure_no_active_users_or_exit
|
||||
|
||||
# The actual work starts below !
|
||||
|
||||
elasticsearch_is_enabled() {
|
||||
systemd_list_units_enabled "elasticsearch.service"
|
||||
|
||||
}
|
||||
|
||||
elasticsearch_restart() {
|
||||
if ! timeout 60 systemctl restart elasticsearch.service > /dev/null
|
||||
then
|
||||
log_error_exit 'failed to restart elasticsearch'
|
||||
fi
|
||||
}
|
||||
|
||||
# Test functions
|
||||
test_elasticsearch_process_present() {
|
||||
pgrep -u elasticsearch > /dev/null
|
||||
}
|
||||
|
||||
if elasticsearch_is_enabled
|
||||
then
|
||||
if ! test_elasticsearch_process_present
|
||||
then
|
||||
log_action "Redémarrage de elasticsearch"
|
||||
elasticsearch_restart
|
||||
hook_mail success
|
||||
else
|
||||
log_error_exit "Elasticsearch process alive. Aborting"
|
||||
fi
|
||||
else
|
||||
log_error_exit "Elasticsearch is not enabled. Aborting"
|
||||
fi
|
||||
|
||||
AUTOSYSADMIN=1 /usr/share/scripts/evomaintenance.sh -m "$0: done" --no-commit --no-mail
|
|
@ -1,141 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Source functions file
|
||||
# shellcheck source=./functions.sh
|
||||
source /usr/share/scripts/autosysadmin/functions.sh
|
||||
|
||||
init_autosysadmin
|
||||
load_conf
|
||||
|
||||
test "${repair_http:=off}" = off && log_error_exit 'Script disabled, nothing to do here!'
|
||||
|
||||
# Has it recently been run?
|
||||
is_too_soon
|
||||
|
||||
lockfile="/run/lock/repair_http"
|
||||
cleanup() {
|
||||
rm -f "${lockfile}"
|
||||
}
|
||||
trap 'cleanup' 0
|
||||
acquire_lock_or_exit "${lockfile}"
|
||||
|
||||
ensure_no_active_users_or_exit
|
||||
|
||||
# The actual work starts below !
|
||||
|
||||
log_system_status
|
||||
|
||||
http_detect_service() {
|
||||
# check whether nginx, apache or both are supposed to be running
|
||||
if is_debian_jessie; then
|
||||
find /etc/rc2.d/
|
||||
else
|
||||
systemctl list-unit-files --state=enabled
|
||||
fi | awk '/nginx/ { nginx = 1 } /apache2/ { apache2 = 1 } END { if (nginx && apache2) { print "both" } else if (nginx) { print "nginx" } else if (apache2) { print "apache2" } }'
|
||||
# The previous awk command looks for two patterns: "nginx"
|
||||
# and "apache2". If a line matches the patterns, a variable
|
||||
# "nginx" or "apache2" is set to 1 (true). The "END" checks
|
||||
# if one or both patterns has been found.
|
||||
}
|
||||
|
||||
http_handle_apache() {
|
||||
# check syntax
|
||||
if ! apache2ctl -t > /dev/null 2> /dev/null
|
||||
then
|
||||
log_error_exit 'apache2 configuration syntax is not valid'
|
||||
fi
|
||||
|
||||
# try restart
|
||||
if ! timeout 20 systemctl restart apache2.service > /dev/null 2> /dev/null
|
||||
then
|
||||
log_error_exit 'failed to restart apache2'
|
||||
fi
|
||||
|
||||
log_action "Redémarrage de Apache"
|
||||
|
||||
internal_info "#### grep $(LANG=en_US.UTF-8 date '+%b %d') /home/*/log/error.log /var/log/apache2/*error.log (avec filtrage)"
|
||||
ERROR_LOG=$(grep "$(LANG=en_US.UTF-8 date '+%b %d')" /home/*/log/error.log /var/log/apache2/*error.log | grep -v -e "Got error 'PHP message:" -e "No matching DirectoryIndex" -e "client denied by server configuration" -e "server certificate does NOT include an ID which matches the server name" )
|
||||
internal_info "$ERROR_LOG"
|
||||
|
||||
}
|
||||
|
||||
http_handle_nginx() {
|
||||
# check syntax
|
||||
if ! nginx -t > /dev/null 2> /dev/null
|
||||
then
|
||||
log_error_exit 'nginx configuration syntax is not valid'
|
||||
fi
|
||||
|
||||
# try restart
|
||||
if ! timeout 20 systemctl restart nginx.service > /dev/null 2> /dev/null
|
||||
then
|
||||
log_error_exit 'failed to restart nginx'
|
||||
fi
|
||||
|
||||
log_action "Redémarrage de Nginx"
|
||||
}
|
||||
|
||||
http_handle_lxc_php() {
|
||||
# check whether containers are used for PHP and reboot them if so
|
||||
if systemd_list_units_enabled 'lxc'
|
||||
then
|
||||
for php in $(lxc-ls | grep 'php'); do
|
||||
lxc-stop -n "$php"
|
||||
lxc-start --daemon -n "$php"
|
||||
log_action "lxc-fpm - Redémarrage container ${php}"
|
||||
done
|
||||
|
||||
fi
|
||||
}
|
||||
|
||||
http_handle_fpm_php() {
|
||||
# check whether php-fpm is installed and restart it if so
|
||||
if enabled_units="$(systemd_list_units_enabled "php.*-fpm")"
|
||||
then
|
||||
systemctl restart "${enabled_units}"
|
||||
log_action 'php-fpm - Redémarrage de php-fpm'
|
||||
fi
|
||||
}
|
||||
|
||||
case "$(http_detect_service)" in
|
||||
nginx)
|
||||
|
||||
http_handle_nginx
|
||||
|
||||
http_handle_lxc_php
|
||||
http_handle_fpm_php
|
||||
|
||||
hook_mail success
|
||||
hook_mail internal_info
|
||||
;;
|
||||
|
||||
apache2)
|
||||
|
||||
http_handle_apache
|
||||
|
||||
http_handle_lxc_php
|
||||
http_handle_fpm_php
|
||||
|
||||
hook_mail success
|
||||
hook_mail internal_info
|
||||
;;
|
||||
|
||||
both)
|
||||
|
||||
http_handle_nginx
|
||||
http_handle_apache
|
||||
|
||||
http_handle_lxc_php
|
||||
http_handle_fpm_php
|
||||
|
||||
hook_mail success
|
||||
hook_mail internal_info
|
||||
;;
|
||||
|
||||
*)
|
||||
# unknown
|
||||
log 'nothing to do'
|
||||
;;
|
||||
esac
|
||||
|
||||
AUTOSYSADMIN=1 /usr/share/scripts/evomaintenance.sh -m "$0: done" --no-commit --no-mail
|
|
@ -1,71 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Source functions file
|
||||
# shellcheck source=./functions.sh
|
||||
source /usr/share/scripts/autosysadmin/functions.sh
|
||||
|
||||
init_autosysadmin
|
||||
load_conf
|
||||
|
||||
test "${repair_mysql:=off}" = off && log_error_exit 'Script disabled, nothing to do here!'
|
||||
|
||||
# Has it recently been run?
|
||||
is_too_soon
|
||||
|
||||
lockfile="/run/lock/repair_mysql"
|
||||
cleanup() {
|
||||
rm -f "${lockfile}"
|
||||
}
|
||||
trap 'cleanup' 0
|
||||
acquire_lock_or_exit "${lockfile}"
|
||||
|
||||
ensure_no_active_users_or_exit
|
||||
|
||||
# The actual work starts below !
|
||||
|
||||
log_system_status
|
||||
|
||||
mysql_is_enabled() {
|
||||
if is_debian_jessie
|
||||
then
|
||||
find /etc/rc2.d/ -name '*mysql*' > /dev/null
|
||||
else
|
||||
systemd_list_units_enabled "mysql.service"
|
||||
fi
|
||||
}
|
||||
|
||||
mysql_restart() {
|
||||
if is_debian_jessie
|
||||
then
|
||||
if ! timeout 60 /etc/init.d/mysql restart > /dev/null
|
||||
then
|
||||
log_error_exit 'failed to restart mysql'
|
||||
fi
|
||||
else
|
||||
if ! timeout 60 systemctl restart mysql.service > /dev/null
|
||||
then
|
||||
log_error_exit 'failed to restart mysql'
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Test functions
|
||||
test_mysql_process_present() {
|
||||
pgrep -u mysql mysqld > /dev/null
|
||||
}
|
||||
|
||||
if mysql_is_enabled
|
||||
then
|
||||
if ! test_mysql_process_present
|
||||
then
|
||||
log_action "Redémarrage de MySQL"
|
||||
mysql_restart
|
||||
hook_mail success
|
||||
else
|
||||
log_error_exit "mysqld process alive. Aborting"
|
||||
fi
|
||||
else
|
||||
log_error_exit "MySQL/MariaDB not enabled. Aborting"
|
||||
fi
|
||||
|
||||
AUTOSYSADMIN=1 /usr/share/scripts/evomaintenance.sh -m "$0: done" --no-commit --no-mail
|
|
@ -1,61 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Source functions file
|
||||
# shellcheck source=./functions.sh
|
||||
source /usr/share/scripts/autosysadmin/functions.sh
|
||||
|
||||
init_autosysadmin
|
||||
load_conf
|
||||
|
||||
test "${repair_opendkim:=off}" = off && log_error_exit 'Script disabled, nothing to do here!'
|
||||
|
||||
# Has it recently been run?
|
||||
is_too_soon
|
||||
|
||||
lockfile="/run/lock/repair_opendkim"
|
||||
cleanup() {
|
||||
rm -f "${lockfile}"
|
||||
}
|
||||
trap 'cleanup' 0
|
||||
acquire_lock_or_exit "${lockfile}"
|
||||
|
||||
ensure_no_active_users_or_exit
|
||||
|
||||
log_system_status
|
||||
|
||||
# Functions dedicated to this repair script
|
||||
|
||||
opendkim_is_enabled() {
|
||||
systemd_list_units_enabled "opendkim.service"
|
||||
|
||||
}
|
||||
|
||||
opendkim_restart() {
|
||||
if ! timeout 60 systemctl restart opendkim.service > /dev/null
|
||||
then
|
||||
log_error_exit 'failed to restart opendkim'
|
||||
fi
|
||||
}
|
||||
|
||||
opendkim_test_process_present() {
|
||||
pgrep -u opendkim > /dev/null
|
||||
}
|
||||
|
||||
|
||||
# Main logic
|
||||
|
||||
if opendkim_is_enabled
|
||||
then
|
||||
if ! opendkim_test_process_present
|
||||
then
|
||||
log_action "Redémarrage de opendkim"
|
||||
opendkim_restart
|
||||
hook_mail success
|
||||
else
|
||||
log_error_exit "opendkim process alive. Aborting"
|
||||
fi
|
||||
else
|
||||
log_error_exit "opendkim is not enabled. Aborting"
|
||||
fi
|
||||
|
||||
AUTOSYSADMIN=1 /usr/share/scripts/evomaintenance.sh -m "$0: done" --no-commit --no-mail
|
|
@ -1,53 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Source functions file
|
||||
# shellcheck source=./functions.sh
|
||||
source /usr/share/scripts/autosysadmin/functions.sh
|
||||
|
||||
init_autosysadmin
|
||||
load_conf
|
||||
|
||||
test "${repair_php_fpm56:=off}" = off && log_error_exit 'Script disabled, nothing to do here!'
|
||||
|
||||
# Has it recently been run?
|
||||
is_too_soon
|
||||
|
||||
lockfile="/run/lock/repair_http"
|
||||
cleanup() {
|
||||
rm -f "${lockfile}"
|
||||
}
|
||||
trap 'cleanup' 0
|
||||
acquire_lock_or_exit "${lockfile}" 15s
|
||||
|
||||
ensure_no_active_users_or_exit
|
||||
|
||||
# The actual work starts below !
|
||||
|
||||
log_system_status
|
||||
log_check_php_fpm
|
||||
|
||||
if systemd_list_units_enabled 'lxc'
|
||||
then
|
||||
|
||||
if lxc-ls | grep -q php56
|
||||
then
|
||||
lxc-stop -n php56
|
||||
lxc-start --daemon -n php56
|
||||
log_action "lxc-fpm - Redémarrage container php56"
|
||||
|
||||
internal_info "#### tail /var/lib/lxc/php56/rootfs/var/log/php5-fpm.log"
|
||||
FPM_LOG=$(tail /var/lib/lxc/php56/rootfs/var/log/php5-fpm.log)
|
||||
internal_info "$FPM_LOG" "$(read_log_system_status)"
|
||||
|
||||
hook_mail success
|
||||
hook_mail internal_info
|
||||
|
||||
else
|
||||
log 'Not possible :v'
|
||||
fi
|
||||
|
||||
else
|
||||
log 'Error, not a multi-php install'
|
||||
fi
|
||||
|
||||
AUTOSYSADMIN=1 /usr/share/scripts/evomaintenance.sh -m "$0: done" --no-commit --no-mail
|
|
@ -1,53 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Source functions file
|
||||
# shellcheck source=./functions.sh
|
||||
source /usr/share/scripts/autosysadmin/functions.sh
|
||||
|
||||
init_autosysadmin
|
||||
load_conf
|
||||
|
||||
test "${repair_php_fpm70:=off}" = off && log_error_exit 'Script disabled, nothing to do here!'
|
||||
|
||||
# Has it recently been run?
|
||||
is_too_soon
|
||||
|
||||
lockfile="/run/lock/repair_http"
|
||||
cleanup() {
|
||||
rm -f "${lockfile}"
|
||||
}
|
||||
trap 'cleanup' 0
|
||||
acquire_lock_or_exit "${lockfile}" 15s
|
||||
|
||||
ensure_no_active_users_or_exit
|
||||
|
||||
# The actual work starts below !
|
||||
|
||||
log_system_status
|
||||
log_check_php_fpm
|
||||
|
||||
if systemd_list_units_enabled 'lxc'
|
||||
then
|
||||
|
||||
if lxc-ls | grep -q php70
|
||||
then
|
||||
lxc-stop -n php70
|
||||
lxc-start --daemon -n php70
|
||||
log_action "lxc-fpm - Redémarrage container php70"
|
||||
|
||||
internal_info "#### tail /var/lib/lxc/php70/rootfs/var/log/php7.0-fpm.log"
|
||||
FPM_LOG=$(tail /var/lib/lxc/php70/rootfs/var/log/php7.0-fpm.log)
|
||||
internal_info "$FPM_LOG" "$(read_log_system_status)"
|
||||
|
||||
hook_mail success
|
||||
hook_mail internal_info
|
||||
|
||||
else
|
||||
log 'Not possible :v'
|
||||
fi
|
||||
|
||||
else
|
||||
log 'Error, not a multi-php install'
|
||||
fi
|
||||
|
||||
AUTOSYSADMIN=1 /usr/share/scripts/evomaintenance.sh -m "$0: done" --no-commit --no-mail
|
|
@ -1,53 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Source functions file
|
||||
# shellcheck source=./functions.sh
|
||||
source /usr/share/scripts/autosysadmin/functions.sh
|
||||
|
||||
init_autosysadmin
|
||||
load_conf
|
||||
|
||||
test "${repair_php_fpm73:=off}" = off && log_error_exit 'Script disabled, nothing to do here!'
|
||||
|
||||
# Has it recently been run?
|
||||
is_too_soon
|
||||
|
||||
lockfile="/run/lock/repair_http"
|
||||
cleanup() {
|
||||
rm -f "${lockfile}"
|
||||
}
|
||||
trap 'cleanup' 0
|
||||
acquire_lock_or_exit "${lockfile}" 15s
|
||||
|
||||
ensure_no_active_users_or_exit
|
||||
|
||||
# The actual work starts below !
|
||||
|
||||
log_system_status
|
||||
log_check_php_fpm
|
||||
|
||||
if systemd_list_units_enabled 'lxc'
|
||||
then
|
||||
|
||||
if lxc-ls | grep -q php73
|
||||
then
|
||||
lxc-stop -n php73
|
||||
lxc-start --daemon -n php73
|
||||
log_action "lxc-fpm - Redémarrage container php73"
|
||||
|
||||
internal_info "#### tail /var/lib/lxc/php73/rootfs/var/log/php7.3-fpm.log"
|
||||
FPM_LOG=$(tail /var/lib/lxc/php73/rootfs/var/log/php7.3-fpm.log)
|
||||
internal_info "$FPM_LOG" "$(read_log_system_status)"
|
||||
|
||||
hook_mail success
|
||||
hook_mail internal_info
|
||||
|
||||
else
|
||||
log 'Not possible :v'
|
||||
fi
|
||||
|
||||
else
|
||||
log 'Error, not a multi-php install'
|
||||
fi
|
||||
|
||||
AUTOSYSADMIN=1 /usr/share/scripts/evomaintenance.sh -m "$0: done" --no-commit --no-mail
|
|
@ -1,53 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Source functions file
|
||||
# shellcheck source=./functions.sh
|
||||
source /usr/share/scripts/autosysadmin/functions.sh
|
||||
|
||||
init_autosysadmin
|
||||
load_conf
|
||||
|
||||
test "${repair_php_fpm74:=off}" = off && log_error_exit 'Script disabled, nothing to do here!'
|
||||
|
||||
# Has it recently been run?
|
||||
is_too_soon
|
||||
|
||||
lockfile="/run/lock/repair_http"
|
||||
cleanup() {
|
||||
rm -f "${lockfile}"
|
||||
}
|
||||
trap 'cleanup' 0
|
||||
acquire_lock_or_exit "${lockfile}" 15s
|
||||
|
||||
ensure_no_active_users_or_exit
|
||||
|
||||
# The actual work starts below !
|
||||
|
||||
log_system_status
|
||||
log_check_php_fpm
|
||||
|
||||
if systemd_list_units_enabled 'lxc'
|
||||
then
|
||||
|
||||
if lxc-ls | grep -q php74
|
||||
then
|
||||
lxc-stop -n php74
|
||||
lxc-start --daemon -n php74
|
||||
log_action "lxc-fpm - Redémarrage container php74"
|
||||
|
||||
internal_info "#### tail /var/lib/lxc/php74/rootfs/var/log/php7.4-fpm.log"
|
||||
FPM_LOG=$(tail /var/lib/lxc/php74/rootfs/var/log/php7.4-fpm.log)
|
||||
internal_info "$FPM_LOG" "$(read_log_system_status)"
|
||||
|
||||
hook_mail success
|
||||
hook_mail internal_info
|
||||
|
||||
else
|
||||
log 'Not possible :v'
|
||||
fi
|
||||
|
||||
else
|
||||
log 'Error, not a multi-php install'
|
||||
fi
|
||||
|
||||
AUTOSYSADMIN=1 /usr/share/scripts/evomaintenance.sh -m "$0: done" --no-commit --no-mail
|
|
@ -1,53 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Source functions file
|
||||
# shellcheck source=./functions.sh
|
||||
source /usr/share/scripts/autosysadmin/functions.sh
|
||||
|
||||
init_autosysadmin
|
||||
load_conf
|
||||
|
||||
test "${repair_php_fpm80:=off}" = off && log_error_exit 'Script disabled, nothing to do here!'
|
||||
|
||||
# Has it recently been run?
|
||||
is_too_soon
|
||||
|
||||
lockfile="/run/lock/repair_http"
|
||||
cleanup() {
|
||||
rm -f "${lockfile}"
|
||||
}
|
||||
trap 'cleanup' 0
|
||||
acquire_lock_or_exit "${lockfile}" 15s
|
||||
|
||||
ensure_no_active_users_or_exit
|
||||
|
||||
# The actual work starts below !
|
||||
|
||||
log_system_status
|
||||
log_check_php_fpm
|
||||
|
||||
if systemd_list_units_enabled 'lxc'
|
||||
then
|
||||
|
||||
if lxc-ls | grep -q php80
|
||||
then
|
||||
lxc-stop -n php80
|
||||
lxc-start --daemon -n php80
|
||||
log_action "lxc-fpm - Redémarrage container php80"
|
||||
|
||||
internal_info "#### tail /var/lib/lxc/php80/rootfs/var/log/php8.0-fpm.log"
|
||||
FPM_LOG=$(tail /var/lib/lxc/php80/rootfs/var/log/php8.0-fpm.log)
|
||||
internal_info "$FPM_LOG" "$(read_log_system_status)"
|
||||
|
||||
hook_mail success
|
||||
hook_mail internal_info
|
||||
|
||||
else
|
||||
log 'Not possible :v'
|
||||
fi
|
||||
|
||||
else
|
||||
log 'Error, not a multi-php install'
|
||||
fi
|
||||
|
||||
AUTOSYSADMIN=1 /usr/share/scripts/evomaintenance.sh -m "$0: done" --no-commit --no-mail
|
|
@ -1,53 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Source functions file
|
||||
# shellcheck source=./functions.sh
|
||||
source /usr/share/scripts/autosysadmin/functions.sh
|
||||
|
||||
init_autosysadmin
|
||||
load_conf
|
||||
|
||||
test "${repair_php_fpm81:=off}" = off && log_error_exit 'Script disabled, nothing to do here!'
|
||||
|
||||
# Has it recently been run?
|
||||
is_too_soon
|
||||
|
||||
lockfile="/run/lock/repair_http"
|
||||
cleanup() {
|
||||
rm -f "${lockfile}"
|
||||
}
|
||||
trap 'cleanup' 0
|
||||
acquire_lock_or_exit "${lockfile}" 15s
|
||||
|
||||
ensure_no_active_users_or_exit
|
||||
|
||||
# The actual work starts below !
|
||||
|
||||
log_system_status
|
||||
log_check_php_fpm
|
||||
|
||||
if systemd_list_units_enabled 'lxc'
|
||||
then
|
||||
|
||||
if lxc-ls | grep -q php81
|
||||
then
|
||||
lxc-stop -n php81
|
||||
lxc-start --daemon -n php81
|
||||
log_action "lxc-fpm - Redémarrage container php81"
|
||||
|
||||
internal_info "#### tail /var/lib/lxc/php81/rootfs/var/log/php8.1-fpm.log"
|
||||
FPM_LOG=$(tail /var/lib/lxc/php81/rootfs/var/log/php8.1-fpm.log)
|
||||
internal_info "$FPM_LOG" "$(read_log_system_status)"
|
||||
|
||||
hook_mail success
|
||||
hook_mail internal_info
|
||||
|
||||
else
|
||||
log 'Not possible :v'
|
||||
fi
|
||||
|
||||
else
|
||||
log 'Error, not a multi-php install'
|
||||
fi
|
||||
|
||||
AUTOSYSADMIN=1 /usr/share/scripts/evomaintenance.sh -m "$0: done" --no-commit --no-mail
|
|
@ -1,53 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Source functions file
|
||||
# shellcheck source=./functions.sh
|
||||
source /usr/share/scripts/autosysadmin/functions.sh
|
||||
|
||||
init_autosysadmin
|
||||
load_conf
|
||||
|
||||
test "${repair_php_fpm82:=off}" = off && log_error_exit 'Script disabled, nothing to do here!'
|
||||
|
||||
# Has it recently been run?
|
||||
is_too_soon
|
||||
|
||||
lockfile="/run/lock/repair_http"
|
||||
cleanup() {
|
||||
rm -f "${lockfile}"
|
||||
}
|
||||
trap 'cleanup' 0
|
||||
acquire_lock_or_exit "${lockfile}" 15s
|
||||
|
||||
ensure_no_active_users_or_exit
|
||||
|
||||
# The actual work starts below !
|
||||
|
||||
log_system_status
|
||||
log_check_php_fpm
|
||||
|
||||
if systemd_list_units_enabled 'lxc'
|
||||
then
|
||||
|
||||
if lxc-ls | grep -q php82
|
||||
then
|
||||
lxc-stop -n php82
|
||||
lxc-start --daemon -n php82
|
||||
log_action "lxc-fpm - Redémarrage container php82"
|
||||
|
||||
internal_info "#### tail /var/lib/lxc/php82/rootfs/var/log/php8.2-fpm.log"
|
||||
FPM_LOG=$(tail /var/lib/lxc/php82/rootfs/var/log/php8.2-fpm.log)
|
||||
internal_info "$FPM_LOG" "$(read_log_system_status)"
|
||||
|
||||
hook_mail success
|
||||
hook_mail internal_info
|
||||
|
||||
else
|
||||
log 'Not possible :v'
|
||||
fi
|
||||
|
||||
else
|
||||
log 'Error, not a multi-php install'
|
||||
fi
|
||||
|
||||
AUTOSYSADMIN=1 /usr/share/scripts/evomaintenance.sh -m "$0: done" --no-commit --no-mail
|
|
@ -1,53 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Source functions file
|
||||
# shellcheck source=./functions.sh
|
||||
source /usr/share/scripts/autosysadmin/functions.sh
|
||||
|
||||
init_autosysadmin
|
||||
load_conf
|
||||
|
||||
test "${repair_php_fpm83:=off}" = off && log_error_exit 'Script disabled, nothing to do here!'
|
||||
|
||||
# Has it recently been run?
|
||||
is_too_soon
|
||||
|
||||
lockfile="/run/lock/repair_http"
|
||||
cleanup() {
|
||||
rm -f "${lockfile}"
|
||||
}
|
||||
trap 'cleanup' 0
|
||||
acquire_lock_or_exit "${lockfile}" 15s
|
||||
|
||||
ensure_no_active_users_or_exit
|
||||
|
||||
# The actual work starts below !
|
||||
|
||||
log_system_status
|
||||
log_check_php_fpm
|
||||
|
||||
if systemd_list_units_enabled 'lxc'
|
||||
then
|
||||
|
||||
if lxc-ls | grep -q php83
|
||||
then
|
||||
lxc-stop -n php83
|
||||
lxc-start --daemon -n php83
|
||||
log_action "lxc-fpm - Redémarrage container php83"
|
||||
|
||||
internal_info "#### tail /var/lib/lxc/php83/rootfs/var/log/php8.3-fpm.log"
|
||||
FPM_LOG=$(tail /var/lib/lxc/php83/rootfs/var/log/php8.3-fpm.log)
|
||||
internal_info "$FPM_LOG" "$(read_log_system_status)"
|
||||
|
||||
hook_mail success
|
||||
hook_mail internal_info
|
||||
|
||||
else
|
||||
log 'Not possible :v'
|
||||
fi
|
||||
|
||||
else
|
||||
log 'Error, not a multi-php install'
|
||||
fi
|
||||
|
||||
AUTOSYSADMIN=1 /usr/share/scripts/evomaintenance.sh -m "$0: done" --no-commit --no-mail
|
|
@ -1,58 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Source functions file
|
||||
# shellcheck source=./functions.sh
|
||||
source /usr/share/scripts/autosysadmin/functions.sh
|
||||
|
||||
init_autosysadmin
|
||||
load_conf
|
||||
|
||||
test "${repair_redis:=off}" = off && log_error_exit 'Script disabled, nothing to do here!'
|
||||
|
||||
# Has it recently been run?
|
||||
is_too_soon
|
||||
|
||||
lockfile="/run/lock/repair_redis"
|
||||
cleanup() {
|
||||
rm -f "${lockfile}"
|
||||
}
|
||||
trap 'cleanup' 0
|
||||
acquire_lock_or_exit "${lockfile}"
|
||||
|
||||
ensure_no_active_users_or_exit
|
||||
|
||||
# The actual work starts below !
|
||||
|
||||
handle_redis() {
|
||||
for service in $(systemd_list_service_failed redis*)
|
||||
do
|
||||
# ne rien faire si le service est désactivé
|
||||
if ! systemctl is-enabled --quiet "${service}"
|
||||
then
|
||||
continue
|
||||
fi
|
||||
|
||||
# ne rien faire si le service est actif
|
||||
if systemctl is-active --quiet "${service}"
|
||||
then
|
||||
continue
|
||||
fi
|
||||
|
||||
if ! timeout 20 systemctl restart redis.service > /dev/null 2> /dev/null
|
||||
then
|
||||
log_error_exit "failed to restart redis ${service}"
|
||||
fi
|
||||
|
||||
log_action "Redémarrer service ${service}"
|
||||
done
|
||||
}
|
||||
|
||||
if ( systemd_list_units_enabled 'redis.*\.service$' ) > /dev/null
|
||||
then
|
||||
handle_redis
|
||||
hook_mail success
|
||||
else
|
||||
log 'Error: redis service is not enabled'
|
||||
fi
|
||||
|
||||
AUTOSYSADMIN=1 /usr/share/scripts/evomaintenance.sh -m "$0: done" --no-commit --no-mail
|
|
@ -1,63 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Source functions file
|
||||
# shellcheck source=./functions.sh
|
||||
source /usr/share/scripts/autosysadmin/functions.sh
|
||||
|
||||
init_autosysadmin
|
||||
load_conf
|
||||
|
||||
# Comment this line to enable
|
||||
repair_template=off
|
||||
test "${repair_template:=off}" = off && log_error_exit 'Script disabled, nothing to do here!'
|
||||
|
||||
# Has it recently been run?
|
||||
is_too_soon
|
||||
|
||||
lockfile="/run/lock/repair_template"
|
||||
cleanup() {
|
||||
rm -f "${lockfile}"
|
||||
}
|
||||
trap 'cleanup' 0
|
||||
acquire_lock_or_exit "${lockfile}"
|
||||
|
||||
ensure_no_active_users_or_exit
|
||||
|
||||
log_system_status
|
||||
|
||||
# Functions dedicated to this repair script
|
||||
|
||||
template_is_enabled() {
|
||||
systemd_list_units_enabled "template.service"
|
||||
|
||||
}
|
||||
|
||||
template_restart() {
|
||||
if ! timeout 60 systemctl restart template.service > /dev/null
|
||||
then
|
||||
log_error_exit 'failed to restart template'
|
||||
fi
|
||||
}
|
||||
|
||||
template_test_process_present() {
|
||||
pgrep -u template > /dev/null
|
||||
}
|
||||
|
||||
|
||||
# Main logic
|
||||
|
||||
if template_is_enabled
|
||||
then
|
||||
if ! template_test_process_present
|
||||
then
|
||||
log_action "Redémarrage de template"
|
||||
template_restart
|
||||
hook_mail success
|
||||
else
|
||||
log_error_exit "template process alive. Aborting"
|
||||
fi
|
||||
else
|
||||
log_error_exit "template is not enabled. Aborting"
|
||||
fi
|
||||
|
||||
AUTOSYSADMIN=1 /usr/share/scripts/evomaintenance.sh -m "$0: done" --no-commit --no-mail
|
|
@ -1,35 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
restart_amavis() {
|
||||
/etc/init.d/amavis stop 2>/dev/null
|
||||
/etc/init.d/clamav-freshclam stop 2>/dev/null
|
||||
/etc/init.d/clamav-daemon stop 2>/dev/null
|
||||
|
||||
if systemctl is-enabled --quiet 'clamav-freshclam.service'
|
||||
then
|
||||
freshclam
|
||||
log_action "Mise à jour des définitions antivirus"
|
||||
fi
|
||||
|
||||
if systemctl is-enabled --quiet 'clamav-daemon.service'
|
||||
then
|
||||
/etc/init.d/clamav-daemon start
|
||||
log_action "Redémarrage de clamav-daemon"
|
||||
else
|
||||
log 'Error, clamav not installed'
|
||||
fi
|
||||
|
||||
if systemctl is-enabled --quiet 'clamav-freshclam.service'
|
||||
then
|
||||
/etc/init.d/clamav-freshclam start
|
||||
log_action "Redémarrage de clamav-freshclam"
|
||||
fi
|
||||
|
||||
if systemctl is-enabled --quiet 'amavis.service'
|
||||
then
|
||||
/etc/init.d/amavis start
|
||||
log_action "Redémarrage de amavis"
|
||||
else
|
||||
log 'Error, amavis not installed'
|
||||
fi
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
---
|
||||
|
||||
- name: Restart nagios-nrpe-server
|
||||
ansible.builtin.service:
|
||||
name: nagios-nrpe-server
|
||||
state: restarted
|
||||
|
||||
- name: Restart nrpe
|
||||
ansible.builtin.service:
|
||||
name: nrpe
|
||||
state: restarted
|
||||
|
||||
- name: Restart rsyslog
|
||||
ansible.builtin.service:
|
||||
name: rsyslog
|
||||
state: restarted
|
|
@ -1,61 +0,0 @@
|
|||
---
|
||||
- name: "Remount /usr if needed"
|
||||
ansible.builtin.import_role:
|
||||
name: remount-usr
|
||||
|
||||
- name: Create autosysadmin directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ autosysadmin_dir }}"
|
||||
state: directory
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0750"
|
||||
tags:
|
||||
- autosysadmin
|
||||
|
||||
- name: Copy scripts
|
||||
ansible.builtin.copy:
|
||||
src: "files/scripts/{{ item }}"
|
||||
dest: "{{ autosysadmin_dir }}/{{ item }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0750"
|
||||
loop:
|
||||
- "functions.sh"
|
||||
- "restart_amavis.sh"
|
||||
- "repair_amavis.sh"
|
||||
- "repair_disk.sh"
|
||||
- "repair_elasticsearch.sh"
|
||||
- "repair_http.sh"
|
||||
- "repair_mysql.sh"
|
||||
- "repair_php_fpm56.sh"
|
||||
- "repair_php_fpm70.sh"
|
||||
- "repair_php_fpm73.sh"
|
||||
- "repair_php_fpm74.sh"
|
||||
- "repair_php_fpm80.sh"
|
||||
- "repair_php_fpm81.sh"
|
||||
- "repair_php_fpm82.sh"
|
||||
- "repair_php_fpm83.sh"
|
||||
- "repair_tomcat_instance.sh"
|
||||
tags:
|
||||
- autosysadmin
|
||||
|
||||
- name: Ensure /etc/evolinux folder exists
|
||||
ansible.builtin.file:
|
||||
path: "/etc/evolinux"
|
||||
state: directory
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0700"
|
||||
tags:
|
||||
- autosysadmin
|
||||
|
||||
- name: Copy the configuration file
|
||||
ansible.builtin.template:
|
||||
src: "autosysadmin.cf.j2"
|
||||
dest: "/etc/evolinux/autosysadmin"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0640"
|
||||
tags:
|
||||
- autosysadmin
|
|
@ -1,37 +0,0 @@
|
|||
---
|
||||
- name: Install dependencies
|
||||
ansible.builtin.import_tasks: dependencies.yml
|
||||
tags:
|
||||
- autosysadmin
|
||||
|
||||
- name: Install autosysadmin scripts
|
||||
ansible.builtin.import_tasks: autosysadmin_scripts.yml
|
||||
tags:
|
||||
- autosysadmin
|
||||
|
||||
- name: Amend NRPE configuration
|
||||
ansible.builtin.import_tasks: nrpe.yml
|
||||
tags:
|
||||
- autosysadmin
|
||||
|
||||
- name: Amend sudo configuration
|
||||
ansible.builtin.import_tasks: sudo.yml
|
||||
tags:
|
||||
- autosysadmin
|
||||
|
||||
- name: Amend rsyslog configuration
|
||||
ansible.builtin.import_tasks: rsyslog.yml
|
||||
tags:
|
||||
- autosysadmin
|
||||
|
||||
- name: Amend logrotate configuration
|
||||
ansible.builtin.import_tasks: logrotate.yml
|
||||
tags:
|
||||
- autosysadmin
|
||||
|
||||
- name: Install last version of dump-server-state
|
||||
ansible.builtin.import_role:
|
||||
name: evolinux-base
|
||||
tasks_from: dump-server-state.yml
|
||||
tags:
|
||||
- autosysadmin
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
- name: Custom configuration is present
|
||||
ansible.builtin.template:
|
||||
src: autosysadmin.cfg.j2
|
||||
dest: /etc/nagios/nrpe.d/autosysadmin.cfg
|
||||
group: nagios
|
||||
mode: "0640"
|
||||
force: true
|
||||
notify: Restart nagios-nrpe-server
|
||||
tags:
|
||||
- autosysadmin
|
|
@ -1,74 +0,0 @@
|
|||
#
|
||||
# Ansible managed - DO NOT MODIFY, your changes will be **overwritten** !
|
||||
#
|
||||
# Update the hosts_vars/group_vars on the autosysadmin project
|
||||
# https://gitea.evolix.org/evolix/autosysadmin/src/branch/master
|
||||
#
|
||||
|
||||
# Configuration for autosysadmin
|
||||
# Use this file to change configuration values defined in repair scripts
|
||||
# Ex : repair_http=off
|
||||
|
||||
{% if repair_amavis == "off" %}
|
||||
repair_amavis=off
|
||||
{% endif %}
|
||||
|
||||
{% if repair_disk == "off" %}
|
||||
repair_disk=off
|
||||
{% endif %}
|
||||
|
||||
{% if repair_elasticsearch == "off" %}
|
||||
repair_elasticsearch=off
|
||||
{% endif %}
|
||||
|
||||
{% if repair_http == "off" %}
|
||||
repair_http=off
|
||||
{% endif %}
|
||||
|
||||
{% if repair_mysql == "off" %}
|
||||
repair_mysql=off
|
||||
{% endif %}
|
||||
|
||||
{% if repair_opendkim == "off" %}
|
||||
repair_opendkim=off
|
||||
{% endif %}
|
||||
|
||||
{% if repair_php_fpm56 == "off" %}
|
||||
repair_php_fpm56=off
|
||||
{% endif %}
|
||||
|
||||
{% if repair_php_fpm70 == "off" %}
|
||||
repair_php_fpm70=off
|
||||
{% endif %}
|
||||
|
||||
{% if repair_php_fpm73 == "off" %}
|
||||
repair_php_fpm73=off
|
||||
{% endif %}
|
||||
|
||||
{% if repair_php_fpm74 == "off" %}
|
||||
repair_php_fpm74=off
|
||||
{% endif %}
|
||||
|
||||
{% if repair_php_fpm80 == "off" %}
|
||||
repair_php_fpm80=off
|
||||
{% endif %}
|
||||
|
||||
{% if repair_php_fpm81 == "off" %}
|
||||
repair_php_fpm81=off
|
||||
{% endif %}
|
||||
|
||||
{% if repair_php_fpm82 == "off" %}
|
||||
repair_php_fpm82=off
|
||||
{% endif %}
|
||||
|
||||
{% if repair_php_fpm83 == "off" %}
|
||||
repair_php_fpm83=off
|
||||
{% endif %}
|
||||
|
||||
{% if repair_redis == "off" %}
|
||||
repair_redis=off
|
||||
{% endif %}
|
||||
|
||||
{% if repair_tomcat_instance == "off" %}
|
||||
repair_tomcat_instance=off
|
||||
{% endif %}
|
|
@ -1,22 +0,0 @@
|
|||
#
|
||||
# Ansible managed - DO NOT MODIFY, your changes will be overwritten !
|
||||
#
|
||||
|
||||
# Autosysadmin repair commands
|
||||
command[repair_amavis]=sudo {{ autosysadmin_dir }}/repair_amavis.sh
|
||||
command[repair_disk]=sudo {{ autosysadmin_dir }}/repair_disk.sh
|
||||
command[repair_elasticsearch]=sudo {{ autosysadmin_dir }}/repair_elasticsearch.sh
|
||||
command[repair_http]=sudo {{ autosysadmin_dir }}/repair_http.sh
|
||||
command[repair_mysql]=sudo {{ autosysadmin_dir }}/repair_mysql.sh
|
||||
command[repair_opendkim]=sudo {{ autosysadmin_dir }}/repair_opendkim.sh
|
||||
command[repair_php_fpm56]=sudo {{ autosysadmin_dir }}/repair_php_fpm56.sh
|
||||
command[repair_php_fpm70]=sudo {{ autosysadmin_dir }}/repair_php_fpm70.sh
|
||||
command[repair_php_fpm73]=sudo {{ autosysadmin_dir }}/repair_php_fpm73.sh
|
||||
command[repair_php_fpm74]=sudo {{ autosysadmin_dir }}/repair_php_fpm74.sh
|
||||
command[repair_php_fpm80]=sudo {{ autosysadmin_dir }}/repair_php_fpm80.sh
|
||||
command[repair_php_fpm81]=sudo {{ autosysadmin_dir }}/repair_php_fpm81.sh
|
||||
command[repair_php_fpm82]=sudo {{ autosysadmin_dir }}/repair_php_fpm82.sh
|
||||
command[repair_php_fpm83]=sudo {{ autosysadmin_dir }}/repair_php_fpm83.sh
|
||||
command[repair_redis]=sudo {{ autosysadmin_dir }}/repair_redis.sh
|
||||
command[repair_tomcat_instance]=sudo {{ autosysadmin_dir }}/repair_tomcat_instance.sh
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
#
|
||||
# Ansible managed - DO NOT MODIFY, your changes will be overwritten !
|
||||
#
|
||||
|
||||
nagios ALL = NOPASSWD: {{ autosysadmin_dir }}/repair_amavis.sh
|
||||
nagios ALL = NOPASSWD: {{ autosysadmin_dir }}/repair_disk.sh
|
||||
nagios ALL = NOPASSWD: {{ autosysadmin_dir }}/repair_elasticsearch.sh
|
||||
nagios ALL = NOPASSWD: {{ autosysadmin_dir }}/repair_http.sh
|
||||
nagios ALL = NOPASSWD: {{ autosysadmin_dir }}/repair_mysql.sh
|
||||
nagios ALL = NOPASSWD: {{ autosysadmin_dir }}/repair_opendkim.sh
|
||||
nagios ALL = NOPASSWD: {{ autosysadmin_dir }}/repair_php_fpm56.sh
|
||||
nagios ALL = NOPASSWD: {{ autosysadmin_dir }}/repair_php_fpm70.sh
|
||||
nagios ALL = NOPASSWD: {{ autosysadmin_dir }}/repair_php_fpm73.sh
|
||||
nagios ALL = NOPASSWD: {{ autosysadmin_dir }}/repair_php_fpm74.sh
|
||||
nagios ALL = NOPASSWD: {{ autosysadmin_dir }}/repair_php_fpm80.sh
|
||||
nagios ALL = NOPASSWD: {{ autosysadmin_dir }}/repair_php_fpm81.sh
|
||||
nagios ALL = NOPASSWD: {{ autosysadmin_dir }}/repair_php_fpm82.sh
|
||||
nagios ALL = NOPASSWD: {{ autosysadmin_dir }}/repair_php_fpm83.sh
|
||||
nagios ALL = NOPASSWD: {{ autosysadmin_dir }}/repair_redis.sh
|
||||
nagios ALL = NOPASSWD: {{ autosysadmin_dir }}/repair_tomcat_instance.sh
|
||||
|
|
@ -39,8 +39,8 @@ concat_files() {
|
|||
chown root: "${hapee_cert_file}"
|
||||
}
|
||||
cert_and_key_mismatch() {
|
||||
hapee_cert_md5=$(openssl x509 -noout -modulus -in "${hapee_cert_file}" | openssl md5)
|
||||
hapee_key_md5=$(openssl rsa -noout -modulus -in "${hapee_cert_file}" | openssl md5)
|
||||
hapee_cert_md5=$(openssl x509 -noout -pubkey -in "${hapee_cert_file}" | openssl md5)
|
||||
hapee_key_md5=$(openssl pkey -pubout -in "${hapee_cert_file}" | openssl md5)
|
||||
|
||||
test "${hapee_cert_md5}" != "${hapee_key_md5}"
|
||||
}
|
||||
|
|
|
@ -29,8 +29,8 @@ concat_files() {
|
|||
chown root: "${haproxy_cert_file}"
|
||||
}
|
||||
cert_and_key_mismatch() {
|
||||
haproxy_cert_md5=$(openssl x509 -noout -modulus -in "${haproxy_cert_file}" | openssl md5)
|
||||
haproxy_key_md5=$(openssl rsa -noout -modulus -in "${haproxy_cert_file}" | openssl md5)
|
||||
haproxy_cert_md5=$(openssl x509 -noout -pubkey -in "${haproxy_cert_file}" | openssl md5)
|
||||
haproxy_key_md5=$(openssl pkey -pubout -in "${haproxy_cert_file}" | openssl md5)
|
||||
|
||||
test "${haproxy_cert_md5}" != "${haproxy_key_md5}"
|
||||
}
|
||||
|
|
44
certbot/files/hooks/deploy/nrpe.sh
Normal file
44
certbot/files/hooks/deploy/nrpe.sh
Normal file
|
@ -0,0 +1,44 @@
|
|||
#!/bin/sh
|
||||
|
||||
error() {
|
||||
>&2 echo "${PROGNAME}: $1"
|
||||
exit 1
|
||||
}
|
||||
debug() {
|
||||
if [ "${VERBOSE}" = "1" ] && [ "${QUIET}" != "1" ]; then
|
||||
>&2 echo "${PROGNAME}: $1"
|
||||
fi
|
||||
}
|
||||
daemon_found_and_running() {
|
||||
test -n "$(pidof nrpe)"
|
||||
}
|
||||
letsencrypt_lineaged_used() {
|
||||
grep -r "^ssl_cert_file" /etc/nagios/ | grep "letsencrypt" | grep -q "$(basename "${RENEWED_LINEAGE}")"
|
||||
}
|
||||
copy_letsencrypt_cert() {
|
||||
DEST_CERTIFICATE=$(grep -r "^ssl_cert_file" /etc/nagios/ | awk -F'=' '{print $2}')
|
||||
DEST_PRIVATE_KEY=$(grep -r "^ssl_privatekey_file" /etc/nagios/ | awk -F'=' '{print $2}')
|
||||
|
||||
install --mode 440 --group nagios ${RENEWED_LINEAGE}/fullchain.pem ${DEST_CERTIFICATE}
|
||||
install --mode 440 --group nagios ${RENEWED_LINEAGE}/privkey.pem ${DEST_PRIVATE_KEY}
|
||||
}
|
||||
main() {
|
||||
if daemon_found_and_running; then
|
||||
if letsencrypt_lineaged_used; then
|
||||
debug "NRPE detected... Copying certificates to the right place & permissions"
|
||||
copy_letsencrypt_cert
|
||||
debug "Restarting NRPE"
|
||||
systemctl restart nagios-nrpe-server
|
||||
else
|
||||
debug "NRPE doesn't use the given Let's Encrypt certificate. Skip."
|
||||
fi
|
||||
else
|
||||
debug "NRPE is not running or missing. Skip."
|
||||
fi
|
||||
}
|
||||
|
||||
readonly PROGNAME=$(basename "$0")
|
||||
readonly VERBOSE=${VERBOSE:-"0"}
|
||||
readonly QUIET=${QUIET:-"0"}
|
||||
|
||||
main
|
|
@ -3,28 +3,25 @@
|
|||
docker_home: /var/lib/docker
|
||||
docker_tmpdir: "{{ docker_home }}/tmp"
|
||||
|
||||
# Chose to use iptables instead of docker-proxy userland process
|
||||
docker_conf_use_iptables: False
|
||||
|
||||
# Disable the possibility for containers processes to gain new privileges
|
||||
docker_conf_no_newprivileges: False
|
||||
docker_conf_no_newprivileges: false
|
||||
|
||||
# Toggle live restore (need to be disabled in swarm mode)
|
||||
docker_conf_live_restore: True
|
||||
docker_conf_live_restore: true
|
||||
|
||||
# Toggle user namespace
|
||||
docker_conf_user_namespace: True
|
||||
docker_conf_user_namespace: true
|
||||
|
||||
# Disable all default network connectivity
|
||||
docker_conf_disable_default_networking: False
|
||||
docker_conf_disable_default_networking: false
|
||||
|
||||
# Remote access
|
||||
docker_remote_access_enabled: False
|
||||
docker_remote_access_enabled: false
|
||||
docker_daemon_port: 2376
|
||||
docker_daemon_listening_ip: 0.0.0.0
|
||||
|
||||
# TLS
|
||||
docker_tls_enabled: False
|
||||
docker_tls_enabled: false
|
||||
docker_tls_path: "{{ docker_home }}/tls"
|
||||
docker_tls_ca: ca/ca.pem
|
||||
docker_tls_ca_key: ca/ca-key.pem
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
# This role installs the docker daemon
|
||||
---
|
||||
|
||||
- name: Fail if docker_conf_use_iptables is defined
|
||||
ansible.builtin.fail:
|
||||
msg: "Variable docker_conf_use_iptables is deprecated and not configurable anymore. Please remove it from your variables. Also double-check the daemon.json config for docker"
|
||||
when:
|
||||
- docker_conf_use_iptables is defined
|
||||
tags:
|
||||
- always
|
||||
|
||||
- name: Remove older docker packages
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
|
@ -23,7 +32,7 @@
|
|||
when: ansible_distribution_major_version is version('10', '<')
|
||||
|
||||
- name: "Ensure {{ apt_keyring_dir }} directory exists"
|
||||
file:
|
||||
ansible.builtin.file:
|
||||
path: "{{ apt_keyring_dir }}"
|
||||
state: directory
|
||||
mode: "755"
|
||||
|
@ -44,35 +53,34 @@
|
|||
repo: 'deb [signed-by={{ apt_keyring_dir }}/docker-debian.asc] https://download.docker.com/linux/debian {{ ansible_distribution_release }} stable'
|
||||
filename: docker
|
||||
state: present
|
||||
update_cache: yes
|
||||
update_cache: true
|
||||
when: ansible_distribution_major_version is version('12', '<')
|
||||
|
||||
- name: Add Docker repository (Debian >=12)
|
||||
ansible.builtin.template:
|
||||
src: docker.sources.j2
|
||||
dest: /etc/apt/sources.list.d/docker.sources
|
||||
register: docker_sources
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
when: ansible_distribution_major_version is version('12', '>=')
|
||||
|
||||
- name: Update APT cache
|
||||
ansible.builtin.apt:
|
||||
update_cache: yes
|
||||
when: docker_sources is changed
|
||||
|
||||
- name: Install Docker
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- docker-ce
|
||||
- docker-ce-cli
|
||||
- containerd.io
|
||||
update_cache: true
|
||||
cache_valid_time: 3600
|
||||
|
||||
- name: python-docker is installed
|
||||
- name: Package python-docker is installed
|
||||
ansible.builtin.apt:
|
||||
name: python-docker
|
||||
state: present
|
||||
when: ansible_python_version is version('3', '<')
|
||||
|
||||
- name: python3-docker is installed
|
||||
- name: Package python3-docker is installed
|
||||
ansible.builtin.apt:
|
||||
name: python3-docker
|
||||
state: present
|
||||
|
@ -82,6 +90,9 @@
|
|||
ansible.builtin.template:
|
||||
src: daemon.json.j2
|
||||
dest: /etc/docker/daemon.json
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
notify: restart docker
|
||||
|
||||
- name: Creating Docker tmp directory
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"debug": false
|
||||
,"iptables": true
|
||||
{# Docker data-dir (default to /var/lib/docker) #}
|
||||
,"data-root": "{{ docker_home }}"
|
||||
{# Keep containers running while docker daemon downtime #}
|
||||
|
@ -7,11 +8,6 @@
|
|||
{% if docker_conf_user_namespace %}
|
||||
{# Turn on user namespace remaping #}
|
||||
,"userns-remap": "default"
|
||||
{% endif %}
|
||||
{% if docker_conf_use_iptables %}
|
||||
{# Use iptables instead of docker-proxy #}
|
||||
,"userland-proxy": false
|
||||
,"iptables": true
|
||||
{% endif %}
|
||||
{# Disable the possibility for containers processes to gain new privileges #}
|
||||
,"no-new-privileges": {{ docker_conf_no_newprivileges | to_json }}
|
||||
|
|
|
@ -1,23 +1,16 @@
|
|||
# evobackup-client
|
||||
|
||||
Allows the configuration of backups to one or more remote filesystems.
|
||||
Install the necessary libraries and script to configure backup scripts.
|
||||
|
||||
The backup hosts and the ports in use need to be defined in
|
||||
evobackup-client__hosts before running it.
|
||||
Additional information:
|
||||
|
||||
The default zzz_evobackup.sh configures a system only backup, but the
|
||||
template can be overriden to configure a full backup instead. If
|
||||
you change the variables in defaults/main.yml you can easily run
|
||||
this again and configure backups to a second set of hosts.
|
||||
* [evobackup-client documentation](https://gitea.evolix.org/evolix/evobackup/src/branch/master/client/README.md)
|
||||
* canary
|
||||
|
||||
Do not forget to set the evobackup-client__mail variable to an
|
||||
email adress you control.
|
||||
## Available variables
|
||||
|
||||
You can add this example to an installation playbook to create the
|
||||
ssh key without running the rest of the role.
|
||||
|
||||
~~~
|
||||
post_tasks:
|
||||
- include_role:
|
||||
name: evobackup-client tasks_from: ssh_key.yml
|
||||
~~~
|
||||
* `evobackup_client__lib_dir` : directory for libraries (default: `/usr/local/lib/evobackup`)
|
||||
* `evobackup_client__bin_dir` : directory for scripts/binaries (default: `/usr/local/bin`)
|
||||
* `evobackup_client__update_canary_enable` : should the canary be updated (default: `True`)
|
||||
* `evobackup_client__update_canary_path` : path for the canary update script (default: `/etc/cron.daily/000-update-evobackup-canary`)
|
||||
* `evobackup_client__update_canary_who` : who the canary update must be attributed to (default: `@daily`)
|
||||
|
|
|
@ -1,15 +1,22 @@
|
|||
---
|
||||
evobackup_client__root_key_path: "/root/.ssh/id_ed25519"
|
||||
evobackup_client__root_key_type: "ed25519"
|
||||
evobackup_client__cron_path: "/etc/cron.daily/zzz_evobackup"
|
||||
evobackup_client__cron_template_name: "zzz_evobackup"
|
||||
evobackup_client__mail: null
|
||||
evobackup_client__servers_fallback: -1
|
||||
evobackup_client__pid_path: "/var/run/evobackup.pid"
|
||||
evobackup_client__log_path: "/var/log/evobackup.log"
|
||||
evobackup_client__backup_path: "/home/backup"
|
||||
evobackup_client__hosts: null
|
||||
# evobackup_client__root_key_path: "/root/.ssh/id_ed25519"
|
||||
# evobackup_client__root_key_type: "ed25519"
|
||||
# evobackup_client__cron_path: "/etc/cron.daily/zzz_evobackup"
|
||||
# evobackup_client__cron_template_name: "zzz_evobackup"
|
||||
# evobackup_client__mail: null
|
||||
# evobackup_client__servers_fallback: -1
|
||||
# evobackup_client__pid_path: "/var/run/evobackup.pid"
|
||||
# evobackup_client__log_path: "/var/log/evobackup.log"
|
||||
# evobackup_client__backup_path: "/home/backup"
|
||||
# evobackup_client__hosts: null
|
||||
# - name: "backups.example.org"
|
||||
# ip: "xxx.xxx.xxx.xxx"
|
||||
# fingerprint: "ecdsa-sha2-nistp256 ..."
|
||||
# port: xxxx
|
||||
|
||||
evobackup_client__lib_dir: "/usr/local/lib/evobackup"
|
||||
evobackup_client__bin_dir: "/usr/local/bin"
|
||||
|
||||
evobackup_client__update_canary_enable: True
|
||||
evobackup_client__update_canary_path: /etc/cron.daily/000-update-evobackup-canary
|
||||
evobackup_client__update_canary_who: "@daily"
|
||||
|
|
82
evobackup-client/files/upstream/CHANGELOG.md
Normal file
82
evobackup-client/files/upstream/CHANGELOG.md
Normal file
|
@ -0,0 +1,82 @@
|
|||
# Changelog
|
||||
|
||||
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 the year
|
||||
The **minor** part changes is the month
|
||||
The **patch** part changes is incremented if multiple releases happen the same month
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
### Changed
|
||||
|
||||
### Deprecated
|
||||
|
||||
### Removed
|
||||
|
||||
### Fixed
|
||||
|
||||
### Security
|
||||
|
||||
## [24.04.1]
|
||||
|
||||
### Fixed
|
||||
|
||||
* evobackupctl: quote ARGS variable for options parsing.
|
||||
|
||||
## [24.04]
|
||||
|
||||
### Added
|
||||
|
||||
* Vagrant definition for manual tests
|
||||
|
||||
### Changed
|
||||
|
||||
* split functions into libraries
|
||||
* add evobackupctl script
|
||||
* change the "zzz_evobackup" script to a template, easy to copy with evobackupctl
|
||||
* use env-based shebang for shell scripts
|
||||
* use $TMPDIR if available
|
||||
|
||||
### Removed
|
||||
|
||||
* update-evobackup-canary is managed by ansible-roles.git
|
||||
* deployment by Ansible is managed elsewhere (now in evolix-private.git, later in ansible-roles.git)
|
||||
|
||||
### Fixed
|
||||
|
||||
* don't exit the whole program if a sync task can't be done
|
||||
|
||||
## [22.12]
|
||||
|
||||
### Changed
|
||||
|
||||
* Use --dump-dir instead of --backup-dir to suppress dump-server-state warning
|
||||
* Do not use rsync compression
|
||||
* Replace rsync option --verbose by --itemize-changes
|
||||
* Add canary to zzz_evobackup
|
||||
* update-evobackup-canary: do not use GNU date, for it to be compatible with OpenBSD
|
||||
* Add AGPL License and README
|
||||
* Script now depends on Bash
|
||||
* tolerate absence of mtr or traceroute
|
||||
* Only one loop for all Redis instances
|
||||
* remodel how we build the rsync command
|
||||
* use sub shells instead of moving around
|
||||
* Separate Rsync for the canary file if the main Rsync has finished without errors
|
||||
|
||||
### Removed
|
||||
|
||||
* No more fallback if dump-server-state is missing
|
||||
|
||||
### Fixed
|
||||
|
||||
* Make start_time and stop_time compatible with OpenBSD
|
||||
|
||||
## [22.03]
|
||||
|
||||
Split client and server parts of the project
|
153
evobackup-client/files/upstream/bin/evobackupctl
Normal file
153
evobackup-client/files/upstream/bin/evobackupctl
Normal file
|
@ -0,0 +1,153 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# shellcheck disable=SC2155
|
||||
readonly PROGNAME=$(basename "${0}")
|
||||
# shellcheck disable=SC2155
|
||||
readonly PROGDIR=$(readlink -m "$(dirname "${0}")")
|
||||
# shellcheck disable=SC2124
|
||||
readonly ARGS=$@
|
||||
|
||||
# Change this to wherever you install the libraries
|
||||
readonly LIBDIR="/usr/local/lib/evobackup"
|
||||
|
||||
source "${LIBDIR}/main.sh"
|
||||
|
||||
show_version() {
|
||||
cat <<END
|
||||
${PROGNAME} version ${VERSION}
|
||||
|
||||
Copyright 2024 Evolix <info@evolix.fr>,
|
||||
Jérémy Lecour <jlecour@evolix.fr>.
|
||||
|
||||
${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} helps managing evobackup scripts
|
||||
|
||||
Options
|
||||
-h, --help print this message and exit
|
||||
-V, --version print version and exit
|
||||
--jail-init-commands print jail init commands
|
||||
--copy-template=PATH copy the backup template to PATH
|
||||
END
|
||||
}
|
||||
|
||||
jail_init_commands() {
|
||||
if [ ! -f /root/.ssh/id_ed25519.pub ]; then
|
||||
ssh-keygen -t ed25519 -f /root/.ssh/id_ed25519 -N ''
|
||||
echo ""
|
||||
fi
|
||||
|
||||
SSH_KEY=$(cat /root/.ssh/id_ed25519.pub)
|
||||
SERVER_NAME=$(hostname -s)
|
||||
if [ "$(uname -s)" = "OpenBSD" ]; then
|
||||
SERVER_IP=$(ifconfig egress | grep "inet " | head -1 | awk '{ print $2}')
|
||||
else
|
||||
SERVER_IP=$(curl -4 https://ifconfig.me 2> /dev/null || hostname -I | awk '{ print $1}')
|
||||
fi
|
||||
|
||||
echo "Copy-paste those lines on backup server(s) :"
|
||||
echo "----------"
|
||||
echo "SERVER_NAME=${SERVER_NAME}"
|
||||
echo "SERVER_IP=${SERVER_IP}"
|
||||
echo "echo '${SSH_KEY}' > /root/\${SERVER_NAME}.pub"
|
||||
echo "bkctld init \${SERVER_NAME}"
|
||||
echo "bkctld key \${SERVER_NAME} /root/\${SERVER_NAME}.pub"
|
||||
echo "bkctld ip \${SERVER_NAME} \${SERVER_IP}"
|
||||
echo "bkctld start \${SERVER_NAME}"
|
||||
echo "bkctld status \${SERVER_NAME}"
|
||||
echo "grep --quiet --extended-regexp \"^\\s?NODE=\" /etc/default/bkctld && bkctld sync \${SERVER_NAME}"
|
||||
echo "----------"
|
||||
}
|
||||
|
||||
copy_template() {
|
||||
dest_path=${1}
|
||||
dest_dir="$(dirname "${dest_path}")"
|
||||
|
||||
if [ -e "${dest_path}" ]; then
|
||||
printf "Path for new evobackup script '%s' already exists.\n" "${dest_path}" >&2
|
||||
exit 1
|
||||
elif [ ! -e "${dest_dir}" ]; then
|
||||
printf "Parent directory '%s' doesn't exist. Create it first.\n" "${dest_dir}" >&2
|
||||
exit 1
|
||||
else
|
||||
if cp "${LIBDIR}/zzz_evobackup.sh" "${dest_path}"; then
|
||||
chmod 750 "${dest_path}"
|
||||
|
||||
sed -i "s|@COMMAND@|${PROGDIR}/${PROGNAME} ${ARGS}|" "${dest_path}"
|
||||
sed -i "s|@DATE@|$(date --iso-8601=seconds)|" "${dest_path}"
|
||||
sed -i "s|@VERSION@|${VERSION}|" "${dest_path}"
|
||||
|
||||
printf "New evobackup script has been saved to '%s'.\n" "${dest_path}"
|
||||
printf "Remember to customize it (mail notifications, backup servers…).\n"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
# If no argument is provided, print help and exit
|
||||
# shellcheck disable=SC2086
|
||||
if [ -z "${ARGS}" ]; then
|
||||
show_help
|
||||
exit 0
|
||||
fi
|
||||
# Parse options, based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
|
||||
while :; do
|
||||
case ${1:-''} in
|
||||
-V|--version)
|
||||
show_version
|
||||
exit 0
|
||||
;;
|
||||
-h|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
--jail-init-commands)
|
||||
jail_init_commands
|
||||
exit 0
|
||||
;;
|
||||
--copy-template)
|
||||
# copy-template option, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
copy_template "${2}"
|
||||
shift
|
||||
else
|
||||
printf "'%s' requires a non-empty option argument.\n" "--copy-template" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--copy-template=?*)
|
||||
# copy-template option, with value separated by =
|
||||
copy_template "${1#*=}"
|
||||
;;
|
||||
--copy-template=)
|
||||
# copy-template option, without value
|
||||
printf "'%s' requires a non-empty option argument.\n" "--copy-template" >&2
|
||||
exit 1
|
||||
;;
|
||||
--)
|
||||
# End of all options.
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-?*|[[:alnum:]]*)
|
||||
# ignore unknown options
|
||||
printf "unknown option '%s'.\n" "${1}" >&2
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
# Default case: If no more options then break out of the loop.
|
||||
break
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
}
|
||||
|
||||
main ${ARGS}
|
301
evobackup-client/files/upstream/lib/dump/elasticsearch.sh
Normal file
301
evobackup-client/files/upstream/lib/dump/elasticsearch.sh
Normal file
|
@ -0,0 +1,301 @@
|
|||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC2034,SC2317,SC2155
|
||||
|
||||
#######################################################################
|
||||
# Snapshot Elasticsearch data
|
||||
#
|
||||
# Arguments:
|
||||
# --protocol=<http|https> (default: http)
|
||||
# --cacert=[String] (default: <none>)
|
||||
# path to the CA certificate to use when using https
|
||||
# --host=[String] (default: localhost)
|
||||
# --port=[Integer] (default: 9200)
|
||||
# --user=[String] (default: <none>)
|
||||
# --password=[String] (default: <none>)
|
||||
# --repository=[String] (default: snaprepo)
|
||||
# --snapshot=[String] (default: snapshot.daily)
|
||||
#######################################################################
|
||||
dump_elasticsearch() {
|
||||
local option_protocol="http"
|
||||
local option_cacert=""
|
||||
local option_host="localhost"
|
||||
local option_port="9200"
|
||||
local option_user=""
|
||||
local option_password=""
|
||||
local option_repository="snaprepo"
|
||||
local option_snapshot="snapshot.daily"
|
||||
local option_others=""
|
||||
|
||||
# Parse options, based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
|
||||
while :; do
|
||||
case ${1:-''} in
|
||||
--protocol)
|
||||
# protocol options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_protocol="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--protocol' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--protocol=?*)
|
||||
# protocol options, with value separated by =
|
||||
option_protocol="${1#*=}"
|
||||
;;
|
||||
--protocol=)
|
||||
# protocol options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--protocol' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--cacert)
|
||||
# cacert options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_cacert="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--cacert' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--cacert=?*)
|
||||
# cacert options, with value separated by =
|
||||
option_cacert="${1#*=}"
|
||||
;;
|
||||
--cacert=)
|
||||
# cacert options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--cacert' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--host)
|
||||
# host options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_host="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--host' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--host=?*)
|
||||
# host options, with value separated by =
|
||||
option_host="${1#*=}"
|
||||
;;
|
||||
--host=)
|
||||
# host options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--host' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--port)
|
||||
# port options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_port="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--port' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--port=?*)
|
||||
# port options, with value separated by =
|
||||
option_port="${1#*=}"
|
||||
;;
|
||||
--port=)
|
||||
# port options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--port' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--user)
|
||||
# user options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_user="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--user' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--user=?*)
|
||||
# user options, with value separated by =
|
||||
option_user="${1#*=}"
|
||||
;;
|
||||
--user=)
|
||||
# user options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--user' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--password)
|
||||
# password options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_password="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--password' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--password=?*)
|
||||
# password options, with value separated by =
|
||||
option_password="${1#*=}"
|
||||
;;
|
||||
--password=)
|
||||
# password options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--password' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--repository)
|
||||
# repository options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_repository="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--repository' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--repository=?*)
|
||||
# repository options, with value separated by =
|
||||
option_repository="${1#*=}"
|
||||
;;
|
||||
--repository=)
|
||||
# repository options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--repository' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--snapshot)
|
||||
# snapshot options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_snapshot="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--snapshot' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--snapshot=?*)
|
||||
# snapshot options, with value separated by =
|
||||
option_snapshot="${1#*=}"
|
||||
;;
|
||||
--snapshot=)
|
||||
# snapshot options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--snapshot' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--)
|
||||
# End of all options.
|
||||
shift
|
||||
option_others=${*}
|
||||
break
|
||||
;;
|
||||
-?*|[[:alnum:]]*)
|
||||
# ignore unknown options
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: unknown option '${1}' (ignored)"
|
||||
;;
|
||||
*)
|
||||
# Default case: If no more options then break out of the loop.
|
||||
break
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
# Use the default Elasticsearch CA certificate when using HTTPS, if not specified directly
|
||||
local default_cacert="/etc/elasticsearch/certs/http_ca.crt"
|
||||
if [ "${option_protocol}" = "https" ] && [ -z "${option_cacert}" ] && [ -f "${default_cacert}" ]; then
|
||||
option_cacert="${default_cacert}"
|
||||
fi
|
||||
|
||||
local errors_dir="${ERRORS_DIR}/elasticsearch-${option_repository}-${option_snapshot}"
|
||||
rm -rf "${errors_dir}"
|
||||
mkdir -p "${errors_dir}"
|
||||
# No need to change recursively, the top directory is enough
|
||||
chmod 700 "${errors_dir}"
|
||||
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${option_snapshot}"
|
||||
|
||||
## Take a snapshot as a backup.
|
||||
## Warning: You need to have a path.repo configured.
|
||||
## See: https://wiki.evolix.org/HowtoElasticsearch#snapshots-et-sauvegardes
|
||||
|
||||
local base_url="${option_protocol}://${option_host}:${option_port}"
|
||||
local repository_url="${base_url}/_snapshot/${option_repository}"
|
||||
local snapshot_url="${repository_url}/${option_snapshot}"
|
||||
|
||||
# Verify snapshot repository
|
||||
|
||||
local error_file="${errors_dir}/verify.err"
|
||||
|
||||
declare -a connect_options
|
||||
connect_options=()
|
||||
if [ -n "${option_cacert}" ]; then
|
||||
connect_options+=(--cacert "${option_cacert}")
|
||||
fi
|
||||
if [ -n "${option_user}" ] || [ -n "${option_password}" ]; then
|
||||
local connect_options+=("--user ${option_user}:${option_password}")
|
||||
fi
|
||||
if [ -n "${option_others}" ]; then
|
||||
# word splitting is deliberate here
|
||||
# shellcheck disable=SC2206
|
||||
connect_options+=(${option_others})
|
||||
fi
|
||||
# Add the http return code at the end of the output
|
||||
connect_options+=(--write-out '%{http_code}\n')
|
||||
connect_options+=(--silent)
|
||||
|
||||
declare -a dump_options
|
||||
dump_options=()
|
||||
dump_options+=(--request POST)
|
||||
|
||||
dump_cmd="curl ${connect_options[*]} ${dump_options[*]} ${repository_url}/_verify?pretty"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd} > "${error_file}"
|
||||
|
||||
# test if the last line of the log file is "200"
|
||||
tail -n 1 "${error_file}" | grep --quiet "^200$" "${error_file}"
|
||||
|
||||
local last_rc=$?
|
||||
# shellcheck disable=SC2086
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: repository verification returned an error ${last_rc}" "${error_file}"
|
||||
GLOBAL_RC=${E_DUMPFAILED}
|
||||
else
|
||||
rm -f "${error_file}"
|
||||
|
||||
# Delete snapshot
|
||||
|
||||
declare -a dump_options
|
||||
dump_options=()
|
||||
dump_options+=(--request DELETE)
|
||||
|
||||
dump_cmd="curl ${connect_options[*]} ${dump_options[*]} ${snapshot_url}"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd} > /dev/null
|
||||
|
||||
# Create snapshot
|
||||
|
||||
local error_file="${errors_dir}/create.err"
|
||||
|
||||
declare -a dump_options
|
||||
dump_options=()
|
||||
dump_options+=(--request PUT)
|
||||
|
||||
dump_cmd="curl ${connect_options[*]} ${dump_options[*]} ${snapshot_url}?wait_for_completion=true"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd} > "${error_file}"
|
||||
|
||||
# test if the last line of the log file is "200"
|
||||
tail -n 1 "${error_file}" | grep --quiet "^200$" "${error_file}"
|
||||
|
||||
local last_rc=$?
|
||||
# shellcheck disable=SC2086
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: curl returned an error ${last_rc}" "${error_file}"
|
||||
GLOBAL_RC=${E_DUMPFAILED}
|
||||
else
|
||||
rm -f "${error_file}"
|
||||
fi
|
||||
fi
|
||||
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${option_snapshot}"
|
||||
}
|
559
evobackup-client/files/upstream/lib/dump/misc.sh
Normal file
559
evobackup-client/files/upstream/lib/dump/misc.sh
Normal file
|
@ -0,0 +1,559 @@
|
|||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC2034,SC2317,SC2155
|
||||
|
||||
#######################################################################
|
||||
# Dump LDAP files (config, data, all)
|
||||
#
|
||||
# Arguments: <none>
|
||||
#######################################################################
|
||||
dump_ldap() {
|
||||
## OpenLDAP : example with slapcat
|
||||
local dump_dir="${LOCAL_BACKUP_DIR}/ldap"
|
||||
rm -rf "${dump_dir}"
|
||||
mkdir -p "${dump_dir}"
|
||||
chmod 700 "${dump_dir}"
|
||||
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${FUNCNAME[0]} to ${dump_dir}"
|
||||
|
||||
dump_cmd="slapcat -n 0 -l ${dump_dir}/config.bak"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd}
|
||||
|
||||
dump_cmd="slapcat -n 1 -l ${dump_dir}/data.bak"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd}
|
||||
|
||||
dump_cmd="slapcat -l ${dump_dir}/all.bak"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd}
|
||||
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${FUNCNAME[0]}"
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Copy dump file of Redis instances
|
||||
#
|
||||
# Arguments:
|
||||
# --instances=[Integer] (default: all)
|
||||
#######################################################################
|
||||
dump_redis() {
|
||||
all_instances=$(find /var/lib/ -mindepth 1 -maxdepth 1 '(' -type d -o -type l ')' -name 'redis*')
|
||||
|
||||
local option_instances=""
|
||||
# Parse options, based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
|
||||
while :; do
|
||||
case ${1:-''} in
|
||||
--instances)
|
||||
# instances options, with key and value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
if [ "${2}" == "all" ]; then
|
||||
read -a option_instances <<< "${all_instances}"
|
||||
else
|
||||
IFS="," read -a option_instances <<< "${2}"
|
||||
fi
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--instances' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--instances=?*)
|
||||
# instances options, with key and value separated by =
|
||||
if [ "${1#*=}" == "all" ]; then
|
||||
read -a option_instances <<< "${all_instances}"
|
||||
else
|
||||
IFS="," read -a option_instances <<< "${1#*=}"
|
||||
fi
|
||||
;;
|
||||
--instances=)
|
||||
# instances options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--instances' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--)
|
||||
# End of all options.
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-?*|[[:alnum:]]*)
|
||||
# ignore unknown options
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: unknown option '${1}' (ignored)"
|
||||
;;
|
||||
*)
|
||||
# Default case: If no more options then break out of the loop.
|
||||
break
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
for instance in "${option_instances[@]}"; do
|
||||
name=$(basename "${instance}")
|
||||
local dump_dir="${LOCAL_BACKUP_DIR}/${name}"
|
||||
local errors_dir=$(errors_dir_from_dump_dir "${dump_dir}")
|
||||
rm -rf "${dump_dir}" "${errors_dir}"
|
||||
mkdir -p "${dump_dir}" "${errors_dir}"
|
||||
# No need to change recursively, the top directory is enough
|
||||
chmod 700 "${dump_dir}" "${errors_dir}"
|
||||
|
||||
if [ -f "${instance}/dump.rdb" ]; then
|
||||
local error_file="${errors_dir}/${name}.err"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_dir}"
|
||||
|
||||
# Copy the Redis database
|
||||
dump_cmd="cp -a ${instance}/dump.rdb ${dump_dir}/dump.rdb"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd} 2> "${error_file}"
|
||||
|
||||
local last_rc=$?
|
||||
# shellcheck disable=SC2086
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: cp ${instance}/dump.rdb to ${dump_dir} returned an error ${last_rc}" "${error_file}"
|
||||
GLOBAL_RC=${E_DUMPFAILED}
|
||||
else
|
||||
rm -f "${error_file}"
|
||||
fi
|
||||
|
||||
# Compress the Redis database
|
||||
dump_cmd="gzip ${dump_dir}/dump.rdb"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd}
|
||||
|
||||
local last_rc=$?
|
||||
# shellcheck disable=SC2086
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: gzip ${dump_dir}/dump.rdb returned an error ${last_rc}" "${error_file}"
|
||||
GLOBAL_RC=${E_DUMPFAILED}
|
||||
else
|
||||
rm -f "${error_file}"
|
||||
fi
|
||||
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${dump_dir}"
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '${instance}/dump.rdb' not found."
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Dump all collections of a MongoDB database
|
||||
# using a custom authentication, instead of /etc/mysql/debian.cnf
|
||||
#
|
||||
# Arguments:
|
||||
# --port=[String] (default: <blank>)
|
||||
# --user=[String] (default: <blank>)
|
||||
# --password=[String] (default: <blank>)
|
||||
# --dump-label=[String] (default: "default")
|
||||
# used as suffix of the dump dir to differenciate multiple instances
|
||||
# Other options after -- are passed as-is to mongodump
|
||||
#
|
||||
# don't forget to create use with read-only access
|
||||
# > use admin
|
||||
# > db.createUser( { user: "mongobackup", pwd: "PASS", roles: [ "backup", ] } )
|
||||
#######################################################################
|
||||
dump_mongodb() {
|
||||
local option_port=""
|
||||
local option_user=""
|
||||
local option_password=""
|
||||
local option_dump_label=""
|
||||
local option_others=""
|
||||
|
||||
# Parse options, based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
|
||||
while :; do
|
||||
case ${1:-''} in
|
||||
--port)
|
||||
# port options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_port="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--port' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--port=?*)
|
||||
# port options, with value separated by =
|
||||
option_port="${1#*=}"
|
||||
;;
|
||||
--port=)
|
||||
# port options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--port' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--user)
|
||||
# user options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_user="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--user' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--user=?*)
|
||||
# user options, with value separated by =
|
||||
option_user="${1#*=}"
|
||||
;;
|
||||
--user=)
|
||||
# user options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--user' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--password)
|
||||
# password options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_password="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--password' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--password=?*)
|
||||
# password options, with value separated by =
|
||||
option_password="${1#*=}"
|
||||
;;
|
||||
--password=)
|
||||
# password options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--password' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--dump-label)
|
||||
# dump-label options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_dump_label="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--dump-label' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--dump-label=?*)
|
||||
# dump-label options, with value separated by =
|
||||
option_dump_label="${1#*=}"
|
||||
;;
|
||||
--dump-label=)
|
||||
# dump-label options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--dump-label' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--)
|
||||
# End of all options.
|
||||
shift
|
||||
option_others=${*}
|
||||
break
|
||||
;;
|
||||
-?*|[[:alnum:]]*)
|
||||
# ignore unknown options
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: unknown option '${1}' (ignored)"
|
||||
;;
|
||||
*)
|
||||
# Default case: If no more options then break out of the loop.
|
||||
break
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
if [ -z "${option_dump_label}" ]; then
|
||||
if [ -n "${option_port}" ]; then
|
||||
option_dump_label="${option_port}"
|
||||
else
|
||||
option_dump_label="default"
|
||||
fi
|
||||
fi
|
||||
|
||||
local dump_dir="${LOCAL_BACKUP_DIR}/mongodb-${option_dump_label}"
|
||||
local errors_dir=$(errors_dir_from_dump_dir "${dump_dir}")
|
||||
rm -rf "${dump_dir}" "${errors_dir}"
|
||||
mkdir -p "${dump_dir}" "${errors_dir}"
|
||||
# No need to change recursively, the top directory is enough
|
||||
chmod 700 "${dump_dir}" "${errors_dir}"
|
||||
|
||||
local error_file="${errors_dir}.err"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_dir}"
|
||||
|
||||
declare -a dump_options
|
||||
dump_options=()
|
||||
if [ -n "${option_port}" ]; then
|
||||
dump_options+=(--port="${option_port}")
|
||||
fi
|
||||
if [ -n "${option_user}" ]; then
|
||||
dump_options+=(--username="${option_user}")
|
||||
fi
|
||||
if [ -n "${option_password}" ]; then
|
||||
dump_options+=(--password="${option_password}")
|
||||
fi
|
||||
dump_options+=(--out="${dump_dir}/")
|
||||
if [ -n "${option_others}" ]; then
|
||||
# word splitting is deliberate here
|
||||
# shellcheck disable=SC2206
|
||||
dump_options+=(${option_others})
|
||||
fi
|
||||
|
||||
dump_cmd="mongodump ${dump_options[*]}"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd} > /dev/null"
|
||||
${dump_cmd} 2> "${error_file}" > /dev/null
|
||||
|
||||
local last_rc=$?
|
||||
# shellcheck disable=SC2086
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: mongodump to ${dump_dir} returned an error ${last_rc}" "${error_file}"
|
||||
GLOBAL_RC=${E_DUMPFAILED}
|
||||
else
|
||||
rm -f "${error_file}"
|
||||
fi
|
||||
log "LOCAL_TASKS - stop ${FUNCNAME[0]}: ${dump_dir}"
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Dump RAID configuration
|
||||
#
|
||||
# Arguments: <none>
|
||||
#######################################################################
|
||||
dump_raid_config() {
|
||||
local dump_dir="${LOCAL_BACKUP_DIR}/raid"
|
||||
local errors_dir=$(errors_dir_from_dump_dir "${dump_dir}")
|
||||
rm -rf "${dump_dir}" "${errors_dir}"
|
||||
mkdir -p "${dump_dir}" "${errors_dir}"
|
||||
# No need to change recursively, the top directory is enough
|
||||
chmod 700 "${dump_dir}" "${errors_dir}"
|
||||
|
||||
if command -v megacli > /dev/null; then
|
||||
local error_file="${errors_dir}/megacli.cfg"
|
||||
local dump_file="${dump_dir}/megacli.err"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_file}"
|
||||
|
||||
dump_cmd="megacli -CfgSave -f ${dump_file} -a0"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd} 2> "${error_file}"
|
||||
|
||||
local last_rc=$?
|
||||
# shellcheck disable=SC2086
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: megacli to ${dump_file} returned an error ${last_rc}" "${error_file}"
|
||||
GLOBAL_RC=${E_DUMPFAILED}
|
||||
else
|
||||
rm -f "${error_file}"
|
||||
fi
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${dump_file}"
|
||||
elif command -v perccli > /dev/null; then
|
||||
local error_file="${errors_dir}/perccli.cfg"
|
||||
local dump_file="${dump_dir}/perccli.err"
|
||||
# log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_file}"
|
||||
|
||||
# TODO: find out what the correct command is
|
||||
|
||||
# dump_cmd="perccli XXXX"
|
||||
# log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
# ${dump_cmd} 2> ${error_file}
|
||||
|
||||
# local last_rc=$?
|
||||
# # shellcheck disable=SC2086
|
||||
# if [ ${last_rc} -ne 0 ]; then
|
||||
# log_error "LOCAL_TASKS - ${FUNCNAME[0]}: perccli to ${dump_file} returned an error ${last_rc}" "${error_file}"
|
||||
# GLOBAL_RC=${E_DUMPFAILED}
|
||||
# else
|
||||
# rm -f "${error_file}"
|
||||
# fi
|
||||
# log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${dump_file}"
|
||||
else
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: 'megacli' and 'perccli' not found, unable to dump RAID configuration"
|
||||
fi
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Save some traceroute/mtr results
|
||||
#
|
||||
# Arguments:
|
||||
# --targets=[IP,HOST] (default: <none>)
|
||||
#######################################################################
|
||||
dump_traceroute() {
|
||||
local option_targets=""
|
||||
|
||||
# Parse options, based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
|
||||
while :; do
|
||||
case ${1:-''} in
|
||||
--targets)
|
||||
# targets options, with key and value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
IFS="," read -a option_targets <<< "${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--targets' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--targets=?*)
|
||||
# targets options, with key and value separated by =
|
||||
IFS="," read -a option_targets <<< "${1#*=}"
|
||||
;;
|
||||
--targets=)
|
||||
# targets options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--targets' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--)
|
||||
# End of all options.
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-?*|[[:alnum:]]*)
|
||||
# ignore unknown options
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: unknown option '${1}' (ignored)"
|
||||
;;
|
||||
*)
|
||||
# Default case: If no more options then break out of the loop.
|
||||
break
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
local dump_dir="${LOCAL_BACKUP_DIR}/traceroute"
|
||||
local errors_dir=$(errors_dir_from_dump_dir "${dump_dir}")
|
||||
rm -rf "${dump_dir}" "${errors_dir}"
|
||||
mkdir -p "${dump_dir}" "${errors_dir}"
|
||||
# No need to change recursively, the top directory is enough
|
||||
chmod 700 "${dump_dir}" "${errors_dir}"
|
||||
|
||||
|
||||
mtr_bin=$(command -v mtr)
|
||||
if [ -n "${mtr_bin}" ]; then
|
||||
for target in "${option_targets[@]}"; do
|
||||
local dump_file="${dump_dir}/mtr-${target}"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_file}"
|
||||
|
||||
${mtr_bin} -r "${target}" > "${dump_file}"
|
||||
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${dump_file}"
|
||||
done
|
||||
fi
|
||||
|
||||
traceroute_bin=$(command -v traceroute)
|
||||
if [ -n "${traceroute_bin}" ]; then
|
||||
for target in "${option_targets[@]}"; do
|
||||
local dump_file="${dump_dir}/traceroute-${target}"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_file}"
|
||||
|
||||
${traceroute_bin} -n "${target}" > "${dump_file}" 2>&1
|
||||
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${dump_file}"
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Save many system information, using dump_server_state
|
||||
#
|
||||
# Arguments:
|
||||
# any option for dump-server-state (except --dump-dir) is usable
|
||||
# (default: --all)
|
||||
#######################################################################
|
||||
dump_server_state() {
|
||||
local dump_dir="${LOCAL_BACKUP_DIR}/server-state"
|
||||
rm -rf "${dump_dir}"
|
||||
# Do not create the directory
|
||||
# mkdir -p -m 700 "${dump_dir}"
|
||||
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_dir}"
|
||||
|
||||
# pass all options
|
||||
read -a options <<< "${@}"
|
||||
# if no option is given, use "--all" as fallback
|
||||
if [ ${#options[@]} -le 0 ]; then
|
||||
options=(--all)
|
||||
fi
|
||||
# add "--dump-dir" in case it is missing (as it should)
|
||||
options+=(--dump-dir "${dump_dir}")
|
||||
|
||||
dump_server_state_bin=$(command -v dump-server-state)
|
||||
if [ -z "${dump_server_state_bin}" ]; then
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: dump-server-state is missing"
|
||||
rc=1
|
||||
else
|
||||
dump_cmd="${dump_server_state_bin} ${options[*]}"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd}
|
||||
|
||||
local last_rc=$?
|
||||
# shellcheck disable=SC2086
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: dump-server-state returned an error ${last_rc}, check ${dump_dir}"
|
||||
GLOBAL_RC=${E_DUMPFAILED}
|
||||
fi
|
||||
fi
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${dump_dir}"
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Save RabbitMQ data
|
||||
#
|
||||
# Arguments: <none>
|
||||
#
|
||||
# Warning: This has been poorly tested
|
||||
#######################################################################
|
||||
dump_rabbitmq() {
|
||||
local dump_dir="${LOCAL_BACKUP_DIR}/rabbitmq"
|
||||
local errors_dir=$(errors_dir_from_dump_dir "${dump_dir}")
|
||||
rm -rf "${dump_dir}" "${errors_dir}"
|
||||
mkdir -p "${dump_dir}" "${errors_dir}"
|
||||
# No need to change recursively, the top directory is enough
|
||||
chmod 700 "${dump_dir}" "${errors_dir}"
|
||||
|
||||
local error_file="${errors_dir}.err"
|
||||
local dump_file="${dump_dir}/config"
|
||||
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_file}"
|
||||
|
||||
dump_cmd="rabbitmqadmin export ${dump_file}"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd} 2> "${error_file}"
|
||||
|
||||
local last_rc=$?
|
||||
# shellcheck disable=SC2086
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: pg_dump to ${dump_file} returned an error ${last_rc}" "${error_file}"
|
||||
GLOBAL_RC=${E_DUMPFAILED}
|
||||
else
|
||||
rm -f "${error_file}"
|
||||
fi
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${dump_file}"
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Save Files ACL on various partitions.
|
||||
#
|
||||
# Arguments: <none>
|
||||
#######################################################################
|
||||
dump_facl() {
|
||||
local dump_dir="${LOCAL_BACKUP_DIR}/facl"
|
||||
local errors_dir=$(errors_dir_from_dump_dir "${dump_dir}")
|
||||
rm -rf "${dump_dir}" "${errors_dir}"
|
||||
mkdir -p "${dump_dir}" "${errors_dir}"
|
||||
# No need to change recursively, the top directory is enough
|
||||
chmod 700 "${dump_dir}" "${errors_dir}"
|
||||
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_dir}"
|
||||
|
||||
dump_cmd="getfacl -R /etc > ${dump_dir}/etc.txt"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd}
|
||||
|
||||
dump_cmd="getfacl -R /home > ${dump_dir}/home.txt"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd}
|
||||
|
||||
dump_cmd="getfacl -R /usr > ${dump_dir}/usr.txt"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd}
|
||||
|
||||
dump_cmd="getfacl -R /var > ${dump_dir}/var.txt"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd}
|
||||
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${dump_dir}"
|
||||
}
|
1551
evobackup-client/files/upstream/lib/dump/mysql.sh
Normal file
1551
evobackup-client/files/upstream/lib/dump/mysql.sh
Normal file
|
@ -0,0 +1,1551 @@
|
|||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC2034,SC2317,SC2155
|
||||
|
||||
#######################################################################
|
||||
# Dump complete summary of an instance (using pt-mysql-summary)
|
||||
#
|
||||
# Arguments:
|
||||
# --port=[Integer] (default: <blank>)
|
||||
# --socket=[String] (default: <blank>)
|
||||
# --user=[String] (default: <blank>)
|
||||
# --password=[String] (default: <blank>)
|
||||
# --defaults-file=[String] (default: <blank>)
|
||||
# --defaults-extra-file=[String] (default: <blank>)
|
||||
# --defaults-group-suffix=[String] (default: <blank>)
|
||||
# --dump-label=[String] (default: "default")
|
||||
# used as suffix of the dump dir to differenciate multiple instances
|
||||
#######################################################################
|
||||
dump_mysql_summary() {
|
||||
local option_port=""
|
||||
local option_socket=""
|
||||
local option_defaults_file=""
|
||||
local option_defaults_extra_file=""
|
||||
local option_defaults_group_suffix=""
|
||||
local option_user=""
|
||||
local option_password=""
|
||||
local option_dump_label=""
|
||||
|
||||
# Parse options, based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
|
||||
while :; do
|
||||
case ${1:-''} in
|
||||
--defaults-file)
|
||||
# defaults-file options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_defaults_file="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-file' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--defaults-file=?*)
|
||||
# defaults-file options, with value separated by =
|
||||
option_defaults_file="${1#*=}"
|
||||
;;
|
||||
--defaults-file=)
|
||||
# defaults-file options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-file' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--defaults-extra-file)
|
||||
# defaults-file options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_defaults_extra_file="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-file' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--defaults-extra-file=?*)
|
||||
# defaults-extra-file options, with value separated by =
|
||||
option_defaults_extra_file="${1#*=}"
|
||||
;;
|
||||
--defaults-extra-file=)
|
||||
# defaults-extra-file options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-extra-file' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--defaults-group-suffix)
|
||||
# defaults-group-suffix options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_defaults_group_suffix="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-group-suffix' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--defaults-group-suffix=?*)
|
||||
# defaults-group-suffix options, with value separated by =
|
||||
option_defaults_group_suffix="${1#*=}"
|
||||
;;
|
||||
--defaults-group-suffix=)
|
||||
# defaults-group-suffix options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-group-suffix' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--port)
|
||||
# port options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_port="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--port' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--port=?*)
|
||||
# port options, with value separated by =
|
||||
option_port="${1#*=}"
|
||||
;;
|
||||
--port=)
|
||||
# port options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--port' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--socket)
|
||||
# socket options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_socket="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--socket' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--socket=?*)
|
||||
# socket options, with value separated by =
|
||||
option_socket="${1#*=}"
|
||||
;;
|
||||
--socket=)
|
||||
# socket options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--socket' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--user)
|
||||
# user options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_user="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--user' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--user=?*)
|
||||
# user options, with value separated by =
|
||||
option_user="${1#*=}"
|
||||
;;
|
||||
--user=)
|
||||
# user options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--user' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--password)
|
||||
# password options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_password="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--password' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--password=?*)
|
||||
# password options, with value separated by =
|
||||
option_password="${1#*=}"
|
||||
;;
|
||||
--password=)
|
||||
# password options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--password' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--dump-label)
|
||||
# dump-label options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_dump_label="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--dump-label' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--dump-label=?*)
|
||||
# dump-label options, with value separated by =
|
||||
option_dump_label="${1#*=}"
|
||||
;;
|
||||
--dump-label=)
|
||||
# dump-label options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--dump-label' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--)
|
||||
# End of all options.
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-?*|[[:alnum:]]*)
|
||||
# ignore unknown options
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: unkwnown option (ignored): '${1}'"
|
||||
;;
|
||||
*)
|
||||
# Default case: If no more options then break out of the loop.
|
||||
break
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
if [ -z "${option_dump_label}" ]; then
|
||||
if [ -n "${option_defaults_group_suffix}" ]; then
|
||||
option_dump_label="${option_defaults_group_suffix}"
|
||||
elif [ -n "${option_port}" ]; then
|
||||
option_dump_label="${option_port}"
|
||||
elif [ -n "${option_socket}" ]; then
|
||||
option_dump_label=$(path_to_str "${option_socket}")
|
||||
else
|
||||
option_dump_label="default"
|
||||
fi
|
||||
fi
|
||||
|
||||
local dump_dir="${LOCAL_BACKUP_DIR}/mysql-${option_dump_label}-summary"
|
||||
local errors_dir=$(errors_dir_from_dump_dir "${dump_dir}")
|
||||
rm -rf "${dump_dir}" "${errors_dir}"
|
||||
mkdir -p "${dump_dir}" "${errors_dir}"
|
||||
# No need to change recursively, the top directory is enough
|
||||
chmod 700 "${dump_dir}" "${errors_dir}"
|
||||
|
||||
## Dump all grants (requires 'percona-toolkit' package)
|
||||
if command -v pt-mysql-summary > /dev/null; then
|
||||
local error_file="${errors_dir}/mysql-summary.err"
|
||||
local dump_file="${dump_dir}/mysql-summary.out"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_file}"
|
||||
|
||||
## Connection options
|
||||
declare -a connect_options
|
||||
connect_options=()
|
||||
if [ -n "${option_defaults_file}" ]; then
|
||||
connect_options+=(--defaults-file="${option_defaults_file}")
|
||||
fi
|
||||
if [ -n "${option_defaults_extra_file}" ]; then
|
||||
connect_options+=(--defaults-extra-file="${option_defaults_extra_file}")
|
||||
fi
|
||||
if [ -n "${option_defaults_group_suffix}" ]; then
|
||||
connect_options+=(--defaults-group-suffix="${option_defaults_group_suffix}")
|
||||
fi
|
||||
if [ -n "${option_port}" ]; then
|
||||
connect_options+=(--protocol=tcp)
|
||||
connect_options+=(--port="${option_port}")
|
||||
fi
|
||||
if [ -n "${option_socket}" ]; then
|
||||
connect_options+=(--protocol=socket)
|
||||
connect_options+=(--socket="${option_socket}")
|
||||
fi
|
||||
if [ -n "${option_user}" ]; then
|
||||
connect_options+=(--user="${option_user}")
|
||||
fi
|
||||
if [ -n "${option_password}" ]; then
|
||||
connect_options+=(--password="${option_password}")
|
||||
fi
|
||||
|
||||
declare -a options
|
||||
options=()
|
||||
options+=(--sleep=0)
|
||||
|
||||
dump_cmd="pt-mysql-summary ${options[*]} -- ${connect_options[*]}"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd} 2> "${error_file}" > "${dump_file}"
|
||||
|
||||
local last_rc=$?
|
||||
# shellcheck disable=SC2086
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: pt-mysql-summary to ${dump_file} returned an error ${last_rc}" "${error_file}"
|
||||
GLOBAL_RC=${E_DUMPFAILED}
|
||||
else
|
||||
rm -f "${error_file}"
|
||||
fi
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${dump_file}"
|
||||
else
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: 'pt-mysql-summary' not found, unable to dump summary"
|
||||
fi
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Dump grants of an instance
|
||||
#
|
||||
# Arguments:
|
||||
# --port=[Integer] (default: <blank>)
|
||||
# --socket=[String] (default: <blank>)
|
||||
# --user=[String] (default: <blank>)
|
||||
# --password=[String] (default: <blank>)
|
||||
# --defaults-file=[String] (default: <blank>)
|
||||
# --dump-label=[String] (default: "default")
|
||||
# used as suffix of the dump dir to differenciate multiple instances
|
||||
#######################################################################
|
||||
dump_mysql_grants() {
|
||||
local option_port=""
|
||||
local option_socket=""
|
||||
local option_defaults_file=""
|
||||
local option_user=""
|
||||
local option_password=""
|
||||
local option_dump_label=""
|
||||
|
||||
# Parse options, based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
|
||||
while :; do
|
||||
case ${1:-''} in
|
||||
--defaults-file)
|
||||
# defaults-file options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_defaults_file="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-file' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--defaults-file=?*)
|
||||
# defaults-file options, with value separated by =
|
||||
option_defaults_file="${1#*=}"
|
||||
;;
|
||||
--defaults-file=)
|
||||
# defaults-file options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-file' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--port)
|
||||
# port options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_port="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--port' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--port=?*)
|
||||
# port options, with value separated by =
|
||||
option_port="${1#*=}"
|
||||
;;
|
||||
--port=)
|
||||
# port options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--port' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--socket)
|
||||
# socket options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_socket="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--socket' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--socket=?*)
|
||||
# socket options, with value separated by =
|
||||
option_socket="${1#*=}"
|
||||
;;
|
||||
--socket=)
|
||||
# socket options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--socket' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--user)
|
||||
# user options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_user="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--user' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--user=?*)
|
||||
# user options, with value separated by =
|
||||
option_user="${1#*=}"
|
||||
;;
|
||||
--user=)
|
||||
# user options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--user' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--password)
|
||||
# password options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_password="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--password' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--password=?*)
|
||||
# password options, with value separated by =
|
||||
option_password="${1#*=}"
|
||||
;;
|
||||
--password=)
|
||||
# password options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--password' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--dump-label)
|
||||
# dump-label options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_dump_label="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--dump-label' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--dump-label=?*)
|
||||
# dump-label options, with value separated by =
|
||||
option_dump_label="${1#*=}"
|
||||
;;
|
||||
--dump-label=)
|
||||
# dump-label options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--dump-label' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--)
|
||||
# End of all options.
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-?*|[[:alnum:]]*)
|
||||
# ignore unknown options
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: unknown option '${1}' (ignored)"
|
||||
;;
|
||||
*)
|
||||
# Default case: If no more options then break out of the loop.
|
||||
break
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
if [ -z "${option_dump_label}" ]; then
|
||||
if [ -n "${option_port}" ]; then
|
||||
option_dump_label="${option_port}"
|
||||
elif [ -n "${option_socket}" ]; then
|
||||
option_dump_label=$(path_to_str "${option_socket}")
|
||||
else
|
||||
option_dump_label="default"
|
||||
fi
|
||||
fi
|
||||
|
||||
local dump_dir="${LOCAL_BACKUP_DIR}/mysql-${option_dump_label}-grants"
|
||||
local errors_dir=$(errors_dir_from_dump_dir "${dump_dir}")
|
||||
rm -rf "${dump_dir}" "${errors_dir}"
|
||||
mkdir -p "${dump_dir}" "${errors_dir}"
|
||||
# No need to change recursively, the top directory is enough
|
||||
chmod 700 "${dump_dir}" "${errors_dir}"
|
||||
|
||||
## Dump all grants (requires 'percona-toolkit' package)
|
||||
if command -v pt-show-grants > /dev/null; then
|
||||
local error_file="${errors_dir}/all_grants.err"
|
||||
local dump_file="${dump_dir}/all_grants.sql"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_file}"
|
||||
|
||||
declare -a options
|
||||
options=()
|
||||
if [ -n "${option_defaults_file}" ]; then
|
||||
options+=(--defaults-file="${option_defaults_file}")
|
||||
fi
|
||||
if [ -n "${option_port}" ]; then
|
||||
options+=(--port="${option_port}")
|
||||
fi
|
||||
if [ -n "${option_socket}" ]; then
|
||||
options+=(--socket="${option_socket}")
|
||||
fi
|
||||
if [ -n "${option_user}" ]; then
|
||||
options+=(--user="${option_user}")
|
||||
fi
|
||||
if [ -n "${option_password}" ]; then
|
||||
options+=(--password="${option_password}")
|
||||
fi
|
||||
options+=(--flush)
|
||||
options+=(--no-header)
|
||||
|
||||
dump_cmd="pt-show-grants ${options[*]}"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd} 2> "${error_file}" > "${dump_file}"
|
||||
|
||||
local last_rc=$?
|
||||
# shellcheck disable=SC2086
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: pt-show-grants to ${dump_file} returned an error ${last_rc}" "${error_file}"
|
||||
GLOBAL_RC=${E_DUMPFAILED}
|
||||
else
|
||||
rm -f "${error_file}"
|
||||
fi
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${dump_file}"
|
||||
else
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: 'pt-show-grants' not found, unable to dump grants"
|
||||
fi
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Dump a single compressed file of all databases of an instance
|
||||
# and a file containing only the schema.
|
||||
#
|
||||
# Arguments:
|
||||
# --masterdata (default: <absent>)
|
||||
# --port=[Integer] (default: <blank>)
|
||||
# --socket=[String] (default: <blank>)
|
||||
# --user=[String] (default: <blank>)
|
||||
# --password=[String] (default: <blank>)
|
||||
# --defaults-file=[String] (default: <blank>)
|
||||
# --defaults-extra-file=[String] (default: <blank>)
|
||||
# --defaults-group-suffix=[String] (default: <blank>)
|
||||
# --dump-label=[String] (default: "default")
|
||||
# used as suffix of the dump dir to differenciate multiple instances
|
||||
# --compress=<gzip|pigz|bzip2|xz|none> (default: "gzip")
|
||||
# Other options after -- are passed as-is to mysqldump
|
||||
#######################################################################
|
||||
dump_mysql_global() {
|
||||
local option_masterdata=""
|
||||
local option_port=""
|
||||
local option_socket=""
|
||||
local option_defaults_file=""
|
||||
local option_defaults_extra_file=""
|
||||
local option_defaults_group_suffix=""
|
||||
local option_user=""
|
||||
local option_password=""
|
||||
local option_dump_label=""
|
||||
local option_compress=""
|
||||
local option_others=""
|
||||
|
||||
# Parse options, based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
|
||||
while :; do
|
||||
case ${1:-''} in
|
||||
--masterdata)
|
||||
option_masterdata="--masterdata"
|
||||
;;
|
||||
--defaults-file)
|
||||
# defaults-file options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_defaults_file="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-file' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--defaults-file=?*)
|
||||
# defaults-file options, with value separated by =
|
||||
option_defaults_file="${1#*=}"
|
||||
;;
|
||||
--defaults-file=)
|
||||
# defaults-file options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-file' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--defaults-extra-file)
|
||||
# defaults-file options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_defaults_extra_file="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-file' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--defaults-extra-file=?*)
|
||||
# defaults-extra-file options, with value separated by =
|
||||
option_defaults_extra_file="${1#*=}"
|
||||
;;
|
||||
--defaults-extra-file=)
|
||||
# defaults-extra-file options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-extra-file' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--defaults-group-suffix)
|
||||
# defaults-group-suffix options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_defaults_group_suffix="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-group-suffix' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--defaults-group-suffix=?*)
|
||||
# defaults-group-suffix options, with value separated by =
|
||||
option_defaults_group_suffix="${1#*=}"
|
||||
;;
|
||||
--defaults-group-suffix=)
|
||||
# defaults-group-suffix options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-group-suffix' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--port)
|
||||
# port options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_port="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--port' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--port=?*)
|
||||
# port options, with value separated by =
|
||||
option_port="${1#*=}"
|
||||
;;
|
||||
--port=)
|
||||
# port options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--port' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--socket)
|
||||
# socket options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_socket="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--socket' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--socket=?*)
|
||||
# socket options, with value separated by =
|
||||
option_socket="${1#*=}"
|
||||
;;
|
||||
--socket=)
|
||||
# socket options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--socket' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--user)
|
||||
# user options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_user="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--user' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--user=?*)
|
||||
# user options, with value separated by =
|
||||
option_user="${1#*=}"
|
||||
;;
|
||||
--user=)
|
||||
# user options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--user' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--password)
|
||||
# password options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_password="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--password' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--password=?*)
|
||||
# password options, with value separated by =
|
||||
option_password="${1#*=}"
|
||||
;;
|
||||
--password=)
|
||||
# password options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--password' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--dump-label)
|
||||
# dump-label options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_dump_label="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--dump-label' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--dump-label=?*)
|
||||
# dump-label options, with value separated by =
|
||||
option_dump_label="${1#*=}"
|
||||
;;
|
||||
--dump-label=)
|
||||
# dump-label options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--dump-label' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--compress)
|
||||
# compress options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_compress="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--compress' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--compress=?*)
|
||||
# compress options, with value separated by =
|
||||
option_compress="${1#*=}"
|
||||
;;
|
||||
--compress=)
|
||||
# compress options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--compress' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--)
|
||||
# End of all options.
|
||||
shift
|
||||
option_others=${*}
|
||||
break
|
||||
;;
|
||||
-?*|[[:alnum:]]*)
|
||||
# ignore unknown options
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: unknown option '${1}' (ignored)"
|
||||
;;
|
||||
*)
|
||||
# Default case: If no more options then break out of the loop.
|
||||
break
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
case "${option_compress}" in
|
||||
none)
|
||||
compress_cmd="cat"
|
||||
dump_ext=""
|
||||
;;
|
||||
bzip2|bz|bz2)
|
||||
compress_cmd="bzip2 --best"
|
||||
dump_ext=".bz"
|
||||
;;
|
||||
xz)
|
||||
compress_cmd="xz --best"
|
||||
dump_ext=".xz"
|
||||
;;
|
||||
pigz)
|
||||
compress_cmd="pigz --best"
|
||||
dump_ext=".gz"
|
||||
;;
|
||||
gz|gzip|*)
|
||||
compress_cmd="gzip --best"
|
||||
dump_ext=".gz"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "${option_dump_label}" ]; then
|
||||
if [ -n "${option_defaults_group_suffix}" ]; then
|
||||
option_dump_label="${option_defaults_group_suffix}"
|
||||
elif [ -n "${option_port}" ]; then
|
||||
option_dump_label="${option_port}"
|
||||
elif [ -n "${option_socket}" ]; then
|
||||
option_dump_label=$(path_to_str "${option_socket}")
|
||||
else
|
||||
option_dump_label="default"
|
||||
fi
|
||||
fi
|
||||
|
||||
## Connection options
|
||||
declare -a connect_options
|
||||
connect_options=()
|
||||
if [ -n "${option_defaults_file}" ]; then
|
||||
connect_options+=(--defaults-file="${option_defaults_file}")
|
||||
fi
|
||||
if [ -n "${option_defaults_extra_file}" ]; then
|
||||
connect_options+=(--defaults-extra-file="${option_defaults_extra_file}")
|
||||
fi
|
||||
if [ -n "${option_defaults_group_suffix}" ]; then
|
||||
connect_options+=(--defaults-group-suffix="${option_defaults_group_suffix}")
|
||||
fi
|
||||
if [ -n "${option_port}" ]; then
|
||||
connect_options+=(--protocol=tcp)
|
||||
connect_options+=(--port="${option_port}")
|
||||
fi
|
||||
if [ -n "${option_socket}" ]; then
|
||||
connect_options+=(--protocol=socket)
|
||||
connect_options+=(--socket="${option_socket}")
|
||||
fi
|
||||
if [ -n "${option_user}" ]; then
|
||||
connect_options+=(--user="${option_user}")
|
||||
fi
|
||||
if [ -n "${option_password}" ]; then
|
||||
connect_options+=(--password="${option_password}")
|
||||
fi
|
||||
|
||||
## Global all databases in one file
|
||||
|
||||
local dump_dir="${LOCAL_BACKUP_DIR}/mysql-${option_dump_label}"
|
||||
local errors_dir=$(errors_dir_from_dump_dir "${dump_dir}")
|
||||
rm -rf "${dump_dir}" "${errors_dir}"
|
||||
mkdir -p "${dump_dir}" "${errors_dir}"
|
||||
# No need to change recursively, the top directory is enough
|
||||
chmod 700 "${dump_dir}" "${errors_dir}"
|
||||
|
||||
local error_file="${errors_dir}/mysqldump.err"
|
||||
local dump_file="${dump_dir}/mysqldump.sql${dump_ext}"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_file}"
|
||||
|
||||
declare -a dump_options
|
||||
dump_options=()
|
||||
dump_options+=(--opt)
|
||||
dump_options+=(--force)
|
||||
dump_options+=(--events)
|
||||
dump_options+=(--hex-blob)
|
||||
dump_options+=(--all-databases)
|
||||
if [ -n "${option_masterdata}" ]; then
|
||||
dump_options+=("${option_masterdata}")
|
||||
fi
|
||||
if [ -n "${option_others}" ]; then
|
||||
# word splitting is deliberate here
|
||||
# shellcheck disable=SC2206
|
||||
dump_options+=(${option_others})
|
||||
fi
|
||||
|
||||
## WARNING : logging and executing the command must be separate
|
||||
## because otherwise Bash would interpret | and > as strings and not syntax.
|
||||
|
||||
dump_cmd="mysqldump ${connect_options[*]} ${dump_options[*]} 2> ${error_file} | ${compress_cmd} > ${dump_file}"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
mysqldump "${connect_options[@]}" "${dump_options[@]}" 2> "${error_file}" | ${compress_cmd} > "${dump_file}"
|
||||
|
||||
local last_rc=$?
|
||||
# shellcheck disable=SC2086
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: mysqldump returned an error ${last_rc}" "${error_file}"
|
||||
GLOBAL_RC=${E_DUMPFAILED}
|
||||
else
|
||||
rm -f "${error_file}"
|
||||
fi
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${dump_file}"
|
||||
|
||||
|
||||
## Schema only (no data) for each databases
|
||||
|
||||
local error_file="${errors_dir}/mysqldump.schema.err"
|
||||
local dump_file="${dump_dir}/mysqldump.schema.sql"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_file}"
|
||||
|
||||
declare -a dump_options
|
||||
dump_options=()
|
||||
dump_options+=(--force)
|
||||
dump_options+=(--no-data)
|
||||
dump_options+=(--all-databases)
|
||||
if [ -n "${option_others}" ]; then
|
||||
# word splitting is deliberate here
|
||||
# shellcheck disable=SC2206
|
||||
dump_options+=(${option_others})
|
||||
fi
|
||||
|
||||
dump_cmd="mysqldump ${connect_options[*]} ${dump_options[*]}"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd} 2> "${error_file}" > "${dump_file}"
|
||||
|
||||
local last_rc=$?
|
||||
# shellcheck disable=SC2086
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: mysqldump returned an error ${last_rc}" "${error_file}"
|
||||
GLOBAL_RC=${E_DUMPFAILED}
|
||||
else
|
||||
rm -f "${error_file}"
|
||||
fi
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${dump_file}"
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Dump a file of each databases of an instance
|
||||
# and a file containing only the schema.
|
||||
#
|
||||
# Arguments:
|
||||
# --port=[Integer] (default: <blank>)
|
||||
# --socket=[String] (default: <blank>)
|
||||
# --user=[String] (default: <blank>)
|
||||
# --password=[String] (default: <blank>)
|
||||
# --defaults-file=[String] (default: <blank>)
|
||||
# --defaults-extra-file=[String] (default: <blank>)
|
||||
# --defaults-group-suffix=[String] (default: <blank>)
|
||||
# --dump-label=[String] (default: "default")
|
||||
# used as suffix of the dump dir to differenciate multiple instances
|
||||
# --compress=<gzip|pigz|bzip2|xz|none> (default: "gzip")
|
||||
# Other options after -- are passed as-is to mysqldump
|
||||
#######################################################################
|
||||
dump_mysql_per_base() {
|
||||
local option_port=""
|
||||
local option_socket=""
|
||||
local option_defaults_file=""
|
||||
local option_defaults_extra_file=""
|
||||
local option_defaults_group_suffix=""
|
||||
local option_user=""
|
||||
local option_password=""
|
||||
local option_dump_label=""
|
||||
local option_compress=""
|
||||
local option_others=""
|
||||
|
||||
# Parse options, based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
|
||||
while :; do
|
||||
case ${1:-''} in
|
||||
--defaults-file)
|
||||
# defaults-file options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_defaults_file="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-file' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--defaults-file=?*)
|
||||
# defaults-file options, with value separated by =
|
||||
option_defaults_file="${1#*=}"
|
||||
;;
|
||||
--defaults-file=)
|
||||
# defaults-file options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-file' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--defaults-extra-file)
|
||||
# defaults-file options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_defaults_extra_file="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-file' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--defaults-extra-file=?*)
|
||||
# defaults-extra-file options, with value separated by =
|
||||
option_defaults_extra_file="${1#*=}"
|
||||
;;
|
||||
--defaults-extra-file=)
|
||||
# defaults-extra-file options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-extra-file' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--defaults-group-suffix)
|
||||
# defaults-group-suffix options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_defaults_group_suffix="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-group-suffix' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--defaults-group-suffix=?*)
|
||||
# defaults-group-suffix options, with value separated by =
|
||||
option_defaults_group_suffix="${1#*=}"
|
||||
;;
|
||||
--defaults-group-suffix=)
|
||||
# defaults-group-suffix options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-group-suffix' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--port)
|
||||
# port options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_port="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--port' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--port=?*)
|
||||
# port options, with value separated by =
|
||||
option_port="${1#*=}"
|
||||
;;
|
||||
--port=)
|
||||
# port options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--port' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--socket)
|
||||
# socket options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_socket="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--socket' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--socket=?*)
|
||||
# socket options, with value separated by =
|
||||
option_socket="${1#*=}"
|
||||
;;
|
||||
--socket=)
|
||||
# socket options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--socket' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--user)
|
||||
# user options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_user="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--user' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--user=?*)
|
||||
# user options, with value separated by =
|
||||
option_user="${1#*=}"
|
||||
;;
|
||||
--user=)
|
||||
# user options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--user' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--password)
|
||||
# password options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_password="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--password' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--password=?*)
|
||||
# password options, with value separated by =
|
||||
option_password="${1#*=}"
|
||||
;;
|
||||
--password=)
|
||||
# password options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--password' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--dump-label)
|
||||
# dump-label options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_dump_label="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--dump-label' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--dump-label=?*)
|
||||
# dump-label options, with value separated by =
|
||||
option_dump_label="${1#*=}"
|
||||
;;
|
||||
--dump-label=)
|
||||
# dump-label options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--dump-label' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--compress)
|
||||
# compress options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_compress="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--compress' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--compress=?*)
|
||||
# compress options, with value separated by =
|
||||
option_compress="${1#*=}"
|
||||
;;
|
||||
--compress=)
|
||||
# compress options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--compress' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--)
|
||||
# End of all options.
|
||||
shift
|
||||
option_others=${*}
|
||||
break
|
||||
;;
|
||||
-?*|[[:alnum:]]*)
|
||||
# ignore unknown options
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: unknown option '${1}' (ignored)"
|
||||
;;
|
||||
*)
|
||||
# Default case: If no more options then break out of the loop.
|
||||
break
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
case "${option_compress}" in
|
||||
none)
|
||||
compress_cmd="cat"
|
||||
dump_ext=""
|
||||
;;
|
||||
bzip2|bz|bz2)
|
||||
compress_cmd="bzip2 --best"
|
||||
dump_ext=".bz"
|
||||
;;
|
||||
xz)
|
||||
compress_cmd="xz --best"
|
||||
dump_ext=".xz"
|
||||
;;
|
||||
pigz)
|
||||
compress_cmd="pigz --best"
|
||||
dump_ext=".gz"
|
||||
;;
|
||||
gz|gzip|*)
|
||||
compress_cmd="gzip --best"
|
||||
dump_ext=".gz"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "${option_dump_label}" ]; then
|
||||
if [ -n "${option_defaults_group_suffix}" ]; then
|
||||
option_dump_label="${option_defaults_group_suffix}"
|
||||
elif [ -n "${option_port}" ]; then
|
||||
option_dump_label="${option_port}"
|
||||
elif [ -n "${option_socket}" ]; then
|
||||
option_dump_label=$(path_to_str "${option_socket}")
|
||||
else
|
||||
option_dump_label="default"
|
||||
fi
|
||||
fi
|
||||
|
||||
## Connection options
|
||||
declare -a connect_options
|
||||
connect_options=()
|
||||
if [ -n "${option_defaults_file}" ]; then
|
||||
connect_options+=(--defaults-file="${option_defaults_file}")
|
||||
fi
|
||||
if [ -n "${option_defaults_extra_file}" ]; then
|
||||
connect_options+=(--defaults-extra-file="${option_defaults_extra_file}")
|
||||
fi
|
||||
if [ -n "${option_defaults_group_suffix}" ]; then
|
||||
connect_options+=(--defaults-group-suffix="${option_defaults_group_suffix}")
|
||||
fi
|
||||
if [ -n "${option_port}" ]; then
|
||||
connect_options+=(--protocol=tcp)
|
||||
connect_options+=(--port="${option_port}")
|
||||
fi
|
||||
if [ -n "${option_socket}" ]; then
|
||||
connect_options+=(--protocol=socket)
|
||||
connect_options+=(--socket="${option_socket}")
|
||||
fi
|
||||
if [ -n "${option_user}" ]; then
|
||||
connect_options+=(--user="${option_user}")
|
||||
fi
|
||||
if [ -n "${option_password}" ]; then
|
||||
connect_options+=(--password="${option_password}")
|
||||
fi
|
||||
|
||||
local dump_dir="${LOCAL_BACKUP_DIR}/mysql-${option_dump_label}-per-base"
|
||||
local errors_dir=$(errors_dir_from_dump_dir "${dump_dir}")
|
||||
rm -rf "${dump_dir}" "${errors_dir}"
|
||||
mkdir -p "${dump_dir}" "${errors_dir}"
|
||||
# No need to change recursively, the top directory is enough
|
||||
chmod 700 "${dump_dir}" "${errors_dir}"
|
||||
|
||||
databases=$(mysql "${connect_options[@]}" --execute="show databases" --silent --skip-column-names \
|
||||
| grep --extended-regexp --invert-match "^(Database|information_schema|performance_schema|sys)")
|
||||
|
||||
for database in ${databases}; do
|
||||
local error_file="${errors_dir}/${database}.err"
|
||||
local dump_file="${dump_dir}/${database}.sql${dump_ext}"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_file}"
|
||||
|
||||
declare -a dump_options
|
||||
dump_options=()
|
||||
dump_options+=(--opt)
|
||||
dump_options+=(--force)
|
||||
dump_options+=(--events)
|
||||
dump_options+=(--hex-blob)
|
||||
dump_options+=(--databases "${database}")
|
||||
if [ -n "${option_others}" ]; then
|
||||
# word splitting is deliberate here
|
||||
# shellcheck disable=SC2206
|
||||
dump_options+=(${option_others})
|
||||
fi
|
||||
|
||||
## WARNING : logging and executing the command must be separate
|
||||
## because otherwise Bash would interpret | and > as strings and not syntax.
|
||||
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: mysqldump ${connect_options[*]} ${dump_options[*]} | ${compress_cmd} > ${dump_file}"
|
||||
mysqldump "${connect_options[@]}" "${dump_options[@]}" 2> "${error_file}" | ${compress_cmd} > "${dump_file}"
|
||||
|
||||
local last_rc=$?
|
||||
# shellcheck disable=SC2086
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: mysqldump returned an error ${last_rc}" "${error_file}"
|
||||
GLOBAL_RC=${E_DUMPFAILED}
|
||||
else
|
||||
rm -f "${error_file}"
|
||||
fi
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${dump_file}"
|
||||
|
||||
|
||||
## Schema only (no data) for each databases
|
||||
|
||||
local error_file="${errors_dir}/${database}.schema.err"
|
||||
local dump_file="${dump_dir}/${database}.schema.sql"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_file}"
|
||||
|
||||
declare -a dump_options
|
||||
dump_options=()
|
||||
dump_options+=(--force)
|
||||
dump_options+=(--no-data)
|
||||
dump_options+=(--databases "${database}")
|
||||
if [ -n "${option_others}" ]; then
|
||||
# word splitting is deliberate here
|
||||
# shellcheck disable=SC2206
|
||||
dump_options+=(${option_others})
|
||||
fi
|
||||
|
||||
dump_cmd="mysqldump ${connect_options[*]} ${dump_options[*]}"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd} 2> "${error_file}" > "${dump_file}"
|
||||
|
||||
local last_rc=$?
|
||||
# shellcheck disable=SC2086
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: mysqldump returned an error ${last_rc}" "${error_file}"
|
||||
GLOBAL_RC=${E_DUMPFAILED}
|
||||
else
|
||||
rm -f "${error_file}"
|
||||
fi
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${dump_file}"
|
||||
done
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Dump "tabs style" separate schema/data for each database of an instance
|
||||
#
|
||||
# Arguments:
|
||||
# --port=[Integer] (default: <blank>)
|
||||
# --socket=[String] (default: <blank>)
|
||||
# --user=[String] (default: <blank>)
|
||||
# --password=[String] (default: <blank>)
|
||||
# --defaults-file=[String] (default: <blank>)
|
||||
# --defaults-extra-file=[String] (default: <blank>)
|
||||
# --defaults-group-suffix=[String] (default: <blank>)
|
||||
# --dump-label=[String] (default: "default")
|
||||
# used as suffix of the dump dir to differenciate multiple instances
|
||||
# --compress=<gzip|pigz|bzip2|xz|none> (default: "gzip")
|
||||
# Other options after -- are passed as-is to mysqldump
|
||||
#######################################################################
|
||||
dump_mysql_tabs() {
|
||||
local option_port=""
|
||||
local option_socket=""
|
||||
local option_defaults_file=""
|
||||
local option_defaults_extra_file=""
|
||||
local option_defaults_group_suffix=""
|
||||
local option_user=""
|
||||
local option_password=""
|
||||
local option_dump_label=""
|
||||
local option_compress=""
|
||||
local option_others=""
|
||||
|
||||
# Parse options, based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
|
||||
while :; do
|
||||
case ${1:-''} in
|
||||
--defaults-file)
|
||||
# defaults-file options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_defaults_file="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-file' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--defaults-file=?*)
|
||||
# defaults-file options, with value separated by =
|
||||
option_defaults_file="${1#*=}"
|
||||
;;
|
||||
--defaults-file=)
|
||||
# defaults-file options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-file' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--defaults-extra-file)
|
||||
# defaults-file options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_defaults_extra_file="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-file' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--defaults-extra-file=?*)
|
||||
# defaults-extra-file options, with value separated by =
|
||||
option_defaults_extra_file="${1#*=}"
|
||||
;;
|
||||
--defaults-extra-file=)
|
||||
# defaults-extra-file options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-extra-file' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--defaults-group-suffix)
|
||||
# defaults-group-suffix options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_defaults_group_suffix="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-group-suffix' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--defaults-group-suffix=?*)
|
||||
# defaults-group-suffix options, with value separated by =
|
||||
option_defaults_group_suffix="${1#*=}"
|
||||
;;
|
||||
--defaults-group-suffix=)
|
||||
# defaults-group-suffix options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--defaults-group-suffix' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--port)
|
||||
# port options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_port="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--port' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--port=?*)
|
||||
# port options, with value separated by =
|
||||
option_port="${1#*=}"
|
||||
;;
|
||||
--port=)
|
||||
# port options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--port' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--socket)
|
||||
# socket options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_socket="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--socket' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--socket=?*)
|
||||
# socket options, with value separated by =
|
||||
option_socket="${1#*=}"
|
||||
;;
|
||||
--socket=)
|
||||
# socket options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--socket' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--user)
|
||||
# user options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_user="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--user' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--user=?*)
|
||||
# user options, with value separated by =
|
||||
option_user="${1#*=}"
|
||||
;;
|
||||
--user=)
|
||||
# user options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--user' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--password)
|
||||
# password options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_password="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--password' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--password=?*)
|
||||
# password options, with value separated by =
|
||||
option_password="${1#*=}"
|
||||
;;
|
||||
--password=)
|
||||
# password options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--password' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--dump-label)
|
||||
# dump-label options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_dump_label="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--dump-label' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--dump-label=?*)
|
||||
# dump-label options, with value separated by =
|
||||
option_dump_label="${1#*=}"
|
||||
;;
|
||||
--dump-label=)
|
||||
# dump-label options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--dump-label' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--compress)
|
||||
# compress options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_compress="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--compress' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--compress=?*)
|
||||
# compress options, with value separated by =
|
||||
option_compress="${1#*=}"
|
||||
;;
|
||||
--compress=)
|
||||
# compress options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--compress' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--)
|
||||
# End of all options.
|
||||
shift
|
||||
option_others=${*}
|
||||
break
|
||||
;;
|
||||
-?*|[[:alnum:]]*)
|
||||
# ignore unknown options
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: unknown option '${1}' (ignored)"
|
||||
;;
|
||||
*)
|
||||
# Default case: If no more options then break out of the loop.
|
||||
break
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
case "${option_compress}" in
|
||||
none)
|
||||
compress_cmd="cat"
|
||||
dump_ext=""
|
||||
;;
|
||||
bzip2|bz|bz2)
|
||||
compress_cmd="bzip2 --best"
|
||||
dump_ext=".bz"
|
||||
;;
|
||||
xz)
|
||||
compress_cmd="xz --best"
|
||||
dump_ext=".xz"
|
||||
;;
|
||||
pigz)
|
||||
compress_cmd="pigz --best"
|
||||
dump_ext=".gz"
|
||||
;;
|
||||
gz|gzip|*)
|
||||
compress_cmd="gzip --best"
|
||||
dump_ext=".gz"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "${option_dump_label}" ]; then
|
||||
if [ -n "${option_defaults_group_suffix}" ]; then
|
||||
option_dump_label="${option_defaults_group_suffix}"
|
||||
elif [ -n "${option_port}" ]; then
|
||||
option_dump_label="${option_port}"
|
||||
elif [ -n "${option_socket}" ]; then
|
||||
option_dump_label=$(path_to_str "${option_socket}")
|
||||
else
|
||||
option_dump_label="default"
|
||||
fi
|
||||
fi
|
||||
|
||||
## Connection options
|
||||
declare -a connect_options
|
||||
connect_options=()
|
||||
if [ -n "${option_defaults_file}" ]; then
|
||||
connect_options+=(--defaults-file="${option_defaults_file}")
|
||||
fi
|
||||
if [ -n "${option_defaults_extra_file}" ]; then
|
||||
connect_options+=(--defaults-extra-file="${option_defaults_extra_file}")
|
||||
fi
|
||||
if [ -n "${option_defaults_group_suffix}" ]; then
|
||||
connect_options+=(--defaults-group-suffix="${option_defaults_group_suffix}")
|
||||
fi
|
||||
if [ -n "${option_port}" ]; then
|
||||
connect_options+=(--protocol=tcp)
|
||||
connect_options+=(--port="${option_port}")
|
||||
fi
|
||||
if [ -n "${option_socket}" ]; then
|
||||
connect_options+=(--protocol=socket)
|
||||
connect_options+=(--socket="${option_socket}")
|
||||
fi
|
||||
if [ -n "${option_user}" ]; then
|
||||
connect_options+=(--user="${option_user}")
|
||||
fi
|
||||
if [ -n "${option_password}" ]; then
|
||||
connect_options+=(--password="${option_password}")
|
||||
fi
|
||||
|
||||
databases=$(mysql "${connect_options[@]}" --execute="show databases" --silent --skip-column-names \
|
||||
| grep --extended-regexp --invert-match "^(Database|information_schema|performance_schema|sys)")
|
||||
|
||||
for database in ${databases}; do
|
||||
local dump_dir="${LOCAL_BACKUP_DIR}/mysql-${option_dump_label}-tabs/${database}"
|
||||
local errors_dir=$(errors_dir_from_dump_dir "${dump_dir}")
|
||||
rm -rf "${dump_dir}" "${errors_dir}"
|
||||
mkdir -p "${dump_dir}" "${errors_dir}"
|
||||
# No need to change recursively, the top directory is enough
|
||||
chmod 700 "${dump_dir}" "${errors_dir}"
|
||||
chown -RL mysql "${dump_dir}"
|
||||
|
||||
local error_file="${errors_dir}.err"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_dir}"
|
||||
|
||||
declare -a dump_options
|
||||
dump_options=()
|
||||
dump_options+=(--force)
|
||||
dump_options+=(--quote-names)
|
||||
dump_options+=(--opt)
|
||||
dump_options+=(--events)
|
||||
dump_options+=(--hex-blob)
|
||||
dump_options+=(--skip-comments)
|
||||
dump_options+=(--fields-enclosed-by='\"')
|
||||
dump_options+=(--fields-terminated-by=',')
|
||||
dump_options+=(--tab="${dump_dir}")
|
||||
if [ -n "${option_others}" ]; then
|
||||
# word splitting is deliberate here
|
||||
# shellcheck disable=SC2206
|
||||
dump_options+=(${option_others})
|
||||
fi
|
||||
dump_options+=("${database}")
|
||||
|
||||
dump_cmd="mysqldump ${connect_options[*]} ${dump_options[*]}"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd} 2> "${error_file}"
|
||||
|
||||
local last_rc=$?
|
||||
# shellcheck disable=SC2086
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: mysqldump to ${dump_dir} returned an error ${last_rc}" "${error_file}"
|
||||
GLOBAL_RC=${E_DUMPFAILED}
|
||||
else
|
||||
rm -f "${error_file}"
|
||||
fi
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${dump_dir}"
|
||||
done
|
||||
}
|
343
evobackup-client/files/upstream/lib/dump/postgresql.sh
Normal file
343
evobackup-client/files/upstream/lib/dump/postgresql.sh
Normal file
|
@ -0,0 +1,343 @@
|
|||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC2034,SC2317,SC2155
|
||||
|
||||
#######################################################################
|
||||
# Dump a single file of all PostgreSQL databases
|
||||
#
|
||||
# Arguments:
|
||||
# --dump-label=[String] (default: "default")
|
||||
# used as suffix of the dump dir to differenciate multiple instances
|
||||
# --compress=<gzip|pigz|bzip2|xz|none> (default: "gzip")
|
||||
# Other options after -- are passed as-is to pg_dump
|
||||
#######################################################################
|
||||
dump_postgresql_global() {
|
||||
local option_dump_label=""
|
||||
local option_compress=""
|
||||
local option_others=""
|
||||
|
||||
# Parse options, based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
|
||||
while :; do
|
||||
case ${1:-''} in
|
||||
--dump-label)
|
||||
# dump-label options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_dump_label="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--dump-label' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--dump-label=?*)
|
||||
# dump-label options, with value separated by =
|
||||
option_dump_label="${1#*=}"
|
||||
;;
|
||||
--dump-label=)
|
||||
# dump-label options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--dump-label' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--compress)
|
||||
# compress options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_compress="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--compress' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--compress=?*)
|
||||
# compress options, with value separated by =
|
||||
option_compress="${1#*=}"
|
||||
;;
|
||||
--compress=)
|
||||
# compress options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--compress' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--)
|
||||
# End of all options.
|
||||
shift
|
||||
option_others=${*}
|
||||
break
|
||||
;;
|
||||
-?*|[[:alnum:]]*)
|
||||
# ignore unknown options
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: unknown option '${1}' (ignored)"
|
||||
;;
|
||||
*)
|
||||
# Default case: If no more options then break out of the loop.
|
||||
break
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
case "${option_compress}" in
|
||||
none)
|
||||
compress_cmd="cat"
|
||||
dump_ext=""
|
||||
;;
|
||||
bzip2|bz|bz2)
|
||||
compress_cmd="bzip2 --best"
|
||||
dump_ext=".bz"
|
||||
;;
|
||||
xz)
|
||||
compress_cmd="xz --best"
|
||||
dump_ext=".xz"
|
||||
;;
|
||||
pigz)
|
||||
compress_cmd="pigz --best"
|
||||
dump_ext=".gz"
|
||||
;;
|
||||
gz|gzip|*)
|
||||
compress_cmd="gzip --best"
|
||||
dump_ext=".gz"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "${option_dump_label}" ]; then
|
||||
if [ -n "${option_defaults_group_suffix}" ]; then
|
||||
option_dump_label="${option_defaults_group_suffix}"
|
||||
elif [ -n "${option_port}" ]; then
|
||||
option_dump_label="${option_port}"
|
||||
elif [ -n "${option_socket}" ]; then
|
||||
option_dump_label=$(path_to_str "${option_socket}")
|
||||
else
|
||||
option_dump_label="default"
|
||||
fi
|
||||
fi
|
||||
|
||||
local dump_dir="${LOCAL_BACKUP_DIR}/postgresql-${option_dump_label}-global"
|
||||
local errors_dir=$(errors_dir_from_dump_dir "${dump_dir}")
|
||||
rm -rf "${dump_dir}" "${errors_dir}"
|
||||
mkdir -p "${dump_dir}" "${errors_dir}"
|
||||
# No need to change recursively, the top directory is enough
|
||||
chmod 700 "${dump_dir}" "${errors_dir}"
|
||||
|
||||
## example with pg_dumpall and with compression
|
||||
local error_file="${errors_dir}/pg_dumpall.err"
|
||||
local dump_file="${dump_dir}/pg_dumpall.sql${dump_ext}"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_file}"
|
||||
|
||||
declare -a dump_options
|
||||
dump_options=()
|
||||
if [ -n "${option_others}" ]; then
|
||||
# word splitting is deliberate here
|
||||
# shellcheck disable=SC2206
|
||||
dump_options+=(${option_others})
|
||||
fi
|
||||
|
||||
dump_cmd="(sudo -u postgres pg_dumpall ${dump_options[*]}) 2> ${error_file} | ${compress_cmd} > ${dump_file}"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd}
|
||||
|
||||
local last_rc=$?
|
||||
# shellcheck disable=SC2086
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: pg_dumpall to ${dump_file} returned an error ${last_rc}" "${error_file}"
|
||||
GLOBAL_RC=${E_DUMPFAILED}
|
||||
else
|
||||
rm -f "${error_file}"
|
||||
fi
|
||||
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${dump_file}"
|
||||
|
||||
## example with pg_dumpall and without compression
|
||||
## WARNING: you need space in ~postgres
|
||||
# local error_file="${errors_dir}/pg_dumpall.err"
|
||||
# local dump_file="${dump_dir}/pg_dumpall.sql"
|
||||
# log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_file}"
|
||||
#
|
||||
# (su - postgres -c "pg_dumpall > ~/pg.dump.bak") 2> "${error_file}"
|
||||
# mv ~postgres/pg.dump.bak "${dump_file}"
|
||||
#
|
||||
# log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${dump_file}"
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Dump a compressed file per database
|
||||
#
|
||||
# Arguments: <none>
|
||||
#######################################################################
|
||||
dump_postgresql_per_base() {
|
||||
local option_dump_label=""
|
||||
local option_compress=""
|
||||
local option_others=""
|
||||
|
||||
# Parse options, based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
|
||||
while :; do
|
||||
case ${1:-''} in
|
||||
--dump-label)
|
||||
# dump-label options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_dump_label="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--dump-label' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--dump-label=?*)
|
||||
# dump-label options, with value separated by =
|
||||
option_dump_label="${1#*=}"
|
||||
;;
|
||||
--dump-label=)
|
||||
# dump-label options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--dump-label' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--compress)
|
||||
# compress options, with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
option_compress="${2}"
|
||||
shift
|
||||
else
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--compress' requires a non-empty option argument."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--compress=?*)
|
||||
# compress options, with value separated by =
|
||||
option_compress="${1#*=}"
|
||||
;;
|
||||
--compress=)
|
||||
# compress options, without value
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: '--compress' requires a non-empty option argument."
|
||||
exit 1
|
||||
;;
|
||||
--)
|
||||
# End of all options.
|
||||
shift
|
||||
option_others=${*}
|
||||
break
|
||||
;;
|
||||
-?*|[[:alnum:]]*)
|
||||
# ignore unknown options
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: unknown option '${1}' (ignored)"
|
||||
;;
|
||||
*)
|
||||
# Default case: If no more options then break out of the loop.
|
||||
break
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
case "${option_compress}" in
|
||||
none)
|
||||
compress_cmd="cat"
|
||||
dump_ext=""
|
||||
;;
|
||||
bzip2|bz|bz2)
|
||||
compress_cmd="bzip2 --best"
|
||||
dump_ext=".bz"
|
||||
;;
|
||||
xz)
|
||||
compress_cmd="xz --best"
|
||||
dump_ext=".xz"
|
||||
;;
|
||||
pigz)
|
||||
compress_cmd="pigz --best"
|
||||
dump_ext=".gz"
|
||||
;;
|
||||
gz|gzip|*)
|
||||
compress_cmd="gzip --best"
|
||||
dump_ext=".gz"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "${option_dump_label}" ]; then
|
||||
if [ -n "${option_defaults_group_suffix}" ]; then
|
||||
option_dump_label="${option_defaults_group_suffix}"
|
||||
elif [ -n "${option_port}" ]; then
|
||||
option_dump_label="${option_port}"
|
||||
elif [ -n "${option_socket}" ]; then
|
||||
option_dump_label=$(path_to_str "${option_socket}")
|
||||
else
|
||||
option_dump_label="default"
|
||||
fi
|
||||
fi
|
||||
|
||||
local dump_dir="${LOCAL_BACKUP_DIR}/postgresql-${option_dump_label}-per-base"
|
||||
local errors_dir=$(errors_dir_from_dump_dir "${dump_dir}")
|
||||
rm -rf "${dump_dir}" "${errors_dir}"
|
||||
mkdir -p "${dump_dir}" "${errors_dir}"
|
||||
# No need to change recursively, the top directory is enough
|
||||
chmod 700 "${dump_dir}" "${errors_dir}"
|
||||
|
||||
(
|
||||
# shellcheck disable=SC2164
|
||||
cd /var/lib/postgresql
|
||||
databases=$(sudo -u postgres psql -U postgres -lt | awk -F \| '{print $1}' | grep -v "template.*")
|
||||
for database in ${databases} ; do
|
||||
local error_file="${errors_dir}/${database}.err"
|
||||
local dump_file="${dump_dir}/${database}.sql${dump_ext}"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_file}"
|
||||
|
||||
declare -a dump_options
|
||||
dump_options=()
|
||||
dump_options+=(--create)
|
||||
dump_options+=(-U postgres)
|
||||
dump_options+=(-d "${database}")
|
||||
if [ -n "${option_others}" ]; then
|
||||
# word splitting is deliberate here
|
||||
# shellcheck disable=SC2206
|
||||
dump_options+=(${option_others})
|
||||
fi
|
||||
|
||||
dump_cmd="(sudo -u postgres /usr/bin/pg_dump ${dump_options[*]}) 2> ${error_file} | ${compress_cmd} > ${dump_file}"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
${dump_cmd}
|
||||
|
||||
local last_rc=$?
|
||||
# shellcheck disable=SC2086
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: pg_dump to ${dump_file} returned an error ${last_rc}" "${error_file}"
|
||||
GLOBAL_RC=${E_DUMPFAILED}
|
||||
else
|
||||
rm -f "${error_file}"
|
||||
fi
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${dump_file}"
|
||||
done
|
||||
)
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# Dump a compressed file per database
|
||||
#
|
||||
# Arguments: <none>
|
||||
#
|
||||
# TODO: add arguments to include/exclude tables
|
||||
#######################################################################
|
||||
dump_postgresql_filtered() {
|
||||
local dump_dir="${LOCAL_BACKUP_DIR}/postgresql-filtered"
|
||||
local errors_dir=$(errors_dir_from_dump_dir "${dump_dir}")
|
||||
rm -rf "${dump_dir}" "${errors_dir}"
|
||||
mkdir -p "${dump_dir}" "${errors_dir}"
|
||||
# No need to change recursively, the top directory is enough
|
||||
chmod 700 "${dump_dir}" "${errors_dir}"
|
||||
|
||||
local error_file="${errors_dir}/pg-backup.err"
|
||||
local dump_file="${dump_dir}/pg-backup.tar"
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_file}"
|
||||
|
||||
## example with all tables from MYBASE excepts TABLE1 and TABLE2
|
||||
# pg_dump -p 5432 -h 127.0.0.1 -U USER --clean -F t --inserts -f "${dump_file}" -t 'TABLE1' -t 'TABLE2' MYBASE 2> "${error_file}"
|
||||
|
||||
## example with only TABLE1 and TABLE2 from MYBASE
|
||||
# pg_dump -p 5432 -h 127.0.0.1 -U USER --clean -F t --inserts -f "${dump_file}" -T 'TABLE1' -T 'TABLE2' MYBASE 2> "${error_file}"
|
||||
|
||||
local last_rc=$?
|
||||
# shellcheck disable=SC2086
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
log_error "LOCAL_TASKS - ${FUNCNAME[0]}: pg_dump to ${dump_file} returned an error ${last_rc}" "${error_file}"
|
||||
GLOBAL_RC=${E_DUMPFAILED}
|
||||
else
|
||||
rm -f "${error_file}"
|
||||
fi
|
||||
log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${dump_file}"
|
||||
}
|
466
evobackup-client/files/upstream/lib/main.sh
Normal file
466
evobackup-client/files/upstream/lib/main.sh
Normal file
|
@ -0,0 +1,466 @@
|
|||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC2034,SC2317
|
||||
|
||||
readonly VERSION="24.04.1"
|
||||
|
||||
# set all programs to C language (english)
|
||||
export LC_ALL=C
|
||||
|
||||
# If expansion is attempted on an unset variable or parameter, the shell prints an
|
||||
# error message, and, if not interactive, exits with a non-zero status.
|
||||
set -o nounset
|
||||
# The pipeline's return status is the value of the last (rightmost) command
|
||||
# to exit with a non-zero status, or zero if all commands exit successfully.
|
||||
set -o pipefail
|
||||
# Enable trace mode if called with environment variable TRACE=1
|
||||
if [[ "${TRACE-0}" == "1" ]]; then
|
||||
set -o xtrace
|
||||
fi
|
||||
|
||||
source "${LIBDIR}/utilities.sh"
|
||||
source "${LIBDIR}/dump/elasticsearch.sh"
|
||||
source "${LIBDIR}/dump/mysql.sh"
|
||||
source "${LIBDIR}/dump/postgresql.sh"
|
||||
source "${LIBDIR}/dump/misc.sh"
|
||||
|
||||
# Called from main, it is wrapping the local_tasks function defined in the real script
|
||||
local_tasks_wrapper() {
|
||||
log "START LOCAL_TASKS"
|
||||
|
||||
# Remove old log directories (recursively)
|
||||
find "${LOCAL_BACKUP_DIR}/" -type d -name "${PROGNAME}.errors-*" -ctime +30 -exec rm -rf \;
|
||||
|
||||
local_tasks_type="$(type -t local_tasks)"
|
||||
if [ "${local_tasks_type}" = "function" ]; then
|
||||
local_tasks
|
||||
else
|
||||
log_error "There is no 'local_tasks' function to execute"
|
||||
fi
|
||||
|
||||
# TODO: check if this is still needed
|
||||
# print_error_files_content
|
||||
|
||||
log "STOP LOCAL_TASKS"
|
||||
}
|
||||
|
||||
# Called from main, it is wrapping the sync_tasks function defined in the real script
|
||||
sync_tasks_wrapper() {
|
||||
declare -a SERVERS # Indexed array for server/port values
|
||||
declare -a RSYNC_INCLUDES # Indexed array for includes
|
||||
declare -a RSYNC_EXCLUDES # Indexed array for excludes
|
||||
|
||||
case "${SYSTEM}" in
|
||||
linux)
|
||||
# NOTE: remember to single-quote paths if they contain globs (*)
|
||||
# and you want to defer expansion
|
||||
declare -a rsync_default_includes=(
|
||||
/bin
|
||||
/boot
|
||||
/lib
|
||||
/opt
|
||||
/sbin
|
||||
/usr
|
||||
)
|
||||
;;
|
||||
*bsd)
|
||||
# NOTE: remember to single-quote paths if they contain globs (*)
|
||||
# and you want to defer expansion
|
||||
declare -a rsync_default_includes=(
|
||||
/bin
|
||||
/bsd
|
||||
/sbin
|
||||
/usr
|
||||
)
|
||||
;;
|
||||
*)
|
||||
echo "Unknown system '${SYSTEM}'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
if [ -f "${CANARY_FILE}" ]; then
|
||||
rsync_default_includes+=("${CANARY_FILE}")
|
||||
fi
|
||||
readonly rsync_default_includes
|
||||
|
||||
# NOTE: remember to single-quote paths if they contain globs (*)
|
||||
# and you want to defer expansion
|
||||
declare -a rsync_default_excludes=(
|
||||
/dev
|
||||
/proc
|
||||
/run
|
||||
/sys
|
||||
/tmp
|
||||
/usr/doc
|
||||
/usr/obj
|
||||
/usr/share/doc
|
||||
/usr/src
|
||||
/var/apt
|
||||
/var/cache
|
||||
'/var/db/munin/*.tmp'
|
||||
/var/lib/amavis/amavisd.sock
|
||||
/var/lib/amavis/tmp
|
||||
/var/lib/amavis/virusmails
|
||||
'/var/lib/clamav/*.tmp'
|
||||
/var/lib/elasticsearch
|
||||
/var/lib/metche
|
||||
/var/lib/mongodb
|
||||
'/var/lib/munin/*tmp*'
|
||||
/var/lib/mysql
|
||||
/var/lib/php/sessions
|
||||
/var/lib/php5
|
||||
/var/lib/postgres
|
||||
/var/lib/postgresql
|
||||
/var/lib/sympa
|
||||
/var/lock
|
||||
/var/run
|
||||
/var/spool/postfix
|
||||
/var/spool/smtpd
|
||||
/var/spool/squid
|
||||
/var/state
|
||||
/var/tmp
|
||||
lost+found
|
||||
'.nfs.*'
|
||||
'lxc/*/rootfs/tmp'
|
||||
'lxc/*/rootfs/usr/doc'
|
||||
'lxc/*/rootfs/usr/obj'
|
||||
'lxc/*/rootfs/usr/share/doc'
|
||||
'lxc/*/rootfs/usr/src'
|
||||
'lxc/*/rootfs/var/apt'
|
||||
'lxc/*/rootfs/var/cache'
|
||||
'lxc/*/rootfs/var/lib/php5'
|
||||
'lxc/*/rootfs/var/lib/php/sessions'
|
||||
'lxc/*/rootfs/var/lock'
|
||||
'lxc/*/rootfs/var/run'
|
||||
'lxc/*/rootfs/var/state'
|
||||
'lxc/*/rootfs/var/tmp'
|
||||
/home/mysqltmp
|
||||
)
|
||||
readonly rsync_default_excludes
|
||||
|
||||
sync_tasks_type="$(type -t sync_tasks)"
|
||||
if [ "${sync_tasks_type}" = "function" ]; then
|
||||
sync_tasks
|
||||
else
|
||||
log_error "There is no 'sync_tasks' function to execute"
|
||||
fi
|
||||
}
|
||||
|
||||
sync() {
|
||||
local sync_name=${1}
|
||||
local -a rsync_servers=("${!2}")
|
||||
local -a rsync_includes=("${!3}")
|
||||
local -a rsync_excludes=("${!4}")
|
||||
|
||||
## Initialize variable to store SSH connection errors
|
||||
declare -a SSH_ERRORS=()
|
||||
|
||||
log "START SYNC_TASKS - sync=${sync_name}"
|
||||
|
||||
# echo "### sync ###"
|
||||
|
||||
# for server in "${rsync_servers[@]}"; do
|
||||
# echo "server: ${server}"
|
||||
# done
|
||||
|
||||
# for include in "${rsync_includes[@]}"; do
|
||||
# echo "include: ${include}"
|
||||
# done
|
||||
|
||||
# for exclude in "${rsync_excludes[@]}"; do
|
||||
# echo "exclude: ${exclude}"
|
||||
# done
|
||||
|
||||
local -i n=0
|
||||
local server=""
|
||||
if [ "${SERVERS_FALLBACK}" = "1" ]; then
|
||||
# We try to find a suitable server
|
||||
while :; do
|
||||
server=$(pick_server ${n} "${sync_name}")
|
||||
rc=$?
|
||||
if [ ${rc} != 0 ]; then
|
||||
GLOBAL_RC=${E_NOSRVAVAIL}
|
||||
log "STOP SYNC_TASKS - sync=${sync_name}'"
|
||||
return
|
||||
fi
|
||||
|
||||
if test_server "${server}"; then
|
||||
break
|
||||
else
|
||||
server=""
|
||||
n=$(( n + 1 ))
|
||||
fi
|
||||
done
|
||||
else
|
||||
# we force the server
|
||||
server=$(pick_server "${n}" "${sync_name}")
|
||||
fi
|
||||
|
||||
rsync_server=$(echo "${server}" | cut -d':' -f1)
|
||||
rsync_port=$(echo "${server}" | cut -d':' -f2)
|
||||
|
||||
log "SYNC_TASKS - sync=${sync_name}: use ${server}"
|
||||
|
||||
# Rsync complete log file for the current run
|
||||
RSYNC_LOGFILE="/var/log/${PROGNAME}.${sync_name}.rsync.log"
|
||||
# Rsync stats for the current run
|
||||
RSYNC_STATSFILE="/var/log/${PROGNAME}.${sync_name}.rsync-stats.log"
|
||||
|
||||
# reset Rsync log file
|
||||
if [ -n "$(command -v truncate)" ]; then
|
||||
truncate -s 0 "${RSYNC_LOGFILE}"
|
||||
truncate -s 0 "${RSYNC_STATSFILE}"
|
||||
else
|
||||
printf "" > "${RSYNC_LOGFILE}"
|
||||
printf "" > "${RSYNC_STATSFILE}"
|
||||
fi
|
||||
|
||||
# Initialize variable here, we need it later
|
||||
local -a mtree_files=()
|
||||
|
||||
if [ "${MTREE_ENABLED}" = "1" ]; then
|
||||
mtree_bin=$(command -v mtree)
|
||||
|
||||
if [ -n "${mtree_bin}" ]; then
|
||||
# Dump filesystem stats with mtree
|
||||
log "SYNC_TASKS - sync=${sync_name}: start mtree"
|
||||
|
||||
# Loop over Rsync includes
|
||||
for i in "${!rsync_includes[@]}"; do
|
||||
include="${rsync_includes[i]}"
|
||||
|
||||
if [ -d "${include}" ]; then
|
||||
# … but exclude for mtree what will be excluded by Rsync
|
||||
mtree_excludes_file="$(mktemp --tmpdir "${PROGNAME}.${sync_name}.mtree-excludes.XXXXXX")"
|
||||
add_to_temp_files "${mtree_excludes_file}"
|
||||
|
||||
for j in "${!rsync_excludes[@]}"; do
|
||||
echo "${rsync_excludes[j]}" | grep -E "^([^/]|${include})" | sed -e "s|^${include}|.|" >> "${mtree_excludes_file}"
|
||||
done
|
||||
|
||||
mtree_file="/var/log/evobackup.$(basename "${include}").mtree"
|
||||
add_to_temp_files "${mtree_file}"
|
||||
|
||||
${mtree_bin} -x -c -p "${include}" -X "${mtree_excludes_file}" > "${mtree_file}"
|
||||
mtree_files+=("${mtree_file}")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "${#mtree_files[@]}" -le 0 ]; then
|
||||
log_error "SYNC_TASKS - ${sync_name}: ERROR: mtree didn't produce any file"
|
||||
fi
|
||||
|
||||
log "SYNC_TASKS - sync=${sync_name}: stop mtree (files: ${mtree_files[*]})"
|
||||
else
|
||||
log "SYNC_TASKS - sync=${sync_name}: skip mtree (missing)"
|
||||
fi
|
||||
else
|
||||
log "SYNC_TASKS - sync=${sync_name}: skip mtree (disabled)"
|
||||
fi
|
||||
|
||||
rsync_bin=$(command -v rsync)
|
||||
# Build the final Rsync command
|
||||
|
||||
# Rsync main options
|
||||
rsync_main_args=()
|
||||
rsync_main_args+=(--archive)
|
||||
rsync_main_args+=(--itemize-changes)
|
||||
rsync_main_args+=(--quiet)
|
||||
rsync_main_args+=(--stats)
|
||||
rsync_main_args+=(--human-readable)
|
||||
rsync_main_args+=(--relative)
|
||||
rsync_main_args+=(--partial)
|
||||
rsync_main_args+=(--delete)
|
||||
rsync_main_args+=(--delete-excluded)
|
||||
rsync_main_args+=(--force)
|
||||
rsync_main_args+=(--ignore-errors)
|
||||
rsync_main_args+=(--log-file "${RSYNC_LOGFILE}")
|
||||
rsync_main_args+=(--rsh "ssh -p ${rsync_port} -o 'ConnectTimeout ${SSH_CONNECT_TIMEOUT}'")
|
||||
|
||||
# Rsync excludes
|
||||
for i in "${!rsync_excludes[@]}"; do
|
||||
rsync_main_args+=(--exclude "${rsync_excludes[i]}")
|
||||
done
|
||||
|
||||
# Rsync local sources
|
||||
rsync_main_args+=("${rsync_includes[@]}")
|
||||
|
||||
# Rsync remote destination
|
||||
rsync_main_args+=("root@${rsync_server}:${REMOTE_BACKUP_DIR}/")
|
||||
|
||||
# … log it
|
||||
log "SYNC_TASKS - sync=${sync_name}: Rsync main command : ${rsync_bin} ${rsync_main_args[*]}"
|
||||
|
||||
# … execute it
|
||||
${rsync_bin} "${rsync_main_args[@]}"
|
||||
|
||||
rsync_main_rc=$?
|
||||
|
||||
# Copy last lines of rsync log to the main log
|
||||
tail -n 30 "${RSYNC_LOGFILE}" >> "${LOGFILE}"
|
||||
# Copy Rsync stats to special file
|
||||
tail -n 30 "${RSYNC_LOGFILE}" | grep --invert-match --extended-regexp " [\<\>ch\.\*]\S{10} " > "${RSYNC_STATSFILE}"
|
||||
|
||||
# We ignore rc=24 (vanished files)
|
||||
if [ ${rsync_main_rc} -ne 0 ] && [ ${rsync_main_rc} -ne 24 ]; then
|
||||
log_error "SYNC_TASKS - sync=${sync_name}: Rsync main command returned an error ${rsync_main_rc}" "${LOGFILE}"
|
||||
GLOBAL_RC=${E_SYNCFAILED}
|
||||
else
|
||||
# Build the report Rsync command
|
||||
local -a rsync_report_args
|
||||
|
||||
rsync_report_args=()
|
||||
|
||||
# Rsync options
|
||||
rsync_report_args+=(--rsh "ssh -p ${rsync_port} -o 'ConnectTimeout ${SSH_CONNECT_TIMEOUT}'")
|
||||
|
||||
# Rsync local sources
|
||||
if [ "${#mtree_files[@]}" -gt 0 ]; then
|
||||
# send mtree files if there is any
|
||||
rsync_report_args+=("${mtree_files[@]}")
|
||||
fi
|
||||
if [ -f "${RSYNC_LOGFILE}" ]; then
|
||||
# send rsync full log file if it exists
|
||||
rsync_report_args+=("${RSYNC_LOGFILE}")
|
||||
fi
|
||||
if [ -f "${RSYNC_STATSFILE}" ]; then
|
||||
# send rsync stats log file if it exists
|
||||
rsync_report_args+=("${RSYNC_STATSFILE}")
|
||||
fi
|
||||
|
||||
# Rsync remote destination
|
||||
rsync_report_args+=("root@${rsync_server}:${REMOTE_LOG_DIR}/")
|
||||
|
||||
# … log it
|
||||
log "SYNC_TASKS - sync=${sync_name}: Rsync report command : ${rsync_bin} ${rsync_report_args[*]}"
|
||||
|
||||
# … execute it
|
||||
${rsync_bin} "${rsync_report_args[@]}"
|
||||
fi
|
||||
|
||||
log "STOP SYNC_TASKS - sync=${sync_name}"
|
||||
}
|
||||
|
||||
setup() {
|
||||
# Default return-code (0 == succes)
|
||||
GLOBAL_RC=0
|
||||
|
||||
# Possible error codes
|
||||
readonly E_NOSRVAVAIL=21 # No server is available
|
||||
readonly E_SYNCFAILED=20 # Failed sync task
|
||||
readonly E_DUMPFAILED=10 # Failed dump task
|
||||
|
||||
# explicit PATH
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin
|
||||
|
||||
# System name (linux, openbsd…)
|
||||
: "${SYSTEM:=$(uname | tr '[:upper:]' '[:lower:]')}"
|
||||
|
||||
# Hostname (for logs and notifications)
|
||||
: "${HOSTNAME:=$(hostname)}"
|
||||
|
||||
# Store pid in a file named after this program's name
|
||||
: "${PROGNAME:=$(basename "$0")}"
|
||||
: "${PIDFILE:="/var/run/${PROGNAME}.pid"}"
|
||||
|
||||
# Customize the log path if you want multiple scripts to have separate log files
|
||||
: "${LOGFILE:="/var/log/evobackup.log"}"
|
||||
|
||||
# Canary file to update before executing tasks
|
||||
: "${CANARY_FILE:="/zzz_evobackup_canary"}"
|
||||
|
||||
# Date format for log messages
|
||||
: "${DATE_FORMAT:="%Y-%m-%d %H:%M:%S"}"
|
||||
|
||||
# Should we fallback on other servers when the first one is unreachable?
|
||||
: "${SERVERS_FALLBACK:=1}"
|
||||
# timeout (in seconds) for SSH connections
|
||||
: "${SSH_CONNECT_TIMEOUT:=90}"
|
||||
|
||||
: "${LOCAL_BACKUP_DIR:="/home/backup"}"
|
||||
# shellcheck disable=SC2174
|
||||
mkdir -p -m 700 "${LOCAL_BACKUP_DIR}"
|
||||
|
||||
: "${ERRORS_DIR:="${LOCAL_BACKUP_DIR}/${PROGNAME}.errors-${START_TIME}"}"
|
||||
# shellcheck disable=SC2174
|
||||
mkdir -p -m 700 "${ERRORS_DIR}"
|
||||
|
||||
# Backup directory on remote server
|
||||
: "${REMOTE_BACKUP_DIR:="/var/backup"}"
|
||||
# Log directory in remote server
|
||||
: "${REMOTE_LOG_DIR:="/var/log"}"
|
||||
|
||||
# Email address for notifications
|
||||
: "${MAIL:="root"}"
|
||||
|
||||
# Email subject for notifications
|
||||
: "${MAIL_SUBJECT:="[info] EvoBackup - Client ${HOSTNAME}"}"
|
||||
|
||||
# Enable/disable local tasks (default: enabled)
|
||||
: "${LOCAL_TASKS:=1}"
|
||||
# Enable/disable sync tasks (default: enabled)
|
||||
: "${SYNC_TASKS:=1}"
|
||||
|
||||
# Enable/disable mtree (default: enabled)
|
||||
: "${MTREE_ENABLED:=1}"
|
||||
|
||||
# If "setup_custom" exists and is a function, let's call it
|
||||
setup_custom_type="$(type -t setup_custom)"
|
||||
if [ "${setup_custom_type}" = "function" ]; then
|
||||
setup_custom
|
||||
fi
|
||||
|
||||
## Force umask
|
||||
umask 077
|
||||
|
||||
# Initialize a list of temporary files
|
||||
declare -a TEMP_FILES=()
|
||||
# Any file in this list will be deleted when the program exits
|
||||
trap "cleanup" EXIT
|
||||
}
|
||||
|
||||
|
||||
run_evobackup() {
|
||||
# Start timer
|
||||
START_EPOCH=$(/bin/date +%s)
|
||||
START_TIME=$(/bin/date +"%Y%m%d%H%M%S")
|
||||
|
||||
# Configure variables and environment
|
||||
setup
|
||||
|
||||
log "START GLOBAL - VERSION=${VERSION} LOCAL_TASKS=${LOCAL_TASKS} SYNC_TASKS=${SYNC_TASKS}"
|
||||
|
||||
# /!\ Only one backup processus can run at the sametime /!\
|
||||
# Based on PID file, kill any running process before continuing
|
||||
enforce_single_process "${PIDFILE}"
|
||||
|
||||
# Update canary to keep track of each run
|
||||
update-evobackup-canary --who "${PROGNAME}" --file "${CANARY_FILE}"
|
||||
|
||||
if [ "${LOCAL_TASKS}" = "1" ]; then
|
||||
local_tasks_wrapper
|
||||
fi
|
||||
|
||||
if [ "${SYNC_TASKS}" = "1" ]; then
|
||||
sync_tasks_wrapper
|
||||
fi
|
||||
|
||||
STOP_EPOCH=$(/bin/date +%s)
|
||||
|
||||
case "${SYSTEM}" in
|
||||
*bsd)
|
||||
start_time=$(/bin/date -f "%s" -j "${START_EPOCH}" +"${DATE_FORMAT}")
|
||||
stop_time=$(/bin/date -f "%s" -j "${STOP_EPOCH}" +"${DATE_FORMAT}")
|
||||
;;
|
||||
*)
|
||||
start_time=$(/bin/date --date="@${START_EPOCH}" +"${DATE_FORMAT}")
|
||||
stop_time=$(/bin/date --date="@${STOP_EPOCH}" +"${DATE_FORMAT}")
|
||||
;;
|
||||
esac
|
||||
duration=$(( STOP_EPOCH - START_EPOCH ))
|
||||
|
||||
log "STOP GLOBAL - start='${start_time}' stop='${stop_time}' duration=${duration}s"
|
||||
|
||||
send_mail
|
||||
|
||||
exit ${GLOBAL_RC}
|
||||
}
|
143
evobackup-client/files/upstream/lib/utilities.sh
Normal file
143
evobackup-client/files/upstream/lib/utilities.sh
Normal file
|
@ -0,0 +1,143 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Output a message to the log file
|
||||
log() {
|
||||
local msg="${1:-$(cat /dev/stdin)}"
|
||||
local pid=$$
|
||||
|
||||
printf "[%s] %s[%s]: %s\\n" \
|
||||
"$(/bin/date +"${DATE_FORMAT}")" "${PROGNAME}" "${pid}" "${msg}" \
|
||||
>> "${LOGFILE}"
|
||||
}
|
||||
log_error() {
|
||||
local error_msg=${1}
|
||||
local error_file=${2:-""}
|
||||
|
||||
if [ -n "${error_file}" ] && [ -f "${error_file}" ]; then
|
||||
printf "\n### %s\n" "${error_msg}" >&2
|
||||
# shellcheck disable=SC2046
|
||||
if [ $(wc -l "${error_file}" | cut -d " " -f 1) -gt 30 ]; then
|
||||
printf "~~~{%s (tail -30)}\n" "${error_file}" >&2
|
||||
tail -n 30 "${error_file}" >&2
|
||||
else
|
||||
printf "~~~{%s}\n" "${error_file}" >&2
|
||||
cat "${error_file}" >&2
|
||||
fi
|
||||
printf "~~~\n" >&2
|
||||
|
||||
log "${error_msg}, check ${error_file}"
|
||||
else
|
||||
printf "\n### %s\n" "${error_msg}" >&2
|
||||
|
||||
log "${error_msg}"
|
||||
fi
|
||||
|
||||
}
|
||||
add_to_temp_files() {
|
||||
TEMP_FILES+=("${1}")
|
||||
}
|
||||
# Remove all temporary file created during the execution
|
||||
cleanup() {
|
||||
# shellcheck disable=SC2086
|
||||
rm -f "${TEMP_FILES[@]}"
|
||||
find "${ERRORS_DIR}" -type d -empty -delete
|
||||
}
|
||||
enforce_single_process() {
|
||||
local pidfile=$1
|
||||
|
||||
if [ -e "${pidfile}" ]; then
|
||||
pid=$(cat "${pidfile}")
|
||||
# Does process still exist?
|
||||
if kill -0 "${pid}" 2> /dev/null; then
|
||||
# Killing the childs of evobackup.
|
||||
for ppid in $(pgrep -P "${pid}"); do
|
||||
kill -9 "${ppid}";
|
||||
done
|
||||
# Then kill the main PID.
|
||||
kill -9 "${pid}"
|
||||
printf "%s is still running (PID %s). Process has been killed" "$0" "${pid}\\n" >&2
|
||||
else
|
||||
rm -f "${pidfile}"
|
||||
fi
|
||||
fi
|
||||
add_to_temp_files "${pidfile}"
|
||||
|
||||
echo "$$" > "${pidfile}"
|
||||
}
|
||||
|
||||
# Build the error directory (inside ERRORS_DIR) based on the dump directory path
|
||||
errors_dir_from_dump_dir() {
|
||||
local dump_dir=$1
|
||||
local relative_path=$(realpath --relative-to="${LOCAL_BACKUP_DIR}" "${dump_dir}")
|
||||
|
||||
# return absolute path
|
||||
realpath --canonicalize-missing "${ERRORS_DIR}/${relative_path}"
|
||||
}
|
||||
|
||||
# Call test_server with "HOST:PORT" string
|
||||
# It will return with 0 if the server is reachable.
|
||||
# It will return with 1 and a message on stderr if not.
|
||||
test_server() {
|
||||
local item=$1
|
||||
# split HOST and PORT from the input string
|
||||
local host=$(echo "${item}" | cut -d':' -f1)
|
||||
local port=$(echo "${item}" | cut -d':' -f2)
|
||||
|
||||
local new_error
|
||||
|
||||
# Test if the server is accepting connections
|
||||
ssh -q -o "ConnectTimeout ${SSH_CONNECT_TIMEOUT}" "${host}" -p "${port}" -t "exit"
|
||||
# shellcheck disable=SC2181
|
||||
if [ $? = 0 ]; then
|
||||
# SSH connection is OK
|
||||
return 0
|
||||
else
|
||||
# SSH connection failed
|
||||
new_error=$(printf "Failed to connect to \`%s' within %s seconds" "${item}" "${SSH_CONNECT_TIMEOUT}")
|
||||
log "${new_error}"
|
||||
SSH_ERRORS+=("${new_error}")
|
||||
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Call pick_server with an optional positive integer to get the nth server in the list.
|
||||
pick_server() {
|
||||
local -i increment=${1:-0}
|
||||
local -i list_length=${#SERVERS[@]}
|
||||
local sync_name=${2:""}
|
||||
|
||||
if (( increment >= list_length )); then
|
||||
# We've reached the end of the list
|
||||
new_error="No more server available"
|
||||
new_error="${new_error} for sync '${sync_name}'"
|
||||
log "${new_error}"
|
||||
SSH_ERRORS+=("${new_error}")
|
||||
|
||||
# Log errors to stderr
|
||||
for i in "${!SSH_ERRORS[@]}"; do
|
||||
printf "%s\n" "${SSH_ERRORS[i]}" >&2
|
||||
done
|
||||
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Extract the day of month, without leading 0 (which would give an octal based number)
|
||||
today=$(/bin/date +%e)
|
||||
# A salt is useful to randomize the starting point in the list
|
||||
# but stay identical each time it's called for a server (based on hostname).
|
||||
salt=$(hostname | cksum | cut -d' ' -f1)
|
||||
# Pick an integer between 0 and the length of the SERVERS list
|
||||
# It changes each day
|
||||
n=$(( (today + salt + increment) % list_length ))
|
||||
|
||||
echo "${SERVERS[n]}"
|
||||
}
|
||||
|
||||
send_mail() {
|
||||
tail -20 "${LOGFILE}" | mail -s "${MAIL_SUBJECT}" "${MAIL}"
|
||||
}
|
||||
|
||||
path_to_str() {
|
||||
echo "${1}" | sed -e 's|^/||; s|/$||; s|/|:|g'
|
||||
}
|
326
evobackup-client/files/upstream/lib/zzz_evobackup.sh
Normal file
326
evobackup-client/files/upstream/lib/zzz_evobackup.sh
Normal file
|
@ -0,0 +1,326 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Evobackup client
|
||||
# See https://gitea.evolix.org/evolix/evobackup
|
||||
#
|
||||
# This is a generated backup script made by:
|
||||
# command: @COMMAND@
|
||||
# version: @VERSION@
|
||||
# date: @DATE@
|
||||
|
||||
#######################################################################
|
||||
#
|
||||
# You must configure the MAIL variable to receive notifications.
|
||||
#
|
||||
# There is some optional configuration that you can do
|
||||
# at the end of this script.
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
# Email adress for notifications
|
||||
MAIL=__NOTIFICATION_MAIL__
|
||||
|
||||
#######################################################################
|
||||
#
|
||||
# The "sync_tasks" function will be called by the "run_evobackup" function.
|
||||
#
|
||||
# You can customize the variables:
|
||||
# * "SYNC_NAME" (String)
|
||||
# * "SERVERS" (Array of HOST:PORT)
|
||||
# * "RSYNC_INCLUDES" (Array of paths to include)
|
||||
# * "RSYNC_EXCLUDES" (Array of paths to exclude)
|
||||
#
|
||||
# WARNING: remember to single-quote paths if they contain globs (*)
|
||||
# and you want to pass them as-is to Rsync.
|
||||
#
|
||||
# The "sync" function can be called multiple times
|
||||
# with a different set of variables.
|
||||
# That way you can to sync to various destinations.
|
||||
#
|
||||
# Default includes/excludes are defined in the "main" library,
|
||||
# referenced at this end of this file.
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
sync_tasks() {
|
||||
|
||||
########## System-only backup (to Evolix servers) #################
|
||||
|
||||
SYNC_NAME="evolix-system"
|
||||
SERVERS=(
|
||||
__SRV0_HOST__:__SRV0_PORT__
|
||||
__SRV1_HOST__:__SRV1_PORT__
|
||||
)
|
||||
RSYNC_INCLUDES=(
|
||||
"${rsync_default_includes[@]}"
|
||||
/etc
|
||||
/root
|
||||
/var
|
||||
)
|
||||
RSYNC_EXCLUDES=(
|
||||
"${rsync_default_excludes[@]}"
|
||||
)
|
||||
sync "${SYNC_NAME}" "SERVERS[@]" "RSYNC_INCLUDES[@]" "RSYNC_EXCLUDES[@]"
|
||||
|
||||
|
||||
########## Full backup (to client servers) ########################
|
||||
|
||||
### SYNC_NAME="client-full"
|
||||
### SERVERS=(
|
||||
### client-backup00.evolix.net:2221
|
||||
### client-backup01.evolix.net:2221
|
||||
### )
|
||||
### RSYNC_INCLUDES=(
|
||||
### "${rsync_default_includes[@]}"
|
||||
### /etc
|
||||
### /root
|
||||
### /var
|
||||
### /home
|
||||
### /srv
|
||||
### )
|
||||
### RSYNC_EXCLUDES=(
|
||||
### "${rsync_default_excludes[@]}"
|
||||
### )
|
||||
### sync "${SYNC_NAME}" "SERVERS[@]" "RSYNC_INCLUDES[@]" "RSYNC_EXCLUDES[@]"
|
||||
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
#
|
||||
# The "local_tasks" function will be called by the "run_evobackup" function.
|
||||
#
|
||||
# You can call any available "dump_xxx" function
|
||||
# (usually installed at /usr/local/lib/evobackup/dump-*.sh)
|
||||
#
|
||||
# You can also write some custom functions and call them.
|
||||
# A "dump_custom" example is available further down.
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
local_tasks() {
|
||||
|
||||
########## Server state ###########
|
||||
|
||||
# Run dump-server-state to extract system information
|
||||
#
|
||||
# Options : any dump-server-state supported option
|
||||
# (except --dump-dir that will be overwritten)
|
||||
# See 'dump-server-state -h' for details.
|
||||
#
|
||||
dump_server_state
|
||||
|
||||
########## MySQL ##################
|
||||
|
||||
# Very common strategy for a single instance server with default configuration :
|
||||
#
|
||||
### dump_mysql_global; dump_mysql_grants; dump_mysql_summary
|
||||
#
|
||||
# See below for details regarding dump functions for MySQL/MariaDB
|
||||
|
||||
# Dump all databases in a single compressed file
|
||||
#
|
||||
# Options :
|
||||
# --masterdata (default: <absent>)
|
||||
# --port=[Integer] (default: <blank>)
|
||||
# --socket=[String] (default: <blank>)
|
||||
# --user=[String] (default: <blank>)
|
||||
# --password=[String] (default: <blank>)
|
||||
# --defaults-file=[String] (default: <blank>)
|
||||
# --defaults-extra-file=[String] (default: <blank>)
|
||||
# --defaults-group-suffix=[String] (default: <blank>)
|
||||
# --dump-label=[String] (default: "default")
|
||||
# used as suffix of the dump dir to differenciate multiple instances
|
||||
#
|
||||
### dump_mysql_global
|
||||
|
||||
# Dump each database separately, in a compressed file
|
||||
#
|
||||
# Options :
|
||||
# --port=[Integer] (default: <blank>)
|
||||
# --socket=[String] (default: <blank>)
|
||||
# --user=[String] (default: <blank>)
|
||||
# --password=[String] (default: <blank>)
|
||||
# --defaults-file=[String] (default: <blank>)
|
||||
# --defaults-extra-file=[String] (default: <blank>)
|
||||
# --defaults-group-suffix=[String] (default: <blank>)
|
||||
# --dump-label=[String] (default: "default")
|
||||
# used as suffix of the dump dir to differenciate multiple instances
|
||||
#
|
||||
### dump_mysql_per_base
|
||||
|
||||
# Dump permissions of an instance (using pt-show-grants)
|
||||
#
|
||||
# Options :
|
||||
# --port=[Integer] (default: <blank>)
|
||||
# --socket=[String] (default: <blank>)
|
||||
# --user=[String] (default: <blank>)
|
||||
# --password=[String] (default: <blank>)
|
||||
# --defaults-file=[String] (default: <blank>)
|
||||
# --dump-label=[String] (default: "default")
|
||||
# used as suffix of the dump dir to differenciate multiple instances
|
||||
#
|
||||
# WARNING - unsupported options :
|
||||
# --defaults-extra-file
|
||||
# --defaults-group-suffix
|
||||
# You have to provide credentials manually
|
||||
#
|
||||
### dump_mysql_grants
|
||||
|
||||
# Dump complete summary of an instance (using pt-mysql-summary)
|
||||
#
|
||||
# Options :
|
||||
# --port=[Integer] (default: <blank>)
|
||||
# --socket=[String] (default: <blank>)
|
||||
# --user=[String] (default: <blank>)
|
||||
# --password=[String] (default: <blank>)
|
||||
# --defaults-file=[String] (default: <blank>)
|
||||
# --defaults-extra-file=[String] (default: <blank>)
|
||||
# --defaults-group-suffix=[String] (default: <blank>)
|
||||
# --dump-label=[String] (default: "default")
|
||||
# used as suffix of the dump dir to differenciate multiple instances
|
||||
#
|
||||
### dump_mysql_summary
|
||||
|
||||
# Dump each table in separate schema/data files
|
||||
#
|
||||
# Options :
|
||||
# --port=[Integer] (default: <blank>)
|
||||
# --socket=[String] (default: <blank>)
|
||||
# --user=[String] (default: <blank>)
|
||||
# --password=[String] (default: <blank>)
|
||||
# --defaults-file=[String] (default: <blank>)
|
||||
# --defaults-extra-file=[String] (default: <blank>)
|
||||
# --defaults-group-suffix=[String] (default: <blank>)
|
||||
# --dump-label=[String] (default: "default")
|
||||
# used as suffix of the dump dir to differenciate multiple instances
|
||||
#
|
||||
### dump_mysql_tabs
|
||||
|
||||
########## PostgreSQL #############
|
||||
|
||||
# Dump all databases in a single file (compressed or not)
|
||||
#
|
||||
### dump_postgresql_global
|
||||
|
||||
# Dump a specific databse with only some tables, or all but some tables (must be configured)
|
||||
#
|
||||
### dump_postgresql_filtered
|
||||
|
||||
# Dump each database separately, in a compressed file
|
||||
#
|
||||
### dump_postgresql_per_base
|
||||
|
||||
########## MongoDB ################
|
||||
|
||||
### dump_mongodb [--user=foo] [--password=123456789]
|
||||
|
||||
########## Redis ##################
|
||||
|
||||
# Copy data file for all instances
|
||||
#
|
||||
### dump_redis [--instances=<all|instance1|instance2>]
|
||||
|
||||
########## Elasticsearch ##########
|
||||
|
||||
# Snapshot data for a single-node cluster
|
||||
#
|
||||
### dump_elasticsearch_snapshot_singlenode [--protocol=http] [--host=localhost] [--port=9200] [--user=foo] [--password=123456789] [--repository=snaprepo] [--snapshot=snapshot.daily]
|
||||
|
||||
# Snapshot data for a multi-node cluster
|
||||
#
|
||||
### dump_elasticsearch_snapshot_multinode [--protocol=http] [--host=localhost] [--port=9200] [--user=foo] [--password=123456789] [--repository=snaprepo] [--snapshot=snapshot.daily] [--nfs-server=192.168.2.1]
|
||||
|
||||
########## RabbitMQ ###############
|
||||
|
||||
### dump_rabbitmq
|
||||
|
||||
########## MegaCli ################
|
||||
|
||||
# Copy RAID config
|
||||
#
|
||||
### dump_megacli_config
|
||||
|
||||
# Dump file access control lists
|
||||
#
|
||||
### dump_facl
|
||||
|
||||
########## OpenLDAP ###############
|
||||
|
||||
### dump_ldap
|
||||
|
||||
########## Network ################
|
||||
|
||||
# Dump network routes with mtr and traceroute (warning: could be long with aggressive firewalls)
|
||||
#
|
||||
### dump_traceroute --targets=host_or_ip[,host_or_ip]
|
||||
dump_traceroute --targets=8.8.8.8,www.evolix.fr,travaux.evolix.net
|
||||
|
||||
# No-op, in case nothing is enabled
|
||||
:
|
||||
}
|
||||
|
||||
# This is an example for a custom dump function
|
||||
# Uncomment, customize and call it from the "local_tasks" function
|
||||
### dump_custom() {
|
||||
### # Set dump and errors directories and files
|
||||
### local dump_dir="${LOCAL_BACKUP_DIR}/custom"
|
||||
### local dump_file="${dump_dir}/dump.gz"
|
||||
### local errors_dir=$(errors_dir_from_dump_dir "${dump_dir}")
|
||||
### local error_file="${errors_dir}/dump.err"
|
||||
###
|
||||
### # Reset dump and errors directories
|
||||
### rm -rf "${dump_dir}" "${errors_dir}"
|
||||
### # shellcheck disable=SC2174
|
||||
### mkdir -p -m 700 "${dump_dir}" "${errors_dir}"
|
||||
###
|
||||
### # Log the start of the function
|
||||
### log "LOCAL_TASKS - ${FUNCNAME[0]}: start ${dump_file}"
|
||||
###
|
||||
### # Prepare the dump command (errors go to the error file and the data to the dump file)
|
||||
### dump_cmd="my-dump-command 2> ${error_file} > ${dump_file}"
|
||||
### log "LOCAL_TASKS - ${FUNCNAME[0]}: ${dump_cmd}"
|
||||
###
|
||||
### # Execute the dump command
|
||||
### ${dump_cmd}
|
||||
###
|
||||
### # Check result and deal with potential errors
|
||||
### local last_rc=$?
|
||||
### # shellcheck disable=SC2086
|
||||
### if [ ${last_rc} -ne 0 ]; then
|
||||
### log_error "LOCAL_TASKS - ${FUNCNAME[0]}: my-dump-command to ${dump_file} returned an error ${last_rc}" "${error_file}"
|
||||
### GLOBAL_RC=${E_DUMPFAILED}
|
||||
### else
|
||||
### rm -f "${error_file}"
|
||||
### fi
|
||||
###
|
||||
### # Log the end of the function
|
||||
### log "LOCAL_TASKS - ${FUNCNAME[0]}: stop ${dump_file}"
|
||||
### }
|
||||
|
||||
########## Optional configuration #####################################
|
||||
|
||||
setup_custom() {
|
||||
# System name ("linux" and "openbsd" currently supported)
|
||||
### SYSTEM="$(uname)"
|
||||
|
||||
# Host name for logs and notifications
|
||||
### HOSTNAME="$(hostname)"
|
||||
|
||||
# Email subject for notifications
|
||||
### MAIL_SUBJECT="[info] EvoBackup - Client ${HOSTNAME}"
|
||||
|
||||
# No-op in case nothing is executed
|
||||
:
|
||||
}
|
||||
|
||||
########## Libraries ##################################################
|
||||
|
||||
# Change this to wherever you install the libraries
|
||||
LIBDIR="/usr/local/lib/evobackup"
|
||||
|
||||
source "${LIBDIR}/main.sh"
|
||||
|
||||
########## Let's go! ##################################################
|
||||
|
||||
run_evobackup
|
50
evobackup-client/tasks/install.yml
Normal file
50
evobackup-client/tasks/install.yml
Normal file
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
|
||||
- name: Dependencies are present
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- rsync
|
||||
- mtree-netbsd
|
||||
state: present
|
||||
|
||||
- name: "Remount /usr if needed"
|
||||
include_role:
|
||||
name: remount-usr
|
||||
when: evobackup_client__lib_dir is search("/usr") or evobackup_client__bin_dir is search("/usr")
|
||||
|
||||
- name: copy evobackup libs
|
||||
ansible.builtin.copy:
|
||||
src: upstream/lib
|
||||
dest: "{{ evobackup_client__lib_dir }}/"
|
||||
force: True
|
||||
mode: "0644"
|
||||
owner: root
|
||||
group: root
|
||||
|
||||
- name: copy evobackupctl script
|
||||
ansible.builtin.copy:
|
||||
src: upstream/bin/evobackupctl
|
||||
dest: "{{ evobackup_client__bin_dir }}/evobackupctl"
|
||||
force: True
|
||||
mode: "0755"
|
||||
owner: root
|
||||
group: root
|
||||
|
||||
- name: LIBDIR is customized in evobackupctl
|
||||
ansible.builtin.replace:
|
||||
path: "{{ evobackup_client__bin_dir }}/evobackupctl"
|
||||
regexp: "^LIBDIR=.+"
|
||||
replace: "LIBDIR=\"{{ evobackup_client__lib_dir }}\""
|
||||
|
||||
- name: Evobackup canary cron is present
|
||||
ansible.builtin.template:
|
||||
src: update-evobackup-canary.sh.j2
|
||||
dest: "{{ evobackup_client__update_canary_path }}"
|
||||
mode: "0700"
|
||||
when: evobackup_client__update_canary_enable | bool
|
||||
|
||||
- name: Evobackup canary cron is absent
|
||||
ansible.builtin.file:
|
||||
path: "{{ evobackup_client__update_canary_path }}"
|
||||
state: absent
|
||||
when: not ( evobackup_client__update_canary_enable | bool)
|
|
@ -1,26 +1,31 @@
|
|||
---
|
||||
|
||||
- ansible.builtin.include: "ssh_key.yml"
|
||||
tags:
|
||||
- evobackup_client
|
||||
- evobackup_client_backup_ssh_key
|
||||
- name: Install evobackup client components
|
||||
ansible.builtin.include: "install.yml"
|
||||
|
||||
- ansible.builtin.include: "jail.yml"
|
||||
tags:
|
||||
- evobackup_client
|
||||
- evobackup_client_jail
|
||||
### This is commented because supposedly non-functionnal
|
||||
|
||||
- ansible.builtin.include: "upload_scripts.yml"
|
||||
tags:
|
||||
- evobackup_client
|
||||
- evobackup_client_backup_scripts
|
||||
# - ansible.builtin.include: "ssh_key.yml"
|
||||
# tags:
|
||||
# - evobackup_client
|
||||
# - evobackup_client_backup_ssh_key
|
||||
|
||||
- ansible.builtin.include: "open_ssh_ports.yml"
|
||||
tags:
|
||||
- evobackup_client
|
||||
- evobackup_client_backup_firewall
|
||||
# - ansible.builtin.include: "jail.yml"
|
||||
# tags:
|
||||
# - evobackup_client
|
||||
# - evobackup_client_jail
|
||||
|
||||
- ansible.builtin.include: "verify_ssh.yml"
|
||||
tags:
|
||||
- evobackup_client
|
||||
- evobackup_client_backup_hosts
|
||||
# - ansible.builtin.include: "upload_scripts.yml"
|
||||
# tags:
|
||||
# - evobackup_client
|
||||
# - evobackup_client_backup_scripts
|
||||
|
||||
# - ansible.builtin.include: "open_ssh_ports.yml"
|
||||
# tags:
|
||||
# - evobackup_client
|
||||
# - evobackup_client_backup_firewall
|
||||
|
||||
# - ansible.builtin.include: "verify_ssh.yml"
|
||||
# tags:
|
||||
# - evobackup_client
|
||||
# - evobackup_client_backup_hosts
|
||||
|
|
3
evobackup-client/templates/update-evobackup-canary.sh.j2
Normal file
3
evobackup-client/templates/update-evobackup-canary.sh.j2
Normal file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
update-evobackup-canary --who {{ evobackup_client__update_canary_who | mandatory }}
|
|
@ -1,305 +0,0 @@
|
|||
#!/bin/sh
|
||||
# Careful, the zzz_evobackup template was last updated on 2020/06/08
|
||||
#
|
||||
# Script Evobackup client
|
||||
# See https://gitea.evolix.org/evolix/evobackup
|
||||
#
|
||||
# Author: Gregory Colpart <reg@evolix.fr>
|
||||
# Contributors:
|
||||
# Romain Dessort <rdessort@evolix.fr>
|
||||
# Benoît Série <bserie@evolix.fr>
|
||||
# Tristan Pilat <tpilat@evolix.fr>
|
||||
# Victor Laborie <vlaborie@evolix.fr>
|
||||
# Jérémy Lecour <jlecour@evolix.fr>
|
||||
#
|
||||
# Licence: AGPLv3
|
||||
#
|
||||
# /!\ DON'T FORGET TO SET "MAIL" and "SERVERS" VARIABLES
|
||||
|
||||
# Fail on unassigned variables
|
||||
set -u
|
||||
|
||||
##### Configuration ###################################################
|
||||
|
||||
# email adress for notifications
|
||||
MAIL={{ evobackup_client__mail }}
|
||||
|
||||
# list of hosts (hostname or IP) and SSH port for Rsync
|
||||
SERVERS="{% for host in evobackup_client__hosts %}{{ host.name }}:{{ host.port }}{% if loop.index != loop.length %} {% endif %}{% endfor %}"
|
||||
|
||||
# Should we fallback on servers when the first is unreachable ?
|
||||
SERVERS_FALLBACK={{ evobackup_client__servers_fallback }}
|
||||
|
||||
# timeout (in seconds) for SSH connections
|
||||
SSH_CONNECT_TIMEOUT=${SSH_CONNECT_TIMEOUT:-30}
|
||||
|
||||
## We use /home/backup : feel free to use your own dir
|
||||
LOCAL_BACKUP_DIR="{{ evobackup_client__backup_path }}"
|
||||
|
||||
# You can set "linux" or "bsd" manually or let it choose automatically
|
||||
SYSTEM=$(uname | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
# Change these 2 variables if you have more than one backup cron
|
||||
PIDFILE="{{ evobackup_client__pid_path }}"
|
||||
LOGFILE="{{ evobackup_client__log_path }}"
|
||||
|
||||
## Enable/Disable tasks
|
||||
LOCAL_TASKS=${LOCAL_TASKS:-1}
|
||||
SYNC_TASKS=${SYNC_TASKS:-1}
|
||||
|
||||
##### SETUP AND FUNCTIONS #############################################
|
||||
|
||||
BEGINNING=$(/bin/date +"%d-%m-%Y ; %H:%M")
|
||||
|
||||
# shellcheck disable=SC2174
|
||||
mkdir -p -m 700 ${LOCAL_BACKUP_DIR}
|
||||
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin
|
||||
|
||||
## lang = C for english outputs
|
||||
export LANGUAGE=C
|
||||
export LANG=C
|
||||
|
||||
## Force umask
|
||||
umask 077
|
||||
|
||||
## Initialize variable to store SSH connection errors
|
||||
SERVERS_SSH_ERRORS=""
|
||||
|
||||
# Call test_server with "HOST:PORT" string
|
||||
# It will return with 0 if the server is reachable.
|
||||
# It will return with 1 and a message on stderr if not.
|
||||
test_server() {
|
||||
item=$1
|
||||
# split HOST and PORT from the input string
|
||||
host=$(echo "${item}" | cut -d':' -f1)
|
||||
port=$(echo "${item}" | cut -d':' -f2)
|
||||
|
||||
# Test if the server is accepting connections
|
||||
ssh -q -o "ConnectTimeout ${SSH_CONNECT_TIMEOUT}" -i {{ evobackup_client__root_key_path }} "${host}" -p "${port}" -t "exit"
|
||||
# shellcheck disable=SC2181
|
||||
if [ $? = 0 ]; then
|
||||
# SSH connection is OK
|
||||
return 0
|
||||
else
|
||||
# SSH connection failed
|
||||
new_error=$(printf "Failed to connect to \`%s' within %s seconds" "${item}" "${SSH_CONNECT_TIMEOUT}")
|
||||
SERVERS_SSH_ERRORS=$(printf "%s\\n%s" "${SERVERS_SSH_ERRORS}" "${new_error}" | sed -e '/^$/d')
|
||||
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
# Call pick_server with an optional positive integer to get the nth server in the list.
|
||||
pick_server() {
|
||||
increment=${1:-0}
|
||||
list_length=$(echo "${SERVERS}" | wc -w)
|
||||
|
||||
if [ "${increment}" -ge "${list_length}" ]; then
|
||||
# We've reached the end of the list
|
||||
new_error="No more server available"
|
||||
SERVERS_SSH_ERRORS=$(printf "%s\\n%s" "${SERVERS_SSH_ERRORS}" "${new_error}" | sed -e '/^$/d')
|
||||
|
||||
# Log errors to stderr
|
||||
printf "%s\\n" "${SERVERS_SSH_ERRORS}" >&2
|
||||
# Log errors to logfile
|
||||
printf "%s\\n" "${SERVERS_SSH_ERRORS}" >> $LOGFILE
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Extract the day of month, without leading 0 (which would give an octal based number)
|
||||
today=$(date +%e)
|
||||
# A salt is useful to randomize the starting point in the list
|
||||
# but stay identical each time it's called for a server (based on hostname).
|
||||
salt=$(hostname | cksum | cut -d' ' -f1)
|
||||
# Pick an integer between 0 and the length of the SERVERS list
|
||||
# It changes each day
|
||||
item=$(( (today + salt + increment) % list_length ))
|
||||
# cut starts counting fields at 1, not 0.
|
||||
field=$(( item + 1 ))
|
||||
|
||||
echo "${SERVERS}" | cut -d' ' -f${field}
|
||||
}
|
||||
|
||||
## Verify other evobackup process and kill if needed
|
||||
if [ -e "${PIDFILE}" ]; then
|
||||
pid=$(cat "${PIDFILE}")
|
||||
# Does process still exist ?
|
||||
if kill -0 "${pid}" 2>/dev/null; then
|
||||
# Killing the childs of evobackup.
|
||||
for ppid in $(pgrep -P "${pid}"); do
|
||||
kill -9 "${ppid}";
|
||||
done
|
||||
# Then kill the main PID.
|
||||
kill -9 "${pid}"
|
||||
printf "%s is still running (PID %s). Process has been killed" "$0" "${pid}\\n" >&2
|
||||
else
|
||||
rm -f ${PIDFILE}
|
||||
fi
|
||||
fi
|
||||
echo "$$" > ${PIDFILE}
|
||||
# shellcheck disable=SC2064
|
||||
trap "rm -f ${PIDFILE}" EXIT
|
||||
|
||||
|
||||
##### LOCAL BACKUP ####################################################
|
||||
|
||||
if [ "${LOCAL_TASKS}" = "1" ]; then
|
||||
## Dump system and kernel versions
|
||||
uname -a > ${LOCAL_BACKUP_DIR}/uname
|
||||
|
||||
## Dump network routes with mtr and traceroute (warning: could be long with aggressive firewalls)
|
||||
for addr in 8.8.8.8 www.evolix.fr travaux.evolix.net; do
|
||||
mtr -r ${addr} > ${LOCAL_BACKUP_DIR}/mtr-${addr}
|
||||
traceroute -n ${addr} > ${LOCAL_BACKUP_DIR}/traceroute-${addr} 2>&1
|
||||
done
|
||||
|
||||
## Dump process with ps
|
||||
ps auwwx >${LOCAL_BACKUP_DIR}/ps.out
|
||||
|
||||
if [ "${SYSTEM}" = "linux" ]; then
|
||||
## Dump network connections with ss
|
||||
ss -taupen > ${LOCAL_BACKUP_DIR}/netstat.out
|
||||
|
||||
## List Debian packages
|
||||
dpkg -l > ${LOCAL_BACKUP_DIR}/packages
|
||||
dpkg --get-selections > ${LOCAL_BACKUP_DIR}/packages.getselections
|
||||
apt-cache dumpavail > ${LOCAL_BACKUP_DIR}/packages.available
|
||||
|
||||
## Dump MBR / table partitions
|
||||
disks=$(lsblk -l | grep disk | grep -v -E '(drbd|fd[0-9]+)' | awk '{print $1}')
|
||||
for disk in ${disks}; do
|
||||
dd if="/dev/${disk}" of="${LOCAL_BACKUP_DIR}/MBR-${disk}" bs=512 count=1 2>&1 | grep -Ev "(records in|records out|512 bytes)"
|
||||
fdisk -l "/dev/${disk}" > "${LOCAL_BACKUP_DIR}/partitions-${disk}" 2>&1
|
||||
done
|
||||
cat ${LOCAL_BACKUP_DIR}/partitions-* > ${LOCAL_BACKUP_DIR}/partitions
|
||||
|
||||
## Dump iptables
|
||||
if [ -x /sbin/iptables ]; then
|
||||
{ /sbin/iptables -L -n -v; /sbin/iptables -t filter -L -n -v; } > ${LOCAL_BACKUP_DIR}/iptables.txt
|
||||
fi
|
||||
|
||||
## Dump findmnt(8) output
|
||||
FINDMNT_BIN=$(command -v findmnt)
|
||||
if [ -x "${FINDMNT_BIN}" ]; then
|
||||
${FINDMNT_BIN} > ${LOCAL_BACKUP_DIR}/findmnt.txt
|
||||
fi
|
||||
else
|
||||
## Dump network connections with netstat
|
||||
netstat -finet -atn > ${LOCAL_BACKUP_DIR}/netstat.out
|
||||
|
||||
## List OpenBSD packages
|
||||
pkg_info -m > ${LOCAL_BACKUP_DIR}/packages
|
||||
|
||||
## Dump MBR / table partitions
|
||||
disklabel sd0 > ${LOCAL_BACKUP_DIR}/partitions
|
||||
|
||||
## Dump pf infos
|
||||
pfctl -sa > ${LOCAL_BACKUP_DIR}/pfctl-sa.txt
|
||||
|
||||
fi
|
||||
|
||||
## Dump rights
|
||||
#getfacl -R /var > ${LOCAL_BACKUP_DIR}/rights-var.txt
|
||||
#getfacl -R /etc > ${LOCAL_BACKUP_DIR}/rights-etc.txt
|
||||
#getfacl -R /usr > ${LOCAL_BACKUP_DIR}/rights-usr.txt
|
||||
#getfacl -R /home > ${LOCAL_BACKUP_DIR}/rights-home.txt
|
||||
|
||||
fi
|
||||
|
||||
##### REMOTE BACKUP ###################################################
|
||||
|
||||
n=0
|
||||
server=""
|
||||
if [ "${SERVERS_FALLBACK}" = "1" ]; then
|
||||
# We try to find a suitable server
|
||||
while :; do
|
||||
server=$(pick_server "${n}")
|
||||
test $? = 0 || exit 2
|
||||
|
||||
if test_server "${server}"; then
|
||||
break
|
||||
else
|
||||
server=""
|
||||
n=$(( n + 1 ))
|
||||
fi
|
||||
done
|
||||
else
|
||||
# we force the server
|
||||
server=$(pick_server "${n}")
|
||||
fi
|
||||
|
||||
SSH_SERVER=$(echo "${server}" | cut -d':' -f1)
|
||||
SSH_PORT=$(echo "${server}" | cut -d':' -f2)
|
||||
|
||||
HOSTNAME=$(hostname)
|
||||
|
||||
if [ "${SYSTEM}" = "linux" ]; then
|
||||
rep="/bin /boot /lib /opt /sbin /usr /srv"
|
||||
else
|
||||
rep="/bsd /bin /sbin /usr"
|
||||
fi
|
||||
|
||||
|
||||
if [ "${SYNC_TASKS}" = "1" ]; then
|
||||
# /!\ DO NOT USE COMMENTS in the rsync command /!\
|
||||
# It breaks the command and destroys data, simply remove (or add) lines.
|
||||
|
||||
# Remote shell command
|
||||
RSH_COMMAND="ssh -i {{ evobackup_client__root_key_path }} -p ${SSH_PORT} -o 'ConnectTimeout ${SSH_CONNECT_TIMEOUT}'"
|
||||
|
||||
# ignore check because we want it to split the different arguments to $rep
|
||||
# shellcheck disable=SC2086
|
||||
rsync -avzh --stats --delete --delete-excluded --force --ignore-errors --partial \
|
||||
--exclude "lost+found" \
|
||||
--exclude ".nfs.*" \
|
||||
--exclude "/var/log" \
|
||||
--exclude "/var/log/evobackup*" \
|
||||
--exclude "/var/lib/mysql" \
|
||||
--exclude "/var/lib/postgres" \
|
||||
--exclude "/var/lib/postgresql" \
|
||||
--exclude "/var/lib/sympa" \
|
||||
--exclude "/var/lib/metche" \
|
||||
--exclude "/var/run" \
|
||||
--exclude "/var/lock" \
|
||||
--exclude "/var/state" \
|
||||
--exclude "/var/apt" \
|
||||
--exclude "/var/cache" \
|
||||
--exclude "/usr/src" \
|
||||
--exclude "/usr/doc" \
|
||||
--exclude "/usr/share/doc" \
|
||||
--exclude "/usr/obj" \
|
||||
--exclude "dev" \
|
||||
--exclude "/var/spool/postfix" \
|
||||
--exclude "/var/lib/amavis/amavisd.sock" \
|
||||
--exclude "/var/lib/munin/*tmp*" \
|
||||
--exclude "/var/lib/php5" \
|
||||
--exclude "/var/spool/squid" \
|
||||
--exclude "/var/lib/elasticsearch" \
|
||||
--exclude "/var/lib/amavis/tmp" \
|
||||
--exclude "/var/lib/clamav/*.tmp" \
|
||||
--exclude "/home/mysqltmp" \
|
||||
--exclude "/var/lib/php/sessions" \
|
||||
${rep} \
|
||||
/etc \
|
||||
/root \
|
||||
/var \
|
||||
-e "${RSH_COMMAND}" \
|
||||
"root@${SSH_SERVER}:/var/backup/" \
|
||||
| tail -30 >> $LOGFILE
|
||||
fi
|
||||
|
||||
##### REPORTING #######################################################
|
||||
|
||||
END=$(/bin/date +"%d-%m-%Y ; %H:%M")
|
||||
|
||||
printf "EvoBackup - %s - START %s ON %s (LOCAL_TASKS=%s SYNC_TASKS=%s)\\n" \
|
||||
"${HOSTNAME}" "${BEGINNING}" "${SSH_SERVER}" "${LOCAL_TASKS}" "${SYNC_TASKS}" \
|
||||
>> $LOGFILE
|
||||
|
||||
printf "EvoBackup - %s - STOP %s ON %s (LOCAL_TASKS=%s SYNC_TASKS=%s)\\n" \
|
||||
"${HOSTNAME}" "${END}" "${SSH_SERVER}" "${LOCAL_TASKS}" "${SYNC_TASKS}" \
|
||||
>> $LOGFILE
|
||||
|
||||
tail -10 $LOGFILE | \
|
||||
mail -s "[info] EvoBackup - Client ${HOSTNAME}" \
|
||||
${MAIL}
|
|
@ -142,6 +142,9 @@ evolinux_ssh_group: "evolinux-ssh"
|
|||
#
|
||||
# evolinux_users_include: True
|
||||
|
||||
# bash
|
||||
evolinux_bash_config_include: true
|
||||
|
||||
# root
|
||||
|
||||
evolinux_root_include: True
|
||||
|
|
|
@ -64,12 +64,19 @@
|
|||
when: evolinux_logs_default_dateext | bool
|
||||
|
||||
# Logcheck
|
||||
- name: Check if journald.logfiles exists
|
||||
stat:
|
||||
path: /etc/logcheck/logcheck.logfiles.d/journal.logfiles
|
||||
register: _logcheck_journald_logfiles
|
||||
|
||||
- name: Disable logcheck monitoring of journald
|
||||
ansible.builtin.lineinfile:
|
||||
dest: /etc/logrotate.conf
|
||||
dest: /etc/logcheck/logcheck.logfiles.d/journal.logfiles
|
||||
line: "#journal"
|
||||
regexp: "^journal"
|
||||
when: evolinux_logs_disable_logcheck_journald | bool
|
||||
when:
|
||||
- _logcheck_journald_logfiles.stat.exists
|
||||
- evolinux_logs_disable_logcheck_journald | bool
|
||||
|
||||
# Journald
|
||||
- name: /etc/systemd/journald.conf.d/ is present
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
|
||||
- name: Bash configuration
|
||||
ansible.builtin.import_tasks: bash.yml
|
||||
when: evolinux_bash_config_include | bool
|
||||
|
||||
- name: Root user configuration
|
||||
ansible.builtin.import_tasks: root.yml
|
||||
|
@ -147,9 +148,14 @@
|
|||
tags:
|
||||
- postfix
|
||||
|
||||
- name: Autosysadmin
|
||||
- name: Autosysadmin (agent)
|
||||
ansible.builtin.include_role:
|
||||
name: 'evolix/autosysadmin'
|
||||
name: 'evolix/autosysadmin-agent'
|
||||
when: evolinux_autosysadmin_include | bool
|
||||
|
||||
- name: Autosysadmin (restart_nrpe)
|
||||
ansible.builtin.include_role:
|
||||
name: 'evolix/autosysadmin-restart_nrpe'
|
||||
when: evolinux_autosysadmin_include | bool
|
||||
|
||||
- name: fail2ban
|
||||
|
|
|
@ -24,6 +24,8 @@ 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 = NOPASSWD: /usr/local/bin/mvcli info -o blk
|
||||
nagios ALL = NOPASSWD: /usr/local/bin/mvcli info -o vd
|
||||
nagios ALL = NOPASSWD: /usr/local/lib/nagios/plugins/check_gluster.rb
|
||||
|
||||
nagios ALL = (clamav) NOPASSWD: /usr/bin/clamscan /tmp/safe.txt
|
||||
|
|
|
@ -115,7 +115,7 @@
|
|||
- name: Script unban_ip is installed
|
||||
ansible.builtin.copy:
|
||||
src: unban_ip.sh
|
||||
dst: /usr/local/sbin/unban_ip
|
||||
dest: /usr/local/sbin/unban_ip
|
||||
mode: '0700'
|
||||
tags:
|
||||
- fail2ban
|
||||
|
|
|
@ -2,12 +2,15 @@
|
|||
# Juin - Decembre 2022 : #64088
|
||||
# Purge pour Stretch et Buster
|
||||
|
||||
/usr/bin/ionice -c3 /usr/bin/sqlite3 /var/lib/fail2ban/fail2ban.sqlite3 "DELETE FROM bans WHERE datetime('now', '-{{ fail2ban_dbpurgeage_default }}') > datetime(timeofban, 'unixepoch');"
|
||||
/usr/bin/ionice -c3 /usr/bin/sqlite3 /var/lib/fail2ban/fail2ban.sqlite3 ".timeout 5000; DELETE FROM bans WHERE datetime('now', '-{{ fail2ban_dbpurgeage_default }}') > datetime(timeofban, 'unixepoch');"
|
||||
|
||||
place_dispo=$( df -h /var/lib/fail2ban/fail2ban.sqlite3 --output="avail" -h --block-size=1 |tail -n1 )
|
||||
place_pris=$( echo $(("$(stat --format %s /var/lib/fail2ban/fail2ban.sqlite3 ) * 2" )) )
|
||||
place_dispo="$(df /var/lib/fail2ban/fail2ban.sqlite3 --output="avail" --block-size=1 | tail -n1)"
|
||||
place_pris="$(stat --format %s /var/lib/fail2ban/fail2ban.sqlite3)"
|
||||
|
||||
if [ $place_pris -lt $place_dispo ]
|
||||
if [ "$place_pris" -lt "$place_dispo" ]
|
||||
then
|
||||
/usr/bin/ionice -c3 /usr/bin/sqlite3 /var/lib/fail2ban/fail2ban.sqlite3 "VACUUM;"
|
||||
else
|
||||
>&2 echo "Fail2ban SQLite VACUUM not done because /var lacks of space (VACUUM may use twice the database size)."
|
||||
exit 1
|
||||
fi
|
||||
|
|
|
@ -59,7 +59,7 @@ bantime = {{ fail2ban_wordpress_soft_bantime }}
|
|||
enabled = {{ fail2ban_roundcube }}
|
||||
port = http, https
|
||||
filter = roundcube
|
||||
logpath = /var/lib/roundcube/logs/errors
|
||||
logpath = /var/log/roundcube/errors
|
||||
maxretry = {{ fail2ban_roundcube_maxretry }}
|
||||
findtime = {{ fail2ban_roundcube_findtime }}
|
||||
bantime = {{ fail2ban_roundcube_bantime }}
|
||||
|
|
|
@ -35,5 +35,6 @@ haproxy_deny_ips: []
|
|||
haproxy_backports_packages_stretch: haproxy libssl1.0.0
|
||||
haproxy_backports_packages_buster: haproxy
|
||||
haproxy_backports_packages_bullseye: haproxy
|
||||
haproxy_backports_packages_bookworm: haproxy
|
||||
|
||||
haproxy_allow_ip_nonlocal_bind: Null
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue