From 6dfaf433dc6d798a49922f88d195218d64ea5511 Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Fri, 1 Sep 2023 15:42:19 -0400 Subject: [PATCH] Initial commit of PVC Ansible role --- README.md | 14 + group_vars/default/vars.yml | 62 + hosts | 9 + pvc.yml | 10 + roles/base/files/usr/bin/check_mk_agent | 1107 +++++++++++++++++ .../usr/lib/check_mk_agent/plugins/backup | 11 + .../lib/check_mk_agent/plugins/cephfsmounts | 15 + .../files/usr/lib/check_mk_agent/plugins/dpkg | 33 + .../usr/lib/check_mk_agent/plugins/entropy | 16 + .../usr/lib/check_mk_agent/plugins/freshness | 52 + .../lib/check_mk_agent/plugins/kernelversion | 14 + .../usr/lib/check_mk_agent/plugins/ownership | 68 + roles/base/files/usr/lib/openssh/ssh-keysign | Bin 0 -> 432264 bytes roles/base/handlers/main.yml | 36 + roles/base/tasks/main.yml | 719 +++++++++++ .../etc/ansible/facts.d/dhcp_status.fact.j2 | 5 + .../etc/ansible/facts.d/host_group.fact.j2 | 5 + .../etc/ansible/facts.d/host_id.fact.j2 | 8 + .../etc/apt/apt.conf.d/10norecommends.j2 | 5 + .../apt/apt.conf.d/50unattended-upgrades.j2 | 37 + .../templates/etc/apt/preferences.d/pins.j2 | 12 + .../templates/etc/apt/sources.list.x86_64.j2 | 14 + roles/base/templates/etc/bash.bashrc.j2 | 126 ++ .../templates/etc/check_mk/logwatch.cfg.j2 | 58 + .../base/templates/etc/cron.d/update-motd.j2 | 4 + roles/base/templates/etc/crontab.j2 | 12 + roles/base/templates/etc/default/locale.j2 | 4 + .../dhcp/dhclient-enter-hooks.d/noresolv.j2 | 6 + .../etc/fail2ban/action.d/route.conf.j2 | 15 + .../etc/fail2ban/filter.d/sshd.conf.j2 | 50 + .../etc/fail2ban/jail.d/sshd.conf.j2 | 30 + .../etc/fail2ban/jail.d/sshd.local.j2 | 11 + roles/base/templates/etc/hosts.j2 | 6 + roles/base/templates/etc/locale.gen.j2 | 4 + .../etc/logrotate.d/rsyslog-loghost.j2 | 23 + .../base/templates/etc/logrotate.d/rsyslog.j2 | 23 + roles/base/templates/etc/ntp.conf.j2 | 27 + roles/base/templates/etc/pam.d/sshd.j2 | 54 + roles/base/templates/etc/postfix/main.cf.j2 | 17 + roles/base/templates/etc/profile.d/w.sh.j2 | 7 + roles/base/templates/etc/resolv.conf.j2 | 5 + roles/base/templates/etc/rsyslog.conf.j2 | 37 + roles/base/templates/etc/ssh/shosts.equiv.j2 | 3 + roles/base/templates/etc/ssh/ssh_config.j2 | 43 + .../base/templates/etc/ssh/ssh_known_hosts.j2 | 3 + roles/base/templates/etc/ssh/sshd_config.j2 | 43 + .../templates/etc/sudoers.d/sudoers-backup.j2 | 5 + roles/base/templates/etc/sudoers.j2 | 12 + roles/base/templates/etc/sysctl.d/pvc.conf.j2 | 47 + .../templates/etc/systemd/journald.conf.j2 | 4 + .../etc/systemd/system/check_mk.socket | 10 + .../etc/systemd/system/check_mk@.service | 12 + roles/base/templates/root/vimrc.j2 | 5 + .../usr/local/sbin/dpkg-cleanup.sh.j2 | 18 + .../usr/local/sbin/loghost-archive.sh.j2 | 23 + .../usr/local/sbin/update-motd.sh.j2 | 26 + .../var/backups/ssh/authorized_keys.j2 | 4 + .../templates/var/backups/timestamp.sh.j2 | 11 + .../templates/var/home/user/bash_logout.j2 | 7 + roles/base/templates/var/home/user/bashrc.j2 | 144 +++ .../var/home/user/config/htop/htoprc.j2 | 25 + roles/base/templates/var/home/user/profile.j2 | 16 + roles/base/templates/var/home/user/vimrc.j2 | 13 + roles/pvc/README.md | 13 + roles/pvc/defaults/main.yml | 57 + roles/pvc/files/mariadb/mk_mysql.agents | 90 ++ roles/pvc/files/patroni/postgres | 485 ++++++++ roles/pvc/files/patroni/powerdns-schema.sql | 94 ++ roles/pvc/handlers/main.yml | 25 + roles/pvc/tasks/ceph.yml | 48 + roles/pvc/tasks/frr.yml | 23 + roles/pvc/tasks/libvirt.yml | 43 + roles/pvc/tasks/main.yml | 26 + roles/pvc/tasks/patroni.yml | 128 ++ roles/pvc/tasks/pvc.yml | 43 + roles/pvc/tasks/zookeeper.yml | 26 + roles/pvc/templates/ceph/default.conf.j2 | 4 + roles/pvc/templates/ceph/limits.conf.j2 | 4 + roles/pvc/templates/ceph/sysctl.conf.j2 | 4 + roles/pvc/templates/frr/daemons.j2 | 16 + roles/pvc/templates/frr/frr.conf.j2 | 53 + .../pvc/templates/libvirt/ceph-secret.xml.j2 | 6 + roles/pvc/templates/libvirt/libvirtd.conf.j2 | 7 + roles/pvc/templates/patroni/patroni.yml.j2 | 63 + .../templates/patroni/postgresql.pvc.conf.j2 | 21 + roles/pvc/templates/pvc/pvcd.yaml.j2 | 75 ++ roles/pvc/templates/system/blacklist.j2 | 11 + .../templates/zookeeper/configuration.xsl.j2 | 25 + roles/pvc/templates/zookeeper/environment.j2 | 10 + .../templates/zookeeper/log4j.properties.j2 | 50 + roles/pvc/templates/zookeeper/myid.j2 | 1 + roles/pvc/templates/zookeeper/zoo.cfg.j2 | 13 + 92 files changed, 4709 insertions(+) create mode 100644 README.md create mode 100644 group_vars/default/vars.yml create mode 100644 hosts create mode 100644 pvc.yml create mode 100755 roles/base/files/usr/bin/check_mk_agent create mode 100755 roles/base/files/usr/lib/check_mk_agent/plugins/backup create mode 100755 roles/base/files/usr/lib/check_mk_agent/plugins/cephfsmounts create mode 100755 roles/base/files/usr/lib/check_mk_agent/plugins/dpkg create mode 100755 roles/base/files/usr/lib/check_mk_agent/plugins/entropy create mode 100755 roles/base/files/usr/lib/check_mk_agent/plugins/freshness create mode 100755 roles/base/files/usr/lib/check_mk_agent/plugins/kernelversion create mode 100755 roles/base/files/usr/lib/check_mk_agent/plugins/ownership create mode 100755 roles/base/files/usr/lib/openssh/ssh-keysign create mode 100644 roles/base/handlers/main.yml create mode 100644 roles/base/tasks/main.yml create mode 100644 roles/base/templates/etc/ansible/facts.d/dhcp_status.fact.j2 create mode 100644 roles/base/templates/etc/ansible/facts.d/host_group.fact.j2 create mode 100644 roles/base/templates/etc/ansible/facts.d/host_id.fact.j2 create mode 100644 roles/base/templates/etc/apt/apt.conf.d/10norecommends.j2 create mode 100644 roles/base/templates/etc/apt/apt.conf.d/50unattended-upgrades.j2 create mode 100644 roles/base/templates/etc/apt/preferences.d/pins.j2 create mode 100644 roles/base/templates/etc/apt/sources.list.x86_64.j2 create mode 100755 roles/base/templates/etc/bash.bashrc.j2 create mode 100644 roles/base/templates/etc/check_mk/logwatch.cfg.j2 create mode 100644 roles/base/templates/etc/cron.d/update-motd.j2 create mode 100644 roles/base/templates/etc/crontab.j2 create mode 100644 roles/base/templates/etc/default/locale.j2 create mode 100644 roles/base/templates/etc/dhcp/dhclient-enter-hooks.d/noresolv.j2 create mode 100644 roles/base/templates/etc/fail2ban/action.d/route.conf.j2 create mode 100644 roles/base/templates/etc/fail2ban/filter.d/sshd.conf.j2 create mode 100644 roles/base/templates/etc/fail2ban/jail.d/sshd.conf.j2 create mode 100644 roles/base/templates/etc/fail2ban/jail.d/sshd.local.j2 create mode 100644 roles/base/templates/etc/hosts.j2 create mode 100644 roles/base/templates/etc/locale.gen.j2 create mode 100644 roles/base/templates/etc/logrotate.d/rsyslog-loghost.j2 create mode 100644 roles/base/templates/etc/logrotate.d/rsyslog.j2 create mode 100644 roles/base/templates/etc/ntp.conf.j2 create mode 100644 roles/base/templates/etc/pam.d/sshd.j2 create mode 100644 roles/base/templates/etc/postfix/main.cf.j2 create mode 100644 roles/base/templates/etc/profile.d/w.sh.j2 create mode 100644 roles/base/templates/etc/resolv.conf.j2 create mode 100644 roles/base/templates/etc/rsyslog.conf.j2 create mode 100644 roles/base/templates/etc/ssh/shosts.equiv.j2 create mode 100644 roles/base/templates/etc/ssh/ssh_config.j2 create mode 100644 roles/base/templates/etc/ssh/ssh_known_hosts.j2 create mode 100644 roles/base/templates/etc/ssh/sshd_config.j2 create mode 100644 roles/base/templates/etc/sudoers.d/sudoers-backup.j2 create mode 100644 roles/base/templates/etc/sudoers.j2 create mode 100644 roles/base/templates/etc/sysctl.d/pvc.conf.j2 create mode 100644 roles/base/templates/etc/systemd/journald.conf.j2 create mode 100644 roles/base/templates/etc/systemd/system/check_mk.socket create mode 100644 roles/base/templates/etc/systemd/system/check_mk@.service create mode 100644 roles/base/templates/root/vimrc.j2 create mode 100755 roles/base/templates/usr/local/sbin/dpkg-cleanup.sh.j2 create mode 100755 roles/base/templates/usr/local/sbin/loghost-archive.sh.j2 create mode 100755 roles/base/templates/usr/local/sbin/update-motd.sh.j2 create mode 100644 roles/base/templates/var/backups/ssh/authorized_keys.j2 create mode 100755 roles/base/templates/var/backups/timestamp.sh.j2 create mode 100755 roles/base/templates/var/home/user/bash_logout.j2 create mode 100755 roles/base/templates/var/home/user/bashrc.j2 create mode 100644 roles/base/templates/var/home/user/config/htop/htoprc.j2 create mode 100644 roles/base/templates/var/home/user/profile.j2 create mode 100644 roles/base/templates/var/home/user/vimrc.j2 create mode 100644 roles/pvc/README.md create mode 100644 roles/pvc/defaults/main.yml create mode 100755 roles/pvc/files/mariadb/mk_mysql.agents create mode 100755 roles/pvc/files/patroni/postgres create mode 100644 roles/pvc/files/patroni/powerdns-schema.sql create mode 100644 roles/pvc/handlers/main.yml create mode 100644 roles/pvc/tasks/ceph.yml create mode 100644 roles/pvc/tasks/frr.yml create mode 100644 roles/pvc/tasks/libvirt.yml create mode 100644 roles/pvc/tasks/main.yml create mode 100644 roles/pvc/tasks/patroni.yml create mode 100644 roles/pvc/tasks/pvc.yml create mode 100644 roles/pvc/tasks/zookeeper.yml create mode 100644 roles/pvc/templates/ceph/default.conf.j2 create mode 100644 roles/pvc/templates/ceph/limits.conf.j2 create mode 100644 roles/pvc/templates/ceph/sysctl.conf.j2 create mode 100644 roles/pvc/templates/frr/daemons.j2 create mode 100644 roles/pvc/templates/frr/frr.conf.j2 create mode 100644 roles/pvc/templates/libvirt/ceph-secret.xml.j2 create mode 100644 roles/pvc/templates/libvirt/libvirtd.conf.j2 create mode 100644 roles/pvc/templates/patroni/patroni.yml.j2 create mode 100644 roles/pvc/templates/patroni/postgresql.pvc.conf.j2 create mode 100644 roles/pvc/templates/pvc/pvcd.yaml.j2 create mode 100644 roles/pvc/templates/system/blacklist.j2 create mode 100644 roles/pvc/templates/zookeeper/configuration.xsl.j2 create mode 100644 roles/pvc/templates/zookeeper/environment.j2 create mode 100644 roles/pvc/templates/zookeeper/log4j.properties.j2 create mode 100644 roles/pvc/templates/zookeeper/myid.j2 create mode 100644 roles/pvc/templates/zookeeper/zoo.cfg.j2 diff --git a/README.md b/README.md new file mode 100644 index 0000000..adb4954 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# PVC Ansible + +A set of Ansible roles to set up a PVC node host. + +## Variables + +A default example set of configuration variables can be found in `group_vars/default/vars.yml + +## Using + +0. Deploy Debian 10 to a set of servers. +0. Create a new cluster group in the `hosts` file. +0. Create a set of vars in `group_vars`. +0. Run the `pvc.yml` playbook against the servers. diff --git a/group_vars/default/vars.yml b/group_vars/default/vars.yml new file mode 100644 index 0000000..3e7a15f --- /dev/null +++ b/group_vars/default/vars.yml @@ -0,0 +1,62 @@ +--- +# Ceph storage +pvc_ceph_storage_secret_uuid: "6e1f4969-f7ea-4be1-9232-e67ce3bfc37e" +pvc_ceph_storage_secret_key: "AQC8y6tWkfUEKxAAI9XKcXlN38Nzbrom899rJw==" +# Database +pvc_dns_database_name: "pvcdns" +pvc_dns_database_user: "pvcdns" +pvc_dns_database_password: "PVCdnsPassw0rd" +pvc_replication_database_user: "replicator" +pvc_replication_database_password: "PVCreplicatorPassw0rd" +pvc_superuser_database_user: "postgres" +pvc_superuser_database_password: "PVCpostgresPassw0rd" +# Coordinators +pvc_nodes: + - hostname: "pvchv1" + is_coordinator: yes + node_id: 1 + router_id: "{{ blsecluster_pvc_clustersubnetsnip }}.1" + cluster_ip: "by-id" + storage_ip: "{{ blsecluster_pvc_storagesubnetsnip }}.25/24" + upstream_ip: "{{ blsecluster_pvc_upstreamsubnetsnip }}.25/24" + ipmi_host: "hv1-lom.{{ blsedomains_mgmtdomain }}" + ipmi_user: "{{ username_ipmi_host }}" + ipmi_password: "{{ passwd_ipmi_host }}" + - hostname: "pvchv2" + is_coordinator: yes + node_id: 2 + router_id: "{{ blsecluster_pvc_clustersubnetsnip }}.2" + cluster_ip: "by-id" + storage_ip: "{{ blsecluster_pvc_storagesubnetsnip }}.26/24" + upstream_ip: "{{ blsecluster_pvc_upstreamsubnetsnip }}.26/24" + ipmi_host: "hv2-lom.{{ blsedomains_mgmtdomain }}" + ipmi_user: "{{ username_ipmi_host }}" + ipmi_password: "{{ passwd_ipmi_host }}" + - hostname: "pvchv3" + is_coordinator: yes + node_id: 3 + router_id: "{{ blsecluster_pvc_clustersubnetsnip }}.3" + cluster_ip: "by-id" + storage_ip: "{{ blsecluster_pvc_storagesubnetsnip }}.27/24" + upstream_ip: "{{ blsecluster_pvc_upstreamsubnetsnip }}.27/24" + ipmi_host: "hv3-lom.{{ blsedomains_mgmtdomain }}" + ipmi_user: "{{ username_ipmi_host }}" + ipmi_password: "{{ passwd_ipmi_host }}" +# Networks +pvc_asn: "{{ blsecluster_pvc_asn }}" +pvc_routers: + - "{{ blsecluster_pvc_upstreamsubnetsnip }}.2" + - "{{ blsecluster_pvc_upstreamsubnetsnip }}.3" +pvc_cluster_device: "bond0" +pvc_cluster_domain: "{{ blsedomains_pvc_clusterdomain }}" +pvc_cluster_subnet: "{{ blsecluster_pvc_clustersubnetv4 }}" +pvc_cluster_floatingip: "{{ blsecluster_pvc_clustersubnetsnip }}.252/24" +pvc_storage_device: "vlan99" +pvc_storage_domain: "{{ blsedomains_pvc_storagedomain }}" +pvc_storage_subnet: "{{ blsecluster_pvc_storagesubnetv4 }}" +pvc_storage_floatingip: "{{ blsecluster_pvc_storagesubnetsnip }}.252/24" +pvc_upstream_device: "vlan100" +pvc_upstream_domain: "{{ blsedomains_pvc_upstreamdomain }}" +pvc_upstream_subnet: "{{ blsecluster_pvc_upstreamsubnetv4 }}" +pvc_upstream_floatingip: "{{ blsecluster_pvc_upstreamsubnetsnip }}.252/24" +pvc_upstream_gatewayip: "{{ blsecluster_pvc_upstreamsubnetsnip }}.1" diff --git a/hosts b/hosts new file mode 100644 index 0000000..ba6dbae --- /dev/null +++ b/hosts @@ -0,0 +1,9 @@ +# PVC hosts file + +[sites:children] +default + +[default] +pvchv1 +pvchv2 +pvchv3 diff --git a/pvc.yml b/pvc.yml new file mode 100644 index 0000000..a5d1b73 --- /dev/null +++ b/pvc.yml @@ -0,0 +1,10 @@ +--- +- hosts: all + remote_user: deploy + become: yes + roles: + - name: base + tags: base + + - name: pvc + tags: pvc diff --git a/roles/base/files/usr/bin/check_mk_agent b/roles/base/files/usr/bin/check_mk_agent new file mode 100755 index 0000000..3bc41e0 --- /dev/null +++ b/roles/base/files/usr/bin/check_mk_agent @@ -0,0 +1,1107 @@ +#!/bin/bash +# Check_MK Agent for Linux +# +------------------------------------------------------------------+ +# | ____ _ _ __ __ _ __ | +# | / ___| |__ ___ ___| | __ | \/ | |/ / | +# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / | +# | | |___| | | | __/ (__| < | | | | . \ | +# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ | +# | | +# | Copyright Mathias Kettner 2014 mk@mathias-kettner.de | +# +------------------------------------------------------------------+ +# +# This file is part of Check_MK. +# The official homepage is at http://mathias-kettner.de/check_mk. +# +# check_mk is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation in version 2. check_mk is distributed +# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with- +# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU General Public License for more de- +# tails. You should have received a copy of the GNU General Public +# License along with GNU Make; see the file COPYING. If not, write +# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301 USA. + +# Remove locale settings to eliminate localized outputs where possible +export LC_ALL=C +unset LANG + +export MK_LIBDIR=${MK_LIBDIR:-/usr/lib/check_mk_agent} +export MK_CONFDIR=${MK_CONFDIR:-/etc/check_mk} +export MK_VARDIR=${MK_VARDIR:-/var/lib/check_mk_agent} + +# Provide information about the remote host. That helps when data +# is being sent only once to each remote host. +if [ "$REMOTE_HOST" ] ; then + export REMOTE=$REMOTE_HOST +elif [ "$SSH_CLIENT" ] ; then + export REMOTE=${SSH_CLIENT%% *} +fi + +# Make sure, locally installed binaries are found +PATH=$PATH:/usr/local/bin + +# All executables in PLUGINSDIR will simply be executed and their +# ouput appended to the output of the agent. Plugins define their own +# sections and must output headers with '<<<' and '>>>' +PLUGINSDIR=$MK_LIBDIR/plugins + +# All executables in LOCALDIR will by executabled and their +# output inserted into the section <<>>. Please +# refer to online documentation for details about local checks. +LOCALDIR=$MK_LIBDIR/local + +# All files in SPOOLDIR will simply appended to the agent +# output if they are not outdated (see below) +SPOOLDIR=$MK_VARDIR/spool + +# close standard input (for security reasons) and stderr +if [ "$1" = -d ] +then + set -xv +else + exec /dev/null +fi + +# Prefer (relatively) new /usr/bin/timeout from coreutils against +# our shipped waitmax. waitmax is statically linked and crashes on +# some Ubuntu versions recently. +if type timeout >/dev/null 2>&1 ; then + function waitmax () { + timeout "$@" + } + export -f waitmax +fi + +if [ -f $MK_CONFDIR/encryption.cfg ] ; then + source $MK_CONFDIR/encryption.cfg +fi + +if [ "$ENCRYPTED" == "yes" ] ; then + echo -n "00" # protocol version + exec > >(openssl enc -aes-256-cbc -k $PASSPHRASE -nosalt) +fi + + +# +# CHECK SECTIONS +# + +function section_mem() +{ + echo '<<>>' + egrep -v '^Swap:|^Mem:|total:' < /proc/meminfo +} + +function section_cpu() +{ + echo '<<>>' + if [ $(uname -m) = "armv7l" ]; then + CPU_REGEX='^processor' + else + CPU_REGEX='^CPU|^processor' + fi + echo "$(cat /proc/loadavg) $(grep -E $CPU_REGEX < /proc/cpuinfo | wc -l)" +} + + +function run_mrpe() { + local descr=$1 + shift + local cmdline="$@" + + echo '<<>>' + + PLUGIN=${cmdline%% *} + OUTPUT=$(eval "$cmdline") + + echo -n "(${PLUGIN##*/}) $descr $? $OUTPUT" | tr \\n \\1 + echo +} + +export -f run_mrpe + +# Runs a command asynchronous by use of a cache file. Usage: +# run_cached [-s] NAME MAXAGE +# -s creates the section header <<<$NAME>>> +# -m mrpe-mode: stores exit code with the cache +# NAME is the name of the section (also used as cache file name) +# MAXAGE is the maximum cache livetime in seconds +function run_cached () { + local NOW=$(date +%s) + local section= + local mrpe=0 + local append_age=0 + if [ "$1" = -s ] ; then local section="echo '<<<$2:cached($NOW,$3)>>>' ; " ; shift ; fi + if [ "$1" = -m ] ; then local mrpe=1 ; shift ; fi + if [ "$1" = -a ] ; then local append_age=1 ; shift ; fi + local NAME=$1 + local MAXAGE=$2 + shift 2 + local CMDLINE="$section$@" + + if [ ! -d $MK_VARDIR/cache ]; then mkdir -p $MK_VARDIR/cache ; fi + if [ "$mrpe" = 1 ] ; then + CACHEFILE="$MK_VARDIR/cache/mrpe_$NAME.cache" + else + CACHEFILE="$MK_VARDIR/cache/$NAME.cache" + fi + + # Check if the creation of the cache takes suspiciously long and kill the + # process if the age (access time) of $CACHEFILE.new is twice the MAXAGE. + # Output the evantually already cached section anyways and start the cache + # update again. + if [ -e "$CACHEFILE.new" ] ; then + local CF_ATIME=$(stat -c %X "$CACHEFILE.new") + if [ $((NOW - CF_ATIME)) -ge $((MAXAGE * 2)) ] ; then + # Kill the process still accessing that file in case + # it is still running. This avoids overlapping processes! + fuser -k -9 "$CACHEFILE.new" >/dev/null 2>&1 + rm -f "$CACHEFILE.new" + fi + fi + + + # Check if cache file exists and is recent enough + if [ -s "$CACHEFILE" ] ; then + local MTIME=$(stat -c %Y "$CACHEFILE") + local AGE=$((NOW - MTIME)) + if [ $AGE -le $MAXAGE ] ; then local USE_CACHEFILE=1 ; fi + # Output the file in any case, even if it is + # outdated. The new file will not yet be available + if [ $append_age -eq 1 ] ; then + # insert the cached-string before the pipe (first -e) + # or, if no pipe found (-e t) append it (third -e), + # but only once and on the second line (2!b) (first line is section header, + # all further lines are long output) + cat "$CACHEFILE" | sed -e "2s/|/ (Cached: ${AGE}\/${MAXAGE}s)|/" -e t -e "2s/$/ (Cached: ${AGE}\/${MAXAGE}s)/" + else + cat "$CACHEFILE" + fi + fi + + # Cache file outdated and new job not yet running? Start it + if [ -z "$USE_CACHEFILE" ] && [ ! -e "$CACHEFILE.new" ] ; then + # When the command fails, the output is throws away ignored + if [ $mrpe -eq 1 ] ; then + echo "set -o noclobber ; exec > \"$CACHEFILE.new\" || exit 1 ; run_mrpe $NAME $CMDLINE && mv \"$CACHEFILE.new\" \"$CACHEFILE\" || rm -f \"$CACHEFILE\" \"$CACHEFILE.new\"" | nohup /bin/bash >/dev/null 2>&1 & + else + echo "set -o noclobber ; exec > \"$CACHEFILE.new\" || exit 1 ; $CMDLINE && mv \"$CACHEFILE.new\" \"$CACHEFILE\" || rm -f \"$CACHEFILE\" \"$CACHEFILE.new\"" | nohup /bin/bash >/dev/null 2>&1 & + fi + fi +} + +# Make run_cached available for subshells (plugins, local checks, etc.) +export -f run_cached + +# Implements Real-Time Check feature of the Check_MK agent which can send +# some section data in 1 second resolution. Useful for fast notifications and +# detailed graphing (if you configure your RRDs to this resolution). +function run_real_time_checks() +{ + PIDFILE=$MK_VARDIR/real_time_checks.pid + echo $$ > $PIDFILE + + . $MK_CONFDIR/real_time_checks.cfg + + if [ "$PASSPHRASE" != "" ] ; then + # new mechanism to set the passphrase has priority + RTC_SECRET=$PASSPHRASE + fi + + while true; do + # terminate when pidfile is gone or other Real-Time Check process started or configured timeout + if [ ! -e $PIDFILE ] || [ $(<$PIDFILE) -ne $$ ] || [ $RTC_TIMEOUT -eq 0 ]; then + exit 1 + fi + + for SECTION in $RTC_SECTIONS; do + if [ "$ENCRYPTED_RT" != "no" ] ; then + PROTOCOL=00 + else + PROTOCOL=99 + fi + # Be aware of maximum packet size. Maybe we need to check the size of the section + # output and do some kind of nicer error handling. + # 2 bytes: protocol version, 10 bytes: timestamp, rest: encrypted data + # dd is used to concatenate the output of all commands to a single write/block => udp packet + { echo -n $PROTOCOL ; + date +%s | tr -d '\n' ; + if [ "$ENCRYPTED_RT" != "no" ] ; then + export RTC_SECRET=$RTC_SECRET ; section_$SECTION | openssl enc -aes-256-cbc -pass env:RTC_SECRET -nosalt ; + else + section_$SECTION ; + fi + } | dd bs=9999 iflag=fullblock 2>/dev/null >/dev/udp/$REMOTE/$RTC_PORT + done + + sleep 1 + RTC_TIMEOUT=$((RTC_TIMEOUT-1)) + done +} + +echo '<<>>' +echo Version: 1.4.0p11 +echo AgentOS: linux +echo Hostname: $HOSTNAME +echo AgentDirectory: $MK_CONFDIR +echo DataDirectory: $MK_VARDIR +echo SpoolDirectory: $SPOOLDIR +echo PluginsDirectory: $PLUGINSDIR +echo LocalDirectory: $LOCALDIR + +# If we are called via xinetd, try to find only_from configuration +if [ -n "$REMOTE_HOST" ] +then + echo -n 'OnlyFrom: ' + echo $(sed -n '/^service[[:space:]]*check_mk/,/}/s/^[[:space:]]*only_from[[:space:]]*=[[:space:]]*\(.*\)/\1/p' /etc/xinetd.d/* | head -n1) +fi + +# Print out Partitions / Filesystems. (-P gives non-wrapped POSIXed output) +# Heads up: NFS-mounts are generally supressed to avoid agent hangs. +# If hard NFS mounts are configured or you have too large nfs retry/timeout +# settings, accessing those mounts from the agent would leave you with +# thousands of agent processes and, ultimately, a dead monitored system. +# These should generally be monitored on the NFS server, not on the clients. + +echo '<<>>' +# The exclusion list is getting a bit of a problem. -l should hide any remote FS but seems +# to be all but working. +excludefs="-x smbfs -x cifs -x iso9660 -x udf -x nfsv4 -x nfs -x mvfs -x zfs -x prl_fs" +df -PTlk $excludefs | sed 1d + +# df inodes information +echo '<<>>' +echo '[df_inodes_start]' +df -PTli $excludefs | sed 1d +echo '[df_inodes_end]' + +# Filesystem usage for ZFS +if type zfs > /dev/null 2>&1 ; then + echo '<<>>' + zfs get -Hp name,quota,used,avail,mountpoint,type -t filesystem,volume || \ + zfs get -Hp name,quota,used,avail,mountpoint,type + echo '[df]' + df -PTlk -t zfs | sed 1d +fi + +# Check NFS mounts by accessing them with stat -f (System +# call statfs()). If this lasts more then 2 seconds we +# consider it as hanging. We need waitmax. +if type waitmax >/dev/null +then + STAT_VERSION=$(stat --version | head -1 | cut -d" " -f4) + STAT_BROKE="5.3.0" + + echo '<<>>' + sed -n '/ nfs4\? /s/[^ ]* \([^ ]*\) .*/\1/p' < /proc/mounts | + sed 's/\\040/ /g' | + while read MP + do + if [ ! -r $MP ]; then + echo "$MP Permission denied" + elif [ $STAT_VERSION != $STAT_BROKE ]; then + waitmax -s 9 2 stat -f -c "$MP ok %b %f %a %s" "$MP" || \ + echo "$MP hanging 0 0 0 0" + else + waitmax -s 9 2 stat -f -c "$MP ok %b %f %a %s" "$MP" && \ + printf '\n'|| echo "$MP hanging 0 0 0 0" + fi + done + + echo '<<>>' + sed -n '/ cifs\? /s/[^ ]* \([^ ]*\) .*/\1/p' < /proc/mounts | + sed 's/\\040/ /g' | + while read MP + do + if [ ! -r $MP ]; then + echo "$MP Permission denied" + elif [ $STAT_VERSION != $STAT_BROKE ]; then + waitmax -s 9 2 stat -f -c "$MP ok %b %f %a %s" "$MP" || \ + echo "$MP hanging 0 0 0 0" + else + waitmax -s 9 2 stat -f -c "$MP ok %b %f %a %s" "$MP" && \ + printf '\n'|| echo "$MP hanging 0 0 0 0" + fi + done +fi + +# Check mount options. Filesystems may switch to 'ro' in case +# of a read error. +echo '<<>>' +grep ^/dev < /proc/mounts + +# processes including username, without kernel processes +echo '<<>>' +ps ax -o user:32,vsz,rss,cputime,etime,pid,command --columns 10000 | sed -e 1d -e 's/ *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\([^ ]*\) */(\1,\2,\3,\4\/\5,\6) /' + +# Memory usage +section_mem + +# Load and number of processes +section_cpu + +# Uptime +echo '<<>>' +cat /proc/uptime + + +# New variant: Information about speed and state in one section +if type ip > /dev/null +then + echo '<<>>' + echo "[start_iplink]" + ip link + echo "[end_iplink]" +fi + +echo '<<>>' +sed 1,2d /proc/net/dev +if type ethtool > /dev/null +then + for eth in $(sed -e 1,2d < /proc/net/dev | cut -d':' -f1 | sort) + do + echo "[$eth]" + ethtool $eth | egrep '(Speed|Duplex|Link detected|Auto-negotiation):' + echo -en "\tAddress: " ; cat /sys/class/net/$eth/address ; echo + done +fi + + +# Current state of bonding interfaces +if [ -e /proc/net/bonding ] ; then + echo '<<>>' + pushd /proc/net/bonding > /dev/null + head -v -n 1000 * + popd > /dev/null +fi + +# Same for Open vSwitch bonding +if type ovs-appctl > /dev/null ; then + echo '<<>>' + for bond in $(ovs-appctl bond/list | sed -e 1d | rev | cut -f3 | rev) ; do + echo "[$bond]" + ovs-appctl bond/show $bond + done +fi + + +# Number of TCP connections in the various states +echo '<<>>' +if type waitmax >/dev/null ; then + THIS=$(waitmax -s 1 10 cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | awk ' /:/ { c[$4]++; } END { for (x in c) { print x, c[x]; } }') + if [ $? == 0 ] ; then + echo "$THIS" + else + ss -ant |grep -v ^State | awk ' /:/ { c[$1]++; } END { for (x in c) { print x, c[x]; } }' |sed -e 's/^ESTAB/01/g;s/^SYN-SENT/02/g;s/^SYN-RECV/03/g;s/^FIN-WAIT-1/04/g;s/^FIN-WAIT-2/05/g;s/^TIME-WAIT/06/g;s/^CLOSED/07/g;s/^CLOSE-WAIT/08/g;s/^LAST-ACK/09/g;s/^LISTEN/0A/g;s/^CLOSING/0B/g;' + fi +fi + +# Linux Multipathing +if type multipath >/dev/null ; then + if [ -f /etc/multipath.conf ] ; then + echo '<<>>' + multipath -l + fi +fi + +# Performancecounter Platten +echo '<<>>' +date +%s +egrep ' (x?[shv]d[a-z]*|cciss/c[0-9]+d[0-9]+|emcpower[a-z]+|dm-[0-9]+|VxVM.*|mmcblk.*|dasd[a-z]*|nvme[0-9]+n[0-9]+) ' < /proc/diskstats +if type dmsetup >/dev/null ; then + echo '[dmsetup_info]' + dmsetup info -c --noheadings --separator ' ' -o name,devno,vg_name,lv_name +fi +if [ -d /dev/vx/dsk ] ; then + echo '[vx_dsk]' + stat -c "%t %T %n" /dev/vx/dsk/*/* +fi + + +# Performancecounter Kernel +echo '<<>>' +date +%s +cat /proc/vmstat /proc/stat + +# Hardware sensors via IPMI (need ipmitool) +if type ipmitool > /dev/null +then + run_cached -s "ipmi:sep(124)" 300 "waitmax 300 ipmitool sensor list | grep -v 'command failed' | egrep -v '^[^ ]+ na ' | grep -v ' discrete '" + # readable discrete sensor states + run_cached -s "ipmi_discrete:sep(124)" 300 "waitmax 300 ipmitool sdr elist compact" +fi + + +# IPMI data via ipmi-sensors (of freeipmi). Please make sure, that if you +# have installed freeipmi that IPMI is really support by your hardware. +if type ipmi-sensors >/dev/null +then + echo '<<>>' + # Newer ipmi-sensors version have new output format; Legacy format can be used + if ipmi-sensors --help | grep -q legacy-output; then + IPMI_FORMAT="--legacy-output" + else + IPMI_FORMAT="" + fi + if ipmi-sensors --help | grep -q " \-\-groups"; then + IPMI_GROUP_OPT="-g" + else + IPMI_GROUP_OPT="-t" + fi + + # At least with ipmi-sensors 0.7.16 this group is Power_Unit instead of "Power Unit" + run_cached -s ipmi_sensors 300 "for class in Temperature Power_Unit Fan + do + ipmi-sensors $IPMI_FORMAT --sdr-cache-directory /var/cache $IPMI_GROUP_OPT \"$class\" | sed -e 's/ /_/g' -e 's/:_\?/ /g' -e 's@ \([^(]*\)_(\([^)]*\))@ \2_\1@' + # In case of a timeout immediately leave loop. + if [ $? = 255 ] ; then break ; fi + done" +fi + +# RAID status of Linux software RAID +echo '<<>>' +cat /proc/mdstat + +# RAID status of Linux RAID via device mapper +if type dmraid >/dev/null && DMSTATUS=$(dmraid -r) +then + echo '<<>>' + + # Output name and status + dmraid -s | grep -e ^name -e ^status + + # Output disk names of the RAID disks + DISKS=$(echo "$DMSTATUS" | cut -f1 -d\:) + + for disk in $DISKS ; do + device=$(cat /sys/block/$(basename $disk)/device/model ) + status=$(echo "$DMSTATUS" | grep ^${disk}) + echo "$status Model: $device" + done +fi + +# RAID status of LSI controllers via cfggen +if type cfggen > /dev/null ; then + echo '<<>>' + cfggen 0 DISPLAY | egrep '(Target ID|State|Volume ID|Status of volume)[[:space:]]*:' | sed -e 's/ *//g' -e 's/:/ /' +fi + +# RAID status of LSI MegaRAID controller via MegaCli. You can download that tool from: +# http://www.lsi.com/downloads/Public/MegaRAID%20Common%20Files/8.02.16_MegaCLI.zip +if type MegaCli >/dev/null ; then + MegaCli_bin="MegaCli" +elif type MegaCli64 >/dev/null ; then + MegaCli_bin="MegaCli64" +elif type megacli >/dev/null ; then + MegaCli_bin="megacli" +else + MegaCli_bin="unknown" +fi + +if [ "$MegaCli_bin" != "unknown" ]; then + echo '<<>>' + for part in $($MegaCli_bin -EncInfo -aALL -NoLog < /dev/null \ + | sed -rn 's/:/ /g; s/[[:space:]]+/ /g; s/^ //; s/ $//; s/Number of enclosures on adapter ([0-9]+).*/adapter \1/g; /^(Enclosure|Device ID|adapter) [0-9]+$/ p'); do + [ $part = adapter ] && echo "" + [ $part = 'Enclosure' ] && echo -ne "\ndev2enc" + echo -n " $part" + done + echo + $MegaCli_bin -PDList -aALL -NoLog < /dev/null | egrep 'Enclosure|Raw Size|Slot Number|Device Id|Firmware state|Inquiry|Adapter' + echo '<<>>' + $MegaCli_bin -LDInfo -Lall -aALL -NoLog < /dev/null | egrep 'Size|State|Number|Adapter|Virtual' + echo '<<>>' + $MegaCli_bin -AdpBbuCmd -GetBbuStatus -aALL -NoLog < /dev/null | grep -v Exit +fi + +# RAID status of 3WARE disk controller (by Radoslaw Bak) +if type tw_cli > /dev/null ; then + for C in $(tw_cli show | awk 'NR < 4 { next } { print $1 }'); do + echo '<<<3ware_info>>>' + tw_cli /$C show all | egrep 'Model =|Firmware|Serial' + echo '<<<3ware_disks>>>' + tw_cli /$C show drivestatus | egrep 'p[0-9]' | sed "s/^/$C\//" + echo '<<<3ware_units>>>' + tw_cli /$C show unitstatus | egrep 'u[0-9]' | sed "s/^/$C\//" + done +fi + +# RAID controllers from areca (Taiwan) +# cli64 can be found at ftp://ftp.areca.com.tw/RaidCards/AP_Drivers/Linux/CLI/ +if type cli64 >/dev/null ; then + run_cached -s arc_raid_status 300 "cli64 rsf info | tail -n +3 | head -n -2" +fi + +# VirtualBox Guests. Section must always been output. Otherwise the +# check would not be executed in case no guest additions are installed. +# And that is something the check wants to detect +echo '<<>>' +if type VBoxControl >/dev/null 2>&1 && lsmod | grep vboxguest >/dev/null 2>&1; then + VBoxControl -nologo guestproperty enumerate | cut -d, -f1,2 + [ ${PIPESTATUS[0]} = 0 ] || echo "ERROR" +fi + +# OpenVPN Clients. Currently we assume that the configuration # is in +# /etc/openvpn. We might find a safer way to find the configuration later. +if [ -e /etc/openvpn/openvpn-status.log ] ; then + echo '<<>>' + sed -n -e '/CLIENT LIST/,/ROUTING TABLE/p' < /etc/openvpn/openvpn-status.log | sed -e 1,3d -e '$d' +fi + +# Time synchronization with NTP +if type ntpq > /dev/null 2>&1 ; then + # remove heading, make first column space separated + run_cached -s ntp 30 "waitmax 5 ntpq -np | sed -e 1,2d -e 's/^\(.\)/\1 /' -e 's/^ /%/' || true" +fi + +# Time synchronization with Chrony +if type chronyc > /dev/null 2>&1 ; then + # Force successful exit code. Otherwise section will be missing if daemon not running + run_cached -s chrony 30 "waitmax 5 chronyc -n tracking || true" +fi + +if type nvidia-settings >/dev/null && [ -S /tmp/.X11-unix/X0 ] +then + echo '<<>>' + for var in GPUErrors GPUCoreTemp + do + DISPLAY=:0 waitmax 2 nvidia-settings -t -q $var | sed "s/^/$var: /" + done +fi + +if [ -e /proc/drbd ]; then + echo '<<>>' + cat /proc/drbd +fi + +# Status of CUPS printer queues +if type lpstat > /dev/null 2>&1; then + # Systemd starts cupsd on demand: Instead of checking that the cupsd is + # running we check that the cups service exists and is enabled. + if pgrep -f "\bcupsd" > /dev/null 2>&1 \ + || (type systemctl >/dev/null 2>&1 && systemctl is-enabled cups.service); then + # first define a function to check cups + function cups_queues () { + CPRINTCONF=/etc/cups/printers.conf + if [ -r "$CPRINTCONF" ] ; then + LOCAL_PRINTERS=$(grep -E "<(Default)?Printer .*>" $CPRINTCONF | awk '{print $2}' | sed -e 's/>//') + lpstat -p | while read LINE + do + PRINTER=$(echo $LINE | awk '{print $2}') + if echo "$LOCAL_PRINTERS" | grep -q "$PRINTER"; then + echo $LINE + fi + done + echo '---' + lpstat -o | while read LINE + do + PRINTER=${LINE%%-*} + if echo $LOCAL_PRINTERS | grep -q $PRINTER; then + echo $LINE + fi + done + else + lpstat -p + echo '---' + lpstat -o | sort + fi + } + # Make cups_queues available for subshell + export -f cups_queues + # Use cups_queues function with run_cached and cache time of 5 mins + run_cached -s cups_queues 300 "cups_queues" + fi +fi + +# Heartbeat monitoring +# Different handling for heartbeat clusters with and without CRM +# for the resource state +if [ -S /var/run/heartbeat/crm/cib_ro -o -S /var/run/crm/cib_ro ] || pgrep crmd > /dev/null 2>&1; then + echo '<<>>' + TZ=UTC crm_mon -1 -r | grep -v ^$ | sed 's/^ //; /^\sResource Group:/,$ s/^\s//; s/^\s/_/g' +fi +if type cl_status > /dev/null 2>&1; then + echo '<<>>' + cl_status rscstatus + + echo '<<>>' + for NODE in $(cl_status listnodes); do + if [ $NODE != $(echo $HOSTNAME | tr 'A-Z' 'a-z') ]; then + STATUS=$(cl_status nodestatus $NODE) + echo -n "$NODE $STATUS" + for LINK in $(cl_status listhblinks $NODE 2>/dev/null); do + echo -n " $LINK $(cl_status hblinkstatus $NODE $LINK)" + done + echo + fi + done +fi + +# Postfix mailqueue monitoring +# Determine the number of mails and their size in several postfix mail queues +function read_postfix_queue_dirs { + postfix_queue_dir=$1 + if [ -n "$postfix_queue_dir" ]; then + echo '<<>>' + if [ ! -z "$2" ]; then + echo "[[[${2}]]]" + fi + for queue in deferred active + do + count=$(find $postfix_queue_dir/$queue -type f | wc -l) + size=$(du -s $postfix_queue_dir/$queue | awk '{print $1 }') + if [ -z "$size" ]; then + size=0 + fi + if [ -z "$count" ]; then + echo "Mail queue is empty" + else + echo "QUEUE_${queue} $size $count" + fi + done + fi +} + +# Postfix mailqueue monitoring +# Determine the number of mails and their size in several postfix mail queues +if type postconf >/dev/null ; then + # Check if multi_instance_directories exists in main.cf and is not empty + # always takes the last entry, multiple entries possible + multi_instances_dirs=$(postconf -c /etc/postfix 2>/dev/null | grep ^multi_instance_directories | sed 's/.*=[[:space:]]*//g') + if [ ! -z "$multi_instances_dirs" ]; then + for queue_dir in $multi_instances_dirs + do + if [ -n "$queue_dir" ]; then + postfix_queue_dir=$(postconf -c $queue_dir 2>/dev/null | grep ^queue_directory | sed 's/.*=[[:space:]]*//g') + read_postfix_queue_dirs $postfix_queue_dir $queue_dir + fi + done + + else + postfix_queue_dir=$(postconf -h queue_directory 2>/dev/null) + read_postfix_queue_dirs $postfix_queue_dir + fi + +elif [ -x /usr/sbin/ssmtp ] ; then + echo '<<>>' + mailq 2>&1 | sed 's/^[^:]*: \(.*\)/\1/' | tail -n 6 + +fi + +# Postfix status monitoring. Can handle multiple instances. +if type postfix >/dev/null ; then + echo "<<>>" + for i in $(ls -d /var/spool/postfix*) + do + if [ -e "$i/pid/master.pid" ]; then + postfix_pid=$(cat $i/pid/master.pid | sed 's/ //g') # handle possible spaces in output + if readlink -- "/proc/$postfix_pid/exe" | grep -q ".*postfix/\(sbin/\)\?master.*"; then + echo "$i:the Postfix mail system is running:PID:$postfix_pid" | sed 's/\/var\/spool\///g' + else + echo "$i:PID file exists but instance is not running!" | sed 's/\/var\/spool\///g' + fi + else + echo "$i:the Postfix mail system is not running" | sed 's/\/var\/spool\///g' + fi + done +fi + +# Check status of qmail mailqueue +if type qmail-qstat >/dev/null +then + echo "<<>>" + qmail-qstat +fi + +# Nullmailer queue monitoring +if type nullmailer-send >/dev/null && [ -d /var/spool/nullmailer/queue ] +then + echo '<<>>' + COUNT=$(find /var/spool/nullmailer/queue -type f | wc -l) + SIZE=$(du -s /var/spool/nullmailer/queue | awk '{print $1 }') + echo "$SIZE $COUNT" +fi + +# Check status of OMD sites and Check_MK Notification spooler +if type omd >/dev/null +then + run_cached -s omd_status 60 "omd status --bare --auto || true" + echo '<<>>' + for statefile in /omd/sites/*/var/log/mknotifyd.state ; do + if [ -e "$statefile" ] ; then + site=${statefile%/var/log*} + site=${site#/omd/sites/} + echo "[$site]" + grep -v '^#' < $statefile + fi + done + + echo '<<>>' + for statsfile in /omd/sites/*/var/log/apache/stats; do + if [ -e "$statsfile" ] ; then + site=${statsfile%/var/log*} + site=${site#/omd/sites/} + echo "[$site]" + cat $statsfile + > $statsfile + # prevent next section to fail caused by a missing newline at the end of the statsfile + echo + fi + done +fi + + +# Welcome the ZFS check on Linux +# We do not endorse running ZFS on linux if your vendor doesnt support it ;) +# check zpool status +if type zpool >/dev/null; then + echo "<<>>" + zpool status -x +fi + + +# Veritas Cluster Server +# Software is always installed in /opt/VRTSvcs. +# Secure mode must be off to allow root to execute commands +if [ -x /opt/VRTSvcs/bin/haclus ] +then + echo "<<>>" + vcshost=$(hostname | cut -d. -f1) + /opt/VRTSvcs/bin/haclus -display -localclus | grep -e ClusterName -e ClusState + /opt/VRTSvcs/bin/hasys -display -attribute SysState + /opt/VRTSvcs/bin/hagrp -display -sys $vcshost -attribute State -localclus + /opt/VRTSvcs/bin/hares -display -sys $vcshost -attribute State -localclus +fi + + +# Fileinfo-Check: put patterns for files into /etc/check_mk/fileinfo.cfg +if [ -r "$MK_CONFDIR/fileinfo.cfg" ] ; then + echo '<<>>' + date +%s + for line in $(cat "$MK_CONFDIR/fileinfo.cfg") + do + # only work on lines containing files, skip e.g. comments and blank lines + if [ ${line:0:1} = "/" ]; then + stat -c "%n|%s|%Y" "${line}" 2>/dev/null + + if [ $? -ne 0 ]; then + echo "$line|missing|$(date +%s)" + fi + fi + done +fi + +# Get stats about OMD monitoring cores running on this machine. +# Since cd is a shell builtin the check does not affect the performance +# on non-OMD machines. +if cd /omd/sites +then + echo '<<>>' + for site in * + do + if [ -S "/omd/sites/$site/tmp/run/live" ] ; then + echo "[$site]" + echo -e "GET status" | \ + waitmax 3 /omd/sites/$site/bin/unixcat /omd/sites/$site/tmp/run/live + fi + done + echo '<<>>' + for site in * + do + if [ -S "/omd/sites/$site/tmp/run/mkeventd/status" ] ; then + echo "[\"$site\"]" + echo -e "GET status\nOutputFormat: json" \ + | waitmax 3 /omd/sites/$site/bin/unixcat /omd/sites/$site/tmp/run/mkeventd/status + fi + done +fi + +# Collect states of configured Check_MK site backup jobs +if ls /omd/sites/*/var/check_mk/backup/*.state >/dev/null 2>&1; then + echo "<<>>" + for F in /omd/sites/*/var/check_mk/backup/*.state; do + SITE=${F#/*/*/*} + SITE=${SITE%%/*} + + JOB_IDENT=${F%.state} + JOB_IDENT=${JOB_IDENT##*/} + + if [ "$JOB_IDENT" != "restore" ]; then + echo "[[[site:$SITE:$JOB_IDENT]]]" + cat $F + echo + fi + done +fi + +# Collect states of configured CMA backup jobs +if type mkbackup >/dev/null && ls /var/lib/mkbackup/*.state >/dev/null 2>&1; then + echo "<<>>" + for F in /var/lib/mkbackup/*.state; do + JOB_IDENT=${F%.state} + JOB_IDENT=${JOB_IDENT##*/} + + if [ "$JOB_IDENT" != "restore" ]; then + echo "[[[system:$JOB_IDENT]]]" + cat $F + echo + fi + done +fi + +# Get statistics about monitored jobs. Below the job directory there +# is a sub directory per user that ran a job. That directory must be +# owned by the user so that a symlink or hardlink attack for reading +# arbitrary files can be avoided. +if pushd $MK_VARDIR/job >/dev/null; then + echo '<<>>' + for username in * + do + if [ -d "$username" ] && cd "$username" ; then + if [ $EUID -eq 0 ]; then + su "$username" -c "head -n -0 -v *" + else + head -n -0 -v * + fi + cd .. + fi + done + popd > /dev/null +fi + +# Gather thermal information provided e.g. by acpi +# At the moment only supporting thermal sensors +if ls /sys/class/thermal/thermal_zone* >/dev/null 2>&1; then + echo '<<>>' + for F in /sys/class/thermal/thermal_zone*; do + echo -n "${F##*/} " + if [ ! -e $F/mode ] ; then echo -n "- " ; fi + cat $F/{mode,type,temp,trip_point_*} | tr \\n " " + echo + done +fi + +# Libelle Business Shadow +if type trd >/dev/null; then + echo "<<>>" + trd -s +fi + +# HTTP Accelerator Statistics +if type varnishstat >/dev/null; then + echo "<<>>" + varnishstat -1 +fi + +# Proxmox Cluster +if type pvecm > /dev/null 2>&1 ; then + echo "<<>>" + pvecm status + echo "<<>>" + pvecm nodes +fi + +# Start new liveupdate process in background on each agent execution. Starting +# a new live update process will terminate the old one automatically after +# max. 1 sec. +if [ -e $MK_CONFDIR/real_time_checks.cfg ]; then + if [ -z $REMOTE ]; then + echo "ERROR: \$REMOTE not specified. Not starting Real-Time Checks." >&2 + elif ! type openssl >/dev/null; then + echo "ERROR: openssl command is missing. Not starting Real-Time Checks." >&2 + else + run_real_time_checks >/dev/null & + fi +fi + +# MK's Remote Plugin Executor +if [ -e "$MK_CONFDIR/mrpe.cfg" ] +then + grep -Ev '^[[:space:]]*($|#)' "$MK_CONFDIR/mrpe.cfg" | \ + while read descr cmdline + do + interval= + args="-m" + # NOTE: Due to an escaping-related bug in some old bash versions + # (3.2.x), we have to use an intermediate variable for the pattern. + pattern='\(([^\)]*)\)[[:space:]](.*)' + if [[ $cmdline =~ $pattern ]] + then + parameters=${BASH_REMATCH[1]} + cmdline=${BASH_REMATCH[2]} + + # split multiple parameter assignments + for par in $(echo $parameters | tr ":" "\n") + do + # split each assignment + key=$(echo $par | cut -d= -f1) + value=$(echo $par | cut -d= -f2) + + if [ "$key" = "interval" ] ; then + interval=$value + elif [ "$key" = "appendage" ] ; then + args="$args -a" + fi + done + fi + + if [ -z "$interval" ] + then + run_mrpe $descr "$cmdline" + else + run_cached $args $descr $interval "$cmdline" + fi + done +fi + +# MK's runas Executor +if [ -e "$MK_CONFDIR/runas.cfg" ] +then + grep -Ev '^[[:space:]]*($|#)' "$MK_CONFDIR/runas.cfg" | \ + while read type user include + do + if [ -d $include -o \( "$type" == "mrpe" -a -f $include \) ] ; then + PREFIX="" + if [ "$user" != "-" ] ; then + PREFIX="su $user -c " + fi + + # mrpe includes + if [ "$type" == "mrpe" ] ; then + grep -Ev '^[[:space:]]*($|#)' "$include" | \ + while read descr cmdline + do + interval= + # NOTE: Due to an escaping-related bug in some old bash + # versions (3.2.x), we have to use an intermediate variable + # for the pattern. + pattern='\(([^\)]*)\)[[:space:]](.*)' + if [[ $cmdline =~ $pattern ]] + then + parameters=${BASH_REMATCH[1]} + cmdline=${BASH_REMATCH[2]} + + # split multiple parameter assignments + for par in $(echo $parameters | tr ":" "\n") + do + # split each assignment + IFS='=' read key value <<< $par + if [ "$key" = "interval" ] + then + interval=$value + # no other parameters supported currently + fi + done + fi + + if [ -n "$PREFIX" ] ; then + cmdline="$PREFIX\'$cmdline\'" + fi + if [ -z "$interval" ] + then + run_mrpe $descr "$cmdline" + else + run_cached -m $descr $interval "$cmdline" + fi + done + + # local and plugin includes + elif [ "$type" == "local" -o "$type" == "plugin" ] ; then + if [ "$type" == "local" ] ; then + echo "<<>>" + fi + + find $include -executable -type f | \ + while read filename + do + if [ -n "$PREFIX" ] ; then + cmdline="$PREFIX\"$filename\"" + else + cmdline=$filename + fi + + $cmdline + done + fi + fi + done +fi + +function is_valid_plugin () { + # NOTE: Due to an escaping-related bug in some old bash versions + # (3.2.x), we have to use an intermediate variable for the pattern. + pattern='\.dpkg-(new|old|temp)$' + [[ -f "$1" && -x "$1" && ! "$1" =~ $pattern ]] && true || false +} + + +# Local checks +echo '<<>>' +if cd $LOCALDIR ; then + for skript in $(ls) ; do + if is_valid_plugin "$skript" ; then + ./$skript + fi + done + # Call some plugins only every X'th second + for skript in [1-9]*/* ; do + if is_valid_plugin "$skript" ; then + run_cached local_${skript//\//\\} ${skript%/*} "$skript" + fi + done +fi + +# Plugins +if cd $PLUGINSDIR ; then + for skript in $(ls) ; do + if is_valid_plugin "$skript" ; then + ./$skript + fi + done + # Call some plugins only every Xth second + for skript in [1-9]*/* ; do + if is_valid_plugin "$skript" ; then + run_cached plugins_${skript//\//\\} ${skript%/*} "$skript" + fi + done +fi + +# Agent output snippets created by cronjobs, etc. +if [ -d "$SPOOLDIR" ] +then + pushd "$SPOOLDIR" > /dev/null + now=$(date +%s) + + for file in * + do + test "$file" = "*" && break + # output every file in this directory. If the file is prefixed + # with a number, then that number is the maximum age of the + # file in seconds. If the file is older than that, it is ignored. + maxage="" + part="$file" + + # Each away all digits from the front of the filename and + # collect them in the variable maxage. + while [ "${part/#[0-9]/}" != "$part" ] + do + maxage=$maxage${part:0:1} + part=${part:1} + done + + # If there is at least one digit, than we honor that. + if [ "$maxage" ] ; then + mtime=$(stat -c %Y "$file") + if [ $((now - mtime)) -gt $maxage ] ; then + continue + fi + fi + + # Output the file + cat "$file" + done + popd > /dev/null +fi diff --git a/roles/base/files/usr/lib/check_mk_agent/plugins/backup b/roles/base/files/usr/lib/check_mk_agent/plugins/backup new file mode 100755 index 0000000..878ed7c --- /dev/null +++ b/roles/base/files/usr/lib/check_mk_agent/plugins/backup @@ -0,0 +1,11 @@ +#!/bin/bash + +# Backup check for Check_MK +# Installed by BLSE 2.0 ansible + +SHARELIST=( $( cat /var/backups/shares ) ) + +echo "<<>>" +for SHARE in ${SHARELIST[@]}; do + echo "${SHARE} $( cat ${SHARE}/.backup )" +done diff --git a/roles/base/files/usr/lib/check_mk_agent/plugins/cephfsmounts b/roles/base/files/usr/lib/check_mk_agent/plugins/cephfsmounts new file mode 100755 index 0000000..19d82ac --- /dev/null +++ b/roles/base/files/usr/lib/check_mk_agent/plugins/cephfsmounts @@ -0,0 +1,15 @@ +echo '<<>>' +sed -n '/ ceph\? /s/[^ ]* \([^ ]*\) .*/\1/p' < /proc/mounts | + sed 's/\\040/ /g' | + while read MP + do + if [ ! -r $MP ]; then + echo "$MP Permission denied" + elif [ $STAT_VERSION != $STAT_BROKE ]; then + waitmax -s 9 2 stat -f -c "$MP ok %b %f %a %s" "$MP" || \ + echo "$MP hanging 0 0 0 0" + else + waitmax -s 9 2 stat -f -c "$MP ok %b %f %a %s" "$MP" && \ + printf '\n'|| echo "$MP hanging 0 0 0 0" + fi + done diff --git a/roles/base/files/usr/lib/check_mk_agent/plugins/dpkg b/roles/base/files/usr/lib/check_mk_agent/plugins/dpkg new file mode 100755 index 0000000..ead76d0 --- /dev/null +++ b/roles/base/files/usr/lib/check_mk_agent/plugins/dpkg @@ -0,0 +1,33 @@ +#!/bin/bash + +# Apt and dpkg status check for Check_MK +# Installed by BLSE 2.0 ansible + +TMP_DPKG="$( COLUMNS=200 dpkg --list )" +TMP_AWK="$( awk ' + { if (NR>5) { + if ($1 != "ii") bad_package[$2]=$1; + }} + END { + print NR-5; + bad_package_count=asort(bad_package,junk) + if (bad_package_count) { + for (package in bad_package) + print package "[" bad_package[package] "]" + exit 1 + } + } +' <<<"$TMP_DPKG" )" + +DEBIAN_VERSION="$( cat /etc/debian_version )" +TOTAL_PACKAGES=$( head --lines=1 <<<"${TMP_AWK}" ) +UPGRADABLE_PACKAGES=( $( apt list --upgradable 2>/dev/null | grep -v '^Listing' | awk '{ gsub(/\]/,"",$NF); print $1 "[" $NF "<>" $2 "]" }' ) ) +INCONSISTENT_PACKAGES=( $( tail --lines=+2 <<<"${TMP_AWK}" ) ) +OLD_CONFIG_FILES=( $( ionice -c3 find /etc -type f -a \( -name '*.dpkg-*' -o -name '*.ucf-*' \) 2>/dev/null ) ) + +echo "<<>>" +echo "debian_version ${DEBIAN_VERSION}" +echo "total_packages ${TOTAL_PACKAGES}" +echo "upgradable_packages ${#UPGRADABLE_PACKAGES[*]} ${UPGRADABLE_PACKAGES[*]}" +echo "inconsistent_packages ${#INCONSISTENT_PACKAGES[*]} ${INCONSISTENT_PACKAGES[*]}" +echo "obsolete_configuration_files ${#OLD_CONFIG_FILES[*]} ${OLD_CONFIG_FILES[*]}" diff --git a/roles/base/files/usr/lib/check_mk_agent/plugins/entropy b/roles/base/files/usr/lib/check_mk_agent/plugins/entropy new file mode 100755 index 0000000..35a5965 --- /dev/null +++ b/roles/base/files/usr/lib/check_mk_agent/plugins/entropy @@ -0,0 +1,16 @@ +#!/bin/bash + +# Entropy availability check for Check_MK +# Installed by BLSE 2.0 ansible + +if [ -e /proc/sys/kernel/random/entropy_avail ]; then + + echo '<<>>' + + echo -n "entropy_avail " + cat /proc/sys/kernel/random/entropy_avail + + echo -n "poolsize " + cat /proc/sys/kernel/random/poolsize + +fi diff --git a/roles/base/files/usr/lib/check_mk_agent/plugins/freshness b/roles/base/files/usr/lib/check_mk_agent/plugins/freshness new file mode 100755 index 0000000..3cc7aab --- /dev/null +++ b/roles/base/files/usr/lib/check_mk_agent/plugins/freshness @@ -0,0 +1,52 @@ +#!/bin/bash + +# Open file handle freshness check for Check_MK +# Installed by BLSE 2.0 ansible + +OK=0 +WARNING=1 + +FRESHNESS="$( lsof -Fcftn / 2>/dev/null | grep -v '/tmp' | \ +awk ' +{ + field=substr($0,1,1); + data=substr($0,2); + if (field=="f") { + file_descriptor=data; + } else if (field=="t") { + file_type=data; + } else if (field=="c") { + command_name=data; + } else if (field=="n" && file_descriptor=="DEL" && file_type=="REG") { + name=data; + file[command_name]++; + } +} +END { + for (name in file) { + error++; + # Skip these problematic programs + if (name=="systemd-udevd") { continue; } + if (name=="pulseaudio") { continue; } + if (name=="light-locker") { continue; } + if (name=="at-spi-bus-laun") { continue; } + if (name=="node") { continue; } + if (error_name) { error_name=error_name " " }; + error_name=error_name name; + } + if (error_name) { + print error_name; + exit error; + } else { + exit; + } +}' )"; + +echo "<<>>" +if [ "$FRESHNESS" ]; then + echo "Applications needing restart: $FRESHNESS" + exit $WARNING +else + echo "No applications needing restart" + exit $OK +fi diff --git a/roles/base/files/usr/lib/check_mk_agent/plugins/kernelversion b/roles/base/files/usr/lib/check_mk_agent/plugins/kernelversion new file mode 100755 index 0000000..d0beb2e --- /dev/null +++ b/roles/base/files/usr/lib/check_mk_agent/plugins/kernelversion @@ -0,0 +1,14 @@ +#!/bin/bash +OK=0 +WARNING=1 + +echo "<<>>" +ACTIVE="$( uname -v | awk '{ print $4" "$5 }' )" +ONDISK="$( strings /vmlinuz | grep 'Debian' | head -1 | awk '{ print $6" "$7 }' )" +echo ${ACTIVE} +echo ${ONDISK} +if [[ ${ACTIVE} != ${ONDISK} ]]; then + exit $WARNING +else + exit $OK +fi diff --git a/roles/base/files/usr/lib/check_mk_agent/plugins/ownership b/roles/base/files/usr/lib/check_mk_agent/plugins/ownership new file mode 100755 index 0000000..f1e129c --- /dev/null +++ b/roles/base/files/usr/lib/check_mk_agent/plugins/ownership @@ -0,0 +1,68 @@ +#!/bin/bash + +# File ownership check for Check_MK +# Installed by BLSE 2.0 ansible + +UID_MAX=299 +# http://www.debian.org/doc/debian-policy/ch-opersys.html +# 0-99: Globally allocated by the Debian project +# 100-199: (BLSE) Dynamically allocated system users and groups +# 200-299: (BLSE) BLSE users and groups +# 300-499: (BLSE) reserved +# 500-599: (BLSE) system administrators +# 600-999: (BLSE) reserved +# 64045: (BLSE) ceph + +function is_element_of { + local TO_FIND=$1 + shift + + for ARRAY_ELEMENT in $* + do + if test $TO_FIND = $ARRAY_ELEMENT + then + return 0 + fi + done + return 1 +} + +OK=0 +WARNING=1 + +FILESYSTEMs=(/ /var/log) +MOUNTs=($(awk '{print $2}' '/proc/mounts')) + +FILEs=() +for FILESYSTEM in ${FILESYSTEMs[@]}; do + while IFS= read -r -d $'\0' FILE + do + if ! is_element_of "$FILE" ${FILESYSTEMs[*]}; then + if is_element_of $FILE ${MOUNTs[*]}; then + continue + fi + fi + FILEs+=($FILE) + done < <( find ${FILESYSTEM} -xdev -uid +$UID_MAX -not -uid +64000 -not -uid 2000 \ + -not \( -type d -a \( -path /media -o -path /mnt \) \) \ + -not \( -name '.*.swp' -a -mtime -3 \) \ + -not \( -path '*/.git' -o -path '*/.git/*' \) \ + -not \( -path '*.dirtrack.Storable' \) \ + -not \( -path '/home/*' \) \ + -not \( -path '/tmp/*' \) \ + -not \( -path '/var/home/*' \) \ + -not \( -path '/var/log/gitlab/*' \) \ + -print0 2>/dev/null ) +done + +echo "<<>>" + +if ! test ${#FILEs[*]} -eq 0; then + echo -n "${#FILEs[*]} file(s) found with invalid ownership (must be UID <299): " + echo "${FILEs[*]}" + exit $WARNING +else + echo "All files have valid ownership" + exit $OK +fi + diff --git a/roles/base/files/usr/lib/openssh/ssh-keysign b/roles/base/files/usr/lib/openssh/ssh-keysign new file mode 100755 index 0000000000000000000000000000000000000000..8eba9f8dc42064356d4cac237725f73010f04686 GIT binary patch literal 432264 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�S4UrYTtb(82C>My7pM9-!ElDb;-Olq6DSoAdN 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

