Compare commits
156 Commits
Author | SHA1 | Date |
---|---|---|
Jérémy Dubois | 99ff7284a3 | |
Jérémy Dubois | 6a2faf5649 | |
Jérémy Dubois | f2451118c4 | |
Ludovic Poujol | 28851698e6 | |
Ludovic Poujol | 9fe7825499 | |
Ludovic Poujol | f7b29deda3 | |
Ludovic Poujol | 43e8ebfa0a | |
Ludovic Poujol | bce501dee0 | |
Jérémy Dubois | 70ab0c80de | |
Jérémy Dubois | bf1bb2f80e | |
Jérémy Dubois | a61f2423bc | |
Jérémy Dubois | 7dd930afcb | |
Jérémy Dubois | 8e18b6972a | |
Jérémy Dubois | 63212accdd | |
Jérémy Dubois | aee18bfde9 | |
Jérémy Dubois | 1f0011ad2a | |
Jérémy Dubois | 6822eaa4f0 | |
Jérémy Dubois | aed20187de | |
Jérémy Dubois | 28021670f0 | |
Jérémy Dubois | a217bb2e56 | |
Jérémy Dubois | 832e93da0d | |
Jérémy Dubois | ced4098192 | |
Jérémy Dubois | 7aa588528c | |
Jérémy Dubois | afba3ad7e1 | |
Jérémy Dubois | 05bdef9ab8 | |
Jérémy Lecour | b2438dde80 | |
Jérémy Lecour | f644f8c449 | |
Jérémy Dubois | a0139688c6 | |
Jérémy Dubois | a66e1c1ee9 | |
Jérémy Dubois | b4e1afa698 | |
Jérémy Dubois | 5ca86431eb | |
Jérémy Dubois | 8a63c8336f | |
Jérémy Dubois | d2574faaef | |
Jérémy Dubois | f43405991e | |
Jérémy Dubois | e4bc6c1d97 | |
Jérémy Dubois | 6f97857b91 | |
Jérémy Dubois | 264c58a03d | |
Jérémy Dubois | 7ab102376f | |
Jérémy Dubois | 81d8774885 | |
Jérémy Dubois | 9c450ff11b | |
Jérémy Dubois | f801218789 | |
Jérémy Dubois | a045995c01 | |
Jérémy Dubois | c7e3b2d9ac | |
Jérémy Dubois | f42477c8fb | |
Jérémy Dubois | 3a0db4bfb4 | |
Jérémy Dubois | 394b71c947 | |
Jérémy Dubois | ccdd16c523 | |
Jérémy Dubois | 84e6ccec4f | |
Jérémy Dubois | 7258d99d13 | |
Jérémy Dubois | 60fd0e1e38 | |
Jérémy Dubois | e7ff98662f | |
William Hirigoyen | 079d807c7f | |
William Hirigoyen | 69ab1503b3 | |
Jérémy Dubois | 4b971b19fb | |
Jérémy Dubois | 328dc63d82 | |
Jérémy Dubois | cdc2546448 | |
Jérémy Dubois | a5f0695bbb | |
Jérémy Dubois | 9515c8639f | |
Jérémy Dubois | 0960b8a7b3 | |
Jérémy Dubois | 835371b861 | |
Jérémy Dubois | f43094e7b5 | |
Jérémy Dubois | 4ace413343 | |
Jérémy Dubois | 73563d6838 | |
Jérémy Dubois | dfaaa8e0da | |
Jérémy Dubois | 22cb655f78 | |
Jérémy Dubois | f71560a87b | |
Jérémy Dubois | a458f51289 | |
Jérémy Dubois | d10b2c42b3 | |
Jérémy Dubois | ec6de426d6 | |
Jérémy Dubois | c0b1131f36 | |
Jérémy Dubois | c7bf4a461f | |
Jérémy Dubois | 61c5f6810c | |
Jérémy Dubois | 3c29a6ff10 | |
Jérémy Dubois | c692105b5c | |
Jérémy Dubois | daaa33a10a | |
Jérémy Dubois | b070e4bac0 | |
Jérémy Dubois | ce5e4a48de | |
Jérémy Dubois | 6f1c10744b | |
Jérémy Dubois | 3d941a99a3 | |
Jérémy Dubois | aed61c3df6 | |
Jérémy Dubois | d9b757ca46 | |
Jérémy Dubois | 5da921572e | |
Jérémy Dubois | 28b946bd47 | |
Jérémy Dubois | 3878e1bddc | |
Jérémy Dubois | c2e0809865 | |
Jérémy Dubois | 749f026f32 | |
Jérémy Dubois | 97d1f90082 | |
Jérémy Dubois | 9a4a906b23 | |
Jérémy Dubois | 24180c31e4 | |
Jérémy Dubois | 891513d633 | |
Jérémy Dubois | 8e3b4b35cd | |
Jérémy Dubois | 534efdcc01 | |
Jérémy Dubois | 48066052ac | |
Jérémy Dubois | 62f31f519e | |
Jérémy Dubois | 7a9d60b397 | |
Jérémy Dubois | 56682b1646 | |
Jérémy Dubois | fae8837f98 | |
Jérémy Dubois | 48f25bbe7c | |
Jérémy Dubois | 7a92c25e27 | |
Jérémy Dubois | 2d95820de9 | |
Jérémy Dubois | 91922175cd | |
Jérémy Dubois | 0e9df878e1 | |
Jérémy Dubois | 12c8f02884 | |
Jérémy Dubois | 17ac3a3a36 | |
Jérémy Dubois | 8bfc0b1aea | |
Jérémy Dubois | 674a4aa836 | |
Jérémy Dubois | 7a47d95776 | |
Jérémy Dubois | 6667c4b9e8 | |
Jérémy Dubois | e5d1dc96bb | |
Jérémy Dubois | 962eefe3d7 | |
Jérémy Dubois | 0e5922c8d8 | |
Jérémy Dubois | e2d0256946 | |
Jérémy Dubois | ab7cc1189f | |
Jérémy Dubois | f4e07b4578 | |
Jérémy Dubois | b220c1934d | |
Jérémy Dubois | 19a0ebb8ea | |
Jérémy Dubois | d145d3fdc3 | |
Jérémy Dubois | 7b98ae73a8 | |
Jérémy Dubois | 6c93e13a25 | |
Jérémy Dubois | a4492844e4 | |
Jérémy Dubois | 950dbaec21 | |
Jérémy Dubois | 1f07862c84 | |
Jérémy Dubois | 6ef04839c4 | |
Jérémy Dubois | 335969ed42 | |
Jérémy Dubois | 445c6afe1f | |
Jérémy Dubois | 2dc7d3073f | |
Jérémy Dubois | be9f183359 | |
Jérémy Dubois | bb43bc5370 | |
Jérémy Dubois | 490b733f1a | |
Jérémy Dubois | e1ae8fefb9 | |
Jérémy Dubois | 46b9baf601 | |
Jérémy Dubois | f57e9934ff | |
Jérémy Dubois | 1939ca3142 | |
Jérémy Dubois | 04bdff87f4 | |
Jérémy Dubois | 5481bb4698 | |
Jérémy Dubois | bd1d29b1bd | |
Jérémy Dubois | bbe56e3422 | |
Jérémy Dubois | 5892777ef9 | |
Jérémy Dubois | e0c27ff083 | |
Jérémy Dubois | 07f4dadd0e | |
Jérémy Dubois | ce886fdc1d | |
Jérémy Dubois | bdda2b7b79 | |
Jérémy Dubois | 40ed5b0437 | |
Jérémy Dubois | eb96fd41b2 | |
Jérémy Dubois | e8782227b2 | |
Jérémy Dubois | 30a601b2e1 | |
Jérémy Dubois | b114d139d4 | |
Jérémy Dubois | ecacb00018 | |
Jérémy Dubois | 576e13db78 | |
Jérémy Dubois | a34f3d606b | |
Jérémy Dubois | fe6235f8fb | |
Jérémy Dubois | d643c15be5 | |
Jérémy Dubois | 66c84dca6c | |
Jérémy Dubois | 93f21a947c | |
Jérémy Dubois | 4506c835c5 | |
Jérémy Dubois | f0ecc79696 |
|
@ -0,0 +1,3 @@
|
|||
skip_list:
|
||||
- '106' # Role name {} does not match ``^[a-z][a-z0-9_]+$`` pattern
|
||||
- '204' # Lines should be no longer than 160 chars
|
206
CHANGELOG
206
CHANGELOG
|
@ -9,140 +9,236 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
### Added
|
||||
|
||||
* base: set the title of the terminal when connecting to a server
|
||||
* base: import dump-server-state.sh script
|
||||
* post-install: add a version number to motd-carp-state.sh
|
||||
* nagios-nrpe: add a check dhcp_pool
|
||||
* collectd: add dhcp_pool.pl script
|
||||
* base: add a "next_part" before executing evobackup in daily.local file
|
||||
* base: add update-evobackup-canary script
|
||||
* base: session timeout is configurable
|
||||
* add a update-utils.yml playbook to update scripts
|
||||
* base: use a variable to define ntpd server
|
||||
* base: add entry in doas.conf for sd0 in case we have a hard raid
|
||||
* base: add munin files in newsyslog.conf by default
|
||||
* nagios-nrpe: add some information in check_connections_state.sh check
|
||||
* ospf: precise in the readme file that no daemon is configured/activated
|
||||
* logsentry: delete unused default file that we put in /usr/share/scripts
|
||||
* base: set the lookup option so that resolv.conf searches /etc/hosts before querying a domain name server; the default is the opposite
|
||||
* post-install: add the pf_states check by default in generateldif.sh script
|
||||
* nagios-nrpe: allow older cipher suites for older Icinga version
|
||||
* evobackup: execute canary script before executing backup script
|
||||
* accounts: create only users who have a certain value for the `create` key (default: `always`)
|
||||
* nagios-nrpe: add the ipmi_sensor check
|
||||
* base: doas configuration for ipmi_sensor NRPE check
|
||||
* base: deactivate insults in sudo
|
||||
* base: added handlers for entries in fstab
|
||||
* forwarding: added tags to distinguish IPv4 from IPv6
|
||||
* accounts: add a "users" tag so that new users are not created and customized password are not reset based on vars files when executing evolixisation.yml again
|
||||
* base: Generate default (self-signed) certificate
|
||||
|
||||
### Changed
|
||||
|
||||
* accounts: use "evobsd_internal_group" for SSH authentication
|
||||
* base: zzz_evobackup upstream release 22.03
|
||||
* etc-git: manage commits with an optimized shell script instead of many slow Ansible tasks
|
||||
* etc-git: use "ansible-commit" to efficiently commit all available repositories from Ansible
|
||||
* etc-git: add versioning for /usr/share/scripts
|
||||
* nagios-nrpe: add a wraper to check_dhcpd to define the number of dhcpd processes that must be running depending on the CARP state
|
||||
* evocheck: renamed install.yml to main.yml and add evocheck cron at the beginning of the daily.local file
|
||||
* pf: reorder some rules, more details on some comments
|
||||
* update of tags for each tasks and ease the update of scripts
|
||||
* evocheck: execute evocheck without --cron the first of the month
|
||||
* etc-git: chmod 600 for local periodic files (daily, weekly, monthly)
|
||||
* base: loop over fstab entries instead of copying the same task for each entries
|
||||
* etc-git: do not erase custom entries of servers in .gitignore files
|
||||
* nagios-nrpe: check_disk1 returns only alerts
|
||||
* base: do not erase custom configuration of servers in doas.conf
|
||||
* base: vmd and pass are not used in our infrastructure, deletion of autocompletion
|
||||
* nagios-nrpe: do not erase custom configuration of servers in nrpe.d/evolix.cfg, and do not use zzz_evolix.cfg anymore
|
||||
* base: export evomaintenance and evobackup tasks into their own roles
|
||||
* nagios-nrpe: multiples IP can now be checked with check_ipsecctl_critiques.sh
|
||||
* base: use a variable for /etc/installurl content
|
||||
* base: use "servers" option instead of "server" option for ntpd.conf
|
||||
* base: fstab options can be activated or not
|
||||
* base: configure "/usr/X11R6" and "/usr/local" for servers that have a mount on it
|
||||
* base: we can chose to deploy or not utils files
|
||||
* base: reordering default variable file and deleting unused one
|
||||
* base: use a template for ntp configuration to ease the management of the different cases
|
||||
* logsentry: update config files, add "[logsentry]" in subject, and simplify task
|
||||
* nagios-nrpe: deleted unused variables and added a ntp check server variable
|
||||
* post-install: use basename of path in generateldif.sh to define file from elsewhere
|
||||
* bgp, collectd, logsentry, ospf: update scripts
|
||||
* collectd: improve dns_stats.sh script for more metrics
|
||||
* ospf: do not repeat use of command, use variable instead with output of command
|
||||
* nagios-nrpe: changed check_load to make it more relevant
|
||||
* nagios-nrpe: check_ipsecctl.sh is never used standalone for check_vpn, always called by check_ipsecctl_critiques.sh
|
||||
* evobackup: zzz_evobackup upstream release 22.12, and call zzz_evobackup with bash
|
||||
* base: install bash, now needed for zzz_evobackup script
|
||||
* post-install: execute motd-carp-state.sh every 10 minuts
|
||||
* collectd: modified collectd scripts directory and scripts files right so that only _collectd group can execute them
|
||||
* base: install ncdu and htop often used as diagnostic tools
|
||||
* base: dump-server-state.sh upstream release 24.01
|
||||
* evocheck: upstream release 23.06
|
||||
* base: add evobsd_alias_fwupdate variable and make kshrc file a template so we can set or not a fw_update alias to servers that need it
|
||||
* etc-git: add versioning for /var/unbound/etc
|
||||
* base: ignore errors on packages installation because it fails for some packages when run in check mode
|
||||
* evomaintenance: upstream release 23.10.1
|
||||
* accounts, etc-git, evocheck, nagios-nrpe: multiple changes to not fail when run in check mode
|
||||
* base: configure "/var/log" for servers that have a mount on it
|
||||
* nagios-nrpe: configure allowed_hosts in template and make use of the 'nagios_nrpe_additional_allowed_hosts' var in inventory for additional IP
|
||||
* nagios-nrpe: configure server certificate for nrpe daemon
|
||||
|
||||
### Fixed
|
||||
|
||||
* base: fix shell configuration, increase $HISTSIZE, and change history alias so it displays full history
|
||||
* nagios-nrpe: handle the case where cached_mem is in GB to convert it in MB in check_free_mem.sh
|
||||
* post-install: improve management of ldif file for ldap
|
||||
* post-install: ignore errors from syspatch
|
||||
* nagios-nrpe: grep in check_ipsecctl_critiques.sh was too large
|
||||
* post-install: fix missing space in generateldif.sh script
|
||||
* logsentry: fix variables for configuration files
|
||||
* nagios-nrpe: fix allowed_hosts configuration: keep potential added IP, but we cannot use backrefs if the line does not exist yet
|
||||
* accounts: configure user home, ssh keys and groups only if it already exists, so that there is no error when run in check mode and user doesn't exist yet
|
||||
* collectd: fix rights for collectd directory
|
||||
* etc-git: Remove deprecated/unsupported "warn" parameter
|
||||
* ospf, bgp: fix checks scripts
|
||||
* base, collectd, etc-git, logsentry, nagios-nrpe: install packages manually because openbsd_pkg module is broken since OpenBSD 7.4 with the version of Ansible we currently use
|
||||
|
||||
### Removed
|
||||
|
||||
* openvpn: deleted this deprecated role ; use the one provided in the ansible-roles repo
|
||||
* base: doas is used for evomaintenance, not sudo ; wheel group mustn't be sudo because we use the evolinux-sudo group
|
||||
* base: doas configuration for _collectd user is managed in collectd role, not needed to have it by default
|
||||
|
||||
## [21.12] - 2021-12-17
|
||||
|
||||
### Changed
|
||||
|
||||
- Configure locale to en_US.UTF-8 in .profile file so that "git log" displays the accents correctly
|
||||
- Use vim as default git editor
|
||||
- Change version pattern and fix release scheme
|
||||
* Configure locale to en_US.UTF-8 in .profile file so that "git log" displays the accents correctly
|
||||
* Use vim as default git editor
|
||||
* Change version pattern and fix release scheme
|
||||
|
||||
### Added
|
||||
|
||||
- Add a bioctl NRPE check for RAID devices
|
||||
* Add a bioctl NRPE check for RAID devices
|
||||
|
||||
## [6.9.2] - 2021-10-15
|
||||
|
||||
### Added
|
||||
|
||||
- Add a more complete ipsecctl check script
|
||||
- Add doas configuration for check_openvpn_certificates.sh
|
||||
* Add a more complete ipsecctl check script
|
||||
* Add doas configuration for check_openvpn_certificates.sh
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix check_dhcpd for dhcpd server themselves : use back check_procs -c1: -C dhcpd
|
||||
- Fix check_mailq : check from monitoring-plugins current version is not compatible with opensmtpd
|
||||
* Fix check_dhcpd for dhcpd server themselves: use back check_procs -c1: -C dhcpd
|
||||
* Fix check_mailq: check from monitoring-plugins current version is not compatible with opensmtpd
|
||||
|
||||
## [6.9.1] - 2021-07-19
|
||||
|
||||
### Added
|
||||
|
||||
- Configure the ntpd.conf file
|
||||
* Configure the ntpd.conf file
|
||||
|
||||
## [6.9.0] - 2021-05-06
|
||||
|
||||
### Changed
|
||||
|
||||
- Remove the variable VERBOSESTATUS in daily.local configuration file since it is no longer valid.
|
||||
* Remove the variable VERBOSESTATUS in daily.local configuration file since it is no longer valid.
|
||||
|
||||
## [6.8.3] - 2021-02-15
|
||||
|
||||
### Added
|
||||
|
||||
- Add a customization of the logsentry configuration
|
||||
- Add a check_openvpn_certificates in NRPE and OpenVPN role to check expiration date of server CA and certificates files
|
||||
* Add a customization of the logsentry configuration
|
||||
* Add a check_openvpn_certificates in NRPE and OpenVPN role to check expiration date of server CA and certificates files
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix the check_mem command in the NRPE role, precising the percentage sign for it not to check the memory in MB.
|
||||
- Fix the check_mem script in the NRPE role, adding cached RAM as free RAM
|
||||
- Fix motd-carp-state.sh by updating the OpenBSD release in our customized motd after an upgrade
|
||||
* Fix the check_mem command in the NRPE role, precising the percentage sign for it not to check the memory in MB.
|
||||
* Fix the check_mem script in the NRPE role, adding cached RAM as free RAM
|
||||
* Fix motd-carp-state.sh by updating the OpenBSD release in our customized motd after an upgrade
|
||||
|
||||
### Changed
|
||||
|
||||
- The PF role now use a variable for trusted IPs
|
||||
* The PF role now use a variable for trusted IPs
|
||||
|
||||
## [6.8.2] - 2020-10-30
|
||||
|
||||
### Added
|
||||
|
||||
- Add a Logsentry role
|
||||
* Add a Logsentry role
|
||||
|
||||
## [6.8.1] - 2020-10-26
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix a task using a register where simple quotes prevented the register to be properly filled, breaking the following task
|
||||
* Fix a task using a register where simple quotes prevented the register to be properly filled, breaking the following task
|
||||
|
||||
## [6.8.0] - 2020-10-23
|
||||
|
||||
### Added
|
||||
|
||||
- Add a PF tag to be able to skip that part when rerunning EvoBSD
|
||||
- Add a doas authorization for NRPE check_ipsecctl_critiques
|
||||
* Add a PF tag to be able to skip that part when rerunning EvoBSD
|
||||
* Add a doas authorization for NRPE check_ipsecctl_critiques
|
||||
|
||||
### Changed
|
||||
|
||||
- The task mail.yml replace the former boot/reboot message only if it is untouched
|
||||
- Replace the variable used to set the email address in etc-git role - now using inventory_hostname
|
||||
- Not checking syspatch when OpenBSD <= 6.1
|
||||
- Amend fstab file adding noatime option to each entrie
|
||||
- Import evocheck v.6.7.7
|
||||
- Comment NRPE checks that cannot be used as is
|
||||
* The task mail.yml replace the former boot/reboot message only if it is untouched
|
||||
* Replace the variable used to set the email address in etc-git role - now using inventory_hostname
|
||||
* Not checking syspatch when OpenBSD <= 6.1
|
||||
* Amend fstab file adding noatime option to each entrie
|
||||
* Import evocheck v.6.7.7
|
||||
* Comment NRPE checks that cannot be used as is
|
||||
|
||||
### Fixed
|
||||
|
||||
- Add the creation of the NRPE plugins directory in nagios-nrpe role
|
||||
- Add collectd doas rights in the base role to avoid broking anything if EvoBSD is rerun without the collectd role included
|
||||
- Do not add the motd cron if the same line is already there but uncommented
|
||||
- Amend fstab entries only when the filesystem is ffs
|
||||
* Add the creation of the NRPE plugins directory in nagios-nrpe role
|
||||
* Add collectd doas rights in the base role to avoid broking anything if EvoBSD is rerun without the collectd role included
|
||||
* Do not add the motd cron if the same line is already there but uncommented
|
||||
* Amend fstab entries only when the filesystem is ffs
|
||||
|
||||
## [6.7.2] - 2020-10-13
|
||||
|
||||
### Added
|
||||
|
||||
- Now handling deletion of evobackup crontab (replaced by daily.local cron)
|
||||
- Customize fstab with noexec and softdep
|
||||
- Collectd role
|
||||
* Now handling deletion of evobackup crontab (replaced by daily.local cron)
|
||||
* Customize fstab with noexec and softdep
|
||||
* Collectd role
|
||||
|
||||
### Changed
|
||||
|
||||
- Improve rc.local file configuration
|
||||
- Update evocheck to version 6.7.5
|
||||
- Hide default daily output mail content (VERBOSESTATUS=0)
|
||||
- Add deletion of old log files in the OSPF role
|
||||
* Improve rc.local file configuration
|
||||
* Update evocheck to version 6.7.5
|
||||
* Hide default daily output mail content (VERBOSESTATUS=0)
|
||||
* Add deletion of old log files in the OSPF role
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix duplicate evobackup cron if the entry is uncommented in daily.local
|
||||
* Fix duplicate evobackup cron if the entry is uncommented in daily.local
|
||||
|
||||
## [6.7.1] - 2020-09-10
|
||||
|
||||
### Added
|
||||
|
||||
- Add completions functions in root's profile dotfile
|
||||
- Add check_connections_state.sh NRPE plugin
|
||||
- Add an evocheck role
|
||||
- Add stricter ssh and doas access
|
||||
- Add an openvpn role
|
||||
- Add an OpenBGPd NRPE plugin
|
||||
- Add ospf and bgp roles
|
||||
- Add an unbound NRPE check since it is part of the base system
|
||||
- Add a motd-carp-state.sh script that checks the carp state and generates the /etc/motd file
|
||||
* Add completions functions in root's profile dotfile
|
||||
* Add check_connections_state.sh NRPE plugin
|
||||
* Add an evocheck role
|
||||
* Add stricter ssh and doas access
|
||||
* Add an openvpn role
|
||||
* Add an OpenBGPd NRPE plugin
|
||||
* Add ospf and bgp roles
|
||||
* Add an unbound NRPE check since it is part of the base system
|
||||
* Add a motd-carp-state.sh script that checks the carp state and generates the /etc/motd file
|
||||
|
||||
### Changed
|
||||
|
||||
- Disable sndiod since it is not required on serveurs
|
||||
- Replace sudo with doas for script executions
|
||||
- Update evomaintenance version to 0.6.3
|
||||
- Disable mouse function in vim configuration
|
||||
- Drop openup since syspatch can apply stable patches now
|
||||
- Update evobackup script
|
||||
- Rewrite newsyslog configuration
|
||||
- Drop postgresql-client package since evomaintenance use an API now
|
||||
* Disable sndiod since it is not required on serveurs
|
||||
* Replace sudo with doas for script executions
|
||||
* Update evomaintenance version to 0.6.3
|
||||
* Disable mouse function in vim configuration
|
||||
* Drop openup since syspatch can apply stable patches now
|
||||
* Update evobackup script
|
||||
* Rewrite newsyslog configuration
|
||||
* Drop postgresql-client package since evomaintenance use an API now
|
||||
|
|
11
README.md
11
README.md
|
@ -28,6 +28,17 @@ Subsequent use (become_method: sudo) :
|
|||
ansible-playbook evolixisation.yml --ask-vault-pass -CDKi hosts --skip-tags pf -l HOSTNAME
|
||||
```
|
||||
|
||||
## How to update scripts
|
||||
|
||||
Several tags in the format `*utils` are configured to update the different scripts, to be used with the update-utils.yml playbook :
|
||||
|
||||
* utils : update scripts from base role, utils.yml task
|
||||
* motd-utils : update script from post-install role, motd.yml task
|
||||
* evomaintenance-utils : update scripts from evomaintenance role, main.yml task
|
||||
* evocheck-utils : update scripts from evocheck role, main.yml task
|
||||
* nagios-nrpe-utils : update scripts and checks from nagios-nrpe role, main.yml task
|
||||
* etc-git-utils : update scripts from etc-git role, utils.yml task
|
||||
|
||||
## Contributions
|
||||
|
||||
See the [contribution guidelines](CONTRIBUTING.md)
|
||||
|
|
|
@ -1,42 +1,62 @@
|
|||
# yamllint disable rule:line-length
|
||||
# Playbook command
|
||||
# First use (become_method: su) :
|
||||
# First use :
|
||||
# ansible-playbook evolixisation.yml --ask-vault-pass -CDki hosts -u root -l HOSTNAME
|
||||
# Subsequent use (become_method: sudo) :
|
||||
# ansible-playbook evolixisation.yml --ask-vault-pass -CDKi hosts --skip-tags pf -l HOSTNAME
|
||||
# Subsequent use :
|
||||
# ansible-playbook evolixisation.yml --ask-vault-pass -CDKi hosts --skip-tags pf,users,generateldif-exec -l HOSTNAME
|
||||
|
||||
## EXAMPLE OF PLAYBOOK - PLEASE USE YOUR OWN PLAYBOOK
|
||||
|
||||
---
|
||||
- name: Evolixisation of an OpenBSD system
|
||||
hosts: openbsd
|
||||
become: true
|
||||
become_user: root
|
||||
become_method: sudo
|
||||
# become_method: su
|
||||
|
||||
|
||||
vars_files:
|
||||
- vars/main.yml
|
||||
- vars/evolix-main.yml
|
||||
- vars/evolinux-secrets.yml
|
||||
|
||||
roles:
|
||||
- etc-git
|
||||
- base
|
||||
- forwarding
|
||||
- pf
|
||||
- accounts
|
||||
- nagios-nrpe
|
||||
- evocheck
|
||||
- post-install
|
||||
# - openvpn
|
||||
# - ospf
|
||||
# - bgp
|
||||
# - { role: collectd, collectd_server: "127.0.0.1" }
|
||||
|
||||
post_tasks:
|
||||
- include: "tasks/commit_etc_git.yml"
|
||||
vars:
|
||||
commit_message: "Ansible - Evolixisation"
|
||||
- include_role:
|
||||
name: evocheck
|
||||
tasks_from: exec.yml
|
||||
# - name: Evolixisation of an OpenBSD system
|
||||
# hosts: openbsd
|
||||
# become: true
|
||||
# become_user: root
|
||||
# become_method: sudo
|
||||
#
|
||||
# vars_files:
|
||||
# - vars/main.yml
|
||||
# - vars/evolix-main.yml
|
||||
# - vars/evolinux-secrets.yml
|
||||
#
|
||||
# vars:
|
||||
# client_number: "XXX"
|
||||
# monitoring_mode: "everytime"
|
||||
#
|
||||
# pre_tasks:
|
||||
# - include_role:
|
||||
# name: etc-git
|
||||
# tasks_from: commit.yml
|
||||
# vars:
|
||||
# commit_message: "Ansible pre-run evolisation.yml"
|
||||
# when: not ansible_check_mode
|
||||
# tags: always
|
||||
#
|
||||
# roles:
|
||||
# - evomaintenance
|
||||
# - etc-git
|
||||
# - base
|
||||
# - forwarding
|
||||
# - pf
|
||||
# - accounts
|
||||
# - nagios-nrpe
|
||||
# - evocheck
|
||||
# - evobackup
|
||||
# - post-install
|
||||
# # - ospf
|
||||
# # - bgp
|
||||
# # - { role: collectd, collectd_server: "127.0.0.1" }
|
||||
# # - logsentry
|
||||
#
|
||||
# post_tasks:
|
||||
# - include_role:
|
||||
# name: etc-git
|
||||
# tasks_from: commit.yml
|
||||
# vars:
|
||||
# commit_message: "Ansible post-run evolisation.yml"
|
||||
# when: not ansible_check_mode
|
||||
# tags: always
|
||||
#
|
||||
# - include_role:
|
||||
# name: evocheck
|
||||
# tasks_from: exec.yml
|
||||
|
|
2
hosts
2
hosts
|
@ -2,4 +2,4 @@
|
|||
foo.example.com ansible_host=192.0.2.1
|
||||
|
||||
[openbsd:vars]
|
||||
ansible_python_interpreter=/usr/local/bin/python3.9
|
||||
ansible_python_interpreter=/usr/local/bin/python
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
- name: Install ansible's prerequisite
|
||||
# yamllint disable-line rule:line-length
|
||||
raw: export PKG_PATH=http://ftp.eu.openbsd.org/pub/OpenBSD/$(uname -r)/packages/$(uname -p)/; pkg_add -z python-3
|
||||
ansible.builtin.raw: export PKG_PATH=http://ftp.eu.openbsd.org/pub/OpenBSD/$(uname -r)/packages/$(uname -p)/; pkg_add -z python-3
|
||||
changed_when: true
|
||||
|
||||
# vim:ft=ansible
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
evobsd_root_login: "no"
|
||||
|
||||
# Defines which groups of users are created
|
||||
evobsd_users_create: "always"
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
|
||||
- name: reload sshd
|
||||
service:
|
||||
ansible.builtin.service:
|
||||
name: sshd
|
||||
state: reloaded
|
||||
|
|
|
@ -1,47 +1,68 @@
|
|||
# yamllint disable rule:line-length
|
||||
---
|
||||
- name: "Create {{ evobsd_ssh_group }} group"
|
||||
group:
|
||||
name: "{{ evobsd_ssh_group }}"
|
||||
- name: "Create {{ evobsd_internal_group }}, {{ evobsd_ssh_group }}, {{ evobsd_sudo_group }} group"
|
||||
ansible.builtin.group:
|
||||
name: "{{ item }}"
|
||||
system: true
|
||||
with_items:
|
||||
- "{{ evobsd_internal_group }}"
|
||||
- "{{ evobsd_ssh_group }}"
|
||||
- "{{ evobsd_sudo_group }}"
|
||||
tags:
|
||||
- accounts
|
||||
- admin
|
||||
|
||||
- name: "Create {{ evobsd_sudo_group }} group"
|
||||
group:
|
||||
name: "{{ evobsd_sudo_group }}"
|
||||
system: true
|
||||
|
||||
- name: Create user accounts
|
||||
- name: "Create user accounts"
|
||||
include: user.yml
|
||||
vars:
|
||||
user: "{{ item.value }}"
|
||||
with_dict: "{{ evolix_users }}"
|
||||
when: evolix_users != {}
|
||||
when:
|
||||
- user.create == evobsd_users_create
|
||||
- evolix_users != {}
|
||||
tags:
|
||||
- accounts
|
||||
- admin
|
||||
- users
|
||||
|
||||
- name: verify AllowGroups directive
|
||||
command: "grep -E '^AllowGroups' /etc/ssh/sshd_config"
|
||||
- name: "Verify AllowGroups directive"
|
||||
ansible.builtin.command: "grep -E '^AllowGroups' /etc/ssh/sshd_config"
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
check_mode: false
|
||||
register: grep_allowgroups_ssh
|
||||
tags:
|
||||
- accounts
|
||||
- admin
|
||||
|
||||
- name: verify AllowUsers directive
|
||||
command: "grep -E '^AllowUsers' /etc/ssh/sshd_config"
|
||||
- name: "Verify AllowUsers directive"
|
||||
ansible.builtin.command: "grep -E '^AllowUsers' /etc/ssh/sshd_config"
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
check_mode: false
|
||||
register: grep_allowusers_ssh
|
||||
tags:
|
||||
- accounts
|
||||
- admin
|
||||
|
||||
- name: "Check that AllowUsers and AllowGroup do not override each other"
|
||||
assert:
|
||||
ansible.builtin.assert:
|
||||
that: "not (grep_allowusers_ssh.rc == 0 and grep_allowgroups_ssh.rc == 0)"
|
||||
msg: "We can't deal with AllowUsers and AllowGroups at the same time"
|
||||
tags:
|
||||
- accounts
|
||||
- admin
|
||||
|
||||
- name: "If AllowGroups is present then use it"
|
||||
set_fact:
|
||||
ansible.builtin.set_fact:
|
||||
ssh_allowgroups:
|
||||
"{{ (grep_allowgroups_ssh.rc == 0) or (grep_allowusers_ssh.rc != 0) }}"
|
||||
tags:
|
||||
- accounts
|
||||
- admin
|
||||
|
||||
- name: "Add AllowGroups sshd directive with '{{ evobsd_ssh_group }}'"
|
||||
lineinfile:
|
||||
ansible.builtin.lineinfile:
|
||||
dest: /etc/ssh/sshd_config
|
||||
line: "\nAllowGroups {{ evobsd_ssh_group }}"
|
||||
insertafter: 'Subsystem'
|
||||
|
@ -50,9 +71,12 @@
|
|||
when:
|
||||
- ssh_allowgroups
|
||||
- grep_allowgroups_ssh.rc == 1
|
||||
tags:
|
||||
- accounts
|
||||
- admin
|
||||
|
||||
- name: "Append '{{ evobsd_ssh_group }}' to AllowGroups sshd directive"
|
||||
replace:
|
||||
ansible.builtin.replace:
|
||||
dest: /etc/ssh/sshd_config
|
||||
regexp: '^(AllowGroups ((?!\b{{ evobsd_ssh_group }}\b).)*)$'
|
||||
replace: '\1 {{ evobsd_ssh_group }}'
|
||||
|
@ -61,25 +85,34 @@
|
|||
when:
|
||||
- ssh_allowgroups
|
||||
- grep_allowgroups_ssh.rc == 0
|
||||
tags:
|
||||
- accounts
|
||||
- admin
|
||||
|
||||
- name: "Security directives for EvoBSD"
|
||||
blockinfile:
|
||||
ansible.builtin.blockinfile:
|
||||
dest: /etc/ssh/sshd_config
|
||||
marker: "# {mark} EVOBSD PASSWORD RESTRICTIONS"
|
||||
block: |
|
||||
Match Address {{ evolix_trusted_ips | join(',') }}
|
||||
PasswordAuthentication yes
|
||||
Match Group {{ evobsd_ssh_group }}
|
||||
Match Group {{ evobsd_internal_group }}
|
||||
PasswordAuthentication no
|
||||
insertafter: EOF
|
||||
validate: '/usr/sbin/sshd -t -f %s'
|
||||
notify: reload sshd
|
||||
when:
|
||||
- evolix_trusted_ips != []
|
||||
tags:
|
||||
- accounts
|
||||
- admin
|
||||
|
||||
- name: "Disable root login"
|
||||
replace:
|
||||
ansible.builtin.replace:
|
||||
dest: /etc/ssh/sshd_config
|
||||
regexp: '^PermitRootLogin (yes|without-password|prohibit-password)'
|
||||
replace: "PermitRootLogin no"
|
||||
regexp: '^PermitRootLogin\s+(yes|without-password|prohibit-password)'
|
||||
replace: "PermitRootLogin {{ evobsd_root_login }}"
|
||||
notify: reload sshd
|
||||
tags:
|
||||
- accounts
|
||||
- admin
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
# yamllint disable rule:line-length
|
||||
---
|
||||
- name: "Group '{{ user.name }}' is present"
|
||||
group:
|
||||
ansible.builtin.group:
|
||||
state: present
|
||||
name: "{{ user.name }}"
|
||||
gid: "{{ user.uid }}"
|
||||
tags:
|
||||
- accounts
|
||||
- admin
|
||||
- users
|
||||
|
||||
- name: "User '{{ user.name }}' is present"
|
||||
user:
|
||||
ansible.builtin.user:
|
||||
state: present
|
||||
name: '{{ user.name }}'
|
||||
uid: '{{ user.uid }}'
|
||||
|
@ -16,40 +21,70 @@
|
|||
shell: /bin/ksh
|
||||
append: true
|
||||
tags:
|
||||
- accounts
|
||||
- admin
|
||||
- users
|
||||
|
||||
- name: "Gather available local users for usage in check_mode"
|
||||
ansible.builtin.getent:
|
||||
database: passwd
|
||||
tags:
|
||||
- accounts
|
||||
- admin
|
||||
- users
|
||||
|
||||
- name: "Home directory for '{{ user.name }}' is only accesible by owner"
|
||||
file:
|
||||
ansible.builtin.file:
|
||||
name: '/home/{{ user.name }}'
|
||||
mode: "0700"
|
||||
owner: "{{ user.name }}"
|
||||
group: "{{ user.name }}"
|
||||
state: directory
|
||||
when: user.name in getent_passwd.keys()
|
||||
tags:
|
||||
- accounts
|
||||
- admin
|
||||
- users
|
||||
|
||||
- name: "SSH public keys for '{{ user.name }}' are present"
|
||||
authorized_key:
|
||||
ansible.posix.authorized_key:
|
||||
user: "{{ user.name }}"
|
||||
key: "{{ ssk_key }}"
|
||||
state: present
|
||||
with_items: "{{ user.ssh_keys }}"
|
||||
loop_control:
|
||||
loop_var: ssk_key
|
||||
when: user.ssh_keys is defined
|
||||
when:
|
||||
- user.ssh_keys is defined
|
||||
- user.name in getent_passwd.keys()
|
||||
tags:
|
||||
- accounts
|
||||
- admin
|
||||
- users
|
||||
|
||||
- name: "Add {{ user.name }} to {{ evobsd_ssh_group }} group"
|
||||
user:
|
||||
name: "{{ user.name }}"
|
||||
groups: "{{ evobsd_ssh_group }}"
|
||||
append: true
|
||||
- name: "Gather available local groups for usage in check_mode"
|
||||
ansible.builtin.getent:
|
||||
database: group
|
||||
tags:
|
||||
- accounts
|
||||
- admin
|
||||
- users
|
||||
|
||||
- name: "Add {{ user.name }} to {{ evobsd_sudo_group }} group"
|
||||
user:
|
||||
- name: "Add {{ user.name }} to {{ evobsd_internal_group }}, {{ evobsd_ssh_group }}, {{ evobsd_sudo_group }} group"
|
||||
ansible.builtin.user:
|
||||
name: "{{ user.name }}"
|
||||
groups: "{{ evobsd_sudo_group }}"
|
||||
groups: "{{ groups_item }}"
|
||||
append: true
|
||||
with_items:
|
||||
- "{{ evobsd_internal_group }}"
|
||||
- "{{ evobsd_ssh_group }}"
|
||||
- "{{ evobsd_sudo_group }}"
|
||||
loop_control:
|
||||
loop_var: groups_item
|
||||
when:
|
||||
- user.name in getent_passwd.keys()
|
||||
- groups_item in getent_group.keys()
|
||||
tags:
|
||||
- accounts
|
||||
- admin
|
||||
- users
|
||||
|
|
|
@ -1,38 +1,33 @@
|
|||
# yamllint disable rule:line-length
|
||||
---
|
||||
|
||||
# dotfiles.yml
|
||||
evobsd_system_timeout: 36000
|
||||
evobsd_path: "$HOME/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
|
||||
evobsd_alias_fwupdate: false
|
||||
|
||||
# mail.yml
|
||||
general_alert_email: "root@localhost"
|
||||
|
||||
# cron.yml
|
||||
cron_root_path: "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
|
||||
|
||||
# ntp.yml
|
||||
is_ntpd_server: false
|
||||
ntpd_servers: "ntp.evolix.net"
|
||||
|
||||
general_alert_email: "root@localhost"
|
||||
general_technical_realm: "example.com"
|
||||
# fstab.yml
|
||||
evobsd_fstab_softdep: true
|
||||
evobsd_fstab_noatime: true
|
||||
evobsd_fstab_noexec: true
|
||||
|
||||
evomaintenance_realm: "example.com"
|
||||
evomaintenance_alert_email:
|
||||
"evomaintenance-{{ inventory_hostname }}@{{ evomaintenance_realm }}"
|
||||
evomaintenance_hostname:
|
||||
"{{ inventory_hostname }}.{{ general_technical_realm }}"
|
||||
evomaintenance_pg_host: null
|
||||
evomaintenance_pg_passwd: null
|
||||
evomaintenance_pg_db: null
|
||||
evomaintenance_pg_table: null
|
||||
evomaintenance_from_domain: "{{ evomaintenance_realm }}"
|
||||
evomaintenance_from: "evomaintenance@{{ evomaintenance_from_domain }}"
|
||||
evomaintenance_full_from: "Evomaintenance <{{ evomaintenance_from }}>"
|
||||
evomaintenance_urgency_from: mama.doe@example.com
|
||||
evomaintenance_urgency_tel: "06.00.00.00.00"
|
||||
evomaintenance_install_vendor: false
|
||||
evomaintenance_force_config: true
|
||||
evomaintenance_api_endpoint: null
|
||||
evomaintenance_api_key: null
|
||||
evomaintenance_hook_api: true
|
||||
evomaintenance_hook_db: false
|
||||
evomaintenance_hook_commit: true
|
||||
evomaintenance_hook_mail: true
|
||||
evomaintenance_default_hosts: []
|
||||
evomaintenance_additional_hosts: []
|
||||
evomaintenance_hosts: >
|
||||
{{ evomaintenance_default_hosts
|
||||
| union(evomaintenance_additional_hosts)
|
||||
| unique }}
|
||||
# utils.yml
|
||||
evobsd_updateevobackupcanary_include: true
|
||||
evobsd_dumpserverstate_include: true
|
||||
|
||||
evobsd_path: >-
|
||||
"$HOME/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
|
||||
cron_root_path: "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
|
||||
# packages.yml
|
||||
evobsd_install_url: "https://cdn.openbsd.org/pub/OpenBSD"
|
||||
|
||||
# default_ssl.yml
|
||||
evobsd_default_ssl_cert: true
|
||||
evobsd_ssl_cert_hostname: "{{ inventory_hostname }}.{{ general_technical_realm }}"
|
||||
|
|
|
@ -0,0 +1,755 @@
|
|||
#!/bin/sh
|
||||
|
||||
PROGNAME="dump-server-state"
|
||||
REPOSITORY="https://gitea.evolix.org/evolix/dump-server-state"
|
||||
|
||||
VERSION="24.01"
|
||||
readonly VERSION
|
||||
|
||||
dump_dir=
|
||||
rc=0
|
||||
|
||||
# base functions
|
||||
|
||||
show_version() {
|
||||
cat <<END
|
||||
${PROGNAME} version ${VERSION}
|
||||
|
||||
Copyright 2018-2022 Evolix <info@evolix.fr>,
|
||||
Jérémy Lecour <jlecour@evolix.fr>,
|
||||
Éric Morino <emorino@evolix.fr>,
|
||||
Brice Waegeneire <bwaegeneire@evolix.fr>,
|
||||
Jérémy Dubois <jdubois@evolix.fr>
|
||||
and others.
|
||||
|
||||
${REPOSITORY}
|
||||
|
||||
${PROGNAME} comes with ABSOLUTELY NO WARRANTY.This is free software,
|
||||
and you are welcome to redistribute it under certain conditions.
|
||||
See the GNU General Public License v3.0 for details.
|
||||
END
|
||||
}
|
||||
show_help() {
|
||||
cat <<END
|
||||
${PROGNAME} is dumping information related to the state of the server.
|
||||
|
||||
Usage: ${PROGNAME} --dump-dir=/path/to/dump/directory [OPTIONS]
|
||||
|
||||
Main options
|
||||
-d, --dump-dir path to the directory where data will be stored
|
||||
-f, --force keep existing dump directory and its content
|
||||
-v, --verbose print details about each task
|
||||
-V, --version print version and exit
|
||||
-h, --help print this message and exit
|
||||
|
||||
Tasks options
|
||||
--all reset options to execute all tasks
|
||||
--none reset options to execute no task
|
||||
--[no-]etc copy of /etc (default: no)
|
||||
--[no-]packages copy of installed packages (default: yes)
|
||||
--[no-]uname copy of uname value (default: yes)
|
||||
--[no-]uptime copy of uptime value (default: yes)
|
||||
--[no-]processes copy of process list (default: yes)
|
||||
--[no-]fstat copy of network status (default: yes)
|
||||
--[no-]netcfg copy of network configuration (default: yes)
|
||||
--[no-]pfctl copy of PacketFilter values (default: yes)
|
||||
--[no-]sysctl copy of sysctl values (default: yes)
|
||||
--[no-]disks copy of MBR, partitions and disks information (default: yes)
|
||||
--[no-]mount copy of mount points (default: yes)
|
||||
--[no-]df copy of disk usage (default: yes)
|
||||
--[no-]dmesg copy of dmesg (default: yes)
|
||||
--[no-]rcctl copy of services states (default: yes)
|
||||
|
||||
Tasks options order matters. They are evaluated from left to right.
|
||||
Examples :
|
||||
* "[…] --none --uname" will do only the uname task
|
||||
* "[…] --all --no-etc" will do everything but the etc task
|
||||
* "[…] --etc --none --mysql" will do only the mysql task
|
||||
END
|
||||
}
|
||||
debug() {
|
||||
if [ "${VERBOSE}" = "1" ]; then
|
||||
msg="${1:-$(cat /dev/stdin)}"
|
||||
echo "${msg}"
|
||||
fi
|
||||
}
|
||||
|
||||
create_dump_dir() {
|
||||
debug "Task: Create ${dump_dir}"
|
||||
|
||||
last_result=$(mkdir -p "${dump_dir}" && chmod -R 755 "${dump_dir}")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ]; then
|
||||
debug "* mkdir/chmod OK"
|
||||
else
|
||||
debug "* mkdir/chmod ERROR :"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
}
|
||||
|
||||
task_etc() {
|
||||
debug "Task: /etc"
|
||||
|
||||
rsync_bin=$(command -v rsync)
|
||||
|
||||
if [ -n "${rsync_bin}" ]; then
|
||||
last_result=$(${rsync_bin} -ah --itemize-changes --exclude=.git /etc "${dump_dir}/")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ]; then
|
||||
debug "* rsync OK"
|
||||
else
|
||||
debug "* rsync ERROR :"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
else
|
||||
debug "* rsync not found"
|
||||
last_result=$(cp -r /etc "${dump_dir}/ && rm -rf ${dump_dir}/etc/.git")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ]; then
|
||||
debug "* cp OK"
|
||||
else
|
||||
debug "* cp ERROR :"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
task_packages() {
|
||||
debug "Task: List of installed packages"
|
||||
|
||||
last_result=$(pkg_info > "${dump_dir}/packages.txt")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ]; then
|
||||
debug "* pkg_info OK"
|
||||
else
|
||||
debug "* pkg_info ERROR :"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
|
||||
last_result=$(pkg_info -m > "${dump_dir}/packages_manual.txt")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ]; then
|
||||
debug "* pkg_info -m OK"
|
||||
else
|
||||
debug "* pkg_info -m ERROR :"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
}
|
||||
|
||||
task_uname() {
|
||||
debug "Task: uname"
|
||||
|
||||
last_result=$(uname -a > "${dump_dir}/uname.txt")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ]; then
|
||||
debug "* uname OK"
|
||||
else
|
||||
debug "* uname ERROR"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
}
|
||||
|
||||
task_uptime() {
|
||||
debug "Task: uptime"
|
||||
|
||||
last_result=$(uptime > "${dump_dir}/uptime.txt")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ]; then
|
||||
debug "* uptime OK"
|
||||
else
|
||||
debug "* uptime ERROR"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
}
|
||||
|
||||
task_processes() {
|
||||
debug "Task: Process list"
|
||||
|
||||
last_result=$(ps auwwx > "${dump_dir}/ps.txt")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ]; then
|
||||
debug "* ps OK"
|
||||
else
|
||||
debug "* ps ERROR"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
|
||||
pstree_bin=$(command -v pstree)
|
||||
|
||||
if [ -n "${pstree_bin}" ]; then
|
||||
last_result=$(${pstree_bin} -w > "${dump_dir}/pstree.txt")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ]; then
|
||||
debug "* pstree OK"
|
||||
else
|
||||
debug "* pstree ERROR"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
task_fstat() {
|
||||
debug "Task: Network status"
|
||||
|
||||
last_result=$({ fstat | head -1 ; fstat | grep internet ; } > "${dump_dir}/fstat.txt")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ]; then
|
||||
debug "* fstat OK"
|
||||
else
|
||||
debug "* fstat ERROR"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
}
|
||||
|
||||
task_netcfg() {
|
||||
debug "Task: Network configuration"
|
||||
|
||||
last_result=$(ifconfig -A > "${dump_dir}/ifconfig.txt")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ]; then
|
||||
debug "* ifconfig OK"
|
||||
else
|
||||
debug "* ifconfig ERROR"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
|
||||
last_result=$(netstat -nr > "${dump_dir}/routes.txt")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ]; then
|
||||
debug "* netstat OK"
|
||||
else
|
||||
debug "* netstat ERROR"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
}
|
||||
|
||||
task_pfctl() {
|
||||
debug "Task : PacketFilter"
|
||||
|
||||
last_result=$(pfctl -sa > "${dump_dir}/pfctl.txt")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ]; then
|
||||
debug "* pfctl OK"
|
||||
else
|
||||
debug "* pfctl ERROR"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
}
|
||||
|
||||
task_sysctl() {
|
||||
debug "Task: sysctl values"
|
||||
|
||||
sysctl_bin=$(command -v sysctl)
|
||||
|
||||
if [ -n "${sysctl_bin}" ]; then
|
||||
last_result=$(${sysctl_bin} -a 2>/dev/null | sort -h > "${dump_dir}/sysctl.txt")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ]; then
|
||||
debug "* sysctl OK"
|
||||
else
|
||||
debug "* sysctl ERROR"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
else
|
||||
debug "* sysctl not found"
|
||||
fi
|
||||
}
|
||||
|
||||
task_disks() {
|
||||
debug "Task: Disks"
|
||||
|
||||
sysctl_bin=$(command -v sysctl)
|
||||
|
||||
if [ -n "${sysctl_bin}" ]; then
|
||||
disks=$(${sysctl_bin} hw.disknames | grep -Eo "(wd|sd)[0-9]*")
|
||||
for disk in ${disks}; do
|
||||
disklabel_bin=$(command -v disklabel)
|
||||
if [ -n "${disklabel_bin}" ]; then
|
||||
last_result=$(${disklabel_bin} "${disk}" 2>&1 > "${dump_dir}/partitions-${disk}")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ] || { [ ${last_rc} -ne 0 ] && [ "${last_result}" = "disklabel: DIOCGDINFO: Input/output error" ]; }; then
|
||||
debug "* disklabel ${disk} OK"
|
||||
else
|
||||
debug "* disklabel ${disk} ERROR"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
else
|
||||
debug "* disklabel not found"
|
||||
fi
|
||||
|
||||
bioctl_bin=$(command -v bioctl)
|
||||
if [ -n "${bioctl_bin}" ]; then
|
||||
last_result=$(${bioctl_bin} "${disk}" 2>&1 > "${dump_dir}/bioctl-${disk}")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ] || { [ ${last_rc} -ne 0 ] && [ "${last_result}" = "bioctl: DIOCINQ: Inappropriate ioctl for device" ]; } || { [ ${last_rc} -ne 0 ] && [ "${last_result}" = "bioctl: BIOCINQ: Input/output error" ]; }; then
|
||||
debug "* bioctl ${disk} OK"
|
||||
else
|
||||
debug "* bioctl ${disk} ERROR"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
else
|
||||
debug "* bioctl not found"
|
||||
fi
|
||||
|
||||
atactl_bin=$(command -v atactl)
|
||||
if [ -n "${atactl_bin}" ]; then
|
||||
last_result=$(${atactl_bin} "${disk}" 2>&1 > "${dump_dir}/atactl-${disk}")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ] || { [ ${last_rc} -ne 0 ] && [ "${last_result}" = "atactl: ATA device returned error register 0" ]; } || { [ ${last_rc} -ne 0 ] && [ "${last_result}" = "atactl: ATAIOCCOMMAND failed: Input/output error" ]; }; then
|
||||
debug "* atactl ${disk} OK"
|
||||
else
|
||||
debug "* atactl ${disk} ERROR"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
else
|
||||
debug "* atactl not found"
|
||||
fi
|
||||
|
||||
done
|
||||
cat "${dump_dir}"/partitions-* > "${dump_dir}/partitions"
|
||||
cat "${dump_dir}"/bioctl-* > "${dump_dir}/bioctl"
|
||||
cat "${dump_dir}"/atactl-* > "${dump_dir}/atactl"
|
||||
else
|
||||
debug "* sysctl not found"
|
||||
fi
|
||||
}
|
||||
|
||||
task_mount() {
|
||||
debug "Task: Mount points"
|
||||
|
||||
mount_bin=$(command -v mount)
|
||||
|
||||
if [ -n "${mount_bin}" ]; then
|
||||
last_result=$(${mount_bin} > "${dump_dir}/mount.txt")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ]; then
|
||||
debug "* mount points OK"
|
||||
else
|
||||
debug "* mount points ERROR"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
else
|
||||
debug "* mount not found"
|
||||
fi
|
||||
}
|
||||
|
||||
task_df() {
|
||||
debug "Task: df"
|
||||
|
||||
df_bin=$(command -v df)
|
||||
|
||||
if [ -n "${df_bin}" ]; then
|
||||
last_result=$(${df_bin} > "${dump_dir}/df.txt")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ]; then
|
||||
debug "* df OK"
|
||||
else
|
||||
debug "* df ERROR"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
else
|
||||
debug "* df not found"
|
||||
fi
|
||||
}
|
||||
|
||||
task_dmesg() {
|
||||
debug "Task: dmesg"
|
||||
|
||||
dmesg_bin=$(command -v dmesg)
|
||||
|
||||
if [ -n "${dmesg_bin}" ]; then
|
||||
last_result=$(${dmesg_bin} > "${dump_dir}/dmesg.txt")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ]; then
|
||||
debug "* dmesg OK"
|
||||
else
|
||||
debug "* dmesg ERROR"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
|
||||
last_result=$(${dmesg_bin} -s > "${dump_dir}/dmesg-console.txt")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ]; then
|
||||
debug "* dmesg console buffer OK"
|
||||
else
|
||||
debug "* dmesg console buffer ERROR"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
|
||||
else
|
||||
debug "* dmesg not found"
|
||||
fi
|
||||
}
|
||||
|
||||
task_rcctl() {
|
||||
debug "Task: Services"
|
||||
|
||||
rcctl_bin=$(command -v rcctl)
|
||||
|
||||
if [ -n "${rcctl_bin}" ]; then
|
||||
last_result=$(${rcctl_bin} ls failed > "${dump_dir}/rcctl-failed-services.txt")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ] || [ ${last_rc} -eq 1 ]; then
|
||||
debug "* failed services OK"
|
||||
else
|
||||
debug "* failed services ERROR"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
|
||||
last_result=$(${rcctl_bin} ls on > "${dump_dir}/rcctl-on-services.txt")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ]; then
|
||||
debug "* on services OK"
|
||||
else
|
||||
debug "* on services ERROR"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
|
||||
last_result=$(${rcctl_bin} ls started > "${dump_dir}/rcctl-started-services.txt")
|
||||
last_rc=$?
|
||||
|
||||
if [ ${last_rc} -eq 0 ]; then
|
||||
debug "* started services OK"
|
||||
else
|
||||
debug "* started services ERROR"
|
||||
debug "${last_result}"
|
||||
rc=10
|
||||
fi
|
||||
|
||||
else
|
||||
debug "* rcctl not found"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
main() {
|
||||
if [ -z "${dump_dir}" ]; then
|
||||
echo "ERROR: You must provide the --dump-dir argument" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -d "${dump_dir}" ]; then
|
||||
if [ "${FORCE}" != "1" ]; then
|
||||
echo "ERROR: The dump directory ${dump_dir} already exists. Delete it first." >&2
|
||||
exit 2
|
||||
fi
|
||||
else
|
||||
create_dump_dir
|
||||
fi
|
||||
|
||||
if [ "${TASK_ETC}" -eq 1 ]; then
|
||||
task_etc
|
||||
fi
|
||||
if [ "${TASK_PACKAGES}" -eq 1 ]; then
|
||||
task_packages
|
||||
fi
|
||||
if [ "${TASK_UNAME}" -eq 1 ]; then
|
||||
task_uname
|
||||
fi
|
||||
if [ "${TASK_UPTIME}" -eq 1 ]; then
|
||||
task_uptime
|
||||
fi
|
||||
if [ "${TASK_PROCESSES}" -eq 1 ]; then
|
||||
task_processes
|
||||
fi
|
||||
if [ "${TASK_FSTAT}" -eq 1 ]; then
|
||||
task_fstat
|
||||
fi
|
||||
if [ "${TASK_NETCFG}" -eq 1 ]; then
|
||||
task_netcfg
|
||||
fi
|
||||
if [ "${TASK_PFCTL}" -eq 1 ]; then
|
||||
task_pfctl
|
||||
fi
|
||||
if [ "${TASK_SYSCTL}" -eq 1 ]; then
|
||||
task_sysctl
|
||||
fi
|
||||
if [ "${TASK_DISKS}" -eq 1 ]; then
|
||||
task_disks
|
||||
fi
|
||||
if [ "${TASK_MOUNT}" -eq 1 ]; then
|
||||
task_mount
|
||||
fi
|
||||
if [ "${TASK_DF}" -eq 1 ]; then
|
||||
task_df
|
||||
fi
|
||||
if [ "${TASK_DMESG}" -eq 1 ]; then
|
||||
task_dmesg
|
||||
fi
|
||||
if [ "${TASK_RCCTL}" -eq 1 ]; then
|
||||
task_rcctl
|
||||
fi
|
||||
|
||||
|
||||
debug "=> Your dump is available at ${dump_dir}"
|
||||
exit ${rc}
|
||||
}
|
||||
|
||||
# parse options
|
||||
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
|
||||
while :; do
|
||||
case $1 in
|
||||
-h|-\?|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
-V|--version)
|
||||
show_version
|
||||
exit 0
|
||||
;;
|
||||
-v|--verbose)
|
||||
VERBOSE=1
|
||||
;;
|
||||
|
||||
-f|--force)
|
||||
FORCE=1
|
||||
;;
|
||||
|
||||
-d|--dump-dir)
|
||||
# with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
dump_dir=$2
|
||||
shift
|
||||
else
|
||||
printf 'ERROR: "-d|--dump-dir" requires a non-empty option argument.\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--dump-dir=?*)
|
||||
# with value speparated by =
|
||||
dump_dir=${1#*=}
|
||||
;;
|
||||
--dump-dir=)
|
||||
# without value
|
||||
printf 'ERROR: "--dump-dir" requires a non-empty option argument.\n' >&2
|
||||
exit 1
|
||||
;;
|
||||
|
||||
--all)
|
||||
for option in \
|
||||
TASK_ETC \
|
||||
TASK_PACKAGES \
|
||||
TASK_UNAME \
|
||||
TASK_UPTIME \
|
||||
TASK_PROCESSES \
|
||||
TASK_FSTAT \
|
||||
TASK_NETCFG \
|
||||
TASK_PFCTL \
|
||||
TASK_SYSCTL \
|
||||
TASK_DISKS \
|
||||
TASK_MOUNT \
|
||||
TASK_DF \
|
||||
TASK_DMESG \
|
||||
TASK_RCCTL
|
||||
do
|
||||
eval "${option}=1"
|
||||
done
|
||||
;;
|
||||
|
||||
--none)
|
||||
for option in \
|
||||
TASK_ETC \
|
||||
TASK_PACKAGES \
|
||||
TASK_UNAME \
|
||||
TASK_UPTIME \
|
||||
TASK_PROCESSES \
|
||||
TASK_FSTAT \
|
||||
TASK_NETCFG \
|
||||
TASK_PFCTL \
|
||||
TASK_SYSCTL \
|
||||
TASK_DISKS \
|
||||
TASK_MOUNT \
|
||||
TASK_DF \
|
||||
TASK_DMESG \
|
||||
TASK_RCCTL
|
||||
do
|
||||
eval "${option}=0"
|
||||
done
|
||||
;;
|
||||
|
||||
--etc)
|
||||
TASK_ETC=1
|
||||
;;
|
||||
--no-etc)
|
||||
TASK_ETC=0
|
||||
;;
|
||||
|
||||
--packages)
|
||||
TASK_PACKAGES=1
|
||||
;;
|
||||
--no-packages)
|
||||
TASK_PACKAGES=0
|
||||
;;
|
||||
|
||||
--uname)
|
||||
TASK_UNAME=1
|
||||
;;
|
||||
--no-uname)
|
||||
TASK_UNAME=0
|
||||
;;
|
||||
|
||||
--uptime)
|
||||
TASK_UPTIME=1
|
||||
;;
|
||||
--no-uptime)
|
||||
TASK_UPTIME=0
|
||||
;;
|
||||
|
||||
--processes)
|
||||
TASK_PROCESSES=1
|
||||
;;
|
||||
--no-processes)
|
||||
TASK_PROCESSES=0
|
||||
;;
|
||||
|
||||
--fstat)
|
||||
TASK_FSTAT=1
|
||||
;;
|
||||
--no-fstat)
|
||||
TASK_FSTAT=0
|
||||
;;
|
||||
|
||||
--netcfg)
|
||||
TASK_NETCFG=1
|
||||
;;
|
||||
--no-netcfg)
|
||||
TASK_NETCFG=0
|
||||
;;
|
||||
|
||||
--pfctl)
|
||||
TASK_PFCTL=1
|
||||
;;
|
||||
--no-pfctl)
|
||||
TASK_PFCTL=0
|
||||
;;
|
||||
|
||||
--sysctl)
|
||||
TASK_SYSCTL=1
|
||||
;;
|
||||
--no-sysctl)
|
||||
TASK_SYSCTL=0
|
||||
;;
|
||||
|
||||
--disks)
|
||||
TASK_DISKS=1
|
||||
;;
|
||||
--no-disks)
|
||||
TASK_DISKS=0
|
||||
;;
|
||||
|
||||
--mount)
|
||||
TASK_MOUNT=1
|
||||
;;
|
||||
--no-mount)
|
||||
TASK_MOUNT=0
|
||||
;;
|
||||
|
||||
--df)
|
||||
TASK_DF=1
|
||||
;;
|
||||
--no-df)
|
||||
TASK_DF=0
|
||||
;;
|
||||
|
||||
--dmesg)
|
||||
TASK_DMESG=1
|
||||
;;
|
||||
--no-dmesg)
|
||||
TASK_DMESG=0
|
||||
;;
|
||||
|
||||
--rcctl)
|
||||
TASK_RCCTL=1
|
||||
;;
|
||||
--no-rcctl)
|
||||
TASK_RCCTL=0
|
||||
;;
|
||||
|
||||
--)
|
||||
# End of all options.
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-?*)
|
||||
# ignore unknown options
|
||||
printf 'WARN: Unknown option : %s\n' "$1" >&2
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
# Default case: If no more options then break out of the loop.
|
||||
break
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
# Default values
|
||||
: "${VERBOSE:=0}"
|
||||
: "${FORCE:=0}"
|
||||
: "${TASK_ETC:=0}"
|
||||
: "${TASK_PACKAGES:=1}"
|
||||
: "${TASK_UNAME:=1}"
|
||||
: "${TASK_UPTIME:=1}"
|
||||
: "${TASK_PROCESSES:=1}"
|
||||
: "${TASK_FSTAT:=1}"
|
||||
: "${TASK_NETCFG:=1}"
|
||||
: "${TASK_PFCTL:=1}"
|
||||
: "${TASK_SYSCTL:=1}"
|
||||
: "${TASK_DISKS:=1}"
|
||||
: "${TASK_MOUNT:=1}"
|
||||
: "${TASK_DF:=1}"
|
||||
: "${TASK_DMESG:=1}"
|
||||
: "${TASK_RCCTL:=1}"
|
||||
|
||||
export LC_ALL=C
|
||||
|
||||
set -u
|
||||
|
||||
main
|
|
@ -1 +0,0 @@
|
|||
https://cdn.openbsd.org/pub/OpenBSD
|
|
@ -1,17 +0,0 @@
|
|||
alias vi='vim'
|
||||
sudo() { if [[ $# == "1" ]] && [[ $1 == "su" ]]; then command sudo -i; else command sudo "$@"; fi }
|
||||
|
||||
##
|
||||
# Caracterisation du shell
|
||||
##
|
||||
|
||||
bind -m '^L'='^U 'clear'^M^Y'
|
||||
bind '^[[4~'=end-of-line
|
||||
bind '^[[1~'=beginning-of-line
|
||||
bind '^[[3~'=delete-char-forward
|
||||
bind '^[[8~'=end-of-line
|
||||
bind '^[[7~'=beginning-of-line
|
||||
bind '^[Oc'=forward-word
|
||||
bind '^[Od'=backward-word
|
||||
bind '^[^[[C'=forward-word
|
||||
bind '^[^[[D'=backward-word
|
|
@ -13,3 +13,7 @@
|
|||
/var/log/pflog 600 30 * $D0 ZB "pkill -HUP -u root -U root -t - -x pflogd"
|
||||
/var/www/logs/access.log 644 52 * $W1 Z "pkill -USR1 -u root -U root -x httpd"
|
||||
/var/www/logs/error.log 644 52 * $W1 Z "pkill -USR1 -u root -U root -x httpd"
|
||||
/var/log/munin/munin-html.log 644 52 * $W5D4 Z
|
||||
/var/log/munin/munin-limits.log 644 52 * $W5D4 Z
|
||||
/var/log/munin/munin-node.log 644 52 * $W5D4 Z
|
||||
/var/log/munin/munin-update.log 644 52 * $W5D4 Z
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
#!/bin/sh
|
||||
|
||||
PROGNAME="update-evobackup-canary"
|
||||
REPOSITORY="https://gitea.evolix.org/evolix/evobackup"
|
||||
|
||||
VERSION="22.06"
|
||||
readonly VERSION
|
||||
|
||||
# base functions
|
||||
|
||||
show_version() {
|
||||
cat <<END
|
||||
${PROGNAME} version ${VERSION}
|
||||
|
||||
Copyright 2022 Evolix <info@evolix.fr>,
|
||||
Jérémy Lecour <jlecour@evolix.fr>,
|
||||
and others.
|
||||
|
||||
${REPOSITORY}
|
||||
|
||||
${PROGNAME} comes with ABSOLUTELY NO WARRANTY. This is free software,
|
||||
and you are welcome to redistribute it under certain conditions.
|
||||
See the GNU General Public License v3.0 for details.
|
||||
END
|
||||
}
|
||||
show_help() {
|
||||
cat <<END
|
||||
${PROGNAME} is updating a canary file for evobackup.
|
||||
|
||||
Usage: ${PROGNAME} [OPTIONS]
|
||||
|
||||
Main options
|
||||
-w, --who who has updated the file (default: logname())
|
||||
-f, --file path of the canary file (default: /zzz_evobackup_canary)
|
||||
-V, --version print version and exit
|
||||
-h, --help print this message and exit
|
||||
END
|
||||
}
|
||||
|
||||
main() {
|
||||
if [ -z "${who:-}" ]; then
|
||||
who=$(logname)
|
||||
fi
|
||||
if [ -z "${canary_file:-}" ]; then
|
||||
canary_file="/zzz_evobackup_canary"
|
||||
fi
|
||||
# This option is supported both on OpenBSD which does not use GNU date and on Debian
|
||||
date=$(date "+%FT%T%z")
|
||||
|
||||
printf "%s %s\n" "${date}" "${who}" >> "${canary_file}"
|
||||
}
|
||||
|
||||
# parse options
|
||||
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
|
||||
while :; do
|
||||
case $1 in
|
||||
-h|-\?|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
-V|--version)
|
||||
show_version
|
||||
exit 0
|
||||
;;
|
||||
|
||||
-w|--who)
|
||||
# with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
who=$2
|
||||
shift
|
||||
else
|
||||
printf 'ERROR: "-w|--who" requires a non-empty option argument.\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--who=?*)
|
||||
# with value speparated by =
|
||||
who=${1#*=}
|
||||
;;
|
||||
--who=)
|
||||
# without value
|
||||
printf 'ERROR: "--who" requires a non-empty option argument.\n' >&2
|
||||
exit 1
|
||||
;;
|
||||
|
||||
-f|--file)
|
||||
# with value separated by space
|
||||
if [ -n "$2" ]; then
|
||||
canary_file=$2
|
||||
shift
|
||||
else
|
||||
printf 'ERROR: "-f|--file" requires a non-empty option argument.\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--file=?*)
|
||||
# with value speparated by =
|
||||
canary_file=${1#*=}
|
||||
;;
|
||||
--file=)
|
||||
# without value
|
||||
printf 'ERROR: "--file" requires a non-empty option argument.\n' >&2
|
||||
exit 1
|
||||
;;
|
||||
|
||||
--)
|
||||
# End of all options.
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-?*)
|
||||
# ignore unknown options
|
||||
printf 'WARN: Unknown option : %s\n' "$1" >&2
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
# Default case: If no more options then break out of the loop.
|
||||
break
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
export LC_ALL=C
|
||||
|
||||
set -u
|
||||
|
||||
main
|
|
@ -1,450 +0,0 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Script Evobackup client
|
||||
# See https://gitea.evolix.org/evolix/evobackup
|
||||
#
|
||||
# Author: Gregory Colpart <reg@evolix.fr>
|
||||
# Contributors:
|
||||
# Romain Dessort <rdessort@evolix.fr>
|
||||
# Benoît Série <bserie@evolix.fr>
|
||||
# Tristan Pilat <tpilat@evolix.fr>
|
||||
# Victor Laborie <vlaborie@evolix.fr>
|
||||
# Jérémy Lecour <jlecour@evolix.fr>
|
||||
#
|
||||
# Licence: AGPLv3
|
||||
#
|
||||
# /!\ DON'T FORGET TO SET "MAIL" and "SERVERS" VARIABLES
|
||||
|
||||
# Fail on unassigned variables
|
||||
set -u
|
||||
|
||||
##### Configuration ###################################################
|
||||
|
||||
# email adress for notifications
|
||||
MAIL=jdoe@example.com
|
||||
|
||||
# list of hosts (hostname or IP) and SSH port for Rsync
|
||||
SERVERS="node0.backup.example.com:2XXX node1.backup.example.com:2XXX"
|
||||
|
||||
# Should we fallback on servers when the first is unreachable ?
|
||||
SERVERS_FALLBACK=${SERVERS_FALLBACK:-1}
|
||||
|
||||
# timeout (in seconds) for SSH connections
|
||||
SSH_CONNECT_TIMEOUT=${SSH_CONNECT_TIMEOUT:-90}
|
||||
|
||||
# We use /home/backup : feel free to use your own dir
|
||||
LOCAL_BACKUP_DIR="/home/backup"
|
||||
|
||||
# You can set "linux" or "bsd" manually or let it choose automatically
|
||||
SYSTEM=$(uname | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
# Store pid and logs in a file named after this program's name
|
||||
PROGNAME=$(basename $0)
|
||||
PIDFILE="/var/run/${PROGNAME}.pid"
|
||||
LOGFILE="/var/log/${PROGNAME}.log"
|
||||
|
||||
# Enable/Disable tasks
|
||||
LOCAL_TASKS=${LOCAL_TASKS:-1}
|
||||
SYNC_TASKS=${SYNC_TASKS:-1}
|
||||
|
||||
##### SETUP AND FUNCTIONS #############################################
|
||||
|
||||
BEGINNING=$(/bin/date +"%d-%m-%Y ; %H:%M")
|
||||
|
||||
# shellcheck disable=SC2174
|
||||
mkdir -p -m 700 ${LOCAL_BACKUP_DIR}
|
||||
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin
|
||||
|
||||
## lang = C for english outputs
|
||||
export LANGUAGE=C
|
||||
export LANG=C
|
||||
|
||||
## Force umask
|
||||
umask 077
|
||||
|
||||
## Initialize variable to store SSH connection errors
|
||||
SERVERS_SSH_ERRORS=""
|
||||
|
||||
# Call test_server with "HOST:PORT" string
|
||||
# It will return with 0 if the server is reachable.
|
||||
# It will return with 1 and a message on stderr if not.
|
||||
test_server() {
|
||||
item=$1
|
||||
# split HOST and PORT from the input string
|
||||
host=$(echo "${item}" | cut -d':' -f1)
|
||||
port=$(echo "${item}" | cut -d':' -f2)
|
||||
|
||||
# Test if the server is accepting connections
|
||||
ssh -q -o "ConnectTimeout ${SSH_CONNECT_TIMEOUT}" "${host}" -p "${port}" -t "exit"
|
||||
# shellcheck disable=SC2181
|
||||
if [ $? = 0 ]; then
|
||||
# SSH connection is OK
|
||||
return 0
|
||||
else
|
||||
# SSH connection failed
|
||||
new_error=$(printf "Failed to connect to \`%s' within %s seconds" "${item}" "${SSH_CONNECT_TIMEOUT}")
|
||||
SERVERS_SSH_ERRORS=$(printf "%s\\n%s" "${SERVERS_SSH_ERRORS}" "${new_error}" | sed -e '/^$/d')
|
||||
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
# Call pick_server with an optional positive integer to get the nth server in the list.
|
||||
pick_server() {
|
||||
increment=${1:-0}
|
||||
list_length=$(echo "${SERVERS}" | wc -w)
|
||||
|
||||
if [ "${increment}" -ge "${list_length}" ]; then
|
||||
# We've reached the end of the list
|
||||
new_error="No more server available"
|
||||
SERVERS_SSH_ERRORS=$(printf "%s\\n%s" "${SERVERS_SSH_ERRORS}" "${new_error}" | sed -e '/^$/d')
|
||||
|
||||
# Log errors to stderr
|
||||
printf "%s\\n" "${SERVERS_SSH_ERRORS}" >&2
|
||||
# Log errors to logfile
|
||||
printf "%s\\n" "${SERVERS_SSH_ERRORS}" >> $LOGFILE
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Extract the day of month, without leading 0 (which would give an octal based number)
|
||||
today=$(date +%e)
|
||||
# A salt is useful to randomize the starting point in the list
|
||||
# but stay identical each time it's called for a server (based on hostname).
|
||||
salt=$(hostname | cksum | cut -d' ' -f1)
|
||||
# Pick an integer between 0 and the length of the SERVERS list
|
||||
# It changes each day
|
||||
item=$(( (today + salt + increment) % list_length ))
|
||||
# cut starts counting fields at 1, not 0.
|
||||
field=$(( item + 1 ))
|
||||
|
||||
echo "${SERVERS}" | cut -d' ' -f${field}
|
||||
}
|
||||
|
||||
## Verify other evobackup process and kill if needed
|
||||
if [ -e "${PIDFILE}" ]; then
|
||||
pid=$(cat "${PIDFILE}")
|
||||
# Does process still exist ?
|
||||
if kill -0 "${pid}" 2> /dev/null; then
|
||||
# Killing the childs of evobackup.
|
||||
for ppid in $(pgrep -P "${pid}"); do
|
||||
kill -9 "${ppid}";
|
||||
done
|
||||
# Then kill the main PID.
|
||||
kill -9 "${pid}"
|
||||
printf "%s is still running (PID %s). Process has been killed" "$0" "${pid}\\n" >&2
|
||||
else
|
||||
rm -f ${PIDFILE}
|
||||
fi
|
||||
fi
|
||||
echo "$$" > ${PIDFILE}
|
||||
# shellcheck disable=SC2064
|
||||
trap "rm -f ${PIDFILE}" EXIT
|
||||
|
||||
##### LOCAL BACKUP ####################################################
|
||||
|
||||
if [ "${LOCAL_TASKS}" = "1" ]; then
|
||||
# You can comment or uncomment sections below to customize the backup
|
||||
|
||||
## OpenLDAP : example with slapcat
|
||||
# slapcat -n 0 -l ${LOCAL_BACKUP_DIR}/config.ldap.bak
|
||||
# slapcat -n 1 -l ${LOCAL_BACKUP_DIR}/data.ldap.bak
|
||||
# slapcat -l ${LOCAL_BACKUP_DIR}/ldap.bak
|
||||
|
||||
## MySQL
|
||||
|
||||
## example with global and compressed mysqldump
|
||||
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 \
|
||||
# --opt --all-databases --force --events --hex-blob | gzip --best > ${LOCAL_BACKUP_DIR}/mysql.bak.gz
|
||||
|
||||
## example with two dumps for each table (.sql/.txt) for all databases
|
||||
# for i in $(echo SHOW DATABASES | mysql --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 \
|
||||
# | egrep -v "^(Database|information_schema|performance_schema|sys)" ); \
|
||||
# do mkdir -p -m 700 /home/mysqldump/$i ; chown -RL mysql /home/mysqldump ; \
|
||||
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf --force -P 3306 -Q --opt --events --hex-blob --skip-comments \
|
||||
# --fields-enclosed-by='\"' --fields-terminated-by=',' -T /home/mysqldump/$i $i; done
|
||||
|
||||
## Dump all grants (requires 'percona-toolkit' package)
|
||||
# mkdir -p -m 700 ${LOCAL_BACKUP_DIR}/mysql/
|
||||
# pt-show-grants --flush --no-header > ${LOCAL_BACKUP_DIR}/mysql/all_grants.sql
|
||||
|
||||
## example with SQL dump (schema only, no data) for each databases
|
||||
# mkdir -p -m 700 ${LOCAL_BACKUP_DIR}/mysql/
|
||||
# for i in $(mysql --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 -e 'show databases' -s --skip-column-names \
|
||||
# | egrep -v "^(Database|information_schema|performance_schema|sys)"); do
|
||||
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf --force -P 3306 --no-data --databases $i > ${LOCAL_BACKUP_DIR}/mysql/${i}.schema.sql
|
||||
# done
|
||||
|
||||
## example with compressed SQL dump (with data) for each databases
|
||||
# mkdir -p -m 700 ${LOCAL_BACKUP_DIR}/mysql/
|
||||
# for i in $(mysql --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 -e 'show databases' -s --skip-column-names \
|
||||
# | egrep -v "^(Database|information_schema|performance_schema|sys)"); do
|
||||
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf --force -P 3306 --events --hex-blob $i | gzip --best > ${LOCAL_BACKUP_DIR}/mysql/${i}.sql.gz
|
||||
# done
|
||||
|
||||
## example with *one* uncompressed SQL dump for *one* database (MYBASE)
|
||||
# mkdir -p -m 700 ${LOCAL_BACKUP_DIR}/mysql/MYBASE
|
||||
# chown -RL mysql ${LOCAL_BACKUP_DIR}/mysql/
|
||||
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf --force -Q \
|
||||
# --opt --events --hex-blob --skip-comments -T ${LOCAL_BACKUP_DIR}/mysql/MYBASE MYBASE
|
||||
|
||||
## example with mysqlhotcopy
|
||||
# mkdir -p -m 700 ${LOCAL_BACKUP_DIR}/mysqlhotcopy/
|
||||
# mysqlhotcopy BASE ${LOCAL_BACKUP_DIR}/mysql/mysqlhotcopy/
|
||||
|
||||
## example for multiples MySQL instances
|
||||
# mysqladminpasswd=$(grep -m1 'password = .*' /root/.my.cnf|cut -d" " -f3)
|
||||
# grep -E "^port\s*=\s*\d*" /etc/mysql/my.cnf |while read instance; do
|
||||
# instance=$(echo "$instance"|awk '{ print $3 }')
|
||||
# if [ "$instance" != "3306" ]
|
||||
# then
|
||||
# mysqldump -P $instance --opt --all-databases --hex-blob -u mysqladmin -p$mysqladminpasswd > ${LOCAL_BACKUP_DIR}/mysql.$instance.bak
|
||||
# fi
|
||||
# done
|
||||
|
||||
## PostgreSQL
|
||||
|
||||
## example with pg_dumpall (warning: you need space in ~postgres)
|
||||
# su - postgres -c "pg_dumpall > ~/pg.dump.bak"
|
||||
# mv ~postgres/pg.dump.bak ${LOCAL_BACKUP_DIR}/
|
||||
## another method with gzip directly piped
|
||||
# cd /var/lib/postgresql
|
||||
# sudo -u postgres pg_dumpall | gzip > ${LOCAL_BACKUP_DIR}/pg.dump.bak.gz
|
||||
# cd - > /dev/null
|
||||
|
||||
## example with all tables from MYBASE excepts TABLE1 and TABLE2
|
||||
# pg_dump -p 5432 -h 127.0.0.1 -U USER --clean -F t --inserts -f ${LOCAL_BACKUP_DIR}/pg-backup.tar -t 'TABLE1' -t 'TABLE2' MYBASE
|
||||
|
||||
## example with only TABLE1 and TABLE2 from MYBASE
|
||||
# pg_dump -p 5432 -h 127.0.0.1 -U USER --clean -F t --inserts -f ${LOCAL_BACKUP_DIR}/pg-backup.tar -T 'TABLE1' -T 'TABLE2' MYBASE
|
||||
|
||||
## MongoDB
|
||||
|
||||
## don't forget to create use with read-only access
|
||||
## > use admin
|
||||
## > db.createUser( { user: "mongobackup", pwd: "PASS", roles: [ "backup", ] } )
|
||||
# test -d ${LOCAL_BACKUP_DIR}/mongodump/ && rm -rf ${LOCAL_BACKUP_DIR}/mongodump/
|
||||
# mkdir -p -m 700 ${LOCAL_BACKUP_DIR}/mongodump/
|
||||
# mongodump --quiet -u mongobackup -pPASS -o ${LOCAL_BACKUP_DIR}/mongodump/
|
||||
# if [ $? -ne 0 ]; then
|
||||
# echo "Error with mongodump!"
|
||||
# fi
|
||||
|
||||
## Redis
|
||||
|
||||
## example with copy .rdb file
|
||||
## for the default instance :
|
||||
# cp /var/lib/redis/dump.rdb ${LOCAL_BACKUP_DIR}/
|
||||
## for multiple instances :
|
||||
# for instance in $(ls -d /var/lib/redis-*); do
|
||||
# name=$(basename $instance)
|
||||
# mkdir -p ${LOCAL_BACKUP_DIR}/${name}
|
||||
# cp -a ${instance}/dump.rdb ${LOCAL_BACKUP_DIR}/${name}
|
||||
# done
|
||||
|
||||
## ElasticSearch
|
||||
|
||||
## Take a snapshot as a backup.
|
||||
## Warning: You need to have a path.repo configured.
|
||||
## See: https://wiki.evolix.org/HowtoElasticsearch#snapshots-et-sauvegardes
|
||||
# curl -s -XDELETE "localhost:9200/_snapshot/snaprepo/snapshot.daily" -o /tmp/es_delete_snapshot.daily.log
|
||||
# curl -s -XPUT "localhost:9200/_snapshot/snaprepo/snapshot.daily?wait_for_completion=true" -o /tmp/es_snapshot.daily.log
|
||||
## Clustered version here
|
||||
## It basically the same thing except that you need to check that NFS is mounted
|
||||
# if ss | grep ':nfs' | grep -q 'ip\.add\.res\.s1' && ss | grep ':nfs' | grep -q 'ip\.add\.res\.s2'
|
||||
# then
|
||||
# curl -s -XDELETE "localhost:9200/_snapshot/snaprepo/snapshot.daily" -o /tmp/es_delete_snapshot.daily.log
|
||||
# curl -s -XPUT "localhost:9200/_snapshot/snaprepo/snapshot.daily?wait_for_completion=true" -o /tmp/es_snapshot.daily.log
|
||||
# else
|
||||
# echo 'Cannot make a snapshot of elasticsearch, at least one node is not mounting the repository.'
|
||||
# fi
|
||||
## If you need to keep older snapshot, for example the last 10 daily snapshots, replace the XDELETE and XPUT lines by :
|
||||
# for snapshot in $(curl -s -XGET "localhost:9200/_snapshot/snaprepo/_all?pretty=true" | grep -Eo 'snapshot_[0-9]{4}-[0-9]{2}-[0-9]{2}' | head -n -10); do
|
||||
# curl -s -XDELETE "localhost:9200/_snapshot/snaprepo/${snapshot}" | grep -v -Fx '{"acknowledged":true}'
|
||||
# done
|
||||
# date=$(date +%F)
|
||||
# curl -s -XPUT "localhost:9200/_snapshot/snaprepo/snapshot_${date}?wait_for_completion=true" -o /tmp/es_snapshot_${date}.log
|
||||
|
||||
## RabbitMQ
|
||||
|
||||
## export config
|
||||
#rabbitmqadmin export ${LOCAL_BACKUP_DIR}/rabbitmq.config >> $LOGFILE
|
||||
|
||||
## MegaCli config
|
||||
|
||||
#megacli -CfgSave -f ${LOCAL_BACKUP_DIR}/megacli_conf.dump -a0 >/dev/null
|
||||
|
||||
## Dump system and kernel versions
|
||||
uname -a > ${LOCAL_BACKUP_DIR}/uname
|
||||
|
||||
## Dump network routes with mtr and traceroute (warning: could be long with aggressive firewalls)
|
||||
for addr in 8.8.8.8 www.evolix.fr travaux.evolix.net; do
|
||||
mtr -r ${addr} > ${LOCAL_BACKUP_DIR}/mtr-${addr}
|
||||
traceroute -n ${addr} > ${LOCAL_BACKUP_DIR}/traceroute-${addr} 2>&1
|
||||
done
|
||||
|
||||
## Dump process with ps
|
||||
ps auwwx >${LOCAL_BACKUP_DIR}/ps.out
|
||||
|
||||
if [ "${SYSTEM}" = "linux" ]; then
|
||||
## Dump network connections with ss
|
||||
ss -taupen > ${LOCAL_BACKUP_DIR}/netstat.out
|
||||
|
||||
## List Debian packages
|
||||
dpkg -l > ${LOCAL_BACKUP_DIR}/packages
|
||||
dpkg --get-selections > ${LOCAL_BACKUP_DIR}/packages.getselections
|
||||
apt-cache dumpavail > ${LOCAL_BACKUP_DIR}/packages.available
|
||||
|
||||
## Dump MBR / table partitions
|
||||
disks=$(lsblk -l | grep disk | grep -v -E '(drbd|fd[0-9]+)' | awk '{print $1}')
|
||||
for disk in ${disks}; do
|
||||
dd if="/dev/${disk}" of="${LOCAL_BACKUP_DIR}/MBR-${disk}" bs=512 count=1 2>&1 | grep -Ev "(records in|records out|512 bytes)"
|
||||
fdisk -l "/dev/${disk}" > "${LOCAL_BACKUP_DIR}/partitions-${disk}" 2>&1
|
||||
done
|
||||
cat ${LOCAL_BACKUP_DIR}/partitions-* > ${LOCAL_BACKUP_DIR}/partitions
|
||||
|
||||
## Dump iptables
|
||||
if [ -x /sbin/iptables ]; then
|
||||
{ /sbin/iptables -L -n -v; /sbin/iptables -t filter -L -n -v; } > ${LOCAL_BACKUP_DIR}/iptables.txt
|
||||
fi
|
||||
|
||||
## Dump findmnt(8) output
|
||||
FINDMNT_BIN=$(command -v findmnt)
|
||||
if [ -x "${FINDMNT_BIN}" ]; then
|
||||
${FINDMNT_BIN} > ${LOCAL_BACKUP_DIR}/findmnt.txt
|
||||
fi
|
||||
else
|
||||
## Dump network connections with fstat
|
||||
fstat | head -1 > ${LOCAL_BACKUP_DIR}/netstat.out
|
||||
fstat | grep internet >> ${LOCAL_BACKUP_DIR}/netstat.out
|
||||
|
||||
## List OpenBSD packages
|
||||
pkg_info -m > ${LOCAL_BACKUP_DIR}/packages
|
||||
|
||||
## Dump MBR / table partitions
|
||||
disklabel sd0 > ${LOCAL_BACKUP_DIR}/partitions
|
||||
|
||||
## Dump pf infos
|
||||
pfctl -sa > ${LOCAL_BACKUP_DIR}/pfctl-sa.txt
|
||||
|
||||
fi
|
||||
|
||||
## Dump rights
|
||||
#getfacl -R /var > ${LOCAL_BACKUP_DIR}/rights-var.txt
|
||||
#getfacl -R /etc > ${LOCAL_BACKUP_DIR}/rights-etc.txt
|
||||
#getfacl -R /usr > ${LOCAL_BACKUP_DIR}/rights-usr.txt
|
||||
#getfacl -R /home > ${LOCAL_BACKUP_DIR}/rights-home.txt
|
||||
|
||||
fi
|
||||
|
||||
##### REMOTE BACKUP ###################################################
|
||||
|
||||
n=0
|
||||
server=""
|
||||
if [ "${SERVERS_FALLBACK}" = "1" ]; then
|
||||
# We try to find a suitable server
|
||||
while :; do
|
||||
server=$(pick_server "${n}")
|
||||
test $? = 0 || exit 2
|
||||
|
||||
if test_server "${server}"; then
|
||||
break
|
||||
else
|
||||
server=""
|
||||
n=$(( n + 1 ))
|
||||
fi
|
||||
done
|
||||
else
|
||||
# we force the server
|
||||
server=$(pick_server "${n}")
|
||||
fi
|
||||
|
||||
SSH_SERVER=$(echo "${server}" | cut -d':' -f1)
|
||||
SSH_PORT=$(echo "${server}" | cut -d':' -f2)
|
||||
|
||||
HOSTNAME=$(hostname)
|
||||
|
||||
if [ "${SYSTEM}" = "linux" ]; then
|
||||
rep="/bin /boot /lib /opt /sbin /usr"
|
||||
else
|
||||
rep="/bsd /bin /sbin /usr"
|
||||
fi
|
||||
|
||||
|
||||
if [ "${SYNC_TASKS}" = "1" ]; then
|
||||
# /!\ DO NOT USE COMMENTS in the rsync command /!\
|
||||
# It breaks the command and destroys data, simply remove (or add) lines.
|
||||
|
||||
# Remote shell command
|
||||
RSH_COMMAND="ssh -p ${SSH_PORT} -o 'ConnectTimeout ${SSH_CONNECT_TIMEOUT}'"
|
||||
|
||||
# ignore check because we want it to split the different arguments to $rep
|
||||
# shellcheck disable=SC2086
|
||||
rsync -avzh --relative --stats --delete --delete-excluded --force --ignore-errors --partial \
|
||||
--exclude "dev" \
|
||||
--exclude "lost+found" \
|
||||
--exclude ".nfs.*" \
|
||||
--exclude "/usr/doc" \
|
||||
--exclude "/usr/obj" \
|
||||
--exclude "/usr/share/doc" \
|
||||
--exclude "/usr/src" \
|
||||
--exclude "/var/apt" \
|
||||
--exclude "/var/cache" \
|
||||
--exclude "/var/lib/amavis/amavisd.sock" \
|
||||
--exclude "/var/lib/amavis/tmp" \
|
||||
--exclude "/var/lib/clamav/*.tmp" \
|
||||
--exclude "/var/lib/elasticsearch" \
|
||||
--exclude "/var/lib/metche" \
|
||||
--exclude "/var/lib/munin/*tmp*" \
|
||||
--exclude "/var/db/munin/*.tmp" \
|
||||
--exclude "/var/lib/mysql" \
|
||||
--exclude "/var/lib/php5" \
|
||||
--exclude "/var/lib/php/sessions" \
|
||||
--exclude "/var/lib/postgres" \
|
||||
--exclude "/var/lib/postgresql" \
|
||||
--exclude "/var/lib/sympa" \
|
||||
--exclude "/var/lock" \
|
||||
--exclude "/var/log" \
|
||||
--exclude "/var/log/evobackup*" \
|
||||
--exclude "/var/run" \
|
||||
--exclude "/var/spool/postfix" \
|
||||
--exclude "/var/spool/smtpd" \
|
||||
--exclude "/var/spool/squid" \
|
||||
--exclude "/var/state" \
|
||||
--exclude "lxc/*/rootfs/usr/doc" \
|
||||
--exclude "lxc/*/rootfs/usr/obj" \
|
||||
--exclude "lxc/*/rootfs/usr/share/doc" \
|
||||
--exclude "lxc/*/rootfs/usr/src" \
|
||||
--exclude "lxc/*/rootfs/var/apt" \
|
||||
--exclude "lxc/*/rootfs/var/cache" \
|
||||
--exclude "lxc/*/rootfs/var/lib/php5" \
|
||||
--exclude "lxc/*/rootfs/var/lib/php/sessions" \
|
||||
--exclude "lxc/*/rootfs/var/lock" \
|
||||
--exclude "lxc/*/rootfs/var/log" \
|
||||
--exclude "lxc/*/rootfs/var/run" \
|
||||
--exclude "lxc/*/rootfs/var/state" \
|
||||
--exclude "/home/mysqltmp" \
|
||||
${rep} \
|
||||
/etc \
|
||||
/root \
|
||||
/var \
|
||||
/home \
|
||||
-e "${RSH_COMMAND}" \
|
||||
"root@${SSH_SERVER}:/var/backup/" \
|
||||
| tail -30 >> $LOGFILE
|
||||
fi
|
||||
|
||||
##### REPORTING #######################################################
|
||||
|
||||
END=$(/bin/date +"%d-%m-%Y ; %H:%M")
|
||||
|
||||
printf "EvoBackup - %s - START %s ON %s (LOCAL_TASKS=%s SYNC_TASKS=%s)\\n" \
|
||||
"${HOSTNAME}" "${BEGINNING}" "${SSH_SERVER}" "${LOCAL_TASKS}" "${SYNC_TASKS}" \
|
||||
>> $LOGFILE
|
||||
|
||||
printf "EvoBackup - %s - STOP %s ON %s (LOCAL_TASKS=%s SYNC_TASKS=%s)\\n" \
|
||||
"${HOSTNAME}" "${END}" "${SSH_SERVER}" "${LOCAL_TASKS}" "${SYNC_TASKS}" \
|
||||
>> $LOGFILE
|
||||
|
||||
tail -10 $LOGFILE | \
|
||||
mail -s "[info] EvoBackup - Client ${HOSTNAME}" \
|
||||
${MAIL}
|
|
@ -1,38 +1,53 @@
|
|||
---
|
||||
- name: newaliases
|
||||
shell: smtpctl update table aliases
|
||||
ansible.builtin.command: smtpctl update table aliases
|
||||
|
||||
- name: remount / noatime
|
||||
command: mount -u -o noatime /
|
||||
ansible.builtin.command: mount -u -o noatime /
|
||||
args:
|
||||
warn: false
|
||||
|
||||
- name: remount /var noatime
|
||||
command: mount -u -o noatime /var
|
||||
ansible.builtin.command: mount -u -o noatime /var
|
||||
args:
|
||||
warn: false
|
||||
|
||||
- name: remount /var/log noatime
|
||||
ansible.builtin.command: mount -u -o noatime /var/log
|
||||
args:
|
||||
warn: false
|
||||
|
||||
- name: remount /usr noatime
|
||||
command: mount -u -o noatime /usr
|
||||
ansible.builtin.command: mount -u -o noatime /usr
|
||||
args:
|
||||
warn: false
|
||||
|
||||
- name: remount /usr/X11R6 noatime
|
||||
ansible.builtin.command: mount -u -o noatime /usr/X11R6
|
||||
args:
|
||||
warn: false
|
||||
|
||||
- name: remount /usr/local noatime
|
||||
ansible.builtin.command: mount -u -o noatime /usr/local
|
||||
args:
|
||||
warn: false
|
||||
|
||||
- name: remount /tmp noexec
|
||||
command: mount -u -o noexec /tmp
|
||||
ansible.builtin.command: mount -u -o noexec /tmp
|
||||
args:
|
||||
warn: false
|
||||
|
||||
- name: remount /tmp noatime
|
||||
command: mount -u -o noatime /tmp
|
||||
ansible.builtin.command: mount -u -o noatime /tmp
|
||||
args:
|
||||
warn: false
|
||||
|
||||
- name: remount /home noatime
|
||||
command: mount -u -o noatime /home
|
||||
ansible.builtin.command: mount -u -o noatime /home
|
||||
args:
|
||||
warn: false
|
||||
|
||||
- name: reload ntp
|
||||
service:
|
||||
- name: restart ntpd
|
||||
ansible.builtin.service:
|
||||
name: ntpd
|
||||
state: restarted
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
- name: Customize PATH variable of root crontab
|
||||
cron:
|
||||
- name: "Customize PATH variable of root crontab"
|
||||
ansible.builtin.cron:
|
||||
name: PATH
|
||||
env: true
|
||||
value: "{{ cron_root_path }}"
|
||||
tags:
|
||||
- cron
|
||||
- cron
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
|
||||
- name: Default certificate is present
|
||||
when: evobsd_default_ssl_cert | bool
|
||||
block:
|
||||
- name: Ensure /etc/ssl/certs exists
|
||||
ansible.builtin.file:
|
||||
path: /etc/ssl/certs/
|
||||
owner: root
|
||||
group: wheel
|
||||
mode: "0755"
|
||||
state: directory
|
||||
ignore_errors: '{{ ansible_check_mode }}'
|
||||
|
||||
- name: Create private key and csr for default site ({{ evobsd_ssl_cert_hostname }})
|
||||
ansible.builtin.command:
|
||||
cmd: openssl req -newkey rsa:2048 -sha256 -nodes -keyout /etc/ssl/private/{{ evobsd_ssl_cert_hostname }}.key -out /etc/ssl/{{ evobsd_ssl_cert_hostname }}.csr -batch -subj "/CN={{ evobsd_ssl_cert_hostname }}"
|
||||
args:
|
||||
creates: "/etc/ssl/private/{{ evobsd_ssl_cert_hostname }}.key"
|
||||
|
||||
- name: Create certificate for default site
|
||||
ansible.builtin.command:
|
||||
cmd: openssl x509 -req -days 3650 -sha256 -in /etc/ssl/{{ evobsd_ssl_cert_hostname }}.csr -signkey /etc/ssl/private/{{ evobsd_ssl_cert_hostname }}.key -out /etc/ssl/certs/{{ evobsd_ssl_cert_hostname }}.crt
|
||||
args:
|
||||
creates: "/etc/ssl/certs/{{ evobsd_ssl_cert_hostname }}.crt"
|
|
@ -1,11 +1,29 @@
|
|||
# yamllint disable rule:line-length
|
||||
---
|
||||
- name: Configure doas
|
||||
template:
|
||||
src: doas.conf.j2
|
||||
- name: "Configure doas"
|
||||
ansible.builtin.blockinfile:
|
||||
dest: /etc/doas.conf
|
||||
owner: root
|
||||
group: wheel
|
||||
mode: "0640"
|
||||
backup: false
|
||||
create: true
|
||||
marker: "# {mark} ANSIBLE MANAGED BLOCK FROM EVOBSD"
|
||||
block: |
|
||||
permit setenv {SSH_AUTH_SOCK SSH_TTY PKG_PATH HOME=/root ENV=/root/.profile} :{{ evobsd_sudo_group }}
|
||||
permit nopass root
|
||||
permit setenv {ENV PS1 SSH_AUTH_SOCK SSH_TTY} nopass :{{ evobsd_ssh_group }} as root cmd /usr/share/scripts/evomaintenance.sh
|
||||
permit nopass _nrpe as root cmd /sbin/bioctl args sd2
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_mailq.pl
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_ipsecctl.sh
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_ospfd_simple
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_ospfd
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_ospf6d
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_openbgpd
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_pf_states
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_connections_state.sh
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_packetfilter.sh
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_ipsecctl_critiques.sh
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_openvpn_certificates.sh
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_ipmi_sensor
|
||||
tags:
|
||||
- doas
|
||||
|
|
|
@ -1,42 +1,45 @@
|
|||
---
|
||||
- name: Customize root's .profile
|
||||
template:
|
||||
- name: "Customize root's .profile"
|
||||
ansible.builtin.template:
|
||||
src: profile.j2
|
||||
dest: /root/.profile
|
||||
mode: "0644"
|
||||
tags:
|
||||
- admin
|
||||
- dotfiles
|
||||
|
||||
- name: Copy vim default configuration
|
||||
copy:
|
||||
- name: "Copy vim default configuration"
|
||||
ansible.builtin.copy:
|
||||
src: vimrc
|
||||
dest: /root/.vimrc
|
||||
mode: "0644"
|
||||
tags:
|
||||
- admin
|
||||
- dotfiles
|
||||
- vim
|
||||
|
||||
- name: Customize .kshrc environment file
|
||||
copy:
|
||||
src: kshrc
|
||||
- name: "Customize .kshrc environment file"
|
||||
ansible.builtin.template:
|
||||
src: kshrc.j2
|
||||
dest: /root/.kshrc
|
||||
mode: "0644"
|
||||
tags:
|
||||
- admin
|
||||
- dotfiles
|
||||
|
||||
- name: Change default .profile skeleton
|
||||
template:
|
||||
- name: "Change default .profile skeleton"
|
||||
ansible.builtin.template:
|
||||
src: profile.j2
|
||||
dest: /etc/skel/.profile
|
||||
mode: "0644"
|
||||
tags:
|
||||
- admin
|
||||
- dotfiles
|
||||
|
||||
- name: Add evomaintenance trap .profile skeleton with doas
|
||||
lineinfile:
|
||||
- name: "Add evomaintenance trap .profile skeleton with doas"
|
||||
ansible.builtin.lineinfile:
|
||||
state: present
|
||||
dest: /etc/skel/.profile
|
||||
mode: "0644"
|
||||
insertafter: EOF
|
||||
line: 'trap "doas /usr/share/scripts/evomaintenance.sh" 0'
|
||||
create: true
|
||||
|
@ -44,20 +47,20 @@
|
|||
- admin
|
||||
- dotfiles
|
||||
|
||||
- name: Add vim configuration to dotfiles for new users
|
||||
copy:
|
||||
- name: "Add vim configuration to dotfiles for new users"
|
||||
ansible.builtin.copy:
|
||||
src: vimrc
|
||||
dest: /etc/skel/.vimrc
|
||||
mode: "0644"
|
||||
tags:
|
||||
- admin
|
||||
- dotfiles
|
||||
- vim
|
||||
|
||||
- name: Customize .kshrc environment file for new users
|
||||
copy:
|
||||
src: kshrc
|
||||
- name: "Customize .kshrc environment file for new users"
|
||||
ansible.builtin.template:
|
||||
src: kshrc.j2
|
||||
dest: /etc/skel/.kshrc
|
||||
mode: "0644"
|
||||
tags:
|
||||
- admin
|
||||
- dotfiles
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
---
|
||||
- name: Copy zzz_evobackup script
|
||||
copy:
|
||||
src: zzz_evobackup
|
||||
dest: /usr/share/scripts/zzz_evobackup
|
||||
owner: root
|
||||
group: wheel
|
||||
mode: "0755"
|
||||
force: false
|
||||
tags:
|
||||
- evobackup
|
||||
|
||||
- name: Fetch daily.local content
|
||||
command: 'grep "sh /usr/share/scripts/zzz_evobackup" /etc/daily.local'
|
||||
check_mode: false
|
||||
register: daily_local_content
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
tags:
|
||||
- evobackup
|
||||
|
||||
- name: Add evobackup cron (disabled)
|
||||
lineinfile:
|
||||
path: /etc/daily.local
|
||||
line: '#sh /usr/share/scripts/zzz_evobackup'
|
||||
owner: root
|
||||
mode: "0644"
|
||||
create: true
|
||||
when:
|
||||
- not (daily_local_content.stdout
|
||||
| regex_search('sh /usr/share/scripts/zzz_evobackup'))
|
||||
tags:
|
||||
- evobackup
|
||||
|
||||
- name: Delete evobackup root crontab replaced by daily.local cron
|
||||
lineinfile:
|
||||
path: /var/cron/tabs/root
|
||||
regexp: '/usr/share/scripts/zzz_evobackup'
|
||||
validate: /usr/bin/crontab %s
|
||||
state: absent
|
||||
tags:
|
||||
- evobackup
|
|
@ -1,138 +0,0 @@
|
|||
---
|
||||
- name: Fetch fstab content
|
||||
command: "grep -v '^#' /etc/fstab"
|
||||
check_mode: false
|
||||
register: fstab_content
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
tags:
|
||||
- fstab
|
||||
|
||||
- name: / partition is customized - softdep
|
||||
replace:
|
||||
dest: /etc/fstab
|
||||
regexp: '([^#]\s+/\s+ffs\s+rw)(.*)'
|
||||
replace: '\1,softdep\2'
|
||||
when:
|
||||
- fstab_content.stdout | regex_search('\s/\s')
|
||||
- not (fstab_content.stdout | regex_search('\s+/\s+ffs\s+rw,softdep'))
|
||||
tags:
|
||||
- fstab
|
||||
|
||||
- name: / partition is customized - noatime
|
||||
replace:
|
||||
dest: /etc/fstab
|
||||
regexp: '([^#]\s+/\s+ffs\s+rw)(\S*)(\s+.*)'
|
||||
replace: '\1\2,noatime\3'
|
||||
notify: remount / noatime
|
||||
when:
|
||||
- fstab_content.stdout | regex_search('\s/\s')
|
||||
- not (fstab_content.stdout | regex_search('\s+/\s+ffs\s+rw\S*noatime'))
|
||||
tags:
|
||||
- fstab
|
||||
|
||||
- name: /var partition is customized - softdep
|
||||
replace:
|
||||
dest: /etc/fstab
|
||||
regexp: '([^#]\s+/var\s+ffs\s+rw)(.*)'
|
||||
replace: '\1,softdep\2'
|
||||
when:
|
||||
- fstab_content.stdout | regex_search('\s/var\s')
|
||||
- not (fstab_content.stdout | regex_search('\s+/var\s+ffs\s+rw,softdep'))
|
||||
tags:
|
||||
- fstab
|
||||
|
||||
- name: /var partition is customized - noatime
|
||||
replace:
|
||||
dest: /etc/fstab
|
||||
regexp: '([^#]\s+/var\s+ffs\s+rw)(\S*)(\s+.*)'
|
||||
replace: '\1\2,noatime\3'
|
||||
notify: remount /var noatime
|
||||
when:
|
||||
- fstab_content.stdout | regex_search('\s/var\s')
|
||||
- not (fstab_content.stdout | regex_search('\s+/var\s+ffs\s+rw\S*noatime'))
|
||||
tags:
|
||||
- fstab
|
||||
|
||||
- name: /usr partition is customized - softdep
|
||||
replace:
|
||||
dest: /etc/fstab
|
||||
regexp: '([^#]\s+/usr\s+ffs\s+rw)(.*)'
|
||||
replace: '\1,softdep\2'
|
||||
when:
|
||||
- fstab_content.stdout | regex_search('\s/usr\s')
|
||||
- not (fstab_content.stdout | regex_search('\s+/usr\s+ffs\s+rw,softdep'))
|
||||
tags:
|
||||
- fstab
|
||||
|
||||
- name: /usr partition is customized - noatime
|
||||
replace:
|
||||
dest: /etc/fstab
|
||||
regexp: '([^#]\s+/usr\s+ffs\s+rw)(\S*)(\s+.*)'
|
||||
replace: '\1\2,noatime\3'
|
||||
notify: remount /usr noatime
|
||||
when:
|
||||
- fstab_content.stdout | regex_search('\s/usr\s')
|
||||
- not (fstab_content.stdout | regex_search('\s+/usr\s+ffs\s+rw\S*noatime'))
|
||||
tags:
|
||||
- fstab
|
||||
|
||||
- name: /tmp partition is customized - noexec
|
||||
replace:
|
||||
dest: /etc/fstab
|
||||
regexp: '([^#]\s+/tmp\s+ffs\s+rw(,softdep)*)(.*)'
|
||||
replace: '\1,noexec\3'
|
||||
notify: remount /tmp noexec
|
||||
when:
|
||||
- fstab_content.stdout | regex_search('\s/tmp\s')
|
||||
- not (fstab_content.stdout
|
||||
| regex_search('\s+/tmp\s+ffs\s+rw,(softdep,)*noexec'))
|
||||
tags:
|
||||
- fstab
|
||||
|
||||
- name: /tmp partition is customized - softdep
|
||||
replace:
|
||||
dest: /etc/fstab
|
||||
regexp: '([^#]\s+/tmp\s+ffs\s+rw)(.*)'
|
||||
replace: '\1,softdep\2'
|
||||
when:
|
||||
- fstab_content.stdout | regex_search('\s/tmp\s')
|
||||
- not (fstab_content.stdout
|
||||
| regex_search('\s+/tmp\s+ffs\s+rw,(noexec,)*softdep'))
|
||||
tags:
|
||||
- fstab
|
||||
|
||||
- name: /tmp partition is customized - noatime
|
||||
replace:
|
||||
dest: /etc/fstab
|
||||
regexp: '([^#]\s+/tmp\s+ffs\s+rw)(\S*)(\s+.*)'
|
||||
replace: '\1\2,noatime\3'
|
||||
notify: remount /tmp noatime
|
||||
when:
|
||||
- fstab_content.stdout | regex_search('\s/tmp\s')
|
||||
- not (fstab_content.stdout | regex_search('\s+/tmp\s+ffs\s+rw\S*noatime'))
|
||||
tags:
|
||||
- fstab
|
||||
|
||||
- name: /home partition is customized - softdep
|
||||
replace:
|
||||
dest: /etc/fstab
|
||||
regexp: '([^#]\s+/home\s+ffs\s+rw)(.*)'
|
||||
replace: '\1,softdep\2'
|
||||
when:
|
||||
- fstab_content.stdout | regex_search('\s/home\s')
|
||||
- not (fstab_content.stdout | regex_search('\s+/home\s+ffs\s+rw,softdep'))
|
||||
tags:
|
||||
- fstab
|
||||
|
||||
- name: /home partition is customized - noatime
|
||||
replace:
|
||||
dest: /etc/fstab
|
||||
regexp: '([^#]\s+/home\s+ffs\s+rw)(\S*)(\s+.*)'
|
||||
replace: '\1\2,noatime\3'
|
||||
notify: remount /home noatime
|
||||
when:
|
||||
- fstab_content.stdout | regex_search('\s/home\s')
|
||||
- not (fstab_content.stdout | regex_search('\s+/home\s+ffs\s+rw\S*noatime'))
|
||||
tags:
|
||||
- fstab
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
- name: "Fetch fstab content"
|
||||
ansible.builtin.command: "grep -v '^#' /etc/fstab"
|
||||
check_mode: false
|
||||
register: fstab_content
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
tags:
|
||||
- fstab
|
||||
|
||||
- include: fstab_entry.yml
|
||||
vars:
|
||||
fstab_path: "{{ item }}"
|
||||
with_items:
|
||||
- "/"
|
||||
- "/var"
|
||||
- "/var/log"
|
||||
- "/usr"
|
||||
- "/usr/X11R6"
|
||||
- "/usr/local"
|
||||
- "/tmp"
|
||||
- "/home"
|
||||
tags:
|
||||
- fstab
|
|
@ -0,0 +1,40 @@
|
|||
# yamllint disable rule:line-length
|
||||
---
|
||||
- name: "{{ fstab_path }} partition is customized - softdep"
|
||||
ansible.builtin.replace:
|
||||
dest: /etc/fstab
|
||||
regexp: '([^#]\s+{{ fstab_path }}\s+ffs\s+rw)(.*)'
|
||||
replace: '\1,softdep\2'
|
||||
when:
|
||||
- evobsd_fstab_softdep | bool
|
||||
- fstab_content.stdout | regex_search('\s' + fstab_path + '\s')
|
||||
- not (fstab_content.stdout | regex_search('\s+' + fstab_path + '\s+ffs\s+rw,softdep'))
|
||||
tags:
|
||||
- fstab
|
||||
|
||||
- name: "{{ fstab_path }} partition is customized - noatime"
|
||||
ansible.builtin.replace:
|
||||
dest: /etc/fstab
|
||||
regexp: '([^#]\s+{{ fstab_path }}\s+ffs\s+rw)(\S*)(\s+.*)'
|
||||
replace: '\1\2,noatime\3'
|
||||
notify: remount {{ fstab_path }} noatime
|
||||
when:
|
||||
- evobsd_fstab_noatime | bool
|
||||
- fstab_content.stdout | regex_search('\s' + fstab_path + '\s')
|
||||
- not (fstab_content.stdout | regex_search('\s+' + fstab_path + '\s+ffs\s+rw\S*noatime'))
|
||||
tags:
|
||||
- fstab
|
||||
|
||||
- name: "{{ fstab_path }} partition is customized - noexec"
|
||||
ansible.builtin.replace:
|
||||
dest: /etc/fstab
|
||||
regexp: '([^#]\s+{{ fstab_path }}\s+ffs\s+rw(,softdep)*)(.*)'
|
||||
replace: '\1,noexec\3'
|
||||
notify: remount {{ fstab_path }} noexec
|
||||
when:
|
||||
- evobsd_fstab_noexec | bool
|
||||
- fstab_path == "/tmp"
|
||||
- fstab_content.stdout | regex_search('\s' + fstab_path + '\s')
|
||||
- not (fstab_content.stdout | regex_search('\s+' + fstab_path + '\s+ffs\s+rw,(softdep,)*noexec'))
|
||||
tags:
|
||||
- fstab
|
|
@ -1,37 +1,38 @@
|
|||
---
|
||||
- name: Fetch rc.local content
|
||||
command: "grep -v '^#' /etc/rc.local"
|
||||
- name: "Fetch rc.local content"
|
||||
ansible.builtin.command: "grep -v '^#' /etc/rc.local"
|
||||
check_mode: false
|
||||
register: rclocal_content
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
tags:
|
||||
- misc
|
||||
- alerting
|
||||
|
||||
- name: Configure rc.local
|
||||
lineinfile:
|
||||
- name: "Configure rc.local"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/rc.local
|
||||
line:
|
||||
'date | mail -s "boot/reboot of $(hostname -s)" {{ general_alert_email }}'
|
||||
insertbefore: 'echo'
|
||||
mode: "0640"
|
||||
create: true
|
||||
when:
|
||||
- not (rclocal_content.stdout
|
||||
| regex_search('date \| mail -s (\"|\')boot/reboot of \$\(hostname -s\)'))
|
||||
tags:
|
||||
- misc
|
||||
- alerting
|
||||
|
||||
- name: Delete rc.local entry of boot/reboot not precising hostname
|
||||
lineinfile:
|
||||
- name: "Delete rc.local entry of boot/reboot not precising hostname"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/rc.local
|
||||
regexp:
|
||||
"^.* mail -s (?!.*of.*).+$"
|
||||
state: absent
|
||||
tags:
|
||||
- misc
|
||||
- alerting
|
||||
|
||||
- name: Set root mail alias
|
||||
replace:
|
||||
- name: "Set root mail alias"
|
||||
ansible.builtin.replace:
|
||||
dest: /etc/mail/aliases
|
||||
regexp: "# root:"
|
||||
replace: "root: {{ general_alert_email }}"
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
---
|
||||
# tasks file for evobsd-base
|
||||
- include: resolvconf.yml
|
||||
- include: packages.yml
|
||||
- include: doas.yml
|
||||
- include: dotfiles.yml
|
||||
- include: evomaintenance.yml
|
||||
- include: mail.yml
|
||||
- include: sudo.yml
|
||||
- include: evobackup.yml
|
||||
- include: newsyslog.yml
|
||||
- include: cron.yml
|
||||
- include: fstab.yml
|
||||
- include: fstab_entries.yml
|
||||
- include: ntp.yml
|
||||
- include: utils.yml
|
||||
- include: default_ssl.yml
|
|
@ -1,7 +1,8 @@
|
|||
---
|
||||
- name: Customize newsyslog
|
||||
copy:
|
||||
- name: "Customize newsyslog"
|
||||
ansible.builtin.copy:
|
||||
src: newsyslog.conf
|
||||
dest: /etc/newsyslog.conf
|
||||
mode: "0644"
|
||||
tags:
|
||||
- newsyslog
|
||||
|
|
|
@ -1,30 +1,12 @@
|
|||
---
|
||||
- name: Retrieve ntpd.conf content
|
||||
command: cat ntpd.conf
|
||||
args:
|
||||
chdir: /etc/
|
||||
check_mode: no
|
||||
register: ntpd_conf
|
||||
tags:
|
||||
- ntp
|
||||
|
||||
- name: Empty ntpd.conf before customizing it
|
||||
file:
|
||||
path: /etc/ntpd.conf
|
||||
state: absent
|
||||
when: ntpd_conf.stdout is not regex("^server ntp.evolix.net$")
|
||||
tags:
|
||||
- ntp
|
||||
|
||||
- name: Customize ntpd conf
|
||||
lineinfile:
|
||||
path: /etc/ntpd.conf
|
||||
line: "server {{ ntpd_servers }}"
|
||||
create: yes
|
||||
- name: "Customize ntpd conf"
|
||||
ansible.builtin.template:
|
||||
src: ntpd.conf.j2
|
||||
dest: /etc/ntpd.conf
|
||||
owner: root
|
||||
group: wheel
|
||||
mode: '0644'
|
||||
notify:
|
||||
- reload ntp
|
||||
- restart ntpd
|
||||
tags:
|
||||
- ntp
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
|
||||
- name: "Check if {{ package }} is already installed"
|
||||
ansible.builtin.command:
|
||||
cmd: pkg_info -Iq inst:{{ package }}
|
||||
register: is_installed
|
||||
ignore_errors: true
|
||||
changed_when: false
|
||||
tags:
|
||||
- pkg
|
||||
|
||||
- name: "Install {{ package }}"
|
||||
ansible.builtin.command:
|
||||
cmd: pkg_add {{ package }}
|
||||
when: "'Can\\'t find inst:' in is_installed.stderr"
|
||||
tags:
|
||||
- pkg
|
|
@ -1,26 +1,49 @@
|
|||
---
|
||||
|
||||
- name: Configure installurl
|
||||
copy:
|
||||
- name: "Configure installurl"
|
||||
ansible.builtin.copy:
|
||||
content: "{{ evobsd_install_url }}\n"
|
||||
dest: /etc/installurl
|
||||
src: installurl
|
||||
mode: "0644"
|
||||
tags:
|
||||
- pkg
|
||||
|
||||
- name: Install packages (vim rsync mtr etc)
|
||||
openbsd_pkg:
|
||||
name:
|
||||
- wget
|
||||
- vim--no_x11
|
||||
- rsync--
|
||||
- mtr--
|
||||
- iftop
|
||||
- sudo--
|
||||
# openbsd_pkg is broken since OpenBSD 7.4 with the version of Ansible we currently use
|
||||
#- name: "Install packages (vim rsync mtr etc)"
|
||||
# community.general.openbsd_pkg:
|
||||
# name:
|
||||
# - wget
|
||||
# - vim--no_x11
|
||||
# - rsync--
|
||||
# - mtr--
|
||||
# - iftop
|
||||
# - sudo--
|
||||
# - bash
|
||||
# - ncdu
|
||||
# - htop
|
||||
# ignore_errors: true
|
||||
# tags:
|
||||
# - pkg
|
||||
|
||||
- name: "Install packages (vim rsync mtr etc)"
|
||||
include: openbsd_pkg_custom.yml
|
||||
vars:
|
||||
package: "{{ item }}"
|
||||
loop:
|
||||
- wget
|
||||
- vim--no_x11
|
||||
- rsync--
|
||||
- mtr--
|
||||
- iftop
|
||||
- sudo--
|
||||
- bash
|
||||
- ncdu
|
||||
- htop
|
||||
tags:
|
||||
- pkg
|
||||
|
||||
- name: Disable sndiod
|
||||
service:
|
||||
- name: "Disable sndiod"
|
||||
ansible.builtin.service:
|
||||
name: sndiod
|
||||
enabled: false
|
||||
state: stopped
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
- name: "Configure resolv.conf"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/resolv.conf
|
||||
line: "lookup file bind"
|
||||
insertbefore: BOF
|
||||
owner: root
|
||||
group: wheel
|
||||
mode: "0644"
|
||||
tags:
|
||||
- resolvconf
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
- name: Configure sudoers umask
|
||||
lineinfile:
|
||||
- name: "Configure sudoers umask"
|
||||
ansible.builtin.lineinfile:
|
||||
dest: /etc/sudoers
|
||||
insertafter: '# Defaults specification'
|
||||
line: 'Defaults umask=0077'
|
||||
|
@ -8,34 +8,21 @@
|
|||
tags:
|
||||
- sudo
|
||||
|
||||
- name: Allow wheel group to run command as root in sudo
|
||||
lineinfile:
|
||||
- name: "Deactivate sudo insults"
|
||||
ansible.builtin.lineinfile:
|
||||
dest: /etc/sudoers
|
||||
insertafter: '# and set environment variables.'
|
||||
line: "%wheel\tALL=(ALL) SETENV: ALL"
|
||||
insertafter: 'Defaults umask=0077'
|
||||
line: 'Defaults !insults'
|
||||
validate: 'visudo -cf %s'
|
||||
backup: false
|
||||
tags:
|
||||
- sudo
|
||||
|
||||
- name: Delete line with space instead of tab
|
||||
lineinfile:
|
||||
dest: /etc/sudoers
|
||||
line: "%wheel ALL=(ALL) SETENV: ALL"
|
||||
validate: 'visudo -cf %s'
|
||||
backup: false
|
||||
state: absent
|
||||
tags:
|
||||
- sudo
|
||||
|
||||
- name: Configure sudoers for evomaintenance and monitoring
|
||||
blockinfile:
|
||||
- name: "Configure sudoers"
|
||||
ansible.builtin.blockinfile:
|
||||
state: present
|
||||
dest: /etc/sudoers
|
||||
insertafter: EOF
|
||||
block: |
|
||||
Cmnd_Alias MAINT = /usr/share/scripts/evomaintenance.sh
|
||||
%wheel ALL=NOPASSWD: MAINT
|
||||
%evolinux-sudo ALL=(ALL) SETENV: ALL
|
||||
validate: 'visudo -cf %s'
|
||||
backup: false
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
- name: "dump-server-state script is present"
|
||||
ansible.builtin.copy:
|
||||
src: "dump-server-state.sh"
|
||||
dest: /usr/local/sbin/dump-server-state
|
||||
force: true
|
||||
owner: root
|
||||
group: wheel
|
||||
mode: "0750"
|
||||
when:
|
||||
- evobsd_dumpserverstate_include | bool
|
||||
tags:
|
||||
- utils
|
||||
|
||||
- name: "update-evobackup-canary script is present"
|
||||
ansible.builtin.copy:
|
||||
src: "update-evobackup-canary"
|
||||
dest: /usr/local/bin/update-evobackup-canary
|
||||
force: true
|
||||
owner: root
|
||||
group: wheel
|
||||
mode: "0755"
|
||||
when:
|
||||
- evobsd_updateevobackupcanary_include | bool
|
||||
tags:
|
||||
- utils
|
|
@ -1,18 +0,0 @@
|
|||
# {{ ansible_managed }}
|
||||
permit setenv {SSH_AUTH_SOCK SSH_TTY PKG_PATH HOME=/root ENV=/root/.profile} :{{ evobsd_sudo_group }}
|
||||
permit nopass root
|
||||
permit setenv {ENV PS1 SSH_AUTH_SOCK SSH_TTY} nopass :{{ evobsd_ssh_group }} as root cmd /usr/share/scripts/evomaintenance.sh
|
||||
permit nopass _collectd as root cmd /bin/cat
|
||||
permit nopass _collectd as root cmd /usr/sbin/bgpctl
|
||||
permit nopass _nrpe as root cmd /sbin/bioctl args sd2
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_mailq.pl
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_ipsecctl.sh
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_ospfd_simple
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_ospfd
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_ospf6d
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_openbgpd
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_pf_states
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_connections_state.sh
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_packetfilter.sh
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_ipsecctl_critiques.sh
|
||||
permit nopass _nrpe as root cmd /usr/local/libexec/nagios/plugins/check_openvpn_certificates.sh
|
|
@ -0,0 +1,44 @@
|
|||
{% if evobsd_alias_fwupdate %}
|
||||
alias fw_update="{{ evobsd_alias_fwupdate }}"
|
||||
{% endif %}
|
||||
alias vi='vim'
|
||||
sudo() { if [[ $# == "1" ]] && [[ $1 == "su" ]]; then command sudo -i; else command sudo "$@"; fi }
|
||||
alias history="fc -l 0"
|
||||
|
||||
##
|
||||
# Caracterisation du shell
|
||||
##
|
||||
|
||||
# If this is an xterm set the title to user@host:dir
|
||||
case "$TERM" in
|
||||
xterm*|rxvt*)
|
||||
PS1="\[\e]0;\u@\h: \w\a\]$PS1"
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
|
||||
bind -m '^L'='^U 'clear'^M^Y'
|
||||
bind '^[[4~'=end-of-line
|
||||
bind '^[[1~'=beginning-of-line
|
||||
bind '^[[3~'=delete-char-forward
|
||||
bind '^[[8~'=end-of-line
|
||||
bind '^[[7~'=beginning-of-line
|
||||
bind '^[Oc'=forward-word
|
||||
bind '^[Od'=backward-word
|
||||
bind '^[^[[C'=forward-word
|
||||
bind '^[^[[D'=backward-word
|
||||
|
||||
set -A complete_kill_1 -- -9 -HUP -INFO -KILL -TERM
|
||||
PKG_LIST=$(ls -1 /var/db/pkg)
|
||||
set -A complete_pkg_delete -- $PKG_LIST
|
||||
set -A complete_pkg_info -- $PKG_LIST
|
||||
set -A complete_rcctl_1 -- disable enable get ls order set reload check restart stop start
|
||||
set -A complete_rcctl_2 -- $(ls /etc/rc.d)
|
||||
set -A complete_signify_1 -- -C -G -S -V
|
||||
set -A complete_signify_2 -- -q -p -x -c -m -t -z
|
||||
set -A complete_signify_3 -- -p -x -c -m -t -z
|
||||
set -A complete_make_1 -- install clean repackage reinstall
|
||||
set -A complete_gpg2 -- --refresh --receive-keys --armor --clearsign --sign --list-key --decrypt --verify --detach-sig
|
||||
set -A complete_git -- pull push mpull mpush status clone branch add rm checkout fetch show tag commit
|
||||
set -A complete_ifconfig_1 -- $(ifconfig | grep ^[a-z] | cut -d: -f1)
|
|
@ -0,0 +1,4 @@
|
|||
{% if is_ntpd_server %}
|
||||
listen on *
|
||||
{% endif %}
|
||||
servers {{ ntpd_servers }}
|
|
@ -1,4 +1,4 @@
|
|||
# $OpenBSD: dot.profile,v 1.5 2018/02/02 02:29:54 yasuoka Exp $
|
||||
# $OpenBSD: dot.profile,v 1.8 2022/08/10 07:40:37 tb Exp $
|
||||
#
|
||||
# sh/ksh initialization
|
||||
|
||||
|
@ -8,9 +8,9 @@ export LANG="en_US.UTF-8"
|
|||
export LC_ALL="en_US.UTF-8"
|
||||
export PS1="\u@\h:\w\\$ "
|
||||
HISTFILE=$HOME/.histfile
|
||||
export HISTSIZE=10000
|
||||
export HISTSIZE=100000
|
||||
export HISTCONTROL='ignoredups:ignorespace'
|
||||
export TMOUT=36000
|
||||
export TMOUT="{{ evobsd_system_timeout }}"
|
||||
export PAGER=less
|
||||
umask 022
|
||||
|
||||
|
@ -27,32 +27,3 @@ case "$-" in
|
|||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
PKG_LIST=$(ls -1 /var/db/pkg)
|
||||
|
||||
set -A complete_kill_1 -- -9 -HUP -INFO -KILL -TERM
|
||||
pgrep -q vmd
|
||||
if [ $? = 0 ]; then
|
||||
set -A complete_vmctl -- console load reload start stop reset status
|
||||
set -A complete_vmctl_2 -- $(vmctl status | awk '!/NAME/{print $NF}')
|
||||
fi
|
||||
if [ -d ~/.password-store ]; then
|
||||
PASS_LIST=$(
|
||||
cd ~/.password-store
|
||||
find . -type f -name \*.gpg | sed 's/^\.\///' | sed 's/\.gpg$//g'
|
||||
)
|
||||
|
||||
set -A complete_pass -- $PASS_LIST -c generate edit insert git
|
||||
set -A complete_pass_2 -- $PASS_LIST push
|
||||
fi
|
||||
set -A complete_pkg_delete -- $PKG_LIST
|
||||
set -A complete_pkg_info -- $PKG_LIST
|
||||
set -A complete_rcctl_1 -- disable enable get ls order set reload check restart stop start
|
||||
set -A complete_rcctl_2 -- $(ls /etc/rc.d)
|
||||
set -A complete_signify_1 -- -C -G -S -V
|
||||
set -A complete_signify_2 -- -q -p -x -c -m -t -z
|
||||
set -A complete_signify_3 -- -p -x -c -m -t -z
|
||||
set -A complete_make_1 -- install clean repackage reinstall
|
||||
set -A complete_gpg2 -- --refresh --receive-keys --armor --clearsign --sign --list-key --decrypt --verify --detach-sig
|
||||
set -A complete_git -- pull push mpull mpush status clone branch add rm checkout fetch show tag commit
|
||||
set -A complete_ifconfig_1 -- $(ifconfig | grep ^[a-z] | cut -d: -f1)
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
---
|
||||
- name: Deploy bgp check script
|
||||
template:
|
||||
- name: "Deploy bgp check script"
|
||||
ansible.builtin.template:
|
||||
src: bgpd-check-peers.sh.j2
|
||||
dest: /usr/share/scripts/bgpd-check-peers.sh
|
||||
when: group_names | select('search','bgp') | list | count > 0
|
||||
tags:
|
||||
- bgp
|
||||
|
||||
- name: Cron job for bgp check script is installed
|
||||
cron:
|
||||
- name: "Cron job for bgp check script is installed"
|
||||
ansible.builtin.cron:
|
||||
name: bgp check
|
||||
job: "/bin/sh /usr/share/scripts/bgpd-check-peers.sh"
|
||||
when: group_names | select('search','bgp') | list | count > 0
|
||||
tags:
|
||||
- bgp
|
||||
|
||||
- name: Create bgp log directory
|
||||
file:
|
||||
- name: "Create bgp log directory"
|
||||
ansible.builtin.file:
|
||||
path: /var/log/bgp
|
||||
state: directory
|
||||
when: group_names | select('search','bgp') | list | count > 0
|
||||
tags:
|
||||
- bgp
|
||||
|
||||
- name: daily best routes cron job is installed
|
||||
cron:
|
||||
- name: "Daily best routes cron job is installed"
|
||||
ansible.builtin.cron:
|
||||
name: bgp best routes
|
||||
minute: 0
|
||||
hour: 4
|
||||
|
@ -35,8 +35,8 @@
|
|||
tags:
|
||||
- bgp
|
||||
|
||||
- name: weekly best routes clean up cron job is installed
|
||||
cron:
|
||||
- name: "Weekly best routes clean up cron job is installed"
|
||||
ansible.builtin.cron:
|
||||
name: bgp best routes clean up
|
||||
minute: 0
|
||||
hour: 4
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/ksh
|
||||
#!/bin/sh
|
||||
|
||||
# Script writen by Daniel Jakots
|
||||
|
||||
|
@ -9,8 +9,6 @@
|
|||
|
||||
# If it did, we send a mail with the states of the different sessions.
|
||||
|
||||
set -u
|
||||
|
||||
PATH=$HOME/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:.
|
||||
|
||||
_MAILTO="{{ bgp_mailto }}"
|
||||
|
@ -30,6 +28,7 @@ mkdir -p "${_TMPDIR}"
|
|||
# Don't try to run if it's already running
|
||||
if [ -e "${_PIDFILE}" ]; then
|
||||
echo "$(date)" >> "${_TMPDIR}"/log
|
||||
echo "ERROR : $0 already has a PIDFILE"
|
||||
exit 1
|
||||
else
|
||||
echo $$ >> "${_PIDFILE}"
|
||||
|
@ -46,7 +45,7 @@ fi
|
|||
# List peers and loops on them to list them and their BGP state
|
||||
bgpctl show neighbor | grep Description {{ bgp_exclude_grep_command }} | sed s,\ Description:\ ,,g > "${_TMPDIR}"/peers-list
|
||||
|
||||
while read _PEER
|
||||
while read -r _PEER
|
||||
do
|
||||
_STATUS=$(/usr/sbin/bgpctl show neighbor "${_PEER}" | grep state | awk '{print $4}' |tr -d ',')
|
||||
echo -n "${_PEER}" >> "${_TMPDIR}"/bgp-status
|
||||
|
@ -74,7 +73,7 @@ mkdir -p "${_TMPMAILDIR}"
|
|||
|
||||
# go through sessions and list them depending on their BGP state
|
||||
echo "*** Session(s) OK ***\n" >> "${_TMPMAILDIR}"/bodyok
|
||||
while read _LINE
|
||||
while read -r _LINE
|
||||
do
|
||||
# _LINE is session + status
|
||||
_STATUS=$(echo "${_LINE##* }")
|
||||
|
|
|
@ -14,6 +14,7 @@ collectd_plugin_exec_interval: "{{ collectd_interval }}"
|
|||
collectd_plugin_exec_ifq_drops: false
|
||||
collectd_plugin_exec_dns_stats: false # Based on unbound
|
||||
collectd_plugin_exec_dns_stats_interval: "{{ collectd_interval }}"
|
||||
collectd_plugin_exec_dhcp_pool: false
|
||||
|
||||
# others plugins
|
||||
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Copyright (C) 2008 Rien Broekstra <rien@rename-it.nl>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; version 2 dated June,
|
||||
# 1991.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
#
|
||||
# Configuration variables:
|
||||
#
|
||||
# conffile - path to dhcpd's configuration file (default "/etc/dhcpd.conf")
|
||||
# leasefile - path to dhcpd's leases file (default "/var/lib/dhcp/dhcpd.leases")
|
||||
#
|
||||
|
||||
use POSIX;
|
||||
use Time::Local;
|
||||
use Sys::Hostname;
|
||||
use strict;
|
||||
|
||||
my $CONFFILE = exists $ENV{'conffile'} ? $ENV{'conffile'} : "/etc/dhcpd.conf";
|
||||
my $LEASEFILE = exists $ENV{'leasefile'} ? $ENV{'leasefile'} : "/var/db/dhcpd.leases";
|
||||
|
||||
my (@activeleases, %dhcp_pools, $pool_start, $pool_end, $pool_size, $pool_free, $pool_usage, $pool_status, $label, $lease, @output);
|
||||
my $hostname = hostname;
|
||||
|
||||
# Determine all leased IP addresses
|
||||
@activeleases = determine_active_leases();
|
||||
|
||||
# Determine the available IP pools
|
||||
%dhcp_pools = determine_pools();
|
||||
|
||||
# For each pool, count how many leases from that pool are currently active
|
||||
foreach $pool_start (keys %dhcp_pools) {
|
||||
$pool_size = $dhcp_pools{$pool_start};
|
||||
$pool_end = $pool_start+$pool_size-1;
|
||||
$pool_free = $pool_size;
|
||||
|
||||
foreach $lease (@activeleases) {
|
||||
if ($lease >= $pool_start && $lease <= $pool_end) {
|
||||
$pool_free--;
|
||||
}
|
||||
}
|
||||
|
||||
$label = ip2string($pool_start)."_".ip2string($pool_end);
|
||||
$pool_usage = sprintf("%.1f", 100*($pool_size-$pool_free)/$pool_size);
|
||||
|
||||
push(@output, "PUTVAL $hostname/dhcp_pool/gauge-$label N:$pool_usage\n");
|
||||
}
|
||||
|
||||
print @output;
|
||||
exit 0;
|
||||
|
||||
################
|
||||
###### FUNCTIONS
|
||||
|
||||
# Parse dhcpd.conf for range statements.
|
||||
#
|
||||
# Returns a hash with start IP -> size
|
||||
sub determine_pools {
|
||||
my (%pools, @conffile, $line, $start, $end, $size);
|
||||
|
||||
open(CONFFILE, "<${CONFFILE}") || exit -1;
|
||||
@conffile = <CONFFILE>;
|
||||
close (CONFFILE);
|
||||
|
||||
foreach $line (@conffile) {
|
||||
next if $line =~ /^\s*#/;
|
||||
|
||||
if ($line =~ /range[\s]+([\d]+\.[\d]+\.[\d]+\.[\d]+)[\s]+([\d]+\.[\d]+\.[\d]+\.[\d]+)/) {
|
||||
$start = string2ip($1);
|
||||
$end = string2ip($2);
|
||||
|
||||
defined($start) || next;
|
||||
defined($end) || next;
|
||||
|
||||
# The range statement gives the lowest and highest IP addresses in a range.
|
||||
$size = $end - $start + 1;
|
||||
|
||||
$pools{$start} = $size;
|
||||
}
|
||||
}
|
||||
return %pools;
|
||||
}
|
||||
|
||||
# Very simple parser for dhcpd.leases. This will break very easily if dhcpd decides to
|
||||
# format the file differently. Ideally a simple recursive-descent parser should be used.
|
||||
#
|
||||
# Returns an array with currently leased IP's
|
||||
sub determine_active_leases {
|
||||
my (@leasefile, $startdate, $enddate, $lease, @activeleases, $mytz, $line, %saw);
|
||||
|
||||
open(LEASEFILE, "<${LEASEFILE}") || exit -1;
|
||||
@leasefile = <LEASEFILE>;
|
||||
close (LEASEFILE);
|
||||
|
||||
@activeleases = ();
|
||||
|
||||
# Portable way of converting a GMT date/time string to timestamp is setting TZ to UTC, and then calling mktime()
|
||||
$mytz = $ENV{'TZ'};
|
||||
$ENV{'TZ'} = 'UTC 0';
|
||||
tzset();
|
||||
|
||||
foreach $line (@leasefile) {
|
||||
if ($line =~ /lease ([\d]+\.[\d]+\.[\d]+\.[\d]+)/) {
|
||||
$lease = string2ip($1);
|
||||
defined($lease) || next;
|
||||
|
||||
undef $startdate;
|
||||
undef $enddate;
|
||||
}
|
||||
elsif ($line =~ /starts \d ([\d]{4})\/([\d]{2})\/([\d]{2}) ([\d]{2}):([\d]{2}):([\d]{2})/) {
|
||||
$startdate = mktime($6, $5, $4, $3, $2-1, $1-1900, 0, 0);
|
||||
}
|
||||
elsif ($line =~ /ends \d ([\d]{4})\/([\d]{2})\/([\d]{2}) ([\d]{2}):([\d]{2}):([\d]{2})/) {
|
||||
$enddate = mktime($6, $5, $4, $3, $2-1, $1-1900, 0, 0);
|
||||
}
|
||||
elsif ($line !~ /abandoned/) {
|
||||
if (defined($enddate) && defined($startdate) && defined($lease)) {
|
||||
if ($startdate < time() && $enddate > time()) {
|
||||
push (@activeleases, $lease);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# Set TZ back to its original setting
|
||||
if (defined($mytz)) {
|
||||
$ENV{'TZ'} = $mytz;
|
||||
}
|
||||
else {
|
||||
delete $ENV{'TZ'};
|
||||
}
|
||||
tzset();
|
||||
|
||||
# Sort the array, strip doubles, and return
|
||||
return grep(!$saw{$_}++, @activeleases);
|
||||
}
|
||||
|
||||
#
|
||||
# Helper routine to convert an IP address a.b.c.d into an integer
|
||||
#
|
||||
# Returns an integer representation of an IP address
|
||||
sub string2ip {
|
||||
my $string = shift;
|
||||
defined($string) || return undef;
|
||||
if ($string =~ /([\d]+)\.([\d]+)\.([\d]+)\.([\d]+)/) {
|
||||
if ($1 < 0 || $1 > 255 || $2 < 0 || $2 > 255 || $3 < 0 || $3 > 255 || $4 < 0 || $4 > 255) {
|
||||
return undef;
|
||||
}
|
||||
else {
|
||||
return $1 << 24 | $2 << 16 | $3 << 8 | $4;
|
||||
}
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
#
|
||||
# Returns a dotted quad notation of an
|
||||
#
|
||||
sub ip2string {
|
||||
my $ip = shift;
|
||||
defined ($ip) || return undef;
|
||||
return sprintf ("%d.%d.%d.%d", ($ip >> 24) & 0xff, ($ip >> 16) & 0xff, ($ip >> 8) & 0xff, $ip & 0xff);
|
||||
}
|
|
@ -1,3 +1,62 @@
|
|||
#!/bin/ksh
|
||||
#!/bin/sh
|
||||
|
||||
echo "PUTVAL $(hostname)/dns_stats/count N:$(doas /bin/cat /var/log/daemon | grep "server stats" | grep -v "requestlist max" | awk '{print $13}' | tail -1)"
|
||||
UNBOUND_RAWSTATS=$(doas /usr/sbin/unbound-control stats)
|
||||
|
||||
echo "PUTVAL $(hostname)/dns_unbound-query_count/count-queries N:$(echo "$UNBOUND_RAWSTATS" | grep total.num.queries= | cut -d= -f2 )"
|
||||
|
||||
echo "PUTVAL $(hostname)/dns_unbound-cache/count-hits N:$(echo "$UNBOUND_RAWSTATS" | grep total.num.cachehits= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-cache/count-miss N:$(echo "$UNBOUND_RAWSTATS" | grep total.num.cachemiss= | cut -d= -f2)"
|
||||
|
||||
echo "PUTVAL $(hostname)/dns_unbound-query_type/count-A N:$(echo "$UNBOUND_RAWSTATS" | (grep num.query.type.A= || echo 0) | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-query_type/count-AAAA N:$(echo "$UNBOUND_RAWSTATS" | (grep num.query.type.AAAA= || echo 0) | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-query_type/count-NS N:$(echo "$UNBOUND_RAWSTATS" | (grep num.query.type.NS= || echo 0) | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-query_type/count-PTR N:$(echo "$UNBOUND_RAWSTATS" | (grep num.query.type.PTR= || echo 0) | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-query_type/count-MX N:$(echo "$UNBOUND_RAWSTATS" | (grep num.query.type.MX= || echo 0) | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-query_type/count-TXT N:$(echo "$UNBOUND_RAWSTATS" | (grep num.query.type.TXT= || echo 0) | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-query_type/count-SRV N:$(echo "$UNBOUND_RAWSTATS" | (grep num.query.type.SRV= || echo 0) | cut -d= -f2)"
|
||||
|
||||
echo "PUTVAL $(hostname)/dns_unbound-answer_rcode/count-NOERROR N:$(echo "$UNBOUND_RAWSTATS" | grep num.answer.rcode.NOERROR= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-answer_rcode/count-SERVFAIL N:$(echo "$UNBOUND_RAWSTATS" | grep num.answer.rcode.SERVFAIL= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-answer_rcode/count-NXDOMAIN N:$(echo "$UNBOUND_RAWSTATS" | grep num.answer.rcode.NXDOMAIN= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-answer_rcode/count-REFUSED N:$(echo "$UNBOUND_RAWSTATS" | grep num.answer.rcode.REFUSED= | cut -d= -f2)"
|
||||
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-0_to_1µs N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.000000.to.000000.000001= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-1_to_2µs N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.000001.to.000000.000002= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-2_to_4µs N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.000002.to.000000.000004= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-4_to_8µs N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.000004.to.000000.000008= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-8_to_16µs N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.000008.to.000000.000016= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-16_to_32µs N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.000016.to.000000.000032= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-32_to_64µs N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.000032.to.000000.000064= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-64_to_128µs N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.000064.to.000000.000128= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-128_to_256µs N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.000128.to.000000.000256= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-256_to_512µs N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.000256.to.000000.000512= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-0.5_to_1ms N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.000512.to.000000.001024= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-1_to_2ms N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.001024.to.000000.002048= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-2_to_4ms N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.002048.to.000000.004096= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-4_to_8ms N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.004096.to.000000.008192= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-8_to_16ms N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.008192.to.000000.016384= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-16_to_32ms N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.016384.to.000000.032768= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-32_to_65ms N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.032768.to.000000.065536= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-65_to_131ms N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.065536.to.000000.131072= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-131_to_262ms N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.131072.to.000000.262144= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-262_to_524ms N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.262144.to.000000.524288= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-0.5_to_1s N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000000.524288.to.000001.000000= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-1_to_2s N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000001.000000.to.000002.000000= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-2_to_4s N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000002.000000.to.000004.000000= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-4_to_8s N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000004.000000.to.000008.000000= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-8_to_16s N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000008.000000.to.000016.000000= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-16_to_32s N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000016.000000.to.000032.000000= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-32_to_64s N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000032.000000.to.000064.000000= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-64_to_128s N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000064.000000.to.000128.000000= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-128_to_256s N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000128.000000.to.000256.000000= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-256_to_512s N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000256.000000.to.000512.000000= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-512_to_1024s N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.000512.000000.to.001024.000000= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-1024_to_2048s N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.001024.000000.to.002048.000000= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-2048_to_4096s N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.002048.000000.to.004096.000000= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-4096_to_8192s N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.004096.000000.to.008192.000000= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-8192_to_16384s N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.008192.000000.to.016384.000000= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-16384_to_32768s N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.016384.000000.to.032768.000000= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-32768_to_65536s N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.032768.000000.to.065536.000000= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-65536_to_131072s N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.065536.000000.to.131072.000000= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-131072_to_262144s N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.131072.000000.to.262144.000000= | cut -d= -f2)"
|
||||
echo "PUTVAL $(hostname)/dns_unbound-histogram/count-262144_to_524288s N:$(echo "$UNBOUND_RAWSTATS" | grep histogram.262144.000000.to.524288.000000= | cut -d= -f2)"
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
---
|
||||
- name: restart collectd
|
||||
service:
|
||||
ansible.builtin.service:
|
||||
name: collectd
|
||||
state: restarted
|
||||
|
||||
- name: reload unbound
|
||||
service:
|
||||
name: unbound
|
||||
state: reloaded
|
||||
|
|
|
@ -1,97 +1,130 @@
|
|||
# yamllint disable rule:line-length
|
||||
---
|
||||
- name: Install Collectd package
|
||||
openbsd_pkg:
|
||||
name: "collectd"
|
||||
# openbsd_pkg is broken since OpenBSD 7.4 with the version of Ansible we currently use
|
||||
#- name: "Install Collectd package"
|
||||
# community.general.openbsd_pkg:
|
||||
# name: "collectd"
|
||||
# tags:
|
||||
# - collectd
|
||||
|
||||
- name: "Check if collectd is already installed"
|
||||
ansible.builtin.command:
|
||||
cmd: pkg_info -Iq inst:collectd
|
||||
register: is_installed
|
||||
ignore_errors: true
|
||||
changed_when: false
|
||||
tags:
|
||||
- collectd
|
||||
|
||||
- name: Deploy Collectd configuration
|
||||
template:
|
||||
- name: "Install collectd"
|
||||
ansible.builtin.command:
|
||||
cmd: pkg_add collectd
|
||||
when: "'Can\\'t find inst:' in is_installed.stderr"
|
||||
tags:
|
||||
- collectd
|
||||
|
||||
- name: "Deploy Collectd configuration"
|
||||
ansible.builtin.template:
|
||||
src: "collectd.conf.j2"
|
||||
dest: "/etc/collectd.conf"
|
||||
notify: restart collectd
|
||||
tags:
|
||||
- collectd
|
||||
|
||||
- name: Enabling Collectd
|
||||
service:
|
||||
- name: "Enabling Collectd"
|
||||
ansible.builtin.service:
|
||||
name: collectd
|
||||
enabled: true
|
||||
when: not ansible_check_mode
|
||||
tags:
|
||||
- collectd
|
||||
|
||||
- name: Create scripts directory for exec plugins
|
||||
file:
|
||||
- name: "Fix rights for collectd directory"
|
||||
ansible.builtin.file:
|
||||
path: /usr/local/share/collectd
|
||||
state: directory
|
||||
owner: "root"
|
||||
group: "wheel"
|
||||
mode: "0755"
|
||||
when: collectd_plugin_exec_ifq_drops or collectd_plugin_exec_dns_stats or collectd_plugin_exec_dhcp_pool
|
||||
tags:
|
||||
- collectd
|
||||
|
||||
- name: "Create scripts directory for exec plugins"
|
||||
ansible.builtin.file:
|
||||
path: /usr/local/share/collectd/scripts
|
||||
state: directory
|
||||
when: collectd_plugin_exec_ifq_drops or collectd_plugin_exec_dns_stats
|
||||
owner: "root"
|
||||
group: "_collectd"
|
||||
mode: "0710"
|
||||
when: collectd_plugin_exec_ifq_drops or collectd_plugin_exec_dns_stats or collectd_plugin_exec_dhcp_pool
|
||||
tags:
|
||||
- collectd
|
||||
|
||||
- name: Copy ifq_drops.sh
|
||||
copy:
|
||||
- name: "Copy ifq_drops.sh"
|
||||
ansible.builtin.copy:
|
||||
src: ifq_drops.sh
|
||||
dest: /usr/local/share/collectd/scripts/ifq_drops.sh
|
||||
mode: 0755
|
||||
owner: "root"
|
||||
group: "_collectd"
|
||||
mode: "0710"
|
||||
force: true
|
||||
when: collectd_plugin_exec_ifq_drops
|
||||
tags:
|
||||
- collectd
|
||||
|
||||
- name: Remove ifq_drops.sh
|
||||
file:
|
||||
- name: "Remove ifq_drops.sh"
|
||||
ansible.builtin.file:
|
||||
path: /usr/local/share/collectd/scripts/ifq_drops.sh
|
||||
state: absent
|
||||
when: not collectd_plugin_exec_ifq_drops
|
||||
tags:
|
||||
- collectd
|
||||
|
||||
- name: Copy dns_stats.sh
|
||||
copy:
|
||||
- name: "Copy dns_stats.sh"
|
||||
ansible.builtin.copy:
|
||||
src: dns_stats.sh
|
||||
dest: /usr/local/share/collectd/scripts/dns_stats.sh
|
||||
mode: 0755
|
||||
owner: "root"
|
||||
group: "_collectd"
|
||||
mode: "0710"
|
||||
force: true
|
||||
when: collectd_plugin_exec_dns_stats
|
||||
tags:
|
||||
- collectd
|
||||
|
||||
- name: Add stats DNS on unbound
|
||||
lineinfile:
|
||||
path: /var/unbound/etc/unbound.conf
|
||||
regexp: 'statistics-interval'
|
||||
line:
|
||||
' statistics-interval: {{ collectd_plugin_exec_dns_stats_interval }}'
|
||||
insertafter: 'hide-version:'
|
||||
backup: true
|
||||
notify: reload unbound
|
||||
when: collectd_plugin_exec_dns_stats
|
||||
tags:
|
||||
- collectd
|
||||
|
||||
- name: Remove dns_stats.sh
|
||||
file:
|
||||
- name: "Remove dns_stats.sh"
|
||||
ansible.builtin.file:
|
||||
path: /usr/local/share/collectd/scripts/dns_stats.sh
|
||||
state: absent
|
||||
when: not collectd_plugin_exec_dns_stats
|
||||
tags:
|
||||
- collectd
|
||||
|
||||
- name: Remove stats DNS on unbound
|
||||
lineinfile:
|
||||
path: /var/unbound/etc/unbound.conf
|
||||
regexp: 'statistics-interval'
|
||||
backup: true
|
||||
state: absent
|
||||
notify: reload unbound
|
||||
when: not collectd_plugin_exec_dns_stats
|
||||
tags:
|
||||
- collectd
|
||||
|
||||
- name: Add doas configuration for dns_stats.sh execution
|
||||
lineinfile:
|
||||
- name: "Add doas configuration for dns_stats.sh execution"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/doas.conf
|
||||
line: 'permit nopass _collectd as root cmd /bin/cat'
|
||||
line: 'permit nopass _collectd as root cmd /usr/sbin/unbound-control args stats'
|
||||
when: collectd_plugin_exec_dns_stats
|
||||
tags:
|
||||
- collectd
|
||||
|
||||
- name: "Copy dhcp_pool.pl"
|
||||
ansible.builtin.copy:
|
||||
src: dhcp_pool.pl
|
||||
dest: /usr/local/share/collectd/scripts/dhcp_pool.pl
|
||||
owner: "root"
|
||||
group: "_collectd"
|
||||
mode: "0710"
|
||||
force: true
|
||||
when: collectd_plugin_exec_dhcp_pool
|
||||
tags:
|
||||
- collectd
|
||||
|
||||
- name: "Remove dhcp_pool.pl"
|
||||
ansible.builtin.file:
|
||||
path: /usr/local/share/collectd/scripts/dhcp_pool.pl
|
||||
state: absent
|
||||
when: not collectd_plugin_exec_dhcp_pool
|
||||
tags:
|
||||
- collectd
|
||||
|
|
|
@ -2,11 +2,12 @@ Interval {{ collectd_interval }}
|
|||
Timeout 2
|
||||
|
||||
LoadPlugin syslog
|
||||
|
||||
<Plugin syslog>
|
||||
LogLevel warning
|
||||
</Plugin>
|
||||
|
||||
{% if (collectd_plugin_exec_ifq_drops is sameas true) or (collectd_plugin_exec_dns_stats is sameas true) %}
|
||||
{% if (collectd_plugin_exec_ifq_drops is sameas true) or (collectd_plugin_exec_dns_stats is sameas true) or (collectd_plugin_exec_dhcp_pool is sameas true) %}
|
||||
<LoadPlugin exec>
|
||||
Interval {{ collectd_plugin_exec_interval }}
|
||||
</LoadPlugin>
|
||||
|
@ -18,27 +19,51 @@ LoadPlugin syslog
|
|||
{% if collectd_plugin_exec_dns_stats is sameas true %}
|
||||
Exec "_collectd" "/usr/local/share/collectd/scripts/dns_stats.sh"
|
||||
{% endif %}
|
||||
{% if collectd_plugin_exec_dhcp_pool is sameas true %}
|
||||
Exec "_collectd" "/usr/local/share/collectd/scripts/dhcp_pool.pl"
|
||||
{% endif %}
|
||||
</Plugin>
|
||||
|
||||
{% endif %}
|
||||
{% if collectd_plugin_cpu is sameas true %}
|
||||
LoadPlugin cpu
|
||||
{% endif %}
|
||||
{% if collectd_plugin_df is sameas true %}
|
||||
LoadPlugin df
|
||||
{% endif %}
|
||||
{% if collectd_plugin_disk is sameas true %}
|
||||
LoadPlugin disk
|
||||
{% endif %}
|
||||
{% if collectd_plugin_interface is sameas true %}
|
||||
LoadPlugin interface
|
||||
{% endif %}
|
||||
{% if collectd_plugin_load is sameas true %}
|
||||
LoadPlugin load
|
||||
{% endif %}
|
||||
{% if collectd_plugin_memory is sameas true %}
|
||||
LoadPlugin memory
|
||||
{% endif %}
|
||||
LoadPlugin network
|
||||
{% if collectd_plugin_pf is sameas true %}
|
||||
LoadPlugin pf
|
||||
{% endif %}
|
||||
{% if collectd_plugin_processes is sameas true %}
|
||||
LoadPlugin processes
|
||||
{% endif %}
|
||||
{% if collectd_plugin_swap is sameas true %}
|
||||
LoadPlugin swap
|
||||
{% endif %}
|
||||
{% if collectd_plugin_tcpconns is sameas true %}
|
||||
LoadPlugin tcpconns
|
||||
{% endif %}
|
||||
{% if collectd_plugin_uptime is sameas true %}
|
||||
LoadPlugin uptime
|
||||
{% endif %}
|
||||
{% if collectd_plugin_users is sameas true %}
|
||||
LoadPlugin users
|
||||
{% endif %}
|
||||
{% if collectd_plugin_pf is sameas true %}
|
||||
LoadPlugin pf
|
||||
{% endif %}
|
||||
|
||||
{% if collectd_plugin_df is sameas true %}
|
||||
LoadPlugin df
|
||||
<Plugin df>
|
||||
# expose host's mounts into container using -v /:/host:ro (location inside container does not matter much)
|
||||
# ignore rootfs; else, the root file-system would appear twice, causing
|
||||
|
@ -70,7 +95,6 @@ LoadPlugin df
|
|||
|
||||
{% endif %}
|
||||
{% if collectd_plugin_disk is sameas true %}
|
||||
LoadPlugin disk
|
||||
<Plugin "disk">
|
||||
#Disk "/^[hsv]d[a-z]/"
|
||||
IgnoreSelected false
|
||||
|
@ -78,28 +102,24 @@ LoadPlugin disk
|
|||
|
||||
{% endif %}
|
||||
{% if collectd_plugin_cpu is sameas true %}
|
||||
LoadPlugin cpu
|
||||
<Plugin cpu>
|
||||
ValuesPercentage true
|
||||
</Plugin>
|
||||
|
||||
{% endif %}
|
||||
{% if collectd_plugin_memory is sameas true %}
|
||||
LoadPlugin memory
|
||||
<Plugin memory>
|
||||
ValuesPercentage true
|
||||
</Plugin>
|
||||
|
||||
{% endif %}
|
||||
{% if collectd_plugin_swap is sameas true %}
|
||||
LoadPlugin swap
|
||||
<Plugin swap>
|
||||
ValuesPercentage true
|
||||
</Plugin>
|
||||
|
||||
{% endif %}
|
||||
{% if collectd_plugin_interface is sameas true %}
|
||||
LoadPlugin interface
|
||||
<Plugin interface>
|
||||
Interface "/^lo[0-9]*/"
|
||||
Interface "/^veth.*/"
|
||||
|
@ -110,13 +130,12 @@ LoadPlugin interface
|
|||
|
||||
{% endif %}
|
||||
{% if collectd_plugin_tcpconns is sameas true %}
|
||||
LoadPlugin tcpconns
|
||||
<Plugin "tcpconns">
|
||||
AllPortsSummary true
|
||||
</Plugin>
|
||||
|
||||
{% endif %}
|
||||
LoadPlugin network
|
||||
<Plugin "network">
|
||||
Server "{{ collectd_server }}" "25826"
|
||||
<Server "{{ collectd_server }}" "25826">
|
||||
</Server>
|
||||
</Plugin>
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
commit_message: Ansible run
|
||||
|
||||
etc_git_monitor_status: true
|
||||
etc_git_config_repositories: true
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -u
|
||||
|
||||
VERSION="22.05"
|
||||
|
||||
show_version() {
|
||||
cat <<END
|
||||
ansible-commit version ${VERSION}
|
||||
|
||||
Copyright 2022 Evolix <info@evolix.fr>,
|
||||
Jérémy Lecour <jlecour@evolix.fr>
|
||||
and others.
|
||||
|
||||
ansible-commit comes with ABSOLUTELY NO WARRANTY. This is free software,
|
||||
and you are welcome to redistribute it under certain conditions.
|
||||
See the GNU General Public Licence for details.
|
||||
END
|
||||
}
|
||||
|
||||
show_help() {
|
||||
cat <<END
|
||||
ansible-commit is a wrapper for evocommit, to be used with Ansible
|
||||
|
||||
END
|
||||
show_usage
|
||||
}
|
||||
show_usage() {
|
||||
cat <<END
|
||||
Usage: ansible-commit --message "add new host"
|
||||
|
||||
Options
|
||||
--message MESSAGE set the commit message
|
||||
--no-lxc disable commit inside LXC containers
|
||||
-V, --version print version number
|
||||
-v, --verbose increase verbosity
|
||||
-n, --dry-run actions are not executed
|
||||
-h, --help print this message and exit
|
||||
END
|
||||
}
|
||||
|
||||
is_dry_run() {
|
||||
test "${DRY_RUN}" = "1"
|
||||
}
|
||||
is_verbose() {
|
||||
test "${VERBOSE}" = "1"
|
||||
}
|
||||
main() {
|
||||
rc=0
|
||||
common_args="--ansible"
|
||||
if is_verbose; then
|
||||
common_args="${common_args} --verbose"
|
||||
fi
|
||||
if is_dry_run; then
|
||||
common_args="${common_args} --dry-run"
|
||||
fi
|
||||
|
||||
if [ -d "/etc/.git" ]; then
|
||||
# shellcheck disable=SC2086,SC2090
|
||||
${evocommit_bin} ${common_args} --repository /etc --message "${MESSAGE}"
|
||||
last_rc=$?
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
rc=${last_rc}
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -d "/etc/bind/.git" ]; then
|
||||
# shellcheck disable=SC2086,SC2090
|
||||
${evocommit_bin} ${common_args} --repository /etc/bind --message "${MESSAGE}"
|
||||
last_rc=$?
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
rc=${last_rc}
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -d "/usr/share/scripts/.git" ]; then
|
||||
# shellcheck disable=SC2086,SC2090
|
||||
${evocommit_bin} ${common_args} --repository /usr/share/scripts --message "${MESSAGE}"
|
||||
last_rc=$?
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
rc=${last_rc}
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "${LXC}" = "1" ] && [ -n "${lxc_ls_bin}" ]; then
|
||||
for container in $(${lxc_ls_bin} -1); do
|
||||
if [ -n "${lxc_config_bin}" ]; then
|
||||
# discovered path
|
||||
etc_path="$(${lxc_config_bin} lxc.lxcpath)/${container}/rootfs/etc"
|
||||
else
|
||||
# fallback to default path
|
||||
etc_path="/var/lib/lxc/${container}/rootfs/etc"
|
||||
fi
|
||||
|
||||
if [ -d "${etc_path}/.git" ]; then
|
||||
# shellcheck disable=SC2086,SC2090
|
||||
${evocommit_bin} ${common_args} --repository "${etc_path}" --message "${MESSAGE}"
|
||||
last_rc=$?
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
rc=${last_rc}
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
exit ${rc}
|
||||
}
|
||||
|
||||
# Parse options
|
||||
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
|
||||
while :; do
|
||||
case ${1:-''} in
|
||||
-h|-\?|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
-V|--version)
|
||||
show_version
|
||||
exit 0
|
||||
;;
|
||||
--message)
|
||||
# message options, with value speparated by space
|
||||
if [ -n "$2" ]; then
|
||||
MESSAGE=$2
|
||||
shift
|
||||
else
|
||||
printf 'FAILED: "--message" requires a non-empty option argument.\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--message=?*)
|
||||
# message options, with value speparated by =
|
||||
MESSAGE=${1#*=}
|
||||
;;
|
||||
--message=)
|
||||
# message options, without value
|
||||
printf 'FAILED: "--message" requires a non-empty option argument.\n' >&2
|
||||
exit 1
|
||||
;;
|
||||
--no-lxc)
|
||||
LXC=0
|
||||
;;
|
||||
-n|--dry-run)
|
||||
# disable actual commands
|
||||
DRY_RUN=1
|
||||
;;
|
||||
-v|--verbose)
|
||||
# print verbose information
|
||||
VERBOSE=1
|
||||
;;
|
||||
--)
|
||||
# End of all options.
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-?*|[[:alnum:]]*)
|
||||
# ignore unknown options
|
||||
printf 'FAILED: Unknown option (ignored): %s\n' "$1" >&2
|
||||
;;
|
||||
*)
|
||||
# Default case: If no more options then break out of the loop.
|
||||
break
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
if [ -z "${MESSAGE}" ]; then
|
||||
echo "FAILED: missing message parameter" >&2
|
||||
show_usage
|
||||
exit 1
|
||||
fi
|
||||
DRY_RUN=${DRY_RUN:-0}
|
||||
VERBOSE=${VERBOSE:-0}
|
||||
LXC=${LXC:-1}
|
||||
|
||||
evocommit_bin=$(command -v evocommit)
|
||||
if [ -z "${evocommit_bin}" ]; then
|
||||
echo "FAILED: evocommit not found" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
lxc_ls_bin=$(command -v lxc-ls)
|
||||
lxc_config_bin=$(command -v lxc-config)
|
||||
|
||||
main
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -u
|
||||
|
||||
repositories="/etc /etc/bind/ /usr/share/scripts"
|
||||
|
||||
for repository in ${repositories}; do
|
||||
if [ -d "${repository}/.git" ]; then
|
||||
git --git-dir="${repository}/.git" gc --quiet
|
||||
fi
|
||||
done
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -u
|
||||
|
||||
repositories="/etc /etc/bind/ /usr/share/scripts"
|
||||
|
||||
for repository in ${repositories}; do
|
||||
if [ -d "${repository}/.git" ]; then
|
||||
git --git-dir="${repository}/.git" --work-tree="${repository}" status --short
|
||||
fi
|
||||
done
|
|
@ -0,0 +1,271 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -u
|
||||
|
||||
VERSION="22.04"
|
||||
|
||||
show_version() {
|
||||
cat <<END
|
||||
evocommit version ${VERSION}
|
||||
|
||||
Copyright 2022 Evolix <info@evolix.fr>,
|
||||
Jérémy Lecour <jlecour@evolix.fr>
|
||||
and others.
|
||||
|
||||
evocommit comes with ABSOLUTELY NO WARRANTY. This is free software,
|
||||
and you are welcome to redistribute it under certain conditions.
|
||||
See the GNU General Public Licence for details.
|
||||
END
|
||||
}
|
||||
|
||||
show_help() {
|
||||
cat <<END
|
||||
evocommit helps properly committing changes in a repository
|
||||
|
||||
END
|
||||
show_usage
|
||||
}
|
||||
show_usage() {
|
||||
cat <<END
|
||||
Usage: evocommit --repository /path/to/repository --message "add new host"
|
||||
|
||||
Options
|
||||
--repository PATH set the path for the repository
|
||||
--message MESSAGE set the commit message
|
||||
-V, --version print version number
|
||||
-v, --verbose increase verbosity
|
||||
-n, --dry-run actions are not executed
|
||||
--help print this message and exit
|
||||
--version print version and exit
|
||||
END
|
||||
}
|
||||
|
||||
syslog() {
|
||||
if [ -x "${LOGGER_BIN}" ]; then
|
||||
${LOGGER_BIN} -t "evocommit" "$1"
|
||||
fi
|
||||
}
|
||||
get_system() {
|
||||
uname -s
|
||||
}
|
||||
is_repository_readonly() {
|
||||
if [ "$(get_system)" = "OpenBSD" ]; then
|
||||
partition=$(stat -f '%Sd' $1)
|
||||
mount | grep "${partition}" | grep -q "read-only"
|
||||
elif command -v findmnt >/dev/null; then
|
||||
mountpoint=$(stat -c '%m' $1)
|
||||
findmnt "${mountpoint}" --noheadings --output OPTIONS -O ro
|
||||
else
|
||||
grep /usr /proc/mounts | grep -E '\bro\b'
|
||||
fi
|
||||
}
|
||||
remount_repository_readwrite() {
|
||||
if [ "$(get_system)" = "OpenBSD" ]; then
|
||||
partition=$(stat -f '%Sd' $1)
|
||||
mount -u -w /dev/${partition} 2>/dev/null
|
||||
syslog "Re-mount ${mountpoint} as read-write to commit in repository $1"
|
||||
else
|
||||
mountpoint=$(stat -c '%m' $1)
|
||||
mount -o remount,rw ${mountpoint}
|
||||
syslog "Re-mount ${mountpoint} as read-write to commit in repository $1"
|
||||
fi
|
||||
}
|
||||
remount_repository_readonly() {
|
||||
if [ "$(get_system)" = "OpenBSD" ]; then
|
||||
partition=$(stat -f '%Sd' $1)
|
||||
mount -u -r /dev/${partition} 2>/dev/null
|
||||
syslog "Re-mount ${mountpoint} as read-only after commit to repository $1"
|
||||
else
|
||||
mountpoint=$(stat -c '%m' $1)
|
||||
mount -o remount,ro ${mountpoint} 2>/dev/null
|
||||
syslog "Re-mount ${mountpoint} as read-only after commit to repository $1"
|
||||
fi
|
||||
}
|
||||
is_dry_run() {
|
||||
test "${DRY_RUN}" = "1"
|
||||
}
|
||||
is_verbose() {
|
||||
test "${VERBOSE}" = "1"
|
||||
}
|
||||
is_ansible() {
|
||||
test "${ANSIBLE}" = "1"
|
||||
}
|
||||
main() {
|
||||
rc=0
|
||||
lock="${GIT_DIR}/index.lock"
|
||||
if [ -f "${lock}" ]; then
|
||||
limit=$(($(date +"%s") - (1 * 60 * 60)))
|
||||
if [ "$(get_system)" = "OpenBSD" ]; then
|
||||
updated_at=$(stat -f "%m" "${lock}")
|
||||
else
|
||||
updated_at=$(stat -c "%Y" "${lock}")
|
||||
fi
|
||||
if [ "$updated_at" -lt "$limit" ]; then
|
||||
rm -f "${lock}"
|
||||
fi
|
||||
fi
|
||||
|
||||
git_status=$(${GIT_BIN} status --porcelain)
|
||||
|
||||
if [ -n "${git_status}" ]; then
|
||||
if is_dry_run; then
|
||||
${GIT_BIN} status
|
||||
else
|
||||
readonly_orig=0
|
||||
# remount mount point read-write if currently readonly
|
||||
if is_repository_readonly "${REPOSITORY}"; then
|
||||
readonly_orig=1;
|
||||
remount_repository_readwrite "${REPOSITORY}";
|
||||
fi
|
||||
author=$(logname)
|
||||
email=$(git config --get user.email)
|
||||
email=${email:-"${author}@evolix.net"}
|
||||
|
||||
# commit changes
|
||||
git_add_result=$(${GIT_BIN} add --all)
|
||||
git_add_rc=$?
|
||||
|
||||
if is_ansible; then
|
||||
if [ ${git_add_rc} -ne 0 ]; then
|
||||
printf "FAILED: %s\n%s" "can't add changes in ${REPOSITORY}" "${git_add_result}"
|
||||
rc=1
|
||||
fi
|
||||
fi
|
||||
|
||||
git_commit_result=$(${GIT_BIN} commit --message "${MESSAGE}" --author "${author} <${email}>")
|
||||
git_commit_rc=$?
|
||||
|
||||
if is_ansible; then
|
||||
if [ ${git_commit_rc} -eq 0 ]; then
|
||||
printf "CHANGED: %s\n" "commit done in ${REPOSITORY} with \`${MESSAGE}'"
|
||||
else
|
||||
printf "FAILED: %s\n%s" "can't commit in ${REPOSITORY} \`${MESSAGE}'" "${git_commit_result}"
|
||||
rc=1
|
||||
fi
|
||||
fi
|
||||
|
||||
# remount mount point read-only if it was before
|
||||
if [ ${readonly_orig} -eq 1 ]; then
|
||||
remount_repository_readonly "${REPOSITORY}"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if is_ansible; then
|
||||
printf "INFO: %s\n" "no commit in ${REPOSITORY}'"
|
||||
fi
|
||||
fi
|
||||
|
||||
unset GIT_DIR
|
||||
unset GIT_WORK_TREE
|
||||
|
||||
exit ${rc}
|
||||
}
|
||||
# Parse options
|
||||
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
|
||||
while :; do
|
||||
case ${1:-''} in
|
||||
-h|-\?|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
-V|--version)
|
||||
show_version
|
||||
exit 0
|
||||
;;
|
||||
--message)
|
||||
# message options, with value speparated by space
|
||||
if [ -n "$2" ]; then
|
||||
MESSAGE=$2
|
||||
shift
|
||||
else
|
||||
printf 'ERROR: "--message" requires a non-empty option argument.\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--message=?*)
|
||||
# message options, with value speparated by =
|
||||
MESSAGE=${1#*=}
|
||||
;;
|
||||
--message=)
|
||||
# message options, without value
|
||||
printf 'ERROR: "--message" requires a non-empty option argument.\n' >&2
|
||||
exit 1
|
||||
;;
|
||||
--repository)
|
||||
# repository options, with value speparated by space
|
||||
if [ -n "$2" ]; then
|
||||
REPOSITORY=$2
|
||||
shift
|
||||
else
|
||||
printf 'ERROR: "--repository" requires a non-empty option argument.\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--repository=?*)
|
||||
# repository options, with value speparated by =
|
||||
REPOSITORY=${1#*=}
|
||||
;;
|
||||
--repository=)
|
||||
# repository options, without value
|
||||
printf 'ERROR: "--repository" requires a non-empty option argument.\n' >&2
|
||||
exit 1
|
||||
;;
|
||||
-n|--dry-run)
|
||||
# disable actual commands
|
||||
DRY_RUN=1
|
||||
;;
|
||||
-v|--verbose)
|
||||
# print verbose information
|
||||
VERBOSE=1
|
||||
;;
|
||||
--ansible)
|
||||
# print information for Ansible
|
||||
ANSIBLE=1
|
||||
;;
|
||||
--)
|
||||
# End of all options.
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-?*|[[:alnum:]]*)
|
||||
# ignore unknown options
|
||||
printf 'WARN: Unknown option (ignored): %s\n' "$1" >&2
|
||||
;;
|
||||
*)
|
||||
# Default case: If no more options then break out of the loop.
|
||||
break
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
if [ -z "${MESSAGE}" ]; then
|
||||
echo "Error: missing message parameter" >&2
|
||||
show_usage
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "${REPOSITORY}" ]; then
|
||||
echo "Error: missing repository parameter" >&2
|
||||
show_usage
|
||||
exit 1
|
||||
fi
|
||||
DRY_RUN=${DRY_RUN:-0}
|
||||
VERBOSE=${VERBOSE:-0}
|
||||
ANSIBLE=${ANSIBLE:-0}
|
||||
|
||||
GIT_BIN=$(command -v git)
|
||||
readonly GIT_BIN
|
||||
|
||||
LOGGER_BIN=$(command -v logger)
|
||||
readonly LOGGER_BIN
|
||||
|
||||
export GIT_DIR="${REPOSITORY}/.git"
|
||||
export GIT_WORK_TREE="${REPOSITORY}"
|
||||
|
||||
if [ -d "${GIT_DIR}" ]; then
|
||||
main
|
||||
else
|
||||
echo "There is no Git repository in '${REPOSITORY}'" >&2
|
||||
exit 1
|
||||
fi
|
|
@ -1,4 +0,0 @@
|
|||
aliases.db
|
||||
*.swp
|
||||
random.seed
|
||||
openvpn/ipp.txt
|
|
@ -1,72 +1,12 @@
|
|||
# yamllint disable rule:line-length
|
||||
---
|
||||
- name: is /etc clean?
|
||||
command: git status --porcelain
|
||||
args:
|
||||
chdir: /etc
|
||||
changed_when: false
|
||||
register: git_status
|
||||
when: not ansible_check_mode
|
||||
|
||||
- name: "Execute ansible-commit"
|
||||
ansible.builtin.command: "/usr/local/bin/ansible-commit --verbose --message \"{{ commit_message | mandatory }}\""
|
||||
changed_when:
|
||||
- _ansible_commit.stdout
|
||||
- "'CHANGED:' in _ansible_commit.stdout"
|
||||
ignore_errors: true
|
||||
register: _ansible_commit
|
||||
tags:
|
||||
- etc-git
|
||||
- commit-etc
|
||||
|
||||
- debug:
|
||||
var: git_status
|
||||
verbosity: 3
|
||||
tags:
|
||||
- etc-git
|
||||
- commit-etc
|
||||
|
||||
- name: fetch current Git user.email
|
||||
git_config:
|
||||
name: user.email
|
||||
repo: /etc
|
||||
scope: local
|
||||
register: git_config_user_email
|
||||
ignore_errors: true
|
||||
tags:
|
||||
- etc-git
|
||||
- commit-etc
|
||||
|
||||
- name: set commit author
|
||||
set_fact:
|
||||
commit_author: >
|
||||
{% if ansible_env.SUDO_USER is not defined %}
|
||||
root
|
||||
{% else %}
|
||||
{{ ansible_env.SUDO_USER }}
|
||||
{% endif %}
|
||||
commit_email: >
|
||||
{% if git_config_user_email.config_value is not defined
|
||||
or git_config_user_email.config_value == "" %}
|
||||
root@localhost
|
||||
{% else %}
|
||||
{{ git_config_user_email.config_value }}
|
||||
{% endif %}
|
||||
tags:
|
||||
- etc-git
|
||||
- commit-etc
|
||||
|
||||
- name: /etc modifications are committed
|
||||
shell: >
|
||||
git add -A .
|
||||
&& git commit
|
||||
-m "{{ commit_message | mandatory }}"
|
||||
--author
|
||||
"{{ commit_author | mandatory }} <{{ commit_email | mandatory }}>"
|
||||
args:
|
||||
chdir: /etc
|
||||
register: etc_commit_end_run
|
||||
when: not ansible_check_mode and git_status.stdout != ""
|
||||
ignore_errors: true
|
||||
tags:
|
||||
- etc-git
|
||||
- commit-etc
|
||||
|
||||
- debug:
|
||||
var: etc_commit_end_run
|
||||
verbosity: 4
|
||||
tags:
|
||||
- etc-git
|
||||
- commit-etc
|
||||
- always
|
||||
|
|
|
@ -1,153 +1,36 @@
|
|||
---
|
||||
|
||||
- name: Git is installed
|
||||
openbsd_pkg:
|
||||
name: git
|
||||
state: present
|
||||
tags:
|
||||
- etc-git
|
||||
# openbsd_pkg is broken since OpenBSD 7.4 with the version of Ansible we currently use
|
||||
#- name: "Git is installed"
|
||||
# community.general.openbsd_pkg:
|
||||
# name: git
|
||||
# state: present
|
||||
# tags:
|
||||
# - etc-git
|
||||
|
||||
- name: /etc is versioned with git
|
||||
command: "git init ."
|
||||
args:
|
||||
chdir: /etc
|
||||
creates: /etc/.git/
|
||||
warn: false
|
||||
register: git_init
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: Git user.email is configured
|
||||
git_config:
|
||||
name: user.email
|
||||
repo: /etc
|
||||
scope: local
|
||||
value: "root@{{ inventory_hostname }}.{{ general_technical_realm }}"
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: /etc/.git is secure
|
||||
file:
|
||||
path: /etc/.git
|
||||
owner: root
|
||||
mode: "0700"
|
||||
state: directory
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: /etc/.gitignore is present
|
||||
copy:
|
||||
src: gitignore
|
||||
dest: /etc/.gitignore
|
||||
owner: root
|
||||
mode: "0600"
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: Set vim as default editor
|
||||
git_config:
|
||||
name: core.editor
|
||||
scope: global
|
||||
value: vim
|
||||
|
||||
- name: does /etc/ have any commit?
|
||||
command: "git log"
|
||||
args:
|
||||
chdir: /etc
|
||||
warn: false
|
||||
- name: "Check if git is already installed"
|
||||
ansible.builtin.command:
|
||||
cmd: pkg_info -Iq inst:git
|
||||
register: is_installed
|
||||
ignore_errors: true
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
register: git_log
|
||||
check_mode: false
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: initial commit is present?
|
||||
shell: "git add -A . && git commit -m \"Initial commit via Ansible\""
|
||||
args:
|
||||
chdir: /etc
|
||||
warn: false
|
||||
register: git_commit
|
||||
when: git_log.rc != 0 or (git_init is defined and git_init.changed)
|
||||
- name: "Install git"
|
||||
ansible.builtin.command:
|
||||
cmd: pkg_add git
|
||||
when: "'Can\\'t find inst:' in is_installed.stderr"
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: Optimize script is installed in monthly crontab
|
||||
lineinfile:
|
||||
path: /etc/monthly.local
|
||||
line: '/usr/local/bin/git --git-dir /etc/.git gc --quiet'
|
||||
owner: root
|
||||
mode: "0644"
|
||||
create: true
|
||||
- name: "Install and configure utilities"
|
||||
include: utils.yml
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: cron job for /etc/.git status is installed
|
||||
lineinfile:
|
||||
path: /etc/daily.local
|
||||
line:
|
||||
'/usr/local/bin/git --git-dir=/etc/.git --work-tree=/etc status --short'
|
||||
owner: root
|
||||
mode: "0644"
|
||||
create: true
|
||||
when: etc_git_monitor_status
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: cron job for /etc/.git status is installed - next_part
|
||||
lineinfile:
|
||||
path: /etc/daily.local
|
||||
line: 'next_part "Checking /etc git status:"'
|
||||
insertbefore:
|
||||
'/usr/local/bin/git --git-dir=/etc/.git --work-tree=/etc status --short'
|
||||
owner: root
|
||||
mode: "0644"
|
||||
create: true
|
||||
when: etc_git_monitor_status
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: cron job for /etc/.git status is removed
|
||||
lineinfile:
|
||||
path: /etc/daily.local
|
||||
line: "{{ item }}"
|
||||
owner: root
|
||||
mode: "0644"
|
||||
state: absent
|
||||
with_items:
|
||||
- 'next_part "Checking /etc git status:"'
|
||||
- '/usr/local/bin/git --git-dir=/etc/.git --work-tree=/etc status --short'
|
||||
when: not etc_git_monitor_status
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: hourly cron job for /etc/.git status is installed
|
||||
cron:
|
||||
name: git status
|
||||
minute: "42"
|
||||
job: >
|
||||
who
|
||||
> /dev/null
|
||||
|| /usr/local/bin/git
|
||||
--git-dir=/etc/.git
|
||||
--work-tree=/etc
|
||||
status --short
|
||||
when: etc_git_monitor_status
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: hourly cron job for /etc/.git status is removed
|
||||
cron:
|
||||
name: git status
|
||||
minute: 42
|
||||
job: >
|
||||
who
|
||||
> /dev/null
|
||||
|| /usr/local/bin/git
|
||||
--git-dir=/etc/.git
|
||||
--work-tree=/etc
|
||||
status --short
|
||||
state: absent
|
||||
when: not etc_git_monitor_status
|
||||
- name: "Configure repositories"
|
||||
include: repositories.yml
|
||||
when: etc_git_config_repositories | bool
|
||||
tags:
|
||||
- etc-git
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
|
||||
- include: repository.yml
|
||||
vars:
|
||||
repository_path: "/etc"
|
||||
gitignore_items:
|
||||
- "aliases.db"
|
||||
- "*.swp"
|
||||
- "random.seed"
|
||||
- "openvpn/ipp.txt"
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: "Verify /usr/share/scripts presence"
|
||||
ansible.builtin.stat:
|
||||
path: /usr/share/scripts
|
||||
register: _usr_share_scripts
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- include: repository.yml
|
||||
vars:
|
||||
repository_path: "/usr/share/scripts"
|
||||
gitignore_items: []
|
||||
when:
|
||||
- _usr_share_scripts.stat.exists
|
||||
- _usr_share_scripts.stat.isdir
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- include: repository.yml
|
||||
vars:
|
||||
repository_path: "/var/unbound/etc"
|
||||
gitignore_items: []
|
||||
tags:
|
||||
- etc-git
|
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
|
||||
- name: "{{ repository_path }} is versioned with git"
|
||||
ansible.builtin.command: "git init ."
|
||||
args:
|
||||
chdir: "{{ repository_path }}"
|
||||
creates: "{{ repository_path }}/.git/"
|
||||
register: git_init
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: "Git user.email is configured"
|
||||
community.general.git_config:
|
||||
name: user.email
|
||||
repo: "{{ repository_path }}"
|
||||
scope: local
|
||||
value: "root@{{ inventory_hostname }}.{{ general_technical_realm }}"
|
||||
when: not ansible_check_mode
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: "{{ repository_path }}/.git is restricted to root"
|
||||
ansible.builtin.file:
|
||||
path: "{{ repository_path }}/.git"
|
||||
owner: root
|
||||
mode: "0700"
|
||||
state: directory
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: "Some entries MUST be in the {{ repository_path }}/.gitignore file"
|
||||
ansible.builtin.lineinfile:
|
||||
dest: "{{ repository_path }}/.gitignore"
|
||||
line: "{{ item }}"
|
||||
owner: root
|
||||
mode: "0600"
|
||||
create: true
|
||||
loop: "{{ gitignore_items | default([]) }}"
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: "Set vim as default editor"
|
||||
community.general.git_config:
|
||||
name: core.editor
|
||||
scope: global
|
||||
value: vim
|
||||
when: not ansible_check_mode
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: "Does {{ repository_path }}/ have any commit?"
|
||||
ansible.builtin.command: "git log"
|
||||
args:
|
||||
chdir: "{{ repository_path }}"
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
register: git_log
|
||||
check_mode: false
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: "Initial commit is present?"
|
||||
ansible.builtin.shell: "git add -A . && git commit -m \"Initial commit via Ansible\""
|
||||
args:
|
||||
chdir: "{{ repository_path }}"
|
||||
register: git_commit
|
||||
when: git_log.rc != 0 or (git_init is defined and git_init is changed)
|
||||
tags:
|
||||
- etc-git
|
|
@ -0,0 +1,139 @@
|
|||
# yamllint disable rule:line-length
|
||||
---
|
||||
|
||||
- name: "evocommit script is installed"
|
||||
ansible.builtin.copy:
|
||||
src: evocommit
|
||||
dest: /usr/local/bin/evocommit
|
||||
mode: "0755"
|
||||
force: true
|
||||
tags:
|
||||
- etc-git
|
||||
- etc-git-utils
|
||||
|
||||
- name: "ansible-commit script is installed"
|
||||
ansible.builtin.copy:
|
||||
src: ansible-commit
|
||||
dest: /usr/local/bin/ansible-commit
|
||||
mode: "0755"
|
||||
force: true
|
||||
tags:
|
||||
- etc-git
|
||||
- etc-git-utils
|
||||
|
||||
- name: "etc-git-optimize script is installed"
|
||||
ansible.builtin.copy:
|
||||
src: etc-git-optimize
|
||||
dest: /usr/share/scripts/etc-git-optimize
|
||||
mode: "0755"
|
||||
force: true
|
||||
tags:
|
||||
- etc-git
|
||||
- etc-git-utils
|
||||
|
||||
- name: "etc-git-status script is installed"
|
||||
ansible.builtin.copy:
|
||||
src: etc-git-status
|
||||
dest: /usr/share/scripts/etc-git-status
|
||||
mode: "0755"
|
||||
force: true
|
||||
tags:
|
||||
- etc-git
|
||||
- etc-git-utils
|
||||
|
||||
- name: "Legacy monthly cron job for /etc/.git optimization is absent"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/monthly.local
|
||||
line: '/usr/local/bin/git --git-dir /etc/.git gc --quiet'
|
||||
state: absent
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: "Legacy hourly cron job for /etc/.git status is absent"
|
||||
ansible.builtin.cron:
|
||||
name: git status
|
||||
minute: "42"
|
||||
job: who > /dev/null || /usr/local/bin/git --git-dir=/etc/.git --work-tree=/etc status --short
|
||||
state: absent
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: "Legacy daily cron jobs for /etc/.git status are absent"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/daily.local
|
||||
line: "{{ item }}"
|
||||
owner: root
|
||||
mode: "0600"
|
||||
state: absent
|
||||
with_items:
|
||||
- 'next_part "Checking /etc git status:"'
|
||||
- '/usr/local/bin/git --git-dir=/etc/.git --work-tree=/etc status --short'
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: "Cron job for monthly git optimization"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/monthly.local
|
||||
line: "/usr/share/scripts/etc-git-optimize"
|
||||
owner: root
|
||||
mode: "0600"
|
||||
create: true
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: "Cron job for monthly git optimization - next_part"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/monthly.local
|
||||
line: 'next_part "Monthly optimization:"'
|
||||
insertbefore: "/usr/share/scripts/etc-git-optimize"
|
||||
owner: root
|
||||
mode: "0600"
|
||||
create: true
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: "Cron job for hourly git status"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/hourly.local
|
||||
line: "who > /dev/null || /usr/share/scripts/etc-git-status"
|
||||
owner: root
|
||||
mode: "0600"
|
||||
create: true
|
||||
state: "{{ etc_git_monitor_status | bool | ternary('present','absent') }}"
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: "Cron job for hourly git status - next_part"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/hourly.local
|
||||
line: 'next_part "Hourly warning for unclean Git repository if nobody is connected:"'
|
||||
insertbefore: "who > /dev/null || /usr/share/scripts/etc-git-status"
|
||||
owner: root
|
||||
mode: "0600"
|
||||
create: true
|
||||
state: "{{ etc_git_monitor_status | bool | ternary('present','absent') }}"
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: "Cron job for daily git status"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/daily.local
|
||||
line: "/usr/share/scripts/etc-git-status"
|
||||
owner: root
|
||||
mode: "0600"
|
||||
create: true
|
||||
state: "{{ etc_git_monitor_status | bool | ternary('present','absent') }}"
|
||||
tags:
|
||||
- etc-git
|
||||
|
||||
- name: "Cron job for daily git status - next_part"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/daily.local
|
||||
line: 'next_part "Daily warning for unclean Git repository:"'
|
||||
insertbefore: "/usr/share/scripts/etc-git-status"
|
||||
owner: root
|
||||
mode: "0600"
|
||||
create: true
|
||||
state: "{{ etc_git_monitor_status | bool | ternary('present','absent') }}"
|
||||
tags:
|
||||
- etc-git
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
update-evobackup-canary --who @daily
|
|
@ -0,0 +1,670 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Script Evobackup client
|
||||
# See https://gitea.evolix.org/evolix/evobackup
|
||||
#
|
||||
# Authors: Evolix <info@evolix.fr>,
|
||||
# Gregory Colpart <reg@evolix.fr>,
|
||||
# Romain Dessort <rdessort@evolix.fr>,
|
||||
# Benoit Série <bserie@evolix.fr>,
|
||||
# Tristan Pilat <tpilat@evolix.fr>,
|
||||
# Victor Laborie <vlaborie@evolix.fr>,
|
||||
# Jérémy Lecour <jlecour@evolix.fr>
|
||||
# and others.
|
||||
#
|
||||
# Licence: AGPLv3
|
||||
#
|
||||
# /!\ DON'T FORGET TO SET "MAIL" and "SERVERS" VARIABLES
|
||||
|
||||
##### Configuration ###################################################
|
||||
|
||||
VERSION="22.12"
|
||||
|
||||
# email adress for notifications
|
||||
MAIL=jdoe@example.com
|
||||
|
||||
# list of hosts (hostname or IP) and SSH port for Rsync
|
||||
SERVERS="node0.backup.example.com:2XXX node1.backup.example.com:2XXX"
|
||||
|
||||
# explicit PATH
|
||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin
|
||||
|
||||
# Should we fallback on other servers when the first one is unreachable?
|
||||
SERVERS_FALLBACK=${SERVERS_FALLBACK:-1}
|
||||
|
||||
# timeout (in seconds) for SSH connections
|
||||
SSH_CONNECT_TIMEOUT=${SSH_CONNECT_TIMEOUT:-90}
|
||||
|
||||
# We use /home/backup : feel free to use your own dir
|
||||
LOCAL_BACKUP_DIR="/home/backup"
|
||||
|
||||
# You can set "linux" or "bsd" manually or let it choose automatically
|
||||
SYSTEM=$(uname | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
# Store pid in a file named after this program's name
|
||||
PROGNAME=$(basename "$0")
|
||||
PIDFILE="/var/run/${PROGNAME}.pid"
|
||||
|
||||
# Customize the log path if you have multiple scripts and with separate logs
|
||||
LOGFILE="/var/log/evobackup.log"
|
||||
|
||||
# Full Rsync log file, reset each time
|
||||
RSYNC_LOGFILE="/var/log/${PROGNAME}.rsync.log"
|
||||
|
||||
HOSTNAME=$(hostname)
|
||||
|
||||
DATE_FORMAT="%Y-%m-%d %H:%M:%S"
|
||||
|
||||
# Enable/disable local tasks (default: enabled)
|
||||
: "${LOCAL_TASKS:=1}"
|
||||
# Enable/disable sync tasks (default: enabled)
|
||||
: "${SYNC_TASKS:=1}"
|
||||
|
||||
CANARY_FILE="/zzz_evobackup_canary"
|
||||
|
||||
# Source paths can be customized
|
||||
# Empty lines, and lines containing # or ; are ignored
|
||||
RSYNC_INCLUDES="
|
||||
/etc
|
||||
/root
|
||||
/var
|
||||
/home
|
||||
"
|
||||
|
||||
# Excluded paths can be customized
|
||||
# Empty lines, and lines beginning with # or ; are ignored
|
||||
RSYNC_EXCLUDES="
|
||||
/dev
|
||||
/proc
|
||||
/run
|
||||
/sys
|
||||
/tmp
|
||||
/usr/doc
|
||||
/usr/obj
|
||||
/usr/share/doc
|
||||
/usr/src
|
||||
/var/apt
|
||||
/var/cache
|
||||
/var/db/munin/*.tmp
|
||||
/var/lib/amavis/amavisd.sock
|
||||
/var/lib/amavis/tmp
|
||||
/var/lib/clamav/*.tmp
|
||||
/var/lib/elasticsearch
|
||||
/var/lib/metche
|
||||
/var/lib/mongodb
|
||||
/var/lib/munin/*tmp*
|
||||
/var/lib/mysql
|
||||
/var/lib/php/sessions
|
||||
/var/lib/php5
|
||||
/var/lib/postgres
|
||||
/var/lib/postgresql
|
||||
/var/lib/sympa
|
||||
/var/lock
|
||||
/var/run
|
||||
/var/spool/postfix
|
||||
/var/spool/smtpd
|
||||
/var/spool/squid
|
||||
/var/state
|
||||
/var/tmp
|
||||
lost+found
|
||||
.nfs.*
|
||||
lxc/*/rootfs/tmp
|
||||
lxc/*/rootfs/usr/doc
|
||||
lxc/*/rootfs/usr/obj
|
||||
lxc/*/rootfs/usr/share/doc
|
||||
lxc/*/rootfs/usr/src
|
||||
lxc/*/rootfs/var/apt
|
||||
lxc/*/rootfs/var/cache
|
||||
lxc/*/rootfs/var/lib/php5
|
||||
lxc/*/rootfs/var/lib/php/sessions
|
||||
lxc/*/rootfs/var/lock
|
||||
lxc/*/rootfs/var/run
|
||||
lxc/*/rootfs/var/state
|
||||
lxc/*/rootfs/var/tmp
|
||||
/home/mysqltmp
|
||||
"
|
||||
|
||||
|
||||
##### FUNCTIONS #######################################################
|
||||
|
||||
local_tasks() {
|
||||
log "START LOCAL_TASKS"
|
||||
|
||||
# You can comment or uncomment sections below to customize the backup
|
||||
|
||||
## OpenLDAP : example with slapcat
|
||||
# slapcat -n 0 -l ${LOCAL_BACKUP_DIR}/config.ldap.bak
|
||||
# slapcat -n 1 -l ${LOCAL_BACKUP_DIR}/data.ldap.bak
|
||||
# slapcat -l ${LOCAL_BACKUP_DIR}/ldap.bak
|
||||
|
||||
## MySQL
|
||||
|
||||
## Purge previous dumps
|
||||
# rm -f ${LOCAL_BACKUP_DIR}/mysql.*.gz
|
||||
# rm -rf ${LOCAL_BACKUP_DIR}/mysql
|
||||
# rm -rf ${LOCAL_BACKUP_DIR}/mysqlhotcopy
|
||||
# rm -rf /home/mysqldump
|
||||
# find ${LOCAL_BACKUP_DIR}/ -type f -name '*.err' -delete
|
||||
|
||||
## example with global and compressed mysqldump
|
||||
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 \
|
||||
# --opt --all-databases --force --events --hex-blob 2> ${LOCAL_BACKUP_DIR}/mysql.bak.err | gzip --best > ${LOCAL_BACKUP_DIR}/mysql.bak.gz
|
||||
# last_rc=$?
|
||||
# if [ ${last_rc} -ne 0 ]; then
|
||||
# error "mysqldump (global compressed) returned an error ${last_rc}, check ${LOCAL_BACKUP_DIR}/mysql.bak.err"
|
||||
# rc=101
|
||||
# fi
|
||||
|
||||
## example with compressed SQL dump (with data) for each databases
|
||||
# mkdir -p -m 700 ${LOCAL_BACKUP_DIR}/mysql/
|
||||
# for i in $(mysql --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 -e 'show databases' -s --skip-column-names \
|
||||
# | grep --extended-regexp --invert-match "^(Database|information_schema|performance_schema|sys)"); do
|
||||
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf --force -P 3306 --events --hex-blob $i 2> ${LOCAL_BACKUP_DIR}/${i}.err | gzip --best > ${LOCAL_BACKUP_DIR}/mysql/${i}.sql.gz
|
||||
# last_rc=$?
|
||||
# if [ ${last_rc} -ne 0 ]; then
|
||||
# error "mysqldump (${i} compressed) returned an error ${last_rc}, check ${LOCAL_BACKUP_DIR}/${i}.err"
|
||||
# rc=102
|
||||
# fi
|
||||
# done
|
||||
|
||||
## Dump all grants (requires 'percona-toolkit' package)
|
||||
# mkdir -p -m 700 ${LOCAL_BACKUP_DIR}/mysql/
|
||||
# pt-show-grants --flush --no-header 2> ${LOCAL_BACKUP_DIR}/mysql/all_grants.err > ${LOCAL_BACKUP_DIR}/mysql/all_grants.sql
|
||||
# last_rc=$?
|
||||
# if [ ${last_rc} -ne 0 ]; then
|
||||
# error "pt-show-grants returned an error ${last_rc}, check ${LOCAL_BACKUP_DIR}/mysql/all_grants.err"
|
||||
# rc=103
|
||||
# fi
|
||||
|
||||
# Dump all variables
|
||||
# mysql -A -e"SHOW GLOBAL VARIABLES;" 2> ${LOCAL_BACKUP_DIR}/MySQLCurrentSettings.err > ${LOCAL_BACKUP_DIR}/MySQLCurrentSettings.txt
|
||||
# last_rc=$?
|
||||
# if [ ${last_rc} -ne 0 ]; then
|
||||
# error "mysql (variables) returned an error ${last_rc}, check ${LOCAL_BACKUP_DIR}/MySQLCurrentSettings.err"
|
||||
# rc=104
|
||||
# fi
|
||||
|
||||
## example with SQL dump (schema only, no data) for each databases
|
||||
# mkdir -p -m 700 ${LOCAL_BACKUP_DIR}/mysql/
|
||||
# for i in $(mysql --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 -e 'show databases' -s --skip-column-names \
|
||||
# | grep --extended-regexp --invert-match "^(Database|information_schema|performance_schema|sys)"); do
|
||||
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf --force -P 3306 --no-data --databases $i 2> ${LOCAL_BACKUP_DIR}/${i}.schema.err > ${LOCAL_BACKUP_DIR}/mysql/${i}.schema.sql
|
||||
# last_rc=$?
|
||||
# if [ ${last_rc} -ne 0 ]; then
|
||||
# error "mysqldump (${i} schema) returned an error ${last_rc}, check ${LOCAL_BACKUP_DIR}/${i}.schema.err"
|
||||
# rc=105
|
||||
# fi
|
||||
# done
|
||||
|
||||
## example with *one* uncompressed SQL dump for *one* database (MYBASE)
|
||||
# mkdir -p -m 700 ${LOCAL_BACKUP_DIR}/mysql/MYBASE
|
||||
# chown -RL mysql ${LOCAL_BACKUP_DIR}/mysql/
|
||||
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf --force -Q \
|
||||
# --opt --events --hex-blob --skip-comments -T ${LOCAL_BACKUP_DIR}/mysql/MYBASE MYBASE 2> ${LOCAL_BACKUP_DIR}/mysql/MYBASE.err
|
||||
# last_rc=$?
|
||||
# if [ ${last_rc} -ne 0 ]; then
|
||||
# error "mysqldump (MYBASE) returned an error ${last_rc}, check ${LOCAL_BACKUP_DIR}/mysql/MYBASE.err"
|
||||
# rc=106
|
||||
# fi
|
||||
|
||||
## example with two dumps for each table (.sql/.txt) for all databases
|
||||
# for i in $(echo SHOW DATABASES | mysql --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 \
|
||||
# | grep --extended-regexp --invert-match "^(Database|information_schema|performance_schema|sys)" ); do
|
||||
# mkdir -p -m 700 /home/mysqldump/$i ; chown -RL mysql /home/mysqldump
|
||||
# mysqldump --defaults-extra-file=/etc/mysql/debian.cnf --force -P 3306 -Q --opt --events --hex-blob --skip-comments \
|
||||
# --fields-enclosed-by='\"' --fields-terminated-by=',' -T /home/mysqldump/$i $i 2> /home/mysqldump/$i.err"
|
||||
# last_rc=$?
|
||||
# if [ ${last_rc} -ne 0 ]; then
|
||||
# error "mysqldump (${i} files) returned an error ${last_rc}, check /home/mysqldump/$i.err"
|
||||
# rc=107
|
||||
# fi
|
||||
# done
|
||||
|
||||
## example with mysqlhotcopy
|
||||
# mkdir -p -m 700 ${LOCAL_BACKUP_DIR}/mysqlhotcopy/
|
||||
# mysqlhotcopy MYBASE ${LOCAL_BACKUP_DIR}/mysqlhotcopy/ 2> ${LOCAL_BACKUP_DIR}/mysqlhotcopy/MYBASE.err
|
||||
# last_rc=$?
|
||||
# if [ ${last_rc} -ne 0 ]; then
|
||||
# error "mysqlhotcopy returned an error ${last_rc}, check ${LOCAL_BACKUP_DIR}/mysqlhotcopy/MYBASE.err"
|
||||
# rc=108
|
||||
# fi
|
||||
|
||||
## example for multiples MySQL instances
|
||||
# mysqladminpasswd=$(grep -m1 'password = .*' /root/.my.cnf|cut -d" " -f3)
|
||||
# grep --extended-regexp "^port\s*=\s*\d*" /etc/mysql/my.cnf | while read instance; do
|
||||
# instance=$(echo "$instance"|awk '{ print $3 }')
|
||||
# if [ "$instance" != "3306" ]
|
||||
# then
|
||||
# mysqldump -P $instance --opt --all-databases --hex-blob -u mysqladmin -p$mysqladminpasswd 2> ${LOCAL_BACKUP_DIR}/mysql.${instance}.err | gzip --best > ${LOCAL_BACKUP_DIR}/mysql.${instance}.bak.gz
|
||||
# last_rc=$?
|
||||
# if [ ${last_rc} -ne 0 ]; then
|
||||
# error "mysqldump (instance ${instance}) returned an error ${last_rc}, check ${LOCAL_BACKUP_DIR}/mysql.${instance}.err"
|
||||
# rc=107
|
||||
# fi
|
||||
# fi
|
||||
# done
|
||||
|
||||
## PostgreSQL
|
||||
|
||||
## Purge previous dumps
|
||||
# rm -rf ${LOCAL_BACKUP_DIR}/pg.*.gz
|
||||
# rm -rf ${LOCAL_BACKUP_DIR}/pg-backup.tar
|
||||
# rm -rf ${LOCAL_BACKUP_DIR}/postgresql/*
|
||||
|
||||
## example with pg_dumpall (warning: you need space in ~postgres)
|
||||
# su - postgres -c "pg_dumpall > ~/pg.dump.bak"
|
||||
# mv ~postgres/pg.dump.bak ${LOCAL_BACKUP_DIR}/
|
||||
|
||||
## another method with gzip directly piped
|
||||
# (
|
||||
# cd /var/lib/postgresql;
|
||||
# sudo -u postgres pg_dumpall | gzip > ${LOCAL_BACKUP_DIR}/pg.dump.bak.gz
|
||||
# )
|
||||
|
||||
## example with all tables from MYBASE excepts TABLE1 and TABLE2
|
||||
# pg_dump -p 5432 -h 127.0.0.1 -U USER --clean -F t --inserts -f ${LOCAL_BACKUP_DIR}/pg-backup.tar -t 'TABLE1' -t 'TABLE2' MYBASE
|
||||
|
||||
## example with only TABLE1 and TABLE2 from MYBASE
|
||||
# pg_dump -p 5432 -h 127.0.0.1 -U USER --clean -F t --inserts -f ${LOCAL_BACKUP_DIR}/pg-backup.tar -T 'TABLE1' -T 'TABLE2' MYBASE
|
||||
|
||||
## example with compressed PostgreSQL dump for each databases
|
||||
# mkdir -p -m 700 ${LOCAL_BACKUP_DIR}/postgresql
|
||||
# chown postgres:postgres ${LOCAL_BACKUP_DIR}/postgresql
|
||||
# (
|
||||
# cd /var/lib/postgresql
|
||||
# dbs=$(sudo -u postgres psql -U postgres -lt | awk -F\| '{print $1}' |grep -v template*)
|
||||
# for databases in $dbs ; do sudo -u postgres /usr/bin/pg_dump --create -s -U postgres -d $databases | gzip --best -c > ${LOCAL_BACKUP_DIR}/postgresql/$databases.sql.gz ; done
|
||||
# )
|
||||
|
||||
## MongoDB
|
||||
|
||||
## don't forget to create use with read-only access
|
||||
## > use admin
|
||||
## > db.createUser( { user: "mongobackup", pwd: "PASS", roles: [ "backup", ] } )
|
||||
## Purge previous dumps
|
||||
# rm -rf ${LOCAL_BACKUP_DIR}/mongodump/
|
||||
# mkdir -p -m 700 ${LOCAL_BACKUP_DIR}/mongodump/
|
||||
# mongodump --quiet -u mongobackup -pPASS -o ${LOCAL_BACKUP_DIR}/mongodump/
|
||||
# if [ $? -ne 0 ]; then
|
||||
# echo "Error with mongodump!"
|
||||
# fi
|
||||
|
||||
## Redis
|
||||
|
||||
## Purge previous dumps
|
||||
# rm -rf ${LOCAL_BACKUP_DIR}/redis/
|
||||
# rm -rf ${LOCAL_BACKUP_DIR}/redis-*
|
||||
## Copy dump.rdb file for each found instance
|
||||
# for instance in $(find /var/lib/ -mindepth 1 -maxdepth 1 -type d -name 'redis*'); do
|
||||
# if [ -f "${instance}/dump.rdb" ]; then
|
||||
# name=$(basename $instance)
|
||||
# mkdir -p ${LOCAL_BACKUP_DIR}/${name}
|
||||
# cp -a "${instance}/dump.rdb" "${LOCAL_BACKUP_DIR}/${name}"
|
||||
# fi
|
||||
# done
|
||||
|
||||
## ElasticSearch
|
||||
|
||||
## Take a snapshot as a backup.
|
||||
## Warning: You need to have a path.repo configured.
|
||||
## See: https://wiki.evolix.org/HowtoElasticsearch#snapshots-et-sauvegardes
|
||||
# curl -s -XDELETE "localhost:9200/_snapshot/snaprepo/snapshot.daily" >> "${LOGFILE}"
|
||||
# curl -s -XPUT "localhost:9200/_snapshot/snaprepo/snapshot.daily?wait_for_completion=true" >> "${LOGFILE}"
|
||||
## Clustered version here
|
||||
## It basically the same thing except that you need to check that NFS is mounted
|
||||
# if ss | grep ':nfs' | grep -q 'ip\.add\.res\.s1' && ss | grep ':nfs' | grep -q 'ip\.add\.res\.s2'
|
||||
# then
|
||||
# curl -s -XDELETE "localhost:9200/_snapshot/snaprepo/snapshot.daily" >> "${LOGFILE}"
|
||||
# curl -s -XPUT "localhost:9200/_snapshot/snaprepo/snapshot.daily?wait_for_completion=true" >> "${LOGFILE}"
|
||||
# else
|
||||
# echo 'Cannot make a snapshot of elasticsearch, at least one node is not mounting the repository.'
|
||||
# fi
|
||||
## If you need to keep older snapshot, for example the last 10 daily snapshots, replace the XDELETE and XPUT lines by :
|
||||
# for snapshot in $(curl -s -XGET "localhost:9200/_snapshot/snaprepo/_all?pretty=true" | grep -Eo 'snapshot_[0-9]{4}-[0-9]{2}-[0-9]{2}' | head -n -10); do
|
||||
# curl -s -XDELETE "localhost:9200/_snapshot/snaprepo/${snapshot}" | grep -v -Fx '{"acknowledged":true}'
|
||||
# done
|
||||
# date=$(/bin/date +%F)
|
||||
# curl -s -XPUT "localhost:9200/_snapshot/snaprepo/snapshot_${date}?wait_for_completion=true" >> "${LOGFILE}"
|
||||
|
||||
## RabbitMQ
|
||||
|
||||
## export config
|
||||
# rabbitmqadmin export ${LOCAL_BACKUP_DIR}/rabbitmq.config >> "${LOGFILE}"
|
||||
|
||||
## MegaCli config
|
||||
|
||||
# megacli -CfgSave -f ${LOCAL_BACKUP_DIR}/megacli_conf.dump -a0 >/dev/null
|
||||
|
||||
## Dump network routes with mtr and traceroute (warning: could be long with aggressive firewalls)
|
||||
network_targets="8.8.8.8 www.evolix.fr travaux.evolix.net"
|
||||
mtr_bin=$(command -v mtr)
|
||||
if [ -n "${mtr_bin}" ]; then
|
||||
for addr in ${network_targets}; do
|
||||
${mtr_bin} -r "${addr}" > "${LOCAL_BACKUP_DIR}/mtr-${addr}"
|
||||
done
|
||||
fi
|
||||
traceroute_bin=$(command -v traceroute)
|
||||
if [ -n "${traceroute_bin}" ]; then
|
||||
for addr in ${network_targets}; do
|
||||
${traceroute_bin} -n "${addr}" > "${LOCAL_BACKUP_DIR}/traceroute-${addr}" 2>&1
|
||||
done
|
||||
fi
|
||||
|
||||
server_state_dir="${LOCAL_BACKUP_DIR}/server-state"
|
||||
|
||||
dump_server_state_bin=$(command -v dump-server-state)
|
||||
if [ -z "${dump_server_state_bin}" ]; then
|
||||
error "dump-server-state is missing"
|
||||
rc=1
|
||||
else
|
||||
if [ "${SYSTEM}" = "linux" ]; then
|
||||
${dump_server_state_bin} --all --force --dump-dir "${server_state_dir}"
|
||||
last_rc=$?
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
error "dump-server-state returned an error ${last_rc}, check ${server_state_dir}"
|
||||
rc=1
|
||||
fi
|
||||
else
|
||||
${dump_server_state_bin} --all --force --dump-dir "${server_state_dir}"
|
||||
last_rc=$?
|
||||
if [ ${last_rc} -ne 0 ]; then
|
||||
error "dump-server-state returned an error ${last_rc}, check ${server_state_dir}"
|
||||
rc=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
## Dump rights
|
||||
# getfacl -R /var > ${server_state_dir}/rights-var.txt
|
||||
# getfacl -R /etc > ${server_state_dir}/rights-etc.txt
|
||||
# getfacl -R /usr > ${server_state_dir}/rights-usr.txt
|
||||
# getfacl -R /home > ${server_state_dir}/rights-home.txt
|
||||
|
||||
log "STOP LOCAL_TASKS"
|
||||
}
|
||||
build_rsync_main_cmd() {
|
||||
###################################################################
|
||||
# /!\ WARNING /!\ WARNING /!\ WARNING /!\ WARNING /!\ WARNING /!\ #
|
||||
###################################################################
|
||||
# DO NOT USE COMMENTS in rsync lines #
|
||||
# DO NOT ADD WHITESPACES AFTER \ in rsync lines #
|
||||
# It breaks the command and destroys data #
|
||||
# You should not modify this, unless you are really REALLY sure #
|
||||
###################################################################
|
||||
|
||||
# Create a temp file for excludes and includes
|
||||
includes_file="$(mktemp "${PROGNAME}.includes.XXXXXX")"
|
||||
excludes_file="$(mktemp "${PROGNAME}.excludes.XXXXXX")"
|
||||
# … and add them to the list of files to delete at exit
|
||||
temp_files="${temp_files} ${includes_file} ${excludes_file}"
|
||||
|
||||
# Store includes/excludes in files
|
||||
# without blank lines of comments (# or ;)
|
||||
echo "${RSYNC_INCLUDES}" | sed -e 's/\s*\(#\|;\).*//; /^\s*$/d' > "${includes_file}"
|
||||
echo "${RSYNC_EXCLUDES}" | sed -e 's/\s*\(#\|;\).*//; /^\s*$/d' > "${excludes_file}"
|
||||
|
||||
# Rsync command
|
||||
cmd="$(command -v rsync)"
|
||||
|
||||
# Rsync main options
|
||||
cmd="${cmd} --archive"
|
||||
cmd="${cmd} --itemize-changes"
|
||||
cmd="${cmd} --quiet"
|
||||
cmd="${cmd} --stats"
|
||||
cmd="${cmd} --human-readable"
|
||||
cmd="${cmd} --relative"
|
||||
cmd="${cmd} --partial"
|
||||
cmd="${cmd} --delete"
|
||||
cmd="${cmd} --delete-excluded"
|
||||
cmd="${cmd} --force"
|
||||
cmd="${cmd} --ignore-errors"
|
||||
cmd="${cmd} --log-file=${RSYNC_LOGFILE}"
|
||||
cmd="${cmd} --rsh='ssh -p ${SSH_PORT} -o \"ConnectTimeout ${SSH_CONNECT_TIMEOUT}\"'"
|
||||
|
||||
# Rsync excludes
|
||||
while read line ; do
|
||||
cmd="${cmd} --exclude ${line}"
|
||||
done < "${excludes_file}"
|
||||
|
||||
# Rsync local sources
|
||||
cmd="${cmd} ${default_includes}"
|
||||
while read line ; do
|
||||
cmd="${cmd} ${line}"
|
||||
done < "${includes_file}"
|
||||
|
||||
# Rsync remote destination
|
||||
cmd="${cmd} root@${SSH_SERVER}:/var/backup/"
|
||||
|
||||
# output final command
|
||||
echo "${cmd}"
|
||||
}
|
||||
build_rsync_canary_cmd() {
|
||||
# Rsync command
|
||||
cmd="$(command -v rsync)"
|
||||
# Rsync options
|
||||
cmd="${cmd} --rsh='ssh -p ${SSH_PORT} -o \"ConnectTimeout ${SSH_CONNECT_TIMEOUT}\"'"
|
||||
# Rsync local source
|
||||
cmd="${cmd} ${CANARY_FILE}"
|
||||
# Rsync remote destination
|
||||
cmd="${cmd} root@${SSH_SERVER}:/var/backup/"
|
||||
|
||||
# output final command
|
||||
echo "${cmd}"
|
||||
}
|
||||
sync_tasks() {
|
||||
n=0
|
||||
server=""
|
||||
if [ "${SERVERS_FALLBACK}" = "1" ]; then
|
||||
# We try to find a suitable server
|
||||
while :; do
|
||||
server=$(pick_server "${n}")
|
||||
test $? = 0 || exit 2
|
||||
|
||||
if test_server "${server}"; then
|
||||
break
|
||||
else
|
||||
server=""
|
||||
n=$(( n + 1 ))
|
||||
fi
|
||||
done
|
||||
else
|
||||
# we force the server
|
||||
server=$(pick_server "${n}")
|
||||
fi
|
||||
|
||||
SSH_SERVER=$(echo "${server}" | cut -d':' -f1)
|
||||
SSH_PORT=$(echo "${server}" | cut -d':' -f2)
|
||||
|
||||
log "START SYNC_TASKS - server=${server}"
|
||||
|
||||
# default paths, depending on system
|
||||
if [ "${SYSTEM}" = "linux" ]; then
|
||||
default_includes="/bin /boot /lib /opt /sbin /usr"
|
||||
else
|
||||
default_includes="/bsd /bin /sbin /usr"
|
||||
fi
|
||||
|
||||
# reset Rsync log file
|
||||
if [ -n "$(command -v truncate)" ]; then
|
||||
truncate -s 0 "${RSYNC_LOGFILE}"
|
||||
else
|
||||
printf "" > "${RSYNC_LOGFILE}"
|
||||
fi
|
||||
|
||||
# Build the final Rsync command
|
||||
rsync_main_cmd=$(build_rsync_main_cmd)
|
||||
|
||||
# … log it
|
||||
log "SYNC_TASKS - Rsync main command : ${rsync_main_cmd}"
|
||||
|
||||
# … execute it
|
||||
eval "${rsync_main_cmd}"
|
||||
|
||||
rsync_main_rc=$?
|
||||
|
||||
# Copy last lines of rsync log to the main log
|
||||
tail -n 30 "${RSYNC_LOGFILE}" >> "${LOGFILE}"
|
||||
|
||||
if [ ${rsync_main_rc} -ne 0 ]; then
|
||||
error "rsync returned an error ${rsync_main_rc}, check ${LOGFILE}"
|
||||
rc=201
|
||||
else
|
||||
# Build the canary Rsync command
|
||||
rsync_canary_cmd=$(build_rsync_canary_cmd)
|
||||
|
||||
# … log it
|
||||
log "SYNC_TASKS - Rsync canary command : ${rsync_canary_cmd}"
|
||||
|
||||
# … execute it
|
||||
eval "${rsync_canary_cmd}"
|
||||
fi
|
||||
|
||||
log "STOP SYNC_TASKS - server=${server}"
|
||||
}
|
||||
|
||||
# Call test_server with "HOST:PORT" string
|
||||
# It will return with 0 if the server is reachable.
|
||||
# It will return with 1 and a message on stderr if not.
|
||||
test_server() {
|
||||
item=$1
|
||||
# split HOST and PORT from the input string
|
||||
host=$(echo "${item}" | cut -d':' -f1)
|
||||
port=$(echo "${item}" | cut -d':' -f2)
|
||||
|
||||
# Test if the server is accepting connections
|
||||
ssh -q -o "ConnectTimeout ${SSH_CONNECT_TIMEOUT}" "${host}" -p "${port}" -t "exit"
|
||||
# shellcheck disable=SC2181
|
||||
if [ $? = 0 ]; then
|
||||
# SSH connection is OK
|
||||
return 0
|
||||
else
|
||||
# SSH connection failed
|
||||
new_error=$(printf "Failed to connect to \`%s' within %s seconds" "${item}" "${SSH_CONNECT_TIMEOUT}")
|
||||
log "${new_error}"
|
||||
SERVERS_SSH_ERRORS=$(printf "%s\\n%s" "${SERVERS_SSH_ERRORS}" "${new_error}" | sed -e '/^$/d')
|
||||
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
# Call pick_server with an optional positive integer to get the nth server in the list.
|
||||
pick_server() {
|
||||
increment=${1:-0}
|
||||
list_length=$(echo "${SERVERS}" | wc -w)
|
||||
|
||||
if [ "${increment}" -ge "${list_length}" ]; then
|
||||
# We've reached the end of the list
|
||||
new_error="No more server available"
|
||||
log "${new_error}"
|
||||
SERVERS_SSH_ERRORS=$(printf "%s\\n%s" "${SERVERS_SSH_ERRORS}" "${new_error}" | sed -e '/^$/d')
|
||||
|
||||
# Log errors to stderr
|
||||
printf "%s\\n" "${SERVERS_SSH_ERRORS}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Extract the day of month, without leading 0 (which would give an octal based number)
|
||||
today=$(/bin/date +%e)
|
||||
# A salt is useful to randomize the starting point in the list
|
||||
# but stay identical each time it's called for a server (based on hostname).
|
||||
salt=$(hostname | cksum | cut -d' ' -f1)
|
||||
# Pick an integer between 0 and the length of the SERVERS list
|
||||
# It changes each day
|
||||
item=$(( (today + salt + increment) % list_length ))
|
||||
# cut starts counting fields at 1, not 0.
|
||||
field=$(( item + 1 ))
|
||||
|
||||
echo "${SERVERS}" | cut -d' ' -f${field}
|
||||
}
|
||||
log() {
|
||||
msg="${1:-$(cat /dev/stdin)}"
|
||||
pid=$$
|
||||
printf "[%s] %s[%s]: %s\\n" \
|
||||
"$(/bin/date +"${DATE_FORMAT}")" "${PROGNAME}" "${pid}" "${msg}" \
|
||||
>> "${LOGFILE}"
|
||||
}
|
||||
error() {
|
||||
msg="${1:-$(cat /dev/stdin)}"
|
||||
pid=$$
|
||||
printf "[%s] %s[%s]: %s\\n" \
|
||||
"$(/bin/date +"${DATE_FORMAT}")" "${PROGNAME}" "${pid}" "${msg}" \
|
||||
>&2
|
||||
}
|
||||
|
||||
main() {
|
||||
START_EPOCH=$(/bin/date +%s)
|
||||
log "START GLOBAL - VERSION=${VERSION} LOCAL_TASKS=${LOCAL_TASKS} SYNC_TASKS=${SYNC_TASKS}"
|
||||
|
||||
# shellcheck disable=SC2174
|
||||
mkdir -p -m 700 ${LOCAL_BACKUP_DIR}
|
||||
|
||||
## Force umask
|
||||
umask 077
|
||||
|
||||
## Initialize variable to store SSH connection errors
|
||||
SERVERS_SSH_ERRORS=""
|
||||
|
||||
## Verify other evobackup process and kill if needed
|
||||
if [ -e "${PIDFILE}" ]; then
|
||||
pid=$(cat "${PIDFILE}")
|
||||
# Does process still exist ?
|
||||
if kill -0 "${pid}" 2> /dev/null; then
|
||||
# Killing the childs of evobackup.
|
||||
for ppid in $(pgrep -P "${pid}"); do
|
||||
kill -9 "${ppid}";
|
||||
done
|
||||
# Then kill the main PID.
|
||||
kill -9 "${pid}"
|
||||
printf "%s is still running (PID %s). Process has been killed" "$0" "${pid}\\n" >&2
|
||||
else
|
||||
rm -f "${PIDFILE}"
|
||||
fi
|
||||
fi
|
||||
echo "$$" > "${PIDFILE}"
|
||||
|
||||
# Initialize a list of files to delete at exit
|
||||
# Any file added to the list will also be deleted at exit
|
||||
temp_files="${PIDFILE}"
|
||||
|
||||
# shellcheck disable=SC2064
|
||||
trap "rm -f ${temp_files}" EXIT
|
||||
|
||||
# Update canary to keep track of each run
|
||||
update-evobackup-canary --who "${PROGNAME}"
|
||||
|
||||
if [ "${LOCAL_TASKS}" = "1" ]; then
|
||||
local_tasks
|
||||
fi
|
||||
|
||||
if [ "${SYNC_TASKS}" = "1" ]; then
|
||||
sync_tasks
|
||||
fi
|
||||
|
||||
STOP_EPOCH=$(/bin/date +%s)
|
||||
|
||||
if [ "${SYSTEM}" = "openbsd" ]; then
|
||||
start_time=$(/bin/date -f "%s" -j "${START_EPOCH}" +"${DATE_FORMAT}")
|
||||
stop_time=$(/bin/date -f "%s" -j "${STOP_EPOCH}" +"${DATE_FORMAT}")
|
||||
else
|
||||
start_time=$(/bin/date --date="@${START_EPOCH}" +"${DATE_FORMAT}")
|
||||
stop_time=$(/bin/date --date="@${STOP_EPOCH}" +"${DATE_FORMAT}")
|
||||
fi
|
||||
duration=$(( STOP_EPOCH - START_EPOCH ))
|
||||
|
||||
log "STOP GLOBAL - start='${start_time}' stop='${stop_time}' duration=${duration}s"
|
||||
|
||||
tail -20 "${LOGFILE}" | mail -s "[info] EvoBackup - Client ${HOSTNAME}" ${MAIL}
|
||||
}
|
||||
|
||||
# set all programs to C language (english)
|
||||
export LC_ALL=C
|
||||
|
||||
# Error on unassigned variable
|
||||
set -u
|
||||
|
||||
# Default return-code (0 == succes)
|
||||
rc=0
|
||||
|
||||
# execute main funciton
|
||||
main
|
||||
|
||||
exit ${rc}
|
|
@ -0,0 +1,77 @@
|
|||
# yamllint disable rule:line-length
|
||||
---
|
||||
# Info : old zzz_evobackup used sh, and since "sh" match "bash", we keep "sh" for regex commands
|
||||
|
||||
- name: "Copy zzz_evobackup script"
|
||||
ansible.builtin.copy:
|
||||
src: zzz_evobackup
|
||||
dest: /usr/share/scripts/zzz_evobackup
|
||||
owner: root
|
||||
group: wheel
|
||||
mode: "0755"
|
||||
force: false
|
||||
tags:
|
||||
- evobackup
|
||||
|
||||
- name: "Copy update-evobackup-canary script"
|
||||
ansible.builtin.copy:
|
||||
src: 000-update-evobackup-canary
|
||||
dest: /usr/share/scripts/000-update-evobackup-canary
|
||||
owner: root
|
||||
group: wheel
|
||||
mode: "0755"
|
||||
force: true
|
||||
tags:
|
||||
- evobackup
|
||||
|
||||
- name: "Fetch daily.local content"
|
||||
ansible.builtin.command: 'grep "sh /usr/share/scripts/zzz_evobackup" /etc/daily.local'
|
||||
check_mode: false
|
||||
register: daily_local_content
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
tags:
|
||||
- evobackup
|
||||
|
||||
- name: "Add evobackup cron (disabled)"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/daily.local
|
||||
line: '#bash /usr/share/scripts/zzz_evobackup'
|
||||
owner: root
|
||||
mode: "0600"
|
||||
create: true
|
||||
when:
|
||||
- not (daily_local_content.stdout | regex_search('sh /usr/share/scripts/zzz_evobackup'))
|
||||
tags:
|
||||
- evobackup
|
||||
|
||||
- name: "Add evobackup cron - next_part"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/daily.local
|
||||
line: 'next_part "EvoBackup output:"'
|
||||
insertbefore: 'sh /usr/share/scripts/zzz_evobackup'
|
||||
owner: root
|
||||
mode: "0600"
|
||||
create: true
|
||||
tags:
|
||||
- evobackup
|
||||
|
||||
- name: "Add canary cron"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/daily.local
|
||||
line: 'sh /usr/share/scripts/000-update-evobackup-canary'
|
||||
insertafter: 'next_part "EvoBackup output:"'
|
||||
owner: root
|
||||
mode: "0600"
|
||||
create: true
|
||||
tags:
|
||||
- evobackup
|
||||
|
||||
- name: "Delete legacy evobackup root crontab"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /var/cron/tabs/root
|
||||
regexp: '/usr/share/scripts/zzz_evobackup'
|
||||
validate: /usr/bin/crontab %s
|
||||
state: absent
|
||||
tags:
|
||||
- evobackup
|
|
@ -3,74 +3,65 @@
|
|||
# EvoCheck
|
||||
# Script to verify compliance of an OpenBSD server powered by Evolix
|
||||
|
||||
readonly VERSION="21.09"
|
||||
readonly VERSION="23.06"
|
||||
|
||||
# Disable LANG*
|
||||
# base functions
|
||||
|
||||
export LANG=C
|
||||
export LANGUAGE=C
|
||||
|
||||
|
||||
# Default return code : 0 = no error
|
||||
RC=0
|
||||
|
||||
# Verbose function
|
||||
verbose() {
|
||||
msg="${1:-$(cat /dev/stdin)}"
|
||||
[ "${VERBOSE}" -eq 1 ] && [ -n "${msg}" ] && echo "${msg}"
|
||||
}
|
||||
|
||||
# Source configuration file
|
||||
test -f /etc/evocheck.cf && . /etc/evocheck.cf
|
||||
|
||||
# Functions
|
||||
|
||||
show_help() {
|
||||
show_version() {
|
||||
cat <<END
|
||||
NAME:
|
||||
evocheck - a system configuration verification tool
|
||||
evocheck version ${VERSION}
|
||||
|
||||
VERSION:
|
||||
${VERSION}
|
||||
Copyright 2009-2021 Evolix <info@evolix.fr>,
|
||||
Romain Dessort <rdessort@evolix.fr>,
|
||||
Benoit Série <bserie@evolix.fr>,
|
||||
Gregory Colpart <reg@evolix.fr>,
|
||||
Jérémy Lecour <jlecour@evolix.fr>,
|
||||
Tristan Pilat <tpilat@evolix.fr>,
|
||||
Victor Laborie <vlaborie@evolix.fr>,
|
||||
Jérémy Dubois <jdubois@evolix.fr>
|
||||
and others.
|
||||
|
||||
DESCRIPTION:
|
||||
A script that verifies Evolix conventions on OpenBSD servers
|
||||
|
||||
AUTHORS:
|
||||
Benoit Serie <bserie@evolix.fr>
|
||||
Gregory Colpart <reg@evolix.fr>
|
||||
Jeremy Dubois <jdubois@evolix.fr>
|
||||
Jeremy Lecour <jlecour@evolix.fr>
|
||||
Ludovic Poujol <lpoujol@evolix.fr>
|
||||
Romain Dessort <rdessort@evolix.fr>
|
||||
Tristan Pilat <tpilat@evolix.fr>
|
||||
Victor Laborie <vlaborie@evolix.fr>
|
||||
|
||||
USAGE: evocheck
|
||||
or evocheck --cron
|
||||
or evocheck --quiet
|
||||
or evocheck --verbose
|
||||
|
||||
OPTIONS:
|
||||
--cron disable a few checks
|
||||
-v, --verbose increase verbosity of checks
|
||||
-q, --quiet nothing is printed on stdout nor stderr
|
||||
-h, --help, --version print this message and exit
|
||||
|
||||
COPYRIGHT:
|
||||
evocheck comes with ABSOLUTELY NO WARRANTY. This is free software,
|
||||
and you are welcome to redistribute it under certain conditions.
|
||||
See the GNU General Public License v3.0 for details. 2009-2020
|
||||
evocheck comes with ABSOLUTELY NO WARRANTY. This is free software,
|
||||
and you are welcome to redistribute it under certain conditions.
|
||||
See the GNU General Public License v3.0 for details.
|
||||
END
|
||||
}
|
||||
show_help() {
|
||||
cat <<END
|
||||
evocheck is a script that verifies Evolix conventions on OpenBSD servers.
|
||||
|
||||
Usage: evocheck
|
||||
or evocheck --cron
|
||||
or evocheck --quiet
|
||||
or evocheck --verbose
|
||||
|
||||
Options
|
||||
--cron disable a few checks
|
||||
-v, --verbose increase verbosity of checks
|
||||
-q, --quiet nothing is printed on stdout nor stderr
|
||||
-h, --help print this message and exit
|
||||
--version print version and exit
|
||||
END
|
||||
}
|
||||
is_installed(){
|
||||
for pkg in "$@"; do
|
||||
pkg_info | grep -q $pkg || return 1
|
||||
pkg_info | grep -q "$pkg" || return 1
|
||||
done
|
||||
}
|
||||
|
||||
# logging
|
||||
|
||||
log() {
|
||||
date=$(/bin/date +"${DATE_FORMAT}")
|
||||
if [ "${1}" != '' ]; then
|
||||
printf "[%s] %s: %s\\n" "$date" "${PROGNAME}" "${1}" >> "${LOGFILE}"
|
||||
else
|
||||
while read line; do
|
||||
printf "[%s] %s: %s\\n" "$date" "${PROGNAME}" "${line}" >> "${LOGFILE}"
|
||||
done < /dev/stdin
|
||||
fi
|
||||
}
|
||||
|
||||
failed() {
|
||||
check_name=$1
|
||||
shift
|
||||
|
@ -84,83 +75,73 @@ failed() {
|
|||
printf "%s FAILED!\n" "${check_name}" 2>&1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Always log verbose
|
||||
log "${check_name} FAILED! ${check_comments}"
|
||||
}
|
||||
|
||||
|
||||
# If --cron is passed, ignore some checks.
|
||||
if [ "$1" = "--cron" ]; then
|
||||
IS_KERNELUPTODATE=0
|
||||
IS_UPTIME=0
|
||||
fi
|
||||
# check functions
|
||||
|
||||
check_umasksudoers(){
|
||||
grep -E -qr "umask=0077" /etc/sudoers* || failed "IS_UMASKSUDOERS" "sudoers must set umask to 0077"
|
||||
grep -Rq "^Defaults.*umask=0077" /etc/sudoers* || failed "IS_UMASKSUDOERS" "sudoers must set umask to 0077"
|
||||
}
|
||||
|
||||
check_tmpnoexec(){
|
||||
mount | grep "on /tmp" | grep -q noexec || failed "IS_TMPNOEXEC" "/tmp should be mounted with the noexec option"
|
||||
}
|
||||
|
||||
check_softdep(){
|
||||
if [ $(grep -c softdep /etc/fstab) -ne $(grep -c ffs /etc/fstab) ]; then
|
||||
if [ "$(grep -c softdep /etc/fstab)" -ne "$(grep -c ffs /etc/fstab)" ]; then
|
||||
failed "IS_SOFTDEP" "All partitions should have the softdep option"
|
||||
fi
|
||||
}
|
||||
|
||||
check_noatime(){
|
||||
if [ $(mount | grep -c noatime) -ne $(grep ffs /etc/fstab | grep -vc ^\#) ]; then
|
||||
if [ "$(mount | grep -c noatime)" -ne "$(grep ffs /etc/fstab | grep -vc ^\#)" ]; then
|
||||
failed "IS_NOATIME" "All partitions should be mounted with the noatime option"
|
||||
fi
|
||||
}
|
||||
|
||||
check_tmoutprofile(){
|
||||
if [ -f /etc/skel/.profile ]; then
|
||||
grep -q TMOUT= /etc/skel/.profile /root/.profile || failed "IS_TMOUTPROFILE" "In order to fix, add 'export TMOUT=36000' to both /etc/skel/.profile and /root/.profile files"
|
||||
grep -q TMOUT= /etc/skel/.profile /root/.profile || failed "IS_TMOUTPROFILE" "Add 'export TMOUT=36000' to both /etc/skel/.profile and /root/.profile files"
|
||||
else
|
||||
failed "IS_TMOUTPROFILE" "File /etc/skel/.profile does not exist. Both /etc/skel/.profile and /root/.profile should contain at least 'export TMOUT=36000'"
|
||||
fi
|
||||
}
|
||||
|
||||
check_raidok(){
|
||||
egrep 'sd.*RAID' /var/run/dmesg.boot 1> /dev/null 2>&1
|
||||
grep -E 'sd.*RAID' /var/run/dmesg.boot 1> /dev/null 2>&1
|
||||
RESULT=$?
|
||||
if [ $RESULT -eq 0 ]; then
|
||||
raid_device=$(egrep 'sd.*RAID' /var/run/dmesg.boot | awk '{ print $1 }' | tail -1)
|
||||
raid_status=$(bioctl $raid_device | grep softraid | awk '{ print $3 }')
|
||||
if [ $raid_status != "Online" ]; then
|
||||
raid_device=$(grep -E 'sd.*RAID' /var/run/dmesg.boot | awk '{ print $1 }' | tail -1)
|
||||
raid_status=$(bioctl "$raid_device" | grep softraid | awk '{ print $3 }')
|
||||
if [ "$raid_status" != "Online" ]; then
|
||||
failed "IS_RAIDOK" "One of the RAID disk members is faulty. Use bioctl -h $raid_device for more informations"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
check_evobackup(){
|
||||
if [ -f /etc/daily.local ]; then
|
||||
grep -qE "^sh /usr/share/scripts/zzz_evobackup" /etc/daily.local || failed "IS_EVOBACKUP" "Make sure 'sh /usr/share/scripts/zzz_evobackup' is present and activated in /etc/daily.local"
|
||||
grep -qE "^(ba)?sh /usr/share/scripts/zzz_evobackup" /etc/daily.local || failed "IS_EVOBACKUP" "Make sure 'bash or sh /usr/share/scripts/zzz_evobackup' is present and activated in /etc/daily.local"
|
||||
else
|
||||
failed "IS_EVOBACKUP" "Make sure /etc/daily.local exists and 'sh /usr/share/scripts/zzz_evobackup' is present and activated in /etc/daily.local"
|
||||
failed "IS_EVOBACKUP" "Make sure /etc/daily.local exists and 'bash or sh /usr/share/scripts/zzz_evobackup' is present and activated in /etc/daily.local"
|
||||
fi
|
||||
}
|
||||
|
||||
check_uptodate(){
|
||||
if [ $(command -v syspatch) ]; then
|
||||
if syspatch -c | egrep "." 1> /dev/null 2>&1; then
|
||||
if [ "$(command -v syspatch)" ]; then
|
||||
if syspatch -c | grep -E "." 1> /dev/null 2>&1; then
|
||||
failed "IS_UPTODATE" "Security update available! Update with syspatch(8)!"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
check_uptime(){
|
||||
if [ $(uptime | cut -d" " -f 4) -gt 365 ]; then
|
||||
failed "IS_UPTIME" "The server is running for more than a year!"
|
||||
uptime=$(($(date +"%s") - $(sysctl -n kern.boottime)))
|
||||
if [ "$uptime" -gt "$(( 2*365*24*60*60 ))" ]; then
|
||||
failed "IS_UPTIME" "The server has an uptime of more than 2 years, reboot on new kernel advised"
|
||||
fi
|
||||
}
|
||||
|
||||
check_backupuptodate(){
|
||||
backup_dir="/home/backup"
|
||||
if [ -d "${backup_dir}" ]; then
|
||||
if [ -n "$(ls -A ${backup_dir})" ]; then
|
||||
for file in ${backup_dir}/*; do
|
||||
let "limit = $(date +"%s") - 172800"
|
||||
find "${backup_dir}" -maxdepth 1 -type f | while read -r file; do
|
||||
limit=$(($(date +"%s") - 172800))
|
||||
updated_at=$(stat -f "%m" "$file")
|
||||
|
||||
if [ -f "$file" ] && [ "$limit" -gt "$updated_at" ]; then
|
||||
|
@ -175,39 +156,40 @@ check_backupuptodate(){
|
|||
failed "IS_BACKUPUPTODATE" "${backup_dir}/ is missing"
|
||||
fi
|
||||
}
|
||||
|
||||
check_gitperms(){
|
||||
test -d /etc/.git && [ "$(stat -f %p /etc/.git/)" = "40700" ] || failed "IS_GITPERMS" "The directiry /etc/.git sould be in 700"
|
||||
check_gitperms() {
|
||||
GIT_DIR="/etc/.git"
|
||||
if test -d $GIT_DIR; then
|
||||
expected="40700"
|
||||
actual=$(stat -f "%p" $GIT_DIR)
|
||||
[ "$expected" = "$actual" ] || failed "IS_GITPERMS" "$GIT_DIR must be 700"
|
||||
fi
|
||||
}
|
||||
|
||||
check_carpadvbase(){
|
||||
if ls /etc/hostname.carp* 1> /dev/null 2>&1; then
|
||||
bad_advbase=0
|
||||
for advbase in $(ifconfig carp | grep advbase | awk -F 'advbase' '{print $2}' | awk '{print $1}' | xargs); do
|
||||
if [[ "$advbase" -gt 5 ]]; then
|
||||
bad_advbase=1
|
||||
fi
|
||||
if [ "$advbase" -gt 5 ]; then
|
||||
bad_advbase=1
|
||||
fi
|
||||
done
|
||||
if [[ "$bad_advbase" -eq 1 ]]; then
|
||||
if [ "$bad_advbase" -eq 1 ]; then
|
||||
failed "IS_CARPADVBASE" "At least one CARP interface has advbase greater than 5 seconds!"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
check_carppreempt(){
|
||||
if ls /etc/hostname.carp* 1> /dev/null 2>&1; then
|
||||
preempt=$(sysctl net.inet.carp.preempt | cut -d"=" -f2)
|
||||
if [[ "$preempt" -ne 1 ]]; then
|
||||
if [ "$preempt" -ne 1 ]; then
|
||||
failed "IS_CARPPREEMPT" "The preempt function is not activated! Please type 'sysctl net.inet.carp.preempt=1' in"
|
||||
fi
|
||||
if [ -f /etc/sysctl.conf ]; then
|
||||
grep -qE "^net.inet.carp.preempt=1" /etc/sysctl.conf || failed "IS_CARPPREEMPT" "The preempt parameter is not permanently activated! Please add 'net.inet.carp.preempt=1' in /etc/sysctl.conf"
|
||||
else
|
||||
failed "IS_CARPPREEMPT" "Make sure /etc/sysctl.conf exists and contains the line 'net.inet.carp.preempt=1'"
|
||||
failed "IS_CARPPREEMPT" "Make sure /etc/sysctl.conf exists and contains the line 'net.inet.carp.preempt=1'"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
check_rebootmail(){
|
||||
if [ -f /etc/rc.local ]; then
|
||||
grep -qE '^date \| mail -s "boot/reboot of' /etc/rc.local || failed "IS_REBOOTMAIL" "Make sure the line 'date | mail -s \"boot/reboot of \$hostname' is present in the /etc/rc.local file!"
|
||||
|
@ -215,111 +197,99 @@ check_rebootmail(){
|
|||
failed "IS_REBOOTMAIL" "Make sure /etc/rc.local exist and 'date | mail -s \"boot/reboot of \$hostname' is present!"
|
||||
fi
|
||||
}
|
||||
|
||||
check_pfenabled(){
|
||||
if pfctl -si | grep Disabled 1> /dev/null 2>&1; then
|
||||
failed "IS_PFENABLED" "PF is disabled! Make sure pf=NO is absent from /etc/rc.conf.local and carefully run pfctl -e"
|
||||
fi
|
||||
}
|
||||
|
||||
check_pfcustom(){
|
||||
}
|
||||
|
||||
check_wheel(){
|
||||
if [ -f /etc/sudoers ]; then
|
||||
grep -qE "^%wheel.*$" /etc/sudoers || failed "IS_WHEEL" ""
|
||||
fi
|
||||
}
|
||||
|
||||
check_pkgmirror(){
|
||||
grep -qE "^https://cdn\.openbsd\.org/pub/OpenBSD" /etc/installurl || failed "IS_PKGMIRROR" "Check whether the right repo is present in the /etc/installurl file"
|
||||
grep -qE "^https?://ftp\.evolix\.org/openbsd" /etc/installurl || failed "IS_PKGMIRROR" "Check whether the right repo is present in the /etc/installurl file"
|
||||
}
|
||||
|
||||
check_history(){
|
||||
file=/root/.profile
|
||||
grep -qE "^HISTFILE=\$HOME/.histfile" $file && grep -qE "^export HISTSIZE=10000" $file || failed "IS_HISTORY" "Make sure both 'HISTFILE=$HOME/.histfile' and 'export HISTSIZE=10000' are present in /root/.profile"
|
||||
# shellcheck disable=SC2015
|
||||
grep -qE "^HISTFILE=\$HOME/.histfile" $file && grep -qE "^export HISTSIZE=100000" $file || failed "IS_HISTORY" "Make sure both 'HISTFILE=\$HOME/.histfile' and 'export HISTSIZE=100000' are present in /root/.profile"
|
||||
}
|
||||
|
||||
check_vim(){
|
||||
if ! is_installed vim; then
|
||||
failed "IS_VIM" "vim is not installed! Please add with pkg_add vim"
|
||||
fi
|
||||
}
|
||||
|
||||
check_ttyc0secure(){
|
||||
grep -Eqv "^ttyC0.*secure$" /etc/ttys || failed "IS_TTYC0SECURE" "First tty should be secured"
|
||||
}
|
||||
|
||||
check_customsyslog(){
|
||||
grep -q EvoBSD /etc/newsyslog.conf || failed "IS_CUSTOMSYSLOG" ""
|
||||
}
|
||||
|
||||
check_sudomaint(){
|
||||
file=/etc/sudoers
|
||||
grep -q "Cmnd_Alias MAINT = /usr/share/scripts/evomaintenance.sh" $file \
|
||||
&& grep -q "%wheel ALL=NOPASSWD: MAINT" $file \
|
||||
|| failed "IS_SUDOMAINT" ""
|
||||
check_doasmaint(){
|
||||
# shellcheck disable=SC2015
|
||||
grep -q "permit setenv {ENV PS1 SSH_AUTH_SOCK SSH_TTY} nopass :evolinux-ssh as root cmd /usr/share/scripts/evomaintenance.sh" /etc/doas.conf || failed "IS_DOASMAINT" "Make sure evomaintenance.sh permission are properly configured in /etc/doas.conf"
|
||||
}
|
||||
|
||||
check_nrpe(){
|
||||
if ! is_installed monitoring-plugins || ! is_installed nrpe; then
|
||||
failed "IS_NRPE" "nrpe and/or monitoring-plugins are not installed! Please add with pkg_add nrpe monitoring-plugins"
|
||||
fi
|
||||
}
|
||||
|
||||
check_rsync(){
|
||||
if ! is_installed rsync; then
|
||||
failed "IS_RSYNC" "rsync is not installed! Please add with pkg_add rsync"
|
||||
fi
|
||||
}
|
||||
|
||||
check_cronpath(){
|
||||
grep -q "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/share/scripts" /var/cron/tabs/root || failed "IS_CRONPATH" ""
|
||||
}
|
||||
|
||||
check_tmp1777(){
|
||||
ls -ld /tmp | grep -q drwxrwxrwt || failed "IS_TMP_1777" ""
|
||||
check_tmp_1777(){
|
||||
actual=$(stat -f "%p" /tmp)
|
||||
expected="41777"
|
||||
test "$expected" = "$actual" || failed "IS_TMP_1777" "/tmp must be 1777"
|
||||
}
|
||||
|
||||
check_root0700(){
|
||||
ls -ld /root | grep -q drwx------ || failed "IS_ROOT_0700" ""
|
||||
check_root_0700(){
|
||||
actual=$(stat -f "%p" /root)
|
||||
expected="40700"
|
||||
test "$expected" = "$actual" || failed "IS_ROOT_0700" "/root must be 700"
|
||||
}
|
||||
|
||||
check_usrsharescripts(){
|
||||
ls -ld /usr/share/scripts | grep -q drwx------ || failed "IS_USRSHARESCRIPTS" ""
|
||||
actual=$(stat -f "%p" /usr/share/scripts)
|
||||
expected="40700"
|
||||
test "$expected" = "$actual" || failed "IS_USRSHARESCRIPTS" "/usr/share/scripts must be 700"
|
||||
}
|
||||
|
||||
check_sshpermitrootno() {
|
||||
grep -qE ^PermitRoot /etc/ssh/sshd_config && ( grep -E -qi "PermitRoot.*no" /etc/ssh/sshd_config || failed "IS_SSHPERMITROOTNO" "" )
|
||||
if ! (sshd -T -C addr=,user=,host=,laddr=,lport=0,rdomain= 2> /dev/null | grep -qi 'permitrootlogin no'); then
|
||||
failed "IS_SSHPERMITROOTNO" "PermitRoot should be set to no"
|
||||
fi
|
||||
}
|
||||
|
||||
check_evomaintenanceusers(){
|
||||
# Can be changed in evocheck.cf
|
||||
homeDir=${homeDir:-/home}
|
||||
sudoers="/etc/sudoers"
|
||||
for i in $( (grep "^User_Alias *ADMIN" $sudoers | cut -d= -f2 | tr -d " "; grep ^sudo /etc/group |cut -d: -f 4) | tr "," "\n" |sort -u); do
|
||||
grep -qs "^trap.*sudo.*evomaintenance.sh" ${homeDir}/${i}/.*profile
|
||||
if [ $? != 0 ]; then
|
||||
failed "IS_EVOMAINTENANCEUSERS" "$i doesn't have evomaintenance trap!"
|
||||
users=$(getent group evolinux-sudo | cut -d':' -f4 | tr ',' ' ')
|
||||
for user in $users; do
|
||||
user_home=$(getent passwd "$user" | cut -d: -f6)
|
||||
if [ -n "$user_home" ] && [ -d "$user_home" ]; then
|
||||
if ! grep -qs "^trap.*doas.*evomaintenance.sh" "${user_home}"/.*profile; then
|
||||
echo "IS_EVOMAINTENANCEUSERS" "${user} doesn't have an evomaintenance trap"
|
||||
test "${VERBOSE}" = 1 || break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
check_evomaintenanceconf(){
|
||||
file=/etc/evomaintenance.cf
|
||||
( test -e $file \
|
||||
&& test $(stat -f %p $file) = "100600" \
|
||||
&& grep "^export PGPASSWORD" $file |grep -qv "your-passwd" \
|
||||
&& grep "^PGDB" $file |grep -qv "your-db" \
|
||||
&& grep "^PGTABLE" $file |grep -qv "your-table" \
|
||||
&& grep "^PGHOST" $file |grep -qv "your-pg-host" \
|
||||
&& grep "^FROM" $file |grep -qv "jdoe@example.com" \
|
||||
&& grep "^FULLFROM" $file |grep -qv "John Doe <jdoe@example.com>" \
|
||||
&& grep "^URGENCYFROM" $file |grep -qv "mama.doe@example.com" \
|
||||
&& grep "^URGENCYTEL" $file |grep -qv "06.00.00.00.00" \
|
||||
&& grep "^REALM" $file |grep -qv "example.com" ) || failed "IS_EVOMAINTENANCECONF" ""
|
||||
}
|
||||
f=/etc/evomaintenance.cf
|
||||
if [ -e "$f" ]; then
|
||||
perms=$(stat -f "%p" $f)
|
||||
test "$perms" = "100600" || echo "IS_EVOMAINTENANCECONF" "Wrong permissions on \`$f' ($perms instead of 100600)"
|
||||
|
||||
{ grep "^export PGPASSWORD" $f | grep -qv "your-passwd" \
|
||||
&& grep "^PGDB" $f | grep -qv "your-db" \
|
||||
&& grep "^PGTABLE" $f | grep -qv "your-table" \
|
||||
&& grep "^PGHOST" $f | grep -qv "your-pg-host" \
|
||||
&& grep "^FROM" $f | grep -qv "jdoe@example.com" \
|
||||
&& grep "^FULLFROM" $f | grep -qv "John Doe <jdoe@example.com>" \
|
||||
&& grep "^URGENCYFROM" $f | grep -qv "mama.doe@example.com" \
|
||||
&& grep "^URGENCYTEL" $f | grep -qv "06.00.00.00.00" \
|
||||
&& grep "^REALM" $f | grep -qv "example.com"
|
||||
} || echo "IS_EVOMAINTENANCECONF" "evomaintenance is not correctly configured"
|
||||
else
|
||||
echo "IS_EVOMAINTENANCECONF" "Configuration file \`$f' is missing"
|
||||
fi
|
||||
}
|
||||
check_sync(){
|
||||
if ifconfig carp | grep carp 1> /dev/null 2>&1; then
|
||||
sync_script=/usr/share/scripts/sync.sh
|
||||
|
@ -328,7 +298,6 @@ check_sync(){
|
|||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
check_defaultroute(){
|
||||
if [ -f /etc/mygate ]; then
|
||||
file_route=$(cat /etc/mygate)
|
||||
|
@ -340,37 +309,35 @@ check_defaultroute(){
|
|||
failed "IS_DEFAULTROUTE" "The file /etc/mygate does not exist. Make sure you have the same default route in this file as the one currently in use."
|
||||
fi
|
||||
}
|
||||
|
||||
check_ntp(){
|
||||
if grep -q "server ntp.evolix.net" /etc/ntpd.conf; then
|
||||
if [ $(wc -l /etc/ntpd.conf | awk '{print $1}') -ne 1 ]; then
|
||||
failed "IS_NTP" "The /etc/ntpd.conf file should only contains \"server ntp.evolix.net\"."
|
||||
if grep -q "servers ntp.evolix.net" /etc/ntpd.conf; then
|
||||
if [ "$(wc -l /etc/ntpd.conf | awk '{print $1}')" -ne 1 ]; then
|
||||
failed "IS_NTP" "The /etc/ntpd.conf file should only contains \"servers ntp.evolix.net\"."
|
||||
fi
|
||||
else
|
||||
failed "IS_NTP" "The configuration in /etc/ntpd.conf is not compliant. It should contains \"server ntp.evolix.net\"."
|
||||
failed "IS_NTP" "The configuration in /etc/ntpd.conf is not compliant. It should contains \"servers ntp.evolix.net\"."
|
||||
fi
|
||||
}
|
||||
|
||||
check_openvpncronlog(){
|
||||
if /etc/rc.d/openvpn check > /dev/null 2>&1; then
|
||||
# shellcheck disable=SC2016
|
||||
grep -q 'cp /var/log/openvpn.log /var/log/openvpn.log.$(date +\\%F) && echo "$(date +\\%F. .\\%R) - logfile turned over via cron" > /var/log/openvpn.log && gzip /var/log/openvpn.log.$(date +\\%F) && find /var/log/ -type f -name "openvpn.log.\*" -mtime .365 -exec rm {} \\+' /var/cron/tabs/root || failed "IS_OPENVPNCRONLOG" "OpenVPN is enabled but there is no log rotation in the root crontab, or the cron is not up to date (OpenVPN log rotation in newsyslog is not used because a restart is needed)."
|
||||
fi
|
||||
}
|
||||
|
||||
check_carpadvskew(){
|
||||
if ls /etc/hostname.carp* 1> /dev/null 2>&1; then
|
||||
for carp in $(ifconfig carp | grep ^carp | awk '{print $1}' | tr -d ":"); do
|
||||
ifconfig $carp | grep -q master
|
||||
ifconfig "$carp" | grep -q master
|
||||
master=$?
|
||||
ifconfig $carp | grep -q backup
|
||||
ifconfig "$carp" | grep -q backup
|
||||
backup=$?
|
||||
advskew=$(ifconfig $carp | grep advbase | awk -F 'advskew' '{print $2}' | awk '{print $1}')
|
||||
advskew=$(ifconfig "$carp" | grep advbase | awk -F 'advskew' '{print $2}' | awk '{print $1}')
|
||||
if [ "$master" -eq 0 ]; then
|
||||
if [ $advskew -lt 1 ] || [ $advskew -gt 50 ]; then
|
||||
if [ "$advskew" -lt 1 ] || [ "$advskew" -gt 50 ]; then
|
||||
failed "IS_CARPADVSKEW" "Interface $carp is master : advskew must be between 1 and 50, and must remain lower than that of the backup - current value : $advskew"
|
||||
fi
|
||||
elif [ "$backup" -eq 0 ]; then
|
||||
if [ $advskew -lt 100 ] || [ $advskew -gt 150 ]; then
|
||||
if [ "$advskew" -lt 100 ] || [ "$advskew" -gt 150 ]; then
|
||||
failed "IS_CARPADVSKEW" "Interface $carp is backup : advskew must be between 100 and 150, and must remain greater than that of the master - current value : $advskew"
|
||||
fi
|
||||
else
|
||||
|
@ -379,6 +346,196 @@ check_carpadvskew(){
|
|||
done
|
||||
fi
|
||||
}
|
||||
check_nrpeopensmtpd() {
|
||||
grep -Rq "^command.*check_mailq.pl -M opensmtpd" /etc/nrpe.* || failed "IS_NRPE_OPENSMTPD" "NRPE \"check_mailq\" is not configured for opensmtpd."
|
||||
}
|
||||
check_sshallowusers() {
|
||||
grep -E -qir "(AllowUsers|AllowGroups)" /etc/ssh/sshd_config || failed "IS_SSHALLOWUSERS" "Missing AllowUsers or AllowGroups directive in sshd_config"
|
||||
}
|
||||
check_evobackup_exclude_mount() {
|
||||
excludes_file=$(mktemp)
|
||||
files_to_cleanup="${files_to_cleanup} ${excludes_file}"
|
||||
|
||||
# shellcheck disable=SC2013
|
||||
for evobackup_file in $(grep -Eo "/usr/share/scripts/zzz_evobackup.*" /etc/daily.local | grep -v "^#" | awk '{print $1}'); do
|
||||
# if the file seems to be a backup script, with an Rsync invocation
|
||||
if grep -q "^\s*rsync" "${evobackup_file}"; then
|
||||
# If rsync is not limited by "one-file-system"
|
||||
# then we verify that every mount is excluded
|
||||
if ! grep -q -- "^\s*--one-file-system" "${evobackup_file}"; then
|
||||
grep -- "--exclude " "${evobackup_file}" | grep -E -o "\"[^\"]+\"" | tr -d '"' > "${excludes_file}"
|
||||
not_excluded=$(findmnt --type nfs,nfs4,fuse.sshfs, -o target --noheadings | grep -v -f "${excludes_file}")
|
||||
for mount in ${not_excluded}; do
|
||||
failed "IS_EVOBACKUP_EXCLUDE_MOUNT" "${mount} is not excluded from ${evobackup_file} backup script"
|
||||
done
|
||||
fi
|
||||
fi
|
||||
done
|
||||
rm -rf "${excludes_file}"
|
||||
}
|
||||
check_etcgit() {
|
||||
export GIT_DIR="/etc/.git" GIT_WORK_TREE="/etc"
|
||||
git rev-parse --is-inside-work-tree > /dev/null 2>&1 || failed "IS_ETCGIT" "/etc is not a git repository"
|
||||
}
|
||||
check_evolinuxsudogroup() {
|
||||
if grep -q "^evolinux-sudo:" /etc/group; then
|
||||
grep -qE "^%evolinux-sudo ALL ?= ?\(ALL\) SETENV: ALL" /etc/sudoers || failed "IS_EVOLINUXSUDOGROUP" "Missing evolinux-sudo directive in sudoers file"
|
||||
fi
|
||||
}
|
||||
check_bind9munin() {
|
||||
if is_installed isc-bind; then
|
||||
{ test -L /etc/munin/plugins/bind9 \
|
||||
&& test -e /etc/munin/plugin-conf.d/bind9;
|
||||
} || failed "IS_BIND9MUNIN" "missing bind plugin for munin"
|
||||
fi
|
||||
}
|
||||
check_evolix_user() {
|
||||
grep -q -E "^evolix:" /etc/passwd && failed "IS_EVOLIX_USER" "evolix user should not exist"
|
||||
}
|
||||
download_versions() {
|
||||
# shellcheck disable=SC2039
|
||||
local file
|
||||
file=${1:-}
|
||||
|
||||
## The file is supposed to list programs : each on a line, then its latest version number
|
||||
## Examples:
|
||||
# evoacme 21.06
|
||||
# evomaintenance 0.6.4
|
||||
|
||||
versions_url="https://upgrades.evolix.org/versions-openbsd"
|
||||
|
||||
# fetch timeout, in seconds
|
||||
timeout=10
|
||||
|
||||
if command -v curl > /dev/null; then
|
||||
curl -k --max-time ${timeout} --fail --silent --output "${versions_file}" "${versions_url}"
|
||||
# "-k" required until OpenBSD 6.8
|
||||
elif command -v wget > /dev/null; then
|
||||
wget --timeout=${timeout} --quiet "${versions_url}" -O "${versions_file}"
|
||||
elif command -v GET; then
|
||||
GET -t ${timeout}s "${versions_url}" > "${versions_file}"
|
||||
else
|
||||
failed "IS_CHECK_VERSIONS" "failed to find curl, wget or GET"
|
||||
fi
|
||||
test "$?" -eq 0 || failed "IS_CHECK_VERSIONS" "failed to download ${versions_url} to ${versions_file}"
|
||||
}
|
||||
get_command() {
|
||||
# shellcheck disable=SC2039
|
||||
local program
|
||||
program=${1:-}
|
||||
|
||||
case "${program}" in
|
||||
## Special cases where the program name is different than the command name
|
||||
evocheck) echo "${0}" ;;
|
||||
evomaintenance) command -v "evomaintenance.sh" ;;
|
||||
motd-carp-state) command -v "motd-carp-state.sh" ;;
|
||||
|
||||
## General case, where the program name is the same as the command name
|
||||
*) command -v "${program}" ;;
|
||||
esac
|
||||
}
|
||||
get_version() {
|
||||
# shellcheck disable=SC2039
|
||||
local program
|
||||
# shellcheck disable=SC2039
|
||||
local command
|
||||
program=${1:-}
|
||||
command=${2:-}
|
||||
|
||||
case "${program}" in
|
||||
## Special case if `command --version => 'command` is not the standard way to get the version
|
||||
# my_command)
|
||||
# /path/to/my_command --get-version
|
||||
# ;;
|
||||
|
||||
motd-carp-state)
|
||||
grep '^VERSION=' "${command}" | head -1 | cut -d '=' -f 2
|
||||
;;
|
||||
## General case to get the version
|
||||
*) ${command} --version 2> /dev/null | head -1 | cut -d ' ' -f 3 ;;
|
||||
esac
|
||||
}
|
||||
get_lower_version() {
|
||||
# shellcheck disable=SC2039
|
||||
local actual_version
|
||||
# shellcheck disable=SC2039
|
||||
local expected_version
|
||||
actual_version=${1:-}
|
||||
expected_version=${2:-}
|
||||
|
||||
printf "%s\n%s" "${actual_version}" "${expected_version}" | sort -V | head -n 1
|
||||
}
|
||||
check_version() {
|
||||
# shellcheck disable=SC2039
|
||||
local program
|
||||
# shellcheck disable=SC2039
|
||||
local expected_version
|
||||
program=${1:-}
|
||||
expected_version=${2:-}
|
||||
|
||||
command=$(get_command "${program}")
|
||||
if [ -n "${command}" ]; then
|
||||
actual_version=$(get_version "${program}" "${command}")
|
||||
# printf "program:%s expected:%s actual:%s\n" "${program}" "${expected_version}" "${actual_version}"
|
||||
if [ -z "${actual_version}" ]; then
|
||||
failed "IS_CHECK_VERSIONS" "failed to lookup actual version of ${program}"
|
||||
elif [ "${actual_version}" = "${expected_version}" ]; then
|
||||
: # Version check OK ; to check first because of the way the check works
|
||||
elif [ "$(get_lower_version "${actual_version}" "${expected_version}")" = "${actual_version}" ]; then
|
||||
failed "IS_CHECK_VERSIONS" "${program} version ${actual_version} is older than expected version ${expected_version}"
|
||||
elif [ "$(get_lower_version "${actual_version}" "${expected_version}")" = "${expected_version}" ]; then
|
||||
failed "IS_CHECK_VERSIONS" "${program} version ${actual_version} is newer than expected version ${expected_version}, you should update your index."
|
||||
fi
|
||||
fi
|
||||
}
|
||||
add_to_path() {
|
||||
# shellcheck disable=SC2039
|
||||
local new_path
|
||||
new_path=${1:-}
|
||||
|
||||
echo "$PATH" | grep -qF "${new_path}" || export PATH="${PATH}:${new_path}"
|
||||
}
|
||||
check_versions() {
|
||||
versions_file=$(mktemp -p /tmp "evocheck-versions.XXXXXXXX")
|
||||
files_to_cleanup="${files_to_cleanup} ${versions_file}"
|
||||
|
||||
download_versions "${versions_file}"
|
||||
add_to_path "/usr/share/scripts"
|
||||
|
||||
grep -v '^ *#' < "${versions_file}" | while IFS= read -r line; do
|
||||
# shellcheck disable=SC2039
|
||||
local program
|
||||
# shellcheck disable=SC2039
|
||||
local version
|
||||
program=$(echo "${line}" | cut -d ' ' -f 1)
|
||||
version=$(echo "${line}" | cut -d ' ' -f 2)
|
||||
|
||||
if [ -n "${program}" ]; then
|
||||
if [ -n "${version}" ]; then
|
||||
check_version "${program}" "${version}"
|
||||
else
|
||||
failed "IS_CHECK_VERSIONS" "failed to lookup expected version for ${program}"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
rm -f "${versions_file}"
|
||||
}
|
||||
check_root_user() {
|
||||
if [ "$(grep "^root:" /etc/master.passwd | awk -F":" '{print $2}')" != "*************" ]; then
|
||||
failed "IS_ROOT_USER" "root user should not have a password ; replace the password field with 'vipw' for the root user with '*************' (exactly 13 asterisks) "
|
||||
fi
|
||||
}
|
||||
check_mount(){
|
||||
for fstab_entry in $(grep ffs /etc/fstab | grep -v "^#" | awk '{print $2}'); do
|
||||
mount | awk '{print $3}' | grep -q "^$fstab_entry$" || failed "IS_MOUNT" "Local OpenBSD partition(s) detected in /etc/fstab but not mounted"
|
||||
done
|
||||
}
|
||||
check_mountfstab() {
|
||||
for mount_point in $(mount | awk '{print $3}'); do
|
||||
grep -q " $mount_point " /etc/fstab || failed "IS_MOUNT_FSTAB" "Partition(s) detected mounted but no presence in /etc/fstab"
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
main() {
|
||||
|
@ -400,19 +557,17 @@ main() {
|
|||
test "${IS_CARPPREEMPT:=1}" = 1 && check_carppreempt
|
||||
test "${IS_REBOOTMAIL:=1}" = 1 && check_rebootmail
|
||||
test "${IS_PFENABLED:=1}" = 1 && check_pfenabled
|
||||
test "${IS_PFCUSTOM:=1}" = 1 && check_pfcustom
|
||||
test "${IS_WHEEL:=1}" = 1 && check_wheel
|
||||
test "${IS_PKGMIRROR:=1}" = 1 && check_pkgmirror
|
||||
test "${IS_HISTORY:=1}" = 1 && check_history
|
||||
test "${IS_VIM:=1}" = 1 && check_vim
|
||||
test "${IS_TTYC0SECURE:=1}" = 1 && check_ttyc0secure
|
||||
test "${IS_CUSTOMSYSLOG:=1}" = 1 && check_customsyslog
|
||||
test "${IS_SUDOMAINT:=1}" = 1 && check_sudomaint
|
||||
test "${IS_DOASMAINT:=1}" = 1 && check_doasmaint
|
||||
test "${IS_NRPE:=1}" = 1 && check_nrpe
|
||||
test "${IS_RSYNC:=1}" = 1 && check_rsync
|
||||
test "${IS_CRONPATH:=1}" = 1 && check_cronpath
|
||||
test "${IS_TMP_1777:=1}" = 1 && check_tmp1777
|
||||
test "${IS_ROOT_0700:=1}" = 1 && check_root0700
|
||||
test "${IS_TMP_1777:=1}" = 1 && check_tmp_1777
|
||||
test "${IS_ROOT_0700:=1}" = 1 && check_root_0700
|
||||
test "${IS_USRSHARESCRIPTS:=1}" = 1 && check_usrsharescripts
|
||||
test "${IS_SSHPERMITROOTNO:=1}" = 1 && check_sshpermitrootno
|
||||
test "${IS_EVOMAINTENANCEUSERS:=1}" = 1 && check_evomaintenanceusers
|
||||
|
@ -422,20 +577,59 @@ main() {
|
|||
test "${IS_NTP:=1}" = 1 && check_ntp
|
||||
test "${IS_OPENVPNCRONLOG:=1}" = 1 && check_openvpncronlog
|
||||
test "${IS_CARPADVSKEW:=1}" = 1 && check_carpadvskew
|
||||
test "${IS_NRPE_OPENSMTPD:=1}" = 1 && check_nrpeopensmtpd
|
||||
test "${IS_SSHALLOWUSERS:=1}" = 1 && check_sshallowusers
|
||||
test "${IS_EVOBACKUP_EXCLUDE_MOUNT:=1}" = 1 && check_evobackup_exclude_mount
|
||||
test "${IS_ETCGIT:=1}" = 1 && check_etcgit
|
||||
test "${IS_EVOLINUXSUDOGROUP:=1}" = 1 && check_evolinuxsudogroup
|
||||
test "${IS_BIND9MUNIN:=1}" = 1 && check_bind9munin
|
||||
test "${IS_EVOLIX_USER:=1}" = 1 && check_evolix_user
|
||||
test "${IS_CHECK_VERSIONS:=1}" = 1 && check_versions
|
||||
test "${IS_ROOT_USER:=1}" = 1 && check_root_user
|
||||
test "${IS_MOUNT:=1}" = 1 && check_mount
|
||||
test "${IS_MOUNT_FSTAB:=1}" = 1 && check_mountfstab
|
||||
|
||||
exit ${RC}
|
||||
}
|
||||
cleanup() {
|
||||
# Cleanup tmp files
|
||||
# shellcheck disable=SC2086
|
||||
rm -f ${files_to_cleanup}
|
||||
|
||||
log "$PROGNAME exit."
|
||||
}
|
||||
|
||||
PROGNAME=$(basename "$0")
|
||||
|
||||
LOGFILE="/var/log/evocheck.log"
|
||||
|
||||
CONFIGFILE="/etc/evocheck.cf"
|
||||
|
||||
DATE_FORMAT="%Y-%m-%d %H:%M:%S"
|
||||
|
||||
# Disable LANG*
|
||||
export LANG=C
|
||||
export LANGUAGE=C
|
||||
|
||||
# Source configuration file
|
||||
# shellcheck disable=SC1091
|
||||
test -f "${CONFIGFILE}" && . "${CONFIGFILE}"
|
||||
|
||||
# Parse options
|
||||
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
|
||||
while :; do
|
||||
case $1 in
|
||||
-h|-\?|--help|--version)
|
||||
-h|-\?|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
--version)
|
||||
show_version
|
||||
exit 0
|
||||
;;
|
||||
--cron)
|
||||
IS_KERNELUPTODATE=0
|
||||
IS_UPTIME=0
|
||||
IS_CHECK_VERSIONS=0
|
||||
;;
|
||||
-v|--verbose)
|
||||
VERBOSE=1
|
||||
|
@ -462,4 +656,25 @@ while :; do
|
|||
shift
|
||||
done
|
||||
|
||||
# Keep this after "show_version(); exit 0" which is called by check_versions
|
||||
# to avoid logging exit twice.
|
||||
files_to_cleanup=""
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
log '-----------------------------------------------'
|
||||
log "Running $PROGNAME $VERSION..."
|
||||
|
||||
# Log config file content
|
||||
if [ -f "${CONFIGFILE}" ]; then
|
||||
log "Runtime configuration (${CONFIGFILE}):"
|
||||
conf=$(sed -e '/^[[:blank:]]*#/d; s/#.*//; /^[[:blank:]]*$/d' "${CONFIGFILE}")
|
||||
if [ ! -z "${conf}" ]; then
|
||||
sed -e '/^[[:blank:]]*#/d; s/#.*//; /^[[:blank:]]*$/d' "${CONFIGFILE}" | log
|
||||
else
|
||||
log "${CONFIGFILE} is empty."
|
||||
fi
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
main ${ARGS}
|
||||
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
---
|
||||
- name: run evocheck
|
||||
command: "{{ evocheck_bin_dir }}/evocheck.sh"
|
||||
- name: "Run evocheck"
|
||||
ansible.builtin.command:
|
||||
cmd: "{{ evocheck_bin_dir }}/evocheck.sh"
|
||||
register: evocheck_run
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
check_mode: false
|
||||
tags:
|
||||
- evocheck-exec
|
||||
- evocheck-exec
|
||||
|
||||
- debug:
|
||||
- ansible.builtin.debug:
|
||||
var: evocheck_run.stdout_lines
|
||||
when: evocheck_run.stdout != ""
|
||||
when: evocheck_run.stdout | length > 0
|
||||
tags:
|
||||
- evocheck-exec
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
---
|
||||
- name: Scripts dir is present
|
||||
file:
|
||||
path: "{{ evocheck_bin_dir }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: wheel
|
||||
mode: "0700"
|
||||
tags:
|
||||
- evocheck
|
||||
|
||||
- name: Copy evocheck.sh
|
||||
copy:
|
||||
src: evocheck.sh
|
||||
dest: "{{ evocheck_bin_dir }}/evocheck.sh"
|
||||
mode: "0700"
|
||||
owner: root
|
||||
force: true
|
||||
tags:
|
||||
- evocheck
|
||||
|
||||
- name: Copy evocheck.cf
|
||||
copy:
|
||||
src: evocheck.cf
|
||||
dest: /etc/evocheck.cf
|
||||
force: false
|
||||
tags:
|
||||
- evocheck
|
||||
|
||||
- name: Add evocheck cron
|
||||
lineinfile:
|
||||
path: /etc/daily.local
|
||||
line: 'sh /usr/share/scripts/evocheck.sh --verbose --cron'
|
||||
owner: root
|
||||
mode: "0644"
|
||||
create: true
|
||||
tags:
|
||||
- evocheck
|
||||
|
||||
- name: Add evocheck cron next_part
|
||||
lineinfile:
|
||||
path: /etc/daily.local
|
||||
line: 'next_part "Evocheck output:"'
|
||||
insertbefore: 'sh /usr/share/scripts/evocheck.sh --verbose --cron'
|
||||
owner: root
|
||||
mode: "0644"
|
||||
create: true
|
||||
tags:
|
||||
- evocheck
|
|
@ -1,2 +1,72 @@
|
|||
# yamllint disable rule:line-length
|
||||
---
|
||||
- include: install.yml
|
||||
- name: "Scripts dir is present"
|
||||
ansible.builtin.file:
|
||||
path: "{{ evocheck_bin_dir }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: wheel
|
||||
mode: "0700"
|
||||
tags:
|
||||
- evocheck
|
||||
|
||||
- name: "Copy evocheck.sh"
|
||||
ansible.builtin.copy:
|
||||
src: evocheck.sh
|
||||
dest: "{{ evocheck_bin_dir }}/evocheck.sh"
|
||||
mode: "0700"
|
||||
owner: root
|
||||
force: true
|
||||
tags:
|
||||
- evocheck
|
||||
- evocheck-utils
|
||||
|
||||
- name: "Copy evocheck.cf"
|
||||
ansible.builtin.copy:
|
||||
src: evocheck.cf
|
||||
dest: /etc/evocheck.cf
|
||||
mode: "0644"
|
||||
force: false
|
||||
tags:
|
||||
- evocheck
|
||||
|
||||
- name: "Delete legacy evocheck cron"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/daily.local
|
||||
regexp: 'sh /usr/share/scripts/evocheck.sh --verbose --cron'
|
||||
state: absent
|
||||
tags:
|
||||
- evocheck
|
||||
|
||||
- name: "Add evocheck cron"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/daily.local
|
||||
insertbefore: BOF
|
||||
line: 'sh /usr/share/scripts/evocheck.sh --verbose $cron_arg'
|
||||
owner: root
|
||||
mode: "0600"
|
||||
create: true
|
||||
tags:
|
||||
- evocheck
|
||||
|
||||
- name: "Add evocheck cron - test for date"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/daily.local
|
||||
insertbefore: BOF
|
||||
line: 'if [ $(date +%d) -eq "01" ]; then cron_arg=""; else cron_arg="--cron"; fi'
|
||||
owner: root
|
||||
mode: "0600"
|
||||
create: true
|
||||
tags:
|
||||
- evocheck
|
||||
|
||||
- name: "Add evocheck cron - next_part"
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/daily.local
|
||||
insertbefore: BOF
|
||||
line: 'next_part "Evocheck output:"'
|
||||
owner: root
|
||||
mode: "0600"
|
||||
create: true
|
||||
tags:
|
||||
- evocheck
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# yamllint disable rule:line-length
|
||||
---
|
||||
evomaintenance_realm: "example.com"
|
||||
evomaintenance_alert_email: "evomaintenance-{{ inventory_hostname }}@{{ evomaintenance_realm }}"
|
||||
evomaintenance_hostname: "{{ inventory_hostname }}.{{ general_technical_realm }}"
|
||||
evomaintenance_pg_host: null
|
||||
evomaintenance_pg_passwd: null
|
||||
evomaintenance_pg_db: null
|
||||
evomaintenance_pg_table: null
|
||||
evomaintenance_from_domain: "{{ evomaintenance_realm }}"
|
||||
evomaintenance_from: "evomaintenance@{{ evomaintenance_from_domain }}"
|
||||
evomaintenance_full_from: "Evomaintenance <{{ evomaintenance_from }}>"
|
||||
evomaintenance_urgency_from: mama.doe@example.com
|
||||
evomaintenance_urgency_tel: "06.00.00.00.00"
|
||||
evomaintenance_install_vendor: false
|
||||
evomaintenance_force_config: true
|
||||
evomaintenance_api_endpoint: null
|
||||
evomaintenance_api_key: null
|
||||
evomaintenance_hook_api: true
|
||||
evomaintenance_hook_db: false
|
||||
evomaintenance_hook_commit: true
|
||||
evomaintenance_hook_mail: true
|
||||
evomaintenance_default_hosts: []
|
||||
evomaintenance_additional_hosts: []
|
||||
evomaintenance_hosts: "{{ evomaintenance_default_hosts | union(evomaintenance_additional_hosts) | unique }}"
|
|
@ -1,21 +1,16 @@
|
|||
#!/bin/sh
|
||||
|
||||
# EvoMaintenance script
|
||||
# Dependencies (all OS): git postgresql-client
|
||||
# Dependencies (Debian): sudo
|
||||
|
||||
# Copyright 2007-2019 Evolix <info@evolix.fr>, Gregory Colpart <reg@evolix.fr>,
|
||||
# Jérémy Lecour <jlecour@evolix.fr> and others.
|
||||
|
||||
VERSION="0.6.3"
|
||||
VERSION="23.10.1"
|
||||
|
||||
show_version() {
|
||||
cat <<END
|
||||
evomaintenance version ${VERSION}
|
||||
|
||||
Copyright 2007-2019 Evolix <info@evolix.fr>,
|
||||
Copyright 2007-2023 Evolix <info@evolix.fr>,
|
||||
Gregory Colpart <reg@evolix.fr>,
|
||||
Jérémy Lecour <jlecour@evolix.fr>
|
||||
Jérémy Lecour <jlecour@evolix.fr>,
|
||||
Brice Waegeneire <bwaegeneire@evolix.fr>,
|
||||
Mathieu Trossevin <mtrossevin@evolix.fr>
|
||||
and others.
|
||||
|
||||
evomaintenance comes with ABSOLUTELY NO WARRANTY. This is free software,
|
||||
|
@ -47,10 +42,11 @@ Options
|
|||
--no-evocheck disable evocheck execution
|
||||
--auto use "auto" mode
|
||||
--no-auto use "manual" mode (default)
|
||||
-u, --user=USER force USER value (default: logname(1))
|
||||
-v, --verbose increase verbosity
|
||||
-n, --dry-run actions are not executed
|
||||
--help print this message and exit
|
||||
--version print version and exit
|
||||
-V, --version print version and exit
|
||||
END
|
||||
}
|
||||
|
||||
|
@ -97,13 +93,22 @@ get_who() {
|
|||
}
|
||||
|
||||
get_begin_date() {
|
||||
printf "%s %s" "$(date "+%Y")" "$(get_who | cut -d" " -f3,4,5)"
|
||||
# XXX A begin date isn't applicable when used in autosysadmin, so we
|
||||
# use the same date as the end date.
|
||||
if is_autosysadmin; then
|
||||
get_end_date
|
||||
else
|
||||
printf "%s %s" "$(date "+%Y")" "$(get_who | cut -d" " -f3,4,5)"
|
||||
fi
|
||||
}
|
||||
|
||||
get_ip() {
|
||||
ip=$(get_who | cut -d" " -f6 | sed -e "s/^(// ; s/)$//")
|
||||
[ -z "${ip}" ] && ip="unknown (no tty)"
|
||||
[ "${ip}" = ":0" ] && ip="localhost"
|
||||
if is_autosysadmin || [ "${ip}" = ":0" ]; then
|
||||
ip="localhost"
|
||||
elif [ -z "${ip}" ]; then
|
||||
ip="unknown (no tty)"
|
||||
fi
|
||||
|
||||
echo "${ip}"
|
||||
}
|
||||
|
@ -116,6 +121,14 @@ get_now() {
|
|||
date +"%Y-%m-%dT%H:%M:%S%z"
|
||||
}
|
||||
|
||||
get_user() {
|
||||
if [ -n "${FORCE_USER}" ]; then
|
||||
echo "${FORCE_USER}"
|
||||
else
|
||||
logname
|
||||
fi
|
||||
}
|
||||
|
||||
get_complete_hostname() {
|
||||
REAL_HOSTNAME=$(get_fqdn)
|
||||
if [ "${HOSTNAME}" = "${REAL_HOSTNAME}" ]; then
|
||||
|
@ -174,13 +187,19 @@ print_session_data() {
|
|||
printf "Message : %s\n" "${MESSAGE}"
|
||||
}
|
||||
|
||||
is_autosysadmin() {
|
||||
test "${USER}" = "autosysadmin"
|
||||
}
|
||||
|
||||
is_repository_readonly() {
|
||||
if [ "$(get_system)" = "OpenBSD" ]; then
|
||||
partition=$(stat -f '%Sd' $1)
|
||||
mount | grep ${partition} | grep -q "read-only"
|
||||
else
|
||||
elif command -v findmnt >/dev/null; then
|
||||
mountpoint=$(stat -c '%m' $1)
|
||||
findmnt ${mountpoint} --noheadings --output OPTIONS -O ro
|
||||
else
|
||||
grep /usr /proc/mounts | grep -E '\bro\b'
|
||||
fi
|
||||
}
|
||||
remount_repository_readwrite() {
|
||||
|
@ -301,6 +320,9 @@ From: ${FULLFROM}
|
|||
Content-Type: text/plain; charset=UTF-8
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 8bit
|
||||
X-Evomaintenance-Version: ${VERSION}
|
||||
X-Evomaintenance-Host: ${HOSTNAME_TEXT}
|
||||
X-Evomaintenance-User: ${USER}
|
||||
To: ${EVOMAINTMAIL}
|
||||
Subject: [evomaintenance] Intervention sur ${HOSTNAME_TEXT} (${USER})
|
||||
|
||||
|
@ -377,6 +399,7 @@ AUTO=${AUTO:-"0"}
|
|||
EVOCHECK=${EVOCHECK:-"0"}
|
||||
GIT_STATUS_MAX_LINES=${GIT_STATUS_MAX_LINES:-20}
|
||||
API_ENDPOINT=${API_ENDPOINT:-""}
|
||||
FORCE_USER=${FORCE_USER:-""}
|
||||
|
||||
# initialize variables
|
||||
MESSAGE=""
|
||||
|
@ -454,6 +477,31 @@ while :; do
|
|||
# use "auto" mode
|
||||
AUTO=1
|
||||
;;
|
||||
--autosysadmin)
|
||||
# Deprecated, backward compatibility
|
||||
# author change as autosysadmin
|
||||
printf 'WARNING: "--autosysadmin" is deprecated, use "--user autosysadmin".\n' >&2
|
||||
FORCE_USER="autosysadmin"
|
||||
;;
|
||||
-u|--user)
|
||||
# user options, with value speparated by space
|
||||
if [ -n "$2" ]; then
|
||||
FORCE_USER=$2
|
||||
shift
|
||||
else
|
||||
printf 'ERROR: "--user" requires a non-empty option argument.\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--user=?*)
|
||||
# message options, with value speparated by =
|
||||
FORCE_USER=${1#*=}
|
||||
;;
|
||||
--user=)
|
||||
# message options, without value
|
||||
printf 'ERROR: "--user" requires a non-empty option argument.\n' >&2
|
||||
exit 1
|
||||
;;
|
||||
-n|--dry-run)
|
||||
# disable actual commands
|
||||
DRY_RUN=1
|
||||
|
@ -492,7 +540,7 @@ HOSTNAME_TEXT=$(get_complete_hostname)
|
|||
IP=$(get_ip)
|
||||
BEGIN_DATE=$(get_begin_date)
|
||||
END_DATE=$(get_end_date)
|
||||
USER=$(logname)
|
||||
USER=$(get_user)
|
||||
|
||||
PATH=${PATH}:/usr/sbin
|
||||
|
||||
|
@ -531,6 +579,11 @@ EVOCHECK_BIN="/usr/share/scripts/evocheck.sh"
|
|||
|
||||
GIT_REPOSITORIES="/etc /etc/bind /usr/share/scripts"
|
||||
|
||||
# Add /etc directories from lxc containers if they are git directories
|
||||
if [ -d /var/lib/lxc ]; then
|
||||
GIT_REPOSITORIES="${GIT_REPOSITORIES} $(find /var/lib/lxc/ -maxdepth 3 -name 'etc' | tr '\n' ' ' | sed 's/[[:space:]]\+$//')"
|
||||
fi
|
||||
|
||||
# initialize variable
|
||||
GIT_STATUSES=""
|
||||
# git statuses
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
- name: Create scripts directory
|
||||
file:
|
||||
- name: "Create scripts directory"
|
||||
ansible.builtin.file:
|
||||
path: /usr/share/scripts/
|
||||
state: directory
|
||||
owner: root
|
||||
|
@ -9,8 +9,8 @@
|
|||
tags:
|
||||
- evomaintenance
|
||||
|
||||
- name: Copy evomaintenance script and template
|
||||
copy:
|
||||
- name: "Copy evomaintenance script and template"
|
||||
ansible.builtin.copy:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ item.dest }}"
|
||||
owner: 'root'
|
||||
|
@ -21,10 +21,10 @@
|
|||
- {src: 'evomaintenance.tpl', dest: '/usr/share/scripts/', mode: '0600'}
|
||||
tags:
|
||||
- evomaintenance
|
||||
- script-evomaintenance
|
||||
- evomaintenance-utils
|
||||
|
||||
- name: Configure evomaintenance
|
||||
template:
|
||||
- name: "Configure evomaintenance"
|
||||
ansible.builtin.template:
|
||||
src: evomaintenance.j2
|
||||
dest: /etc/evomaintenance.cf
|
||||
owner: root
|
|
@ -1,18 +1,20 @@
|
|||
---
|
||||
- name: Enable IPv4 forwarding
|
||||
sysctl:
|
||||
- name: "Enable IPv4 forwarding"
|
||||
ansible.posix.sysctl:
|
||||
name: net.inet.ip.forwarding
|
||||
value: "1"
|
||||
state: present
|
||||
reload: true
|
||||
tags:
|
||||
- net
|
||||
- forwarding
|
||||
- forwarding-v4
|
||||
|
||||
- name: Enable IPv6 forwarding
|
||||
sysctl:
|
||||
- name: "Enable IPv6 forwarding"
|
||||
ansible.posix.sysctl:
|
||||
name: net.inet6.ip6.forwarding
|
||||
value: "1"
|
||||
state: present
|
||||
reload: true
|
||||
tags:
|
||||
- net
|
||||
- forwarding
|
||||
- forwarding-v6
|
||||
|
|
|
@ -49,38 +49,45 @@ x-gw.*: exit host
|
|||
x-gw.*: permit host
|
||||
xntpd.*Previous time adjustment didn't complete
|
||||
xntpd.*time reset
|
||||
ansible-command: Invoked
|
||||
ansible-copy: Invoked
|
||||
ansible-cron: Invoked
|
||||
ansible-file: Invoked
|
||||
ansible-openbsd_pkg: Invoked
|
||||
ansible-setup: Invoked
|
||||
ansible-slurp: Invoked
|
||||
ansible-stat: Invoked
|
||||
ansible-synchronize: Invoked
|
||||
ansible-.*: Invoked with
|
||||
bgpd.*: neighbor .*: sending IPv4 unicast EOR marker
|
||||
bgpd.*: neighbor .*: sending IPv6 unicast EOR marker
|
||||
bgpd.*: neighbor .*: received IPv4 unicast EOR marker
|
||||
bgpd.*: neighbor .*: received IPv6 unicast EOR marker
|
||||
bgpd.*: RDE reconfigured
|
||||
bgpd.*: RDE soft reconfiguration done
|
||||
bgpd.*: rereading config
|
||||
bgpd.*: running softreconfig in
|
||||
bgpd.*: SE reconfigured
|
||||
bgpd.*: softreconfig in done
|
||||
collectd.*: parse_value: Failed to parse string as gauge: "Active".
|
||||
collectd.*: parse_value: Failed to parse string as gauge: "Connect".
|
||||
collectd.*: parse_value: Failed to parse string as gauge: "Idle".
|
||||
doas: _collectd ran command /bin/cat /var/log/daemon as root from /var/collectd
|
||||
doas: _collectd ran command /usr/sbin/bgpctl sh as root from /var/collectd
|
||||
doas: _collectd ran command /usr/sbin/bgpctl show neighbor as root from /var/collectd
|
||||
doas: _collectd ran command /usr/sbin/unbound-control stats as root from /var/collectd
|
||||
doas: _nrpe ran command /sbin/bioctl sd2 as root from /
|
||||
doas: _nrpe ran command /usr/local/libexec/nagios
|
||||
doas: .* ran command su - as root from
|
||||
doas:.*ran command /usr/share/scripts/evomaintenance.sh as root from
|
||||
last message repeated .* times
|
||||
mownitoring.py: Alert sent through email
|
||||
mownitoring.py: Already known state but still a problem for
|
||||
mta server-cert-check result="failure"
|
||||
newsyslog.*logfile turned over
|
||||
nrpe.*: Could not read request from client, bailing out...
|
||||
nrpe.*: Error: Could not complete SSL handshake.
|
||||
nrpe.*: INFO: SSL Socket Shutdown.
|
||||
nrpe.*: Client request was invalid, bailing out...
|
||||
nrpe.*: Error: Request packet type/version was invalid!
|
||||
ntpd.*: adjusting clock frequency by
|
||||
ntpd.*: peer 31.170.8.123 now invalid
|
||||
ntpd.*: peer 31.170.8.123 now valid
|
||||
ospfd.*recv_packet: authentication error, interface
|
||||
pkg_add: Added
|
||||
pmap_unwire: wiring for pmap .* va .* didn't change!
|
||||
smtpd.*delivery evpid=.* from=<root@.*.evolix.net> to=
|
||||
smtpd.*mta connected
|
||||
smtpd.*mta connecting address=smtp://
|
||||
smtpd.*mta delivery evpid=
|
||||
|
@ -92,8 +99,16 @@ smtpd.*smtp connected address=local
|
|||
smtpd.*smtp disconnected reason=quit
|
||||
smtpd.*smtp envelope evpid=
|
||||
smtpd.*smtp message msgid=
|
||||
sshd.*Accepted publickey for.*from 31.170.* port
|
||||
sshd.*Accepted publickey for.*from 82.65.34.85 port
|
||||
sshd.*Connection closed by 127.0.0.1 port
|
||||
sshd.*: Connection closed by authenticating user .* 31.170.* port
|
||||
sshd.*: Connection closed by authenticating user .* 82.65.34.85 port
|
||||
sshd.*Connection reset by 127.0.0.1 port
|
||||
sshd.*Disconnected from user.*31.170.* port
|
||||
sshd.*Disconnected from user.*82.65.34.85 port
|
||||
sshd.*Received disconnect from 31.170.* port
|
||||
sshd.*Received disconnect from 82.65.34.85 port
|
||||
sudo:.*: a password is required ; TTY=.* ; PWD=/home/.* ; USER=root ; COMMAND=
|
||||
sudo:.*: TTY=.* ; PWD=/home/.* ; USER=root ; COMMAND=
|
||||
syslogd.*restart
|
||||
|
|
|
@ -149,7 +149,7 @@ rm -f $TMPDIR/check.$$ $TMPDIR/checkoutput.$$ $TMPDIR/checkreport.$$
|
|||
if [ -f $TMPDIR/check.$$ -o -f $TMPDIR/checkoutput.$$ -o -f $TMPDIR/checkreport.$$ ]; then
|
||||
echo "Log files exist in $TMPDIR directory that cannot be removed. This
|
||||
may be an attempt to spoof the log checker." \
|
||||
| $MAIL -s "$HOSTNAME $DATE ACTIVE SYSTEM ATTACK!" $SYSADMIN
|
||||
| $MAIL -s "[logsentry] $HOSTNAME $DATE ACTIVE SYSTEM ATTACK!" $SYSADMIN
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
@ -272,9 +272,9 @@ fi
|
|||
# If there are results, mail them to sysadmin
|
||||
|
||||
if [ "$ATTACK" -eq 1 ]; then
|
||||
cat $TMPDIR/checkreport.$$ | $MAIL -s "$HOSTNAME $DATE ACTIVE SYSTEM ATTACK!" $SYSADMIN
|
||||
cat $TMPDIR/checkreport.$$ | $MAIL -s "[logsentry] $HOSTNAME $DATE ACTIVE SYSTEM ATTACK!" $SYSADMIN
|
||||
elif [ "$FOUND" -eq 1 ]; then
|
||||
cat $TMPDIR/checkreport.$$ | $MAIL -s "$HOSTNAME $DATE system check" $SYSADMIN
|
||||
cat $TMPDIR/checkreport.$$ | $MAIL -s "[logsentry] $HOSTNAME $DATE system check" $SYSADMIN
|
||||
fi
|
||||
|
||||
# Clean Up
|
||||
|
|
|
@ -5,5 +5,15 @@ smtpd.*smtp connected address=local
|
|||
smtpd.*smtp disconnected reason=quit
|
||||
smtpd.*smtp envelope evpid=
|
||||
smtpd.*smtp message msgid=
|
||||
smtpd.*mta connecting address=smtp://.* host=
|
||||
smtpd.*mta connected
|
||||
smtpd.*mta tls ciphers=
|
||||
smtpd.*mta server-cert-check result="success"
|
||||
smtpd.*mta delivery evpid=
|
||||
smtpd.*mta disconnected reason=quit messages=
|
||||
nrpe.*: INFO: SSL Socket Shutdown.
|
||||
collectd.*: exec plugin: Failed to execute
|
||||
collectd.*: parse_value: Failed to parse string as gauge: "Active".
|
||||
collectd.*: parse_value: Failed to parse string as gauge: "Connect".
|
||||
collectd.*: parse_value: Failed to parse string as gauge: "Idle".
|
||||
mta server-cert-check result="failure"
|
||||
|
|
|
@ -1,14 +1,31 @@
|
|||
---
|
||||
- name: Install logsentry
|
||||
openbsd_pkg:
|
||||
name:
|
||||
- logsentry--
|
||||
state: present
|
||||
# openbsd_pkg is broken since OpenBSD 7.4 with the version of Ansible we currently use
|
||||
#- name: "Install logsentry"
|
||||
# community.general.openbsd_pkg:
|
||||
# name:
|
||||
# - logsentry--
|
||||
# state: present
|
||||
# tags:
|
||||
# - logsentry
|
||||
|
||||
- name: "Check if logsentry-- is already installed"
|
||||
ansible.builtin.command:
|
||||
cmd: pkg_info -Iq inst:logsentry--
|
||||
register: is_installed
|
||||
ignore_errors: true
|
||||
changed_when: false
|
||||
tags:
|
||||
- logsentry
|
||||
|
||||
- name: Copy logsentry script to /usr/share/scripts
|
||||
copy:
|
||||
- name: "Install logsentry--"
|
||||
ansible.builtin.command:
|
||||
cmd: pkg_add logsentry--
|
||||
when: "'Can\\'t find inst:' in is_installed.stderr"
|
||||
tags:
|
||||
- logsentry
|
||||
|
||||
- name: "Copy logsentry script to /usr/share/scripts"
|
||||
ansible.builtin.copy:
|
||||
src: logsentry.sh
|
||||
dest: /usr/share/scripts/logsentry.sh
|
||||
owner: root
|
||||
|
@ -17,30 +34,29 @@
|
|||
tags:
|
||||
- logsentry
|
||||
|
||||
- name: Copy logsentry.ignore configuration
|
||||
copy:
|
||||
- name: "Copy custom logsentry configuration files"
|
||||
ansible.builtin.copy:
|
||||
src: "{{ item }}"
|
||||
dest: /etc/logsentry/logsentry.ignore
|
||||
with_first_found:
|
||||
- "files/logsentry/logsentry.ignore"
|
||||
- "logsentry.ignore"
|
||||
dest: "/etc/logsentry/{{ item }}"
|
||||
owner: root
|
||||
group: wheel
|
||||
mode: "0600"
|
||||
with_items:
|
||||
- logsentry.ignore
|
||||
- logsentry.violations.ignore
|
||||
tags:
|
||||
- logsentry
|
||||
- config
|
||||
- logsentry-config
|
||||
|
||||
- name: Copy logsentry.violations.ignore configuration
|
||||
copy:
|
||||
src: "{{ item }}"
|
||||
dest: /etc/logsentry/logsentry.violations.ignore
|
||||
with_first_found:
|
||||
- "files/logsentry/logsentry.violations.ignore"
|
||||
- "logsentry.violations.ignore"
|
||||
- name: "Delete unused default script"
|
||||
ansible.builtin.file:
|
||||
state: absent
|
||||
path: /etc/logsentry/logsentry.sh
|
||||
tags:
|
||||
- logsentry
|
||||
- config
|
||||
|
||||
- name: hourly cron job for logsentry.sh is installed
|
||||
cron:
|
||||
- name: "Hourly cron job for logsentry.sh is installed"
|
||||
ansible.builtin.cron:
|
||||
name: logsentry
|
||||
minute: "11"
|
||||
job: >
|
||||
|
|
|
@ -4,9 +4,7 @@ nagios_nrpe_additional_allowed_hosts: []
|
|||
nagios_nrpe_allowed_hosts:
|
||||
"{{ nagios_nrpe_default_allowed_hosts
|
||||
| union(nagios_nrpe_additional_allowed_hosts) | unique }}"
|
||||
nagios_nrpe_pgsql_passwd: PGSQL_PASSWD
|
||||
nagios_nrpe_amavis_from: "foobar@{{ ansible_domain }}"
|
||||
|
||||
nagios_nrpe_check_proxy_host: "www.example.com"
|
||||
nagios_nrpe_default_ntp_server: "pool.ntp.org"
|
||||
|
||||
nagios_plugins_directory: "/usr/local/lib/nagios/plugins"
|
||||
evobsd_ssl_cert_hostname: "{{ inventory_hostname }}.{{ general_technical_realm }}"
|
||||
|
|
|
@ -48,15 +48,13 @@ if [ -z "$2" ];then
|
|||
fi
|
||||
|
||||
# check if the carp interface exists or not
|
||||
ifconfig $1 > /dev/null
|
||||
if [ $? != "0" ];then
|
||||
if ! ifconfig "$1" > /dev/null; then
|
||||
echo "carp interface $1 does not exist. Exiting ...."
|
||||
exit "$STATE_CRITICAL"
|
||||
fi
|
||||
|
||||
# check state
|
||||
ifconfig $1 | grep -i $2 > /dev/null
|
||||
if [ $? != "0" ];then
|
||||
if ! ifconfig "$1" | grep -i "$2" > /dev/null; then
|
||||
echo "NOT_OK - $1 should be $2"
|
||||
exit "$STATE_CRITICAL"
|
||||
else
|
||||
|
|
|
@ -5,8 +5,8 @@ MAIN_CONNECTION_PINGABLE_IP="31.170.8.95"
|
|||
MAIN_CONNECTION_GATEWAY="IP"
|
||||
MAIN_CONNECTION_IP="IP"
|
||||
SECOND_CONNECTION_PINGABLE_IP="31.170.8.243"
|
||||
INFO_MAIN_CONNECTION="IP - Description"
|
||||
INFO_SECOND_CONNECTION="IP - Description"
|
||||
INFO_MAIN_CONNECTION="IP - Description - interface"
|
||||
INFO_SECOND_CONNECTION="IP - Description - interface"
|
||||
CURRENT_GATEWAY=$(/usr/bin/netstat -nr | /usr/bin/grep "default" | /usr/bin/awk '{print $2}')
|
||||
|
||||
IS_GATEWAY_IN_FILE=1 # Check whether /etc/mygate has the IP of main connection
|
||||
|
@ -26,10 +26,9 @@ fi
|
|||
|
||||
# If main connection is UP but not used => critical and continue
|
||||
# If main connection is DOWN (used or not) => warning and exit
|
||||
/sbin/ping -c1 -w1 ${MAIN_CONNECTION_PINGABLE_IP} >/dev/null 2>&1
|
||||
if [ $? = 0 ]; then
|
||||
if /sbin/ping -c1 -w1 ${MAIN_CONNECTION_PINGABLE_IP} >/dev/null 2>&1; then
|
||||
if [ "${CURRENT_GATEWAY}" != "${MAIN_CONNECTION_GATEWAY}" ]; then
|
||||
echo "Main connection is UP but not used as gateway !"
|
||||
echo "Main connection is UP (${INFO_MAIN_CONNECTION}) but not used as gateway !"
|
||||
STATE=2
|
||||
fi
|
||||
else
|
||||
|
@ -42,16 +41,14 @@ else
|
|||
fi
|
||||
|
||||
# If second connection is DOWN => critical and continue
|
||||
/sbin/ping -c1 -w1 ${SECOND_CONNECTION_PINGABLE_IP} >/dev/null 2>&1
|
||||
if [ $? != 0 ]; then
|
||||
if ! /sbin/ping -c1 -w1 ${SECOND_CONNECTION_PINGABLE_IP} >/dev/null 2>&1; then
|
||||
echo "Second connection (${INFO_SECOND_CONNECTION}) is down"
|
||||
STATE=2
|
||||
fi
|
||||
|
||||
# Check whether /etc/mygate has the IP of main connection
|
||||
if [ "${IS_GATEWAY_IN_FILE}" = 1 ]; then
|
||||
/usr/bin/grep -q "${MAIN_CONNECTION_GATEWAY}" /etc/mygate
|
||||
if [ $? != 0 ]; then
|
||||
if ! /usr/bin/grep -q "${MAIN_CONNECTION_GATEWAY}" /etc/mygate; then
|
||||
echo "Main connection is not set in /etc/mygate"
|
||||
STATE=2
|
||||
fi
|
||||
|
@ -59,8 +56,7 @@ fi
|
|||
|
||||
# Check whether ipsecctl use the main connection
|
||||
if [ "${IS_VPN_USING_MAIN_CONNECTION}" = 1 ]; then
|
||||
/sbin/ipsecctl -sa | /usr/bin/grep -q "${MAIN_CONNECTION_IP}"
|
||||
if [ $? != 0 ]; then
|
||||
if ! /sbin/ipsecctl -sa | /usr/bin/grep -q "${MAIN_CONNECTION_IP}"; then
|
||||
echo "VPN is not using the main connection !"
|
||||
STATE=2
|
||||
fi
|
||||
|
@ -68,8 +64,7 @@ fi
|
|||
|
||||
# Check whether PacketFilter has route-to using the main connection
|
||||
if [ "${IS_PF_USING_MAIN_CONNECTION}" = 1 ]; then
|
||||
/sbin/pfctl -sr | /usr/bin/grep "route-to" | /usr/bin/grep -q "${MAIN_CONNECTION_GATEWAY}"
|
||||
if [ $? != 0 ]; then
|
||||
if ! /sbin/pfctl -sr | /usr/bin/grep "route-to" | /usr/bin/grep -q "${MAIN_CONNECTION_GATEWAY}"; then
|
||||
echo "PF is not using the main connection !"
|
||||
STATE=2
|
||||
fi
|
||||
|
@ -81,7 +76,7 @@ if [ "${IS_MISCELLANEOUS}" = 1 ]; then
|
|||
fi
|
||||
|
||||
if [ "${STATE}" = 0 ]; then
|
||||
echo "OK - Main connection is UP and used, second connection is UP"
|
||||
echo "OK - Main connection is UP and used (${INFO_MAIN_CONNECTION}), second connection is UP (${INFO_SECOND_CONNECTION})"
|
||||
fi
|
||||
|
||||
exit ${STATE}
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Copyright (C) 2008 Rien Broekstra <rien@rename-it.nl>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; version 2 dated June,
|
||||
# 1991.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
#
|
||||
# Configuration variables:
|
||||
#
|
||||
# conffile - path to dhcpd's configuration file (default "/etc/dhcpd.conf")
|
||||
# leasefile - path to dhcpd's leases file (default "/var/lib/dhcp/dhcpd.leases")
|
||||
#
|
||||
|
||||
use POSIX;
|
||||
use Time::Local;
|
||||
use strict;
|
||||
|
||||
my $CONFFILE = exists $ENV{'conffile'} ? $ENV{'conffile'} : "/etc/dhcpd.conf";
|
||||
my $LEASEFILE = exists $ENV{'leasefile'} ? $ENV{'leasefile'} : "/var/db/dhcpd.leases";
|
||||
my $WARNING_LEVEL = 70;
|
||||
my $CRITICAL_LEVEL = 90;
|
||||
|
||||
my (@activeleases, %dhcp_pools, $pool_start, $pool_end, $pool_size, $pool_free, $pool_usage, $pool_status, $label, $lease, $nagios_return_code, $nagios_ok, $nagios_warning, $nagios_critical, @nagios_text, @nagios_perfdata);
|
||||
|
||||
# Determine all leased IP addresses
|
||||
@activeleases = determine_active_leases();
|
||||
|
||||
# Determine the available IP pools
|
||||
%dhcp_pools = determine_pools();
|
||||
|
||||
# Nagios return code
|
||||
$nagios_return_code = 0;
|
||||
$nagios_ok = 0;
|
||||
$nagios_warning = 0;
|
||||
$nagios_critical = 0;
|
||||
|
||||
# For each pool, count how many leases from that pool are currently active
|
||||
foreach $pool_start (keys %dhcp_pools) {
|
||||
$pool_size = $dhcp_pools{$pool_start};
|
||||
$pool_end = $pool_start+$pool_size-1;
|
||||
$pool_free = $pool_size;
|
||||
|
||||
foreach $lease (@activeleases) {
|
||||
if ($lease >= $pool_start && $lease <= $pool_end) {
|
||||
$pool_free--;
|
||||
}
|
||||
}
|
||||
|
||||
$label = ip2string($pool_start)."-".ip2string($pool_end);
|
||||
$pool_usage = sprintf("%.1f", 100*($pool_size-$pool_free)/$pool_size);
|
||||
|
||||
if ($pool_usage >= $CRITICAL_LEVEL) {
|
||||
$nagios_return_code = 2;
|
||||
$nagios_critical++;
|
||||
$pool_status = "CRITICAL";
|
||||
} elsif ($pool_usage >= $WARNING_LEVEL) {
|
||||
if ($nagios_return_code == 0 ) {
|
||||
$nagios_return_code = 1;
|
||||
}
|
||||
$nagios_warning++;
|
||||
$pool_status = "WARNING";
|
||||
}
|
||||
else {
|
||||
$nagios_ok++;
|
||||
$pool_status = "OK";
|
||||
}
|
||||
|
||||
push(@nagios_text, "$pool_status : $label - $pool_usage \n");
|
||||
push(@nagios_perfdata, "$label=$pool_usage%;$WARNING_LEVEL%;$CRITICAL_LEVEL%;;" );
|
||||
# 'label'=value[UOM];[warn];[crit];;
|
||||
|
||||
}
|
||||
|
||||
|
||||
print nagios_code_2_txt($nagios_return_code)." - ".$nagios_critical." CRIT / ".$nagios_warning." WARN / ".$nagios_ok." OK \n\n";
|
||||
|
||||
print grep(/CRITICAL/, @nagios_text);
|
||||
print grep(/WARNING/, @nagios_text);
|
||||
print grep(/OK/, @nagios_text);
|
||||
|
||||
print "|@nagios_perfdata";
|
||||
|
||||
exit $nagios_return_code;
|
||||
|
||||
|
||||
################
|
||||
###### FUNCTIONS
|
||||
|
||||
# Parse dhcpd.conf for range statements.
|
||||
#
|
||||
# Returns a hash with start IP -> size
|
||||
sub determine_pools {
|
||||
my (%pools, @conffile, $line, $start, $end, $size);
|
||||
|
||||
open(CONFFILE, "<${CONFFILE}") || exit -1;
|
||||
@conffile = <CONFFILE>;
|
||||
close (CONFFILE);
|
||||
|
||||
foreach $line (@conffile) {
|
||||
next if $line =~ /^\s*#/;
|
||||
|
||||
if ($line =~ /range[\s]+([\d]+\.[\d]+\.[\d]+\.[\d]+)[\s]+([\d]+\.[\d]+\.[\d]+\.[\d]+)/) {
|
||||
$start = string2ip($1);
|
||||
$end = string2ip($2);
|
||||
|
||||
defined($start) || next;
|
||||
defined($end) || next;
|
||||
|
||||
# The range statement gives the lowest and highest IP addresses in a range.
|
||||
$size = $end - $start + 1;
|
||||
|
||||
$pools{$start} = $size;
|
||||
}
|
||||
}
|
||||
return %pools;
|
||||
}
|
||||
|
||||
# Very simple parser for dhcpd.leases. This will break very easily if dhcpd decides to
|
||||
# format the file differently. Ideally a simple recursive-descent parser should be used.
|
||||
#
|
||||
# Returns an array with currently leased IP's
|
||||
sub determine_active_leases {
|
||||
my (@leasefile, $startdate, $enddate, $lease, @activeleases, $mytz, $line, %saw);
|
||||
|
||||
open(LEASEFILE, "<${LEASEFILE}") || exit -1;
|
||||
@leasefile = <LEASEFILE>;
|
||||
close (LEASEFILE);
|
||||
|
||||
@activeleases = ();
|
||||
|
||||
# Portable way of converting a GMT date/time string to timestamp is setting TZ to UTC, and then calling mktime()
|
||||
$mytz = $ENV{'TZ'};
|
||||
$ENV{'TZ'} = 'UTC 0';
|
||||
tzset();
|
||||
|
||||
foreach $line (@leasefile) {
|
||||
if ($line =~ /lease ([\d]+\.[\d]+\.[\d]+\.[\d]+)/) {
|
||||
$lease = string2ip($1);
|
||||
defined($lease) || next;
|
||||
|
||||
undef $startdate;
|
||||
undef $enddate;
|
||||
}
|
||||
elsif ($line =~ /starts \d ([\d]{4})\/([\d]{2})\/([\d]{2}) ([\d]{2}):([\d]{2}):([\d]{2})/) {
|
||||
$startdate = mktime($6, $5, $4, $3, $2-1, $1-1900, 0, 0);
|
||||
}
|
||||
elsif ($line =~ /ends \d ([\d]{4})\/([\d]{2})\/([\d]{2}) ([\d]{2}):([\d]{2}):([\d]{2})/) {
|
||||
$enddate = mktime($6, $5, $4, $3, $2-1, $1-1900, 0, 0);
|
||||
}
|
||||
elsif ($line !~ /abandoned/) {
|
||||
if (defined($enddate) && defined($startdate) && defined($lease)) {
|
||||
if ($startdate < time() && $enddate > time()) {
|
||||
push (@activeleases, $lease);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# Set TZ back to its original setting
|
||||
if (defined($mytz)) {
|
||||
$ENV{'TZ'} = $mytz;
|
||||
}
|
||||
else {
|
||||
delete $ENV{'TZ'};
|
||||
}
|
||||
tzset();
|
||||
|
||||
# Sort the array, strip doubles, and return
|
||||
return grep(!$saw{$_}++, @activeleases);
|
||||
}
|
||||
|
||||
#
|
||||
# Helper routine to convert an IP address a.b.c.d into an integer
|
||||
#
|
||||
# Returns an integer representation of an IP address
|
||||
sub string2ip {
|
||||
my $string = shift;
|
||||
defined($string) || return undef;
|
||||
if ($string =~ /([\d]+)\.([\d]+)\.([\d]+)\.([\d]+)/) {
|
||||
if ($1 < 0 || $1 > 255 || $2 < 0 || $2 > 255 || $3 < 0 || $3 > 255 || $4 < 0 || $4 > 255) {
|
||||
return undef;
|
||||
}
|
||||
else {
|
||||
return $1 << 24 | $2 << 16 | $3 << 8 | $4;
|
||||
}
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
#
|
||||
# Returns a dotted quad notation of an
|
||||
#
|
||||
sub ip2string {
|
||||
my $ip = shift;
|
||||
defined ($ip) || return undef;
|
||||
return sprintf ("%d.%d.%d.%d", ($ip >> 24) & 0xff, ($ip >> 16) & 0xff, ($ip >> 8) & 0xff, $ip & 0xff);
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Return textual status of return code
|
||||
#
|
||||
sub nagios_code_2_txt{
|
||||
my $code = shift;
|
||||
defined ($code) || return undef;
|
||||
|
||||
if($code == 0 ) { return "OK" }
|
||||
elsif( $code == 1 ) { return "WARNING" }
|
||||
elsif( $code == 2 ) { return "CRITICAL" }
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Simple wraper to define the number of dhcpd processes that must be running
|
||||
# depending on the CARP active or backup state
|
||||
# Can be customized if dhcpd must be running even in backup state
|
||||
|
||||
dhcpd_processes_number=1
|
||||
|
||||
CARP_STATUS=$(/sbin/ifconfig carp0 | /usr/bin/grep "status" | /usr/bin/awk '{print $2}')
|
||||
if [ "$CARP_STATUS" = "backup" ]; then
|
||||
dhcpd_processes_number=0
|
||||
fi
|
||||
|
||||
/usr/local/libexec/nagios/check_procs -c ${dhcpd_processes_number}:${dhcpd_processes_number} -C dhcpd
|
|
@ -0,0 +1,1074 @@
|
|||
#!/usr/bin/perl
|
||||
# check_ipmi_sensor: Nagios/Icinga plugin to check IPMI sensors
|
||||
#
|
||||
# Copyright (C) 2009-2019 Thomas-Krenn.AG,
|
||||
# additional contributors see changelog.txt
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
# The following guides provide helpful information if you want to extend this
|
||||
# script:
|
||||
# http://tldp.org/LDP/abs/html/ (Advanced Bash-Scripting Guide)
|
||||
# http://www.gnu.org/software/gawk/manual/ (Gawk: Effective AWK Programming)
|
||||
# http://de.wikibooks.org/wiki/Awk (awk Wikibook, in German)
|
||||
# http://nagios.sourceforge.net/docs/3_0/customobjectvars.html (hints on
|
||||
# custom object variables)
|
||||
# http://nagiosplug.sourceforge.net/developer-guidelines.html (plug-in
|
||||
# development guidelines)
|
||||
# http://nagios.sourceforge.net/docs/3_0/pluginapi.html (plugin API)
|
||||
################################################################################
|
||||
use strict;
|
||||
use warnings;
|
||||
use Getopt::Long qw(:config no_ignore_case);
|
||||
use IPC::Run qw( run ); #interact with processes
|
||||
################################################################################
|
||||
# set text variables
|
||||
our $check_ipmi_sensor_version = "3.13";
|
||||
|
||||
sub get_version{
|
||||
return <<EOT;
|
||||
check_ipmi_sensor version $check_ipmi_sensor_version
|
||||
Copyright (C) 2009-2019 Thomas-Krenn.AG
|
||||
Current updates at https://github.com/thomas-krenn/check_ipmi_sensor_v3.git
|
||||
EOT
|
||||
}
|
||||
|
||||
sub get_usage{
|
||||
return <<EOT;
|
||||
Usage:
|
||||
check_ipmi_sensor -H <hostname>
|
||||
[-f <FreeIPMI config file> | -U <username> -P <password> -L <privilege level>]
|
||||
[-O <FreeIPMI options>] [-b] [-T <sensor type(s)>] [-ST <SEL sensor type(s)>]
|
||||
[-x <sensor id>] [-xT <sensor type(s)>] [-xST <SEL sensor type(s)]
|
||||
[-i <sensor id>] [-o zenoss] [-D <protocol LAN version>] [-h] [-V]
|
||||
[-fc <num_fans>] [--fru] [--nosel] [--selonly] [--seltail <count>]
|
||||
[-sx|--selexclude <sel exclude file>] [-xx|--sexclude <exclude file>]
|
||||
[-us|--unify-sensors <unify file>] [--nosudo [--nothresholds]
|
||||
[--noentityabsent] [-s <ipmi-sensor output file>] [-h] [-V]
|
||||
[-v|-vv|-vvv]
|
||||
EOT
|
||||
}
|
||||
|
||||
sub get_help{
|
||||
return <<EOT;
|
||||
[-H <hostname>]
|
||||
hostname or IP of the IPMI interface.
|
||||
For \"-H localhost\" or if no host is specified (local computer) the
|
||||
Nagios/Icinga user must be allowed to run
|
||||
ipmimonitoring/ipmi-sensors/ipmi-sel/[ipmi-fru] with root privileges
|
||||
or via sudo (ipmimonitoring/ipmi-sensors/ipmi-sel/[ipmi-fru] must be
|
||||
able to access the IPMI devices via the IPMI system interface).
|
||||
[-f <FreeIPMI config file>]
|
||||
path to the FreeIPMI configuration file.
|
||||
Only neccessary for communication via network.
|
||||
Not neccessary for access via IPMI system interface (\"-H localhost\").
|
||||
It should contain IPMI username, IPMI password, and IPMI privilege-level,
|
||||
for example:
|
||||
username monitoring
|
||||
password yourpassword
|
||||
privilege-level user
|
||||
As alternative you can use -U/-P/-L instead (see below).
|
||||
[-U <username> -P <password> -L <privilege level>]
|
||||
IPMI username, IPMI password and IPMI privilege level, provided as
|
||||
parameters and not by a FreeIPMI configuration file. Useful for RHEL/
|
||||
Centos 5.* with FreeIPMI 0.5.1 (this elder FreeIPMI version does not
|
||||
support config files).
|
||||
Warning: with this method the password is visible in the process list.
|
||||
So whenever possible use a FreeIPMI confiugration file instead.
|
||||
[-O <FreeIPMI options>]
|
||||
additional options for FreeIPMI. Useful for RHEL/CentOS 5.* with
|
||||
FreeIPMI 0.5.1 (this elder FreeIPMI version does not support config
|
||||
files).
|
||||
[-b]
|
||||
backward compatibility mode for FreeIPMI 0.5.* (this omits the FreeIPMI
|
||||
caching options --quiet-cache and --sdr-cache-recreate)
|
||||
[-T <sensor type(s)>]
|
||||
limit sensors to query based on IPMI sensor type.
|
||||
Examples for IPMI sensor types are 'Fan', 'Temperature', 'Voltage', ...
|
||||
See the output of the FreeIPMI command 'ipmi-sensors -L' and chapter
|
||||
'42.2 Sensor Type Codes and Data' of the IPMI 2.0 spec for a full list
|
||||
of possible sensor types. You can also find the full list of possible
|
||||
sensor types at https://www.thomas-krenn.com/en/wiki/IPMI_Sensor_Types
|
||||
The available types depend on your particular server and the available
|
||||
sensors there.
|
||||
Multiple sensor types can be specified as a comma-separated list.
|
||||
[-ST <SEL sensor type(s)>]
|
||||
limit SEL entries to specific types, run 'ipmi-sel -L' for a list of
|
||||
types. All sensors are populated to the SEL and per default all sensor
|
||||
types are monitored. E.g. to limit the sensor SEL types to Memory and
|
||||
Processsor use -ST 'Memory,Processor'.
|
||||
[-x <sensor id>]
|
||||
exclude sensor matching <sensor id>. Useful for cases when unused
|
||||
sensors cannot be deleted from SDR and are reported in a non-OK state.
|
||||
Option can be specified multiple times. The <sensor id> is a numeric
|
||||
value (sensor names are not used as some servers have multiple sensors
|
||||
with the same name). Use -vvv option to query the <sensor ids>.
|
||||
[-xT <sensor type(s)>]
|
||||
exclude sensors based on IPMI sensor type.
|
||||
Multiple sensor types can be specified as a comma-separated list.
|
||||
[-xST <SEL sensor type(s)]
|
||||
exclude SEL entries of specific sensor types.
|
||||
Multiple sensor types can be specified as a comma-separated list.
|
||||
[-i <sensor id>]
|
||||
include only sensor matching <sensor id>. Useful for cases when only
|
||||
specific sensors should be monitored. Be aware that only for the
|
||||
specified sensor errors/warnings are generated. Use -vvv option to query
|
||||
the <sensor ids>.
|
||||
[-v|-vv|-vvv]
|
||||
be verbose
|
||||
(no -v) .. single line output
|
||||
-v ..... single line output with additional details for warnings
|
||||
-vv ..... multi line output, also with additional details for warnings
|
||||
-vvv ..... debugging output, followed by normal multi line output
|
||||
[-o]
|
||||
change output format. Useful for using the plugin with other monitoring
|
||||
software than Nagios or Icinga.
|
||||
-o zenoss .. create ZENOSS compatible formatted output (output with
|
||||
underscores instead of whitespaces and no single quotes)
|
||||
[-D]
|
||||
change the protocol LAN version. Normally LAN_2_0 is used as protocol
|
||||
version if not overwritten with this option. Use 'default' here if you
|
||||
don't want to use LAN_2_0.
|
||||
[-fc <num fans>]
|
||||
number of installed fans. If the number of current installed
|
||||
fans reported by IPMI is not equal than <num fans> then a Warning state
|
||||
is returned. Please use this option carefully as number of fans and
|
||||
number of fan sensors can differ!
|
||||
[--fru]
|
||||
print the product serial number if it is available in the IPMI FRU data.
|
||||
For this purpose the tool 'ipmi-fru' is used. E.g.:
|
||||
IPMI Status: OK (9000096781)
|
||||
[--nosel]
|
||||
turn off system event log checking via ipmi-sel. If there are
|
||||
unintentional entries in SEL, use 'ipmi-sel --clear' or the -sx or -xST
|
||||
option.
|
||||
[--selonly]
|
||||
check only system event log checking via ipmi-sel. If there are
|
||||
unintentional entries in SEL, use 'ipmi-sel --clear' or the -sx or -xST
|
||||
option.
|
||||
[--seltail <count>]
|
||||
limit SEL output to specified count of last messages
|
||||
[-sx|--selexclude <sel exclude file>]
|
||||
use a sel exclude file to exclude entries from the system event log.
|
||||
Specify name and type pipe delimitered in this file to exclude an entry,
|
||||
for example: System Chassis Chassis Intru|Physical Security
|
||||
To get valid names and types use the -vvv option and take a look at:
|
||||
debug output for sel (-vvv is set). Don't use name and type from the
|
||||
web interface as sensor descriptions are not complete there.
|
||||
As with the '-xx' option if the first character of a line is '~' the
|
||||
name is treated as a regular expression.
|
||||
[-xx|--sexclude <exclude file>]
|
||||
use an exclude file to exclude sensors, each line specifies an exclude.
|
||||
Specify name and type pipe delimitered in this file to exclude a sensor,
|
||||
for example: System Chassis Chassis Intru|Physical Security
|
||||
If the first character of a line is '~' the name is treated as a regular
|
||||
expression. E.g. to exclude all sensor names from CPU0 to CPU9:
|
||||
~CPU[0-9] Temp|Temperature
|
||||
To get valid names and types use the -vvv option.
|
||||
[-us|--unify-sensors <unify file>]
|
||||
use an unify file to unify sensor names. This is an easy way to rename
|
||||
sensors with given patterns in the file. Once might use this option
|
||||
to get the same sensor names accross different platforms, e.g. to only
|
||||
have 'Mainboard Temperature' as sensor name and not 'MB1 Temperature' or 'System Temp'.
|
||||
Rules in the file follow simple regex patterns e.g.:
|
||||
^(MB1 Temperature|System Temp)\$/Mainboard Temperature
|
||||
Temp\$/TEMP
|
||||
[--nosudo]
|
||||
turn off sudo usage on localhost or if ipmi host is ommited.
|
||||
[--nothresholds]
|
||||
turn off performance data thresholds from output-sensor-thresholds.
|
||||
[--noentityabsent]
|
||||
skip sensor checks for sensors that have 'noentityabsent' as event state
|
||||
[-s <ipmi-sensor output file>]
|
||||
simulation mode - test the plugin with an ipmi-sensor output redirected
|
||||
to a file.
|
||||
[-h]
|
||||
show this help
|
||||
[-V]
|
||||
show version information
|
||||
|
||||
Examples:
|
||||
\$ check_ipmi_sensor -H 192.0.2.1 -U monitor -P monitor -L user
|
||||
IPMI Status: OK | 'System Temp'=30.00 'Peripheral Temp'=32.00
|
||||
'FAN 1'=2775.00 [...]
|
||||
\$ check_ipmi_sensor -H 192.0.2.1 -U monitor -P monitor -L user -x 205
|
||||
IPMI Status: OK | 'System Temp'=30.00 'Peripheral Temp'=32.00
|
||||
'FAN 2'=2775.00 [...]
|
||||
\$ check_ipmi_sensor -H 192.0.2.1 -U monitor -P monitor -L user -i 4,71
|
||||
IPMI Status: OK | 'System Temp'=30.00 'Peripheral Temp'=32.00
|
||||
\$ check_ipmi_sensor -H 192.0.2.1 -U monitor -P monitor -L user -i 4 --fru
|
||||
IPMI Status: OK (0000012345) | 'System Temp'=30.00
|
||||
|
||||
Further information about this plugin can be found at
|
||||
http://www.thomas-krenn.com/en/wiki/IPMI_Sensor_Monitoring_Plugin
|
||||
|
||||
Use the github repo at https://github.com/thomas-krenn/check_ipmi_sensor_v3.git
|
||||
to submit patches, suggest improvements or if you have questions regarding
|
||||
use of this plugin.
|
||||
|
||||
Attention: the mailing list is no longer in use but an archive can be found at
|
||||
http://lists.thomas-krenn.com/
|
||||
EOT
|
||||
}
|
||||
|
||||
sub usage{
|
||||
my ($arg) = @_; #the list of inputs
|
||||
my ($exitcode);
|
||||
if ( defined $arg ){
|
||||
if ( $arg =~ m/^\d+$/ ){
|
||||
$exitcode = $arg;
|
||||
}
|
||||
else{
|
||||
print STDOUT $arg, "\n";
|
||||
$exitcode = 1;
|
||||
}
|
||||
}
|
||||
print STDOUT get_usage();
|
||||
exit($exitcode) if defined $exitcode;
|
||||
}
|
||||
################################################################################
|
||||
# set ipmimonitoring path
|
||||
our $MISSING_COMMAND_TEXT = '';
|
||||
our $IPMICOMMAND ="";
|
||||
if(-x "/usr/sbin/ipmimonitoring"){
|
||||
$IPMICOMMAND = "/usr/sbin/ipmimonitoring";
|
||||
}
|
||||
elsif (-x "/usr/bin/ipmimonitoring"){
|
||||
$IPMICOMMAND = "/usr/bin/ipmimonitoring";
|
||||
}
|
||||
elsif (-x "/usr/local/sbin/ipmimonitoring"){
|
||||
$IPMICOMMAND = "/usr/local/sbin/ipmimonitoring";
|
||||
}
|
||||
elsif (-x "/usr/local/bin/ipmimonitoring"){
|
||||
$IPMICOMMAND = "/usr/local/bin/ipmimonitoring";
|
||||
}
|
||||
else{
|
||||
$MISSING_COMMAND_TEXT = " ipmimonitoring/ipmi-sensors command not found!\n";
|
||||
}
|
||||
|
||||
# Identify the version of the ipmi-tool
|
||||
sub get_ipmi_version{
|
||||
my @ipmi_version_output = '';
|
||||
my $ipmi_version = '';
|
||||
@ipmi_version_output = `$IPMICOMMAND -V`;
|
||||
$ipmi_version = shift(@ipmi_version_output);
|
||||
$ipmi_version =~ /(\d+)\.(\d+)\.(\d+)/;
|
||||
@ipmi_version_output = ();
|
||||
push @ipmi_version_output,$1,$2,$3;
|
||||
return @ipmi_version_output;
|
||||
}
|
||||
|
||||
sub simulate{
|
||||
my $output = '';
|
||||
my $simul_file = $_[0];
|
||||
if( !defined $simul_file || (-x '\"'.$simul_file.'\"')){
|
||||
print "DEBUG: Using simulation file: $simul_file\n";
|
||||
print "Error: Simulation file with ipmi output not found.\n";
|
||||
exit(3);
|
||||
}
|
||||
return ($output = `cat $simul_file`);
|
||||
}
|
||||
|
||||
sub get_fru{
|
||||
my @frucmd = @{(shift)};
|
||||
my $verbosity = shift;
|
||||
my $fru;
|
||||
if(-e '/usr/sbin/ipmi-fru'){
|
||||
$fru = '/usr/sbin/ipmi-fru';
|
||||
}
|
||||
else{
|
||||
chomp($fru = `which ipmi-fru`);
|
||||
}
|
||||
#if sudo is used the command is the second element
|
||||
if($frucmd[0] eq 'sudo'){
|
||||
$frucmd[1] = $fru;
|
||||
}
|
||||
else{
|
||||
$frucmd[0] = $fru;
|
||||
}
|
||||
#skip checksum validation
|
||||
push @frucmd,'-s';
|
||||
my $fruoutput;
|
||||
my $returncode;
|
||||
run \@frucmd, '>&', \$fruoutput;
|
||||
#the upper eight bits contain the error condition (exit code)
|
||||
#see http://perldoc.perl.org/perlvar.html#Error-Variables
|
||||
$returncode = $? >> 8;
|
||||
if ( $returncode != 0 ){
|
||||
print "$fruoutput\n";
|
||||
print "-> Execution of $fru failed with return code $returncode.\n";
|
||||
print "-> $fru was executed with the following parameters:\n";
|
||||
print " ", join(' ', @frucmd), "\n";
|
||||
exit(3);
|
||||
}
|
||||
if($verbosity == 3){
|
||||
print "------------- debug output for fru (-vvv is set): ------------\n";
|
||||
print " $fru was executed with the following parameters:\n";
|
||||
print " ", join(' ', @frucmd), "\n";
|
||||
print " output of FreeIPMI:\n";
|
||||
print "$fruoutput";
|
||||
}
|
||||
return split('\n', $fruoutput);
|
||||
}
|
||||
|
||||
sub get_sel{
|
||||
my @selcmd = @{(shift)};
|
||||
my $verbosity = shift;
|
||||
my @sel_sensor_types = @{(shift)};
|
||||
my @exclude_sel_sensor_types = @{(shift)};
|
||||
my $sel;
|
||||
if(-e '/usr/sbin/ipmi-sel'){
|
||||
$sel = '/usr/sbin/ipmi-sel';
|
||||
}
|
||||
else{
|
||||
chomp($sel = `which ipmi-sel`);
|
||||
}
|
||||
#if sudo is used the command is the second element
|
||||
if($selcmd[0] eq 'sudo'){
|
||||
$selcmd[1] = $sel;
|
||||
}
|
||||
else{
|
||||
$selcmd[0] = $sel;
|
||||
}
|
||||
push @selcmd, '--output-event-state', '--interpret-oem-data', '--entity-sensor-names';
|
||||
push @selcmd, '--sensor-types=' . join(',', @sel_sensor_types);
|
||||
push @selcmd, '--exclude-sensor-types=' . join(',', @exclude_sel_sensor_types);
|
||||
my $seloutput;
|
||||
my $returncode;
|
||||
run \@selcmd, '>&', \$seloutput;
|
||||
$returncode = $? >> 8;
|
||||
if ( $returncode != 0 ){
|
||||
print "$seloutput\n";
|
||||
print "-> Execution of $sel failed with return code $returncode.\n";
|
||||
print "-> $sel was executed with the following parameters:\n";
|
||||
print " ", join(' ', @selcmd), "\n";
|
||||
exit(3);
|
||||
}
|
||||
if($verbosity == 3){
|
||||
print "------------- debug output for sel (-vvv is set): ------------\n";
|
||||
print " $sel was executed with the following parameters:\n";
|
||||
print " ", join(' ', @selcmd), "\n";
|
||||
print " output of FreeIPMI:\n";
|
||||
print "$seloutput";
|
||||
}
|
||||
return split('\n', $seloutput);
|
||||
}
|
||||
|
||||
sub parse_sel{
|
||||
my $selcmd = shift;
|
||||
my $verbosity = shift;
|
||||
my $sel_xfile = shift;
|
||||
my $sel_sensor_types = shift;
|
||||
my $exclude_sel_sensor_types = shift;
|
||||
my @seloutput = get_sel($selcmd, $verbosity, $sel_sensor_types, $exclude_sel_sensor_types);
|
||||
@seloutput = map { [ map { s/^\s*//; s/\s*$//; $_; } split(m/\|/, $_) ] } @seloutput;
|
||||
my $header = shift(@seloutput);
|
||||
|
||||
my @sel_rows;
|
||||
foreach my $row (@seloutput){
|
||||
my %curr_row;
|
||||
for(my $i = 0; $i < scalar(@{$header}); $i++){
|
||||
my $key = lc $header->[$i];
|
||||
$curr_row{$key} = $row->[$i];
|
||||
}
|
||||
if(!(exclude_with_file($sel_xfile, $curr_row{'name'}, $curr_row{'type'}))){
|
||||
push @sel_rows, \%curr_row;
|
||||
}
|
||||
}
|
||||
return \@sel_rows;
|
||||
}
|
||||
|
||||
sub get_dcmi{
|
||||
my @dcmicmd = @{(shift)};
|
||||
my $verbosity = shift;
|
||||
my $dcmi;
|
||||
if(-e '/usr/sbin/ipmi-dcmi'){
|
||||
$dcmi = '/usr/sbin/ipmi-dcmi';
|
||||
}
|
||||
else{
|
||||
chomp($dcmi = `which ipmi-dcmi`);
|
||||
}
|
||||
#if sudo is used the command is the second element
|
||||
if($dcmicmd[0] eq 'sudo'){
|
||||
$dcmicmd[1] = $dcmi;
|
||||
}
|
||||
else{
|
||||
$dcmicmd[0] = $dcmi;
|
||||
}
|
||||
push @dcmicmd, '--get-system-power-statistics';
|
||||
|
||||
my $dcmioutput;
|
||||
my $returncode;
|
||||
run \@dcmicmd, '>&', \$dcmioutput;
|
||||
$returncode = $? >> 8;
|
||||
if ( $returncode == 0 ){
|
||||
return split('\n', $dcmioutput);
|
||||
}
|
||||
}
|
||||
|
||||
sub parse_dcmi{
|
||||
my $dcmicmd = shift;
|
||||
my $verbosity = shift;
|
||||
my @dcmioutput = get_dcmi($dcmicmd, $verbosity);
|
||||
if(@dcmioutput){
|
||||
@dcmioutput = map { [ map { s/^\s*//; s/\s*$//; $_; } split(m/\:/, $_) ] } @dcmioutput;
|
||||
my %current_power;
|
||||
my $power_available = 0;
|
||||
foreach my $power (@dcmioutput){
|
||||
if(defined($power) && defined($power->[0]) && $power->[0] ne ''){
|
||||
if($power->[0] eq 'Current Power'){
|
||||
$power->[1] =~ m/^(\d+)/;
|
||||
my $watts = $1;
|
||||
$current_power{'Current Power'} = $watts;
|
||||
}
|
||||
if($power->[0] eq 'Power Measurement'){
|
||||
if($power->[1] eq 'Active'){
|
||||
$power_available = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if($power_available == 1){
|
||||
return \%current_power;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Excludes a name and type pair if it is present in the given file, pipe
|
||||
# delimitered.
|
||||
# @return 1 if name should be skipped, 0 if not
|
||||
sub exclude_with_file{
|
||||
my $file_name = shift;
|
||||
my $name = shift;
|
||||
my $type = shift;
|
||||
my @xlist;
|
||||
my $skip = 0;
|
||||
if($file_name){
|
||||
if(!(open (FH, "< $file_name"))){
|
||||
print "-> Reading exclude file $file_name failed with: $!.\n";
|
||||
exit(3);
|
||||
};
|
||||
@xlist = <FH>;
|
||||
}
|
||||
foreach my $exclude (@xlist){
|
||||
my @curr_exclude = map { s/^\s*//; s/\s*$//; $_; } split(/\|/,$exclude);
|
||||
if(@curr_exclude && $curr_exclude[0] ne '' && $curr_exclude[1] ne ''){
|
||||
#if the first char of the name in the exclude file is a '~' treat it as regex
|
||||
if(substr($curr_exclude[0], 0, 1 ) eq '~'){
|
||||
my $regex_curr_exclude = substr $curr_exclude[0], 1;
|
||||
if($name =~ m/$regex_curr_exclude/ && $curr_exclude[1] eq $type){
|
||||
$skip = 1;
|
||||
}
|
||||
}
|
||||
elsif($curr_exclude[0] eq $name && $curr_exclude[1] eq $type){
|
||||
$skip = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
close FH;
|
||||
return $skip;
|
||||
}
|
||||
|
||||
# Reads regular expressions from a file and applies the rules to sensor names.
|
||||
# This unifies sensor names across different platforms.
|
||||
# @return The sensor name with specified unify rules applied
|
||||
sub unify_with_file{
|
||||
my $file_name = shift;
|
||||
my $name = shift;# given sensor name
|
||||
my @ulist;# list of rules to apply
|
||||
if($file_name){
|
||||
if(!(open (FH, "< $file_name"))){
|
||||
print "-> Reading unify file $file_name failed with: $!.\n";
|
||||
exit(3);
|
||||
};
|
||||
@ulist = <FH>;
|
||||
}
|
||||
foreach my $unify_rule (@ulist){
|
||||
#split at the only / that is not masked with a \,
|
||||
#this is the separator in s/x/y/g to get x and y
|
||||
my @curr_rule = map { s/^\s*//; s/\s*$//; $_; } split(/(?<!\\)\//,$unify_rule);
|
||||
if(@curr_rule && $curr_rule[0] ne '' && $curr_rule[1] ne ''){
|
||||
$name =~ s/$curr_rule[0]/$curr_rule[1]/g;
|
||||
}
|
||||
}
|
||||
close FH;
|
||||
return $name;
|
||||
}
|
||||
|
||||
#define entire hashes
|
||||
our %hdrmap = (
|
||||
'Record_ID' => 'id', # FreeIPMI ...,0.7.x
|
||||
'Record ID' => 'id', # FreeIPMI 0.8.x,... with --legacy-output
|
||||
'ID' => 'id', # FreeIPMI 0.8.x
|
||||
'Sensor Name' => 'name',
|
||||
'Name' => 'name', # FreeIPMI 0.8.x
|
||||
'Sensor Group' => 'type',
|
||||
'Type' => 'type', # FreeIPMI 0.8.x
|
||||
'Monitoring Status' => 'state',
|
||||
'State' => 'state', # FreeIPMI 0.8.x
|
||||
'Sensor Units' => 'units',
|
||||
'Units' => 'units', # FreeIPMI 0.8.x
|
||||
'Sensor Reading' => 'reading',
|
||||
'Reading' => 'reading', # FreeIPMI 0.8.x
|
||||
'Event' => 'event', # FreeIPMI 0.8.x
|
||||
'Lower C' => 'lowerC',
|
||||
'Lower NC' => 'lowerNC',
|
||||
'Upper C' => 'upperC',
|
||||
'Upper NC' => 'upperNC',
|
||||
'Lower NR' => 'lowerNR',
|
||||
'Upper NR' => 'upperNR',
|
||||
);
|
||||
|
||||
our $verbosity = 0;
|
||||
|
||||
MAIN: {
|
||||
$| = 1; #force a flush after every write or print
|
||||
my @ARGV_SAVE = @ARGV;#keep args for verbose output
|
||||
my ($show_help, $show_version);
|
||||
my ($ipmi_host, $ipmi_user, $ipmi_password, $ipmi_privilege_level, $ipmi_config_file, $ipmi_outformat);
|
||||
my (@freeipmi_options, $freeipmi_compat);
|
||||
my (@ipmi_sensor_types, @ipmi_exclude_sensor_types, @ipmi_xlist, @ipmi_ilist);
|
||||
my (@ipmi_version);
|
||||
my $ipmi_sensors = 0;#states to use ipmi-sensors instead of ipmimonitoring
|
||||
my $fan_count;#number of fans that should be installed in unit
|
||||
my $lanVersion;#if desired use a different protocol version
|
||||
my $abort_text = '';
|
||||
my $zenoss = 0;
|
||||
my @sel_sensor_types;
|
||||
my @exclude_sel_sensor_types;
|
||||
my $sel_issues_present = 0;
|
||||
my $simulate = '';
|
||||
my ($use_fru, $no_sel, $sel_only, $sel_tail, $no_sudo, $use_thresholds, $no_thresholds, $sel_xfile, $s_xfile, $s_ufile, $no_entity_absent);
|
||||
|
||||
#read in command line arguments and init hash variables with the given values from argv
|
||||
if ( !( GetOptions(
|
||||
'H|host=s' => \$ipmi_host,
|
||||
'f|config-file=s' => \$ipmi_config_file,
|
||||
'U|user=s' => \$ipmi_user,
|
||||
'P|password=s' => \$ipmi_password,
|
||||
'L|privilege-level=s' => \$ipmi_privilege_level,
|
||||
'O|options=s' => \@freeipmi_options,
|
||||
'b|compat' => \$freeipmi_compat,
|
||||
'T|sensor-types=s' => \@ipmi_sensor_types,
|
||||
'xT|exclude-sensor-types=s' => \@ipmi_exclude_sensor_types,
|
||||
'ST|sel-sensor-types=s' => \@sel_sensor_types,
|
||||
'xST|exclude-sel-sensor-types=s' => \@exclude_sel_sensor_types,
|
||||
'fru' => \$use_fru,
|
||||
'nosel' => \$no_sel,
|
||||
'selonly' => \$sel_only,
|
||||
'seltail=s' => \$sel_tail,
|
||||
'nosudo' => \$no_sudo,
|
||||
'nothresholds' => \$no_thresholds,
|
||||
'noentityabsent' => \$no_entity_absent,
|
||||
'v|verbosity' => \$verbosity,
|
||||
'vv' => sub{$verbosity=2},
|
||||
'vvv' => sub{$verbosity=3},
|
||||
'x|exclude=s' => \@ipmi_xlist,
|
||||
'sx|selexclude=s' => \$sel_xfile,
|
||||
'xx|sexclude=s' => \$s_xfile,
|
||||
'us|unify-sensors=s'=> \$s_ufile,
|
||||
'i|include=s' => \@ipmi_ilist,
|
||||
'o|outformat=s' => \$ipmi_outformat,
|
||||
'fc|fancount=i' => \$fan_count,
|
||||
'D=s' => \$lanVersion,
|
||||
's=s' => \$simulate,
|
||||
'h|help' =>
|
||||
sub{print STDOUT get_version();
|
||||
print STDOUT "\n";
|
||||
print STDOUT get_usage();
|
||||
print STDOUT "\n";
|
||||
print STDOUT get_help();
|
||||
exit(0)
|
||||
},
|
||||
'V|version' =>
|
||||
sub{
|
||||
print STDOUT get_version();
|
||||
exit(0);
|
||||
},
|
||||
'usage|?' =>
|
||||
sub{print STDOUT get_usage();
|
||||
exit(3);
|
||||
}
|
||||
) ) ){
|
||||
usage(1);#call usage if GetOptions failed
|
||||
}
|
||||
usage(1) if @ARGV;#print usage if unknown arg list is left
|
||||
|
||||
################################################################################
|
||||
# check for ipmimonitoring or ipmi-sensors. Since version > 0.8 ipmi-sensors is used
|
||||
# if '--legacy-output' is given ipmi-sensors cannot be used
|
||||
if( $MISSING_COMMAND_TEXT ne "" ){
|
||||
print STDOUT "Error:$MISSING_COMMAND_TEXT";
|
||||
exit(3);
|
||||
}
|
||||
else{
|
||||
@ipmi_version = get_ipmi_version();
|
||||
if( $ipmi_version[0] > 0 && (grep(/legacy\-output/,@freeipmi_options)) == 0){
|
||||
$IPMICOMMAND =~ s/ipmimonitoring/ipmi-sensors/;
|
||||
$ipmi_sensors = 1;
|
||||
}
|
||||
if( $ipmi_version[0] > 0 && (grep(/legacy\-output/,@freeipmi_options)) == 1){
|
||||
print "Error: Cannot use ipmi-sensors with option \'--legacy-output\'. Remove it to work correctly.\n";
|
||||
exit(3);
|
||||
}
|
||||
# check if output-sensor-thresholds can be used, this is supported
|
||||
# since 1.2.1. Version 1.2.0 was not released, so skip the third minor
|
||||
# version number
|
||||
if($ipmi_version[0] > 1 || ($ipmi_version[0] == 1 && $ipmi_version[1] >= 2)){
|
||||
$use_thresholds = 1;
|
||||
}
|
||||
else{
|
||||
$use_thresholds = 0;
|
||||
}
|
||||
}
|
||||
###############################################################################
|
||||
# verify if all mandatory parameters are set and initialize various variables
|
||||
#\s defines any whitespace characters
|
||||
#first join the list, then split it at whitespace ' '
|
||||
#also cf. http://perldoc.perl.org/Getopt/Long.html#Options-with-multiple-values
|
||||
@freeipmi_options = split(/\s+/, join(' ', @freeipmi_options)); # a bit hack, shell word splitting should be implemented...
|
||||
@ipmi_sensor_types = split(/,/, join(',', @ipmi_sensor_types));
|
||||
@ipmi_exclude_sensor_types = split(/,/, join(',', @ipmi_exclude_sensor_types));
|
||||
@sel_sensor_types = split(/,/, join(',', @sel_sensor_types));
|
||||
@exclude_sel_sensor_types = split(/,/, join(',', @exclude_sel_sensor_types));
|
||||
@ipmi_xlist = split(/,/, join(',', @ipmi_xlist));
|
||||
@ipmi_ilist = split(/,/, join(',', @ipmi_ilist));
|
||||
|
||||
#check for zenoss output
|
||||
if(defined $ipmi_outformat && $ipmi_outformat eq "zenoss"){
|
||||
$zenoss = 1;
|
||||
}
|
||||
|
||||
# Per default monitor all sensor types, use -ST to specify your sensor types
|
||||
if(!@sel_sensor_types){
|
||||
@sel_sensor_types = ('all');
|
||||
}
|
||||
# If -xST has not been set, set this array to empty.
|
||||
if(!@exclude_sel_sensor_types){
|
||||
@exclude_sel_sensor_types = ('');
|
||||
}
|
||||
|
||||
# Define basic ipmi command
|
||||
my @basecmd = $IPMICOMMAND;
|
||||
# If host is omitted localhost is assumed, if not turned off sudo is used
|
||||
if(!(defined $ipmi_host) || ($ipmi_host eq 'localhost')){
|
||||
if(!defined($no_sudo)){
|
||||
# Only add sudo if not already root
|
||||
@basecmd = ($> != 0 ? 'sudo' : (), $IPMICOMMAND);
|
||||
}
|
||||
}
|
||||
# If we are not local, we need authentication credentials
|
||||
else{
|
||||
# Add the ipmi desired host
|
||||
push @basecmd, '-h', $ipmi_host;
|
||||
if(defined $ipmi_config_file){
|
||||
push @basecmd, '--config-file', $ipmi_config_file;
|
||||
}
|
||||
elsif(defined $ipmi_user && defined $ipmi_password && defined $ipmi_privilege_level ){
|
||||
push @basecmd, '-u', $ipmi_user, '-p', $ipmi_password, '-l', $ipmi_privilege_level;
|
||||
}
|
||||
else{
|
||||
$abort_text = $abort_text . " -f <FreeIPMI config file> or -U <username> -P <password> -L <privilege level>";
|
||||
}
|
||||
if( $abort_text ne ""){
|
||||
print STDOUT "Error: " . $abort_text . " missing.";
|
||||
print STDOUT get_usage();
|
||||
exit(3);
|
||||
}
|
||||
}
|
||||
# copy command for fru usage
|
||||
my @frucmd;
|
||||
if($use_fru){
|
||||
@frucmd = @basecmd
|
||||
}
|
||||
my @selcmd = @basecmd;
|
||||
my @dcmicmd = @basecmd;
|
||||
|
||||
if(@ipmi_sensor_types){
|
||||
# , is the seperator in the new string
|
||||
# -g option is older name for ipmi-sensors -t or --sensor-types and
|
||||
# compatible with both older and newer version of FreeIPMI
|
||||
push @basecmd, '-g', join(',', @ipmi_sensor_types);
|
||||
}
|
||||
|
||||
# add sensor types to exclude
|
||||
if(@ipmi_exclude_sensor_types){
|
||||
push @basecmd, '--exclude-sensor-types', join(',', @ipmi_exclude_sensor_types);
|
||||
}
|
||||
|
||||
|
||||
if(@freeipmi_options){
|
||||
push @basecmd, @freeipmi_options;
|
||||
}
|
||||
|
||||
#keep original basecmd for later usage
|
||||
my @getstatus = @basecmd;
|
||||
|
||||
#if -b is not defined, caching options are used
|
||||
if( !(defined $freeipmi_compat) ){
|
||||
push @getstatus, '--quiet-cache', '--sdr-cache-recreate';
|
||||
}
|
||||
#since version 0.8 it is possible to interpret OEM data
|
||||
if( ($ipmi_version[0] == 0 && $ipmi_version[1] > 7) ||
|
||||
$ipmi_version[0] > 0){
|
||||
push @getstatus, '--interpret-oem-data';
|
||||
}
|
||||
#since version 0.8 it is necessary to add the legacy option
|
||||
if( ($ipmi_version[0] == 0 && $ipmi_version[1] > 7) && (grep(/legacy\-output/,@freeipmi_options) == 0)){
|
||||
push @getstatus, '--legacy-output';
|
||||
}
|
||||
#if ipmi-sensors is used show the state of sensors and ignore N/A
|
||||
if($ipmi_sensors){
|
||||
push @getstatus, '--output-sensor-state', '--ignore-not-available-sensors';
|
||||
}
|
||||
#if not stated otherwise we use protocol lan version 2 per default
|
||||
if(!defined($lanVersion)){
|
||||
$lanVersion = 'LAN_2_0';
|
||||
}
|
||||
if($lanVersion ne 'default' && defined $ipmi_host && $ipmi_host ne 'localhost'){
|
||||
push @getstatus, "--driver-type=$lanVersion";
|
||||
if(!$no_sel){
|
||||
push @selcmd, "--driver-type=$lanVersion";
|
||||
}
|
||||
if($use_fru){
|
||||
push @frucmd, "--driver-type=$lanVersion";
|
||||
}
|
||||
}
|
||||
if($use_thresholds && !$no_thresholds){
|
||||
push @getstatus, '--output-sensor-thresholds';
|
||||
}
|
||||
if(defined($sel_tail)){
|
||||
push @selcmd, "--tail=$sel_tail";
|
||||
}
|
||||
|
||||
################################################################################
|
||||
#execute status command and redirect stdout and stderr to ipmioutput
|
||||
my $ipmioutput;
|
||||
my $returncode;
|
||||
if ($sel_only){
|
||||
$returncode = 0;
|
||||
}
|
||||
elsif(!$simulate){
|
||||
run \@getstatus, '>&', \$ipmioutput;
|
||||
#the upper eight bits contain the error condition (exit code)
|
||||
#see http://perldoc.perl.org/perlvar.html#Error-Variables
|
||||
$returncode = $? >> 8;
|
||||
}
|
||||
else{
|
||||
$ipmioutput = simulate($simulate);
|
||||
print "DEBUG: Using simulation mode\n";
|
||||
$returncode = 0;
|
||||
}
|
||||
my @fruoutput;
|
||||
if($use_fru){
|
||||
@fruoutput = get_fru(\@frucmd, $verbosity);
|
||||
}
|
||||
my $seloutput;
|
||||
if(!$no_sel){
|
||||
$seloutput = parse_sel(\@selcmd, $verbosity, $sel_xfile, \@sel_sensor_types, \@exclude_sel_sensor_types);
|
||||
}
|
||||
my $dcmioutput;
|
||||
$dcmioutput = parse_dcmi(\@dcmicmd, $verbosity);
|
||||
################################################################################
|
||||
# print debug output when verbosity is set to 3 (-vvv)
|
||||
if ( $verbosity == 3 && !$sel_only ){
|
||||
my $ipmicommandversion;
|
||||
run [$IPMICOMMAND, '-V'], '2>&1', '|', ['head', '-n', 1], '&>', \$ipmicommandversion;
|
||||
#remove trailing newline with chomp
|
||||
chomp $ipmicommandversion;
|
||||
print "------------- debug output for sensors (-vvv is set): ------------\n";
|
||||
print " script was executed with the following parameters:\n";
|
||||
print " $0 ", join(' ', @ARGV_SAVE), "\n";
|
||||
print " check_ipmi_sensor version:\n";
|
||||
print " $check_ipmi_sensor_version\n";
|
||||
print " FreeIPMI version:\n";
|
||||
print " $ipmicommandversion\n";
|
||||
print " FreeIPMI was executed with the following parameters:\n";
|
||||
print " ", join(' ', @getstatus), "\n";
|
||||
print " FreeIPMI return code: $returncode\n";
|
||||
print " output of FreeIPMI:\n";
|
||||
print "$ipmioutput\n";
|
||||
print "--------------------- end of debug output ---------------------\n";
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# generate main output
|
||||
if ( $returncode != 0 ){
|
||||
print "$ipmioutput\n";
|
||||
print "-> Execution of $IPMICOMMAND failed with return code $returncode.\n";
|
||||
print "-> $IPMICOMMAND was executed with the following parameters:\n";
|
||||
print " ", join(' ', @getstatus), "\n";
|
||||
exit(3);
|
||||
}
|
||||
else{
|
||||
my @outputRows;
|
||||
if(defined($ipmioutput)){
|
||||
@outputRows = split('\n', $ipmioutput);
|
||||
}
|
||||
if(!$sel_only && (!defined($ipmioutput) || scalar(@outputRows) == 1)){
|
||||
print "-> Your server seems to be powered off.";
|
||||
print " (Execution of FreeIPMI returned an empty output or only 1 header row!)\n";
|
||||
print "-> $IPMICOMMAND was executed with the following parameters:\n";
|
||||
print " ", join(' ', @getstatus), "\n";
|
||||
exit(3);
|
||||
}
|
||||
#print desired filter types
|
||||
if ( @ipmi_sensor_types ){
|
||||
print "Sensor Type(s) ", join(', ', @ipmi_sensor_types), " Status: ";
|
||||
}
|
||||
elsif ($sel_only){
|
||||
print "SEL Status: ";
|
||||
}
|
||||
else{
|
||||
print "IPMI Status: ";
|
||||
}
|
||||
#start with main output
|
||||
my $exit = 0;
|
||||
my $w_sensors = '';#sensors with warnings
|
||||
my $sel_w_sensors = '';#verbose output for sel entries with warnings
|
||||
my $perf = '';#performance sensor
|
||||
my $curr_fans = 0;
|
||||
my @ipmioutput2;#filtered original ipmi output
|
||||
|
||||
#skip ipmi output, if only SEL queried
|
||||
if (!$sel_only){
|
||||
#split at newlines, fetch array with lines of output
|
||||
my @ipmioutput = split('\n', $ipmioutput);
|
||||
|
||||
#remove sudo errors and warnings like they appear on dns resolving issues
|
||||
@ipmioutput = map { /^sudo:/ ? () : $_ } @ipmioutput;
|
||||
|
||||
#remove leading and trailing whitespace characters, split at the pipe delimiter
|
||||
@ipmioutput = map { [ map { s/^\s*//; s/\s*$//; $_; } split(m/\|/, $_) ] } @ipmioutput;
|
||||
|
||||
#shift out the header as it is the first line
|
||||
my $header = shift @ipmioutput;
|
||||
if(!defined($header)){
|
||||
print "$ipmioutput\n";
|
||||
print " FreeIPMI returned an empty header map (first line)";
|
||||
if(@ipmi_sensor_types){
|
||||
print " FreeIPMI could not find any sensors for the given sensor type (option '-T').\n";
|
||||
}
|
||||
exit(3);
|
||||
}
|
||||
my %header;
|
||||
for(my $i = 0; $i < @$header; $i++)
|
||||
{
|
||||
#assigning %header with (key from hdrmap) => $i
|
||||
#checking at which position in the header is which key
|
||||
$header{$hdrmap{$header->[$i]}} = $i;
|
||||
}
|
||||
foreach my $row ( @ipmioutput ){
|
||||
my %row;
|
||||
#fetch keys from header and assign existent values to row
|
||||
#this maps the values from row(ipmioutput) to the header values
|
||||
while ( my ($key, $index) = each %header ){
|
||||
#check if the option to unify sensor names is active
|
||||
if($key eq 'name' && $s_ufile && $s_ufile ne ''){
|
||||
$row{$key} = unify_with_file($s_ufile, $row->[$index]);
|
||||
}
|
||||
else{
|
||||
$row{$key} = $row->[$index];
|
||||
}
|
||||
}
|
||||
if(!(exclude_with_file($s_xfile, $row{'name'}, $row{'type'}))){
|
||||
push @ipmioutput2, \%row;
|
||||
}
|
||||
}
|
||||
#create hash with sensor name an 1
|
||||
my %ipmi_xlist = map { ($_, 1) } @ipmi_xlist;
|
||||
#filter out the desired sensor values
|
||||
@ipmioutput2 = grep(!exists $ipmi_xlist{$_->{'id'}}, @ipmioutput2);
|
||||
#check for an include list
|
||||
if(@ipmi_ilist){
|
||||
my %ipmi_ilist = map { ($_, 1) } @ipmi_ilist;
|
||||
#only include sensors from include list
|
||||
@ipmioutput2 = grep(exists $ipmi_ilist{$_->{'id'}}, @ipmioutput2);
|
||||
}
|
||||
foreach my $row ( @ipmioutput2 ){
|
||||
if( $zenoss ){
|
||||
$row->{'name'} =~ s/ /_/g;
|
||||
}
|
||||
my $check_sensor_state = 1;
|
||||
if($no_entity_absent){
|
||||
if(exists $row->{'event'} && ($row->{'event'} =~ /\'.*((Device|Entity) (Absent|Removed)).*\'/)){
|
||||
$check_sensor_state = 0;
|
||||
}
|
||||
if(exists $row->{'reading'} && ($row->{'reading'} =~ /\'.*((Device|Entity) (Absent|Removed)).*\'/)){
|
||||
$check_sensor_state = 0;
|
||||
}
|
||||
}
|
||||
#check for warning sensors
|
||||
if($check_sensor_state && ($row->{'state'} ne 'Nominal' && $row->{'state'} ne 'N/A')){
|
||||
$exit = 1 if $exit < 1;
|
||||
$exit = 2 if $exit < 2 && $row->{'state'} ne 'Warning';
|
||||
#don't insert a , the first time
|
||||
$w_sensors .= ", " unless $w_sensors eq '';
|
||||
$w_sensors .= "$row->{'name'} = $row->{'state'}";
|
||||
if( $verbosity ){
|
||||
if( $row->{'reading'} ne 'N/A'){
|
||||
$w_sensors .= " ($row->{'reading'})" ;
|
||||
}
|
||||
else{
|
||||
$w_sensors .= " ($row->{'event'})";
|
||||
}
|
||||
}
|
||||
}
|
||||
if($check_sensor_state && ($row->{'units'} ne 'N/A')){
|
||||
my $val = $row->{'reading'};
|
||||
my $perf_data;
|
||||
my $perf_thresholds;
|
||||
if($zenoss){
|
||||
$perf_data = $row->{'name'}."=".$val;
|
||||
}
|
||||
else{
|
||||
$perf_data = "'".$row->{'name'}."'=".$val;
|
||||
}
|
||||
if($use_thresholds && !$no_thresholds){
|
||||
if(($row->{'lowerNC'} ne 'N/A') && ($row->{'upperNC'} ne 'N/A')){
|
||||
$perf_thresholds = $row->{'lowerNC'}.":".$row->{'upperNC'}.";";
|
||||
}
|
||||
elsif(($row->{'lowerNC'} ne 'N/A') && ($row->{'upperNC'} eq 'N/A')){
|
||||
$perf_thresholds = $row->{'lowerNC'}.":;";
|
||||
}
|
||||
elsif(($row->{'lowerNC'} eq 'N/A') && ($row->{'upperNC'} ne 'N/A')){
|
||||
$perf_thresholds = "~:".$row->{'upperNC'}.";";
|
||||
}
|
||||
elsif(($row->{'lowerNC'} eq 'N/A') && ($row->{'upperNC'} eq 'N/A')){
|
||||
$perf_thresholds = ";";
|
||||
}
|
||||
if(($row->{'lowerC'} ne 'N/A') && ($row->{'upperC'} ne 'N/A')){
|
||||
$perf_thresholds .= $row->{'lowerC'}.":".$row->{'upperC'};
|
||||
}
|
||||
elsif(($row->{'lowerC'} ne 'N/A') && ($row->{'upperC'} eq 'N/A')){
|
||||
$perf_thresholds .= $row->{'lowerC'}.":";
|
||||
}
|
||||
elsif(($row->{'lowerC'} eq 'N/A') && ($row->{'upperC'} ne 'N/A')){
|
||||
$perf_thresholds .= "~:".$row->{'upperC'};
|
||||
}
|
||||
# Add thresholds to performance data
|
||||
if(($row->{'lowerNC'} ne 'N/A') || ($row->{'upperNC'} ne 'N/A') ||
|
||||
($row->{'lowerC'} ne 'N/A') || ($row->{'upperC'} ne 'N/A')){
|
||||
$perf_data .= ";".$perf_thresholds;
|
||||
}
|
||||
}
|
||||
$perf .= $perf_data." ";
|
||||
}
|
||||
if( $row->{'type'} eq 'Fan' && $row->{'reading'} ne 'N/A' ){
|
||||
$curr_fans++;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach my $row (@{$seloutput}){
|
||||
if( $zenoss ){
|
||||
$row->{'name'} =~ s/ /_/g;
|
||||
}
|
||||
if ($row->{'state'} ne 'Nominal'){
|
||||
$sel_issues_present += 1;
|
||||
$exit = 1 if $exit < 1;
|
||||
$exit = 2 if $exit < 2 && $row->{'state'} ne 'Warning';
|
||||
if( $verbosity ){
|
||||
$sel_w_sensors .= ", " unless $sel_w_sensors eq '';
|
||||
$sel_w_sensors .= "($row->{'name'} = $row->{'state'},";
|
||||
$sel_w_sensors .= " $row->{'type'}," ;
|
||||
$sel_w_sensors .= " $row->{'event'})" ;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( $sel_issues_present ){
|
||||
$w_sensors .= ", " unless $w_sensors eq '';
|
||||
if ( $sel_issues_present == 1 ){
|
||||
$w_sensors .= "1 system event log (SEL) entry present";
|
||||
}else{
|
||||
$w_sensors .= $sel_issues_present." system event log (SEL) entries present";
|
||||
}
|
||||
if( $verbosity ){
|
||||
$w_sensors .= " - details: ";
|
||||
$w_sensors .= $sel_w_sensors;
|
||||
$w_sensors .= " - fix the reported issues and clear your SEL";
|
||||
$w_sensors .= " or exclude specific SEL entries using the -sx or -xST option";
|
||||
}
|
||||
}
|
||||
#now check if num fans equals desired unit fans
|
||||
if( $fan_count ){
|
||||
if( $curr_fans < $fan_count ){
|
||||
$exit = 1 if $exit < 1;
|
||||
$w_sensors .= ", " unless $w_sensors eq '';
|
||||
$w_sensors .= "Fan = Warning";
|
||||
if( $verbosity ){
|
||||
$w_sensors .= " ($curr_fans)" ;
|
||||
}
|
||||
}
|
||||
}
|
||||
#check for the FRU serial number
|
||||
my @server_serial;
|
||||
my $serial_number;
|
||||
if( $use_fru ){
|
||||
@server_serial = grep(/Product Serial Number/,@fruoutput);
|
||||
if(@server_serial){
|
||||
$server_serial[0] =~ m/(\d+)/;
|
||||
$serial_number = $1;
|
||||
}
|
||||
}
|
||||
if(defined($dcmioutput) && $dcmioutput ne ''){
|
||||
my $power_perf = '';
|
||||
if(exists $dcmioutput->{'Current Power'}){
|
||||
my $power_key = 'Current Power';
|
||||
if($s_ufile && $s_ufile ne ''){
|
||||
$power_key = unify_with_file($s_ufile, $power_key);
|
||||
}
|
||||
if( $zenoss ){
|
||||
$power_key =~ s/ /_/g;
|
||||
}
|
||||
$power_perf = "\'$power_key\'=" . $dcmioutput->{'Current Power'};
|
||||
}
|
||||
$perf = $power_perf . ' ' . $perf;
|
||||
}
|
||||
$perf = substr($perf, 0, -1);#cut off the last chars
|
||||
if ( $exit == 0 ){
|
||||
print "OK";
|
||||
}
|
||||
elsif ( $exit == 1 ){
|
||||
print "Warning [$w_sensors]";
|
||||
}
|
||||
else{
|
||||
print "Critical [$w_sensors]";
|
||||
}
|
||||
if( $use_fru && defined($serial_number)){
|
||||
print " ($serial_number)";
|
||||
}
|
||||
print " | ", $perf if $perf ne '';
|
||||
print "\n";
|
||||
|
||||
if ( $verbosity > 1 ){
|
||||
foreach my $row (@ipmioutput2){
|
||||
if( $row->{'state'} eq 'N/A'){
|
||||
next;
|
||||
}
|
||||
elsif( $row->{'reading'} ne 'N/A'){
|
||||
print "$row->{'name'} = $row->{'reading'} ";
|
||||
}
|
||||
elsif( $row->{'event'} ne 'N/A'){
|
||||
print "$row->{'name'} = $row->{'event'} ";
|
||||
}
|
||||
else{
|
||||
next;
|
||||
}
|
||||
print "(Status: $row->{'state'})\n";
|
||||
}
|
||||
}
|
||||
exit $exit;
|
||||
}
|
||||
};
|
|
@ -2,19 +2,19 @@
|
|||
IPSECCTL="/sbin/ipsecctl -s sa"
|
||||
STATUS=0
|
||||
|
||||
LINE1=`$IPSECCTL | grep "from $1 to $2" `
|
||||
$IPSECCTL | grep -q "from $1 to $2"
|
||||
if [ $? -eq 1 ]; then
|
||||
STATUS=2;
|
||||
OUTPUT1="No VPN from $1 to $2 "
|
||||
fi
|
||||
|
||||
LINE2=`$IPSECCTL | grep "from $2 to $1" `
|
||||
$IPSECCTL | grep -q "from $2 to $1"
|
||||
if [ $? -eq 1 ]; then
|
||||
STATUS=2;
|
||||
OUTPUT2="No VPN from $2 to $1"
|
||||
fi
|
||||
|
||||
if [ $STATUS -eq 0 ]; then
|
||||
if [ "$STATUS" -eq 0 ]; then
|
||||
echo "VPN OK - $3 is up"
|
||||
exit $STATUS
|
||||
else
|
||||
|
|
|
@ -12,7 +12,7 @@ STATUS=0
|
|||
VPN_KO=""
|
||||
|
||||
default_int=$(route -n show -inet | grep default | awk '{ print $8 }' | grep -v pppoe0)
|
||||
default_ip=$(ifconfig $default_int | grep inet | head -1 | awk '{ print $2 }')
|
||||
default_ip=$(ifconfig "$default_int" | grep inet | head -1 | awk '{ print $2 }')
|
||||
|
||||
# No check if CARP backup
|
||||
|
||||
|
@ -32,7 +32,7 @@ fi
|
|||
|
||||
# Make sure "0.0.0.0" is not configured
|
||||
|
||||
if /sbin/ipsecctl -sa | grep -qF 0.0.0.0; then
|
||||
if /sbin/ipsecctl -sa | grep -qF " 0.0.0.0"; then
|
||||
echo "CRITICAL : Configuration error on client side, \"0.0.0.0\" is configured and makes the network to bug. Check with \"ipsecctl -sa | grep -F 0.0.0.0\" which VPN is affected and shut it down, and contact the client or the VPN provider to solve the problem."
|
||||
STATUS=2
|
||||
fi
|
||||
|
@ -40,11 +40,10 @@ fi
|
|||
# Check with "ipsecctl -sa"
|
||||
|
||||
for vpn in $(cat /etc/ipsec.conf | grep -v "^#" | awk '{print $2}'); do
|
||||
vpn=$(basename $vpn .conf\")
|
||||
vpn=$(basename "$vpn" .conf\")
|
||||
local_ip=$default_ip
|
||||
remote_ip=$(grep -E "remote_ip" /etc/ipsec/${vpn}.conf | grep -v "^#" | grep -o "[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*")
|
||||
$CHECK_IPSECCTL $local_ip $remote_ip "$vpn" > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
remote_ip=$(grep -E "remote_ip" /etc/ipsec/"${vpn}".conf | grep -v "^#" | grep -o "[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*")
|
||||
if ! "$CHECK_IPSECCTL" "$local_ip" "$remote_ip" "$vpn" > /dev/null; then
|
||||
STATUS=2
|
||||
VPN_KO="$VPN_KO $vpn"
|
||||
fi
|
||||
|
@ -57,25 +56,41 @@ if [ $STATUS -eq 0 ]; then
|
|||
# Definition of VPNs to be checked
|
||||
VPNS="A_from_vlan1 A_from_vlan2 B_from_vlan1 C_from_vlan2"
|
||||
|
||||
# Definition of destination IPs (client side) to ping for each VPN
|
||||
A_from_vlan1_IP="192.168.1.1"
|
||||
A_from_vlan2_IP="192.168.2.1"
|
||||
# Definition of destination IPs (client side) to ping for each VPN ; multiples IPs can be given, the check will be OK if at least one IP is answering for each VPN
|
||||
A_from_vlan1_IP="192.168.1.1 192.168.1.50 192.168.1.254"
|
||||
A_from_vlan2_IP="192.168.2.1 192.168.2.10"
|
||||
|
||||
B_from_vlan1_IP="172.16.1.1"
|
||||
|
||||
C_from_vlan2_IP="10.0.1.1"
|
||||
C_from_vlan2_IP="10.0.1.1 10.0.1.5"
|
||||
|
||||
for vpn in $VPNS; do
|
||||
# dst_ip takes the value of VPNS_IP
|
||||
eval dst_ip=\$${vpn}_IP
|
||||
eval dst_ip=\$"${vpn}"_IP
|
||||
pingok=0
|
||||
|
||||
# Definition of the source IP of the ping according to the source network used (our side, adjust the -I option)
|
||||
case $vpn in
|
||||
*vlan1*) ping -q -i 0.1 -I 192.168.5.5 -c 3 -w 1 $dst_ip >/dev/null ;;
|
||||
*vlan2*) ping -q -i 0.1 -I 172.16.2.5 -c 3 -w 1 $dst_ip >/dev/null ;;
|
||||
*vlan1*)
|
||||
for i in $dst_ip; do
|
||||
ping -q -i 0.1 -I 192.168.5.5 -c 3 -w 1 "$dst_ip" >/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
pingok=$(($pingok + 1))
|
||||
fi
|
||||
done
|
||||
;;
|
||||
|
||||
*vlan2*)
|
||||
for i in $dst_ip; do
|
||||
ping -q -i 0.1 -I 172.16.2.5 -c 3 -w 1 "$dst_ip" >/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
pingok=$(($pingok + 1))
|
||||
fi
|
||||
done
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
if [ "$pingok" -eq 0 ]; then
|
||||
VPN_KO="$VPN_KO $vpn"
|
||||
fi
|
||||
done
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
carp=$(/sbin/ifconfig carp0 | /usr/bin/grep 'status' |cut -d' ' -f2)
|
||||
|
||||
if [ $carp = 'backup' ]; then
|
||||
if [ "$carp" = 'backup' ]; then
|
||||
echo "No check, I'm a backup"
|
||||
return 0
|
||||
else
|
||||
|
|
|
@ -10,10 +10,10 @@ _CRTICAL_STATES_LIMIT=$((_MAX_STATES_LIMIT*65/100))
|
|||
|
||||
_CHECK_STATES=$(/sbin/pfctl -si | /usr/bin/grep current | awk '{print $3}')
|
||||
|
||||
if [ $_CHECK_STATES -lt $_WARNING_STATES_LIMIT ];then
|
||||
if [ "$_CHECK_STATES" -lt "$_WARNING_STATES_LIMIT" ];then
|
||||
echo "OK: States number ($_CHECK_STATES) is below threshold (warn : $_WARNING_STATES_LIMIT / crit : $_CRTICAL_STATES_LIMIT / max : $_MAX_STATES_LIMIT)"
|
||||
exit "$STATE_OK"
|
||||
elif [ $_CHECK_STATES -ge $_WARNING_STATES_LIMIT ] && [ $_CHECK_STATES -lt $_CRTICAL_STATES_LIMIT ];then
|
||||
elif [ "$_CHECK_STATES" -ge "$_WARNING_STATES_LIMIT" ] && [ "$_CHECK_STATES" -lt "$_CRTICAL_STATES_LIMIT" ];then
|
||||
echo "WARNING: States number is $_CHECK_STATES (threshold WARNING = $_WARNING_STATES_LIMIT, max = $_MAX_STATES_LIMIT)"
|
||||
exit "$STATE_WARNING"
|
||||
else
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
---
|
||||
- name: restart nrpe
|
||||
service:
|
||||
ansible.builtin.service:
|
||||
name: nrpe
|
||||
state: restarted
|
||||
when: nrpe_exists.stat.exists
|
||||
|
|
|
@ -1,46 +1,81 @@
|
|||
# yamllint disable rule:line-length
|
||||
---
|
||||
- name: Install nrpe
|
||||
openbsd_pkg:
|
||||
name:
|
||||
- nrpe--
|
||||
state: present
|
||||
# openbsd_pkg is broken since OpenBSD 7.4 with the version of Ansible we currently use
|
||||
#- name: "Install nrpe"
|
||||
# community.general.openbsd_pkg:
|
||||
# name:
|
||||
# - nrpe--
|
||||
# state: present
|
||||
# tags:
|
||||
# - nagios-nrpe
|
||||
#
|
||||
#- name: "Install monitoring packages"
|
||||
# community.general.openbsd_pkg:
|
||||
# name:
|
||||
# - monitoring-plugins
|
||||
# - check_bioctl
|
||||
# state: present
|
||||
# tags:
|
||||
# - nagios-nrpe
|
||||
|
||||
- name: Install monitoring packages
|
||||
openbsd_pkg:
|
||||
name:
|
||||
- monitoring-plugins
|
||||
- check_bioctl
|
||||
state: present
|
||||
- name: "Install nrpe and monitoring packages"
|
||||
include: openbsd_pkg_custom.yml
|
||||
vars:
|
||||
package: "{{ item }}"
|
||||
loop:
|
||||
- nrpe--
|
||||
- monitoring-plugins
|
||||
- check_bioctl
|
||||
tags:
|
||||
- nagios-nrpe
|
||||
|
||||
- name: Create nrpe.d dir
|
||||
file:
|
||||
- name: "Create nrpe.d dir"
|
||||
ansible.builtin.file:
|
||||
path: /etc/nrpe.d
|
||||
state: directory
|
||||
owner: root
|
||||
group: wheel
|
||||
mode: "0755"
|
||||
tags:
|
||||
- nagios-nrpe
|
||||
|
||||
- name: Include nrpe.d dir in nrpe.cfg
|
||||
lineinfile:
|
||||
- name: "Include nrpe.d dir in nrpe.cfg"
|
||||
ansible.builtin.lineinfile:
|
||||
dest: /etc/nrpe.cfg
|
||||
line: 'include_dir=/etc/nrpe.d'
|
||||
create: true
|
||||
tags:
|
||||
- nagios-nrpe
|
||||
|
||||
- name: custom configuration is present
|
||||
template:
|
||||
src: evolix_bsd.cfg.j2
|
||||
dest: /etc/nrpe.d/evolix.cfg
|
||||
- name: "Check if nrpe service exists, for usage in check_mode"
|
||||
stat:
|
||||
path: /etc/rc.d/nrpe
|
||||
register: nrpe_exists
|
||||
|
||||
- name: "Custom configuration is present"
|
||||
ansible.builtin.blockinfile:
|
||||
block: "{{ lookup('template', 'evolix_bsd.cfg.j2') }}"
|
||||
path: /etc/nrpe.d/evolix.cfg
|
||||
marker: "## {mark} ANSIBLE MANAGED BLOCK : Custom NRPE configuration file from EvoBSD"
|
||||
create: true
|
||||
mode: "0644"
|
||||
insertbefore: BOF
|
||||
notify: restart nrpe
|
||||
tags:
|
||||
- nagios-nrpe
|
||||
|
||||
- name: Create nrpe plugins dir
|
||||
file:
|
||||
- name: "Create nrpe plugins dir"
|
||||
ansible.builtin.file:
|
||||
path: /usr/local/libexec/nagios/plugins/
|
||||
state: directory
|
||||
owner: root
|
||||
group: wheel
|
||||
mode: "0755"
|
||||
tags:
|
||||
- nagios-nrpe
|
||||
|
||||
- name: Nagios plugins are installed
|
||||
copy:
|
||||
- name: "Nagios plugins are installed"
|
||||
ansible.builtin.copy:
|
||||
src: plugins_bsd/{{ item.name }}
|
||||
dest: /usr/local/libexec/nagios/plugins/{{ item.name }}
|
||||
owner: root
|
||||
|
@ -59,10 +94,16 @@
|
|||
- {name: 'check_packetfilter.sh', force: true}
|
||||
- {name: 'check_pf_states', force: false}
|
||||
- {name: 'check_mailq.pl', force: true}
|
||||
- {name: 'check_dhcp_pool', force: false}
|
||||
- {name: 'check_dhcpd.sh', force: false}
|
||||
- {name: 'check_ipmi_sensor', force: true}
|
||||
notify: restart nrpe
|
||||
tags:
|
||||
- nagios-nrpe
|
||||
- nagios-nrpe-utils
|
||||
|
||||
- name: Nagios plugins are installed - template
|
||||
template:
|
||||
- name: "Nagios plugins are installed - template"
|
||||
ansible.builtin.template:
|
||||
src: plugins_bsd/{{ item.name }}.j2
|
||||
dest: /usr/local/libexec/nagios/plugins/{{ item.name }}
|
||||
owner: root
|
||||
|
@ -72,9 +113,15 @@
|
|||
with_items:
|
||||
- {name: 'check_free_mem.sh', force: true}
|
||||
notify: restart nrpe
|
||||
tags:
|
||||
- nagios-nrpe
|
||||
- nagios-nrpe-utils
|
||||
|
||||
- name: Starting and enabling nrpe
|
||||
service:
|
||||
- name: "Starting and enabling nrpe"
|
||||
ansible.builtin.service:
|
||||
name: nrpe
|
||||
enabled: true
|
||||
state: started
|
||||
when: nrpe_exists.stat.exists
|
||||
tags:
|
||||
- nagios-nrpe
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
- name: "Check if {{ package }} is already installed"
|
||||
ansible.builtin.command:
|
||||
cmd: pkg_info -Iq inst:{{ package }}
|
||||
register: is_installed
|
||||
ignore_errors: true
|
||||
changed_when: false
|
||||
tags:
|
||||
- nagios-nrpe
|
||||
|
||||
- name: "Install {{ package }}"
|
||||
ansible.builtin.command:
|
||||
cmd: pkg_add {{ package }}
|
||||
when: "'Can\\'t find inst:' in is_installed.stderr"
|
||||
tags:
|
||||
- nagios-nrpe
|
|
@ -1,17 +1,19 @@
|
|||
#
|
||||
# Custom NRPE configuration file.
|
||||
# Part of the EvoBSD distribution.
|
||||
#
|
||||
# This is an Ansible managed file !
|
||||
# For local modifications use the /etc/nrpe.d/zzz_evolix.cfg file instead
|
||||
|
||||
# Allowed IPs
|
||||
allowed_hosts={{ nagios_nrpe_allowed_hosts | join(',') }}
|
||||
|
||||
# SSL Certificate
|
||||
ssl_cert_file=/etc/ssl/certs/{{ evobsd_ssl_cert_hostname }}.crt
|
||||
ssl_privatekey_file=/etc/ssl/private/{{ evobsd_ssl_cert_hostname }}.key
|
||||
|
||||
{% if ansible_distribution_version is version_compare("7.2",'>=') %}
|
||||
# Allow older cipher suites for older Icinga version
|
||||
ssl_cipher_list=ALL:!MD5:@STRENGTH:@SECLEVEL=0
|
||||
|
||||
{% endif %}
|
||||
# System checks
|
||||
command[check_users]=/usr/local/libexec/nagios/check_users -w 5 -c 10
|
||||
command[check_load]=/usr/local/libexec/nagios/check_load -w 15,10,5 -c 30,25,20
|
||||
command[check_disk1]=/usr/local/libexec/nagios/check_disk -x /lib/init/rw -x /dev -x /dev/shm -w 10% -c 3% -W 10% -K 3% -C -w 5% -c 2% -W 5% -K 2% -p /home
|
||||
command[check_load]=/usr/local/libexec/nagios/check_load --percpu --warning=0.7,0.6,0.5 --critical=0.9,0.8,0.7
|
||||
command[check_disk1]=/usr/local/libexec/nagios/check_disk -e -w 10% -c 3% -W 10% -K 3% -C -w 5% -c 2% -W 5% -K 2% -p /home -x dev
|
||||
command[check_zombie_procs]=/usr/local/libexec/nagios/check_procs -w 5 -c 10 -s Z
|
||||
command[check_total_procs]=/usr/local/libexec/nagios/check_procs -w 150 -c 200
|
||||
command[check_swap]=/usr/local/libexec/nagios/check_swap --no-swap=ok -a -w 30% -c 20%
|
||||
|
@ -19,7 +21,7 @@ command[check_swap]=/usr/local/libexec/nagios/check_swap --no-swap=ok -a -w 30%
|
|||
# Generic services checks
|
||||
command[check_smtp]=/usr/local/libexec/nagios/check_smtp -H localhost -f {{ general_alert_email }}
|
||||
command[check_dns]=/usr/local/libexec/nagios/check_dns -H evolix.net
|
||||
command[check_ntp]=/usr/local/libexec/nagios/check_ntp -H ntp-check.evolix.net
|
||||
command[check_ntp]=/usr/local/libexec/nagios/check_ntp -H {{ nagios_nrpe_default_ntp_server}}
|
||||
command[check_ssh]=/usr/local/libexec/nagios/check_ssh -p 22 localhost
|
||||
command[check_mailq]=doas /usr/local/libexec/nagios/plugins/check_mailq.pl -M opensmtpd -w 5 -c 10
|
||||
|
||||
|
@ -32,7 +34,6 @@ command[check_unbound]=/usr/local/libexec/nagios/check_dig -l evolix.net -H loca
|
|||
#command[check_smb]=/usr/local/libexec/nagios/check_tcp -H IPLOCALE -p 445
|
||||
command[check_mysql]=/usr/local/libexec/nagios/check_mysql -H 127.0.0.1 -f /etc/nrpe.d/.my.cnf
|
||||
#command[check_vpn]=/usr/local/libexec/nagios/check_ping -H IPDISTANTE -p 1 -w 5000,100% -c 5000,100%
|
||||
command[check_dhcpd]=/usr/local/libexec/nagios/check_procs -c1:1 -C dhcpd
|
||||
command[check_bioctl]=/usr/local/libexec/nagios/check_bioctl -d sd2
|
||||
|
||||
# Local checks (not packaged)
|
||||
|
@ -41,7 +42,7 @@ command[check_bioctl]=/usr/local/libexec/nagios/check_bioctl -d sd2
|
|||
command[check_openvpn_certificates]=doas /usr/local/libexec/nagios/plugins/check_openvpn_certificates.sh
|
||||
#command[check_carp0]=/usr/local/libexec/nagios/plugins/check_carp_if carp0 master
|
||||
command[check_mem]=/usr/local/libexec/nagios/plugins/check_free_mem.sh -w 20% -c 10%
|
||||
#command[check_vpn]=doas /usr/local/libexec/nagios/plugins/check_ipsecctl.sh IPDISTANTE IPLOCALE "VPN MARSEILLE-ROME"
|
||||
#command[check_vpn]=/usr/local/libexec/nagios/plugins/check_ipsecctl_critiques.sh
|
||||
command[check_pf_states]=doas /usr/local/libexec/nagios/plugins/check_pf_states
|
||||
command[check_ospfd]=doas /usr/local/libexec/nagios/plugins/check_ospfd
|
||||
command[check_ospf6d]=doas /usr/local/libexec/nagios/plugins/check_ospf6d
|
||||
|
@ -49,6 +50,6 @@ command[check_ospfd_simple]=doas /usr/local/libexec/nagios/plugins/check_ospfd_s
|
|||
#command[check_bgpd]=doas /usr/local/libexec/nagios/plugins/check_openbgpd -u
|
||||
command[check_connections_state]=doas /usr/local/libexec/nagios/plugins/check_connections_state.sh
|
||||
command[check_packetfilter]=doas /usr/local/libexec/nagios/plugins/check_packetfilter.sh
|
||||
|
||||
# This is an Ansible managed file !
|
||||
# For local modifications use the /etc/nrpe.d/zzz_evolix.cfg file instead
|
||||
command[check_dhcpd]=/usr/local/libexec/nagios/plugins/check_dhcpd.sh
|
||||
command[check_dhcp_pool]=/usr/local/libexec/nagios/plugins/check_dhcp_pool
|
||||
command[check_ipmi_sensors]=doas /usr/local/libexec/nagios/plugins/check_ipmi_sensor
|
||||
|
|
|
@ -67,7 +67,14 @@ tot_mem=$(( `/sbin/sysctl -n hw.physmem` / BYTES_IN_MB))
|
|||
{% if ansible_distribution_version is version_compare("6.2",'<') %}
|
||||
free_mem=$(( `/usr/bin/vmstat | /usr/bin/tail -1 | /usr/bin/awk '{ print $5 }'` / KB_IN_MB ))
|
||||
{% else %}
|
||||
free_mem=$(($(/usr/bin/vmstat | /usr/bin/tail -1 | /usr/bin/awk '{ print $4 }' | tr -d 'M') + $(top -n | grep Memory | awk '{print $8}' | tr -d 'M')))
|
||||
if [ "$(top -n | grep Memory | awk '{print $8}' | tr -d 'M')" == "$(top -n | grep Memory | awk '{print $8}' | tr -d 'G')G" ]; then
|
||||
# If cached_mem = XG then cached_mem = X*1024M
|
||||
cached_mem=$(($(top -n | grep Memory | awk '{print $8}' | tr -d 'G') * 1024))
|
||||
else
|
||||
# Else, cached_mem = XM
|
||||
cached_mem=$(top -n | grep Memory | awk '{print $8}' | tr -d 'M')
|
||||
fi
|
||||
free_mem=$(($(/usr/bin/vmstat | /usr/bin/tail -1 | /usr/bin/awk '{ print $4 }' | tr -d 'M') + $cached_mem))
|
||||
{% endif %}
|
||||
# Free memory size (in percentage)
|
||||
free_mem_perc=$(( free_mem * 100 / tot_mem ))
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
# OpenVPN
|
||||
|
||||
Installation and custom configuration of OpenVPN server.
|
||||
|
||||
## Tasks
|
||||
|
||||
Everything is in the `tasks/main.yml` file.
|
||||
|
||||
## Available variables
|
||||
|
||||
The full list of variables (with default values) can be found in `defaults/main.yml`.
|
||||
|
||||
NOTE: Make sure you have already cloned shellpki in ~/GIT/
|
|
@ -1,3 +0,0 @@
|
|||
---
|
||||
openvpn_lan: "192.168.42.0"
|
||||
openvpn_netmask: "255.255.255.0"
|
|
@ -1,215 +0,0 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
#######################################################################
|
||||
#
|
||||
# Copyright (c) 2007 Jaime Gascon Romero <jgascon@gmail.com>
|
||||
#
|
||||
# License Information:
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# $Id: check_openvpn.pl,v 1.1 2014/09/29 08:39:24 rdessort Exp $
|
||||
# $Revision: 1.1 $
|
||||
# Home Site: http://emergeworld.blogspot.com/
|
||||
# #####################################################################
|
||||
|
||||
use diagnostics;
|
||||
use strict;
|
||||
use Net::Telnet ();
|
||||
use Getopt::Long qw(:config no_ignore_case);
|
||||
use vars qw($PROGNAME $VERSION);
|
||||
use lib "/usr/local/libexec/nagios/";
|
||||
use utils qw(%ERRORS);
|
||||
|
||||
$PROGNAME = "check_openvpn";
|
||||
$VERSION = '$Revision: 1.1 $';
|
||||
|
||||
$ENV{'PATH'}='';
|
||||
$ENV{'BASH_ENV'}='';
|
||||
$ENV{'ENV'}='';
|
||||
|
||||
my ($opt_h, $opt_H, $opt_p, $opt_P, $opt_t, $opt_i, $opt_n, $opt_c, $opt_w, $opt_C, $opt_r);
|
||||
|
||||
sub print_help ();
|
||||
sub print_usage ();
|
||||
|
||||
GetOptions
|
||||
("h" => \$opt_h, "help" => \$opt_h,
|
||||
"H=s" => \$opt_H, "host=s" => \$opt_H,
|
||||
"p=i" => \$opt_p, "port=i" => \$opt_p,
|
||||
"P=s" => \$opt_P, "password=s" => \$opt_P,
|
||||
"t=i" => \$opt_t, "timeout=i" => \$opt_t,
|
||||
"i" => \$opt_i, "ip" => \$opt_i,
|
||||
"n" => \$opt_n, "numeric" => \$opt_n,
|
||||
"c" => \$opt_c, "critical" => \$opt_c,
|
||||
"w" => \$opt_w, "warning" => \$opt_w,
|
||||
"C=s" => \$opt_C, "common_name=s" => \$opt_C,
|
||||
"r=s" => \$opt_r, "remote_ip=s" => \$opt_r,
|
||||
) or exit $ERRORS{'UNKNOWN'};
|
||||
|
||||
# default values
|
||||
unless ( defined $opt_t ) {
|
||||
$opt_t = 10;
|
||||
}
|
||||
|
||||
if ($opt_h) {print_help(); exit $ERRORS{'OK'};}
|
||||
|
||||
if ( ! defined($opt_H) || ! defined($opt_p) ) {
|
||||
print_usage();
|
||||
exit $ERRORS{'UNKNOWN'}
|
||||
}
|
||||
|
||||
my @lines;
|
||||
my @clients;
|
||||
my @clients_ip;
|
||||
my $t;
|
||||
|
||||
eval {
|
||||
$t = new Net::Telnet (Timeout => $opt_t,
|
||||
Port => $opt_p,
|
||||
Prompt => '/END$/'
|
||||
);
|
||||
$t->open($opt_H);
|
||||
if ( defined $opt_P ) {
|
||||
$t->waitfor('/ENTER PASSWORD:$/');
|
||||
$t->print($opt_P);
|
||||
}
|
||||
$t->waitfor('/^$/');
|
||||
@lines = $t->cmd("status 2");
|
||||
$t->close;
|
||||
};
|
||||
|
||||
if ($@) {
|
||||
print "OpenVPN Critical: Can't connect to server\n";
|
||||
exit $ERRORS{'CRITICAL'};
|
||||
}
|
||||
|
||||
|
||||
if (defined $opt_i || defined $opt_r) {
|
||||
foreach (@lines) {
|
||||
if ($_ =~ /CLIENT_LIST,.*,(\d+\.\d+\.\d+\.\d+):\d+,/) {
|
||||
push @clients_ip, $1;
|
||||
}
|
||||
}
|
||||
if (defined $opt_i) {
|
||||
print "OpenVPN OK: "."@clients_ip ";
|
||||
exit $ERRORS{'OK'};
|
||||
} elsif (defined $opt_r) {
|
||||
if ( ! grep /\b$opt_r\b/, @clients_ip) {
|
||||
if (defined $opt_c) {
|
||||
print "OpenVPN CRITICAL: $opt_r don't found";
|
||||
exit $ERRORS{'CRITICAL'};
|
||||
} else {
|
||||
print "OpenVPN WARNING: $opt_r don't found";
|
||||
exit $ERRORS{'WARNING'};
|
||||
}
|
||||
}
|
||||
print "OpenVPN OK: "."@clients_ip ";
|
||||
exit $ERRORS{'OK'};
|
||||
}
|
||||
}
|
||||
|
||||
foreach (@lines) {
|
||||
if ($_ =~ /CLIENT_LIST,(.*),\d+\.\d+\.\d+\.\d+:\d+,/) {
|
||||
push @clients, $1;
|
||||
}
|
||||
}
|
||||
|
||||
if (defined $opt_C) {
|
||||
if ( ! grep /\b$opt_C\b/, @clients) {
|
||||
if (defined $opt_c) {
|
||||
print "OpenVPN CRITICAL: $opt_C don't found";
|
||||
exit $ERRORS{'CRITICAL'};
|
||||
} else {
|
||||
print "OpenVPN WARNING: $opt_C don't found";
|
||||
exit $ERRORS{'WARNING'};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (defined $opt_n) {
|
||||
print "OpenVPN OK: ".@clients." connected clients.";
|
||||
exit $ERRORS{'OK'};
|
||||
}
|
||||
|
||||
print "OpenVPN OK: "."@clients ";
|
||||
exit $ERRORS{'OK'};
|
||||
|
||||
#######################################################################
|
||||
###### Subroutines ####################################################
|
||||
|
||||
sub print_usage() {
|
||||
print "Usage: $PROGNAME -H | --host <IP or hostname> -p | --port <port number> [-P | --password] <password> [-t | --timeout] <timeout in seconds>
|
||||
[-i | --ip] [-n | --numeric] [-C | --common_name] <common_name> [-r | --remote_ip] <remote_ip> [-c | --critical] [-w | --warning]\n\n";
|
||||
print " $PROGNAME [-h | --help]\n";
|
||||
}
|
||||
|
||||
sub print_help() {
|
||||
print "$PROGNAME $VERSION\n\n";
|
||||
print "Copyright (c) 2007 Jaime Gascon Romero
|
||||
|
||||
Nagios plugin to check the clients connected to a openvpn server.
|
||||
|
||||
";
|
||||
print_usage();
|
||||
print "
|
||||
-H | --host
|
||||
IP address or hostname of the openvpn server.
|
||||
|
||||
-p | --port
|
||||
Management port interface of the openvpn server.
|
||||
|
||||
-P | --password
|
||||
Password for the management interface of the openvpn server.
|
||||
|
||||
-t | --timeout
|
||||
Timeout for the connection attempt. Optional, default 10 seconds.
|
||||
|
||||
|
||||
Optional parameters
|
||||
===================
|
||||
|
||||
-i | --ip
|
||||
Prints the IP address of the remote client instead of the common name.
|
||||
|
||||
-n | --numeric
|
||||
Prints the number of clients connected to the openvpn server.
|
||||
|
||||
|
||||
Matching Parameters
|
||||
===================
|
||||
|
||||
-C | --common_name
|
||||
The common name, as it is specified in the client certificate, who is wanted to check.
|
||||
|
||||
-r | --remote_ip
|
||||
The client remote ip address who is wanted to check.
|
||||
|
||||
-c | --critical
|
||||
Exits with CRITICAL status if the client specified by the common name or the remote ip address is not connected.
|
||||
|
||||
-w | --warning
|
||||
Exits with WARNING status if the client specified by the common name or the remote ip address is not connected.
|
||||
|
||||
|
||||
Other Parameters
|
||||
================
|
||||
|
||||
-h | --help
|
||||
Show this help.
|
||||
";
|
||||
|
||||
}
|
||||
|
||||
# vim:sts=2:sw=2:ts=2:et
|
|
@ -1,140 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
trap error 0
|
||||
|
||||
STATE_OK=0
|
||||
STATE_WARNING=1
|
||||
STATE_CRITICAL=2
|
||||
STATE_UNKNOWN=3
|
||||
STATE=$STATE_OK
|
||||
CERT_STATE=$STATE
|
||||
CA_STATE=$STATE
|
||||
CERT_ECHO=""
|
||||
CA_ECHO=""
|
||||
|
||||
error() {
|
||||
if [ $? -eq 2 ] && [ "X$CERT_ECHO" = "X" ] && [ "X$CA_ECHO" = "X" ] ; then
|
||||
echo "CRITICAL - The check exited with an error. Is the conf_file var containing the real conf file location ? On Debian, is the check executed with sudo ?"
|
||||
fi
|
||||
}
|
||||
|
||||
SYSTEM=$(uname | tr '[:upper:]' '[:lower:]')
|
||||
date_cmd=$(command -v date)
|
||||
|
||||
# Dates in seconds
|
||||
_15_days="1296000"
|
||||
_30_days="2592000"
|
||||
current_date=$($date_cmd +"%s")
|
||||
|
||||
# Trying to define the OpenVPN conf file location - default to /etc/openvpn/server.conf
|
||||
conf_file=$(ps auwwwx | grep openvpn | grep -- --config | grep -v sed | sed -e "s/.*config \(\/etc\/openvpn.*.conf\).*/\1/" | head -1)
|
||||
[ "$SYSTEM" = "openbsd" ] && conf_file=${conf_file:-$(grep openvpn_flags /etc/rc.conf.local | sed -e "s/.*config \(\/etc\/openvpn.*.conf\).*/\1/")}
|
||||
conf_file=${conf_file:-"/etc/openvpn/server.conf"}
|
||||
|
||||
# Get the cert and ca file location, based on the OpenVPN conf file location
|
||||
# Done in 2 times because sh does not support pipefail - needed in the case where $conf_file does not exist
|
||||
cert_file=$(grep -s "^cert " $conf_file)
|
||||
cert_file=$(echo $cert_file | sed -e "s/^cert *\//\//")
|
||||
ca_file=$(grep -s "^ca " $conf_file)
|
||||
ca_file=$(echo $ca_file | sed -e "s/^ca *\//\//")
|
||||
|
||||
# Get expiration date of cert and ca certificates
|
||||
cert_expiration_date=$(grep "Not After" $cert_file | sed -e "s/.*Not After : //")
|
||||
ca_expiration_date=$(openssl x509 -enddate -noout -in $ca_file | cut -d '=' -f 2)
|
||||
|
||||
test_cert_expiration() {
|
||||
# Already expired - Cert file
|
||||
if [ $current_date -ge $1 ]; then
|
||||
CERT_ECHO="CRITICAL - The server certificate has expired on $formatted_cert_expiration_date"
|
||||
CERT_STATE=$STATE_CRITICAL
|
||||
# Expiration in 15 days or less - Cert file
|
||||
elif [ $((current_date+_15_days)) -ge $1 ]; then
|
||||
CERT_ECHO="CRITICAL - The server certificate expires in 15 days or less : $formatted_cert_expiration_date"
|
||||
CERT_STATE=$STATE_CRITICAL
|
||||
# Expiration in 30 days or less - Cert file
|
||||
elif [ $((current_date+_30_days)) -ge $1 ]; then
|
||||
CERT_ECHO="WARNING - The server certificate expires in 30 days or less : $formatted_cert_expiration_date"
|
||||
CERT_STATE=$STATE_WARNING
|
||||
# Expiration in more than 30 days - Cert file
|
||||
else
|
||||
CERT_ECHO="OK - The server certificate expires on $formatted_cert_expiration_date"
|
||||
CERT_STATE=$STATE_OK
|
||||
fi
|
||||
}
|
||||
|
||||
test_ca_expiration() {
|
||||
# Already expired - CA file
|
||||
if [ $current_date -ge $1 ]; then
|
||||
CA_ECHO="CRITICAL - The server CA has expired on $formatted_ca_expiration_date"
|
||||
CA_STATE=$STATE_CRITICAL
|
||||
# Expiration in 15 days or less - CA file
|
||||
elif [ $((current_date+_15_days)) -ge $1 ]; then
|
||||
CA_ECHO="CRITICAL - The server CA expires in 15 days or less : $formatted_ca_expiration_date"
|
||||
CA_STATE=$STATE_CRITICAL
|
||||
# Expiration in 30 days or less - CA file
|
||||
elif [ $((current_date+_30_days)) -ge $1 ]; then
|
||||
CA_ECHO="WARNING - The server CA expires in 30 days or less : $formatted_ca_expiration_date"
|
||||
CA_STATE=$STATE_WARNING
|
||||
# Expiration in more than 30 days - CA file
|
||||
else
|
||||
CA_ECHO="OK - The server CA expires on $formatted_ca_expiration_date"
|
||||
CA_STATE=$STATE_OK
|
||||
fi
|
||||
}
|
||||
|
||||
# Linux and BSD systems do not implement 'date' the same way
|
||||
if [ "$SYSTEM" = "linux" ]; then
|
||||
|
||||
# Cert expiration date human formated then in seconds
|
||||
formatted_cert_expiration_date=$(TZ="Europe/Paris" $date_cmd -d "$cert_expiration_date" +"%F %T %Z")
|
||||
seconds_cert_expiration_date=$(TZ="Europe/Paris" $date_cmd -d "$cert_expiration_date" +"%s")
|
||||
|
||||
# CA expiration date human formated then in seconds
|
||||
formatted_ca_expiration_date=$(TZ="Europe/Paris" $date_cmd -d "$ca_expiration_date" +"%F %T %Z")
|
||||
seconds_ca_expiration_date=$(TZ="Europe/Paris" $date_cmd -d "$ca_expiration_date" +"%s")
|
||||
|
||||
test_cert_expiration $seconds_cert_expiration_date
|
||||
test_ca_expiration $seconds_ca_expiration_date
|
||||
|
||||
elif [ "$SYSTEM" = "openbsd" ]; then
|
||||
|
||||
# Cert expiration date for POSIX date, human formated then in seconds
|
||||
posix_cert_expiration_date=$(echo "$cert_expiration_date" | awk '{ printf $4" "(index("JanFebMarAprMayJunJulAugSepOctNovDec",$1)+2)/3" "$2" ",split($3,time,":"); print time[1],time[2],time[3]}' | awk '{printf "%04d%02d%02d%02d%02d.%02d\n", $1, $2, $3, $4, $5, $6}')
|
||||
cert_zone=$(echo "$cert_expiration_date" | awk '{print $5}')
|
||||
formatted_cert_expiration_date=$(TZ=$cert_zone $date_cmd -j -z "Europe/Paris" "$posix_cert_expiration_date" +"%F %T %Z")
|
||||
seconds_cert_expiration_date=$(TZ=$cert_zone $date_cmd -j -z "Europe/Paris" "$posix_cert_expiration_date" +"%s")
|
||||
|
||||
# CA expiration date for POSIX date, human formated then in seconds
|
||||
posix_ca_expiration_date=$(echo "$ca_expiration_date" | awk '{ printf $4" "(index("JanFebMarAprMayJunJulAugSepOctNovDec",$1)+2)/3" "$2" ",split($3,time,":"); print time[1],time[2],time[3]}' | awk '{printf "%04d%02d%02d%02d%02d.%02d\n", $1, $2, $3, $4, $5, $6}')
|
||||
ca_zone=$(echo "$ca_expiration_date" | awk '{print $5}')
|
||||
formatted_ca_expiration_date=$(TZ=$ca_zone $date_cmd -j -z "Europe/Paris" "$posix_ca_expiration_date" +"%F %T %Z")
|
||||
seconds_ca_expiration_date=$(TZ=$ca_zone $date_cmd -j -z "Europe/Paris" "$posix_ca_expiration_date" +"%s")
|
||||
|
||||
test_cert_expiration $seconds_cert_expiration_date
|
||||
test_ca_expiration $seconds_ca_expiration_date
|
||||
|
||||
# If neither Linux nor BSD
|
||||
else
|
||||
|
||||
echo "CRITICAL - OS not supported"
|
||||
STATE=$STATE_CRITICAL
|
||||
exit $STATE
|
||||
|
||||
fi
|
||||
|
||||
# Display the first one that expires first
|
||||
if [ $CA_STATE -gt $CERT_STATE ]; then
|
||||
echo $CA_ECHO
|
||||
echo $CERT_ECHO
|
||||
exit $CA_STATE
|
||||
elif [ $CERT_STATE -gt $CA_STATE ]; then
|
||||
echo $CERT_ECHO
|
||||
echo $CA_ECHO
|
||||
exit $CERT_STATE
|
||||
else
|
||||
echo $CERT_ECHO
|
||||
echo $CA_ECHO
|
||||
exit $CERT_STATE
|
||||
fi
|
|
@ -1 +0,0 @@
|
|||
../../../../shellpki
|
|
@ -1 +0,0 @@
|
|||
%shellpki ALL = (root) /usr/local/sbin/shellpki
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
- name: restart openvpn
|
||||
service:
|
||||
name: openvpn
|
||||
state: restarted
|
|
@ -1,136 +0,0 @@
|
|||
---
|
||||
- name: Install OpenVPN package
|
||||
openbsd_pkg:
|
||||
name: "openvpn--"
|
||||
tags:
|
||||
- openvpn
|
||||
|
||||
- name: Create /etc/openvpn directory
|
||||
file:
|
||||
path: /etc/openvpn
|
||||
state: directory
|
||||
owner: "root"
|
||||
group: "wheel"
|
||||
mode: "0755"
|
||||
tags:
|
||||
- openvpn
|
||||
|
||||
- name: Deploy OpenVPN configuration
|
||||
template:
|
||||
src: "server.conf.j2"
|
||||
dest: "/etc/openvpn/server.conf"
|
||||
mode: "0600"
|
||||
notify: restart openvpn
|
||||
tags:
|
||||
- openvpn
|
||||
|
||||
- name: Enabling OpenVPN
|
||||
service:
|
||||
name: openvpn
|
||||
enabled: true
|
||||
tags:
|
||||
- openvpn
|
||||
|
||||
- name: Set OpenVPN flag
|
||||
shell: 'rcctl set openvpn flags "--config /etc/openvpn/server.conf"'
|
||||
tags:
|
||||
- openvpn
|
||||
|
||||
- name: Create shellpki user
|
||||
user:
|
||||
name: "_shellpki"
|
||||
system: true
|
||||
state: present
|
||||
home: "/etc/shellpki/"
|
||||
shell: "/sbin/nologin"
|
||||
tags:
|
||||
- openvpn
|
||||
|
||||
- name: Copy some shellpki files
|
||||
copy:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ item.dest }}"
|
||||
owner: root
|
||||
group: wheel
|
||||
mode: "{{ item.mode }}"
|
||||
force: true
|
||||
with_items:
|
||||
- src: 'files/shellpki/openssl.cnf'
|
||||
dest: '/etc/shellpki/openssl.cnf'
|
||||
mode: '0640'
|
||||
- src: 'files/shellpki/shellpki'
|
||||
dest: '/usr/local/sbin/shellpki'
|
||||
mode: '0755'
|
||||
tags:
|
||||
- openvpn
|
||||
|
||||
- name: Deploy DH PARAMETERS
|
||||
template:
|
||||
src: "dh2048.pem.j2"
|
||||
dest: "/etc/shellpki/dh2048.pem"
|
||||
mode: "0600"
|
||||
tags:
|
||||
- openvpn
|
||||
|
||||
- name: Create /etc/sudoers.d directory
|
||||
file:
|
||||
path: /etc/sudoers.d
|
||||
state: directory
|
||||
owner: "root"
|
||||
group: "wheel"
|
||||
mode: "0755"
|
||||
tags:
|
||||
- openvpn
|
||||
|
||||
- name: Include /etc/sudoers.d in sudoers configuration file
|
||||
lineinfile:
|
||||
path: /etc/sudoers
|
||||
line: '#includedir /etc/sudoers.d'
|
||||
tags:
|
||||
- openvpn
|
||||
|
||||
- name: Verify shellpki sudoers file presence
|
||||
copy:
|
||||
src: "sudo_shellpki"
|
||||
dest: "/etc/sudoers.d/shellpki"
|
||||
force: true
|
||||
mode: "0440"
|
||||
validate: '/usr/local/sbin/visudo -cf %s'
|
||||
tags:
|
||||
- openvpn
|
||||
|
||||
- name: Copy check_openvpn
|
||||
copy:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ item.dest }}"
|
||||
owner: root
|
||||
group: wheel
|
||||
mode: "{{ item.mode }}"
|
||||
force: true
|
||||
with_items:
|
||||
- src: 'files/check_openvpn.pl'
|
||||
dest: '/usr/local/libexec/nagios/plugins/check_openvpn.pl'
|
||||
mode: '0755'
|
||||
tags:
|
||||
- openvpn
|
||||
|
||||
- name: Install needed package for check_openvpn
|
||||
openbsd_pkg:
|
||||
name: "p5-Net-Telnet"
|
||||
tags:
|
||||
- openvpn
|
||||
|
||||
- name: Copy check_openvpn_certificates.sh
|
||||
copy:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ item.dest }}"
|
||||
owner: root
|
||||
group: wheel
|
||||
mode: "{{ item.mode }}"
|
||||
force: true
|
||||
with_items:
|
||||
- src: 'files/check_openvpn_certificates.sh'
|
||||
dest: '/usr/local/libexec/nagios/plugins/check_openvpn_certificates.sh'
|
||||
mode: '0755'
|
||||
tags:
|
||||
- openvpn
|
|
@ -1,8 +0,0 @@
|
|||
-----BEGIN DH PARAMETERS-----
|
||||
MIIBCAKCAQEAuimweC/f5W/AIIFhLX256Bi5IU+AkN9sKZ9sxGx0xc3J8NwIBnEP
|
||||
R/2RgclJqJ8OodY70zeDHNLDyc01crGvihuupiWVlvQxS4osdhfdM+GoV9pcmCVr
|
||||
TRTybsUPkkm4rQ/SC7I2MxiYnXwDrrYnpMvBDaRZjoHlgTKjOGoYSd+DIDZSFKkv
|
||||
ASkXQkIC9FpvjnxfW5gtzzm6NheqgYUI2Y2QiqM6BmGVZiPcqyUpbWvRCcZLoPa2
|
||||
Z+FV9LxE4J7CX0ilTJXXhs3RaMlG8qZha3l0hEL4SAZp5xn74Ej/9hA5cWqnKEOQ
|
||||
aLfwADI4rPe9uTu9Qnw87DgM2tQeETBlmwIBAg==
|
||||
-----END DH PARAMETERS-----
|
|
@ -1,26 +0,0 @@
|
|||
user nobody
|
||||
group nogroup
|
||||
|
||||
local {{ ansible_default_ipv4.address }}
|
||||
port 1194
|
||||
proto udp
|
||||
dev tun
|
||||
mode server
|
||||
keepalive 10 120
|
||||
|
||||
cipher AES-128-CBC # AES
|
||||
#comp-lzo
|
||||
# compress (à partir d'OpenVPN 2.4)
|
||||
|
||||
persist-key
|
||||
persist-tun
|
||||
|
||||
status /var/log/openvpn-status.log
|
||||
log-append /var/log/openvpn.log
|
||||
|
||||
ca /etc/shellpki/cacert.pem
|
||||
cert /etc/shellpki/certs/{{ ansible_fqdn }}.crt
|
||||
key /etc/shellpki/private/{{ ansible_fqdn }}.key
|
||||
dh /etc/shellpki/dh2048.pem
|
||||
|
||||
server {{ openvpn_lan }} {{ openvpn_netmask }}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue