├── zabbix ├── data_collectors │ ├── riak_status.sh │ ├── smartarray_status.py │ ├── rabbitmq_discovery.py │ ├── get_toner_brother_7860.pl │ ├── 3ware_status.py │ ├── smartarray_discovery.py │ ├── 3ware_discovery.py │ ├── mac.sh │ ├── get_toner_xerox_6015_MFP.pl │ ├── get_toner_brother_9465.pl │ └── get_mac.pl └── alerts │ └── jab.py ├── LICENSE ├── README.md ├── scripts ├── haproxywrap.sh ├── meminfo.py ├── set_zabbix_maintenance.rb └── zabbix_maintenance.py └── nagios ├── check_smartarray.py ├── check_3ware.py ├── check_docker_memory.py └── check_cadvisor.py /zabbix/data_collectors/riak_status.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # script for querying riak status 4 | 5 | IPADDR="192.168.1.11" 6 | PORT="8098" 7 | curl -s http://$IPADDR:$PORT/stats -H "Accept: text/plain" 2> /dev/null | grep "$1" | awk -F":" '{ print $2 }' | awk -F"," '{print $1}' 8 | -------------------------------------------------------------------------------- /zabbix/alerts/jab.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python -W ignore 2 | import sys,xmpp 3 | 4 | list = sys.argv[1:] 5 | to = list[0]; 6 | subj = list[1]; 7 | body = list[2]; 8 | type_ = list[3]; 9 | 10 | # Google Talk constants 11 | FROM_GMAIL_ID = "info@jabber.lan" 12 | GMAIL_PASS = "123456" 13 | GTALK_SERVER = "jabber.lan" 14 | 15 | jid=xmpp.protocol.JID(FROM_GMAIL_ID); 16 | cl=xmpp.Client(jid.getDomain(),debug=[]); 17 | if not cl.connect((GTALK_SERVER,5222)): 18 | raise IOError('Can not connect to server.') 19 | if not cl.auth(jid.getNode(),GMAIL_PASS): 20 | raise IOError('Can not auth with server.') 21 | 22 | cl.send( xmpp.Message( to+"@"+GTALK_SERVER ,subj+" "+body+" "+type_ ) ); 23 | cl.disconnect(); 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Alexander Bulimov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Content 2 | 3 | This repository contains various SysAdmin-related utils and scripts I've written. 4 | 5 | ### Nagios-compatible checks 6 | 7 | Under **nagios** folder you may find Nagios-compatible check scripts. 8 | 9 | Most notable checks are: 10 | 11 | * **check_docker_memory.py** - checks used/free memory in running docker container from parent host; 12 | * **check_cadvisor.py** - checks memory and cpu stats in running docker container from cAdvisor API; 13 | * **check_3ware.py** - checks health status of HDDs attached to 3ware raid controllers; 14 | * **check_smartarray.py** - checks health status of HDDs attached to smartarray raid controllers. 15 | 16 | ### Zabbix checks and low-level discovery 17 | 18 | Under **zabbix** folder you may find Zabbix-related scripts, 19 | mostly for checks and low-level autodiscovery. 20 | 21 | ### Scripts 22 | 23 | Under **scripts** folder you may find various usorted 24 | scripts that might be usefull. 25 | 26 | Most notable scripts are: 27 | 28 | * **zabbix_maintenance.py** - script to create maintenance periods in Zabbix from CLI; 29 | * **haproxywrap.sh** - lightweight shell wrapper around haproxy control socket; 30 | * **meminfo.py** - small PyQT linux memory viualizer, see [my blog](http://bulimov.ru/it/meminfo-visualizer/) (in Russian). 31 | 32 | ## License 33 | 34 | Released under the [MIT License](http://www.opensource.org/licenses/MIT) 35 | -------------------------------------------------------------------------------- /zabbix/data_collectors/smartarray_status.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # This script is used to get a list of 5 | # disks in HP SmartArray RAID controllers 6 | # to provide Zabbix low-level discovery 7 | # License: MIT 8 | # Author: Alexander Bulimov, lazywolf0@gmail.com 9 | # inspired by 3ware_status utility 10 | 11 | import subprocess 12 | import sys 13 | import json 14 | import re 15 | 16 | binary_path = "/usr/sbin/hpacucli" 17 | 18 | def _run(cmd): 19 | # returns (rc, stdout, stderr) from shell command 20 | process = subprocess.Popen(cmd, stdout=subprocess.PIPE, 21 | stderr=subprocess.PIPE, shell=True) 22 | stdout, stderr = process.communicate() 23 | return (process.returncode, stdout, stderr) 24 | 25 | def _fail(msg): 26 | print(msg) 27 | sys.exit(1) 28 | 29 | def parse_disk_status(line): 30 | splitted = line.split() 31 | status = splitted[-1] 32 | return status 33 | 34 | def main(): 35 | if len(sys.argv) < 2: 36 | _fail("usage: %s device_name"%sys.argv[0]) 37 | 38 | disk = sys.argv[1] 39 | m = re.search('^(\d+):([a-zA-Z:0-9]+)$', disk) 40 | if m is None: 41 | _fail("device name must be in form C:NN") 42 | 43 | controller = m.group(1) 44 | physical = m.group(2) 45 | 46 | disks_list = [] 47 | 48 | rc, raw_data, err = _run("%s ctrl slot=%s pd %s show status"%(binary_path, controller, physical)) 49 | if rc != 0: 50 | _fail("hpacucli command failed with %s "%raw_data) 51 | disk_status = parse_disk_status(raw_data) 52 | 53 | print(disk_status) 54 | 55 | if __name__ == "__main__": 56 | main() 57 | -------------------------------------------------------------------------------- /zabbix/data_collectors/rabbitmq_discovery.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # This script is used to get a list of 5 | # RabbitMQ vhosts and queues in JSON 6 | # to provide Zabbix low-level discovery 7 | # License: MIT 8 | # Author: Alexander Bulimov, lazywolf0@gmail.com 9 | 10 | import subprocess 11 | import sys 12 | import json 13 | 14 | def _run(cmd): 15 | # returns (rc, stdout, stderr) from shell command 16 | process = subprocess.Popen(cmd, stdout=subprocess.PIPE, 17 | stderr=subprocess.PIPE, shell=True) 18 | stdout, stderr = process.communicate() 19 | return (process.returncode, stdout, stderr) 20 | 21 | def parse_vhosts(data): 22 | vhosts = [] 23 | for line in data.splitlines(): 24 | vhosts.append(line.strip()) 25 | return vhosts 26 | 27 | def parse_stat(data, vhost): 28 | stat = [] 29 | for line in data.splitlines(): 30 | stat.append({ 31 | '{#RABBITMQ_VHOST_NAME}': vhost, 32 | '{#RABBITMQ_QUEUE_NAME}': line.strip(), 33 | }) 34 | return stat 35 | 36 | def _fail(msg): 37 | print(msg) 38 | sys.exit(1) 39 | 40 | 41 | def main(): 42 | rc, raw_data, err = _run("rabbitmqctl -q list_vhosts name") 43 | if rc != 0: 44 | _fail("rabbitmqctl command failed with %s "%err) 45 | vhosts = parse_vhosts(raw_data) 46 | 47 | raw_stats = [] 48 | for vhost_name in vhosts: 49 | rc, raw_data, err = _run("rabbitmqctl -q list_queues -p %s name"%vhost_name) 50 | if rc != 0: 51 | _fail("rabbitmqctl command failed with %s "%err) 52 | raw_stats = raw_stats + parse_stat(raw_data, vhost_name) 53 | 54 | data = { 55 | 'data': raw_stats 56 | } 57 | #print json.dumps(data,sort_keys=True, indent=4, separators=(',', ': ')) 58 | print json.dumps(data) 59 | 60 | if __name__ == "__main__": 61 | main() 62 | -------------------------------------------------------------------------------- /zabbix/data_collectors/get_toner_brother_7860.pl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | # 3 | # This script is used to get 4 | # toner level from Brother MFC-7860DW 5 | # 6 | # License: MIT 7 | # Author: Alexander Bulimov, lazywolf0@gmail.com 8 | #==================================================================== 9 | # 10 | # QUERY TONER LEVEL FROM Brother MFC-7860DW 11 | #==================================================================== 12 | 13 | 14 | use strict; 15 | use warnings; 16 | use WWW::Curl::Easy; 17 | 18 | my $debug = 0; 19 | my $interval = 90; #refresh rate 20 | my $new = 0; 21 | my $toner; 22 | #===================================== 23 | my $error; 24 | my $c; 25 | my $curl = WWW::Curl::Easy->new; 26 | my $response_body; 27 | my $site; 28 | 29 | $site = 'http://'.$ARGV[0].'/etc/mnt_info.html?kind=item'; 30 | $curl->setopt(CURLOPT_HEADER,1); 31 | $curl->setopt(CURLOPT_URL, $site); 32 | $curl->setopt(CURLOPT_TIMEOUT,10); 33 | $curl->setopt(CURLOPT_WRITEDATA,\$response_body); 34 | 35 | my $retcode = $curl->perform; 36 | if ($retcode == 0) { 37 | my $i; 38 | my @l = split /\n/ ,$response_body; 39 | my $arraySize = @l; 40 | my $line; 41 | my $k; 42 | my $colorCount = 0; 43 | for($i = 0; $i < $arraySize; $i++) { 44 | $line = $l[ $i ]; 45 | if ($line =~ m/Toner\*\*/g) { 46 | my $nextline = $l[ $i + 2 ] ; 47 | $k = 0; 48 | while ($nextline =~ m!((■){1})!g) { 49 | $k++; 50 | }; 51 | $toner = $k * 10; 52 | } 53 | } 54 | } else { 55 | # Error code, type of error, error message 56 | if ($debug == 1){print("An error happened: $retcode ".$curl->strerror($retcode)." ".$curl->errbuf."\n");} 57 | } 58 | #================================== 59 | if (defined $toner) { 60 | print $toner; 61 | } else { 62 | print "0"; 63 | }; 64 | print "\n"; 65 | 66 | #============================================= 67 | #=== exit the program === 68 | exit 0; 69 | -------------------------------------------------------------------------------- /zabbix/data_collectors/3ware_status.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # This script is used to get a list of 5 | # disks in 3ware RAID controllers 6 | # to provide Zabbix low-level discovery 7 | # License: MIT 8 | # Author: Alexander Bulimov, lazywolf0@gmail.com 9 | # inspired by 3ware_status utility 10 | 11 | import subprocess 12 | import sys 13 | import json 14 | import re 15 | 16 | binary_path = "/usr/sbin/tw-cli" 17 | 18 | def _run(cmd): 19 | # returns (rc, stdout, stderr) from shell command 20 | process = subprocess.Popen(cmd, stdout=subprocess.PIPE, 21 | stderr=subprocess.PIPE, shell=True) 22 | stdout, stderr = process.communicate() 23 | return (process.returncode, stdout, stderr) 24 | 25 | def _fail(msg): 26 | print(msg) 27 | sys.exit(1) 28 | 29 | def parse_disks(data, controller): 30 | disks = {} 31 | for line in data.splitlines(): 32 | if line: 33 | splitted = line.split() 34 | if re.match(r'^[p][0-9]+$', splitted[0]): 35 | # '-' means the drive doesn't belong to any array 36 | # If is NOT PRESENT too, it just means this is an empty port 37 | if not splitted[2] == '-' and not splitted[1] == 'NOT-PRESENT': 38 | disks[controller + splitted[2] + splitted[0]] = splitted[1] 39 | return disks 40 | 41 | def main(): 42 | if len(sys.argv) < 2: 43 | _fail("usage: %s device_name"%sys.argv[0]) 44 | 45 | disk = sys.argv[1] 46 | m = re.search('^(c\d+)(u\d+)(p\d+)$', disk) 47 | if m is None: 48 | _fail("device name must be in form cNuNpN") 49 | 50 | controller = m.group(1) 51 | unit = m.group(2) 52 | physical = m.group(3) 53 | 54 | disks_list = [] 55 | 56 | rc, raw_data, err = _run("%s info %s"%(binary_path, controller)) 57 | if rc != 0: 58 | _fail("tw-cli command failed with %s "%err) 59 | disks_list = parse_disks(raw_data, controller) 60 | 61 | if disk in disks_list: 62 | print disks_list[disk] 63 | else: 64 | _fail("no such disk %s"%disk) 65 | 66 | if __name__ == "__main__": 67 | main() 68 | -------------------------------------------------------------------------------- /zabbix/data_collectors/smartarray_discovery.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # This script is used to get a list of 5 | # disks in HP SmartArray RAID controllers 6 | # to provide Zabbix low-level discovery 7 | # License: MIT 8 | # Author: Alexander Bulimov, lazywolf0@gmail.com 9 | # inspired by 3ware_status utility 10 | 11 | import subprocess 12 | import sys 13 | import json 14 | import re 15 | 16 | binary_path = "/usr/sbin/hpacucli" 17 | 18 | def _run(cmd): 19 | # returns (rc, stdout, stderr) from shell command 20 | process = subprocess.Popen(cmd, stdout=subprocess.PIPE, 21 | stderr=subprocess.PIPE, shell=True) 22 | stdout, stderr = process.communicate() 23 | return (process.returncode, stdout, stderr) 24 | 25 | def _fail(msg): 26 | print(msg) 27 | sys.exit(1) 28 | 29 | def parse_controllers(data): 30 | controllers = [] 31 | for line in data.splitlines(): 32 | if line: 33 | res = re.search(r'Slot\s+([0-9]+)', line) 34 | if res: 35 | controllers.append(res.group(1)) 36 | return controllers 37 | 38 | def parse_disks(data, controller): 39 | disks = [] 40 | for line in data.splitlines(): 41 | if line: 42 | splitted = line.split() 43 | if re.match(r'^physicaldrive$', splitted[0]): 44 | disks.append({ 45 | '{#HP_DISK}': controller + ':' + splitted[1] 46 | }) 47 | return disks 48 | 49 | def main(): 50 | disks_list = [] 51 | 52 | rc, raw_data, err = _run("%s ctrl all show status"%binary_path) 53 | if rc != 0: 54 | _fail("hpacucli command failed with %s "%raw_data) 55 | controllers_list = parse_controllers(raw_data) 56 | 57 | for controller in controllers_list: 58 | rc, raw_data, err = _run("%s ctrl slot=%s pd all show status"%(binary_path, controller)) 59 | if rc != 0: 60 | _fail("hpacucli command failed with %s "%raw_data) 61 | disks_list.extend(parse_disks(raw_data, controller)) 62 | 63 | data = { 64 | 'data': disks_list 65 | } 66 | print(json.dumps(data)) 67 | 68 | if __name__ == "__main__": 69 | main() 70 | -------------------------------------------------------------------------------- /zabbix/data_collectors/3ware_discovery.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # This script is used to get a list of 5 | # disks in 3ware RAID controllers 6 | # to provide Zabbix low-level discovery 7 | # License: MIT 8 | # Author: Alexander Bulimov, lazywolf0@gmail.com 9 | # inspired by 3ware_status utility 10 | 11 | import subprocess 12 | import sys 13 | import json 14 | import re 15 | 16 | binary_path = "/usr/sbin/tw-cli" 17 | 18 | def _run(cmd): 19 | # returns (rc, stdout, stderr) from shell command 20 | process = subprocess.Popen(cmd, stdout=subprocess.PIPE, 21 | stderr=subprocess.PIPE, shell=True) 22 | stdout, stderr = process.communicate() 23 | return (process.returncode, stdout, stderr) 24 | 25 | def _fail(msg): 26 | print(msg) 27 | sys.exit(1) 28 | 29 | def parse_controllers(data): 30 | controllers = [] 31 | for line in data.splitlines(): 32 | if line: 33 | splitted = line.split() 34 | if re.match(r'^c[0-9]+$', splitted[0]): 35 | controllers.append(splitted[0]) 36 | return controllers 37 | 38 | def parse_disks(data, controller): 39 | disks = [] 40 | for line in data.splitlines(): 41 | if line: 42 | splitted = line.split() 43 | if re.match(r'^[p][0-9]+$', splitted[0]): 44 | # '-' means the drive doesn't belong to any array 45 | # If is NOT PRESENT too, it just means this is an empty port 46 | if not splitted[2] == '-' and not splitted[1] == 'NOT-PRESENT': 47 | disks.append({ 48 | '{#3WARE_DISK}': controller + splitted[2] + splitted[0] 49 | }) 50 | return disks 51 | 52 | def main(): 53 | disks_list = [] 54 | 55 | rc, raw_data, err = _run("%s info"%binary_path) 56 | if rc != 0: 57 | _fail("tw-cli command failed with %s "%err) 58 | controllers_list = parse_controllers(raw_data) 59 | 60 | for controller in controllers_list: 61 | rc, raw_data, err = _run("%s info %s"%(binary_path, controller)) 62 | if rc != 0: 63 | _fail("tw-cli command failed with %s "%err) 64 | disks_list.extend(parse_disks(raw_data, controller)) 65 | 66 | data = { 67 | 'data': disks_list 68 | } 69 | print json.dumps(data) 70 | 71 | if __name__ == "__main__": 72 | main() 73 | -------------------------------------------------------------------------------- /scripts/haproxywrap.sh: -------------------------------------------------------------------------------- 1 | # !/bin/bash 2 | # 3 | # This script is used to manage backends status in haproxy 4 | # general usage - starting or stoping maintenance 5 | # you need write permissions on haproxy socket 6 | # you need socat to be installed 7 | # License: MIT 8 | # Author: Alexander Bulimov, lazywolf0@gmail.com 9 | 10 | socket=/var/run/haproxy 11 | 12 | command=$1 13 | status() 14 | { 15 | backend=$1 16 | server=$2 17 | if [[ "$server" == "$backend" ]]; then 18 | server="BACKEND" 19 | fi 20 | echo "show stat" | socat unix-connect:$socket stdio | awk -F, '{ printf("%-18s %-12s %s\n",$1,$2,$18) }' | awk "/$backend/ && /$server/ {print \$3}" 21 | } 22 | 23 | trigger() 24 | { 25 | command=$1 26 | backend=$2 27 | server=$3 28 | if [[ "$command" == "disable" ]]; then 29 | state="UP" 30 | else 31 | state="MAINT" 32 | fi 33 | 34 | if [[ "$server" == "$backend" ]]; then 35 | server_list=(`echo "show stat" | socat unix-connect:$socket stdio | awk -F, '{ printf("%-18s %-12s %s\n",$1,$2,$18) }' | awk "/$backend/ && !/BACKEND/ && !/no check/ {print \\$2}"`) 36 | else 37 | server_list=$server 38 | fi 39 | for srv in ${server_list[@]} 40 | do 41 | cur_status=$(status $backend $srv) 42 | while [[ "$cur_status" == "$state" ]]; do 43 | echo "$command server $backend/$srv" 44 | #echo "cur_status $cur_status" 45 | echo "$command server $backend/$srv" | socat unix-connect:$socket stdio 46 | sleep 1 47 | cur_status=$(status $backend $srv) 48 | echo "status changed to $cur_status" 49 | echo "-----------------------------" 50 | done 51 | done 52 | } 53 | 54 | case $command in 55 | stat) 56 | echo "show stat" | socat unix-connect:$socket stdio | awk -F, '{ printf("%-18s %-12s %s\n",$1,$2,$18) }' 57 | ;; 58 | status) 59 | backend="${2%/*}" 60 | server="${2##*/}" 61 | if [ -z "$server" ]; then 62 | echo "use $0 status backend{/server}" 63 | else 64 | status $backend $server 65 | fi 66 | ;; 67 | disable|enable) 68 | backend="${2%/*}" 69 | server="${2##*/}" 70 | if [ -z "$server" ]; then 71 | echo "use $0 $command backend{/server}" 72 | else 73 | trigger $command $backend $server 74 | trigger $command $backend $server 75 | fi 76 | ;; 77 | *) 78 | echo "wrong command $command" 79 | echo "use $0 {stat,status,enable,disable}" 80 | exit 1 81 | ;; 82 | esac 83 | -------------------------------------------------------------------------------- /zabbix/data_collectors/mac.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # License: MIT 3 | # Author: Alexander Bulimov, lazywolf0@gmail.com 4 | 5 | if [ -z "$1" ]; then 6 | echo "no args specified, exiting!" 7 | exit 1 8 | fi 9 | #don't forget that Zabbix don't set $PATH when running scripts 10 | filename=/usr/share/zabbix/scripts/oui.txt 11 | tmpfile=/tmp/oui.txt 12 | link=http://standards.ieee.org/develop/regauth/oui/oui.txt 13 | sed=/bin/sed 14 | awk=/usr/bin/awk 15 | 16 | case $1 in 17 | -s) 18 | silent=1 19 | mac=$2 20 | if [ -z "$2" ]; then 21 | echo "no mac specified, exiting!" 22 | exit 1 23 | fi 24 | ;; 25 | -u) 26 | wget $link -O $tmpfile 27 | if [ $? -gt 0 ]; then 28 | echo "download error, exiting" 29 | exit 1 30 | else 31 | echo "Download ok!" 32 | echo "Moving $tmpfile to $filename..." 33 | mv -f $tmpfile $filename 34 | if [ $? -gt 0 ]; then 35 | echo "Error!" 36 | else 37 | echo "Success!" 38 | fi 39 | exit 0 40 | fi 41 | ;; 42 | *) 43 | mac=$1 44 | ;; 45 | esac 46 | if [ ! -f $filename ]; then 47 | if [ -z $silent ]; then 48 | echo "no mac list file, dowload it? [y/n]" 49 | else 50 | exit 1 51 | fi 52 | while : 53 | do 54 | read INPUT_STRING 55 | case $INPUT_STRING in 56 | y) 57 | echo "Trying to download from $link" 58 | wget $link 59 | if [ $? -gt 0 ]; then 60 | echo "download error, exiting" 61 | exit 1 62 | else 63 | echo "Download ok!" 64 | fi 65 | break 66 | ;; 67 | n) 68 | echo "exiting!" 69 | exit 0 70 | ;; 71 | *) 72 | echo "wrong input, use [y/n]" 73 | ;; 74 | esac 75 | done 76 | fi 77 | if [ ${#mac} -lt 8 ]; then 78 | mac=`echo "$mac" | $sed 's/^\(..\)\(..\)\(..\)/\1-\2-\3/' ` 79 | else 80 | mac=`echo "$mac" | $sed -e 's/:/-/g'` 81 | fi 82 | mac=${mac:0:8} 83 | if [ -z $silent ]; then 84 | echo "Searching for $mac..." 85 | fi 86 | result=`$awk --assign IGNORECASE=1 '/hex/ && /'$mac'/ {for (x=3; x<=NF; x++) {printf("%s ",$x)}}' $filename` 87 | if [ -z "$result" ]; then 88 | result="no info" 89 | fi 90 | echo -n $result 91 | -------------------------------------------------------------------------------- /zabbix/data_collectors/get_toner_xerox_6015_MFP.pl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | # 3 | # This script is used to get 4 | # toner level from Xerox 6015 MFP 5 | # 6 | # License: MIT 7 | # Author: Alexander Bulimov, lazywolf0@gmail.com 8 | #==================================================================== 9 | # 10 | # QUERY TONER LEVEL FROM XEROX 6015 MFP 11 | #==================================================================== 12 | 13 | 14 | use strict; 15 | use warnings; 16 | use WWW::Curl::Easy; 17 | 18 | my $debug = 0; 19 | my $file_name = "/tmp/$ARGV[0]-gettoner_xerox.tmp"; 20 | my $interval = 90; #refresh rate 21 | my $new = 0; 22 | my %toner; 23 | my $needle = $ARGV[1]; 24 | my $write_secs = (stat($file_name))[9]; 25 | 26 | if ($debug == 1){ 27 | print "file $file_name updated at ", scalar(localtime($write_secs)), "\n"; 28 | }; 29 | 30 | if (!(defined $write_secs) || ($write_secs + $interval < time)) { #file updated less then $interval seconds ago 31 | if ($debug == 1){print "generating new toner table \n";} 32 | $new = 1; 33 | open FH, "+<$file_name" or open FH, ">$file_name" or die "can't open '$file_name': $!"; 34 | flock(FH, 2) or die "can't flock $file_name: $!"; 35 | seek(FH, 0, 0); truncate(FH, 0); 36 | } else { 37 | if ($debug == 1){print "using old toner table \n";} 38 | open FR, "<$file_name" or die "can't open '$file_name': $!"; 39 | flock(FR, 1) or die "can't flock $file_name: $!"; 40 | while(my $line = ) { 41 | chomp($line); 42 | my ($p, $m) = split/,/, $line; 43 | $toner{$p} = $m; 44 | } 45 | } 46 | #===================================== 47 | my $error; 48 | my $c; 49 | my @color; 50 | $color[0] = 'Cyan'; 51 | $color[1] = 'Magenta'; 52 | $color[2] = 'Yellow'; 53 | $color[3] = 'Black'; 54 | 55 | my $curl = WWW::Curl::Easy->new; 56 | my $response_body; 57 | my $site; 58 | $site = 'http://'.$ARGV[0].'/status/statsuppliesx.asp'; 59 | 60 | if($new == 1) { 61 | $curl->setopt(CURLOPT_HEADER,1); 62 | $curl->setopt(CURLOPT_URL, $site); 63 | $curl->setopt(CURLOPT_TIMEOUT,10); 64 | $curl->setopt(CURLOPT_WRITEDATA,\$response_body); 65 | my $retcode = $curl->perform; 66 | if ($retcode == 0) { 67 | my $text = $response_body; 68 | my $i = 0; 69 | while ($text =~ m!((\d)+)%!g) { 70 | $toner{$color[$i]} = $1; 71 | $i++; 72 | }; 73 | while ( my ($key, $value) = each(%toner) ) { 74 | print FH "$key,$value\n"; 75 | } 76 | } else { 77 | # Error code, type of error, error message 78 | if ($debug == 1){print("An error happened: $retcode ".$curl->strerror($retcode)." ".$curl->errbuf."\n");} 79 | } 80 | }; 81 | #================================== 82 | if (exists $toner{ $needle }) { 83 | print $toner{$needle}; 84 | } else { 85 | print "0"; 86 | }; 87 | print "\n"; 88 | 89 | #============================================= 90 | #=== Close the session and exit the program === 91 | if($new == 1) { 92 | close FH; 93 | } else { 94 | close FR; 95 | } 96 | exit 0; 97 | 98 | -------------------------------------------------------------------------------- /scripts/meminfo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Visualize /proc/meminfo cache stats 4 | # === 5 | # 6 | # Copyright 2014 Alexander Bulimov 7 | # 8 | # Released under the MIT license, see LICENSE for details. 9 | import sys 10 | from PySide import QtGui, QtCore 11 | 12 | 13 | class MemoryDrawer(QtGui.QWidget): 14 | 15 | def __init__(self): 16 | super(MemoryDrawer, self).__init__() 17 | 18 | self.initUI() 19 | self.data = dict() 20 | self.getData() 21 | 22 | def initUI(self): 23 | 24 | self.setWindowTitle('/proc/meminfo visualizer') 25 | self.timer = QtCore.QTimer() 26 | self.timer.timeout.connect(self.onTimer) 27 | self.timer.start(100) 28 | self.show() 29 | 30 | def paintEvent(self, e): 31 | 32 | qp = QtGui.QPainter() 33 | qp.begin(self) 34 | self.drawRectangles(qp) 35 | qp.end() 36 | 37 | def drawRectangles(self, qp): 38 | 39 | height = self.geometry().height() 40 | width = self.geometry().width() 41 | dataSet = [('MemFree:', 'darkGreen'), 42 | ('Active(file):', 'darkMagenta'), 43 | ('Inactive(file):', 'darkRed'), 44 | ('Cached:', 'darkCyan')] 45 | offset = 20 46 | count = len(dataSet) 47 | sizeX = (width - (count + 1) * offset) // count 48 | 49 | sizeY = height - 2 * offset 50 | 51 | x = offset 52 | y = offset 53 | 54 | for pos, (data, colorName) in enumerate(dataSet): 55 | x = (pos + 1) * offset + pos * sizeX 56 | color = QtGui.QColor(colorName) 57 | pixmap = self.drawGraph(sizeX, sizeY, data, color) 58 | qp.drawPixmap(x, y, pixmap) 59 | 60 | def drawGraph(self, width, height, dataKey, color): 61 | memTotal = self.data['MemTotal:'] 62 | kbPerPixel = height / memTotal 63 | 64 | dataValue = self.data[dataKey] 65 | drawData = dataValue * kbPerPixel 66 | 67 | pixmap = QtGui.QPixmap(width, height) 68 | qp = QtGui.QPainter() 69 | qp.begin(pixmap) 70 | qp.setBrush(QtGui.QColor(255, 255, 255)) 71 | qp.drawRect(0, 0, width, height) 72 | qp.setBrush(color) 73 | qp.drawRect(0, height - drawData, width, height) 74 | qp.drawText(QtCore.QPoint(5, 20), dataKey) 75 | qp.drawText(QtCore.QPoint(5, 40), "%s kb" % dataValue) 76 | qp.end() 77 | return pixmap 78 | 79 | def getData(self): 80 | with open('/proc/meminfo') as f: 81 | for line in f.readlines(): 82 | if line: 83 | splitted = line.split() 84 | self.data[splitted[0]] = int(splitted[1]) 85 | 86 | def onTimer(self): 87 | self.getData() 88 | self.update() 89 | 90 | 91 | def main(): 92 | app = QtGui.QApplication(sys.argv) 93 | drawer = MemoryDrawer() 94 | drawer.show() 95 | sys.exit(app.exec_()) 96 | 97 | 98 | if __name__ == '__main__': 99 | main() 100 | -------------------------------------------------------------------------------- /zabbix/data_collectors/get_toner_brother_9465.pl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | # 3 | # This script is used to get 4 | # toner level from Brother MFC-9465CDN 5 | # 6 | # License: MIT 7 | # Author: Alexander Bulimov, lazywolf0@gmail.com 8 | #==================================================================== 9 | # 10 | # QUERY TONER LEVEL FROM Brother MFC-9465CDN 11 | #==================================================================== 12 | 13 | 14 | use strict; 15 | use warnings; 16 | use WWW::Curl::Easy; 17 | 18 | my $debug = 0; 19 | my $file_name = "/tmp/$ARGV[0]-gettoner_brother.tmp"; 20 | my $interval = 90; #refresh rate 21 | my $new = 0; 22 | my %toner; 23 | my $needle = $ARGV[1]; 24 | my $write_secs = (stat($file_name))[9]; 25 | if ($debug == 1){ 26 | print "file $file_name updated at ", scalar(localtime($write_secs)), "\n"; 27 | }; 28 | if (!(defined $write_secs) || ($write_secs + $interval < time)) { #file updated less then $interval seconds ago 29 | if ($debug == 1){print "generating new toner table \n";} 30 | $new = 1; 31 | open FH, "+<$file_name" or open FH, ">$file_name" or die "can't open '$file_name': $!"; 32 | flock(FH, 2) or die "can't flock $file_name: $!"; 33 | seek(FH, 0, 0); truncate(FH, 0); 34 | }else { 35 | if ($debug == 1){print "using old toner table \n";} 36 | open FR, "<$file_name" or die "can't open '$file_name': $!"; 37 | flock(FR, 1) or die "can't flock $file_name: $!"; 38 | while(my $line = ) { 39 | chomp($line); 40 | my ($p, $m) = split/,/, $line; 41 | $toner{$p} = $m; 42 | } 43 | } 44 | #===================================== 45 | my $error; 46 | my $c; 47 | my @color; 48 | $color[0] = 'Cyan'; 49 | $color[1] = 'Magenta'; 50 | $color[2] = 'Yellow'; 51 | $color[3] = 'Black'; 52 | my $curl = WWW::Curl::Easy->new; 53 | my $response_body; 54 | #open(my $response, '+>', \$response_body) or die "can't open '$file_name': $!"; 55 | my $site; 56 | $site = 'http://'.$ARGV[0].'/etc/mnt_info.html?kind=item'; 57 | if($new == 1) { 58 | $curl->setopt(CURLOPT_HEADER,1); 59 | $curl->setopt(CURLOPT_URL, $site); 60 | $curl->setopt(CURLOPT_WRITEDATA,\$response_body); 61 | $curl->setopt(CURLOPT_TIMEOUT,20); 62 | my $retcode = $curl->perform; 63 | if ($retcode == 0) { 64 | my $i; 65 | my @l = split /\n/ ,$response_body; 66 | my $arraySize = @l; 67 | my $line; 68 | my $k; 69 | my $colorCount = 0; 70 | for($i = 0; $i < $arraySize; $i++) { 71 | $line = $l[ $i ]; 72 | if ($line =~ m/Toner (Yellow|Black|Magenta|Cyan) \((C|M|Y|K)\)\*\*/g) { 73 | my $nextline = $l[ $i + 2 ] ; 74 | $k = 0; 75 | while ($nextline =~ m!((■){1})!g) { 76 | $k++; 77 | }; 78 | $toner{$color[$colorCount]} = $k * 10; 79 | $colorCount++; 80 | } 81 | } 82 | while ( my ($key, $value) = each(%toner) ) { 83 | print FH "$key,$value\n"; 84 | } 85 | } else { 86 | # Error code, type of error, error message 87 | if ($debug == 1){print("An error happened: $retcode ".$curl->strerror($retcode)." ".$curl->errbuf."\n");} 88 | } 89 | }; 90 | #================================== 91 | if (exists $toner{ $needle }) { 92 | print $toner{$needle}; 93 | }else { 94 | print "0"; 95 | }; 96 | print "\n"; 97 | 98 | #============================================= 99 | #=== Close the session and exit the program === 100 | if($new == 1) { 101 | close FH; 102 | } else { 103 | close FR; 104 | } 105 | exit 0; 106 | 107 | -------------------------------------------------------------------------------- /nagios/check_smartarray.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Check HP SmartArray Status Plugin 4 | # === 5 | # 6 | # Checks status for all HDDs in all SmartArray controllers. 7 | # 8 | # hpacucli requires root permissions. 9 | # 10 | # Create a file named /etc/sudoers.d/hpacucli with this line inside : 11 | # username ALL=(ALL) NOPASSWD: /usr/sbin/hpacucli 12 | # 13 | # You can get Debian/Ubuntu hpacucli packages here - http://hwraid.le-vert.net/ 14 | # 15 | # Copyright 2014 Alexander Bulimov 16 | # 17 | # Released under the MIT license, see LICENSE for details. 18 | 19 | import subprocess 20 | import sys 21 | import re 22 | import os 23 | 24 | 25 | class CheckSmartArrayStatus: 26 | def __init__(self): 27 | self.name = 'CheckSmartArrayStatus' 28 | self.good_disks = [] 29 | self.bad_disks = [] 30 | self.controllers = [] 31 | self.binary = 'hpacucli' 32 | if os.getuid() != 0: 33 | self.binary = 'sudo -n -k ' + self.binary 34 | 35 | def execute(self, cmd): 36 | # returns (rc, stdout, stderr) from shell command 37 | process = subprocess.Popen(cmd, stdout=subprocess.PIPE, 38 | stderr=subprocess.PIPE, shell=True) 39 | stdout, stderr = process.communicate() 40 | return (process.returncode, stdout, stderr) 41 | 42 | def ok(self, message): 43 | print("%s OK: %s" % (self.name, message)) 44 | sys.exit(0) 45 | 46 | def warn(self, message): 47 | print("%s WARNING: %s" % (self.name, message)) 48 | sys.exit(1) 49 | 50 | def critical(self, message): 51 | print("%s CRITICAL: %s" % (self.name, message)) 52 | sys.exit(2) 53 | 54 | def unknown(self, message): 55 | print("%s UNKNOWN: %s" % (self.name, message)) 56 | sys.exit(3) 57 | 58 | def parse_controllers(self, data): 59 | for line in data.splitlines(): 60 | if line: 61 | res = re.search(r'Slot\s+([0-9]+)', line) 62 | if res: 63 | self.controllers.append(res.group(1)) 64 | 65 | def parse_disks(self, data, controller): 66 | for line in data.splitlines(): 67 | if line: 68 | splitted = line.split() 69 | if re.match(r'^physicaldrive$', splitted[0]): 70 | status = splitted[-1] 71 | disk = 'ctrl ' + controller + ' ' + line.strip() 72 | if status == 'OK': 73 | self.good_disks.append(disk) 74 | else: 75 | self.bad_disks.append(disk) 76 | 77 | def run(self): 78 | rc, raw_data, err = self.execute( 79 | "%s ctrl all show status" % self.binary 80 | ) 81 | if rc != 0: 82 | error = raw_data + ' ' + err 83 | self.unknown("hpacucli command failed with %s " % error) 84 | self.parse_controllers(raw_data) 85 | 86 | for controller in self.controllers: 87 | rc, raw_data, err = self.execute( 88 | "%s ctrl slot=%s pd all show status" % 89 | (self.binary, controller)) 90 | if rc != 0: 91 | error = raw_data + ' ' + err 92 | self.unknown("hpacucli command failed with %s " % error) 93 | self.parse_disks(raw_data, controller) 94 | 95 | if self.bad_disks: 96 | data = ', '.join(self.bad_disks) 97 | bad_count = len(self.bad_disks) 98 | good_count = len(self.good_disks) 99 | total_count = bad_count + good_count 100 | self.critical("%s of %s disks are in bad state - %s" % 101 | (bad_count, total_count, data)) 102 | else: 103 | data = len(self.good_disks) 104 | self.ok("All %s found disks are OK" % data) 105 | 106 | if __name__ == "__main__": 107 | module = CheckSmartArrayStatus() 108 | module.run() 109 | -------------------------------------------------------------------------------- /scripts/set_zabbix_maintenance.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby -W0 2 | # 3 | # This script is used to set/remove maintenance mode in zabbix 4 | # you need proper permissions for login_user set in zabbix server webui 5 | # you need gem zbxapi 6 | # License: MIT 7 | # Author: Alexander Bulimov, lazywolf0@gmail.com 8 | # 9 | require 'zbxapi' 10 | require 'date' 11 | 12 | ########################################### 13 | #config starts 14 | server = "http://monitoring.lan" 15 | login_user = "user" 16 | login_pass = "password" 17 | #config ends 18 | ########################################### 19 | 20 | def connect(server,login_user,login_pass) 21 | zabbix = ZabbixAPI.new(server) 22 | zabbix.login(login_user,login_pass) 23 | zabbix 24 | end 25 | 26 | def create_maintenance(zabbix,group_id,start_time,period,name="deploy") 27 | end_time = start_time + period 28 | result = zabbix.raw_api( 29 | "maintenance.create", 30 | { 31 | "groupids"=>[group_id.to_i], 32 | "name"=>name, 33 | "maintenance_type"=>"0", 34 | "description"=>"created by zab.rb", 35 | "active_since"=>start_time.to_s, 36 | "active_till"=>end_time.to_s, 37 | "timeperiods"=> [{ 38 | "timeperiod_type"=>"0", 39 | "start_date"=>start_time.to_s, 40 | "period"=>period.to_s 41 | }] 42 | } 43 | ) 44 | result["maintenanceids"] 45 | end 46 | def get_maintenance_ids(zabbix,group_id) 47 | result = zabbix.raw_api("maintenance.get","search"=>{"groupids"=>[group_id]}) 48 | if result[0].nil? 49 | puts "no maintenances for group #{group_id} found!" 50 | exit 2 51 | end 52 | maintenance_ids = [] 53 | result.each do |res| 54 | maintenance_ids << res["maintenanceid"] 55 | end 56 | maintenance_ids 57 | end 58 | def get_maintenances(zabbix,group_id) 59 | result = zabbix.raw_api("maintenance.get","output"=>"extend","search"=>{"groupids"=>[group_id]}) 60 | if result[0].nil? 61 | puts "no maintenances for group #{group_id} found!" 62 | exit 2 63 | end 64 | formated_maintenances = [] 65 | result.each do |res| 66 | end_time = DateTime.strptime(res['active_till'],'%s').to_time.to_s 67 | formated_maintenances << "#{res['maintenanceid']}: #{res['name']} till #{end_time}" 68 | end 69 | formated_maintenances 70 | end 71 | def delete_maintenance(zabbix,maintenance_ids) 72 | result = zabbix.raw_api("maintenance.delete",maintenance_ids) 73 | end 74 | def get_group_id(zabbix,group_name) 75 | group = zabbix.hostgroup.get({"output"=>"extend","search"=>{"name"=>group_name},"searchWildcardsEnabled"=>1}) 76 | if group[0].nil? 77 | puts "group #{group_name} not found!" 78 | exit 2 79 | end 80 | group[0]["groupid"] 81 | end 82 | 83 | 84 | if ARGV[1].nil? 85 | puts "use #{File.basename($0)} create|delete|show group_name [period in seconds]" 86 | exit 1 87 | end 88 | group_name = ARGV[1] 89 | action = ARGV[0] 90 | case action 91 | when "create" 92 | zabbix = connect(server,login_user,login_pass) 93 | now = Time.now 94 | start_time = now.to_i 95 | name = "deploy #{now.to_s}" 96 | period = ARGV[2].to_i 97 | if period == 0 98 | period = 600 #10 * 60 seconds 99 | end 100 | group_id = get_group_id(zabbix,group_name) 101 | maintenance_ids = create_maintenance(zabbix,group_id,start_time,period,name) 102 | puts "done" 103 | exit 0 104 | when "delete" 105 | zabbix = connect(server,login_user,login_pass) 106 | group_id = get_group_id(zabbix,group_name) 107 | maintenance_ids = get_maintenance_ids(zabbix,group_id) 108 | delete_maintenance(zabbix,maintenance_ids) 109 | puts "done" 110 | exit 0 111 | when "show" 112 | zabbix = connect(server,login_user,login_pass) 113 | group_id = get_group_id(zabbix,group_name) 114 | maintenances = get_maintenances(zabbix,group_id) 115 | maintenances.each do |m| 116 | puts m 117 | end 118 | else 119 | puts "Wrong action #{action}" 120 | end 121 | -------------------------------------------------------------------------------- /nagios/check_3ware.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Check 3ware Status Plugin 4 | # === 5 | # 6 | # Checks status for all HDDs in all 3ware controllers. 7 | # 8 | # tw-cli requires root permissions. 9 | # 10 | # Create a file named /etc/sudoers.d/tw-cli with this line inside : 11 | # username ALL=(ALL) NOPASSWD: /usr/sbin/tw-cli 12 | # 13 | # You can get Debian/Ubuntu tw-cli packages here - http://hwraid.le-vert.net/ 14 | # 15 | # Copyright 2014 Alexander Bulimov 16 | # 17 | # Released under the MIT license, see LICENSE for details. 18 | # 19 | # Inspired by 3ware_status utility 20 | 21 | import subprocess 22 | import sys 23 | import re 24 | import os 25 | 26 | 27 | class Check3wareStatus: 28 | def __init__(self): 29 | self.name = 'Check3wareStatus' 30 | self.good_disks = [] 31 | self.bad_disks = [] 32 | self.controllers = [] 33 | self.binary = 'tw-cli' 34 | if os.getuid() != 0: 35 | self.binary = 'sudo -n -k ' + self.binary 36 | 37 | def execute(self, cmd): 38 | # returns (rc, stdout, stderr) from shell command 39 | process = subprocess.Popen(cmd, stdout=subprocess.PIPE, 40 | stderr=subprocess.PIPE, shell=True) 41 | stdout, stderr = process.communicate() 42 | return (process.returncode, stdout, stderr) 43 | 44 | def ok(self, message): 45 | print("%s OK: %s" % (self.name, message)) 46 | sys.exit(0) 47 | 48 | def warn(self, message): 49 | print("%s WARNING: %s" % (self.name, message)) 50 | sys.exit(1) 51 | 52 | def critical(self, message): 53 | print("%s CRITICAL: %s" % (self.name, message)) 54 | sys.exit(2) 55 | 56 | def unknown(self, message): 57 | print("%s UNKNOWN: %s" % (self.name, message)) 58 | sys.exit(3) 59 | 60 | def parse_controllers(self, data): 61 | for line in data.splitlines(): 62 | if line: 63 | controller = line.split()[0] 64 | if re.match(r'^c[0-9]+$', controller): 65 | self.controllers.append(controller) 66 | 67 | def parse_disks(self, data, controller): 68 | for line in data.splitlines(): 69 | if line: 70 | splitted = line.split() 71 | if re.match(r'^[p][0-9]+$', splitted[0]): 72 | # '-' means the drive doesn't belong to any array 73 | # If is NOT PRESENT too, it means this is an empty port 74 | status = splitted[1] 75 | name = splitted[0] 76 | unit = splitted[2] 77 | if not unit == '-' and not unit == 'NOT-PRESENT': 78 | line = controller + unit + name + ': ' + status 79 | if status == 'OK': 80 | self.good_disks.append(line) 81 | else: 82 | self.bad_disks.append(line) 83 | 84 | def run(self): 85 | rc, raw_data, err = self.execute("%s info" % self.binary) 86 | if rc != 0: 87 | self.unknown("tw-cli command failed with %s " % err) 88 | self.parse_controllers(raw_data) 89 | 90 | for controller in self.controllers: 91 | rc, raw_data, err = self.execute("%s info %s" % 92 | (self.binary, controller)) 93 | if rc != 0: 94 | self.unknown("tw-cli command failed with %s " % err) 95 | self.parse_disks(raw_data, controller) 96 | 97 | if self.bad_disks: 98 | data = ', '.join(self.bad_disks) 99 | bad_count = len(self.bad_disks) 100 | good_count = len(self.good_disks) 101 | total_count = bad_count + good_count 102 | self.critical("%s of %s disks are in bad state - %s" % 103 | (bad_count, total_count, data)) 104 | else: 105 | data = len(self.good_disks) 106 | self.ok("All %s found disks are OK" % data) 107 | 108 | if __name__ == "__main__": 109 | module = Check3wareStatus() 110 | module.run() 111 | -------------------------------------------------------------------------------- /zabbix/data_collectors/get_mac.pl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | # 3 | # This script is used to get a list of 4 | # mac addresses per port on 3com switches. 5 | # Tested on 3COM 4200G, 4210, 2916, 2924. 6 | # License: MIT 7 | # Author: Alexander Bulimov, lazywolf0@gmail.com 8 | #==================================================================== 9 | # 10 | # QUERY MAC ADDRESSES FROM 3COM SWITCH FROM SELECTED PORT 11 | #==================================================================== 12 | 13 | 14 | use strict; 15 | use Net::SNMP qw(snmp_dispatcher oid_lex_sort); 16 | 17 | my $show_vendor = 1; 18 | my $script = "/usr/share/zabbix/scripts/mac.sh"; 19 | my $debug = 0; 20 | my $file_name = "/tmp/$ARGV[0]-getmac.tmp"; 21 | my $interval = 90; #refresh rate 22 | my $new = 0; 23 | my @list; 24 | my $write_secs = (stat($file_name))[9]; 25 | if ($debug == 1){ 26 | print "file $file_name updated at ", scalar(localtime($write_secs)), "\n"; 27 | }; 28 | if ($write_secs + $interval < time) { #file updated less then $interval seconds ago 29 | if ($debug == 1){print "generating new mac table \n";} 30 | $new = 1; 31 | open FH, ">$file_name" or die "can't open '$file_name': $!"; 32 | }else { 33 | if ($debug == 1){print "using old mac table \n";} 34 | open FR, "<$file_name" or die "can't open '$file_name': $!"; 35 | while(my $line = ) { 36 | chomp($line); 37 | my ($p, $m) = split/;/, $line; 38 | @list[$p] = "@list[$p]$m, "; 39 | } 40 | } 41 | #===================================== 42 | my $session; 43 | my $error; 44 | my $port = $ARGV[1]; 45 | if($new == 1) { 46 | #=== Setup session to remote host === 47 | ($session, $error) = Net::SNMP->session( 48 | -hostname => $ARGV[0] || 'localhost', 49 | -community => 'public', 50 | -version => '2c', 51 | -translate => [-octetstring => 0], 52 | -port => 161 53 | ); 54 | #=== Was the session created? === 55 | if (!defined($session)) { 56 | printf("ERROR: %s\n", $error); 57 | exit 1; 58 | } 59 | }; 60 | #================================== 61 | 62 | #=== OIDs queried to retrieve information ==== 63 | my $TpFdbAddress = '1.3.6.1.2.1.17.4.3.1.1'; 64 | my $TpFdbPort = '1.3.6.1.2.1.17.4.3.1.2'; 65 | #============================================= 66 | my $result; 67 | my @tmp; 68 | my $x; 69 | if($new == 1) { 70 | if (defined($result = $session->get_table($TpFdbAddress))) { 71 | foreach (oid_lex_sort(keys(%{$result}))) { 72 | $x = unpack('H*',$result->{$_}); 73 | $x =~ s/(..(?!\Z))/\1:/g; 74 | push( @tmp, $x); 75 | } 76 | }else { 77 | if($debug == 1) { 78 | printf("ERROR: %s\n\n", $session->error()); 79 | } 80 | } 81 | #========================================== 82 | #=== Print the returned MAC ports === 83 | $result; 84 | if (defined($result = $session->get_table(-baseoid => $TpFdbPort))) { 85 | my $i = 0; 86 | my $out = ""; 87 | my $res = 0; 88 | my $tmp_port; 89 | my $tmp_mac_list = ""; 90 | foreach (oid_lex_sort(keys(%{$result}))) { 91 | if($result->{$_} == $port) { 92 | $res = 1; 93 | if( $show_vendor == 1) { 94 | $out = `/usr/share/zabbix/scripts/mac.sh -s $tmp[$i]`; 95 | printf("%s(%s)", $tmp[$i], $out); 96 | }else { 97 | printf("%s", $tmp[$i]); 98 | }; 99 | print ", "; 100 | }; 101 | if( $show_vendor == 1) { 102 | $out = `/usr/share/zabbix/scripts/mac.sh -s $tmp[$i]`; 103 | printf FH ("%s;%s(%s)\n", $result->{$_}, $tmp[$i], $out); 104 | }else { 105 | printf FH ("%s;%s\n", $result->{$_}, $tmp[$i]); 106 | }; 107 | $i++; 108 | } 109 | if ($res == 0) { 110 | print "null"; 111 | }; 112 | }else { 113 | if($debug == 1) { 114 | printf("ERROR: %s\n\n", $session->error()); 115 | }else { 116 | print "null"; 117 | }; 118 | } 119 | }else { 120 | if(@list[$port]) { 121 | print "@list[$port]"; 122 | }else { 123 | print "null"; 124 | }; 125 | } 126 | print "\n"; 127 | #============================================= 128 | #=== Close the session and exit the program === 129 | if($new == 1) { 130 | $session->close; 131 | close FH; 132 | }else { 133 | close FR; 134 | } 135 | exit 0; 136 | 137 | -------------------------------------------------------------------------------- /nagios/check_docker_memory.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Check Docker container memory usage Plugin 4 | # === 5 | # 6 | # Checks Memory Usage status inside given container 7 | # just like check_memory.pl checks it on physical host. 8 | # 9 | # docker requires root permissions. 10 | # 11 | # Create a file named /etc/sudoers.d/docker with this line inside : 12 | # username ALL=(ALL) NOPASSWD: /usr/bin/docker ps* 13 | # 14 | # Copyright 2015 Alexander Bulimov 15 | # 16 | # Released under the MIT license, see LICENSE for details. 17 | 18 | from __future__ import unicode_literals 19 | from __future__ import division 20 | from __future__ import print_function 21 | import subprocess 22 | import sys 23 | import re 24 | import argparse 25 | 26 | class CheckDockerMemory: 27 | """Check memory usage of running docker container""" 28 | def __init__(self, docker_name, warn, crit, kind): 29 | self.name = 'CheckDockerMemory' 30 | self.docker_name = docker_name 31 | self.warn_level = warn 32 | self.crit_level = crit 33 | self.check_kind = kind 34 | 35 | self.binary = 'sudo -n -k docker' 36 | 37 | def execute(self, cmd): 38 | """Run command in shell""" 39 | # returns (rc, stdout, stderr) from shell command 40 | process = subprocess.Popen(cmd, stdout=subprocess.PIPE, 41 | stderr=subprocess.PIPE, shell=True) 42 | stdout, stderr = process.communicate() 43 | return (process.returncode, stdout, stderr) 44 | 45 | def ok(self, message): 46 | print("%s OK: %s" % (self.name, message)) 47 | sys.exit(0) 48 | 49 | def warn(self, message): 50 | print("%s WARNING: %s" % (self.name, message)) 51 | sys.exit(1) 52 | 53 | def critical(self, message): 54 | print("%s CRITICAL: %s" % (self.name, message)) 55 | sys.exit(2) 56 | 57 | def unknown(self, message): 58 | print("%s UNKNOWN: %s" % (self.name, message)) 59 | sys.exit(3) 60 | 61 | def get_docker_id(self, data): 62 | """Parse data to get matching name and extract id""" 63 | for line in data.splitlines(): 64 | if line: 65 | splitted = line.split() 66 | if re.match(r'^%s$' % self.docker_name, splitted[-1]): 67 | docker_id = splitted[0] 68 | return docker_id 69 | return None 70 | 71 | 72 | def run(self): 73 | """Main class function""" 74 | rc, raw_data, err = self.execute( 75 | "%s ps -notrunc" % self.binary 76 | ) 77 | if rc != 0: 78 | error = raw_data + ' ' + err 79 | self.unknown("docker command failed with %s " % error) 80 | 81 | docker_id = self.get_docker_id(raw_data) 82 | if not docker_id: 83 | self.critical("No container %s found." % self.docker_name) 84 | with open('/sys/fs/cgroup/memory/docker/%s/memory.usage_in_bytes' % docker_id) as f: 85 | mem_used_kb = int(f.read()) / 1024 86 | with open('/sys/fs/cgroup/memory/docker/%s/memory.limit_in_bytes' % docker_id) as f: 87 | mem_limit_kb = int(f.read()) / 1024 88 | with open('/proc/meminfo') as f: 89 | for line in f.readlines(): 90 | if line and line.startswith('MemTotal'): 91 | mem_total_kb = int(line.split()[1]) 92 | break 93 | 94 | if mem_limit_kb > mem_total_kb: 95 | mem_limit_kb = mem_total_kb 96 | mem_free_kb = mem_limit_kb - mem_used_kb 97 | 98 | perfdata = ' | TOTAL=%dKB;;;; USED=%dKB;;;; FREE=%dKB;;;;' % (mem_limit_kb, 99 | mem_used_kb, 100 | mem_free_kb) 101 | if self.check_kind == 'used': 102 | mem_used_percent = mem_used_kb * (100 / mem_limit_kb) 103 | message = '%5.3f%% (%d kB) used!' % (mem_used_percent, mem_used_kb) + perfdata 104 | if mem_used_percent > self.crit_level: 105 | self.critical(message) 106 | if mem_used_percent > self.warn_level: 107 | self.warn(message) 108 | self.ok(message) 109 | 110 | elif self.check_kind == 'free': 111 | mem_free_percent = mem_free_kb * (100 / mem_limit_kb) 112 | message = '%5.3f%% (%d kB) free!' % (mem_free_percent, mem_free_kb) + perfdata 113 | if mem_free_percent < self.crit_level: 114 | self.critical(message) 115 | if mem_free_percent < self.warn_level: 116 | self.warn(message) 117 | self.ok(message) 118 | 119 | 120 | if __name__ == "__main__": 121 | parser = argparse.ArgumentParser(description='Check Docker container memory') 122 | parser.add_argument('-n', dest='name', required=True, help='Docker container name') 123 | parser.add_argument('-w', dest='warn', type=int, required=True, 124 | help='Percent free/used when to warn') 125 | parser.add_argument('-c', dest='crit', type=int, required=True, 126 | help='Percent free/used when critical') 127 | group = parser.add_mutually_exclusive_group(required=True) 128 | group.add_argument('-f', dest='kind', action='store_false', help='Check FREE memory') 129 | group.add_argument('-u', dest='kind', action='store_true', help='Check USED memory') 130 | args = parser.parse_args() 131 | if args.kind: 132 | check_kind = 'used' 133 | else: 134 | check_kind = 'free' 135 | module = CheckDockerMemory(args.name, args.warn, args.crit, check_kind) 136 | module.run() 137 | -------------------------------------------------------------------------------- /scripts/zabbix_maintenance.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Control Zabbix Maintenance periods 4 | # === 5 | # 6 | # Copyright 2014 Alexander Bulimov 7 | # 8 | # Released under the MIT license, see LICENSE for details. 9 | # 10 | # Updated to be able to use with zabbix server version >=3.0 by Zhelanov Vladimir 11 | 12 | """Zabbix Maintenance Handler. 13 | 14 | Usage: 15 | zabbix_maintenance.py -U= [-P= create \ 16 | () (--hosts|--groups) ... [--period=] [--description=] [--no-data] [--force] 17 | zabbix_maintenance.py -U= [-P= show ( | --all) 18 | zabbix_maintenance.py -U= [-P= remove ( | --all) 19 | zabbix_maintenance.py (-h | --help) 20 | zabbix_maintenance.py --version 21 | 22 | Options: 23 | -h --help Show this screen. 24 | --version Show version. 25 | -a --all Apply action to all maintenance periods. 26 | --no-data Disable data collection during maintenace period. 27 | --force If maintenance with given name already exists, 28 | delete it and create new one. 29 | --hosts Interpret targets as host names. 30 | --groups Interpret targets as group names. 31 | -P --password= Login password. If not set, prompt 32 | will be displayed. 33 | -U --user= Login user. 34 | -S --server= Zabbix server uri, 35 | for example https://monitor.example.com 36 | --period= Period for maintenance window 37 | in minutes [default: 10]. 38 | --description= Description for maintenance 39 | 40 | """ 41 | import sys 42 | import getpass 43 | import datetime 44 | import time 45 | try: 46 | from docopt import docopt 47 | except ImportError: 48 | sys.exit("Missing docopt module (install: pip install docopt)") 49 | 50 | try: 51 | from zabbix_api import ZabbixAPI 52 | except ImportError: 53 | sys.exit("Missing zabbix-api module (install: pip install zabbix-api)") 54 | 55 | 56 | def create_maintenance(zbx, group_ids, host_ids, start_time, maintenance_type, 57 | period, name, desc): 58 | end_time = start_time + period 59 | zbx.maintenance.create( 60 | { 61 | "groupids": group_ids, 62 | "hostids": host_ids, 63 | "name": name, 64 | "maintenance_type": maintenance_type, 65 | "active_since": str(start_time), 66 | "active_till": str(end_time), 67 | "description": desc, 68 | "timeperiods": [{ 69 | "timeperiod_type": "0", 70 | "start_date": str(start_time), 71 | "period": str(period), 72 | }] 73 | } 74 | ) 75 | 76 | 77 | def get_maintenances(zbx, name): 78 | result = zbx.maintenance.get( 79 | { 80 | "output": "extend", 81 | "filter": 82 | { 83 | "name": name 84 | } 85 | } 86 | ) 87 | 88 | return result 89 | 90 | 91 | def parse_maintenances_ids(maintenances): 92 | maintenance_ids = [] 93 | for res in maintenances: 94 | maintenance_ids.append(res["maintenanceid"]) 95 | return maintenance_ids 96 | 97 | 98 | def pretty_maintenance(maint): 99 | end_time = str(datetime.datetime.fromtimestamp( 100 | float(maint['active_till']))) 101 | start_time = str(datetime.datetime.fromtimestamp( 102 | float(maint['active_since']))) 103 | if int(maint['maintenance_type']) == 0: 104 | tp = 'with data collection' 105 | else: 106 | tp = 'without data collection' 107 | pretty = ("%s: since %s, till %s, %s" % 108 | (maint['name'], start_time, end_time, tp)) 109 | return pretty 110 | 111 | 112 | def delete_maintenances(zbx, name): 113 | maintenance = get_maintenances(zbx, name) 114 | 115 | if maintenance: 116 | ids = parse_maintenances_ids(maintenance) 117 | zbx.maintenance.delete(ids) 118 | 119 | 120 | def check_maintenance(zbx, name): 121 | return True if len(zbx.maintenance.get({"output": "extend", "filter": { "name": name }})) > 0 else False 122 | 123 | 124 | def get_group_ids(zbx, host_groups): 125 | group_ids = [] 126 | for group in host_groups: 127 | result = zbx.hostgroup.get( 128 | { 129 | "output": "extend", 130 | "filter": 131 | { 132 | "name": group 133 | } 134 | } 135 | ) 136 | if not result: 137 | return [] 138 | 139 | group_ids.append(result[0]["groupid"]) 140 | 141 | return group_ids 142 | 143 | 144 | def get_host_ids(zbx, host_names): 145 | host_ids = [] 146 | for host in host_names: 147 | result = zbx.host.get( 148 | { 149 | "output": "extend", 150 | "filter": 151 | { 152 | "name": host 153 | } 154 | } 155 | ) 156 | if not result: 157 | return [] 158 | 159 | host_ids.append(result[0]["hostid"]) 160 | 161 | return host_ids 162 | 163 | 164 | def _fail(msg): 165 | sys.exit(msg) 166 | 167 | 168 | def _done(msg): 169 | print(msg) 170 | sys.exit(0) 171 | 172 | 173 | def _ok(msg): 174 | print(msg) 175 | 176 | if __name__ == '__main__': 177 | arguments = docopt(__doc__, version='Zabbix Maintenance 1.1') 178 | 179 | server_url = arguments['--server'] 180 | login_user = arguments['--user'] 181 | if arguments['--password']: 182 | login_password = arguments['--password'] 183 | else: 184 | login_password = getpass.getpass( 185 | prompt='Enter password for user %s on %s: ' % 186 | (login_user, server_url)) 187 | 188 | try: 189 | zbx = ZabbixAPI(server_url) 190 | zbx.login(login_user, login_password) 191 | except BaseException as e: 192 | _fail("Failed to connect to Zabbix server: %s" % e) 193 | 194 | if arguments['--hosts']: 195 | hosts = arguments[''] 196 | groups = [] 197 | else: 198 | hosts = [] 199 | groups = arguments[''] 200 | 201 | name = arguments[''] 202 | 203 | if arguments['--no-data']: 204 | maintenance_type = 1 205 | else: 206 | maintenance_type = 0 207 | 208 | description = arguments['--description'] if arguments.get('--description') else 'Created by zabbix_maintenance.py' 209 | 210 | if arguments['create']: 211 | now = datetime.datetime.now() 212 | start_time = time.mktime(now.timetuple()) 213 | period = 60 * int(arguments['--period']) 214 | try: 215 | exists = check_maintenance(zbx, name) 216 | if exists and not arguments['--force']: 217 | _fail('Maintenance %s already created, aborting.' % name) 218 | else: 219 | if arguments['--force']: 220 | delete_maintenances(zbx, name) 221 | group_ids = get_group_ids(zbx, groups) 222 | if groups and not group_ids: 223 | _fail('One or more group in %s not found, aborting.' % 224 | groups) 225 | host_ids = get_host_ids(zbx, hosts) 226 | if hosts and not host_ids: 227 | _fail('One or more host in %s not found, aborting.' % 228 | hosts) 229 | create_maintenance(zbx, group_ids, host_ids, 230 | start_time, maintenance_type, 231 | period, name, description) 232 | except BaseException as e: 233 | _fail(e) 234 | _done('Done.') 235 | 236 | elif arguments['remove']: 237 | try: 238 | exists = check_maintenance(zbx, name) 239 | 240 | if exists: 241 | if arguments['--all']: 242 | name = '' 243 | delete_maintenances(zbx, name) 244 | _done('Done.') 245 | else: 246 | _done('Nothing to do.') 247 | except BaseException as e: 248 | _fail(e) 249 | 250 | elif arguments['show']: 251 | try: 252 | if arguments['--all']: 253 | name = '' 254 | maintenances = get_maintenances(zbx, name) 255 | if maintenances: 256 | for m in maintenances: 257 | _ok(pretty_maintenance(m)) 258 | else: 259 | _done('No maintenances to show.') 260 | except BaseException as e: 261 | _fail(e) 262 | -------------------------------------------------------------------------------- /nagios/check_cadvisor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Check Docker container stats via cAdvisor HTTP API 4 | # === 5 | # 6 | # Checks CPU or Memory Usage status inside given container 7 | # via cAdvisor API 8 | # 9 | # Copyright 2015 Alexander Bulimov 10 | # 11 | # Released under the MIT license, see LICENSE for details. 12 | 13 | from __future__ import unicode_literals 14 | from __future__ import division 15 | from __future__ import print_function 16 | import sys 17 | import argparse 18 | import json 19 | import requests 20 | 21 | 22 | def get_host_data(cadvisor_url, host_name): 23 | """Get cAdvisor url, hostname, and return host data in JSON""" 24 | host_raw_data = requests.get(cadvisor_url + "/api/v1.2/docker/" + 25 | host_name, 26 | timeout=10) 27 | host_data = json.loads(host_raw_data.text) 28 | host_id = host_data.keys()[0] 29 | return host_data[host_id] 30 | 31 | 32 | 33 | def get_host_procs(companion_url, host_id, sort_by): 34 | """Get cAdvisor url, hostname, and return host data in JSON""" 35 | payload = {'sort': sort_by, 'limit': 5, 'interval': 30} 36 | ps_response = requests.get(companion_url + "/api/v1.0" + host_id + 37 | "/processes", 38 | params=payload, 39 | timeout=5) 40 | ps = json.loads(ps_response.text) 41 | return ps[-1]["processes"] 42 | 43 | 44 | def get_machine_data(cadvisor_url): 45 | """Get cAdvisor url and return parent host data in JSON""" 46 | response = requests.get(cadvisor_url + "/api/v1.2/machine") 47 | payload = json.loads(response.text) 48 | return payload 49 | 50 | 51 | def ok(message): 52 | print("CheckDockerStats OK: %s" % message) 53 | sys.exit(0) 54 | 55 | 56 | def warn(message): 57 | print("CheckDockerStats WARNING: %s" % message) 58 | sys.exit(1) 59 | 60 | 61 | def critical(message): 62 | print("CheckDockerStats CRITICAL: %s" % message) 63 | sys.exit(2) 64 | 65 | 66 | def unknown(message): 67 | print("CheckDockerStats UNKNOWN: %s" % message) 68 | sys.exit(3) 69 | 70 | 71 | def show_procs(procs, mem_limit): 72 | """Pretty print host procs in ps-like fashion""" 73 | mem_limit_kb = mem_limit / 1024 74 | result = "" 75 | fmt_line = "%(user)5d %(pid)5d %(cpu)5.1f %(mem)5.1f %(vsz)8d \ 76 | %(rss)8d %(state)6s %(command)s\n" 77 | if procs: 78 | result = "\n%5s %5s %5s %5s %8s %8s %6s %s\n" % ( 79 | "USER", "PID", "%CPU", "%MEM", "VSZ", "RSS", "STAT", "COMMAND") 80 | for proc in procs: 81 | result += fmt_line % { 82 | "user": proc["status"]["RealUid"], 83 | "pid": proc["stat"]["pid"], 84 | "cpu": proc["relativecpuusage"], 85 | "mem": proc["status"]["VmRSS"] * 100 / mem_limit_kb, 86 | "vsz": proc["status"]["VmSize"], 87 | "rss": proc["status"]["VmRSS"], 88 | "state": proc["stat"]["state"], 89 | "command": proc["cmdline"]} 90 | return result 91 | 92 | 93 | def calculate_mem_limit(machine_data, host_data): 94 | """Calculate real memory limit for container""" 95 | mem_limit = host_data["spec"]["memory"]["limit"] 96 | mem_limit_host = machine_data["memory_capacity"] 97 | 98 | if mem_limit > mem_limit_host: 99 | mem_limit = mem_limit_host 100 | return mem_limit 101 | 102 | 103 | def process_cpu_checks(machine_data, host_data, 104 | warn_level, crit_level, host_procs): 105 | """Process CPU checks for data""" 106 | # Usage % = (Used CPU Time (in nanoseconds) for the interval) / 107 | # (interval (in nano secs) * num cores) 108 | mem_limit = calculate_mem_limit(machine_data, host_data) 109 | cpu_usage_total_per_min = host_data["stats"][-1]["cpu"]["usage"]["total"] -\ 110 | host_data["stats"][0]["cpu"]["usage"]["total"] 111 | cpu_num_cores = machine_data["num_cores"] 112 | cpu_usage_percent = cpu_usage_total_per_min / 60 / 10000000 / cpu_num_cores 113 | perfdata = ' | cpu_usage=%.2f%%;%d;%d;0;100' % \ 114 | (cpu_usage_percent, warn_level, crit_level) 115 | message = '%5.2f%% CPU used!' % cpu_usage_percent 116 | try: 117 | procs_string = show_procs(host_procs, mem_limit) 118 | except Exception: 119 | procs_string = "" 120 | 121 | if cpu_usage_percent > crit_level: 122 | critical(message + procs_string + perfdata) 123 | if cpu_usage_percent > warn_level: 124 | warn(message + procs_string + perfdata) 125 | ok(message + perfdata) 126 | 127 | 128 | def process_mem_checks(machine_data, host_data, check_used, 129 | warn_level, crit_level, host_procs): 130 | """Process memory checks for data""" 131 | mem_limit = calculate_mem_limit(machine_data, host_data) 132 | 133 | mem_used_sum = 0 134 | for stat in host_data["stats"]: 135 | mem_used_sum += stat["memory"]["usage"] 136 | 137 | mem_used = mem_used_sum // len(host_data["stats"]) 138 | mem_free_kb = (mem_limit - mem_used) / 1024 139 | mem_used_kb = mem_used / 1024 140 | mem_limit_kb = mem_limit / 1024 141 | mem_used_percent = mem_used * 100 / mem_limit 142 | mem_free_percent = 100 - mem_used_percent 143 | perfdata = ' | mem_used=%dKB;%d;%d;0;%d' % (mem_used_kb, 144 | warn_level * mem_limit_kb / 100, 145 | crit_level * mem_limit_kb / 100, 146 | mem_limit_kb) 147 | try: 148 | procs_string = show_procs(host_procs, mem_limit) 149 | except Exception: 150 | procs_string = "" 151 | 152 | if check_used: 153 | message = '%5.2f%% Mem (%d kB) used!' % (mem_used_percent, mem_used_kb) 154 | if mem_used_percent > crit_level: 155 | critical(message + procs_string + perfdata) 156 | if mem_used_percent > warn_level: 157 | warn(message + procs_string + perfdata) 158 | ok(message + perfdata) 159 | else: 160 | message = '%5.2f%% Mem (%d kB) free!' % (mem_free_percent, mem_free_kb) 161 | if mem_free_percent < args.crit: 162 | critical(message + procs_string + perfdata) 163 | if mem_free_percent < args.warn: 164 | warn(message + procs_string + perfdata) 165 | ok(message + perfdata) 166 | 167 | 168 | if __name__ == "__main__": 169 | parser = argparse.ArgumentParser(description='Check Docker container from cAdvisor') 170 | parser.add_argument('-u', dest='url', required=True, 171 | help='cAdvisor url') 172 | parser.add_argument('-U', dest='companion_url', required=False, 173 | help='cAdvisor-companion url') 174 | parser.add_argument('-n', dest='name', required=True, 175 | help='Docker container name') 176 | parser.add_argument('-w', dest='warn', type=int, required=True, 177 | help='Load Average when to warn') 178 | parser.add_argument('-c', dest='crit', type=int, required=True, 179 | help='Load Average when critical') 180 | group = parser.add_mutually_exclusive_group(required=True) 181 | group.add_argument('-C', dest='cpu', action='store_true', 182 | help='Check CPU usage percent') 183 | group.add_argument('-m', dest='mem', action='store_false', 184 | help='Check FREE memory percent') 185 | group.add_argument('-M', dest='mem', action='store_true', 186 | help='Check USED memory percent') 187 | args = parser.parse_args() 188 | try: 189 | host_data = get_host_data(args.url, args.name) 190 | machine_data = get_machine_data(args.url) 191 | except (requests.exceptions.RequestException, ValueError) as e: 192 | unknown(e) 193 | if host_data: 194 | host_procs = ([], []) 195 | if args.companion_url: 196 | try: 197 | if args.cpu: 198 | host_procs = get_host_procs(args.companion_url, 199 | host_data["name"], "cpu") 200 | else: 201 | host_procs = get_host_procs(args.companion_url, 202 | host_data["name"], "mem") 203 | except (requests.exceptions.RequestException, ValueError) as e: 204 | print("(can be ignored) Failed to fetch cAdvisor-companion data: %s" % e) 205 | host_procs = [] 206 | if args.cpu: 207 | process_cpu_checks(machine_data, host_data, 208 | args.warn, args.crit, host_procs) 209 | else: 210 | process_mem_checks(machine_data, host_data, args.mem, 211 | args.warn, args.crit, host_procs) 212 | else: 213 | unknown("Host %s not found" % args.name) 214 | --------------------------------------------------------------------------------