From 92cd99bbccbdfe7d4b4e7f4911fad4ff25b33895 Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Sun, 27 Mar 2022 10:01:35 +0200 Subject: [PATCH] dump-server-state has its own repository and changelog --- CHANGELOG | 25 + dump-server-state.sh | 1068 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1093 insertions(+) create mode 100644 CHANGELOG create mode 100644 dump-server-state.sh diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..d7e016e --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,25 @@ +# 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 + +### Fixed + +### Removed + +### Security + +## [22.03.8] 2022-03-27 + +dump-server-state has its own repository and changelog \ No newline at end of file diff --git a/dump-server-state.sh b/dump-server-state.sh new file mode 100644 index 0000000..7adde4e --- /dev/null +++ b/dump-server-state.sh @@ -0,0 +1,1068 @@ +#!/bin/sh + +PROGNAME="dump-server-state" +REPOSITORY="https://gitea.evolix.org/evolix/dump-server-state" + +VERSION="22.03.8" +readonly VERSION + +dump_dir= +rc=0 + +# base functions + +show_version() { + cat <, + Jérémy Lecour , + Éric Morino , + Brice Waegeneire + and others. + +${REPOSITORY} + +${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 < "${dump_dir}/apt-config.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* apt-config OK" + else + debug "* apt-config ERROR" + debug "${last_result}" + rc=10 + fi + else + debug "* apt-config is not found" + fi +} + +do_dpkg_full() { + debug "## DPkg full state" + + dir_state_status="/var/lib/dpkg/status" + + apt_config_bin=$(command -v apt-config) + + if [ -n "${apt_config_bin}" ]; then + eval "$(${apt_config_bin} shell dir_state_status Dir::State::status)" + fi + + dpkg_dir=$(dirname "${dir_state_status}") + + last_result=$(mkdir -p "${dump_dir}${dpkg_dir}" && chmod -R 755 "${dump_dir}${dpkg_dir}") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* mkdir/chmod OK" + else + debug "* mkdir/chmod ERROR" + debug "${last_result}" + rc=10 + fi + + rsync_bin=$(command -v rsync) + + if [ -n "${rsync_bin}" ]; then + last_result=$(${rsync_bin} -ah --itemize-changes --exclude='*-old' "${dpkg_dir}/" "${dump_dir}${dpkg_dir}/") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* rsync OK" + else + debug "* rsync ERROR :" + debug "${last_result}" + rc=10 + fi + else + debug "* rsync not found" + + last_result=$(cp -r "${dpkg_dir}/*" "${dump_dir}${dpkg_dir}/" && rm -rf "${dump_dir}${dpkg_dir}/*-old") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* cp OK" + else + debug "* cp ERROR :" + debug "${last_result}" + rc=10 + fi + fi +} + +do_dpkg_status() { + debug "## DPkg status" + + dir_state_status="/var/lib/dpkg/status" + + apt_config_bin=$(command -v apt-config) + + if [ -n "${apt_config_bin}" ]; then + eval "$(${apt_config_bin} shell dir_state_status Dir::State::status)" + fi + + last_result=$(cp "${dir_state_status}" "${dump_dir}/dpkg-status.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* cp OK" + else + debug "* cp ERROR :" + debug "${last_result}" + rc=10 + fi +} + +do_packages() { + debug "## List of installed package" + + dpkg_bin=$(command -v dpkg) + + if [ -n "${dpkg_bin}" ]; then + last_result=$(${dpkg_bin} --get-selections "*" > "${dump_dir}/current_packages.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* dpkg OK" + else + debug "* dpkg ERROR :" + debug "${last_result}" + rc=10 + fi + else + debug "* dpkg not found" + fi +} + +do_uname() { + debug "## uname" + + last_result=$(uname -a > "${dump_dir}/uname.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* uname OK" + else + debug "* uname ERROR" + debug "${last_result}" + rc=10 + fi +} + +do_uptime() { + debug "## uptime" + + last_result=$(uptime > "${dump_dir}/uptime.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* uptime OK" + else + debug "* uptime ERROR" + debug "${last_result}" + rc=10 + fi +} + +do_processes() { + debug "## Process list" + + last_result=$(ps fauxw > "${dump_dir}/ps.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* ps OK" + else + debug "* ps ERROR" + debug "${last_result}" + rc=10 + fi + + pstree_bin=$(command -v pstree) + + if [ -n "${pstree_bin}" ]; then + last_result=$(${pstree_bin} -pan > "${dump_dir}/pstree.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* pstree OK" + else + debug "* pstree ERROR" + debug "${last_result}" + rc=10 + fi + fi +} + +do_netstat() { + debug "## Network status" + + ss_bin=$(command -v ss) + + if [ -n "${ss_bin}" ]; then + last_result=$(${ss_bin} -tanpul > "${dump_dir}/netstat-ss.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* ss OK" + else + debug "* ss ERROR" + debug "${last_result}" + rc=10 + fi + else + debug "* ss not found" + fi + + netstat_bin=$(command -v netstat) + + if [ -n "${netstat_bin}" ]; then + last_result=$(netstat -laputen > "${dump_dir}/netstat-legacy.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* netstat OK" + else + debug "* netstat ERROR" + debug "${last_result}" + rc=10 + fi + else + debug "* netstat not found" + fi +} + +do_netcfg() { + debug "## Network configuration" + + ip_bin=$(command -v ip) + + if [ -n "${ip_bin}" ]; then + last_result=$(${ip_bin} address show > "${dump_dir}/ip-address.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* ip address OK" + else + debug "* ip address ERROR" + debug "${last_result}" + rc=10 + fi + + last_result=$(${ip_bin} route show > "${dump_dir}/ip-route.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* ip route OK" + else + debug "* ip route ERROR" + debug "${last_result}" + rc=10 + fi + else + debug "* ip not found" + + ifconfig_bin=$(command -v ifconfig) + + if [ -n "${ifconfig_bin}" ]; then + last_result=$(${ifconfig_bin} > "${dump_dir}/ifconfig.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* ifconfig OK" + else + debug "* ifconfig ERROR" + debug "${last_result}" + rc=10 + fi + else + debug "* ifconfig not found" + fi + fi +} + +do_iptables() { + debug "## iptables" + + iptables_bin=$(command -v iptables) + nft_bin=$(command -v nft) + + if [ -n "${nft_bin}" ]; then + debug "* nft found, skip iptables" + else + if [ -n "${iptables_bin}" ]; then + last_result=$({ ${iptables_bin} -L -n -v; ${iptables_bin} -t filter -L -n -v; } >> "${dump_dir}/iptables-v.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* iptables -v OK" + else + debug "* iptables -v ERROR" + debug "${last_result}" + rc=10 + fi + + last_result=$({ ${iptables_bin} -L -n; ${iptables_bin} -t filter -L -n; } >> "${dump_dir}/iptables.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* iptables OK" + else + debug "* iptables ERROR" + debug "${last_result}" + rc=10 + fi + else + debug "* iptables not found" + fi + + iptables_save_bin=$(command -v iptables-save) + + if [ -n "${iptables_save_bin}" ]; then + last_result=$(${iptables_save_bin} > "${dump_dir}/iptables-save.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* iptables-save OK" + else + debug "* iptables-save ERROR" + debug "${last_result}" + rc=10 + fi + else + debug "* iptables-save not found" + fi + fi +} + +do_sysctl() { + debug "## sysctl values" + + sysctl_bin=$(command -v sysctl) + + if [ -n "${sysctl_bin}" ]; then + last_result=$(${sysctl_bin} -a --ignore 2>/dev/null | sort -h > "${dump_dir}/sysctl.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* sysctl OK" + else + debug "* sysctl ERROR" + debug "${last_result}" + rc=10 + fi + else + debug "* sysctl not found" + fi +} + +do_virsh() { + debug "## virsh list" + + virsh_bin=$(command -v virsh) + + if [ -n "${virsh_bin}" ]; then + last_result=$(${virsh_bin} list --all > "${dump_dir}/virsh-list.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* virsh list OK" + else + debug "* virsh list ERROR" + debug "${last_result}" + rc=10 + fi + else + debug "* virsh not found" + fi +} + +do_lxc() { + debug "## lxc list" + + lxc_ls_bin=$(command -v lxc-ls) + + if [ -n "${lxc_ls_bin}" ]; then + last_result=$(${lxc_ls_bin} --fancy > "${dump_dir}/lxc-list.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* lxc list OK" + else + debug "* lxc list ERROR" + debug "${last_result}" + rc=10 + fi + else + debug "* lxc-ls not found" + fi +} + +do_disks() { + debug "## Disks" + + lsblk_bin=$(command -v lsblk) + awk_bin=$(command -v awk) + + if [ -n "${lsblk_bin}" ] && [ -n "${awk_bin}" ]; then + disks=$(${lsblk_bin} -l | grep disk | grep -v -E '(drbd|fd[0-9]+)' | ${awk_bin} '{print $1}') + for disk in ${disks}; do + dd_bin=$(command -v dd) + if [ -n "${dd_bin}" ]; then + last_result=$(${dd_bin} if="/dev/${disk}" of="${dump_dir}/MBR-${disk}" bs=512 count=1 2>&1) + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* dd ${disk} OK" + else + debug "* dd ${disk} ERROR" + debug "${last_result}" + rc=10 + fi + else + debug "* dd not found" + fi + fdisk_bin=$(command -v fdisk) + if [ -n "${fdisk_bin}" ]; then + last_result=$(${fdisk_bin} -l "/dev/${disk}" > "${dump_dir}/partitions-${disk}" 2>&1) + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* fdisk ${disk} OK" + else + debug "* fdisk ${disk} ERROR" + debug "${last_result}" + rc=10 + fi + else + debug "* fdisk not found" + fi + done + cat "${dump_dir}"/partitions-* > "${dump_dir}/partitions" + else + if [ -n "${lsblk_bin}" ]; then + debug "* lsblk not found" + fi + if [ -n "${awk_bin}" ]; then + debug "* awk not found" + fi + fi +} + +do_mount() { + debug "## Mount points" + + findmnt_bin=$(command -v findmnt) + + if [ -n "${findmnt_bin}" ]; then + last_result=$(${findmnt_bin} > "${dump_dir}/mount.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* mount points OK" + else + debug "* mount points ERROR" + debug "${last_result}" + rc=10 + fi + else + debug "* findmnt not found" + + mount_bin=$(command -v mount) + + if [ -n "${mount_bin}" ]; then + last_result=$(${mount_bin} > "${dump_dir}/mount.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* mount points OK" + else + debug "* mount points ERROR" + debug "${last_result}" + rc=10 + fi + else + debug "* mount not found" + fi + fi +} + +do_df() { + debug "## df" + + df_bin=$(command -v df) + + if [ -n "${df_bin}" ]; then + last_result=$(${df_bin} --portability > "${dump_dir}/df.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* df OK" + else + debug "* df ERROR" + debug "${last_result}" + rc=10 + fi + else + debug "* df not found" + fi +} + +do_dmesg() { + debug "## dmesg" + + dmesg_bin=$(command -v dmesg) + + if [ -n "${dmesg_bin}" ]; then + last_result=$(${dmesg_bin} > "${dump_dir}/dmesg.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* dmesg OK" + else + debug "* dmesg ERROR" + debug "${last_result}" + rc=10 + fi + else + debug "* dmesg not found" + fi +} + +do_mysql_processes() { + debug "## MySQL processes" + + mysqladmin_bin=$(command -v mysqladmin) + + if [ -n "${mysqladmin_bin}" ]; then + # Look for local MySQL or MariaDB process + if pgrep mysqld > /dev/null || pgrep mariadbd > /dev/null; then + last_result=$(${mysqladmin_bin} --verbose processlist > "${dump_dir}/mysql-processlist.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* mysqladmin OK" + else + debug "* mysqladmin ERROR" + debug "${last_result}" + rc=10 + fi + else + debug "* no mysqld or mariadbd process is running" + fi + else + debug "* mysqladmin not found" + fi +} + +do_systemctl() { + debug "## Systemd services" + + systemctl_bin=$(command -v systemctl) + + if [ -n "${systemctl_bin}" ]; then + last_result=$(${systemctl_bin} --no-legend --state=failed --type=service > "${dump_dir}/systemctl-failed-services.txt") + last_rc=$? + + if [ ${last_rc} -eq 0 ]; then + debug "* failed services OK" + else + debug "* failed services ERROR" + debug "${last_result}" + rc=10 + fi + else + debug "* systemctl not found" + fi +} + + +main() { + if [ -z "${dump_dir}" ]; then + echo "ERROR: You must provide the --dump-dir argument" >&2 + exit 1 + fi + + if [ -d "${dump_dir}" ]; then + if [ "${FORCE}" != "1" ]; then + echo "ERROR: The dump directory ${dump_dir} already exists. Delete it first." >&2 + exit 2 + fi + else + create_dump_dir + fi + + if [ "${DO_ETC}" -eq 1 ]; then + do_etc + fi + if [ "${DO_DPKG_FULL}" -eq 1 ]; then + do_dpkg_full + fi + if [ "${DO_DPKG_STATUS}" -eq 1 ]; then + do_dpkg_status + fi + if [ "${DO_APT_STATES}" -eq 1 ]; then + do_apt_states + fi + if [ "${DO_APT_CONFIG}" -eq 1 ]; then + do_apt_config + fi + if [ "${DO_PACKAGES}" -eq 1 ]; then + do_packages + fi + if [ "${DO_PROCESSES}" -eq 1 ]; then + do_processes + fi + if [ "${DO_UPTIME}" -eq 1 ]; then + do_uptime + fi + if [ "${DO_UNAME}" -eq 1 ]; then + do_uname + fi + if [ "${DO_NETSTAT}" -eq 1 ]; then + do_netstat + fi + if [ "${DO_NETCFG}" -eq 1 ]; then + do_netcfg + fi + if [ "${DO_IPTABLES}" -eq 1 ]; then + do_iptables + fi + if [ "${DO_SYSCTL}" -eq 1 ]; then + do_sysctl + fi + if [ "${DO_VIRSH}" -eq 1 ]; then + do_virsh + fi + if [ "${DO_LXC}" -eq 1 ]; then + do_lxc + fi + if [ "${DO_DISKS}" -eq 1 ]; then + do_disks + fi + if [ "${DO_MOUNT}" -eq 1 ]; then + do_mount + fi + if [ "${DO_DF}" -eq 1 ]; then + do_df + fi + if [ "${DO_DMESG}" -eq 1 ]; then + do_dmesg + fi + if [ "${DO_MYSQL_PROCESSES}" -eq 1 ]; then + do_mysql_processes + fi + if [ "${DO_SYSTEMCTL}" -eq 1 ]; then + do_systemctl + fi + + + debug "=> Your dump is available at ${dump_dir}" + exit ${rc} +} + +# parse options +# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a +while :; do + case $1 in + -h|-\?|--help) + show_help + exit 0 + ;; + -V|--version) + show_version + exit 0 + ;; + -v|--verbose) + VERBOSE=1 + ;; + + -f|--force) + FORCE=1 + ;; + + -d|--dump-dir) + # with value separated by space + if [ -n "$2" ]; then + dump_dir=$2 + shift + else + printf 'ERROR: "-d|--dump-dir" requires a non-empty option argument.\n' >&2 + exit 1 + fi + ;; + --dump-dir=?*) + # with value speparated by = + dump_dir=${1#*=} + ;; + --dump-dir=) + # without value + printf 'ERROR: "--dump-dir" requires a non-empty option argument.\n' >&2 + exit 1 + ;; + + --backup-dir) + printf 'WARNING: "--backup-dir" is deprecated in favor of "--dump-dir".\n' + if [ -n "${dump_dir}" ]; then + debug "Dump directory is already set, let's ignore this one." + else + debug "Dump directory is not set already, let's stay backward compatible." + # with value separated by space + if [ -n "$2" ]; then + dump_dir=$2 + shift + else + printf 'ERROR: "--backup-dir" requires a non-empty option argument.\n' >&2 + exit 1 + fi + fi + ;; + --backup-dir=?*) + # with value speparated by = + printf 'WARNING: "--backup-dir" is deprecated in favor of "--dump-dir".\n' + if [ -n "${dump_dir}" ]; then + debug "Dump directory is already set, let's ignore this one." + else + debug "Dump directory is not set already, let's stay backward compatible." + dump_dir=${1#*=} + fi + ;; + --backup-dir=) + # without value + printf 'WARNING: "--backup-dir" is deprecated in favor of "--dump-dir".\n' + if [ -n "${dump_dir}" ]; then + debug "Dump directory is already set, let's ignore this one." + else + printf 'ERROR: "--backup-dir" requires a non-empty option argument.\n' >&2 + exit 1 + fi + ;; + + --etc) + DO_ETC=1 + ;; + --no-etc) + DO_ETC=0 + ;; + + --dpkg-full) + DO_DPKG_FULL=1 + ;; + --no-dpkg-full) + DO_DPKG_FULL=0 + ;; + + --dpkg-status) + DO_DPKG_STATUS=1 + ;; + --no-dpkg-status) + DO_DPKG_STATUS=0 + ;; + + --apt-states) + DO_APT_STATES=1 + ;; + --no-apt-states) + DO_APT_STATES=0 + ;; + + --apt-config) + DO_APT_CONFIG=1 + ;; + --no-apt-config) + DO_APT_CONFIG=0 + ;; + + --packages) + DO_PACKAGES=1 + ;; + --no-packages) + DO_PACKAGES=0 + ;; + + --processes) + DO_PROCESSES=1 + ;; + --no-processes) + DO_PROCESSES=0 + ;; + + --uptime) + DO_UPTIME=1 + ;; + --no-uptime) + DO_UPTIME=0 + ;; + + --uname) + DO_UNAME=1 + ;; + --no-uname) + DO_UNAME=0 + ;; + + --netstat) + DO_NETSTAT=1 + ;; + --no-netstat) + DO_NETSTAT=0 + ;; + + --netcfg) + DO_NETCFG=1 + ;; + --no-netcfg) + DO_NETCFG=0 + ;; + + --iptables) + DO_IPTABLES=1 + ;; + --no-iptables) + DO_IPTABLES=0 + ;; + + --sysctl) + DO_SYSCTL=1 + ;; + --no-sysctl) + DO_SYSCTL=0 + ;; + + --virsh) + DO_VIRSH=1 + ;; + --no-virsh) + DO_VIRSH=0 + ;; + + --lxc) + DO_LXC=1 + ;; + --no-lxc) + DO_LXC=0 + ;; + + --disks) + DO_DISKS=1 + ;; + --no-disks) + DO_DISKS=0 + ;; + + --mount) + DO_MOUNT=1 + ;; + --no-mount) + DO_MOUNT=0 + ;; + + --df) + DO_DF=1 + ;; + --no-df) + DO_DF=0 + ;; + + --dmesg) + DO_DMESG=1 + ;; + --no-dmesg) + DO_DMESG=0 + ;; + + --mysql-processes) + DO_MYSQL_PROCESSES=1 + ;; + --no-mysql-processes) + DO_MYSQL_PROCESSES=0 + ;; + + --systemctl) + DO_SYSTEMCTL=1 + ;; + --no-systemctl) + DO_SYSTEMCTL=0 + ;; + + --) + # End of all options. + shift + break + ;; + -?*) + # ignore unknown options + printf 'WARN: Unknown option : %s\n' "$1" >&2 + exit 1 + ;; + *) + # Default case: If no more options then break out of the loop. + break + ;; + esac + + shift +done + +# Default values +: "${VERBOSE:=0}" +: "${FORCE:=0}" +: "${DO_ETC:=0}" +: "${DO_DPKG_FULL:=0}" +: "${DO_DPKG_STATUS:=1}" +: "${DO_APT_STATES:=1}" +: "${DO_APT_CONFIG:=1}" +: "${DO_PACKAGES:=1}" +: "${DO_PROCESSES:=1}" +: "${DO_UNAME:=1}" +: "${DO_UPTIME:=1}" +: "${DO_NETSTAT:=1}" +: "${DO_NETCFG:=1}" +: "${DO_IPTABLES:=1}" +: "${DO_SYSCTL:=1}" +: "${DO_VIRSH:=1}" +: "${DO_LXC:=1}" +: "${DO_DISKS:=1}" +: "${DO_MOUNT:=1}" +: "${DO_DF:=1}" +: "${DO_DMESG:=1}" +: "${DO_MYSQL_PROCESSES:=1}" +: "${DO_SYSTEMCTL:=1}" + +export LC_ALL=C + +set -u + +main