From 4a4ecc60b0f8584fee9c54307f1f8db558ebc47a Mon Sep 17 00:00:00 2001 From: madflojo Date: Sat, 22 Oct 2016 20:08:15 -0700 Subject: [PATCH 1/4] Adding mysql status metrics health check --- docs/plugins/checks/mysql/status_metrics.md | 26 ++++++ mkdocs.yml | 2 + plugins/checks/mysql/status_metrics.py | 88 +++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 docs/plugins/checks/mysql/status_metrics.md create mode 100644 plugins/checks/mysql/status_metrics.py diff --git a/docs/plugins/checks/mysql/status_metrics.md b/docs/plugins/checks/mysql/status_metrics.md new file mode 100644 index 0000000..a6d7915 --- /dev/null +++ b/docs/plugins/checks/mysql/status_metrics.md @@ -0,0 +1,26 @@ +The `status_metrics` plugin is used to query MySQL's internal status system and alert when the defined `metric` exceeds the `warning` and `critical` thresholds. + +## Runbook Example + +The below is an example of using the `status_metrics` health check in a runbook. + +```yaml +checks: + status_metrics: + execute_from: ontarget + type: plugin + plugin: mysql/status_metrics.py + args: --warn=20 --critical=10 --metric=slow_queries --host=localhost --user=USERNAME --password=YOURPASSWORD --type=greater +``` + +This plugin can be executed from either `ontarget` or `remote` depending on the MySQL service's configuration. + +### Required arguments + +The `mysql/status_metrics` plugin requires 7 arguments. + +```yaml +args: -w -c -t {greater, lesser} -m -s -u -p +``` + +The `type` flag is used to define whether or not the alert is triggered when the `metric` value is "greater" or "lesser" than the values defined as `warn` and `critical`. diff --git a/mkdocs.yml b/mkdocs.yml index 2e369ef..d855381 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -21,6 +21,8 @@ pages: - Web Ping: plugins/discovery/webping.md - Digital Ocean: plugins/discovery/digitalocean.md - Checks: + - MySQL: + - Status Metrics: plugins/checks/mysql/status_metrics.md - Systems: - Disk Free: plugins/checks/systems/disk_free.md - Memory Free: plugins/checks/systems/mem_free.md diff --git a/plugins/checks/mysql/status_metrics.py b/plugins/checks/mysql/status_metrics.py new file mode 100644 index 0000000..4700df5 --- /dev/null +++ b/plugins/checks/mysql/status_metrics.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python + +import pymysql +import sys +import argparse + +def get_status(args): + ''' Pull the status values from MySQL ''' + status = {} + try: + db = pymysql.connect( + host=args.host, + user=args.user, + password=args.password, + cursorclass=pymysql.cursors.DictCursor) + except: #pylint disable=broad-except + return False + + try: + with db.cursor() as cursor: + # Get Status + cursor.execute("show status") + for result in cursor.fetchall(): + try: + status[result['Variable_name'].lower()] = int(result['Value']) + except: #pylint disable=broad-except + pass + finally: + db.close() + + return status + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument( + "-w", "--warn", type=float, + help="Warning threshold value", required=True) + parser.add_argument( + "-c", "--critical", type=float, + help="Critical threshold value", required=True) + parser.add_argument( + "-m", "--metric", + help="Metric to validate (i.e. slow-queries)", required=True) + parser.add_argument( + "-s", "--host", + help="MySQL Host", required=True) + parser.add_argument( + "-u", "--user", + help="MySQL User", required=True) + parser.add_argument( + "-p", "--password", + help="MySQL User Password", required=True) + parser.add_argument( + "-t", "--type", + help="Alert if metric's value is greater or lesser than thresholds", + choices=('greater', 'lesser'), + required=True) + args = parser.parse_args() + metric = args.metric.lower() + + + # Get status + status = get_status(args) + alert = "OK" + exit_code = 0 + + if status and metric in status.keys(): + if args.type == "greater": + if args.warn < status[metric]: + alert = "WARNING" + exit_code = 1 + if args.critical < status[metric]: + alert = "CRITICAL" + exit_code = 2 + else: + if args.warn > status[metric]: + alert = "WARNING" + exit_code = 1 + if args.critical > status[metric]: + alert = "CRITICAL" + exit_code = 2 + else: + print "Could not pull stats from MySQL" + sys.exit(3) + + print "MYSQL_STATUS_HEALTH {0} {1} {2}".format(alert, metric, status[metric]) + sys.exit(exit_code) From 778eee4c6f184c667ad6ce43c1fddb559886e9f0 Mon Sep 17 00:00:00 2001 From: madflojo Date: Sun, 23 Oct 2016 14:44:22 -0700 Subject: [PATCH 2/4] Adding MySQL Availability Plugin --- docs/plugins/checks/mysql/available.md | 26 +++++++++++ mkdocs.yml | 1 + plugins/checks/mysql/available.py | 61 ++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 docs/plugins/checks/mysql/available.md create mode 100644 plugins/checks/mysql/available.py diff --git a/docs/plugins/checks/mysql/available.md b/docs/plugins/checks/mysql/available.md new file mode 100644 index 0000000..da644fd --- /dev/null +++ b/docs/plugins/checks/mysql/available.md @@ -0,0 +1,26 @@ +The `available` plugin is used to query MySQL's internal status system and determine whether the MySQL service is available or not. + +## Runbook Example + +The below is an example of using the `mysql/available` health check in a runbook. + +```yaml +checks: + mysql_up: + execute_from: ontarget + type: plugin + plugin: mysql/available.py + args: --host=localhost --user=USERNAME --password=YOURPASSWORD +``` + +This plugin can be executed from either `ontarget` or `remote` depending on the MySQL service's configuration. + +### Required arguments + +The `mysql/available` plugin requires 3 arguments. + +```yaml +args: -s -u -p +``` + +If the `show status` query is unsuccessful or does not find the key it is looking for the check will return a `CRITICAL` status. There is no `WARNING` or `UNKNOWN` status for this check. diff --git a/mkdocs.yml b/mkdocs.yml index d855381..7c14b8b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -22,6 +22,7 @@ pages: - Digital Ocean: plugins/discovery/digitalocean.md - Checks: - MySQL: + - Available: plugins/checks/mysql/available.md - Status Metrics: plugins/checks/mysql/status_metrics.md - Systems: - Disk Free: plugins/checks/systems/disk_free.md diff --git a/plugins/checks/mysql/available.py b/plugins/checks/mysql/available.py new file mode 100644 index 0000000..952df4b --- /dev/null +++ b/plugins/checks/mysql/available.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python + +import pymysql +import sys +import argparse + +def get_status(args): + ''' Pull the status values from MySQL ''' + status = {} + try: + db = pymysql.connect( + host=args.host, + user=args.user, + password=args.password, + cursorclass=pymysql.cursors.DictCursor) + except: #pylint disable=broad-except + return False + + try: + with db.cursor() as cursor: + # Get Status + cursor.execute("show status") + for result in cursor.fetchall(): + try: + status[result['Variable_name']] = int(result['Value']) + except: #pylint disable=broad-except + pass + finally: + db.close() + + if "Uptime" in status.keys(): + return status['Uptime'] + else: + return False + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument( + "-s", "--host", + help="MySQL Host", required=True) + parser.add_argument( + "-u", "--user", + help="MySQL User", required=True) + parser.add_argument( + "-p", "--password", + help="MySQL User Password", required=True) + args = parser.parse_args() + + + if get_status(args): + alert = "OK" + status = "UP" + exit_code = 0 + else: + alert = "CRITICAL" + status = "DOWN" + exit_code = 2 + + print "MYSQL_AVAILABLE {0} {1}".format(alert, status) + sys.exit(exit_code) From 09c628a2e6d8ee9e15d3722d2061a55408e0d349 Mon Sep 17 00:00:00 2001 From: madflojo Date: Sun, 23 Oct 2016 19:55:29 -0700 Subject: [PATCH 3/4] Adding TCP Health Check --- docs/plugins/checks/network/tcp_connect.md | 26 +++++++++++++ mkdocs.yml | 2 + plugins/checks/network/tcp_connect.py | 45 ++++++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 docs/plugins/checks/network/tcp_connect.md create mode 100644 plugins/checks/network/tcp_connect.py diff --git a/docs/plugins/checks/network/tcp_connect.md b/docs/plugins/checks/network/tcp_connect.md new file mode 100644 index 0000000..de2a9c3 --- /dev/null +++ b/docs/plugins/checks/network/tcp_connect.md @@ -0,0 +1,26 @@ +The `tcp_connect` plugin is used to identify if a `host` or `ip` is listening on a specified `port`. This is a simple check that is either `OK` for successful connections or `CRITICAL` for unsuccessful connections. + +## Runbook Example + +The below is an example of using the `network/tcp_connect` health check in a runbook. + +```yaml +checks: + mysql_up: + execute_from: ontarget + type: plugin + plugin: mysql/available.py + args: --host=localhost --port 3306 +``` + +This plugin can be executed from either `ontarget` or `remote` depending on the MySQL service's configuration. + +### Required arguments + +The `mysql/available` plugin requires 2 arguments. + +```yaml +args: -i -p [-t ] +``` + +The third value `-t` is an optional value, default is **5 seconds**. diff --git a/mkdocs.yml b/mkdocs.yml index 7c14b8b..6f760df 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -21,6 +21,8 @@ pages: - Web Ping: plugins/discovery/webping.md - Digital Ocean: plugins/discovery/digitalocean.md - Checks: + - Network: + - TCP Connection: plugins/checks/network/tcp_connect.md - MySQL: - Available: plugins/checks/mysql/available.md - Status Metrics: plugins/checks/mysql/status_metrics.md diff --git a/plugins/checks/network/tcp_connect.py b/plugins/checks/network/tcp_connect.py new file mode 100644 index 0000000..febb1c2 --- /dev/null +++ b/plugins/checks/network/tcp_connect.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +import socket +import argparse +import sys + +def check_connection(args): + ''' Open TCP Connection and Return if successful ''' + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.settimeout(args.timeout) + try: + return not bool(s.connect_ex((args.host, args.port))) + except socket.error: + return False + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument( + "-i", "--host", + help="IP or Host Address", required=True) + parser.add_argument( + "-p", "--port", + help="Port", + type=int, + required=True) + parser.add_argument( + "-t", "--timeout", + help="Timeout in seconds", + type=int, + required=False, + default=5 + ) + args = parser.parse_args() + + if check_connection(args): + alert = "OK" + status = "UP" + exit_code = 0 + else: + alert = "CRITICAL" + status = "DOWN" + exit_code = 2 + + print "TCP_CONNECT {0} {1}".format(alert, status) + sys.exit(exit_code) From a5a5b64f7cac6ec3e86fa7962f372dda511a3301 Mon Sep 17 00:00:00 2001 From: madflojo Date: Sun, 23 Oct 2016 20:39:29 -0700 Subject: [PATCH 4/4] Adding remote host ping plugin --- docs/plugins/checks/network/ping.md | 26 +++++++++++++ docs/plugins/checks/network/tcp_connect.md | 6 +-- mkdocs.yml | 1 + plugins/checks/network/ping.sh | 45 ++++++++++++++++++++++ 4 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 docs/plugins/checks/network/ping.md create mode 100644 plugins/checks/network/ping.sh diff --git a/docs/plugins/checks/network/ping.md b/docs/plugins/checks/network/ping.md new file mode 100644 index 0000000..3de44b3 --- /dev/null +++ b/docs/plugins/checks/network/ping.md @@ -0,0 +1,26 @@ +The `ping` plugin is used to identify if a `host` is online by sending an ICMP packet. This plugin uses `bash` and the `ping` command, which should work on most Unix and Linux systems. + +## Runbook Example + +The below is an example of using the `network/ping` health check in a runbook. + +```yaml +checks: + host_up: + execute_from: remote + type: plugin + plugin: network/ping.sh + args: -i 10.0.0.1 +``` + +This plugin can be executed from either `ontarget` or `remote` depending on the goal of the runbook. + +### Required arguments + +The `network/ping` plugin requires 1 argument. + +```yaml +args: -i [-t ] +``` + +The second value `-t` is an optional value, default is **3 seconds**. diff --git a/docs/plugins/checks/network/tcp_connect.md b/docs/plugins/checks/network/tcp_connect.md index de2a9c3..cd823ee 100644 --- a/docs/plugins/checks/network/tcp_connect.md +++ b/docs/plugins/checks/network/tcp_connect.md @@ -9,15 +9,15 @@ checks: mysql_up: execute_from: ontarget type: plugin - plugin: mysql/available.py + plugin: network/tcp_connect.py args: --host=localhost --port 3306 ``` -This plugin can be executed from either `ontarget` or `remote` depending on the MySQL service's configuration. +This plugin can be executed from either `ontarget` or `remote` depending on the target being monitored. ### Required arguments -The `mysql/available` plugin requires 2 arguments. +The `network/tcp_connect` plugin requires 2 arguments. ```yaml args: -i -p [-t ] diff --git a/mkdocs.yml b/mkdocs.yml index 6f760df..240cae0 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -22,6 +22,7 @@ pages: - Digital Ocean: plugins/discovery/digitalocean.md - Checks: - Network: + - Ping: plugins/checks/network/ping.md - TCP Connection: plugins/checks/network/tcp_connect.md - MySQL: - Available: plugins/checks/mysql/available.md diff --git a/plugins/checks/network/ping.sh b/plugins/checks/network/ping.sh new file mode 100644 index 0000000..dfdb932 --- /dev/null +++ b/plugins/checks/network/ping.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +usage() { + echo 'Usage: '`basename $0` '-i [-t ]' + exit 1 +} + +timeout=3 #Default value + +# Parse command line arguments +while getopts ":i:t:" opts +do + case $opts in + i) + host=${OPTARG} + ;; + t) + timeout=${OPTARG} + ;; + *) + echo "Unknown argument:" ${OPTARG} + usage + ;; + esac +done + +if [ -z $host ] +then + usage +fi + +ping $host -c 1 -w $timeout 2>&1 > /dev/null +if [ $? -eq 0 ] +then + alert="OK" + status="UP" + exit=0 +else + alert="CRITICAL" + status="DOWN" + exit=2 +fi + +echo "PING $alert $status" +exit $exit