&2}r|cc_r9-J{ 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

    J)pfMV}9SD};x>$n!q; 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 z /etc/pvc-install" + register: newhost + args: + creates: "/etc/pvc-install" + +# +# Install custom fact scripts +# +- name: create facts directory + file: + dest: "/etc/ansible/facts.d" + state: directory + recurse: yes + +- name: install custom facts + template: + src: "etc/ansible/facts.d/{{ item }}.fact.j2" + dest: "/etc/ansible/facts.d/{{ item }}.fact" + mode: 0755 + register: installed_facts + with_items: + - host_id + - host_group + - dhcp_status + +- name: regather local facts + setup: + gather_subset: "!all,!any,local" + when: installed_facts.changed + +- debug: + var: ansible_local.host_group + verbosity: 1 + +- debug: + var: ansible_local.host_id + verbosity: 1 + +- debug: + var: ansible_local.dhcp_status + verbosity: 1 + +# +# Debian Buster pre-release tweaks +# +- name: add proper VERSION line in os-release (Debian 10.X testing only) + lineinfile: + dest: "/etc/os-release" + line: 'VERSION="10 (buster)"' + state: present + register: installed_facts + when: + - ansible_distribution_major_version == "buster/sid" + +- name: regather distribution facts + setup: + when: + - installed_facts.changed + - ansible_distribution_major_version == "buster/sid" + +- debug: + var: ansible_distribution_release + verbosity: 1 + when: + - ansible_distribution_major_version == "buster/sid" + +# +# Configure APT +# + +- name: install apt config files + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + with_items: + - { src: "etc/apt/apt.conf.d/10norecommends.j2", dest: "/etc/apt/apt.conf.d/10norecommends" } + - { src: "etc/apt/apt.conf.d/50unattended-upgrades.j2", dest: "/etc/apt/apt.conf.d/50unattended-upgrades" } + - { src: "etc/apt/preferences.d/pins.j2", dest: "/etc/apt/preferences.d/pins" } + - { src: "etc/apt/sources.list.{{ ansible_machine }}.j2", dest: "/etc/apt/sources.list" } + tags: apt + +# +# Safe apt upgrades (on first install only) +# + +- name: apt update + apt: + update-cache: yes + when: newhost.changed + +- name: aptitude safe upgrade with autoremove + apt: + update_cache: yes + autoremove: yes + upgrade: safe + when: newhost.changed + +- name: install dbus + apt: + name: + - dbus + state: latest + when: newhost.changed + +- name: clean out apt cache + file: + path: "/var/cache/apt/archives" + state: absent + when: newhost.changed + +# +# Purge unneeded packages +# + +- name: remove unneeded packages + apt: + name: + - exim4 + - exim4-base + - exim4-config + - exim4-daemon-light + - nano + - joe + state: absent + purge: yes + autoremove: yes + +# +# Install common packages +# + +- name: set override debconf selections + shell: 'echo "{{ item }}" | debconf-set-selections' + with_items: + - "wireshark-common wireshark-common/install-setuid boolean true" + +- name: install common packages (all arch) + apt: + name: + - debconf-utils + - iptables + - locales + - acpid + - acpi-support-base + - rsync + - bash + - bash-completion + - net-tools + - check-mk-agent + - dns-root-data + - bind9-host + - dnsutils + - postfix + - ntp + - openssh-client + - openssh-server + - libpam-systemd + - fail2ban + - ca-certificates + - openssl + - sudo + - rsyslog + - logrotate + - man + - less + - vim + - git + - nmap + - netcat-openbsd + - htop + - psmisc + - dstat + - iotop + - lsof + - jnettop + - iperf + - sysstat + - binutils + - deborphan + - wget + - curl + - gawk + - mmv + - pv + - bc + - reptyr + - sharutils + - tcptraceroute + - nethogs + - strace + - tshark + - acl + - bzip2 + - haveged + - unattended-upgrades + - linux-image-amd64 + - linux-headers-amd64 + +# +# System configuration +# + +# capabilities +- name: set ping capabilities + capabilities: + path: /bin/ping + capability: cap_net_raw=ep + +# locale +- name: install locale config files + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + notify: + - generate locales + with_items: + - { src: "etc/default/locale.j2", dest: "/etc/default/locale" } + - { src: "etc/locale.gen.j2", dest: "/etc/locale.gen" } + +- name: set timezone + file: + src: /usr/share/zoneinfo/Canada/Eastern + dest: /etc/localtime + state: link + force: yes + +# dns +- name: write the hosts config + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + with_items: + - { src: "etc/hosts.j2", dest: "/etc/hosts" } + tags: dns + +- name: write the resolver configs + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + with_items: + - { src: "etc/dhcp/dhclient-enter-hooks.d/noresolv.j2", dest: "/etc/dhcp/dhclient-enter-hooks.d/noresolv" } + - { src: "etc/resolv.conf.j2", dest: "/etc/resolv.conf" } + tags: dns + +# acpi +- name: install sysctl tweaks + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + with_items: + - { src: "etc/sysctl.d/pvc.conf.j2", dest: "/etc/sysctl.d/pvc.conf" } + +- name: activate sysctl tweaks + shell: "sysctl -p {{ item }}" + with_items: + - /etc/sysctl.d/pvc.conf + +# syslog +- name: install rsyslog and logrotate configs + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + notify: + - restart rsyslog + with_items: + - { src: "etc/rsyslog.conf.j2", dest: "/etc/rsyslog.conf" } + - { src: "etc/logrotate.d/rsyslog.j2", dest: "/etc/logrotate.d/rsyslog" } + tags: rsyslog + +- name: set journalctl persistence + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + mode: 0644 + with_items: + - { src: "etc/systemd/journald.conf.j2", dest: "/etc/systemd/journald.conf" } + tags: rsyslog + +# cron +- name: install crontab + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + mode: 0755 + with_items: + - { src: "etc/crontab.j2", dest: "/etc/crontab" } + +# mta +- name: install postfix generic config + template: + src: "etc/postfix/main.cf.j2" + dest: "/etc/postfix/main.cf" + notify: + - restart postfix + +- name: touch the postfix aliases file + file: + dest: /etc/postfix/aliases + state: touch + +# +# Local alias maps +# +- name: install local alias maps for various users + lineinfile: + dest: "/etc/aliases" + regexp: "^{{ item }}:" + line: "{{ item }}: {{ username_email_root }}" + state: present + with_items: + - root + - postmaster + - amavis + - clamav + notify: + - newaliases + +# ntp +- name: write the NTP config file + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + notify: + - restart ntp + with_items: + - { src: "etc/ntp.conf.j2", dest: "/etc/ntp.conf" } + tags: ntp + +# ssl +- name: ensure haveged is running + service: + name: haveged + state: started + +- name: generate diffie-hellman parameters + command: openssl dhparam -out /etc/ssl/dhparams.pem 2048 + args: + creates: /etc/ssl/dhparams.pem + +- name: correct permissions on dhparams + file: + dest: /etc/ssl/dhparams.pem + mode: 0440 + +# ssh +- name: write the sshd_config files + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + notify: + - restart ssh + with_items: + - { src: 'etc/ssh/ssh_config.j2', dest: '/etc/ssh/ssh_config' } + - { src: 'etc/ssh/sshd_config.j2', dest: '/etc/ssh/sshd_config' } + - { src: 'etc/ssh/shosts.equiv.j2', dest: '/etc/ssh/shosts.equiv' } + - { src: 'etc/ssh/ssh_known_hosts.j2', dest: '/etc/ssh/ssh_known_hosts' } + tags: ssh + +- name: write sshd pam.d config + template: + src: "etc/pam.d/sshd.j2" + dest: "/etc/pam.d/sshd" + tags: ssh + +- name: remove unneeded SSH keys (leave only RSA and ED25519) + file: + name: "{{ item }}" + state: "absent" + with_items: + - /etc/ssh/ssh_host_dsa_key + - /etc/ssh/ssh_host_dsa_key.pub + - /etc/ssh/ssh_host_ecdsa_key + - /etc/ssh/ssh_host_ecdsa_key.pub + notify: + - restart ssh + tags: ssh + +- name: set permissions on rsa and ed25519 host keys (just in case they're wrong) + file: + name: "/etc/ssh/{{ item.name }}" + mode: "{{ item.mode }}" + with_items: + - { name: 'ssh_host_rsa_key', mode: '600' } + - { name: 'ssh_host_rsa_key.pub', mode: '644' } + - { name: 'ssh_host_ed25519_key', mode: '600' } + - { name: 'ssh_host_ed25519_key.pub', mode: '644' } + tags: ssh + +# sudo +- name: write the sudoers file + template: + src: "etc/sudoers.j2" + dest: "/etc/sudoers" + mode: 0440 + +# bash +- name: write the bash.bashrc config file + template: + src: "etc/bash.bashrc.j2" + dest: "/etc/bash.bashrc" + +# motd +- name: ensure update-motd and w scripts are present + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + mode: 0755 + with_items: + - { src: "usr/local/sbin/update-motd.sh.j2", dest: "/usr/local/sbin/update-motd.sh" } + - { src: "etc/profile.d/w.sh.j2", dest: "/etc/profile.d/w.sh" } + tags: motd + +- name: install update-motd crontab + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + mode: 0644 + with_items: + - { src: "etc/cron.d/update-motd.j2", dest: "/etc/cron.d/update-motd" } + tags: motd + +- name: ensure /etc/motd is absent + file: + dest: "/etc/motd" + state: absent + tags: motd + +# dpkg +- name: install dpkg-cleanup script + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + mode: 0755 + with_items: + - { src: "usr/local/sbin/dpkg-cleanup.sh.j2", dest: "/usr/local/sbin/dpkg-cleanup.sh" } + tags: dpkg + +# fail2ban +- name: install fail2ban configurations + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + mode: 0644 + notify: restart fail2ban + with_items: + - { src: "etc/fail2ban/action.d/route.conf.j2", dest: "/etc/fail2ban/action.d/route.conf" } + - { src: "etc/fail2ban/filter.d/sshd.conf.j2", dest: "/etc/fail2ban/filter.d/sshd.conf" } + - { src: "etc/fail2ban/jail.d/sshd.conf.j2", dest: "/etc/fail2ban/jail.d/sshd.conf" } + - { src: "etc/fail2ban/jail.d/sshd.local.j2", dest: "/etc/fail2ban/jail.d/sshd.local" } + tags: fail2ban + +# +# Configure users +# + +# common +- name: ensure /var/home exists + file: + state: directory + dest: /var/home + tags: users + +- name: ensure group media exists + group: + name: media + gid: 9000 + state: present + tags: users + +# root +- name: set Root password + user: + name: root + password: "{{ passwdhash_root }}" + tags: users + +- name: remove Root known_hosts + file: + state: absent + dest: /root/.ssh/known_hosts + tags: users + +- name: write vimrc to root homedir + template: + src: var/home/user/vimrc.j2 + dest: /root/.vimrc + mode: 0600 + tags: users + +- name: create vimdir + file: + state: directory + dest: /root/.vim + mode: 0700 + tags: users + +- name: write htoprc to homedir + template: + src: var/home/user/config/htop/htoprc.j2 + dest: /root/.htoprc + mode: 0600 + tags: users + +# backup +- name: ensure backup user has shell + user: + name: backup + shell: /bin/sh + tags: users + +- name: create backup .ssh directory + file: + path: /var/backups/.ssh + state: directory + owner: backup + group: root + mode: 0700 + tags: users + +- name: create backup authorized_keys file + template: + src: var/backups/ssh/authorized_keys.j2 + dest: /var/backups/.ssh/authorized_keys + owner: backup + group: root + mode: 0640 + tags: users + +- name: write the sudoers file + template: + src: etc/sudoers.d/sudoers-backup.j2 + dest: /etc/sudoers.d/backup + tags: users + +- name: install the post-backup timestamp script + template: + src: var/backups/timestamp.sh.j2 + dest: /var/backups/timestamp.sh + mode: 0755 + tags: users + +- name: touch shares file + file: + dest: /var/backups/shares + state: touch + owner: backup + tags: users + +# deploy +- name: ensure user deploy exists + user: + name: deploy + uid: 200 + group: operator + shell: /bin/bash + home: /var/home/deploy + createhome: yes + move_home: yes + state: present + append: yes + tags: users + +- name: ensure homedir has right permissions + file: + dest: /var/home/deploy + state: directory + owner: deploy + group: operator + mode: 0700 + tags: users + +- name: ensure .ssh directory exists + file: + dest: /var/home/deploy/.ssh + state: directory + owner: deploy + group: operator + mode: 0700 + tags: users + +- name: add authorized keys + authorized_key: + user: "deploy" + key: "{{ item.key }}" + with_items: "{{ admin_users }}" + tags: users + +# admin_users +- name: ensure user exists + user: + name: "{{ item.name }}" + uid: "{{ item.uid }}" + group: operator + groups: sudo,adm,media,wireshark + shell: /bin/bash + home: "/var/home/{{ item.name }}" + createhome: yes + state: present + append: yes + with_items: "{{ admin_users }}" + tags: users + +- name: ensure homedir has right permissions + file: + dest: "/var/home/{{ item.name }}" + state: directory + owner: "{{ item.name }}" + group: operator + mode: 0700 + with_items: "{{ admin_users }}" + tags: users + +- name: ensure .ssh directory exists + file: + dest: "/var/home/{{ item.name }}/.ssh" + state: directory + owner: "{{ item.name }}" + group: operator + mode: 0700 + with_items: "{{ admin_users }}" + tags: users + +- name: add authorized keys + authorized_key: + user: "{{ item.name }}" + key: "{{ item.key }}" + with_items: "{{ admin_users }}" + tags: users + +- name: write bashrc to homedir + template: + src: var/home/user/bashrc.j2 + dest: "/var/home/{{ item.name }}/.bashrc" + owner: "{{ item.name }}" + group: operator + mode: 0700 + with_items: "{{ admin_users }}" + tags: users + +- name: write bash_logout to homedir + template: + src: var/home/user/bash_logout.j2 + dest: "/var/home/{{ item.name }}/.bash_logout" + owner: "{{ item.name }}" + group: operator + mode: 0700 + with_items: "{{ admin_users }}" + tags: users + +- name: ensure htop config directory exists + file: + dest: "/var/home/{{ item.name }}/.config/htop" + state: directory + owner: "{{ item.name }}" + group: operator + mode: 0755 + with_items: "{{ admin_users }}" + tags: users + +- name: write htoprc to homedir + template: + src: var/home/user/config/htop/htoprc.j2 + dest: "/var/home/{{ item.name }}/.config/htop/htoprc" + owner: "{{ item.name }}" + group: operator + mode: 0644 + with_items: "{{ admin_users }}" + tags: users + +- name: write profile to homedir + template: + src: var/home/user/profile.j2 + dest: "/var/home/{{ item.name }}/.profile" + owner: "{{ item.name }}" + group: operator + mode: 0700 + with_items: "{{ admin_users }}" + tags: users + +- name: write vimrc to homedir + template: + src: var/home/user/vimrc.j2 + dest: "/var/home/{{ item.name }}/.vimrc" + owner: "{{ item.name }}" + group: operator + mode: 0600 + with_items: "{{ admin_users }}" + tags: users + +- name: create vimdir + file: + state: directory + dest: /var/home/{{ item.name }}/.vim + owner: "{{ item.name }}" + group: operator + mode: 0700 + with_items: "{{ admin_users }}" + tags: users + +# +# Verify and enable services +# + +- name: verify and enable services + service: + name: "{{ item }}" + state: started + enabled: yes + with_items: + - acpid + - rsyslog + - postfix + - ntp + - ssh diff --git a/roles/base/templates/etc/ansible/facts.d/dhcp_status.fact.j2 b/roles/base/templates/etc/ansible/facts.d/dhcp_status.fact.j2 new file mode 100644 index 0000000..46c7953 --- /dev/null +++ b/roles/base/templates/etc/ansible/facts.d/dhcp_status.fact.j2 @@ -0,0 +1,5 @@ +#!/bin/bash +# Ansible fact - dhcp_status +# {{ ansible_managed }} +DHCP_STATUS="$( grep -o 'dhcp' /etc/network/interfaces | uniq )" +echo "\"${DHCP_STATUS}\"" diff --git a/roles/base/templates/etc/ansible/facts.d/host_group.fact.j2 b/roles/base/templates/etc/ansible/facts.d/host_group.fact.j2 new file mode 100644 index 0000000..13efb07 --- /dev/null +++ b/roles/base/templates/etc/ansible/facts.d/host_group.fact.j2 @@ -0,0 +1,5 @@ +#!/bin/bash +# Ansible fact - host_group +# {{ ansible_managed }} +HOST_GROUP="$( hostname -s | sed 's/[0-9]*//g' )" +echo "\"${HOST_GROUP}\"" diff --git a/roles/base/templates/etc/ansible/facts.d/host_id.fact.j2 b/roles/base/templates/etc/ansible/facts.d/host_id.fact.j2 new file mode 100644 index 0000000..90e87ed --- /dev/null +++ b/roles/base/templates/etc/ansible/facts.d/host_id.fact.j2 @@ -0,0 +1,8 @@ +#!/bin/bash +# Ansible fact - host_id +# {{ ansible_managed }} +HOST_ID="$( hostname -s | grep -o '[0-9]\+' )" +if [[ -z ${HOST_ID} ]]; then + HOST_ID="0" +fi +echo "\"${HOST_ID}\"" diff --git a/roles/base/templates/etc/apt/apt.conf.d/10norecommends.j2 b/roles/base/templates/etc/apt/apt.conf.d/10norecommends.j2 new file mode 100644 index 0000000..56709a6 --- /dev/null +++ b/roles/base/templates/etc/apt/apt.conf.d/10norecommends.j2 @@ -0,0 +1,5 @@ +# apt configuration: disable recommends +# {{ ansible_managed }} + +APT::Install-Recommends "0"; +APT::Install-Suggests "0"; diff --git a/roles/base/templates/etc/apt/apt.conf.d/50unattended-upgrades.j2 b/roles/base/templates/etc/apt/apt.conf.d/50unattended-upgrades.j2 new file mode 100644 index 0000000..0f8e64e --- /dev/null +++ b/roles/base/templates/etc/apt/apt.conf.d/50unattended-upgrades.j2 @@ -0,0 +1,37 @@ +# Unattended upgrades configuration +# {{ ansible_managed }} + +Unattended-Upgrade::Origins-Pattern { + "origin=Debian,codename=${distro_codename},label=Debian"; + "origin=Debian,codename=${distro_codename},label=Debian-Security"; +}; + +Unattended-Upgrade::Package-Blacklist { + # "libc6$"; + # "libc6-dev$"; + # "libc6-i686$"; +}; + +# General configurations +Unattended-Upgrade::AutoFixInterruptedDpkg "true"; +Unattended-Upgrade::MinimalSteps "true"; +Unattended-Upgrade::InstallOnShutdown "false"; +Unattended-Upgrade::Mail "root@bonilan.net"; +Unattended-Upgrade::MailOnlyOnError "true"; +Unattended-Upgrade::Remove-Unused-Kernel-Packages "true"; +Unattended-Upgrade::Remove-New-Unused-Dependencies "true"; +Unattended-Upgrade::Remove-Unused-Dependencies "true"; +Unattended-Upgrade::SyslogEnable "true"; +Unattended-Upgrade::SyslogFacility "daemon"; +Unattended-Upgrade::Verbose "false"; +Unattended-Upgrade::Debug "false"; + +# Reboot configurations - skip cephX and hvX +{% if 'hv' in group_names or 'ceph' in group_names %} +Unattended-Upgrade::Automatic-Reboot "false"; +{% else %} +Unattended-Upgrade::Automatic-Reboot "true"; +Unattended-Upgrade::Automatic-Reboot-WithUsers "true"; +{% set reboot_time_minute = 2 * ansible_local.host_id|int %} +Unattended-Upgrade::Automatic-Reboot-Time "04:{{ '%02d' % reboot_time_minute }}"; +{% endif %} diff --git a/roles/base/templates/etc/apt/preferences.d/pins.j2 b/roles/base/templates/etc/apt/preferences.d/pins.j2 new file mode 100644 index 0000000..f8668bd --- /dev/null +++ b/roles/base/templates/etc/apt/preferences.d/pins.j2 @@ -0,0 +1,12 @@ +# apt configuration: pinning preferences +# {{ ansible_managed }} + +Package: * +Pin: release a={{ ansible_distribution_release }} +Pin-Priority: 999 + +{% if 'base' in group_names %} +Package: * +Pin: release a={{ ansible_distribution_release }}-backports +Pin-Priority: -1 +{% endif %} diff --git a/roles/base/templates/etc/apt/sources.list.x86_64.j2 b/roles/base/templates/etc/apt/sources.list.x86_64.j2 new file mode 100644 index 0000000..fbb5ec5 --- /dev/null +++ b/roles/base/templates/etc/apt/sources.list.x86_64.j2 @@ -0,0 +1,14 @@ +# apt configuration: main sources list +# {{ ansible_managed }} + +deb http://debian.mirror.rafal.ca/debian {{ ansible_distribution_release }} main contrib non-free +deb-src http://debian.mirror.rafal.ca/debian {{ ansible_distribution_release }} main contrib + +deb http://security.debian.org/ {{ ansible_distribution_release }}/updates main contrib +deb-src http://security.debian.org/ {{ ansible_distribution_release }}/updates main contrib + +deb http://debian.mirror.rafal.ca/debian/ {{ ansible_distribution_release }}-updates main contrib +deb-src http://debian.mirror.rafal.ca/debian/ {{ ansible_distribution_release }}-updates main contrib + +deb https://repo.bonifacelabs.net/debian/ {{ ansible_distribution_release }}-updates main +deb-src https://repo.bonifacelabs.net/debian/ {{ ansible_distribution_release }}-updates main diff --git a/roles/base/templates/etc/bash.bashrc.j2 b/roles/base/templates/etc/bash.bashrc.j2 new file mode 100755 index 0000000..b8449e8 --- /dev/null +++ b/roles/base/templates/etc/bash.bashrc.j2 @@ -0,0 +1,126 @@ +# System-wide .bashrc file for interactive bash(1) shells. +# {{ ansible_managed }} + +# To enable the settings / commands in this file for login shells as well, +# this file has to be sourced in /etc/profile. + +# Fix the preceeding space stupidity +export HISTCONTROL=ignorespace + +# If not running interactively, don't do anything +[ -z "$PS1" ] && return + +# check the window size after each command and, if necessary, +# update the values of LINES and COLUMNS. +shopt -s checkwinsize + +# set variable identifying the chroot you work in (used in the prompt below) +if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then + debian_chroot=$(cat /etc/debian_chroot) +fi + +#------------------------------------------------------------------------------ +# Returncode. +#------------------------------------------------------------------------------ +function returncode +{ + returncode=$? + if [ $returncode != 0 ]; then + echo "[$returncode]" + else + echo "" + fi +} + +alias ll='ls -al' + +use_color=false + +# Set colorful PS1 only on colorful terminals. +# dircolors --print-database uses its own built-in database +# instead of using /etc/DIR_COLORS. Try to use the external file +# first to take advantage of user additions. Use internal bash +# globbing instead of external grep binary. +safe_term=${TERM//[^[:alnum:]]/?} # sanitize TERM +match_lhs="" +[[ -f ~/.dir_colors ]] && match_lhs="${match_lhs}$(<~/.dir_colors)" +[[ -f /etc/DIR_COLORS ]] && match_lhs="${match_lhs}$(/dev/null \ + && match_lhs=$(dircolors --print-database) +[[ $'\n'${match_lhs} == *$'\n'"TERM "${safe_term}* ]] && use_color=true + +if ${use_color} ; then + # Enable colors for ls, etc. Prefer ~/.dir_colors #64489 + if type -P dircolors >/dev/null ; then + if [[ -f ~/.dir_colors ]] ; then + eval $(dircolors -b ~/.dir_colors) + elif [[ -f /etc/DIR_COLORS ]] ; then + eval $(dircolors -b /etc/DIR_COLORS) + else + eval $(dircolors) + fi + fi + + if [[ ${EUID} == 0 ]] ; then + PS1='\[\033[0;31m\]$(returncode)\[\033[0;37m\]\[\033[0;35m\]${debian_chroot:+($debian_chroot)}\[\033[01;31m\]\H\[\033[01;34m\] \w \$\[\033[00m\] ' + elif [[ ${UID} == 200 ]] ; then + PS1='\[\033[0;31m\]$(returncode)\[\033[0;37m\]\[\033[0;35m\]${debian_chroot:+($debian_chroot)}\[\033[01;31m\]\u@\H\[\033[01;34m\] \w \$\[\033[00m\] ' + else + PS1='\[\033[0;31m\]$(returncode)\[\033[0;37m\]\[\033[0;35m\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\H\[\033[01;34m\] \w \$\[\033[00m\] ' + fi + + alias ls='ls --color=auto' + alias grep='grep --colour=auto' + alias fgrep='fgrep --colour=auto' + alias egrep='egrep --colour=auto' + alias ll='ls -lF' + alias la='ls -A' + alias l='ls -CF' +else + if [[ ${EUID} == 0 ]] ; then + # show root@ when we don't have colors + PS1='\[$(returncode)\]\u@\H \w \$ ' + else + PS1='\[$(returncode)\]\u@\H \w \$ ' + fi +fi + +# Try to keep environment pollution down, EPA loves us. +unset use_color safe_term match_lhs + +# Commented out, don't overwrite xterm -T "title" -n "icontitle" by default. +# If this is an xterm set the title to user@host:dir +#case "$TERM" in +#xterm*|rxvt*) +# PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"' +# ;; +#*) +# ;; +#esac + +# enable bash completion in interactive shells +if ! shopt -oq posix; then + if [ -f /usr/share/bash-completion/bash_completion ]; then + . /usr/share/bash-completion/bash_completion + elif [ -f /etc/bash_completion ]; then + . /etc/bash_completion + fi +fi + +# if the command-not-found package is installed, use it +if [ -x /usr/lib/command-not-found -o -x /usr/share/command-not-found/command-not-found ]; then + function command_not_found_handle { + # check because c-n-f could've been removed in the meantime + if [ -x /usr/lib/command-not-found ]; then + /usr/bin/python /usr/lib/command-not-found -- "$1" + return $? + elif [ -x /usr/share/command-not-found/command-not-found ]; then + /usr/bin/python /usr/share/command-not-found/command-not-found -- "$1" + return $? + else + printf "%s: command not found\n" "$1" >&2 + return 127 + fi + } +fi diff --git a/roles/base/templates/etc/check_mk/logwatch.cfg.j2 b/roles/base/templates/etc/check_mk/logwatch.cfg.j2 new file mode 100644 index 0000000..c45f12b --- /dev/null +++ b/roles/base/templates/etc/check_mk/logwatch.cfg.j2 @@ -0,0 +1,58 @@ +# +------------------------------------------------------------------+ +# | ____ _ _ __ __ _ __ | +# | / ___| |__ ___ ___| | __ | \/ | |/ / | +# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / | +# | | |___| | | | __/ (__| < | | | | . \ | +# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ | +# | | +# | Copyright Mathias Kettner 2013 mk@mathias-kettner.de | +# +------------------------------------------------------------------+ +# +# This file is part of Check_MK. +# The official homepage is at http://mathias-kettner.de/check_mk. +# +# {{ ansible_managed }} +# +# check_mk is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation in version 2. check_mk is distributed +# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with- +# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU General Public License for more de- +# ails. You should have received a copy of the GNU General Public +# License along with GNU Make; see the file COPYING. If not, write +# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301 USA. + +# logwatch.cfg +# This file configures mk_logwatch. Define your logfiles +# and patterns to be looked for here. + +# Name one or more logfiles +/var/log/system.log /var/log/daemon.log +# Patterns are indented with one space are prefixed with: +# C: Critical messages +# W: Warning messages +# I: ignore these lines (OK) +# The first match decided. Lines that do not match any pattern +# are ignored + C Fail event detected on md device + I mdadm.*: Rebuild.*event detected + W mdadm\[ + W ata.*hard resetting link + W ata.*soft reset failed (.*FIS failed) + W device-mapper: thin:.*reached low water mark + C device-mapper: thin:.*no free space + +/var/log/auth.log + W sshd.*Corrupted MAC on input + +/var/log/kern.log + C panic + C Oops + W generic protection rip + W .*Unrecovered read error - auto reallocate failed + +# Globbing patterns are allowed: +# /sapdata/*/saptrans.log +# C ORA- diff --git a/roles/base/templates/etc/cron.d/update-motd.j2 b/roles/base/templates/etc/cron.d/update-motd.j2 new file mode 100644 index 0000000..79f1e2b --- /dev/null +++ b/roles/base/templates/etc/cron.d/update-motd.j2 @@ -0,0 +1,4 @@ +# cron file for motd +# {{ ansible_managed }} + +* * * * * root /bin/sh /usr/local/sbin/update-motd.sh &>/dev/null diff --git a/roles/base/templates/etc/crontab.j2 b/roles/base/templates/etc/crontab.j2 new file mode 100644 index 0000000..82d9da2 --- /dev/null +++ b/roles/base/templates/etc/crontab.j2 @@ -0,0 +1,12 @@ +# /etc/crontab: system-wide crontab +# {{ ansible_managed }} + +SHELL=/bin/sh +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +# m h dom mon dow user command +00 * * * * root cd / && run-parts --report /etc/cron.hourly +05 0 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily ) +15 0 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly ) +30 0 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly ) +# diff --git a/roles/base/templates/etc/default/locale.j2 b/roles/base/templates/etc/default/locale.j2 new file mode 100644 index 0000000..3944c9a --- /dev/null +++ b/roles/base/templates/etc/default/locale.j2 @@ -0,0 +1,4 @@ +LANGUAGE=en_CA.UTF-8 +LC_ALL=en_CA.UTF-8 +LANG=en_CA.UTF-8 +LC_TYPE=en_CA.UTF-8 diff --git a/roles/base/templates/etc/dhcp/dhclient-enter-hooks.d/noresolv.j2 b/roles/base/templates/etc/dhcp/dhclient-enter-hooks.d/noresolv.j2 new file mode 100644 index 0000000..b0cc5ab --- /dev/null +++ b/roles/base/templates/etc/dhcp/dhclient-enter-hooks.d/noresolv.j2 @@ -0,0 +1,6 @@ +#!/bin/sh +# Disasble resolv.conf generation from DHCP +# {{ ansible_managed }} +make_resolv_conf() { + : +} diff --git a/roles/base/templates/etc/fail2ban/action.d/route.conf.j2 b/roles/base/templates/etc/fail2ban/action.d/route.conf.j2 new file mode 100644 index 0000000..19b02c4 --- /dev/null +++ b/roles/base/templates/etc/fail2ban/action.d/route.conf.j2 @@ -0,0 +1,15 @@ +# fail2ban action - route + +[Definition] +actionban = ip route add +actionunban = ip route del +actioncheck = +actionstart = +actionstop = + +[Init] + +# Option: blocktype +# Note: Type can be blackhole, unreachable and prohibit. Unreachable and prohibit correspond to the ICMP reject messages. +# Values: STRING +blocktype = blackhole diff --git a/roles/base/templates/etc/fail2ban/filter.d/sshd.conf.j2 b/roles/base/templates/etc/fail2ban/filter.d/sshd.conf.j2 new file mode 100644 index 0000000..df4f1ed --- /dev/null +++ b/roles/base/templates/etc/fail2ban/filter.d/sshd.conf.j2 @@ -0,0 +1,50 @@ +# Fail2Ban filter for openssh +# {{ ansible_managed }} + +[INCLUDES] + +# Read common prefixes. If any customizations available -- read them from +# common.local +before = common.conf + +[Definition] + +_daemon = sshd + +failregex = ^%(__prefix_line)s(?:error: PAM: )?[aA]uthentication (?:failure|error|failed) for .* from ( via \S+)?\s*$ + ^%(__prefix_line)s(?:error: PAM: )?User not known to the underlying authentication module for .* from \s*$ + ^%(__prefix_line)sFailed \S+ for (?Pinvalid user )?(?P(?P\S+)|(?(cond_inv)(?:(?! from ).)*?|[^:]+)) from (?: port \d+)?(?: ssh\d*)?(?(cond_user):|(?:(?:(?! from ).)*)$) + ^%(__prefix_line)sROOT LOGIN REFUSED.* FROM \s*$ + ^%(__prefix_line)s[iI](?:llegal|nvalid) user .*? from (?: port \d+)?\s*$ + ^%(__prefix_line)sUser .+ from not allowed because not listed in AllowUsers\s*$ + ^%(__prefix_line)sUser .+ from not allowed because listed in DenyUsers\s*$ + ^%(__prefix_line)sUser .+ from not allowed because not in any group\s*$ + ^%(__prefix_line)srefused connect from \S+ \(\)\s*$ + ^%(__prefix_line)s(?:error: )?Received disconnect from : 3: .*: Auth fail(?: \[preauth\])?$ + ^%(__prefix_line)sUser .+ from not allowed because a group is listed in DenyGroups\s*$ + ^%(__prefix_line)sUser .+ from not allowed because none of user's groups are listed in AllowGroups\s*$ + ^(?P<__prefix>%(__prefix_line)s)User .+ not allowed because account is locked(?P=__prefix)(?:error: )?Received disconnect from : 11: .+ \[preauth\]$ + ^(?P<__prefix>%(__prefix_line)s)Disconnecting: Too many authentication failures for .+? \[preauth\](?P=__prefix)(?:error: )?Connection closed by \[preauth\]$ + ^(?P<__prefix>%(__prefix_line)s)Connection from port \d+(?: on \S+ port \d+)?(?P=__prefix)Disconnecting: Too many authentication failures for .+? \[preauth\]$ + ^%(__prefix_line)s(error: )?maximum authentication attempts exceeded for .* from (?: port \d*)?(?: ssh\d*)? \[preauth\]$ + ^%(__prefix_line)spam_unix\(sshd:auth\):\s+authentication failure;\s*logname=\S*\s*uid=\d*\s*euid=\d*\s*tty=\S*\s*ruser=\S*\s*rhost=\s.*$ + ^%(__prefix_line)sUnable to negotiate with .*$ + +ignoreregex = + +[Init] + +# "maxlines" is number of log lines to buffer for multi-line regex searches +maxlines = 10 + +journalmatch = _SYSTEMD_UNIT=sshd.service + _COMM=sshd + +# DEV Notes: +# +# "Failed \S+ for .*? from ..." failregex uses non-greedy catch-all because +# it is coming before use of which is not hard-anchored at the end as well, +# and later catch-all's could contain user-provided input, which need to be greedily +# matched away first. +# +# Author: Cyril Jaquier, Yaroslav Halchenko, Petr Voralek, Daniel Black + diff --git a/roles/base/templates/etc/fail2ban/jail.d/sshd.conf.j2 b/roles/base/templates/etc/fail2ban/jail.d/sshd.conf.j2 new file mode 100644 index 0000000..87e4c97 --- /dev/null +++ b/roles/base/templates/etc/fail2ban/jail.d/sshd.conf.j2 @@ -0,0 +1,30 @@ +# Fail2Ban configuration file +# +# Author: Wolfgang Karall (based on sshd.conf from Cyril Jaquier) +# + +[INCLUDES] + +# Read common prefixes. If any customizations available -- read them from +# common.local +before = common.conf + + +[Definition] + +_daemon = sshd + +# Option: failregex +# Notes.: regex to match the password failures messages in the logfile. The +# host must be matched by a group named "host". The tag "" can +# be used for standard IP/hostname matching and is only an alias for +# (?:::f{4,6}:)?(?P[\w\-.^_]+) +# Values: TEXT +# +failregex = ^%(__prefix_line)sUnable to negotiate with .*$ + +# Option: ignoreregex +# Notes.: regex to ignore. If this regex matches, the line is ignored. +# Values: TEXT +# +ignoreregex = ^%(__prefix_line)sDid not receive identification string from .*$ diff --git a/roles/base/templates/etc/fail2ban/jail.d/sshd.local.j2 b/roles/base/templates/etc/fail2ban/jail.d/sshd.local.j2 new file mode 100644 index 0000000..1ba69dd --- /dev/null +++ b/roles/base/templates/etc/fail2ban/jail.d/sshd.local.j2 @@ -0,0 +1,11 @@ +[DEFAULT] +maxretry = 3 +bantime = 14400 +ignoreip = 127.0.0.0/8 10.0.0.0/8 198.55.48.48/28 + +[ssh] +enabled = true +filter = sshd +action = route +logpath = /var/log/auth.log + diff --git a/roles/base/templates/etc/hosts.j2 b/roles/base/templates/etc/hosts.j2 new file mode 100644 index 0000000..8bc1830 --- /dev/null +++ b/roles/base/templates/etc/hosts.j2 @@ -0,0 +1,6 @@ +# Local system hosts file +# {{ ansible_managed }} + +::1 localhost ip6-localhost ip6-loopback +ff02::1 ip6-allmodes +ff02::2 ip6-allrouters diff --git a/roles/base/templates/etc/locale.gen.j2 b/roles/base/templates/etc/locale.gen.j2 new file mode 100644 index 0000000..531364e --- /dev/null +++ b/roles/base/templates/etc/locale.gen.j2 @@ -0,0 +1,4 @@ +# Locales configuration file +# {{ ansible_managed }} + +en_CA.UTF-8 UTF-8 diff --git a/roles/base/templates/etc/logrotate.d/rsyslog-loghost.j2 b/roles/base/templates/etc/logrotate.d/rsyslog-loghost.j2 new file mode 100644 index 0000000..243ecf7 --- /dev/null +++ b/roles/base/templates/etc/logrotate.d/rsyslog-loghost.j2 @@ -0,0 +1,23 @@ +# Logrotate configuration for loghost archives +# {{ ansible_managed }} + +/srv/log/kern.log +/srv/log/daemon.log +/srv/log/haproxy.log +/srv/log/auth.log +/srv/log/cron.log +/srv/log/mail.log +/srv/log/boot.log +/srv/log/system.log +{ + weekly + missingok + copytruncate + dateext + notifempty + sharedscripts + postrotate + /usr/lib/rsyslog/rsyslog-rotate &>/dev/null + /usr/local/sbin/loghost-archive.sh &>/dev/null + endscript +} diff --git a/roles/base/templates/etc/logrotate.d/rsyslog.j2 b/roles/base/templates/etc/logrotate.d/rsyslog.j2 new file mode 100644 index 0000000..6ae2f58 --- /dev/null +++ b/roles/base/templates/etc/logrotate.d/rsyslog.j2 @@ -0,0 +1,23 @@ +# Logrotate configuration for standard log files +# {{ ansible_managed }} + +/var/log/kern.log +/var/log/daemon.log +/var/log/haproxy.log +/var/log/auth.log +/var/log/cron.log +/var/log/mail.log +/var/log/boot.log +/var/log/system.log +{ + rotate {{ logrotate_keepcount }} + {{ logrotate_interval }} + missingok + notifempty + compress + delaycompress + sharedscripts + postrotate + /usr/lib/rsyslog/rsyslog-rotate &>/dev/null + endscript +} diff --git a/roles/base/templates/etc/ntp.conf.j2 b/roles/base/templates/etc/ntp.conf.j2 new file mode 100644 index 0000000..747031b --- /dev/null +++ b/roles/base/templates/etc/ntp.conf.j2 @@ -0,0 +1,27 @@ +# Main NTP configuration +# {{ ansible_managed }} + +driftfile /var/lib/ntp/ntp.drift + +statistics loopstats peerstats clockstats + +filegen loopstats file loopstats type day enable +filegen peerstats file peerstats type day enable +filegen clockstats file clockstats type day enable + +{% if 'remote' in group_names or 'remote-jellyfin' in group_names %} +server time.nrc.ca +server time.chu.nrc.ca + +restrict -4 default kod notrap nomodify nopeer +restrict -6 default kod notrap nomodify nopeer +{% else %} +disable auth +multicastclient 224.0.0.1 +multicastclient ff05::101 + +restrict -4 default notrap nomodify +restrict -6 default notrap nomodify +{% endif %} +restrict 127.0.0.1 +restrict ::1 diff --git a/roles/base/templates/etc/pam.d/sshd.j2 b/roles/base/templates/etc/pam.d/sshd.j2 new file mode 100644 index 0000000..46d0f3c --- /dev/null +++ b/roles/base/templates/etc/pam.d/sshd.j2 @@ -0,0 +1,54 @@ +# PAM configuration for the Secure Shell service +# {{ ansible_managed }} + +# Standard Un*x authentication. +@include common-auth + +# Disallow non-root logins when /etc/nologin exists. +account required pam_nologin.so + +# Uncomment and edit /etc/security/access.conf if you need to set complex +# access limits that are hard to express in sshd_config. +# account required pam_access.so + +# Standard Un*x authorization. +@include common-account + +# SELinux needs to be the first session rule. This ensures that any +# lingering context has been cleared. Without this it is possible that a +# module could execute code in the wrong domain. +session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close + +# Set the loginuid process attribute. +session required pam_loginuid.so + +# Create a new session keyring. +session optional pam_keyinit.so force revoke + +# Standard Un*x session setup and teardown. +@include common-session + +# Print the message of the day upon successful login. +session optional pam_motd.so motd=/run/pvc-motd.dynamic +session optional pam_motd.so noupdate + +# Print the status of the user's mailbox upon successful login. +#session optional pam_mail.so standard noenv # [1] + +# Set up user limits from /etc/security/limits.conf. +session required pam_limits.so + +# Read environment variables from /etc/environment and +# /etc/security/pam_env.conf. +session required pam_env.so # [1] +# In Debian 4.0 (etch), locale-related environment variables were moved to +# /etc/default/locale, so read that as well. +session required pam_env.so user_readenv=1 envfile=/etc/default/locale + +# SELinux needs to intervene at login time to ensure that the process starts +# in the proper default security context. Only sessions which are intended +# to run in the user's context should be run after this. +session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so open + +# Standard Un*x password updating. +@include common-password diff --git a/roles/base/templates/etc/postfix/main.cf.j2 b/roles/base/templates/etc/postfix/main.cf.j2 new file mode 100644 index 0000000..24db7c0 --- /dev/null +++ b/roles/base/templates/etc/postfix/main.cf.j2 @@ -0,0 +1,17 @@ +# Postfix main configuration for non-MTA hosts +# {{ ansible_managed }} + +smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU) +biff = no +append_dot_mydomain = no +readme_directory = no +smtpd_use_tls=no + +alias_maps = hash:/etc/postfix/aliases +alias_database = hash:/etc/postfix/aliases +mydestination = +mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 +mailbox_size_limit = 0 +recipient_delimiter = + +inet_interfaces = 127.0.0.1 +inet_protocols = ipv4 diff --git a/roles/base/templates/etc/profile.d/w.sh.j2 b/roles/base/templates/etc/profile.d/w.sh.j2 new file mode 100644 index 0000000..1c0aafb --- /dev/null +++ b/roles/base/templates/etc/profile.d/w.sh.j2 @@ -0,0 +1,7 @@ +#!/bin/sh + +# Message of the day script to print active users +# {{ ansible_managed }} + +export PROCPS_FROMLEN=36 PROCPS_USERLEN=12 +w diff --git a/roles/base/templates/etc/resolv.conf.j2 b/roles/base/templates/etc/resolv.conf.j2 new file mode 100644 index 0000000..6744c90 --- /dev/null +++ b/roles/base/templates/etc/resolv.conf.j2 @@ -0,0 +1,5 @@ +# DNS resolver configuration +# {{ ansible_managed }} + +options timeout:1 attempts:3 rotate +nameserver 1.1.1.1 diff --git a/roles/base/templates/etc/rsyslog.conf.j2 b/roles/base/templates/etc/rsyslog.conf.j2 new file mode 100644 index 0000000..669b9bb --- /dev/null +++ b/roles/base/templates/etc/rsyslog.conf.j2 @@ -0,0 +1,37 @@ +# Main rsyslog configuration +# {{ ansible_managed }} + +#### #### +#### MODULES #### +#### #### + +module(load="imuxsock") # provides support for local system logging (e.g. via logger command) +module(load="imklog") # provides kernel logging support (previously done by rklogd) + +$ModLoad imudp +$UDPServerAddress ::1 +$UDPServerRun 514 + +#### #### +#### GLOBAL DIRECTIVES #### +#### #### + +$PreserveFQDN on +$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat + +#### #### +#### RULES #### +#### #### + +ruleset(name="local") { + kern.* /var/log/kern.log + auth,authpriv.* /var/log/auth.log + cron.* /var/log/cron.log + daemon,user.* /var/log/daemon.log + mail.* /var/log/mail.log + local5.* /var/log/nginx.log + local6.* /var/log/haproxy.log + local7.* /var/log/boot.log + *.info;kern,daemon,user,auth,authpriv,cron,mail,local6.none,local7.none /var/log/system.log +} +$DefaultRuleset local diff --git a/roles/base/templates/etc/ssh/shosts.equiv.j2 b/roles/base/templates/etc/ssh/shosts.equiv.j2 new file mode 100644 index 0000000..5bb3663 --- /dev/null +++ b/roles/base/templates/etc/ssh/shosts.equiv.j2 @@ -0,0 +1,3 @@ +# SSH remote allowed hosts +# {{ ansible_managed }} + diff --git a/roles/base/templates/etc/ssh/ssh_config.j2 b/roles/base/templates/etc/ssh/ssh_config.j2 new file mode 100644 index 0000000..b8f5230 --- /dev/null +++ b/roles/base/templates/etc/ssh/ssh_config.j2 @@ -0,0 +1,43 @@ +# Default SSH client configuration +# {{ ansible_managed }} + +Host * +# ForwardAgent no +# ForwardX11 no +# ForwardX11Trusted yes +# RhostsRSAAuthentication no +# RSAAuthentication yes +# PasswordAuthentication yes +# EnableSSHKeysign yes +# HostbasedAuthentication yes +# GSSAPIAuthentication no +# GSSAPIDelegateCredentials no +# GSSAPIKeyExchange no +# GSSAPITrustDNS no +# BatchMode no +# CheckHostIP yes +# AddressFamily any +# ConnectTimeout 0 +# StrictHostKeyChecking ask +# IdentityFile ~/.ssh/identity +# IdentityFile ~/.ssh/id_rsa +# IdentityFile ~/.ssh/id_dsa +# Port 22 +# Protocol 2,1 +# Cipher 3des +# Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc +# MACs hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160 +# EscapeChar ~ +# Tunnel no +# TunnelDevice any:any +# PermitLocalCommand no +# VisualHostKey no +# ProxyCommand ssh -q -W %h:%p gateway.example.com +# PreferredAuthentications hostbased,pubkey + SendEnv LANG LC_* + HashKnownHosts yes + GSSAPIAuthentication yes + GSSAPIDelegateCredentials no + PubkeyAuthentication yes + HostbasedAuthentication yes + EnableSSHKeysign yes diff --git a/roles/base/templates/etc/ssh/ssh_known_hosts.j2 b/roles/base/templates/etc/ssh/ssh_known_hosts.j2 new file mode 100644 index 0000000..5bb3663 --- /dev/null +++ b/roles/base/templates/etc/ssh/ssh_known_hosts.j2 @@ -0,0 +1,3 @@ +# SSH remote allowed hosts +# {{ ansible_managed }} + diff --git a/roles/base/templates/etc/ssh/sshd_config.j2 b/roles/base/templates/etc/ssh/sshd_config.j2 new file mode 100644 index 0000000..9f95029 --- /dev/null +++ b/roles/base/templates/etc/ssh/sshd_config.j2 @@ -0,0 +1,43 @@ +# Main SSH daemon configuraton +# {{ ansible_managed }} + +Port 22 +ListenAddress :: +ListenAddress 0.0.0.0 +Protocol 2 +HostKey /etc/ssh/ssh_host_ed25519_key +UsePrivilegeSeparation yes +SyslogFacility AUTH +LogLevel INFO +LoginGraceTime 120 +UsePAM yes +StrictModes yes +X11Forwarding no +PrintMotd no +PrintLastLog yes +TCPKeepAlive yes +AcceptEnv LANG LC_* + +MACs hmac-sha2-512,hmac-sha2-256 +Ciphers aes256-ctr,aes192-ctr,aes128-ctr + +KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256 +Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr +MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com + +PubkeyAuthentication yes +PermitEmptyPasswords no +ChallengeResponseAuthentication no +PasswordAuthentication no +{% if 'hv' in group_names %} +HostbasedAuthentication yes +HostbasedUsesNameFromPacketOnly yes +IgnoreRhosts no +PermitRootLogin yes +{% else %} +HostbasedAuthentication no +IgnoreRhosts yes +PermitRootLogin no +{% endif %} + +Subsystem sftp /usr/lib/openssh/sftp-server -f AUTH -l INFO diff --git a/roles/base/templates/etc/sudoers.d/sudoers-backup.j2 b/roles/base/templates/etc/sudoers.d/sudoers-backup.j2 new file mode 100644 index 0000000..e54e7a2 --- /dev/null +++ b/roles/base/templates/etc/sudoers.d/sudoers-backup.j2 @@ -0,0 +1,5 @@ +# sudoers configuraton for BackupPC +# {{ ansible_managed }} + +Cmnd_Alias BACKUPS = /usr/bin/rsync, /var/backups/timestamp.sh +backup ALL=(root) NOPASSWD: BACKUPS diff --git a/roles/base/templates/etc/sudoers.j2 b/roles/base/templates/etc/sudoers.j2 new file mode 100644 index 0000000..76db387 --- /dev/null +++ b/roles/base/templates/etc/sudoers.j2 @@ -0,0 +1,12 @@ +# sudoers configuraton; per-host declarations go in /etc/sudoers.d +# {{ ansible_managed }} + +Defaults env_reset +Defaults mail_badpass +Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + +root ALL=(ALL:ALL) NOPASSWD: ALL +deploy ALL=(ALL:ALL) NOPASSWD: /bin/sh +%sudo ALL=(ALL:ALL) NOPASSWD: ALL + +#includedir /etc/sudoers.d diff --git a/roles/base/templates/etc/sysctl.d/pvc.conf.j2 b/roles/base/templates/etc/sysctl.d/pvc.conf.j2 new file mode 100644 index 0000000..8ac3f64 --- /dev/null +++ b/roles/base/templates/etc/sysctl.d/pvc.conf.j2 @@ -0,0 +1,47 @@ +# General sysctl parameters for BLSE2 +# {{ ansible_managed }} + +# Reduce swappiness +vm.swappiness = 1 + +# enable Spoof protection (reverse-path filter) +# Turn on Source Address Verification in all interfaces to +# prevent some spoofing attacks +net.ipv4.conf.default.rp_filter = 1 +net.ipv4.conf.all.rp_filter = 1 + +# Ignore ICMP broadcasts +net.ipv4.icmp_echo_ignore_broadcasts = 1 + +# Ignore bogus ICMP errors +net.ipv4.icmp_ignore_bogus_error_responses = 1 + +# Do not accept ICMP redirects (prevent MITM attacks) +net.ipv4.conf.all.accept_redirects = 0 +{% if not 'rpi' in group_names %} +net.ipv6.conf.all.accept_redirects = 0 +{% endif %} + +# Do not send ICMP redirects (we are not a router) +net.ipv4.conf.all.send_redirects = 0 + +# Do not accept IP source route packets (we are not a router) +net.ipv4.conf.all.accept_source_route = 0 +{% if not 'rpi' in group_names %} +net.ipv6.conf.all.accept_source_route = 0 +{% endif %} + +# Don't log Martian Packets +net.ipv4.conf.all.log_martians = 0 + +# Explicit Congestion Notification (ECN) +net.ipv4.tcp_ecn = 1 + +# number of seconds the kernel waits before rebooting on a panic +kernel.panic = 60 + +# Panic on an OOPS +kernel.panic_on_oops = 1 + +# Restrict dmesg +kernel.dmesg_restrict = 1 diff --git a/roles/base/templates/etc/systemd/journald.conf.j2 b/roles/base/templates/etc/systemd/journald.conf.j2 new file mode 100644 index 0000000..03f2d6a --- /dev/null +++ b/roles/base/templates/etc/systemd/journald.conf.j2 @@ -0,0 +1,4 @@ +# Journald configuration +# {{ ansible_managed }} +[Journal] +Storage=persistent diff --git a/roles/base/templates/etc/systemd/system/check_mk.socket b/roles/base/templates/etc/systemd/system/check_mk.socket new file mode 100644 index 0000000..0e15ba4 --- /dev/null +++ b/roles/base/templates/etc/systemd/system/check_mk.socket @@ -0,0 +1,10 @@ +# systemd socket definition file +[Unit] +Description=Check_MK Agent Socket + +[Socket] +ListenStream=6556 +Accept=true + +[Install] +WantedBy=sockets.target diff --git a/roles/base/templates/etc/systemd/system/check_mk@.service b/roles/base/templates/etc/systemd/system/check_mk@.service new file mode 100644 index 0000000..a721813 --- /dev/null +++ b/roles/base/templates/etc/systemd/system/check_mk@.service @@ -0,0 +1,12 @@ +# systemd service definition file +[Unit] +Description=Check_MK + +[Service] +ExecStart=/usr/bin/check_mk_agent +KillMode=process + +User=root +Group=root + +StandardInput=socket diff --git a/roles/base/templates/root/vimrc.j2 b/roles/base/templates/root/vimrc.j2 new file mode 100644 index 0000000..cd5a9d8 --- /dev/null +++ b/roles/base/templates/root/vimrc.j2 @@ -0,0 +1,5 @@ +set showcmd +set number +set cursorline +syntax on +set mouse= diff --git a/roles/base/templates/usr/local/sbin/dpkg-cleanup.sh.j2 b/roles/base/templates/usr/local/sbin/dpkg-cleanup.sh.j2 new file mode 100755 index 0000000..705b7cd --- /dev/null +++ b/roles/base/templates/usr/local/sbin/dpkg-cleanup.sh.j2 @@ -0,0 +1,18 @@ +#!/bin/bash + +# dpkg-cleanup.sh - Remove obsolete packages and config files +# {{ ansible_managed }} + +# Phase 1 - purge `rc` packages +PACKAGE_LIST=( $( dpkg --list | awk '/^rc/{ print $2 } /^ri/{ print $2 }' ) ) +apt purge -y ${PACKAGE_LIST[@]} + +# Phase 2 - autoremove packages +apt autoremove --purge -y + +# Phase 3 - clean archives +apt clean + +# Phase 4 - find and remove obsolete config files +OLD_FILES_LIST=( $( find /etc -type f -a \( -name '*.dpkg-*' -o -name '*.ucf-*' \) 2>/dev/null ) ) +rm -f ${OLD_FILES_LIST[@]} diff --git a/roles/base/templates/usr/local/sbin/loghost-archive.sh.j2 b/roles/base/templates/usr/local/sbin/loghost-archive.sh.j2 new file mode 100755 index 0000000..f3888d9 --- /dev/null +++ b/roles/base/templates/usr/local/sbin/loghost-archive.sh.j2 @@ -0,0 +1,23 @@ +#!/bin/bash + +# Archive old logs on loghost +# {{ ansible_managed }} + +LOGPATH=/srv/log +ARCHIVEPATH=${LOGPATH}/archive/ +test -d $ARCHIVEPATH || mkdir -p $ARCHIVEPATH +for LOGFILE in \ + kern.log \ + daemon.log \ + haproxy.log \ + auth.log \ + cron.log \ + mail.log \ + boot.log \ + system.log +do + test -d ${ARCHIVEPATH}/${LOGFILE} || mkdir -p ${ARCHIVEPATH}/${LOGFILE} + mv ${LOGPATH}/${LOGFILE}-* ${ARCHIVEPATH}/${LOGFILE} + gzip ${ARCHIVEPATH}/${LOGFILE}/* + find ${ARCHIVEPATH}/${LOGFILE} -type f -ctime +90 -exec rm {} \; +done diff --git a/roles/base/templates/usr/local/sbin/update-motd.sh.j2 b/roles/base/templates/usr/local/sbin/update-motd.sh.j2 new file mode 100755 index 0000000..1261237 --- /dev/null +++ b/roles/base/templates/usr/local/sbin/update-motd.sh.j2 @@ -0,0 +1,26 @@ +#!/bin/sh + +# Update dynamic MOTD file +# {{ ansible_managed }} + +set -o errexit + +TMPFILE=$(mktemp) +TGTFILE=/run/pvc-motd.dynamic +DEBVER="({{ ansible_lsb.description }})" + +echo >> $TMPFILE +echo "\033[01;34mParallel Virtual Cluster \033[01;36m${DEBVER}\033[0m" >> $TMPFILE +echo -n "> \033[01;32m$(hostname)\033[0m" >> $TMPFILE +if test -f /etc/hostdesc; then + echo " - $( cat /etc/hostdesc )" >> $TMPFILE +else + echo >> $TMPFILE +fi +# Get machine information +echo "> \033[1;37mPVC node\033[0m on \033[1;31m$( + /usr/sbin/dmidecode | grep -A1 'Chassis Information' | tail -1 | awk -F':' '{print $2}' | tr -s ' ' + )\033[0m hardware" >> $TMPFILE +echo "> $(/bin/uname -srvmo)" >> $TMPFILE + +mv $TMPFILE $TGTFILE || rm $TMPFILE diff --git a/roles/base/templates/var/backups/ssh/authorized_keys.j2 b/roles/base/templates/var/backups/ssh/authorized_keys.j2 new file mode 100644 index 0000000..80c426f --- /dev/null +++ b/roles/base/templates/var/backups/ssh/authorized_keys.j2 @@ -0,0 +1,4 @@ +# backup user authorized_keys +# {{ ansible_managed }} + +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCnndMxkLF+Trm7Zpo59daJbH6C6SbInl8f1PAizxtUkWg8skP5EXkUc0eguos+5o6BG1VL0c8SWBnl4smvZL075l2wC3+cJeDUIyxC6aue6vualFMPj5p0h4gJWrX+L5r1b1hxnR3r5Mqx7/2W9K35/u3M6TPnRXn0XjGN93j8dsywfDOuU4xH+w0INM4iNeEne4l2SEAVA0Sm7nGNss4X18iwjnxyKgqUB+HtG2WHyEPr/Uv5OiEC+4n4LvkMRMpupx33U5ZH7pgyfFKJJsIObBf4nC4xUUZyCG2FlHiWzX0Ua9xxwz9OJIeqlwfYsLFrHEbPS5KpAXukEjshKGY1 backuppc@base.bonilan.net diff --git a/roles/base/templates/var/backups/timestamp.sh.j2 b/roles/base/templates/var/backups/timestamp.sh.j2 new file mode 100755 index 0000000..48b4ff4 --- /dev/null +++ b/roles/base/templates/var/backups/timestamp.sh.j2 @@ -0,0 +1,11 @@ +#!/bin/bash + +# Writes timestamps on successful BackupPC completion and updates dynamic share inventory for this host +# {{ ansible_managed }} + +OK="$1" +SHARE="$2" +grep -F "${SHARE}" /var/backups/shares || echo "${SHARE}" >> /var/backups/shares +if [[ ${OK} -eq 1 ]]; then + /bin/date +%s > ${SHARE}/.backup +fi diff --git a/roles/base/templates/var/home/user/bash_logout.j2 b/roles/base/templates/var/home/user/bash_logout.j2 new file mode 100755 index 0000000..0859925 --- /dev/null +++ b/roles/base/templates/var/home/user/bash_logout.j2 @@ -0,0 +1,7 @@ +# BLSE 2.0 bash_logout file +# {{ ansible_managed }} + +# when leaving the console clear the screen to increase privacy +if [ "$SHLVL" = 1 ]; then + [ -x /usr/bin/clear_console ] && /usr/bin/clear_console -q +fi diff --git a/roles/base/templates/var/home/user/bashrc.j2 b/roles/base/templates/var/home/user/bashrc.j2 new file mode 100755 index 0000000..2488ad0 --- /dev/null +++ b/roles/base/templates/var/home/user/bashrc.j2 @@ -0,0 +1,144 @@ +#!/bin/bash + +# BLSE 2.0 bashrc file +# {{ ansible_managed }} + +# +# GENERAL SETTINGS +# + +# Before anything, see if we're running interactively. If not, skip everything here. +[[ $- == *i* ]] || return + +# Ensure bash completion is enabled if installed +if ! shopt -oq posix; then + if [ -f /usr/share/bash-completion/bash_completion ]; then + . /usr/share/bash-completion/bash_completion + elif [ -f /etc/bash_completion ]; then + . /etc/bash_completion + fi +fi + +# Some other tweaks +[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" +if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then + debian_chroot=$(cat /etc/debian_chroot) +fi + +# Set history limits and values +shopt -s cdspell +shopt -s dirspell +shopt -s dotglob +shopt -s histreedit +shopt -s histverify +shopt -s histappend +PROMPT_COMMAND="history -a;$PROMPT_COMMAND" +HISTCONTROL=ignoreboth +HISTSIZE=25000 +HISTFILESIZE=25000 + +# +# BASH SETTINGS +# + +# Set a shiny Linux Mint-style PS1 with spaces for easy double-click-select +git_branch() { + git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/git:\1 /' +} +export PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\[\033[01;32m\]\H\[\033[01;34m\] \[\e[35m\]$(git_branch)\[\033[01;34m\]\w \$\[\033[00m\] ' + +# Sensible PATH (find things in *sbin* as non-root user) +export PATH="/usr/lib/check_mk_agent/plugins:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games" + +# Set PATH to include ~/Scripts if it exists +if [ -d ~/Scripts ]; then + export PATH=~/Scripts:$PATH +fi + +# Set editor to vim +export EDITOR=/usr/bin/vim + +# Force SCREEN to xterm due to Debian weirdness +export SCREEN="xterm" + + +# +# ALIASES +# + +# Coloured command aliases +alias ls='ls --color=always' +alias dir='dir --color=always' +alias vdir='vdir --color=always' +alias grep='grep --color=always' +alias fgrep='fgrep --color=always' +alias egrep='egrep --color=always' +alias xzgrep='xzgrep --color=always' +alias less='less -r' + +# Convenient ls aliases +alias ll='ls -alh' +alias la='ls -A' +alias l='ls -lh' + +# Always-sudo commands, because fuck typing sudo all the time +alias service='sudo service' +alias systemctl='sudo systemctl' +alias journalctl='sudo journalctl' +alias dmesg='sudo dmesg' +alias apt='sudo apt' +alias dpkg='sudo dpkg' +alias find='sudo find' +alias htop='sudo htop' +alias powertop='sudo powertop' +alias jnettop='sudo jnettop' +alias wavemon='sudo wavemon' +alias parted='sudo parted' +alias fdisk='sudo fdisk' +alias gdisk='sudo gdisk' +alias chroot='sudo chroot' +alias mount='sudo mount' +alias umount='sudo umount' +alias virsh='sudo virsh -c qemu:///system' +alias ceph='sudo ceph' +alias rbd='sudo rbd' +alias mysql='sudo mysql' +alias zpool='sudo zpool' +alias zfs='sudo zfs' +alias crm='sudo crm' + +# Cool aliases +alias cccp='sudo rsync -auv --progress' +alias untmp='sudo umount /tmp/tmp.*{/*/*,/*,} 2>/dev/null' +alias txz='tar -p --same-owner -I pxz' +alias stxz='sudo tar -p --same-owner -I pxz' +alias zkcli='sudo /usr/share/zookeeper/bin/zkCli.sh' +alias hatop='sudo hatop -s /var/lib/haproxy/admin.sock' +alias patronictl='sudo patronictl -c /etc/patroni/config.yml -d zookeeper://localhost:2181' +alias repo='sudo reprepro -b /srv/debrepo' +alias beet='sudo -u debian-deluged beet --config=/srv/deluged/config.beets/config.yaml' +{% if 'mon' in group_names %} +alias icli='sudo -u monitor icli --status-file /omd/sites/monitor/tmp/nagios/status.dat --config /omd/sites/monitor/var/nagios/objects.cache -z \!o' + +# +# Show monitoring stats +# + +icli +{% endif %} + +# +# SOURCE OTHER SCRIPTS +# + +test -f ~/.bashrc.d/* && . ~/.bashrc.d/* + +# +# NICE AND CLEAN +# + +echo + +# +# END OF FILE +# diff --git a/roles/base/templates/var/home/user/config/htop/htoprc.j2 b/roles/base/templates/var/home/user/config/htop/htoprc.j2 new file mode 100644 index 0000000..f0311f0 --- /dev/null +++ b/roles/base/templates/var/home/user/config/htop/htoprc.j2 @@ -0,0 +1,25 @@ +# htop config file +# {{ ansible_managed }} +fields=0 48 17 18 38 39 40 2 46 47 49 1 +sort_key=46 +sort_direction=1 +hide_threads=0 +hide_kernel_threads=0 +hide_userland_threads=0 +shadow_other_users=0 +show_thread_names=1 +highlight_base_name=1 +highlight_megabytes=1 +highlight_threads=1 +tree_view=0 +header_margin=1 +detailed_cpu_time=1 +cpu_count_from_zero=0 +update_process_names=1 +account_guest_in_cpu_meter=1 +color_scheme=0 +delay=15 +left_meters=LeftCPUs2 Blank CPU Blank Blank Memory Swap +left_meter_modes=1 2 1 2 2 1 1 +right_meters=RightCPUs2 Blank LoadAverage Tasks Blank Hostname Clock Uptime Blank +right_meter_modes=1 2 2 2 2 2 2 2 2 diff --git a/roles/base/templates/var/home/user/profile.j2 b/roles/base/templates/var/home/user/profile.j2 new file mode 100644 index 0000000..41bbb9a --- /dev/null +++ b/roles/base/templates/var/home/user/profile.j2 @@ -0,0 +1,16 @@ +# {{ ansible_managed }} + +EDITOR=/usr/bin/vim + +# if running bash +if [ -n "$BASH_VERSION" ]; then + # include .bashrc if it exists + if [ -f "$HOME/.bashrc" ]; then + . "$HOME/.bashrc" + fi +fi + +# set PATH so it includes user's private bin if it exists +if [ -d "$HOME/bin" ] ; then + PATH="$HOME/bin:$PATH" +fi diff --git a/roles/base/templates/var/home/user/vimrc.j2 b/roles/base/templates/var/home/user/vimrc.j2 new file mode 100644 index 0000000..cdd8303 --- /dev/null +++ b/roles/base/templates/var/home/user/vimrc.j2 @@ -0,0 +1,13 @@ +set showcmd +set number +set cursorline +set autoindent +set expandtab +set tabstop=4 +set viminfo='100,<1000,s1000,h +hi CursorLine term=bold cterm=bold guibg=Grey40 +syntax on +set ruler +set directory=~/.vim +set mouse= +autocmd Filetype gitcommit setlocal spell textwidth=72 diff --git a/roles/pvc/README.md b/roles/pvc/README.md new file mode 100644 index 0000000..ec601d3 --- /dev/null +++ b/roles/pvc/README.md @@ -0,0 +1,13 @@ +# package-pvc + +This package configures the PVC virtual cluster system. + +# Supplemental variables + +## Configurable + +### `ceph_storage_secret_key`: The Ceph storage secret key in base64 format. +* Should be obtained from Ceph cluster. + +### `ceph_storage_secret_uuid`: A UUID for the Ceph secret in libvirt. +* Should be unique per cluster. diff --git a/roles/pvc/defaults/main.yml b/roles/pvc/defaults/main.yml new file mode 100644 index 0000000..0c0dc59 --- /dev/null +++ b/roles/pvc/defaults/main.yml @@ -0,0 +1,57 @@ +--- +# Ceph storage +ceph_storage_secret_key: "" +ceph_storage_secret_uuid: "" +# Database +pvc_dns_database_name: "pvcdns" +pvc_dns_database_user: "pvcdns" +pvc_dns_database_password: "PVCdnsPassw0rd" +# Coordinators +pvc_nodes: + - hostname: "pvc1" + is_coordinator: yes + node_id: 1 + router_id: "10.0.0.1" + cluster_ip: "by-id" + storage_ip: "by-id" + upstream_ip: "" + ipmi_host: "pvc1-lom" + ipmi_user: "" + ipmi_password: "" + - hostname: "pvc2" + is_coordinator: yes + node_id: 2 + router_id: "10.0.0.2" + cluster_ip: "by-id" + storage_ip: "by-id" + upstream_ip: "" + ipmi_host: "pvc2-lom" + ipmi_user: "" + ipmi_password: "" + - hostname: "pvc3" + is_coordinator: yes + node_id: 3 + router_id: "10.0.0.3" + cluster_ip: "by-id" + storage_ip: "by-id" + upstream_ip: "" + ipmi_host: "pvc3-lom" + ipmi_user: "" + ipmi_password: "" +# Networks +pvc_asn: "65001" +pvc_routers: + - "" +pvc_cluster_device: "eth0" +pvc_cluster_domain: "pvc.local" +pvc_cluster_subnet: "10.0.0.0/24" +pvc_cluster_floatingip: "10.0.0.251/24" +pvc_storage_device: "eth1" +pvc_storage_domain: "pvc.storage" +pvc_storage_subnet: "10.0.1.0/24" +pvc_storage_floatingip: "10.0.1.251/24" +pvc_upstream_device: "eth2" +pvc_upstream_domain: "" +pvc_upstream_subnet: "" +pvc_upstream_floatingip: "" +pvc_upstream_gatewayip: "" diff --git a/roles/pvc/files/mariadb/mk_mysql.agents b/roles/pvc/files/mariadb/mk_mysql.agents new file mode 100755 index 0000000..569bb19 --- /dev/null +++ b/roles/pvc/files/mariadb/mk_mysql.agents @@ -0,0 +1,90 @@ +#!/bin/bash +# +------------------------------------------------------------------+ +# | ____ _ _ __ __ _ __ | +# | / ___| |__ ___ ___| | __ | \/ | |/ / | +# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / | +# | | |___| | | | __/ (__| < | | | | . \ | +# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ | +# | | +# | Copyright Mathias Kettner 2014 mk@mathias-kettner.de | +# +------------------------------------------------------------------+ +# +# This file is part of Check_MK. +# The official homepage is at http://mathias-kettner.de/check_mk. +# +# check_mk is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation in version 2. check_mk is distributed +# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with- +# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU General Public License for more de- +# tails. You should have received a copy of the GNU General Public +# License along with GNU Make; see the file COPYING. If not, write +# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301 USA. + +# gets optional socket as argument +function do_query() { + INSTANCE=$(echo $1|awk -v FS="=" '{print $2}') + COUNT=$(ps -efww | grep [/]usr/sbin/mysqld | grep socket | wc -l) + if [ $COUNT -gt 1 ] + then + INSTANCE_NAME=$(ps -efww|grep socket|grep "${INSTANCE}"|grep "[u]ser" | sed -ne 's/.*socket=\([^.]*\).*/\1/p') + INSTANCE_NAME="[[${INSTANCE_NAME##*/}]]" + else + INSTANCE_NAME="[[$(ps -efww|grep socket|grep "${INSTANCE}"|grep "[u]ser" | sed -ne 's/.*user=\([^ ]*\).*/\1/p')]]" + fi + + + + # Check if mysqld is running and root password setup + echo "<<>>" + echo $INSTANCE_NAME + mysqladmin --defaults-extra-file=/root/.my.cnf $1 ping 2>&1 + + if [ $? -eq 0 ]; then + + echo "<<>>" + echo $INSTANCE_NAME + mysql --defaults-extra-file=/root/.my.cnf $1 -sN \ + -e "show global status ; show global variables ;" + + echo "<<>>" + echo $INSTANCE_NAME + mysql --defaults-extra-file=/root/.my.cnf $1 -sN \ + -e "SELECT table_schema, sum(data_length + index_length), sum(data_free) + FROM information_schema.TABLES GROUP BY table_schema" + + echo "<<>>" + echo $INSTANCE_NAME + mysql --defaults-extra-file=/root/.my.cnf $1 -s \ + -e "show slave status\G" + + fi + +} + +if which mysqladmin >/dev/null +then + mysql_sockets=$(fgrep socket /root/.my.cnf|sed -ne 's/.*socket=\([^ ]*\).*/\1/p') + if [ -z "$mysql_sockets" ] ; then + mysql_sockets=$(ps -efww | grep mysqld | grep "[s]ocket" | sed -ne 's/.*socket=\([^ ]*\).*/\1/p') + fi + if [ -z "$mysql_sockets" ] ; then + do_query "" + else + for socket in $mysql_sockets ; do + do_query "--socket="$socket + done + fi + #echo "<<>>" + #mysql -V + + echo "<<>>" + ps -efww|grep mysqld|while read LINE; do echo $LINE|grep "[u]ser" | sed -ne 's/.*user=\([^ ]*\).*/\1/p'; echo $LINE|grep mysqld | grep "[p]ort"|sed -ne 's/.*port=\([^ ]*\).*/\1/p' ; done|xargs -n2 + + #echo "<<>>" + #mysql --defaults-extra-file=/root/.my.cnf $1 -s \ + # -e "show INSTANCES" + +fi diff --git a/roles/pvc/files/patroni/postgres b/roles/pvc/files/patroni/postgres new file mode 100755 index 0000000..5aad043 --- /dev/null +++ b/roles/pvc/files/patroni/postgres @@ -0,0 +1,485 @@ +#!/bin/bash +# +------------------------------------------------------------------+ +# | ____ _ _ __ __ _ __ | +# | / ___| |__ ___ ___| | __ | \/ | |/ / | +# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / | +# | | |___| | | | __/ (__| < | | | | . \ | +# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ | +# | | +# | Copyright Mathias Kettner 2015 mk@mathias-kettner.de | +# +------------------------------------------------------------------+ +# +# This file is part of Check_MK. +# The official homepage is at http://mathias-kettner.de/check_mk. +# +# check_mk is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation in version 2. check_mk is distributed +# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with- +# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU General Public License for more de- +# tails. You should have received a copy of the GNU General Public +# License along with GNU Make; see the file COPYING. If not, write +# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301 USA. + + +# TODO postgres_connections output format + + +# .--common funcs--------------------------------------------------------. +# | __ | +# | ___ ___ _ __ ___ _ __ ___ ___ _ __ / _|_ _ _ __ ___ ___ | +# | / __/ _ \| '_ ` _ \| '_ ` _ \ / _ \| '_ \ | |_| | | | '_ \ / __/ __| | +# || (_| (_) | | | | | | | | | | | (_) | | | || _| |_| | | | | (__\__ \ | +# | \___\___/|_| |_| |_|_| |_| |_|\___/|_| |_||_| \__,_|_| |_|\___|___/ | +# | | +# '----------------------------------------------------------------------' + + +function compare_version_greater_equal() { + local GREATER_ONE + GREATER_ONE=$(echo "$1 $2" | awk '{if ($1 >= $2) print $1; else print $2}') + if [ "$GREATER_ONE" == "$1" ] ; then + return 0 + else + return 1 + fi +} + + +#. +# .--section funcs-------------------------------------------------------. +# | _ _ __ | +# | ___ ___ ___| |_(_) ___ _ __ / _|_ _ _ __ ___ ___ | +# | / __|/ _ \/ __| __| |/ _ \| '_ \ | |_| | | | '_ \ / __/ __| | +# | \__ \ __/ (__| |_| | (_) | | | | | _| |_| | | | | (__\__ \ | +# | |___/\___|\___|\__|_|\___/|_| |_| |_| \__,_|_| |_|\___|___/ | +# | | +# '----------------------------------------------------------------------' + + +function postgres_instances() { + echo '<<>>' + # If we have no instances we take db id (pqsql/postgres) because + # ps output may be unreadable + # In case of instances ps output shows them readable + if [ ! -z "${1}" ]; then + echo "[[[${1}]]]" + fi + pgrep -laf bin/postgres +} + + +function postgres_sessions() { + # Postgres 9.2 uses 'query' instead of 'current_query' + local OUTPUT + OUTPUT="$(echo "\echo '<<>>${INSTANCE_SECTION}' + SELECT ( + SELECT column_name + FROM information_schema.columns + WHERE table_name='pg_stat_activity' AND column_name in ('query', 'current_query') + ) = '' as query, count(*) + FROM pg_stat_activity + GROUP BY (query = '');" |\ + sudo -u "$DBUSER" $export_PGPASSFILE $psql -X --variable ON_ERROR_STOP=1 -d $PGDATABASE ${EXTRA_ARGS} -A -t -F' ' 2>/dev/null)" + + echo "$OUTPUT" + # line with number of idle sessions is sometimes missing on Postgres 8.x. This can lead + # to an altogether empty section and thus the check disappearing. + echo "$OUTPUT" | grep -q '^t ' || echo "t 0" +} + + +function postgres_simple_queries() { + # Querytime + # Supports versions >= 8.3, > 9.1 + local QUERYTIME_QUERY + if compare_version_greater_equal "$POSTGRES_VERSION" "9.2" ; then + QUERYTIME_QUERY="SELECT datname, datid, usename, client_addr, state AS state, COALESCE(ROUND(EXTRACT(epoch FROM now()-query_start)),0) AS seconds, + pid, regexp_replace(query, E'[\\n\\r\\u2028]+', ' ', 'g' ) AS current_query FROM pg_stat_activity WHERE (query_start IS NOT NULL AND (state NOT LIKE 'idle%' OR state IS NULL)) ORDER BY query_start, pid DESC;" + else + QUERYTIME_QUERY="SELECT datname, datid, usename, client_addr, '' AS state, COALESCE(ROUND(EXTRACT(epoch FROM now()-query_start)),0) AS seconds, + procpid as pid, regexp_replace(current_query, E'[\\n\\r\\u2028]+', ' ', 'g' ) AS current_query FROM pg_stat_activity WHERE (query_start IS NOT NULL AND current_query NOT LIKE '%') ORDER BY query_start, procpid DESC;" + fi + + # Number of current connections per database + # We need to output the databases, too. + # This query does not report databases without an active query + local CONNECTIONS_QUERY + if compare_version_greater_equal "$POSTGRES_VERSION" "9.2" ; then + CONNECTIONS_QUERY="SELECT COUNT(datid) AS current, + (SELECT setting AS mc FROM pg_settings WHERE name = 'max_connections') AS mc, + d.datname + FROM pg_database d + LEFT JOIN pg_stat_activity s ON (s.datid = d.oid) WHERE state <> 'idle' + GROUP BY 2,3 + ORDER BY datname;" + else + CONNECTIONS_QUERY="SELECT COUNT(datid) AS current, + (SELECT setting AS mc FROM pg_settings WHERE name = 'max_connections') AS mc, + d.datname + FROM pg_database d + LEFT JOIN pg_stat_activity s ON (s.datid = d.oid) WHERE current_query <> '' + GROUP BY 2,3 + ORDER BY datname;" + fi + + echo "\pset footer off + \echo '<<>>${INSTANCE_SECTION}' + SELECT datid, datname, numbackends, xact_commit, xact_rollback, blks_read, blks_hit, tup_returned, tup_fetched, tup_inserted, tup_updated, tup_deleted, pg_database_size(datname) AS datsize FROM pg_stat_database; + + \echo '<<>>${INSTANCE_SECTION}' + \echo '[databases_start]' + $ECHO_DATABASES + \echo '[databases_end]' + SELECT datname, granted, mode FROM pg_locks l RIGHT JOIN pg_database d ON (d.oid=l.database) WHERE d.datallowconn; + + \echo '<<>>${INSTANCE_SECTION}' + \echo '[databases_start]' + $ECHO_DATABASES + \echo '[databases_end]' + $QUERYTIME_QUERY + + \echo '<<>>${INSTANCE_SECTION}' + \echo '[databases_start]' + $ECHO_DATABASES + \echo '[databases_end]' + $CONNECTIONS_QUERY" \ + | sudo -u "$DBUSER" $export_PGPASSFILE $psql -X -d $PGDATABASE ${EXTRA_ARGS} -q -A -F';' +} + + +function postgres_stats() { + # Contains last vacuum time and analyze time + local LASTVACUUM="SELECT current_database() AS datname, nspname AS sname, relname AS tname, + CASE WHEN v IS NULL THEN -1 ELSE round(extract(epoch FROM v)) END AS vtime, + CASE WHEN g IS NULL THEN -1 ELSE round(extract(epoch FROM v)) END AS atime + FROM (SELECT nspname, relname, GREATEST(pg_stat_get_last_vacuum_time(c.oid), pg_stat_get_last_autovacuum_time(c.oid)) AS v, + GREATEST(pg_stat_get_last_analyze_time(c.oid), pg_stat_get_last_autoanalyze_time(c.oid)) AS g + FROM pg_class c, pg_namespace n + WHERE relkind = 'r' AND n.oid = c.relnamespace AND n.nspname <> 'information_schema' + ORDER BY 3) AS foo;" + + local FIRST= + local QUERY="\pset footer off + BEGIN; + SET statement_timeout=30000; + COMMIT; + + \echo '<<>>${INSTANCE_SECTION}' + \echo '[databases_start]' + $ECHO_DATABASES + \echo '[databases_end]'" + + for db in $DATABASES ; do + QUERY="$QUERY + \c $db + $LASTVACUUM + " + if [ -z $FIRST ] ; then + FIRST=false + QUERY="$QUERY + \pset tuples_only on + " + fi + done + echo "$QUERY" | sudo -u "$DBUSER" $export_PGPASSFILE $psql -X ${EXTRA_ARGS} -q -A -F';' | grep -v -e 'COMMIT$' -e 'SET$' -e 'BEGIN$' +} + + +function postgres_version() { + # Postgres version an connection time + echo -e "<<>>${INSTANCE_SECTION}" + (TIMEFORMAT='%3R'; time echo "SELECT version() AS v" |\ + sudo -u "$DBUSER" $export_PGPASSFILE $psql -X -d $PGDATABASE ${EXTRA_ARGS} -t -A -F';'; echo -e "<<>>${INSTANCE_SECTION}") 2>&1 +} + + +function postgres_bloat() { + # Bloat index and tables + # Supports versions <9.0, >=9.0 + # This huge query has been gratefully taken from Greg Sabino Mullane's check_postgres.pl + local BLOAT_QUERY + if compare_version_greater_equal "$POSTGRES_VERSION" "9.0" ; then + BLOAT_QUERY="SELECT + current_database() AS db, schemaname, tablename, reltuples::bigint AS tups, relpages::bigint AS pages, otta, + ROUND(CASE WHEN otta=0 OR sml.relpages=0 OR sml.relpages=otta THEN 0.0 ELSE sml.relpages/otta::numeric END,1) AS tbloat, + CASE WHEN relpages < otta THEN 0 ELSE relpages::bigint - otta END AS wastedpages, + CASE WHEN relpages < otta THEN 0 ELSE bs*(sml.relpages-otta)::bigint END AS wastedbytes, + CASE WHEN relpages < otta THEN 0 ELSE (bs*(relpages-otta))::bigint END AS wastedsize, + iname, ituples::bigint AS itups, ipages::bigint AS ipages, iotta, + ROUND(CASE WHEN iotta=0 OR ipages=0 OR ipages=iotta THEN 0.0 ELSE ipages/iotta::numeric END,1) AS ibloat, + CASE WHEN ipages < iotta THEN 0 ELSE ipages::bigint - iotta END AS wastedipages, + CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta) END AS wastedibytes, + CASE WHEN ipages < iotta THEN 0 ELSE (bs*(ipages-iotta))::bigint END AS wastedisize, + CASE WHEN relpages < otta THEN + CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta::bigint) END + ELSE CASE WHEN ipages < iotta THEN bs*(relpages-otta::bigint) + ELSE bs*(relpages-otta::bigint + ipages-iotta::bigint) END + END AS totalwastedbytes + FROM ( + SELECT + nn.nspname AS schemaname, + cc.relname AS tablename, + COALESCE(cc.reltuples,0) AS reltuples, + COALESCE(cc.relpages,0) AS relpages, + COALESCE(bs,0) AS bs, + COALESCE(CEIL((cc.reltuples*((datahdr+ma- + (CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)),0) AS otta, + COALESCE(c2.relname,'?') AS iname, COALESCE(c2.reltuples,0) AS ituples, COALESCE(c2.relpages,0) AS ipages, + COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta -- very rough approximation, assumes all cols + FROM + pg_class cc + JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname <> 'information_schema' + LEFT JOIN + ( + SELECT + ma,bs,foo.nspname,foo.relname, + (datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma ELSE hdr%ma END)))::numeric AS datahdr, + (maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma ELSE nullhdr%ma END))) AS nullhdr2 + FROM ( + SELECT + ns.nspname, tbl.relname, hdr, ma, bs, + SUM((1-coalesce(null_frac,0))*coalesce(avg_width, 2048)) AS datawidth, + MAX(coalesce(null_frac,0)) AS maxfracsum, + hdr+( + SELECT 1+count(*)/8 + FROM pg_stats s2 + WHERE null_frac<>0 AND s2.schemaname = ns.nspname AND s2.tablename = tbl.relname + ) AS nullhdr + FROM pg_attribute att + JOIN pg_class tbl ON att.attrelid = tbl.oid + JOIN pg_namespace ns ON ns.oid = tbl.relnamespace + LEFT JOIN pg_stats s ON s.schemaname=ns.nspname + AND s.tablename = tbl.relname + AND s.inherited=false + AND s.attname=att.attname, + ( + SELECT + (SELECT current_setting('block_size')::numeric) AS bs, + CASE WHEN SUBSTRING(SPLIT_PART(v, ' ', 2) FROM '#\[0-9]+.[0-9]+#\%' for '#') + IN ('8.0','8.1','8.2') THEN 27 ELSE 23 END AS hdr, + CASE WHEN v ~ 'mingw32' OR v ~ '64-bit' THEN 8 ELSE 4 END AS ma + FROM (SELECT version() AS v) AS foo + ) AS constants + WHERE att.attnum > 0 AND tbl.relkind='r' + GROUP BY 1,2,3,4,5 + ) AS foo + ) AS rs + ON cc.relname = rs.relname AND nn.nspname = rs.nspname + LEFT JOIN pg_index i ON indrelid = cc.oid + LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid + ) AS sml + WHERE sml.relpages - otta > 0 OR ipages - iotta > 10 ORDER BY totalwastedbytes DESC LIMIT 10;" + else + BLOAT_QUERY="SELECT + current_database() AS db, schemaname, tablename, reltuples::bigint AS tups, relpages::bigint AS pages, otta, + ROUND(CASE WHEN otta=0 OR sml.relpages=0 OR sml.relpages=otta THEN 0.0 ELSE sml.relpages/otta::numeric END,1) AS tbloat, + CASE WHEN relpages < otta THEN 0 ELSE relpages::bigint - otta END AS wastedpages, + CASE WHEN relpages < otta THEN 0 ELSE bs*(sml.relpages-otta)::bigint END AS wastedbytes, + CASE WHEN relpages < otta THEN '0 bytes'::text ELSE (bs*(relpages-otta))::bigint || ' bytes' END AS wastedsize, + iname, ituples::bigint AS itups, ipages::bigint AS ipages, iotta, + ROUND(CASE WHEN iotta=0 OR ipages=0 OR ipages=iotta THEN 0.0 ELSE ipages/iotta::numeric END,1) AS ibloat, + CASE WHEN ipages < iotta THEN 0 ELSE ipages::bigint - iotta END AS wastedipages, + CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta) END AS wastedibytes, + CASE WHEN ipages < iotta THEN '0 bytes' ELSE (bs*(ipages-iotta))::bigint || ' bytes' END AS wastedisize, + CASE WHEN relpages < otta THEN + CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta::bigint) END + ELSE CASE WHEN ipages < iotta THEN bs*(relpages-otta::bigint) + ELSE bs*(relpages-otta::bigint + ipages-iotta::bigint) END + END AS totalwastedbytes + FROM ( + SELECT + nn.nspname AS schemaname, + cc.relname AS tablename, + COALESCE(cc.reltuples,0) AS reltuples, + COALESCE(cc.relpages,0) AS relpages, + COALESCE(bs,0) AS bs, + COALESCE(CEIL((cc.reltuples*((datahdr+ma- + (CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)),0) AS otta, + COALESCE(c2.relname,'?') AS iname, COALESCE(c2.reltuples,0) AS ituples, COALESCE(c2.relpages,0) AS ipages, + COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta -- very rough approximation, assumes all cols + FROM + pg_class cc + JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname <> 'information_schema' + LEFT JOIN + ( + SELECT + ma,bs,foo.nspname,foo.relname, + (datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma ELSE hdr%ma END)))::numeric AS datahdr, + (maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma ELSE nullhdr%ma END))) AS nullhdr2 + FROM ( + SELECT + ns.nspname, tbl.relname, hdr, ma, bs, + SUM((1-coalesce(null_frac,0))*coalesce(avg_width, 2048)) AS datawidth, + MAX(coalesce(null_frac,0)) AS maxfracsum, + hdr+( + SELECT 1+count(*)/8 + FROM pg_stats s2 + WHERE null_frac<>0 AND s2.schemaname = ns.nspname AND s2.tablename = tbl.relname + ) AS nullhdr + FROM pg_attribute att + JOIN pg_class tbl ON att.attrelid = tbl.oid + JOIN pg_namespace ns ON ns.oid = tbl.relnamespace + LEFT JOIN pg_stats s ON s.schemaname=ns.nspname + AND s.tablename = tbl.relname + AND s.attname=att.attname, + ( + SELECT + (SELECT current_setting('block_size')::numeric) AS bs, + CASE WHEN SUBSTRING(SPLIT_PART(v, ' ', 2) FROM '#\"[0-9]+.[0-9]+#\"%' for '#') + IN ('8.0','8.1','8.2') THEN 27 ELSE 23 END AS hdr, + CASE WHEN v ~ 'mingw32' OR v ~ '64-bit' THEN 8 ELSE 4 END AS ma + FROM (SELECT version() AS v) AS foo + ) AS constants + WHERE att.attnum > 0 AND tbl.relkind='r' + GROUP BY 1,2,3,4,5 + ) AS foo + ) AS rs + ON cc.relname = rs.relname AND nn.nspname = rs.nspname + LEFT JOIN pg_index i ON indrelid = cc.oid + LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid + ) AS sml + WHERE sml.relpages - otta > 0 OR ipages - iotta > 10 ORDER BY totalwastedbytes DESC LIMIT 10;" + fi + + local FIRST= + local QUERY="\pset footer off + \echo '<<>>${INSTANCE_SECTION}' + \echo '[databases_start]' + $ECHO_DATABASES + \echo '[databases_end]'" + + for db in $DATABASES ; do + QUERY="$QUERY + \c $db + $BLOAT_QUERY + " + if [ -z $FIRST ] ; then + FIRST=false + QUERY="$QUERY + \pset tuples_only on + " + fi + done + echo "$QUERY" | sudo -u "$DBUSER" $export_PGPASSFILE $psql -X ${EXTRA_ARGS} -q -A -F';' +} + + +#. +# .--main----------------------------------------------------------------. +# | _ | +# | _ __ ___ __ _(_)_ __ | +# | | '_ ` _ \ / _` | | '_ \ | +# | | | | | | | (_| | | | | | | +# | |_| |_| |_|\__,_|_|_| |_| | +# | | +# '----------------------------------------------------------------------' + + +### postgres.cfg ## +# DBUSER=OS_USER_NAME +# INSTANCE=/home/postgres/db1.env:USER_NAME:/PATH/TO/.pgpass +# INSTANCE=/home/postgres/db2.env:USER_NAME:/PATH/TO/.pgpass + +# TODO @dba USERNAME in .pgpass ? +# INSTANCE=/home/postgres/db2.env:/PATH/TO/.pgpass + + +function postgres_main() { + if [ -z "$DBUSER" ] || [ -z "$PGDATABASE" ] ; then + exit 0 + fi + + EXTRA_ARGS="" + if [ ! -z "$PGUSER" ]; then + EXTRA_ARGS=$EXTRA_ARGS" -U $PGUSER" + fi + if [ ! -z "$PGPORT" ]; then + EXTRA_ARGS=$EXTRA_ARGS" -p $PGPORT" + fi + + if [ ! -z "$PGPASSFILE" ]; then + export_PGPASSFILE="export PGPASSFILE=$PGPASSFILE; " + fi + + DATABASES="$(echo "SELECT datname FROM pg_database WHERE datistemplate = false;" |\ + sudo -u "$DBUSER" $export_PGPASSFILE $psql -X -d $PGDATABASE ${EXTRA_ARGS} -t -A -F';')" + ECHO_DATABASES="$(echo "$DATABASES" | sed 's/^/\\echo /')" + + POSTGRES_VERSION=$(sudo -u "$DBUSER" $psql -X -V -d $PGDATABASE ${EXTRA_ARGS} | egrep -o '[0-9]{1,}\.[0-9]{1,}') + + postgres_sessions + postgres_simple_queries + #postgres_stats + postgres_version + postgres_bloat +} + + +MK_CONFFILE=$MK_CONFDIR/postgres.cfg +if [ -e "$MK_CONFFILE" ]; then + + postgres_instances + + DBUSER=$(grep DBUSER "$MK_CONFFILE" | sed 's/.*=//g') + cat "$MK_CONFFILE" | while read line + do + case $line in + INSTANCE*) + instance=$line + ;; + *) + instance= + ;; + esac + + if [ ! -z "$instance" ]; then + instance_path=$(echo "$instance" | sed 's/.*=\(.*\):.*:.*$/\1/g') + instance_name=$(echo "$instance_path" | sed -e 's/.*\/\(.*\)/\1/g' -e 's/\.env$//g') + if [ ! -z "$instance_name" ]; then + INSTANCE_SECTION="\n[[[$instance_name]]]" + else + INSTANCE_SECTION="" + fi + + psql="/$DBUSER/$(grep "^export PGVERSION=" "$instance_path" | + sed -e 's/.*=//g' -e 's/\s*#.*$//g')/bin/psql" + + PGUSER=$(echo "$instance" | sed 's/.*=.*:\(.*\):.*$/\1/g') + PGPASSFILE="$(echo "$instance" | sed 's/.*=.*:.*:\(.*\)$/\1/g')" + PGDATABASE=$(grep "^export PGDATABASE=" "$instance_path" | + sed -e 's/.*=//g' -e 's/\s*#.*$//g') + PGPORT=$(grep "^export PGPORT=" "$instance_path" | + sed -e 's/.*=//g' -e 's/\s*#.*$//g') + + # Fallback + if [ ! -f "$psql" ]; then + psql="$(cat $instance_path | grep "^export PGHOME=" | + sed -e 's/.*=//g' -e 's/\s*#.*$//g')/psql" + fi + + postgres_main + + fi + done + +else + + if id pgsql >/dev/null 2>&1; then + DBUSER=pgsql + elif id postgres >/dev/null 2>&1; then + DBUSER=postgres + else + exit 0 + fi + INSTANCE_SECTION="" + + postgres_instances "$DBUSER" + + psql="psql" + PGDATABASE=postgres + postgres_main + +fi diff --git a/roles/pvc/files/patroni/powerdns-schema.sql b/roles/pvc/files/patroni/powerdns-schema.sql new file mode 100644 index 0000000..e6c6b7c --- /dev/null +++ b/roles/pvc/files/patroni/powerdns-schema.sql @@ -0,0 +1,94 @@ +CREATE TABLE domains ( + id SERIAL PRIMARY KEY, + name VARCHAR(255) NOT NULL, + master VARCHAR(128) DEFAULT NULL, + last_check INT DEFAULT NULL, + type VARCHAR(6) NOT NULL, + notified_serial INT DEFAULT NULL, + account VARCHAR(40) DEFAULT NULL, + CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))) +); + +CREATE UNIQUE INDEX name_index ON domains(name); + + +CREATE TABLE records ( + id BIGSERIAL PRIMARY KEY, + domain_id INT DEFAULT NULL, + name VARCHAR(255) DEFAULT NULL, + type VARCHAR(10) DEFAULT NULL, + content VARCHAR(65535) DEFAULT NULL, + ttl INT DEFAULT NULL, + prio INT DEFAULT NULL, + disabled BOOL DEFAULT 'f', + ordername VARCHAR(255), + auth BOOL DEFAULT 't', + CONSTRAINT domain_exists + FOREIGN KEY(domain_id) REFERENCES domains(id) + ON DELETE CASCADE, + CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))) +); + +CREATE INDEX rec_name_index ON records(name); +CREATE INDEX nametype_index ON records(name,type); +CREATE INDEX domain_id ON records(domain_id); +CREATE INDEX recordorder ON records (domain_id, ordername text_pattern_ops); + + +CREATE TABLE supermasters ( + ip INET NOT NULL, + nameserver VARCHAR(255) NOT NULL, + account VARCHAR(40) NOT NULL, + PRIMARY KEY(ip, nameserver) +); + + +CREATE TABLE comments ( + id SERIAL PRIMARY KEY, + domain_id INT NOT NULL, + name VARCHAR(255) NOT NULL, + type VARCHAR(10) NOT NULL, + modified_at INT NOT NULL, + account VARCHAR(40) DEFAULT NULL, + comment VARCHAR(65535) NOT NULL, + CONSTRAINT domain_exists + FOREIGN KEY(domain_id) REFERENCES domains(id) + ON DELETE CASCADE, + CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))) +); + +CREATE INDEX comments_domain_id_idx ON comments (domain_id); +CREATE INDEX comments_name_type_idx ON comments (name, type); +CREATE INDEX comments_order_idx ON comments (domain_id, modified_at); + + +CREATE TABLE domainmetadata ( + id SERIAL PRIMARY KEY, + domain_id INT REFERENCES domains(id) ON DELETE CASCADE, + kind VARCHAR(32), + content TEXT +); + +CREATE INDEX domainidmetaindex ON domainmetadata(domain_id); + + +CREATE TABLE cryptokeys ( + id SERIAL PRIMARY KEY, + domain_id INT REFERENCES domains(id) ON DELETE CASCADE, + flags INT NOT NULL, + active BOOL, + content TEXT +); + +CREATE INDEX domainidindex ON cryptokeys(domain_id); + + +CREATE TABLE tsigkeys ( + id SERIAL PRIMARY KEY, + name VARCHAR(255), + algorithm VARCHAR(50), + secret VARCHAR(255), + CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))) +); + +CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm); diff --git a/roles/pvc/handlers/main.yml b/roles/pvc/handlers/main.yml new file mode 100644 index 0000000..0a59472 --- /dev/null +++ b/roles/pvc/handlers/main.yml @@ -0,0 +1,25 @@ +--- +- name: restart zookeeper + service: + name: zookeeper + state: restarted + +- name: restart libvirtd + service: + name: libvirtd + state: restarted + +- name: restart frr + service: + name: frr + state: restarted + +- name: restart patroni + service: + name: patroni + state: restarted + +- name: restart pvcd + service: + name: pvcd + state: restarted diff --git a/roles/pvc/tasks/ceph.yml b/roles/pvc/tasks/ceph.yml new file mode 100644 index 0000000..e9d2310 --- /dev/null +++ b/roles/pvc/tasks/ceph.yml @@ -0,0 +1,48 @@ +--- +- name: create ceph group + group: + name: ceph + gid: 64046 + state: present + +- name: install packages + apt: + name: + - ceph-osd + - ceph-mds + - ceph-mon + - ceph-mgr + - radosgw + - libjemalloc2 + state: latest + +- name: install sysctl tweaks + template: + src: ceph/sysctl.conf.j2 + dest: /etc/sysctl.d/pvc-ceph.conf + +- name: activate sysctl tweaks + command: sysctl -p /etc/sysctl.d/pvc-ceph.conf + +- name: install user limits overrides + template: + src: ceph/limits.conf.j2 + dest: /etc/security/limits.d/99-pvc-ceph.conf + +- name: install ceph default config + template: + src: ceph/default.conf.j2 + dest: /etc/default/ceph + +- name: create ceph configuration directory + file: + dest: /etc/ceph + state: directory + +- name: install ceph cluster configurations + template: + src: ceph/{{ item }}.j2 + dest: /etc/ceph/{{ item }} + with_items: + - ceph.conf + - ceph.client.admin.keyring diff --git a/roles/pvc/tasks/frr.yml b/roles/pvc/tasks/frr.yml new file mode 100644 index 0000000..9213237 --- /dev/null +++ b/roles/pvc/tasks/frr.yml @@ -0,0 +1,23 @@ +--- +- name: install frr packages + apt: + name: + - frr + state: latest + +- name: install frr configuration + template: + src: frr/{{ item }}.j2 + dest: /etc/frr/{{ item }} + with_items: + - daemons + - frr.conf + notify: restart frr + ignore_errors: true + +- name: disable services + service: + name: "{{ item }}" + enabled: no + with_items: + - frr diff --git a/roles/pvc/tasks/libvirt.yml b/roles/pvc/tasks/libvirt.yml new file mode 100644 index 0000000..8b349b0 --- /dev/null +++ b/roles/pvc/tasks/libvirt.yml @@ -0,0 +1,43 @@ +--- +- name: install libvirt packages + apt: + name: + - libvirt-daemon-system + - qemu-kvm + - qemu-utils + - qemu-block-extra + - vhostmd + - ceph-common + - libjemalloc2 + state: latest + +- name: install libvirt configuration + template: + src: libvirt/{{ item }}.j2 + dest: /etc/libvirt/{{ item }} + with_items: + - libvirtd.conf + - ceph-secret.xml + notify: restart libvirtd + +- name: define ceph secret + command: virsh secret-define /etc/libvirt/ceph-secret.xml + ignore_errors: true + +- name: set ceph secret value + command: virsh secret-set-value --secret {{ ceph_storage_secret_uuid }} --base64 {{ ceph_storage_secret_key }} + ignore_errors: true + +- name: configure libvirt for listening + replace: + dest: /etc/default/libvirtd + regexp: '#libvirtd_opts=""' + replace: 'libvirtd_opts="--listen"' + notify: restart libvirtd + +- name: disable services + service: + name: "{{ item }}" + enabled: no + with_items: + - libvirtd diff --git a/roles/pvc/tasks/main.yml b/roles/pvc/tasks/main.yml new file mode 100644 index 0000000..85aba17 --- /dev/null +++ b/roles/pvc/tasks/main.yml @@ -0,0 +1,26 @@ +--- +- name: add module blacklist + template: + src: system/blacklist.j2 + dest: /etc/modprobe.d/blacklist.conf + +- include_tasks: ceph.yml + tags: pvc-ceph + +- include_tasks: zookeeper.yml + tags: pvc-zookeeper + +- include_tasks: libvirt.yml + tags: pvc-libvirt + +- include_tasks: frr.yml + tags: pvc-frr + +- include_tasks: patroni.yml + tags: pvc-patroni + +- include_tasks: pvc.yml + tags: pvc-pvc + run_once: true + delegate_to: "{{ item }}" + with_items: "{{ play_hosts }}" diff --git a/roles/pvc/tasks/patroni.yml b/roles/pvc/tasks/patroni.yml new file mode 100644 index 0000000..571bec6 --- /dev/null +++ b/roles/pvc/tasks/patroni.yml @@ -0,0 +1,128 @@ +--- +- name: install patroni packages via apt + apt: + name: + - python-psycopg2 + - python3-kazoo + - patroni + - postgresql-11 + state: latest + update-cache: yes + +- name: first run check + shell: "echo 'bootstrapped' > /etc/postgresql/pvc" + register: newinstance + args: + creates: /etc/postgresql/pvc + +- name: stop and disable postgresql + service: + name: "{{ item }}" + state: stopped + enabled: no + with_items: + - postgresql + - postgresql@11-main + when: newinstance.changed + +- name: remove obsolete database directories + file: + dest: "{{ item }}" + state: absent + with_items: + - /etc/postgresql/11 + - /var/lib/postgresql/11 + when: newinstance.changed + +- name: create patroni database directory + file: + dest: /var/lib/postgresql/patroni/pvc + state: directory + owner: postgres + mode: 0700 + when: newinstance.changed + +- name: install postgresql customization configuration file + template: + src: patroni/postgresql.pvc.conf.j2 + dest: /etc/postgresql/postgresql.pvc.conf + owner: postgres + group: sudo + mode: 0640 + notify: restart patroni + +- name: install patroni configuration file + template: + src: patroni/patroni.yml.j2 + dest: /etc/patroni/config.yml + owner: postgres + group: postgres + mode: 0640 + notify: restart patroni + +- name: install check_mk agent check + copy: + src: patroni/postgres + dest: /usr/lib/check_mk_agent/plugins/postgres + mode: 0755 + +- name: ensure patroni services are enabled and started + service: + name: "{{ item }}.service" + state: started + enabled: yes + with_items: + - patroni + +- name: install initial schema files + copy: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + owner: postgres + group: sudo + mode: 0640 + with_items: + - { src: "patroni/powerdns-schema.sql", dest: "/etc/postgresql/powerdns-schema.sql" } + +- name: set up PVC DNS database on first host + block: + - name: wait 15s for cluster to initialize + pause: + seconds: 15 + + - name: create user for role + postgresql_user: + name: "{{ pvc_dns_database_user }}" + password: "{{ pvc_dns_database_password }}" + state: present + login_host: /run/postgresql + + - name: create database for role + postgresql_db: + name: "{{ pvc_dns_database_name }}" + owner: "{{ pvc_dns_database_user }}" + encoding: utf8 + state: present + login_host: /run/postgresql + + - name: set user privs for role + postgresql_user: + name: "{{ pvc_dns_database_user }}" + db: "{{ pvc_dns_database_name }}" + priv: ALL + login_host: /run/postgresql + + - name: create extensions + postgresql_ext: + name: "{{ item }}" + db: "{{ pvc_dns_database_name }}" + login_host: /run/postgresql + with_items: "{{ extensions }}" + when: extensions is defined + + - name: import dns database schema + command: "psql -U {{ pvc_dns_database_user }} -f /etc/postgresql/powerdns-schema.sql {{ pvc_dns_database_name }}" + + become: yes + become_user: postgres + when: newinstance.changed and ansible_local.host_id == '1' diff --git a/roles/pvc/tasks/pvc.yml b/roles/pvc/tasks/pvc.yml new file mode 100644 index 0000000..26c0585 --- /dev/null +++ b/roles/pvc/tasks/pvc.yml @@ -0,0 +1,43 @@ +--- +- name: install pvc packages + apt: + name: + - pvc-daemon + - pvc-client-cli + - pvc-client-common + state: latest + +- name: install pvc configuration + template: + src: pvc/{{ item }}.j2 + dest: /etc/pvc/{{ item }} + with_items: + - pvcd.yaml + notify: restart pvcd + +- name: verify if cluster has been started + shell: "/usr/share/zookeeper/bin/zkCli.sh stat /nodes 2>&1 | grep -q 'Node does not exist'" + register: cluster_init + failed_when: no + +- name: bootstrap a fresh cluster + shell: /usr/bin/pvc init + when: cluster_init.rc == 0 and ansible_local.host_id == 1 + +- name: stop and disable unneccessary services + service: + name: "{{ item }}" + state: stopped + enabled: no + with_items: + - pdns.service + +- name: start and enable services + service: + name: "{{ item }}" + state: started + enabled: yes + with_items: + - pvc-flush.service + - pvcd.service + - pvcd.target diff --git a/roles/pvc/tasks/zookeeper.yml b/roles/pvc/tasks/zookeeper.yml new file mode 100644 index 0000000..5ebc0a2 --- /dev/null +++ b/roles/pvc/tasks/zookeeper.yml @@ -0,0 +1,26 @@ +--- +- name: install zookeeper packages + apt: + name: + - zookeeperd + - zookeeper-bin + state: latest + +- name: install zookeeper configuration + template: + src: zookeeper/{{ item }}.j2 + dest: /etc/zookeeper/conf/{{ item }} + with_items: + - configuration.xsl + - environment + - log4j.properties + - myid + - zoo.cfg + notify: restart zookeeper + +- name: disable services + service: + name: "{{ item }}" + enabled: no + with_items: + - zookeeper diff --git a/roles/pvc/templates/ceph/default.conf.j2 b/roles/pvc/templates/ceph/default.conf.j2 new file mode 100644 index 0000000..97d658e --- /dev/null +++ b/roles/pvc/templates/ceph/default.conf.j2 @@ -0,0 +1,4 @@ +# Environment file for ceph daemon systemd unit files. +# {{ ansible_managed }} + +LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.1 diff --git a/roles/pvc/templates/ceph/limits.conf.j2 b/roles/pvc/templates/ceph/limits.conf.j2 new file mode 100644 index 0000000..c09a082 --- /dev/null +++ b/roles/pvc/templates/ceph/limits.conf.j2 @@ -0,0 +1,4 @@ +# Limits for ceph processes +# {{ ansible_managed }} +ceph soft nproc unlimited +ceph soft nofile unlimited diff --git a/roles/pvc/templates/ceph/sysctl.conf.j2 b/roles/pvc/templates/ceph/sysctl.conf.j2 new file mode 100644 index 0000000..6c8355f --- /dev/null +++ b/roles/pvc/templates/ceph/sysctl.conf.j2 @@ -0,0 +1,4 @@ +# sysctl: tweak settings for Ceph +# {{ ansible_managed }} + +vm.swappiness = 0 diff --git a/roles/pvc/templates/frr/daemons.j2 b/roles/pvc/templates/frr/daemons.j2 new file mode 100644 index 0000000..b605527 --- /dev/null +++ b/roles/pvc/templates/frr/daemons.j2 @@ -0,0 +1,16 @@ +# frr daemon status +# {{ ansible_managed }} +zebra=yes +bgpd=yes +ospfd=no +ospf6d=no +ripd=no +ripngd=no +isisd=no +pimd=no +ldpd=no +nhrpd=no +eigrpd=no +babeld=no +sharpd=no +pbrd=no diff --git a/roles/pvc/templates/frr/frr.conf.j2 b/roles/pvc/templates/frr/frr.conf.j2 new file mode 100644 index 0000000..7399d8d --- /dev/null +++ b/roles/pvc/templates/frr/frr.conf.j2 @@ -0,0 +1,53 @@ +! frr main configuration +! {{ ansible_managed }} +! +frr version 4.0 +frr defaults traditional +hostname cloud-14 +no ipv6 forwarding +username cumulus nopassword +! +service integrated-vtysh-config +! +log syslog informational +! +line vty +! +! BGP EVPN mesh configuration +! +router bgp {{ pvc_asn }} + bgp router-id {% for node in pvc_nodes if node.hostname == ansible_hostname %}{{ node.router_id }}{% endfor %} + + no bgp default ipv4-unicast + ! BGP sessions with route reflectors + neighbor fabric peer-group + neighbor fabric remote-as {{ pvc_asn }} + neighbor fabric capability extended-nexthop +{% for node in pvc_nodes if node.is_coordinator %} + neighbor {{ node.router_id }} peer-group fabric +{% endfor %} + ! BGP sessions with upstream routers + neighbor upstream peer-group + neighbor upstream remote-as {{ pvc_asn }} + neighbor upstream capability extended-nexthop +{% for router in pvc_routers %} + neighbor {{ router }} peer-group upstream +{% endfor %} + ! + address-family l2vpn evpn + neighbor fabric activate + advertise-all-vni + exit-address-family + address-family ipv4 unicast + neighbor fabric activate + neighbor upstream activate + redistribute connected + exit-address-family + address-family ipv6 unicast + neighbor fabric activate + neighbor upstream activate + redistribute connected + exit-address-family + ! + exit +! diff --git a/roles/pvc/templates/libvirt/ceph-secret.xml.j2 b/roles/pvc/templates/libvirt/ceph-secret.xml.j2 new file mode 100644 index 0000000..81afc89 --- /dev/null +++ b/roles/pvc/templates/libvirt/ceph-secret.xml.j2 @@ -0,0 +1,6 @@ + + {{ ceph_storage_secret_uuid }} + + client.libvirt secret + + diff --git a/roles/pvc/templates/libvirt/libvirtd.conf.j2 b/roles/pvc/templates/libvirt/libvirtd.conf.j2 new file mode 100644 index 0000000..dcf1cf3 --- /dev/null +++ b/roles/pvc/templates/libvirt/libvirtd.conf.j2 @@ -0,0 +1,7 @@ +# PVC libvirt daemon configuration file +# {{ ansible_managed }} + +listen_tls = 0 +listen_tcp = 1 +tcp_port = "16509" +auth_tcp = "none" diff --git a/roles/pvc/templates/patroni/patroni.yml.j2 b/roles/pvc/templates/patroni/patroni.yml.j2 new file mode 100644 index 0000000..6ce6fca --- /dev/null +++ b/roles/pvc/templates/patroni/patroni.yml.j2 @@ -0,0 +1,63 @@ +scope: pvcdns +namespace: /patroni +name: {{ ansible_hostname }} + +restapi: + listen: '0.0.0.0:8008' + connect_address: '{{ ansible_fqdn }}:8008' + +zookeeper: + hosts: [ {% for host in groups[ansible_local.host_group] %}'{{ host }}.{{ ansible_domain }}:2181',{% endfor %} ] + +bootstrap: + dcs: + ttl: 30 + loop_wait: 10 + retry_timeout: 10 + maximum_lag_on_failover: 1048576 + postgresql: + use_pg_rewind: true + + initdb: + - encoding: UTF8 + - data-checksums + + pg_hba: + - local all all peer + - host replication replicator 127.0.0.1/32 trust +{% for host in groups[ansible_local.host_group] %} + - host replication replicator {{ host }}.{{ ansible_domain }} trust +{% endfor %} + - host all all 0.0.0.0/0 md5 + + users: + admin: + password: admin + options: + - createrole + - createdb + +postgresql: + listen: '0.0.0.0:5432' + connect_address: '{{ ansible_fqdn }}:5432' + log_destination: 'stderr' + log_min_messages: INFO + custom_conf: /etc/postgresql/postgresql.pvc.conf + bin_dir: /usr/lib/postgresql/11/bin + data_dir: /var/lib/postgresql/patroni/pvc + pgpass: /tmp/pgpass + authentication: + replication: + username: '{{ pvc_replication_database_user }}' + password: '{{ pvc_replication_database_password }}' + superuser: + username: '{{ pvc_superuser_database_user }}' + password: '{{ pvc_superuser_database_password }}' + parameters: + unix_socket_directories: '/run/postgresql' + +tags: + nofailover: false + noloadbalance: false + clonefrom: false + nosync: false diff --git a/roles/pvc/templates/patroni/postgresql.pvc.conf.j2 b/roles/pvc/templates/patroni/postgresql.pvc.conf.j2 new file mode 100644 index 0000000..ab0d4d9 --- /dev/null +++ b/roles/pvc/templates/patroni/postgresql.pvc.conf.j2 @@ -0,0 +1,21 @@ +# Additional PostgreSQL tuning parameters for PVC Patroni instance +# {{ ansible_managed }} + +max_connections = 100 +shared_buffers = 64MB +effective_cache_size = 256MB +dynamic_shared_memory_type = posix + +random_page_cost = 1 +seq_page_cost = 1 + +log_timezone = 'localtime' +datestyle = 'iso, dmy' +timezone = 'localtime' + +lc_messages = 'en_CA.UTF-8' +lc_monetary = 'en_CA.UTF-8' +lc_numeric = 'en_CA.UTF-8' +lc_time = 'en_CA.UTF-8' + +default_text_search_config = 'pg_catalog.english' diff --git a/roles/pvc/templates/pvc/pvcd.yaml.j2 b/roles/pvc/templates/pvc/pvcd.yaml.j2 new file mode 100644 index 0000000..515e923 --- /dev/null +++ b/roles/pvc/templates/pvc/pvcd.yaml.j2 @@ -0,0 +1,75 @@ +--- +# pvcd cluster configuration +# {{ ansible_managed }} +pvc: + node: {% for node in pvc_nodes if node.hostname == ansible_hostname %}{{ node.hostname }}{% endfor %} + + functions: + enable_hypervisor: True + enable_networking: True + enable_storage: False + cluster: + coordinators: +{% for node in pvc_nodes if node.is_coordinator %} + - {{ node.hostname }} +{% endfor %} + networks: + cluster: + domain: {{ pvc_cluster_domain }} + network: {{ pvc_cluster_subnet }} + floating_ip: {{ pvc_cluster_floatingip }} + storage: + domain: {{ pvc_storage_domain }} + network: {{ pvc_storage_subnet }} + floating_ip: {{ pvc_storage_floatingip }} + upstream: + domain: {{ pvc_upstream_domain }} + network: {{ pvc_upstream_subnet }} + floating_ip: {{ pvc_upstream_floatingip }} + gateway: {{ pvc_upstream_gatewayip }} + coordinator: + dns: + database: + host: localhost + port: 5432 + name: pvcdns + user: pvcdns + pass: PVCdnsPassw0rd + system: + fencing: + intervals: + keepalive_interval: 5 + fence_intervals: 6 + suicide_intervals: 0 + actions: + successful_fence: migrate + failed_fence: None + ipmi: + host: {% for node in pvc_nodes if node.hostname == ansible_hostname %}{{ node.ipmi_host }}{% endfor %} + + user: {% for node in pvc_nodes if node.hostname == ansible_hostname %}{{ node.ipmi_user }}{% endfor %} + + pass: {% for node in pvc_nodes if node.hostname == ansible_hostname %}{{ node.ipmi_password }}{% endfor %} + + migration: + target_selector: mem + configuration: + directories: + dynamic_directory: "/run/pvc" + log_directory: "/var/log/pvc" + console_log_directory: "/var/log/libvirt" + logging: + file_logging: True + stdout_logging: True + console_log_lines: 1000 + networking: + devices: + cluster: {{ pvc_cluster_device }} + storage: {{ pvc_storage_device }} + upstream: {{ pvc_upstream_device }} + addresses: + cluster: {% for node in pvc_nodes if node.hostname == ansible_hostname %}{{ node.cluster_ip }}{% endfor %} + + storage: {% for node in pvc_nodes if node.hostname == ansible_hostname %}{{ node.storage_ip }}{% endfor %} + + upstream: {% for node in pvc_nodes if node.hostname == ansible_hostname %}{{ node.upstream_ip }}{% endfor %} diff --git a/roles/pvc/templates/system/blacklist.j2 b/roles/pvc/templates/system/blacklist.j2 new file mode 100644 index 0000000..10d43a1 --- /dev/null +++ b/roles/pvc/templates/system/blacklist.j2 @@ -0,0 +1,11 @@ +# modprobe blacklist +# {{ ansible_managed }} + +# Blacklist GPU drivers +blacklist nouveau +blacklist radeon +blacklist amdgpu +blacklist snd_hda_intel + +# Blacklist HP Proliant management +blacklist hpwdt diff --git a/roles/pvc/templates/zookeeper/configuration.xsl.j2 b/roles/pvc/templates/zookeeper/configuration.xsl.j2 new file mode 100644 index 0000000..0fa2f82 --- /dev/null +++ b/roles/pvc/templates/zookeeper/configuration.xsl.j2 @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + +
    namevaluedescription
    + + +
    +
    diff --git a/roles/pvc/templates/zookeeper/environment.j2 b/roles/pvc/templates/zookeeper/environment.j2 new file mode 100644 index 0000000..84bc73f --- /dev/null +++ b/roles/pvc/templates/zookeeper/environment.j2 @@ -0,0 +1,10 @@ +# {{ ansible_managed }} +ZOOMAIN=org.apache.zookeeper.server.quorum.QuorumPeerMain +ZOOCFGDIR=/etc/zookeeper/conf +ZOOCFG=/etc/zookeeper/conf/zoo.cfg +ZOO_LOG_DIR=/var/log/zookeeper +ZOO_LOG4J_PROP=INFO,ROLLINGFILE +JMXLOCALONLY=false +JAVA_OPTS="" +JAVA=/usr/bin/java +CLASSPATH="/etc/zookeeper/conf:/usr/share/java/jline.jar:/usr/share/java/log4j-1.2.jar:/usr/share/java/xercesImpl.jar:/usr/share/java/xmlParserAPIs.jar:/usr/share/java/netty.jar:/usr/share/java/slf4j-api.jar:/usr/share/java/slf4j-log4j12.jar:/usr/share/java/zookeeper.jar" diff --git a/roles/pvc/templates/zookeeper/log4j.properties.j2 b/roles/pvc/templates/zookeeper/log4j.properties.j2 new file mode 100644 index 0000000..91f7a22 --- /dev/null +++ b/roles/pvc/templates/zookeeper/log4j.properties.j2 @@ -0,0 +1,50 @@ +# ZooKeeper Logging Configuration +# {{ ansible_managed }} + +# Format is " (, )+ + +log4j.rootLogger=${zookeeper.root.logger} + +# Example: console appender only +# log4j.rootLogger=INFO, CONSOLE + +# Example with rolling log file +#log4j.rootLogger=DEBUG, CONSOLE, ROLLINGFILE + +# Example with rolling log file and tracing +#log4j.rootLogger=TRACE, CONSOLE, ROLLINGFILE, TRACEFILE + +# +# Log INFO level and above messages to the console +# +log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender +log4j.appender.CONSOLE.Threshold=INFO +log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout +log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} - %-5p [%t:%C{1}@%L] - %m%n + +# +# Add ROLLINGFILE to rootLogger to get log file output +# Log DEBUG level and above messages to a log file +log4j.appender.ROLLINGFILE=org.apache.log4j.RollingFileAppender +log4j.appender.ROLLINGFILE.Threshold=DEBUG +log4j.appender.ROLLINGFILE.File=${zookeeper.log.dir}/zookeeper.log + +# Max log file size of 10MB +log4j.appender.ROLLINGFILE.MaxFileSize=10MB +# uncomment the next line to limit number of backup files +#log4j.appender.ROLLINGFILE.MaxBackupIndex=10 + +log4j.appender.ROLLINGFILE.layout=org.apache.log4j.PatternLayout +log4j.appender.ROLLINGFILE.layout.ConversionPattern=%d{ISO8601} - %-5p [%t:%C{1}@%L] - %m%n + + +# +# Add TRACEFILE to rootLogger to get log file output +# Log DEBUG level and above messages to a log file +log4j.appender.TRACEFILE=org.apache.log4j.FileAppender +log4j.appender.TRACEFILE.Threshold=TRACE +log4j.appender.TRACEFILE.File=${zookeeper.log.dir}/zookeeper_trace.log + +log4j.appender.TRACEFILE.layout=org.apache.log4j.PatternLayout +### Notice we are including log4j's NDC here (%x) +log4j.appender.TRACEFILE.layout.ConversionPattern=%d{ISO8601} - %-5p [%t:%C{1}@%L][%x] - %m%n diff --git a/roles/pvc/templates/zookeeper/myid.j2 b/roles/pvc/templates/zookeeper/myid.j2 new file mode 100644 index 0000000..687b441 --- /dev/null +++ b/roles/pvc/templates/zookeeper/myid.j2 @@ -0,0 +1 @@ +{{ ansible_local.host_id }} diff --git a/roles/pvc/templates/zookeeper/zoo.cfg.j2 b/roles/pvc/templates/zookeeper/zoo.cfg.j2 new file mode 100644 index 0000000..1326781 --- /dev/null +++ b/roles/pvc/templates/zookeeper/zoo.cfg.j2 @@ -0,0 +1,13 @@ +# PVC Zookeeper configuration +# {{ ansible_managed }} + +tickTime=1000 +initLimit=10 +syncLimit=5 +dataDir=/var/lib/zookeeper + +clientPort=2181 + +{% for node in pvc_nodes if node.is_coordinator %} +server.{{ node.node_id }}={{ node.hostname }}:2888:3888 +{% endfor %}