├── doc ├── NAGIOS.md ├── EXAMPLES.md └── img │ ├── 06_ok.png │ ├── details.png │ ├── icinga.png │ ├── 02_updates.png │ ├── 07_errors.png │ ├── 08_warnings.png │ ├── 09_unknowns.png │ ├── 01_sec-updates.png │ ├── 03_core-errors.png │ ├── 04_core-warnings.png │ └── 05_db-migrations.png ├── .travis.yml ├── composer.json ├── icingaexchange.yml ├── LICENSE ├── .gitignore ├── CHANGELOG.md ├── bin ├── check_drupal_log └── check_drupal └── README.md /doc/NAGIOS.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/EXAMPLES.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/img/06_ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/06_ok.png -------------------------------------------------------------------------------- /doc/img/details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/details.png -------------------------------------------------------------------------------- /doc/img/icinga.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/icinga.png -------------------------------------------------------------------------------- /doc/img/02_updates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/02_updates.png -------------------------------------------------------------------------------- /doc/img/07_errors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/07_errors.png -------------------------------------------------------------------------------- /doc/img/08_warnings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/08_warnings.png -------------------------------------------------------------------------------- /doc/img/09_unknowns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/09_unknowns.png -------------------------------------------------------------------------------- /doc/img/01_sec-updates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/01_sec-updates.png -------------------------------------------------------------------------------- /doc/img/03_core-errors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/03_core-errors.png -------------------------------------------------------------------------------- /doc/img/04_core-warnings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/04_core-warnings.png -------------------------------------------------------------------------------- /doc/img/05_db-migrations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/05_db-migrations.png -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: sh 2 | 3 | before_script: 4 | - sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu/ trusty-backports restricted main universe" 5 | - sudo apt-get update -qq 6 | - sudo apt-get install -qq shellcheck 7 | 8 | script: 9 | - shellcheck --shell=sh bin/check_drupal 10 | - shellcheck --shell=sh bin/check_drupal_log 11 | 12 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cytopia/check_drupal", 3 | "description": "This nagios plugin will check if your drupal site has issues (security updates, updates[optional], outstanding db updates, other problems).", 4 | "type": "library", 5 | "keywords": ["nagios", "nagios-plugin", "icinga", "drupal"], 6 | "homepage": "https://github.com/cytopia/check_drupal", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name" : "cytopia", 11 | "homepage": "https://github.com/cytopia", 12 | "role": "Developer" 13 | } 14 | ], 15 | "bin": ["bin/check_drupal"] 16 | } 17 | -------------------------------------------------------------------------------- /icingaexchange.yml: -------------------------------------------------------------------------------- 1 | name: check_drupal 2 | description: "file:///README.md" 3 | url: "https://github.com/cytopia/check_drupal" 4 | tags: CMS 5 | vendor: cytopia 6 | target: Operating System,Website 7 | type: Plugin 8 | license: MIT 9 | releases: 10 | - 11 | name: 0.8 12 | description: "0.8 Release" 13 | files: 14 | - 15 | name: check_drupal 16 | url: "file:///bin/check_drupal" 17 | description: "Directly check a drupal CMS" 18 | checksum: 06f9005e97f0526d2b570e0b4a88d6da 19 | - 20 | name: check_drupal_log 21 | url: "file:///bin/check_drupal_log" 22 | description: "Check the logfile created by check_drupal" 23 | checksum: fcb4cd9c7eca94f0574edd62d057f7fc 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 cytopia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ###################################### 2 | # CUSTOM 3 | ###################################### 4 | 5 | 6 | 7 | ###################################### 8 | # GENERIC 9 | ###################################### 10 | 11 | ###### std ###### 12 | .lock 13 | *.log 14 | 15 | ###### patches/diffs ###### 16 | *.patch 17 | *.diff 18 | *.orig 19 | *.rej 20 | 21 | 22 | ###################################### 23 | # Operating Systems 24 | ###################################### 25 | 26 | ###### OSX ###### 27 | ._* 28 | .DS* 29 | .Spotlight-V100 30 | .Trashes 31 | 32 | ###### Windows ###### 33 | Thumbs.db 34 | ehthumbs.db 35 | Desktop.ini 36 | $RECYCLE.BIN/ 37 | *.lnk 38 | 39 | 40 | ###################################### 41 | # Editors 42 | ###################################### 43 | 44 | ###### Sublime ###### 45 | *.sublime-workspace 46 | *.sublime-project 47 | 48 | ###### Eclipse ###### 49 | .classpath 50 | .buildpath 51 | .project 52 | .settings/ 53 | 54 | ###### Netbeans ###### 55 | nbproject/private/ 56 | 57 | ###### Intellij IDE ###### 58 | .idea/ 59 | .idea_modules/ 60 | 61 | ###### vim ###### 62 | *.swp 63 | *.swo 64 | *~ 65 | 66 | ###### TextMate ###### 67 | .tm_properties 68 | *.tmproj 69 | 70 | ###### BBEdit ###### 71 | *.bbprojectd 72 | *.bbproject 73 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Version 0.8 (unreleased) 2 | ----------- 3 | 4 | 5 | Version 0.7 6 | ----------- 7 | 8 | - [Fea] Be able to suppress locked modules (Thanks to https://github.com/fdellwing) 9 | 10 | 11 | Version 0.6 12 | ----------- 13 | 14 | - [Fea] Set language for drush commands to English through forced config file 15 | 16 | 17 | Version 0.5 18 | ----------- 19 | 20 | - [Fea] Drupal 8 support 21 | - [Fix] Fix core error detection 22 | - [Fix] Fix spelling 23 | 24 | 25 | Version 0.4 26 | ----------- 27 | 28 | - [Fea] Implemented multisite checking via `-i` 29 | 30 | 31 | Version 0.3 32 | ----------- 33 | 34 | - [Fea] Added performance data: Sec Updates 35 | - [Fea] Added performance data: Updates 36 | - [Fea] Added performance data: Core errors 37 | - [Fea] Added performance data: Core warnings 38 | - [Fea] Added performance data: DB migrations 39 | - [Fea] Improved short output 40 | 41 | 42 | Version 0.2 43 | ----------- 44 | 45 | - [Fea] Implemented `check_drupal_log` 46 | - [Fix] Fixed misspelled variables 47 | - [Enh] First check all arguments, then run the checks 48 | - [Enh] Move scripts to bin directory 49 | - [Enh] Doc directory for more documentation 50 | 51 | 52 | Version 0.1 53 | ----------- 54 | 55 | - [Fea] Check for Drupal security updates 56 | - [Fea] Check for Drupal system updates 57 | - [Fea] Check for Drupal required database updates 58 | - [Fea] Check for Drupal core errors 59 | - [Fea] Check for Drupal core warnings 60 | - [Fea] Every check can specify nagios severity (Error or Warning) 61 | - [Fea] Specify custom name for nagios short output 62 | - [Fea] Be able to successfully recognize valid Drupal6 or Drupal7 document root 63 | - [Fea] Detailed information in nagios long output 64 | - [Fea] Basic performance data fow: how many OKs, Errors, Warnings and Unknowns 65 | 66 | -------------------------------------------------------------------------------- /bin/check_drupal_log: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Nagios plugin to monitor the state of drupal sites. 4 | # 5 | 6 | ################################################################################ 7 | # 8 | # V A R I A B L E S 9 | # 10 | ################################################################################ 11 | 12 | # Some creds 13 | INFO_NAME="check_drupal_log" 14 | INFO_AUTHOR="cytopia " 15 | INFO_GPGKEY="0x695128A2" 16 | INFO_DATE="2016-12-12" 17 | INFO_LICENSE="MIT" 18 | INFO_VERSION="0.8" 19 | 20 | # Get the path 21 | export PATH="$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin" 22 | 23 | # Nagios error codes 24 | EXIT_OK=0 25 | #EXIT_WARN=1 26 | #EXIT_ERR=2 27 | EXIT_UNKNOWN=3 28 | 29 | 30 | 31 | ################################################################################ 32 | # 33 | # F U N C T I O N S 34 | # 35 | ################################################################################ 36 | 37 | # Test if argument is an integer 38 | # @return integer 0: is numer | 1 not a number 39 | # 40 | # usage: 41 | # if ! isint ${DELETE_IF_OLDER} > /dev/null 2>&1 ; then 42 | # echo "not an integer" 43 | # fi 44 | isint(){ 45 | printf '%d' "$1" >/dev/null 2>&1 && return 0 || return 1; 46 | } 47 | 48 | # Give some creds 49 | # @output string The creds. 50 | # @return integer 0 51 | print_version() { 52 | printf "Name: %s\n" "${INFO_NAME}" 53 | printf "Version: %s (%s)\n" "${INFO_VERSION}" "${INFO_DATE}" 54 | printf "Author: %s (%s)\n" "${INFO_AUTHOR}" "${INFO_GPGKEY}" 55 | printf "License: %s\n" "${INFO_LICENSE}" 56 | return 0 57 | } 58 | 59 | 60 | # Usage 61 | # @output string The usage screen. 62 | # @return integer 0 63 | print_usage() { 64 | printf "Usage: %s -f \n" "${INFO_NAME}" 65 | printf "OR %s --help\n" "${INFO_NAME}" 66 | printf "OR %s --version\n\n" "${INFO_NAME}" 67 | return 0 68 | } 69 | 70 | # Help 71 | # @output string The help screen. 72 | # @return integer 0 73 | print_help() { 74 | 75 | # Show usage first 76 | print_usage 77 | 78 | # Show help and details 79 | printf "Nagios plugin that will parse the logfile created by 'check_drupal'.\n\n" 80 | 81 | printf " -f The full path to logfile created by 'check_drupal'\n\n" 82 | 83 | printf " --help Show this help\n" 84 | printf " --version Show version information.\n" 85 | return 0 86 | } 87 | 88 | 89 | 90 | ################################################################################ 91 | # 92 | # E N T R Y P O I N T 93 | # 94 | ################################################################################ 95 | 96 | ############################################################ 97 | # Check for --help or --version arguments 98 | ############################################################ 99 | if [ "${1}" = "--help" ]; then 100 | print_help 101 | exit $EXIT_OK 102 | fi 103 | if [ "${1}" = "--version" ]; then 104 | print_version 105 | exit $EXIT_OK 106 | fi 107 | 108 | 109 | ############################################################ 110 | # Retrieve arguments 111 | ############################################################ 112 | while test -n "$1"; do 113 | case "$1" in 114 | # ---- 1. Logfile 115 | -f) 116 | # Get next arg in list (Path) 117 | shift 118 | LOGFILE="$1" 119 | ;; 120 | *) 121 | printf "Unknown argument: %s\n" "$1" 122 | print_usage 123 | exit $EXIT_UNKNOWN 124 | ;; 125 | esac 126 | shift 127 | done 128 | 129 | 130 | ############################################################ 131 | # Validate arguments 132 | ############################################################ 133 | 134 | # -f is mandatory!!! 135 | if [ -z "$LOGFILE" ]; then 136 | printf "[UNKNOWN] Logfile parameter '-f' not specified.\n" 137 | print_usage 138 | exit $EXIT_UNKNOWN 139 | fi 140 | 141 | # Check if logfile exists 142 | if [ ! -f "$LOGFILE" ]; then 143 | echo "[UNKNOWN] Logfile does not exist: ${LOGFILE}." 144 | exit $EXIT_UNKNOWN 145 | fi 146 | 147 | # Check if logfile is readable 148 | if [ ! -r "$LOGFILE" ]; then 149 | echo "[UNKNOWN] Logfile is not readable: ${LOGFILE}." 150 | exit $EXIT_UNKNOWN 151 | fi 152 | 153 | # Check if last line contains error code 154 | NAGIOS_EXIT="$(tail -n1 "$LOGFILE")" 155 | if ! isint "${NAGIOS_EXIT}" > /dev/null 2>&1 ; then 156 | echo "[UNKNOWN] Logfile seems invalid: Does not contain exit code on last line." 157 | exit $EXIT_UNKNOWN 158 | fi 159 | 160 | # Check if exit code is within bounds 161 | if [ "$NAGIOS_EXIT" != "0" ] && [ "$NAGIOS_EXIT" != "1" ] && [ "$NAGIOS_EXIT" != "2" ] && [ "$NAGIOS_EXIT" != "3" ]; then 162 | echo "[UNKNOWN] Exit code not within bounds in $LOGFILE" 163 | exit $EXIT_UNKNOWN 164 | fi 165 | 166 | 167 | 168 | NUM_LINES="$(wc -l < "$LOGFILE")" 169 | NUM_LINES="$((NUM_LINES-1))" # Last line is exit code 170 | 171 | OUTPUT="$(head -n${NUM_LINES} "$LOGFILE")" 172 | 173 | echo "$OUTPUT" 174 | exit "$NAGIOS_EXIT" 175 | 176 | # " vim: set ts=4: 177 | 178 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # check_drupal 2 | Nagios drupal plugin to monitor the state of a drupal site and/or drupal multisite for security updates, system updates, core errors, core warnings and missing database migrations. 3 | 4 | [![Build Status](https://travis-ci.org/cytopia/check_drupal.svg?branch=master)](https://travis-ci.org/cytopia/check_drupal) 5 | [![Latest Stable Version](https://poser.pugx.org/cytopia/check_drupal/v/stable)](https://packagist.org/packages/cytopia/check_drupal) [![Total Downloads](https://poser.pugx.org/cytopia/check_drupal/downloads)](https://packagist.org/packages/cytopia/check_drupal) [![Latest Unstable Version](https://poser.pugx.org/cytopia/check_drupal/v/unstable)](https://packagist.org/packages/cytopia/check_drupal) [![License](https://poser.pugx.org/cytopia/check_drupal/license)](http://opensource.org/licenses/MIT) 6 | [![POSIX](https://img.shields.io/badge/posix-100%25-brightgreen.svg)](https://en.wikipedia.org/?title=POSIX) 7 | [![Type](https://img.shields.io/badge/type-%2Fbin%2Fsh-red.svg)](https://en.wikipedia.org/?title=Bourne_shell) 8 | 9 | --- 10 | 11 | | [![Awesome-Nagios-Plugins](https://raw.githubusercontent.com/cytopia/awesome-nagios-plugins/master/doc/img/awesome-nagios.png)](https://github.com/cytopia/awesome-nagios-plugins) | Find more plugins at [Awesome Nagios](https://github.com/cytopia/awesome-nagios-plugins) | 12 | |---|---| 13 | | [![Icinga Exchange](https://raw.githubusercontent.com/cytopia/awesome-nagios-plugins/master/doc/img/icinga.png)](https://exchange.icinga.com/cytopia) | **Find more plugins at [Icinga Exchange](https://exchange.icinga.com/cytopia)** | 14 | | [![Nagios Exchange](https://raw.githubusercontent.com/cytopia/awesome-nagios-plugins/master/doc/img/nagios.png)](https://exchange.nagios.org/directory/Owner/cytopia/1) | **Find more plugins at [Nagios Exchange](https://exchange.nagios.org/directory/Owner/cytopia/1)** | 15 | 16 | --- 17 | 18 | **Tested on** 19 | 20 | * Drupal 6 21 | * Drupal 7 22 | * Drupal 8 23 | 24 | --- 25 | 26 | **Overview** 27 | ![Status](https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/icinga.png) 28 | 29 | **Details** 30 | ![Status](https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/details.png) 31 | 32 | --- 33 | 34 | ##### NOTE 35 | This check can be used in two ways: 36 | 37 | 1. Let nagios always trigger `check_drupal` which might take 1-3 seconds and cause some load 38 | 2. Let nagios simply parse the logfile (with `check_drupal_log`) created by `check_drupal` via cron on the target machine. 39 | 40 | I would recommend the second option as you do not check each drupal site every 5 minutes and also in order to keep the nagios check as fast as possible. For that use cron to trigger the `check_drupal` on the target machine every 6 hours or so. 41 | 42 | 43 | ##### Requirements 44 | | Program | Required | Description | 45 | | ------------- | ------------- | -------- | 46 | | bourne shell (sh) | yes | The whole script is written in pure bourne shell (sh) and is 100% Posix compliant | 47 | | [check_by_ssh](https://www.monitoring-plugins.org/doc/man/check_by_ssh.html) or
[NRPE](https://exchange.nagios.org/directory/Addons/Monitoring-Agents/NRPE--2D-Nagios-Remote-Plugin-Executor/details) | yes | check_by_ssh is used as a wrapper to check on remote hosts. Alternatively you can use NRPE as reported here: [Issue #2](https://github.com/cytopia/check_drupal/issues/2) | 48 | | [drush](http://www.drush.org) | yes | This nagios plugin requires drush to be installed on the target machine | 49 | 50 | ##### Features 51 | * Multisite support 52 | * Check for Drupal security updates 53 | * Check for Drupal system updates 54 | * Check for Drupal required database migrations 55 | * Check for Drupal core errors 56 | * Check for Drupal core warnings 57 | * Every check can specify its own nagios severity (Error or Warning) 58 | * Custom name for nagios short output 59 | * Be able to don't show updates that are locked via drush 60 | * Detailed information in nagios long output 61 | * Be able to successfully recognize valid Drupal6 or Drupal7 document root 62 | * Basic performance data fow: how many OKs, Errors, Warnings and Unknowns 63 | 64 | 65 | 66 | ## 1. Usage 67 | 68 | ### 1.1 `check_drupal` 69 | 70 | With `-l` you will be able to run the `check_drupal` locally on each machine only a few times a day and dump the output to a logfile. 71 | This file can then be checked normaly via nagios by calling `check_drupal_log` instead, which will just read the log and not put any load onto the machine. 72 | Multiple logfiles for multiple drupal site per server will be possible. 73 | 74 | ```shell 75 | Usage: check_drupal -d [-n ] [-s ] [-u ] [-e ] [-w ] [-m ] [-i ] [-l ] [-r] 76 | OR check_drupal --check 77 | OR check_drupal --help 78 | OR check_drupal --version 79 | 80 | Nagios plugin that will check drupal sites for errors. 81 | Errors include the following: available security updates, 82 | missed database migrations and drupal status errors. 83 | For each check you can specify the nagios severity (error or warning). 84 | 85 | -d The full path to the drupal document root (usually 86 | the 'drupal' folder. This parameter is required. 87 | 88 | -n [optional] Specify a name for the drupal instance to 89 | appear on the nagios output. The default is 'Drupal' 90 | 91 | -s [optional] Check for drupal core and module security 92 | updates and return nagios error or warning. 93 | Warning: -s w 94 | Error: -s e 95 | 96 | -u [optional] Check for drupal core and module updates 97 | in general and return nagios error or warning. 98 | Warning: -u w 99 | Error: -u e 100 | 101 | -e [optional] Check for drupal status errors and return 102 | nagios error or warning. 103 | Warning: -e w 104 | Error: -e e 105 | 106 | -w [optional] Check for drupal status warnings and return 107 | nagios error or warning. 108 | Warning: -w w 109 | Error: -w e 110 | 111 | -m [optional] Check for drupal missed database migrations 112 | and return nagios error or warning. (They can occur 113 | when you update core or modules and forget the db). 114 | Warning: -m w 115 | Error: -m e 116 | 117 | -i [optional] Parse in an url for a drupal multisite instance. 118 | 'drush --uri': 119 | In Drupal 7, the value of --uri should always be 120 | the same as when the site is being accessed from a web browser 121 | (e.g. http://mysite.org, although the http:// is optional). 122 | In Drupal 6, the value of --uri should always be the same as the 123 | site's folder name in the 'sites' folder (e.g. default); it is best 124 | if the site folder name matches the URI from the browser, and is consistent 125 | on every instance of the same site 126 | (e.g. also use sites/mysite.org for http://dev.mysite.org). 127 | 128 | -l [optional] Instead of checking all of the above via nagios 129 | every five minutes or so, run this script via cron once a day 130 | (or twice) and write the output into a logfile. This logfile can 131 | then be checked by the nagios plugin 'check_drupal_log' which is 132 | less costy in terms of load/cpu. 133 | See 'check_drupal_log --help' for more info. 134 | Example: 135 | check_drupal -d /var/www -s e -e e -w w -l /var/log/drupal.log 136 | check_drupal_log -l /var/log/drupal.log 137 | 138 | -r [optional] Filters all updates that are locked via drush. 139 | For general infos about locking run 'drush pm-updatestatus -h' 140 | 141 | --check Check for program requirements. 142 | --help Show this help 143 | --version Show version information. 144 | ``` 145 | 146 | ### 1.2 `check_drupal_log` 147 | 148 | ```bash 149 | Usage: check_drupal_log -f 150 | OR check_drupal_log --help 151 | OR check_drupal_log --version 152 | 153 | Nagios plugin that will parse the logfile created by 'check_drupal'. 154 | 155 | -f The full path to logfile created by 'check_drupal' 156 | 157 | --help Show this help 158 | --version Show version information. 159 | ``` 160 | 161 | ## 2. Examples 162 | 163 | The following examples are run directly from the command line. The exit code will always be aggregated, meaning if the program throws a warning and an error, the final exit code will result in an error. 164 | 165 | Also to note: The first line until the `|` represents the actual nagios output. Everything in the first line behind the `|` is performance data used to generate the cool charts. Everything from line two onwards is nagios extended status info (when you click on details). 166 | 167 | 168 | **Check for security updates** 169 | ```bash 170 | ./check_drupal -d /shared/httpd/sites-drupal/COOL-PROJECT/drupal/ -n COOL-PROJECT -s e 171 | [CRITICAL] COOL-PROJECT has errors: 2 Security updates | 'Security Updates'=2;;;; 'Updates'=0;;;; 'Core Errors'=0;;;; 'Core Warnings'=0;;;; 'Database Migrations'=0;;;; 'OK'=0;;;0;1 'Errors'=1;1;1;0;1 'Warnings'=0;1;;0;1 'Unknown'=0;;;0;1 172 | ==== SECURITY UPDATES ==== 173 | [CRITICAL] drupal 7.40 -> 7.41 174 | [CRITICAL] jquery_update 7.x-2.6 -> 7.x-2.7 175 | ``` 176 | 177 | **Check for security and normal updates** 178 | ```bash 179 | ./check_drupal -d /shared/httpd/sites-drupal/COOL-PROJECT/drupal/ -n COOL-PROJECT -s e -u w 180 | [CRITICAL] COOL-PROJECT has errors: 3 Security updates, 3 Updates | 'Security Updates'=3;;;; 'Updates'=3;;;; 'Core Errors'=0;;;; 'Core Warnings'=0;;;; 'Database Migrations'=0;;;; 'OK'=0;;;0;2 'Errors'=1;1;1;0;2 'Warnings'=1;1;;0;2 'Unknown'=0;;;0;2 181 | ==== SECURITY UPDATES ==== 182 | [CRITICAL] drupal 7.40 -> 7.41 183 | [CRITICAL] block_class 7.x-2.1 -> 7.x-2.3 184 | [CRITICAL] jquery_update 7.x-2.6 -> 7.x-2.7 185 | ==== SYSTEM UPDATES ==== 186 | [WARNING] field_collection 7.x-1.0-beta9 -> 7.x-1.0-beta10 187 | [WARNING] views 7.x-3.11 -> 7.x-3.13 188 | [WARNING] bootstrap 7.x-3.0 -> 7.x-3.4 189 | ``` 190 | 191 | **Check for all possible stuff** 192 | ```bash 193 | ./check_drupal -d /shared/httpd/sites-drupal/COOL-PROJECT/drupal/ -n COOL-PROJECT -s e -u w -e e -w w -m e 194 | [CRITICAL] COOL-PROJECT has errors: 3 Security updates, 3 Updates, 5 Core errors, 1 Core warning | 'Security Updates'=3;;;; 'Updates'=3;;;; 'Core Errors'=5;;;; 'Core Warnings'=1;;;; 'Database Migrations'=0;;;; 'OK'=1;;;0;5 'Errors'=2;1;1;0;5 'Warnings'=2;1;;0;5 'Unknown'=0;;;0;5 195 | ==== SECURITY UPDATES ==== 196 | [CRITICAL] drupal 7.40 -> 7.41 197 | [CRITICAL] block_class 7.x-2.1 -> 7.x-2.3 198 | [CRITICAL] jquery_update 7.x-2.6 -> 7.x-2.7 199 | ==== SYSTEM UPDATES ==== 200 | [WARNING] field_collection 7.x-1.0-beta9 -> 7.x-1.0-beta10 201 | [WARNING] views 7.x-3.11 -> 7.x-3.13 202 | [WARNING] bootstrap 7.x-3.0 -> 7.x-3.4 203 | ==== CORE ERRORS ==== 204 | [CRITICAL] CKeditor 205 | [CRITICAL] Cron-Wartungsaufgaben 206 | [CRITICAL] CTools CSS Cache 207 | [CRITICAL] Aktualisierungsstatus von Modulen und Themes 208 | [CRITICAL] Aktualisierungsstatus des Drupal-Kern 209 | ==== CORE WARNINGS ==== 210 | [WARNING] Token 211 | ==== DB UPDATES ==== 212 | [OK] No database migrations required 213 | ``` 214 | **Check for db updates** 215 | ```bash 216 | ./check_drupal -d /shared/httpd/sites-drupal/COOL-PROJECT/drupal/ -n COOL-PROJECT -m e 217 | [OK] COOL-PROJECT is healty | 'Security Updates'=0;;;; 'Updates'=0;;;; 'Core Errors'=0;;;; 'Core Warnings'=0;;;; 'Database Migrations'=0;;;; 'OK'=1;;;0;1 'Errors'=0;1;1;0;1 'Warnings'=0;1;;0;1 'Unknown'=0;;;0;1 218 | ==== DB UPDATES ==== 219 | [OK] No database migrations required 220 | ``` 221 | 222 | ## 3. Nagios Configuration 223 | 224 | ### 3.1 check_drupal 225 | 226 | #### Command definition 227 | In order to check drupal sites on remote servers you will need to make use of `check_by_ssh`. 228 | ```bash 229 | name: check_by_ssh_drupal 230 | command: $USER1$/check_by_ssh -H $HOSTADDRESS$ -t 60 -l "$USER17$" -C "$USER22$/check_drupal -d $ARG1$ -n $ARG2$ $ARG3$" 231 | ``` 232 | #### Service definition 233 | In the above command definition there are two fixed arguments for the document root and the project name as well as one loose argument place holder that can hold all checks you want to run. The following shows one example service definition for one specific drupal site: 234 | ```bash 235 | check command: ssh_drupal_cool-drupal-project 236 | $ARG1$: /var/www/cool-drupal-project/drupal/ 237 | $ARG2$: Cool Drupal Project 238 | $ARG3$: -s e -u w -e e -w w -m e 239 | ``` 240 | The above service definition will check against security updates (with nagios error), against normal updates (with nagios warning), against core errors (with nagios error), against core warnings (with nagios warning) and finally against missed database migrations (with nagios error). 241 | 242 | ### 3.2 check_drupal_log 243 | 244 | #### Command definition 245 | In order to check drupal sites on remote servers you will need to make use of `check_by_ssh`. 246 | ```bash 247 | name: check_by_ssh_drupal 248 | command: $USER1$/check_by_ssh -H $HOSTADDRESS$ -t 60 -l "$USER17$" -C "$USER22$/check_drupal_log -f $ARG1$" 249 | ``` 250 | #### Service definition 251 | In the above command definition there is only one argument. This will point to the logfile created by `check_drupal`: 252 | ```bash 253 | check command: ssh_drupal_cool-drupal-project 254 | $ARG1$: /var/log/drupal_cool-project.log 255 | ``` 256 | 257 | #### Cron setup 258 | For this recommended setup to work you need to setup a cronjob on the target machine (where the drupal site is installed) that is run every 6 hours, every day or whatever you want. 259 | 260 | Setup multiple cronjobs with multiple logfiles if you have multiple drupal sites on this machine that you want to monitor. 261 | 262 | ```cron 263 | 0 */6 * * * /path/to/check_drupal -d /var/www/cool-drupal-project/drupal/ -n "Cool Project" -s e -u w -e e -w w -m e -l /var/log/drupal_cool-project.log 264 | ``` 265 | 266 | ## 4. Icinga2 Configuration 267 | 268 | ### 4.1 check_drupal 269 | 270 | #### Command definition 271 | Because icinga2 should be running on every monitored server, there is no need for `check_by_ssh`. 272 | 273 | ```bash 274 | object CheckCommand "check_drupal" { 275 | import "plugin-check-command" 276 | 277 | command = [ PluginDir + "/check_drupal" ] 278 | 279 | arguments = { 280 | "-d" = "$drupal_root$" 281 | "-n" = "$name$" 282 | "-s" = "$s$" 283 | "-u" = "$u$" 284 | "-e" = "$e$" 285 | "-w" = "$w$" 286 | "-m" = "$m$" 287 | } 288 | } 289 | ``` 290 | 291 | #### Service definition 292 | The following shows an example service definition for one specific drupal site: 293 | 294 | ```bash 295 | apply Service "check_cool-drupal-project" { 296 | import "generic-service" 297 | 298 | check_command = "check_drupal" 299 | 300 | vars.drupal_root = "/var/www/cool-drupal-project/drupal/" 301 | vars.name = "Cool Drupal Project" 302 | vars.s = "e" 303 | vars.u = "w" 304 | vars.e = "e" 305 | vars.w = "w" 306 | vars.m = "e" 307 | 308 | assign where host.name == NodeName 309 | } 310 | ``` 311 | 312 | The above service definition will check against security updates (with nagios error), against normal updates (with nagios warning), against core errors (with nagios error), against core warnings (with nagios warning) and finally against missed database migrations (with nagios error). 313 | 314 | ### 4.2 check_drupal_log 315 | 316 | #### Command definition 317 | ```bash 318 | object CheckCommand "check_drupal_log" { 319 | import "plugin-check-command" 320 | 321 | command = [ PluginDir + "/check_drupal_log" ] 322 | 323 | arguments = { 324 | "-f" = "$logfile$" 325 | } 326 | } 327 | ``` 328 | 329 | #### Service definition 330 | In the above command definition there is only one argument. This will point to the logfile created by `check_drupal`: 331 | 332 | ```bash 333 | apply Service for (logfile => config in host.vars.logfile) { 334 | import "generic-service" 335 | 336 | check_command = "check_drupal_log" 337 | 338 | vars += config 339 | } 340 | ``` 341 | 342 | The above service definition will look for multiple "vars.logfile" in your `host.conf`: 343 | 344 | ```bash 345 | vars.logfile["drupal name1"] = { logfile = "/var/log/check_drupal/name1.log" } 346 | vars.logfile["drupal name2"] = { logfile = "/var/log/check_drupal/name2.log" } 347 | vars.logfile["drupal name3"] = { logfile = "/var/log/check_drupal/name3.log" } 348 | ``` 349 | 350 | #### Cron setup 351 | For this recommended setup to work you need to setup a cronjob on the target machine (where the drupal site is installed) that is run every 6 hours, every day or whatever you want. 352 | 353 | Setup multiple cronjobs with multiple logfiles if you have multiple drupal sites on this machine that you want to monitor. 354 | 355 | ```cron 356 | 0 */6 * * * /path/to/check_drupal -d /var/www/cool-drupal-project/drupal/ -n "Cool Project" -s e -u w -e e -w w -m e -l /var/log/drupal_cool-project.log 357 | ``` 358 | 359 | ## 5. Performance data 360 | 361 | Screenshots taken from an [Icinga](https://www.icinga.org/) setup 362 | 363 | ### 5.1 Specific data 364 | The following performance data gives detailed information about specific errors/warnings that have occured 365 | ![PerfData](https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/01_sec-updates.png) 366 | ![PerfData](https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/02_updates.png) 367 | ![PerfData](https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/03_core-errors.png) 368 | ![PerfData](https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/04_core-warnings.png) 369 | ![PerfData](https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/05_db-migrations.png) 370 | 371 | ### 5.2 General data 372 | The following performance data gives a general overview about how many OK's, Errors, Warnings and Unknowns have happened over time. This way you can also see how quickly the reaction time has been to occured problems. 373 | 374 | **Best practise:** 375 | * OK: should always be a high vertical line 376 | * Error: Should only have short peaks 377 | * Warning: Should only have short peaks 378 | * Unknown: Should never happen 379 | ![PerfData](https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/06_ok.png) 380 | ![PerfData](https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/07_errors.png) 381 | ![PerfData](https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/08_warnings.png) 382 | ![PerfData](https://raw.githubusercontent.com/cytopia/check_drupal/master/doc/img/09_unknowns.png) 383 | 384 | 385 | ## 6. License 386 | [![license](https://poser.pugx.org/cytopia/check_drupal/license)](http://opensource.org/licenses/mit) 387 | 388 | ## 7. Awesome 389 | 390 | Added by the following [![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/sindresorhus/awesome) lists: 391 | 392 | * [awesome-nagios-plugins](https://github.com/cytopia/awesome-nagios-plugins) 393 | * [mrsinguyen/awesome-drupal](https://github.com/mrsinguyen/awesome-drupal) 394 | -------------------------------------------------------------------------------- /bin/check_drupal: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Nagios plugin to monitor the state of drupal sites. 4 | # 5 | 6 | ################################################################################ 7 | # 8 | # V A R I A B L E S 9 | # 10 | ################################################################################ 11 | 12 | # Some creds 13 | INFO_NAME="check_drupal" 14 | INFO_AUTHOR="cytopia " 15 | INFO_GPGKEY="0x695128A2" 16 | INFO_DATE="2019-03-19" 17 | INFO_LICENSE="MIT" 18 | INFO_VERSION="0.9" 19 | 20 | # Get the path 21 | export PATH="$PATH:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin" 22 | 23 | # Nagios error codes 24 | EXIT_OK=0 25 | EXIT_WARN=1 26 | EXIT_ERR=2 27 | EXIT_UNKNOWN=3 28 | 29 | 30 | # Locale command prefix 31 | if locale -a | grep 'en_US.UTF-8' > /dev/null 2>&1; then 32 | LOCALE="en_US.UTF-8" 33 | else 34 | LOCALE="C" 35 | fi 36 | 37 | # Might come in handy later 38 | #PHP_OPTS="-d intl.default_locale='en_US'" 39 | 40 | # Drush executeable 41 | DRUSH="$(which drush 2>/dev/null)" 42 | 43 | 44 | 45 | 46 | ################################################################################ 47 | # 48 | # F U N C T I O N S 49 | # 50 | ################################################################################ 51 | 52 | ############################################################ 53 | # Helper 54 | ############################################################ 55 | 56 | # Trim leading and trailing whitespace 57 | # @param string The input string 58 | # @output string The output string 59 | # @return 0 60 | trim() { 61 | _str="${1}" 62 | echo "${_str}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' 63 | } 64 | 65 | # Remove empty lines 66 | # @param string The input string 67 | # @output string The output string 68 | # @return 0 69 | trim_lines() { 70 | _str="${1}" 71 | echo "${_str}" | grep -v '^$' 72 | } 73 | 74 | # 75 | # Remove annoying BOM 76 | # 77 | remove_bom() { 78 | _str="${1}" 79 | echo "${_str}" | sed '1s/^\xEF\xBB\xBF//' 80 | } 81 | 82 | 83 | # Check for a valid severity and return the 84 | # appropriate nagios exit code 85 | # Allowed values: 'w' or 'e' 86 | # @param string The severity. 87 | # @output integer Nagios exit code 88 | # return integer 0: OK, 1: Wrong 89 | get_severity() { 90 | _code="${1}" 91 | 92 | if [ "${_code}" = "e" ]; then 93 | echo "$EXIT_ERR" 94 | return 0 95 | elif [ "${_code}" = "w" ]; then 96 | echo "$EXIT_WARN" 97 | return 0 98 | else 99 | return 1 100 | fi 101 | } 102 | 103 | 104 | 105 | # Aggregate nagios exit code. 106 | # OK < Warning < Error < Unknown 107 | # @param integer The current exit code. 108 | # @param integer The new exit code 109 | # @output integer The combined exit code 110 | # @return integer The combined exit code 111 | merge_exit_codes() { 112 | _curr_exit="$1" 113 | _next_exit="$2" 114 | 115 | # OK 116 | if [ "${_curr_exit}" = "0" ]; then 117 | _curr_exit="${_next_exit}" 118 | # Warning 119 | elif [ "${_curr_exit}" = "1" ]; then 120 | if [ "${_next_exit}" = "0" ]; then 121 | _curr_exit="1" 122 | elif [ "${_next_exit}" = "1" ]; then 123 | _curr_exit="1" 124 | elif [ "${_next_exit}" = "2" ]; then 125 | _curr_exit="2" 126 | elif [ "${_next_exit}" = "3" ]; then # UNKNOWN -> WARNING 127 | _curr_exit="1" 128 | fi 129 | # Error 130 | elif [ "${_curr_exit}" = "2" ]; then 131 | _curr_exit="2" 132 | # Unknown 133 | elif [ "${_curr_exit}" = "3" ]; then 134 | if [ "${_next_exit}" = "0" ]; then 135 | _curr_exit="3" 136 | elif [ "${_next_exit}" = "1" ]; then 137 | _curr_exit="1" 138 | elif [ "${_next_exit}" = "2" ]; then 139 | _curr_exit="2" 140 | elif [ "${_next_exit}" = "3" ]; then # UNKNOWN -> WARNING 141 | _curr_exit="3" 142 | fi 143 | fi 144 | echo "${_curr_exit}" 145 | return ${_curr_exit} 146 | } 147 | 148 | 149 | # Merge two texts with a delimiter 150 | # 151 | # @param string The current text 152 | # @param string The new text 153 | # @param string The separator 154 | # @output stringr The combined text 155 | merge_text() { 156 | _curr_text="$1" 157 | _next_text="$2" 158 | _separator="$3" 159 | 160 | if [ "$_separator" = "" ]; then 161 | _separator="\n" 162 | fi 163 | 164 | if [ "$_curr_text" = "" ]; then 165 | _curr_text="$_next_text" 166 | else 167 | _curr_text="${_curr_text}${_separator}${_next_text}" 168 | fi 169 | echo "${_curr_text}" 170 | } 171 | 172 | 173 | # Prepend each line with a prefix 174 | # @param string The text (multiline) 175 | # @param string The prefix to prepend to each lines 176 | # @outpt string The new string 177 | prepend_line() { 178 | _text="${1}" 179 | _prefix="${2}" 180 | 181 | echo "${_text}" | awk -v pre="${_prefix}" '{print pre""$0}' 182 | } 183 | 184 | ############################################################ 185 | # Drupal helper 186 | ############################################################ 187 | 188 | # Some hacky way to tell if it is the drupal 189 | # directory root. 190 | # @param string Path to Drupal root 191 | # @return integer 0: OK | 1: Not OK 192 | is_drupal_root() { 193 | # Test if directory exists 194 | if [ ! -d "${1}" ]; then 195 | return 1 196 | fi 197 | 198 | # Test for index.php 199 | if [ ! -f "${1}/index.php" ]; then 200 | return 1 201 | fi 202 | 203 | # Use drush to test root 204 | if ! drush -r "${1}" --uri="${2}" status | grep 'Drupal root' 1>/dev/null; then 205 | return 1 206 | fi 207 | return 0 208 | } 209 | 210 | # Create randomly named drushrc file 211 | # @output string Returns path to file on success 212 | # @return integer Success 213 | write_drushrc() { 214 | _ret=0 215 | 216 | # Generate random tmpfile 217 | if ! command -v mktemp >/dev/null 2>&1; then 218 | _rand="$(LC_ALL=C tr -dc 'a-z0-9' < /dev/urandom | head -c 32)" 219 | _file="/tmp/.drushrc.${_rand}" 220 | touch "${_file}" 221 | _ret=$? 222 | else 223 | _file="$(mktemp)" 224 | _ret=$? 225 | fi 226 | 227 | # Quit on error immediately 228 | if [ ${_ret} -ne 0 ]; then 229 | return ${_ret} 230 | fi 231 | 232 | # Write file 233 | { 234 | echo " 'en'," 238 | echo " 'name' => 'English'," 239 | echo " 'native' => 'English'," 240 | echo " 'direction' => '0'," 241 | echo " 'enabled' => 1," 242 | echo " 'plurals' => '0'," 243 | echo " 'formula' => ''," 244 | echo " 'domain' => ''," 245 | echo " 'prefix' => 'en'," 246 | echo " 'weight' => '0'," 247 | echo " 'javascript' => ''," 248 | echo ");" 249 | } > "${_file}" 250 | 251 | # Return filename 252 | echo "${_file}" 253 | return 0 254 | } 255 | 256 | 257 | # Removes the drushrc.php file from /tmp if it exists 258 | # @param string Path to drush file 259 | remove_drushrc() { 260 | _file="${1}" 261 | if [ -f "${_file}" ]; then 262 | rm -f "${_file}" 263 | fi 264 | } 265 | 266 | 267 | ############################################################ 268 | # Drush check functions 269 | ############################################################ 270 | 271 | # Check if security updates are required. 272 | # 273 | # @param string Path to Drupal root. 274 | # @param string Drupal multisite URI 275 | # @output string Drupal Security Updates. 276 | # @return integer Nagios exit code. 277 | check_security_updates() { 278 | 279 | _drupal_root="${1}" 280 | _multisite_uri="${2}" 281 | 282 | # No URI specified (single site) 283 | if [ -z "${_multisite_uri}" ]; then 284 | _updates="$(LC_MESSAGES=${LOCALE} ${DRUSH} --root="${_drupal_root}" pm-updatestatus --nocolor --security-only --format=csv --fields='name,installed version,proposed version,message' 2> /dev/null)" 285 | _ret=$? 286 | else 287 | _updates="$(LC_MESSAGES=${LOCALE} ${DRUSH} --root="${_drupal_root}" --uri="${_multisite_uri}" pm-updatestatus --nocolor --security-only --format=csv --fields='name,installed version,proposed version,message' 2> /dev/null)" 288 | _ret=$? 289 | fi 290 | 291 | # Error might have multiple causes... 292 | # Drupal database not connected? 293 | # Drupal root wrong? 294 | if [ ${_ret} -ne 0 ]; then 295 | return $EXIT_UNKNOWN 296 | fi 297 | 298 | # Remove via drush locked updates, keep the rest 299 | if [ "$LOCK" = "1" ]; then 300 | _updates="$(echo "${_updates}" | sed '/Locked\ via\ drush/d')" 301 | fi 302 | 303 | if [ "${_updates}" != "" ]; then 304 | # Format security updates 305 | # " -> " 306 | _updates="$(echo "${_updates}" | awk 'BEGIN {FS=","} ; { print $1" "$2" -> "$3 }')" 307 | 308 | # tango out 309 | echo "${_updates}" 310 | return $EXIT_ERR 311 | fi 312 | return $EXIT_OK 313 | } 314 | 315 | # Check if normal system updates are required. 316 | # 317 | # @param string Path to Drupal root. 318 | # @param string Drupal multisite URI 319 | # @output string Drupal System Updates. 320 | # @return integer Nagios exit code. 321 | check_system_updates() { 322 | 323 | _drupal_root="${1}" 324 | _multisite_uri="${2}" 325 | 326 | # read comma separated security updates 327 | # No URI specified (single site) 328 | if [ -z "${_multisite_uri}" ]; then 329 | _updates="$(LC_MESSAGES=${LOCALE} ${DRUSH} --root="${_drupal_root}" pm-updatestatus --nocolor --format=csv --fields='name,installed version,proposed version,message' 2> /dev/null)" 330 | _ret=$? 331 | else 332 | _updates="$(LC_MESSAGES=${LOCALE} ${DRUSH} --root="${_drupal_root}" --uri="${_multisite_uri}" pm-updatestatus --nocolor --format=csv --fields='name,installed version,proposed version,message' 2> /dev/null)" 333 | _ret=$? 334 | fi 335 | 336 | # Error might have multiple causes... 337 | # Drupal database not connected? 338 | # Drupal root wrong? 339 | if [ ${_ret} -ne 0 ]; then 340 | return $EXIT_UNKNOWN 341 | fi 342 | 343 | # Remove normal updates and only keep security updates 344 | _updates="$(echo "${_updates}" | grep -v 'SECURITY UPDATE')" 345 | 346 | # Remove via drush locked updates, keep the rest 347 | if [ "$LOCK" = "1" ]; then 348 | _updates="$(echo "${_updates}" | sed '/Locked\ via\ drush/d')" 349 | fi 350 | 351 | if [ "${_updates}" != "" ]; then 352 | # Format security updates 353 | # " -> " 354 | _updates="$(echo "${_updates}" | awk 'BEGIN {FS=","} ; { print $1" "$2" -> "$3 }')" 355 | 356 | # tango out 357 | echo "${_updates}" 358 | return $EXIT_ERR 359 | fi 360 | return $EXIT_OK 361 | } 362 | 363 | # Check if core errors are present. 364 | # 365 | # @param string Path to Drupal root. 366 | # @param string Drupal multisite URI 367 | # @output string Drupal Core errors. 368 | # @return integer Nagios exit code. 369 | check_core_errors() { 370 | 371 | _drupal_root="${1}" 372 | _multisite_uri="${2}" 373 | 374 | # read comma separated core errors 375 | # No URI specified (single site) 376 | if [ -z "${_multisite_uri}" ]; then 377 | _core_errors="$(LC_MESSAGES=${LOCALE} ${DRUSH} --root="${_drupal_root}" core-requirements --severity=2 --field-labels=0 --format=table --fields='severity,title' 2>/dev/null)" 378 | _ret=$? 379 | else 380 | _core_errors="$(LC_MESSAGES=${LOCALE} ${DRUSH} --root="${_drupal_root}" --uri="${_multisite_uri}" core-requirements --severity=2 --field-labels=0 --format=table --fields='severity,title' 2>/dev/null)" 381 | _ret=$? 382 | fi 383 | 384 | # Error might have multiple causes... 385 | # Drupal database not connected? 386 | # Drupal root wrong? 387 | if [ ${_ret} -ne 0 ]; then 388 | return $EXIT_UNKNOWN 389 | fi 390 | 391 | # Trim the string 392 | _core_errors="$(remove_bom "${_core_errors}")" 393 | _core_errors="$(trim_lines "${_core_errors}")" 394 | _core_errors="$(trim "${_core_errors}")" 395 | 396 | # Format output 397 | # "ERROR " 398 | if [ "${_core_errors}" != "" ]; then 399 | 400 | # Remove leading 'error' 401 | _core_errors="$(echo "${_core_errors}" | awk '{for (i=2; i/dev/null)" 426 | _ret=$? 427 | else 428 | _core_warnings="$(LC_MESSAGES=${LOCALE} ${DRUSH} --root="${_drupal_root}" --uri="${_multisite_uri}" core-requirements --severity=1 --no-field-labels --format=table --fields='severity,title' 2>/dev/null)" 429 | _ret=$? 430 | fi 431 | 432 | # Error might have multiple causes... 433 | # Drupal database not connected? 434 | # Drupal root wrong? 435 | if [ ${_ret} -ne 0 ]; then 436 | return $EXIT_UNKNOWN 437 | fi 438 | 439 | # Only keep "Warning" 440 | _core_warnings="$(echo "${_core_warnings}" | grep -E 'Warning')" 441 | 442 | # Trim the string 443 | _core_warnings="$(trim_lines "${_core_warnings}")" 444 | _core_warnings="$(trim "${_core_warnings}")" 445 | 446 | # Format output 447 | # "ERROR " 448 | if [ "${_core_warnings}" != "" ]; then 449 | 450 | # Remove leading 'error' 451 | _core_warnings="$(echo "${_core_warnings}" | awk '{for (i=2; i /dev/null)" 476 | _ret=$? 477 | else 478 | _updates="$(LC_MESSAGES=${LOCALE} ${DRUSH} --root="${_drupal_root}" --uri="${_multisite_uri}" pm-updatestatus --nocolor --no-field-labels --format=csv --fields='module,update_id' 2> /dev/null)" 479 | _ret=$? 480 | fi 481 | 482 | # Error might have multiple causes... 483 | # Drupal database not connected? 484 | # Drupal root wrong? 485 | if [ ${_ret} -ne 0 ]; then 486 | return $EXIT_UNKNOWN 487 | fi 488 | 489 | # Remove normal updates and only keep security updates 490 | _updates="$(echo "${_updates}" | grep -v 'SECURITY UPDATE')" 491 | 492 | 493 | if [ "${_updates}" != "" ]; then 494 | # Format security updates 495 | # " -> " 496 | _updates="$(echo "${_updates}" | awk 'BEGIN {FS=","} ; { print $1" "$2" -> "$3 }')" 497 | 498 | # tango out 499 | echo "${_updates}" 500 | return $EXIT_ERR 501 | fi 502 | return $EXIT_OK 503 | } 504 | 505 | 506 | ############################################################ 507 | # Program Functions 508 | ############################################################ 509 | 510 | # Give some creds 511 | # @output string The creds. 512 | # @return integer 0 513 | print_version() { 514 | printf "Name: %s\n" "${INFO_NAME}" 515 | printf "Version: %s (%s)\n" "${INFO_VERSION}" "${INFO_DATE}" 516 | printf "Author: %s (%s)\n" "${INFO_AUTHOR}" "${INFO_GPGKEY}" 517 | printf "License: %s\n" "${INFO_LICENSE}" 518 | return 0 519 | } 520 | 521 | # Check requirements. 522 | # @output string The requirements. 523 | # @return integer 0 on success, 2 on fail 524 | check() { 525 | if command -v drush > /dev/null 2>&1; then 526 | echo "[OK] drush found" 527 | return "$EXIT_ERR" 528 | else 529 | echo "[ERR] drush not found" 530 | return "$EXIT_OK" 531 | fi 532 | } 533 | 534 | # Usage 535 | # @output string The usage screen. 536 | # @return integer 0 537 | print_usage() { 538 | printf "Usage: %s -d [-n ] [-s ] [-u ] [-e ] [-w ] [-m ] [-i ] [-l ] [-r]\n" "${INFO_NAME}" 539 | printf "OR %s --check\n" "${INFO_NAME}" 540 | printf "OR %s --help\n" "${INFO_NAME}" 541 | printf "OR %s --version\n\n" "${INFO_NAME}" 542 | return 0 543 | } 544 | 545 | # Help 546 | # @output string The help screen. 547 | # @return integer 0 548 | print_help() { 549 | 550 | # Show usage first 551 | print_usage 552 | 553 | # Show help and details 554 | printf "Nagios plugin that will check drupal sites for errors.\n" 555 | printf "Errors include the following: available security updates,\n" 556 | printf "missed database migrations and drupal status errors.\n" 557 | printf "For each check you can specify the nagios severity (error or warning).\n\n" 558 | 559 | printf " -d The full path to the drupal document root (usually\n" 560 | printf " the 'drupal' folder. This parameter is required.\n\n" 561 | 562 | printf " -n [optional] Specify a name for the drupal instance to\n" 563 | printf " appear on the nagios output. The default is 'Drupal'\n\n" 564 | 565 | printf " -s [optional] Check for drupal core and module security\n" 566 | printf " updates and return nagios error or warning.\n" 567 | printf " Warning: -s w\n" 568 | printf " Error: -s e\n\n" 569 | 570 | printf " -u [optional] Check for drupal core and module updates\n" 571 | printf " in general and return nagios error or warning.\n" 572 | printf " Warning: -u w\n" 573 | printf " Error: -u e\n\n" 574 | 575 | printf " -e [optional] Check for drupal status errors and return\n" 576 | printf " nagios error or warning.\n" 577 | printf " Warning: -e w\n" 578 | printf " Error: -e e\n\n" 579 | 580 | printf " -w [optional] Check for drupal status warnings and return\n" 581 | printf " nagios error or warning.\n" 582 | printf " Warning: -w w\n" 583 | printf " Error: -w e\n\n" 584 | 585 | printf " -m [optional] Check for drupal missed database migrations\n" 586 | printf " and return nagios error or warning. (They can occur\n" 587 | printf " when you update core or modules and forget the db).\n" 588 | printf " Warning: -m w\n" 589 | printf " Error: -m e\n\n" 590 | 591 | printf " -i [optional] Parse in an url for a drupal multisite instance.\n" 592 | printf " 'drush --uri':\n" 593 | printf " In Drupal 7, the value of --uri should always be\n" 594 | printf " the same as when the site is being accessed from a web browser\n" 595 | printf " (e.g. http://mysite.org, although the http:// is optional).\n" 596 | printf " In Drupal 6, the value of --uri should always be the same as the\n" 597 | printf " site's folder name in the 'sites' folder (e.g. default); it is best\n" 598 | printf " if the site folder name matches the URI from the browser, and is consistent\n" 599 | printf " on every instance of the same site\n" 600 | printf " (e.g. also use sites/mysite.org for http://dev.mysite.org).\n\n" 601 | 602 | printf " -l [optional] Instead of checking all of the above via nagios\n" 603 | printf " every five minutes or so, run this script via cron once a day\n" 604 | printf " (or twice) and write the output into a logfile. This logfile can\n" 605 | printf " then be checked by the nagios plugin 'check_drupal_log' which is\n" 606 | printf " less costy in terms of load/cpu.\n" 607 | printf " See 'check_drupal_log --help' for more info.\n" 608 | printf " Example:\n" 609 | printf " check_drupal -d /var/www -s e -e e -w w -l /var/log/drupal.log\n" 610 | printf " check_drupal_log -l /var/log/drupal.log\n\n" 611 | 612 | printf " -r [optional] Filters all updates that are locked via drush.\n" 613 | printf " For general infos about locking run 'drush pm-updatestatus -h'\n\n" 614 | 615 | printf " --check Check for program requirements.\n" 616 | printf " --help Show this help\n" 617 | printf " --version Show version information.\n" 618 | return 0 619 | } 620 | 621 | 622 | 623 | ################################################################################ 624 | # 625 | # E N T R Y P O I N T 626 | # 627 | ################################################################################ 628 | 629 | ############################################################ 630 | # Check for --check, --help or --version arguments 631 | ############################################################ 632 | if [ "${1}" = "--check" ]; then 633 | check 634 | exit $EXIT_OK 635 | fi 636 | if [ "${1}" = "--help" ]; then 637 | print_help 638 | exit $EXIT_OK 639 | fi 640 | if [ "${1}" = "--version" ]; then 641 | print_version 642 | exit $EXIT_OK 643 | fi 644 | 645 | 646 | ############################################################ 647 | # Check requirements 648 | ############################################################ 649 | 650 | # Do we have 'drush'? 651 | if ! command -v drush > /dev/null 2>&1 ; then 652 | printf "[UNKNOWN] 'drush' not found.\n" 653 | exit $EXIT_UNKNOWN 654 | fi 655 | 656 | 657 | ############################################################ 658 | # Internal Variables 659 | ############################################################ 660 | 661 | # This will be filled in the the specified arguments. 662 | DRUPAL_NAME="Drupal" 663 | 664 | # Url for drupal multisite 665 | MULTISITE_URI="" 666 | 667 | # Extended Status Message 668 | MSG_SECURITY_UPDATE="" 669 | MSG_SYSTEM_UPDATE="" 670 | MSG_CORE_ERROR="" 671 | MSG_CORE_WARNING="" 672 | MSG_DB_UPDATE="" 673 | 674 | # Info for normal Status message if there is an error/warning 675 | CNT_SECURITY_UPDATE_ERROR="0" 676 | CNT_SYSTEM_UPDATE_ERROR="0" 677 | CNT_CORE_ERR_ERROR="0" 678 | CNT_CORE_WARN_ERROR="0" 679 | CNT_DB_UPDATE_ERROR="0" 680 | 681 | # Count warnings and errors for performance data 682 | CNT_ALL=0 683 | CNT_OK=0 684 | CNT_ERROR=0 685 | CNT_WARNING=0 686 | 687 | # Do we ignore locked updates? 688 | LOCK="0" 689 | 690 | # Final exit code 691 | NAGIOS_EXIT="${EXIT_OK}" 692 | 693 | 694 | ############################################################ 695 | # Retrieve arguments 696 | ############################################################ 697 | while test -n "$1"; do 698 | case "$1" in 699 | # ---- 1. Drupal root 700 | -d) 701 | # Get next arg in list (Path) 702 | shift 703 | DRUPAL_ROOT="$1" 704 | ;; 705 | # ---- 1. Drupal name 706 | -n) 707 | # Get next arg in list (Name) 708 | shift 709 | DRUPAL_NAME="$1" 710 | ;; 711 | # ---- 2. Security Updates 712 | -s) 713 | # Get next arg in list (Severity ) 714 | shift 715 | if ! CHECK_S="$(get_severity "$1")" > /dev/null 2>&1; then 716 | echo "Invalid value \"$1\" for option \"-s\"." 717 | exit $EXIT_UNKNOWN 718 | fi 719 | ;; 720 | # ---- 3. System Updates 721 | -u) 722 | # Get next arg in list (Severity ) 723 | shift 724 | if ! CHECK_U="$(get_severity "$1")" > /dev/null 2>&1; then 725 | echo "Invalid value \"$1\" for option \"-u\"." 726 | exit $EXIT_UNKNOWN 727 | fi 728 | ;; 729 | # ---- 5. Core errors 730 | -e) 731 | # Get next arg in list (Severity ) 732 | shift 733 | if ! CHECK_E="$(get_severity "$1")" > /dev/null 2>&1; then 734 | echo "Invalid value \"$1\" for option \"-e\"." 735 | exit $EXIT_UNKNOWN 736 | fi 737 | ;; 738 | # ---- 6. Core warnings 739 | -w) 740 | # Get next arg in list (Severity ) 741 | shift 742 | if ! CHECK_W="$(get_severity "$1")" > /dev/null 2>&1; then 743 | echo "Invalid value \"$1\" for option \"-w\"." 744 | exit $EXIT_UNKNOWN 745 | fi 746 | ;; 747 | # ---- 7. Missing DB updates 748 | -m) 749 | # Get next arg in list (Severity ) 750 | shift 751 | if ! CHECK_M="$(get_severity "$1")" > /dev/null 2>&1; then 752 | echo "Invalid value \"$1\" for option \"-m\"." 753 | exit $EXIT_UNKNOWN 754 | fi 755 | ;; 756 | # ---- 8. Do we have an URI for a multisite? 757 | -i) 758 | # Get next arg in list (URL) 759 | shift 760 | MULTISITE_URI="$1" 761 | ;; 762 | # ---- 9. Do we log to file? 763 | -l) 764 | # Get next arg in list (log file) 765 | shift 766 | LOGGING="$1" 767 | ;; 768 | # ---- 10. Do we skip locked updates? 769 | -r) 770 | LOCK="1" 771 | ;; 772 | *) 773 | printf "Unknown argument: %s\n" "$1" 774 | print_usage 775 | exit $EXIT_UNKNOWN 776 | ;; 777 | esac 778 | shift 779 | done 780 | 781 | # Use a drushrc.php file to set the language to english 782 | if ! DRUSHRC="$(write_drushrc)"; then 783 | printf "[UNKNOWN] Unable to create tmpfile\n" 784 | exit $EXIT_UNKNOWN 785 | fi 786 | 787 | DRUSH="${DRUSH} --config=${DRUSHRC}" 788 | 789 | 790 | ############################################################ 791 | # Validate arguments 792 | ############################################################ 793 | 794 | # -d is mandatory!!! 795 | if [ -z "$DRUPAL_ROOT" ]; then 796 | printf "[UNKNOWN] Drupal root parameter '-d' not specified.\n" 797 | print_usage 798 | exit $EXIT_UNKNOWN 799 | fi 800 | 801 | # Check if it is a valid drupal doc root 802 | if ! is_drupal_root "${DRUPAL_ROOT}" "${MULTISITE_URI}" > /dev/null 2>&1; then 803 | echo "[UNKNOWN] '${DRUPAL_ROOT}' is not a valid drupal root directory." 804 | exit $EXIT_UNKNOWN 805 | fi 806 | 807 | # Are we logging? 808 | if [ -n "$LOGGING" ]; then 809 | 810 | # Does the log file exist? 811 | if [ -f "$LOGGING" ]; then 812 | # Is it writeable? 813 | if [ ! -w "$LOGGING" ]; then 814 | printf "[UNKNOWN] Logfile not writeable: %s\n" "${LOGGING}" 815 | exit $EXIT_UNKNOWN 816 | fi 817 | else 818 | # Create the file 819 | if ! touch "${LOGGING}" > /dev/null 2>&1; then 820 | printf "[UNKNOWN] Unable to create logfile in %s\n" "${LOGGING}" 821 | exit $EXIT_UNKNOWN 822 | fi 823 | fi 824 | fi 825 | 826 | 827 | ############################################################ 828 | # Go Go Go!!!! 829 | ############################################################ 830 | 831 | 832 | #### 1. Check for Drupal Security Updates 833 | if [ -n "$CHECK_S" ]; then 834 | 835 | SEVERITY="$CHECK_S" 836 | 837 | # Execute Command 838 | MSG_SECURITY_UPDATE="$(check_security_updates "${DRUPAL_ROOT}" "${MULTISITE_URI}")" 839 | TMP_EXIT="$?" 840 | 841 | # Merge exit codes 842 | if [ "$TMP_EXIT" != "0" ]; then 843 | # Count lines as number of issues 844 | CNT_SECURITY_UPDATE_ERROR="$(echo "${MSG_SECURITY_UPDATE}" | wc -l | xargs)" 845 | 846 | if [ "$SEVERITY" = "$EXIT_ERR" ]; then 847 | CNT_ERROR=$((CNT_ERROR+1)) 848 | MSG_SECURITY_UPDATE="$(prepend_line "${MSG_SECURITY_UPDATE}" "[CRITICAL] ")" 849 | MSG_SECURITY_UPDATE="==== SECURITY UPDATES ====\n${MSG_SECURITY_UPDATE}" 850 | NAGIOS_EXIT="$(merge_exit_codes "$NAGIOS_EXIT" "2")" 851 | else 852 | CNT_WARNING=$((CNT_WARNING+1)) 853 | MSG_SECURITY_UPDATE="$(prepend_line "${MSG_SECURITY_UPDATE}" "[WARNING] ")" 854 | MSG_SECURITY_UPDATE="==== SECURITY UPDATES ====\n${MSG_SECURITY_UPDATE}" 855 | NAGIOS_EXIT="$(merge_exit_codes "$NAGIOS_EXIT" "1")" 856 | fi 857 | else 858 | CNT_OK=$((CNT_OK+1)) 859 | MSG_SECURITY_UPDATE="==== SECURITY UPDATES ====\n[OK] No Security updates required" 860 | NAGIOS_EXIT="$(merge_exit_codes "$NAGIOS_EXIT" "0")" 861 | fi 862 | CNT_ALL=$((CNT_ALL+1)) 863 | 864 | fi 865 | 866 | 867 | #### 2. Check for Drupal normal Updates 868 | if [ -n "$CHECK_U" ]; then 869 | 870 | SEVERITY="$CHECK_U" 871 | 872 | # Execute Command 873 | MSG_SYSTEM_UPDATE="$(check_system_updates "${DRUPAL_ROOT}" "${MULTISITE_URI}")" 874 | TMP_EXIT="$?" 875 | 876 | # Merge exit codes 877 | if [ "$TMP_EXIT" != "0" ]; then 878 | # Count lines as number of issues 879 | CNT_SYSTEM_UPDATE_ERROR="$(echo "${MSG_SYSTEM_UPDATE}" | wc -l | xargs)" 880 | 881 | if [ "$SEVERITY" = "$EXIT_ERR" ]; then 882 | CNT_ERROR=$((CNT_ERROR+1)) 883 | MSG_SYSTEM_UPDATE="$(prepend_line "${MSG_SYSTEM_UPDATE}" "[CRITICAL] ")" 884 | MSG_SYSTEM_UPDATE="==== SYSTEM UPDATES ====\n${MSG_SYSTEM_UPDATE}" 885 | NAGIOS_EXIT="$(merge_exit_codes "$NAGIOS_EXIT" "2")" 886 | else 887 | CNT_WARNING=$((CNT_WARNING+1)) 888 | MSG_SYSTEM_UPDATE="$(prepend_line "${MSG_SYSTEM_UPDATE}" "[WARNING] ")" 889 | MSG_SYSTEM_UPDATE="==== SYSTEM UPDATES ====\n${MSG_SYSTEM_UPDATE}" 890 | NAGIOS_EXIT="$(merge_exit_codes "$NAGIOS_EXIT" "1")" 891 | fi 892 | else 893 | CNT_OK=$((CNT_OK+1)) 894 | MSG_SYSTEM_UPDATE="==== SYSTEM UPDATES ====\n[OK]\nNo Updates required" 895 | NAGIOS_EXIT="$(merge_exit_codes "$NAGIOS_EXIT" "0")" 896 | fi 897 | CNT_ALL=$((CNT_ALL+1)) 898 | 899 | fi 900 | 901 | 902 | #### 3. Check for Drupal core errors 903 | if [ -n "$CHECK_E" ]; then 904 | 905 | SEVERITY="$CHECK_E" 906 | 907 | # Execute Command 908 | MSG_CORE_ERROR="$(check_core_errors "${DRUPAL_ROOT}" "${MULTISITE_URI}")" 909 | TMP_EXIT="$?" 910 | 911 | # Merge exit codes 912 | if [ "$TMP_EXIT" != "0" ]; then 913 | # Count lines as number of issues 914 | CNT_CORE_ERR_ERROR="$(echo "${MSG_CORE_ERROR}" | wc -l | xargs)" 915 | 916 | if [ "$SEVERITY" = "$EXIT_ERR" ]; then 917 | CNT_ERROR=$((CNT_ERROR+1)) 918 | MSG_CORE_ERROR="$(prepend_line "${MSG_CORE_ERROR}" "[CRITICAL] ")" 919 | MSG_CORE_ERROR="==== CORE ERRORS ====\n${MSG_CORE_ERROR}" 920 | NAGIOS_EXIT="$(merge_exit_codes "$NAGIOS_EXIT" "2")" 921 | else 922 | CNT_WARNING=$((CNT_WARNING+1)) 923 | MSG_CORE_ERROR="$(prepend_line "${MSG_CORE_ERROR}" "[WARNING] ")" 924 | MSG_CORE_ERROR="==== CORE ERRORS ====\n${MSG_CORE_ERROR}" 925 | NAGIOS_EXIT="$(merge_exit_codes "$NAGIOS_EXIT" "1")" 926 | fi 927 | else 928 | CNT_OK=$((CNT_OK+1)) 929 | MSG_CORE_ERROR="==== CORE ERRORS ====\n[OK] No core errors" 930 | NAGIOS_EXIT="$(merge_exit_codes "$NAGIOS_EXIT" "0")" 931 | fi 932 | CNT_ALL=$((CNT_ALL+1)) 933 | 934 | fi 935 | 936 | 937 | #### 4. Check for Drupal core warnings 938 | if [ -n "$CHECK_W" ]; then 939 | 940 | SEVERITY="$CHECK_W" 941 | 942 | # Execute Command 943 | MSG_CORE_WARNING="$(check_core_warnings "${DRUPAL_ROOT}" "${MULTISITE_URI}")" 944 | TMP_EXIT="$?" 945 | 946 | # Merge exit codes 947 | if [ "$TMP_EXIT" != "0" ]; then 948 | # Count lines as number of issues 949 | CNT_CORE_WARN_ERROR="$(echo "${MSG_CORE_WARNING}" | wc -l | xargs)" 950 | 951 | if [ "$SEVERITY" = "$EXIT_ERR" ]; then 952 | CNT_ERROR=$((CNT_ERROR+1)) 953 | MSG_CORE_WARNING="$(prepend_line "${MSG_CORE_WARNING}" "[CRITICAL] ")" 954 | MSG_CORE_WARNING="==== CORE WARNINGS ====\n${MSG_CORE_WARNING}" 955 | NAGIOS_EXIT="$(merge_exit_codes "$NAGIOS_EXIT" "2")" 956 | else 957 | CNT_WARNING=$((CNT_WARNING+1)) 958 | MSG_CORE_WARNING="$(prepend_line "${MSG_CORE_WARNING}" "[WARNING] ")" 959 | MSG_CORE_WARNING="==== CORE WARNINGS ====\n${MSG_CORE_WARNING}" 960 | NAGIOS_EXIT="$(merge_exit_codes "$NAGIOS_EXIT" "1")" 961 | fi 962 | else 963 | CNT_OK=$((CNT_OK+1)) 964 | MSG_CORE_WARNING="==== CORE WARNINGS ====\n[OK] No core warnings" 965 | NAGIOS_EXIT="$(merge_exit_codes "$NAGIOS_EXIT" "0")" 966 | fi 967 | CNT_ALL=$((CNT_ALL+1)) 968 | 969 | fi 970 | 971 | 972 | #### 5. Check for Drupal missing db updates 973 | if [ -n "$CHECK_M" ]; then 974 | 975 | SEVERITY="$CHECK_M" 976 | 977 | # Execute Command 978 | MSG_DB_UPDATE="$(check_db_updates "${DRUPAL_ROOT}" "${MULTISITE_URI}")" 979 | TMP_EXIT="$?" 980 | 981 | # Merge exit codes 982 | if [ "$TMP_EXIT" != "0" ]; then 983 | # Count lines as number of issues 984 | CNT_DB_UPDATE_ERROR="$(echo "${MSG_DB_UPDATE}" | wc -l | xargs)" 985 | 986 | if [ "$SEVERITY" = "$EXIT_ERR" ]; then 987 | CNT_ERROR=$((CNT_ERROR+1)) 988 | MSG_DB_UPDATE="$(prepend_line "${MSG_DB_UPDATE}" "[CRITICAL] ")" 989 | MSG_DB_UPDATE="==== DB UPDATES ====\n${MSG_DB_UPDATE}" 990 | NAGIOS_EXIT="$(merge_exit_codes "$NAGIOS_EXIT" "2")" 991 | else 992 | CNT_WARNING=$((CNT_WARNING+1)) 993 | MSG_DB_UPDATE="$(prepend_line "${MSG_DB_UPDATE}" "[WARNING] ")" 994 | MSG_DB_UPDATE="==== DB UPDATES ====\n${MSG_DB_UPDATE}" 995 | NAGIOS_EXIT="$(merge_exit_codes "$NAGIOS_EXIT" "1")" 996 | fi 997 | else 998 | CNT_OK=$((CNT_OK+1)) 999 | MSG_DB_UPDATE="==== DB UPDATES ====\n[OK] No database migrations required" 1000 | NAGIOS_EXIT="$(merge_exit_codes "$NAGIOS_EXIT" "0")" 1001 | fi 1002 | CNT_ALL=$((CNT_ALL+1)) 1003 | 1004 | fi 1005 | 1006 | 1007 | 1008 | ############################################################ 1009 | # Cleanup 1010 | ############################################################ 1011 | 1012 | # Remove temporary file 1013 | remove_drushrc "${DRUSHRC}" 1014 | 1015 | 1016 | 1017 | ############################################################ 1018 | # Eval results 1019 | ############################################################ 1020 | 1021 | #### Build status text 1022 | INFO="" 1023 | if [ "$CNT_SECURITY_UPDATE_ERROR" != "0" ]; then 1024 | if [ "$CNT_SECURITY_UPDATE_ERROR" = "1" ]; then 1025 | INFO="$(merge_text "${INFO}" "1 Security update" ", ")" 1026 | else 1027 | INFO="$(merge_text "${INFO}" "${CNT_SECURITY_UPDATE_ERROR} Security updates" ", ")" 1028 | fi 1029 | fi 1030 | if [ "$CNT_SYSTEM_UPDATE_ERROR" != "0" ]; then 1031 | if [ "$CNT_SYSTEM_UPDATE_ERROR" = "1" ]; then 1032 | INFO="$(merge_text "${INFO}" "1 Update" ", ")" 1033 | else 1034 | INFO="$(merge_text "${INFO}" "${CNT_SYSTEM_UPDATE_ERROR} Updates" ", ")" 1035 | fi 1036 | fi 1037 | if [ "$CNT_CORE_ERR_ERROR" != "0" ]; then 1038 | if [ "$CNT_CORE_ERR_ERROR" = "1" ]; then 1039 | INFO="$(merge_text "${INFO}" "1 Core error" ", ")" 1040 | else 1041 | INFO="$(merge_text "${INFO}" "${CNT_CORE_ERR_ERROR} Core errors" ", ")" 1042 | fi 1043 | fi 1044 | if [ "$CNT_CORE_WARN_ERROR" != "0" ]; then 1045 | if [ "$CNT_CORE_WARN_ERROR" = "1" ]; then 1046 | INFO="$(merge_text "${INFO}" "1 Core warning" ", ")" 1047 | else 1048 | INFO="$(merge_text "${INFO}" "${CNT_CORE_WARN_ERROR} Core warnings" ", ")" 1049 | fi 1050 | fi 1051 | if [ "$CNT_DB_UPDATE_ERROR" != "0" ]; then 1052 | if [ "$CNT_DB_UPDATE_ERROR" = "1" ]; then 1053 | INFO="$(merge_text "${INFO}" "1 DB migration" ", ")" 1054 | else 1055 | INFO="$(merge_text "${INFO}" "${CNT_DB_UPDATE_ERROR} DB migrations" ", ")" 1056 | fi 1057 | fi 1058 | 1059 | #### Short output (std status) 1060 | OUTPUT="" 1061 | if [ "$NAGIOS_EXIT" = "$EXIT_OK" ]; then 1062 | OUTPUT="$(printf "[OK] %s is healthy" "${DRUPAL_NAME}")" 1063 | elif [ "$NAGIOS_EXIT" = "$EXIT_WARN" ]; then 1064 | OUTPUT="$(printf "[WARNING] %s has warnings: %s" "${DRUPAL_NAME}" "${INFO}")" 1065 | elif [ "$NAGIOS_EXIT" = "$EXIT_ERR" ]; then 1066 | OUTPUT="$(printf "[CRITICAL] %s has errors: %s" "${DRUPAL_NAME}" "${INFO}")" 1067 | else 1068 | OUTPUT="$(printf "[UNKNOWN] %s is at unknown state - check extended info" "${DRUPAL_NAME}")" 1069 | fi 1070 | 1071 | 1072 | #### Performance Data 1073 | # @see http://docs.icinga.org/latest/en/perfdata.html 1074 | # 'label'=value[UOM];[warn];[crit];[min];[max] 1075 | PERF="" 1076 | PERF="$(printf "%s'Security Updates'=%d;;;; " "${PERF}" "${CNT_SECURITY_UPDATE_ERROR}")" 1077 | PERF="$(printf "%s'Updates'=%d;;;; " "${PERF}" "${CNT_SYSTEM_UPDATE_ERROR}")" 1078 | PERF="$(printf "%s'Core Errors'=%d;;;; " "${PERF}" "${CNT_CORE_ERR_ERROR}")" 1079 | PERF="$(printf "%s'Core Warnings'=%d;;;; " "${PERF}" "${CNT_CORE_WARN_ERROR}")" 1080 | PERF="$(printf "%s'Database Migrations'=%d;;;; " "${PERF}" "${CNT_DB_UPDATE_ERROR}")" 1081 | 1082 | PERF="$(printf "%s'OK'=%d;;;0;%d " "${PERF}" "${CNT_OK}" "${CNT_ALL}")" 1083 | PERF="$(printf "%s'Errors'=%d;1;1;0;%d " "${PERF}" "${CNT_ERROR}" "${CNT_ALL}")" 1084 | PERF="$(printf "%s'Warnings'=%d;1;;0;%d " "${PERF}" "${CNT_WARNING}" "${CNT_ALL}")" 1085 | PERF="$(printf "%s'Unknown'=0;;;0;%d " "${PERF}" "${CNT_ALL}")" 1086 | 1087 | 1088 | #### Extended status data 1089 | if [ "$MSG_SECURITY_UPDATE" != "" ]; then E_OUTPUT="$(merge_text "${E_OUTPUT}" "${MSG_SECURITY_UPDATE}" "\n")"; fi 1090 | if [ "$MSG_SYSTEM_UPDATE" != "" ]; then E_OUTPUT="$(merge_text "${E_OUTPUT}" "${MSG_SYSTEM_UPDATE}" "\n")"; fi 1091 | if [ "$MSG_CORE_ERROR" != "" ]; then E_OUTPUT="$(merge_text "${E_OUTPUT}" "${MSG_CORE_ERROR}" "\n")"; fi 1092 | if [ "$MSG_CORE_WARNING" != "" ]; then E_OUTPUT="$(merge_text "${E_OUTPUT}" "${MSG_CORE_WARNING}" "\n")"; fi 1093 | if [ "$MSG_DB_UPDATE" != "" ]; then E_OUTPUT="$(merge_text "${E_OUTPUT}" "${MSG_DB_UPDATE}" "\n")"; fi 1094 | 1095 | 1096 | #### Log to file? 1097 | if [ -n "$LOGGING" ]; then 1098 | echo "${OUTPUT} | ${PERF}" > "$LOGGING" 1099 | echo "${E_OUTPUT}" >> "$LOGGING" 1100 | echo "${NAGIOS_EXIT}" >> "$LOGGING" 1101 | exit 0 1102 | else 1103 | echo "${OUTPUT} | ${PERF}" 1104 | echo "${E_OUTPUT}" 1105 | exit "$NAGIOS_EXIT" 1106 | fi 1107 | 1108 | 1109 | # " vim: set ts=4: 1110 | 1111 | --------------------------------------------------------------------------------