├── README.md ├── munin-bitcoind-scripts ├── README.md └── bitcoind_ ├── munin-linux-scripts ├── README.md └── sensors2_ ├── munin-mikrotik-scripts ├── README.md ├── mikrotikcpu_ ├── mikrotikdiskspace_ ├── mikrotikifrate_ ├── mikrotikmemory_ ├── mikrotiksensors_ ├── mikrotikuptime_ ├── mikrotikwificlients_ └── routeros_api.class.php ├── munin-munin-scripts └── munin_stats └── munin-nvidia-scripts ├── README.md └── nvidiasmi_ /README.md: -------------------------------------------------------------------------------- 1 | munin-scripts 2 | ============= 3 | 4 | My collection of updated munin data collection scripts (plugins). 5 | 6 | These are mainly existing scripts that were outdated or lacking functionality and were in need of an update. 7 | 8 | All munin plugins have been developed and tested on Munin 2.0.24. 9 | 10 | Please use the bugtracker @ https://github.com/acidsploit/munin-scripts/issues to leave any comments, issues or feedback. 11 | 12 | ``` 13 | Updated plugins: 14 | - /munin-mikrotik-scripts/mikrotikcpu_ 15 | - /munin-mikrotik-scripts/mikrotikdiskspace_ 16 | - /munin-mikrotik-scripts/mikrotikifrate_ 17 | - /munin-mikrotik-scripts/mikrotikmemory_ 18 | - /munin-bitcoind-scripts/bitcoind_ 19 | 20 | New pugins: 21 | - /munin-mikrotik-scripts/mikrotikuptime_ 22 | - /munin-mikrotik-scripts/mikrotiksensors_ 23 | ``` 24 | -------------------------------------------------------------------------------- /munin-bitcoind-scripts/README.md: -------------------------------------------------------------------------------- 1 | munin-bitcoind-scripts 2 | ====================== 3 | 4 | All munin plugins have been developed and tested on Munin 2.0.24 and bitcoind 0.9.3. 5 | 6 | Please use the bugtracker @ https://github.com/acidsploit/munin-scripts/issues to leave any comments, issues or feedback. 7 | 8 | Updated plugins: 9 | - /munin-bitcoind-scripts/bitcoind_ 10 | - balance 11 | - connections 12 | - paytxfee 13 | - relayfee 14 | - transactions 15 | - block_age 16 | - difficulty 17 | - score 18 | - blocks 19 | 20 | -------------------------------------------------------------------------------- /munin-bitcoind-scripts/bitcoind_: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # bitcoind_ Munin plugin for Bitcoin Server Variables 3 | # 4 | # by Mike Koss 5 | # Feb 14, 2012, MIT License 6 | # 7 | # modified by acidsploit@github 8 | # Jan 03, 2015 9 | # 10 | # You need to be able to authenticate to the bitcoind server to issue rpc's. 11 | # This plugin supporst 2 ways to do that: 12 | # 13 | # 1) In /etc/munin/plugin-conf.d/bitcoin.conf place: 14 | # 15 | # [bitcoind_*] 16 | # user your-username 17 | # 18 | # Then be sure your $HOME/.bitcoin/bitcoin.conf has the correct authentication info: 19 | # rpcconnect, rpcport, rpcuser, rpcpassword 20 | # 21 | # 2) Place your bitcoind authentication directly in /etc/munin/plugin-conf.d/bitcoin.conf 22 | # 23 | # [bitcoind_*] 24 | # env.rpcport 8332 25 | # env.rpcconnect 127.0.0.1 26 | # env.rpcuser your-username-here 27 | # env.rpcpassword your-password-here 28 | # 29 | # To install all available graphs: 30 | # 31 | # sudo munin-node-configure --libdir=. --suggest --shell | sudo bash 32 | # 33 | # Leave out the "| bash" to get a list of commands you can select from to install 34 | # individual graphs. 35 | # 36 | # Munin plugin tags: 37 | # 38 | #%# family=auto 39 | #%# capabilities=autoconf suggest 40 | 41 | import os 42 | import sys 43 | import time 44 | import re 45 | import urllib2 46 | import json 47 | 48 | 49 | DEBUG = False 50 | 51 | 52 | def main(): 53 | # getinfo variable is read from command name - probably the sym-link name. 54 | request_var = sys.argv[0].split('_', 1)[1] or 'balance' 55 | command = sys.argv[1] if len(sys.argv) > 1 else None 56 | request_labels = {'balance': ('Wallet Balance', 'BTC'), 57 | 'connections': ('Peer Connections', 'Connections'), 58 | 'relayfee': ("relayfee", "BTC"), 59 | 'paytxfee': ("paytxfee", "BTC"), 60 | 'transactions': ("Transactions", "Transactions", 61 | ('confirmed', 'waiting')), 62 | 'block_age': ("Last Block Age", "Seconds"), 63 | 'difficulty': ("Network Difficulty", "Difficulty"), 64 | 'score': ("IP Score Value", "Score"), 65 | 'blocks': ("Number of Blocks", "Blocks"), 66 | } 67 | 68 | # Munin should send connection options via environment vars 69 | bitcoin_options = get_env_options('rpcconnect', 'rpcport', 'rpcuser', 'rpcpassword') 70 | bitcoin_options.rpcconnect = bitcoin_options.get('rpcconnect', '127.0.0.1') 71 | bitcoin_options.rpcport = bitcoin_options.get('rpcport', '8332') 72 | 73 | if bitcoin_options.get('rpcuser') is None: 74 | conf_file = os.path.join(os.path.expanduser('~/.bitcoin'), 'bitcoin.conf') 75 | bitcoin_options = parse_conf(conf_file) 76 | 77 | bitcoin_options.require('rpcuser', 'rpcpassword') 78 | 79 | bitcoin = ServiceProxy('http://%s:%s' % (bitcoin_options.rpcconnect, 80 | bitcoin_options.rpcport), 81 | username=bitcoin_options.rpcuser, 82 | password=bitcoin_options.rpcpassword) 83 | 84 | (info, error) = bitcoin.getinfo() 85 | 86 | if error: 87 | if command == 'autoconf': 88 | print 'no' 89 | return 90 | else: 91 | # TODO: Better way to report errors to Munin-node. 92 | raise ValueError("Could not connect to Bitcoin server.") 93 | 94 | if request_var in ('transactions', 'block_age'): 95 | (info, error) = bitcoin.getblockhash(info['blocks']) 96 | (info, error) = bitcoin.getblock(info) 97 | info['block_age'] = int(time.time()) - info['time'] 98 | info['confirmed'] = len(info['tx']) 99 | 100 | if request_var in ('fees', 'paytxfee', 'relayfee', 'transactions'): 101 | (memory_pool, error) = bitcoin.getrawmempool() 102 | if memory_pool: 103 | info['waiting'] = len(memory_pool) 104 | 105 | if request_var in ('score'): 106 | (info, error) = bitcoin.getnetworkinfo() 107 | if info: 108 | info['score'] = [] 109 | #print "%s\n" % (info) 110 | for localaddress in info['localaddresses']: 111 | #print localaddress 112 | info['score'].append([re.sub(r'(\.)', '-' , localaddress['address']), localaddress['score']]) 113 | 114 | if command == 'autoconf': 115 | print 'yes' 116 | return 117 | 118 | labels = request_labels[request_var] 119 | if len(labels) < 3: 120 | line_labels = [request_var] 121 | else: 122 | line_labels = labels[2] 123 | 124 | if command == 'suggest': 125 | for var_name in request_labels.keys(): 126 | print var_name 127 | return 128 | 129 | if command == 'config': 130 | print 'graph_category bitcoind' 131 | print 'graph_title Bitcoin %s' % labels[0] 132 | print 'graph_vlabel %s' % labels[1] 133 | for label in line_labels: 134 | if label in ('paytxfee', 'relayfee'): 135 | print "graph_args --base 1000 -l 0" 136 | 137 | if label in ('score'): 138 | for value in info[label]: 139 | print "%s.label %s" % (value[0], value[0]) 140 | else: 141 | print '%s.label %s' % (label, label) 142 | return 143 | 144 | 145 | for label in line_labels: 146 | if label in ('score'): 147 | for value in info[label]: 148 | print "%s.value %s" % (value[0], value[1]) 149 | else: 150 | print "%s.value %s" % (label, info[label]) 151 | 152 | 153 | def parse_conf(filename): 154 | """ Bitcoin config file parser. """ 155 | 156 | options = Options() 157 | 158 | re_line = re.compile(r'^\s*([^#]*)\s*(#.*)?$') 159 | re_setting = re.compile(r'^(.*)\s*=\s*(.*)$') 160 | try: 161 | with open(filename) as file: 162 | for line in file.readlines(): 163 | line = re_line.match(line).group(1).strip() 164 | m = re_setting.match(line) 165 | if m is None: 166 | continue 167 | (var, value) = (m.group(1), m.group(2).strip()) 168 | options[var] = value 169 | except: 170 | pass 171 | 172 | return options 173 | 174 | 175 | def get_env_options(*vars): 176 | options = Options() 177 | for var in vars: 178 | options[var] = os.getenv(var) 179 | return options 180 | 181 | 182 | class Options(dict): 183 | """A dict that allows for object-like property access syntax.""" 184 | def __getattr__(self, name): 185 | try: 186 | return self[name] 187 | except KeyError: 188 | raise AttributeError(name) 189 | 190 | def require(self, *names): 191 | missing = [] 192 | for name in names: 193 | if self.get(name) is None: 194 | missing.append(name) 195 | if len(missing) > 0: 196 | raise ValueError("Missing required setting%s: %s." % 197 | ('s' if len(missing) > 1 else '', 198 | ', '.join(missing))) 199 | 200 | 201 | class ServiceProxy(object): 202 | """ 203 | Proxy for a JSON-RPC web service. Calls to a function attribute 204 | generates a JSON-RPC call to the host service. If a callback 205 | keyword arg is included, the call is processed as an asynchronous 206 | request. 207 | 208 | Each call returns (result, error) tuple. 209 | """ 210 | def __init__(self, url, username=None, password=None): 211 | self.url = url 212 | self.id = 0 213 | self.username = username 214 | self.password = password 215 | 216 | def __getattr__(self, method): 217 | self.id += 1 218 | return Proxy(self, method, id=self.id) 219 | 220 | 221 | class Proxy(object): 222 | def __init__(self, service, method, id=None): 223 | self.service = service 224 | self.method = method 225 | self.id = id 226 | 227 | def __call__(self, *args): 228 | if DEBUG: 229 | arg_strings = [json.dumps(arg) for arg in args] 230 | print "Calling %s(%s) @ %s" % (self.method, 231 | ', '.join(arg_strings), 232 | self.service.url) 233 | 234 | data = { 235 | 'method': self.method, 236 | 'params': args, 237 | 'id': self.id, 238 | } 239 | request = urllib2.Request(self.service.url, json.dumps(data)) 240 | if self.service.username: 241 | # Strip the newlines from the b64 encoding! 242 | b64 = ('%s:%s' % (self.service.username, self.service.password)).encode('base64').replace('\n','') 243 | request.add_header('Authorization', 'Basic %s' % b64) 244 | 245 | try: 246 | body = urllib2.urlopen(request).read() 247 | except Exception, e: 248 | return (None, e) 249 | 250 | if DEBUG: 251 | print 'RPC Response (%s): %s' % (self.method, json.dumps(body, indent=4)) 252 | 253 | try: 254 | data = json.loads(body) 255 | except ValueError, e: 256 | return (None, e.message) 257 | # TODO: Check that id matches? 258 | return (data['result'], data['error']) 259 | 260 | 261 | def get_json_url(url): 262 | request = urllib2.Request(url) 263 | body = urllib2.urlopen(request).read() 264 | data = json.loads(body) 265 | return data 266 | 267 | 268 | if __name__ == "__main__": 269 | main() 270 | 271 | 272 | -------------------------------------------------------------------------------- /munin-linux-scripts/README.md: -------------------------------------------------------------------------------- 1 | munin-linux-scripts 2 | =================== 3 | 4 | All munin plugins have been developed and tested on Munin 2.0.24 and MikroTik RouterOS 6.24. 5 | 6 | Please use the bugtracker @ https://github.com/acidsploit/munin-scripts/issues to leave any comments, issues or feedback. 7 | 8 | -------------------------------------------------------------------------------- /munin-linux-scripts/sensors2_: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # -*- perl -*- 3 | =head1 NAME 4 | 5 | sensors_ - Wildcard-plugin to monitor information from temperature, 6 | voltage, and fan speed sensors. 7 | 8 | =head1 CONFIGURATION 9 | 10 | The possible wildcard values are the follwing: fan, temp, volt. So you 11 | would create symlinks to this plugin called sensors_fan, sensors_temp, 12 | and sensors_volt. 13 | 14 | The plugins needs the following components configured: 15 | 16 | =over 17 | 18 | =item i2c and lm_sensors modules installed and loaded. 19 | 20 | =item sensors program installed and in path. 21 | 22 | =back 23 | 24 | Note: Sensor names are read from the output of the sensors program. 25 | Change them in /etc/sensors.conf if you don't like them. 26 | 27 | [sensors_*] 28 | env.sensors - Override default sensors program path 29 | env.ignore_temp - Temperature will not be plotted 30 | env.ignore_fan - Fan will not be plotted 31 | env.ignore_volt - Voltage will not be plotted 32 | env.fan_warn_percent - Percentage over mininum for warning 33 | env.volt_warn_percent - Percentage over mininum/under maximum for warning 34 | 35 | =head1 AUTHOR 36 | 37 | Unknown author 38 | 39 | =head1 LICENSE 40 | 41 | GPLv2 42 | 43 | =head1 MAGIC MARKERS 44 | 45 | #%# family=manual 46 | #%# capabilities=autoconf suggest 47 | 48 | =cut 49 | 50 | use strict; 51 | 52 | $ENV{'LANG'} = "C"; # Force parsable output from sensors. 53 | $ENV{'LC_ALL'} = "C"; # Force parsable output from sensors. 54 | my $SENSORS = $ENV{'sensors'} || 'sensors'; 55 | 56 | # Example outputs from sensors & matching regex parts: 57 | 58 | # Fan output example from sensors: 59 | # -------------------------------- 60 | # Case Fan: 1268 RPM (min = 3750 RPM, div = 8) ALARM 61 | # CPU Fan: 0 RPM (min = 1171 RPM, div = 128) ALARM 62 | # Aux Fan: 0 RPM (min = 753 RPM, div = 128) ALARM 63 | # fan4: 3375 RPM (min = 774 RPM, div = 8) 64 | # fan5: 0 RPM (min = 1054 RPM, div = 128) ALARM 65 | # 66 | # ^^^^ ^^^^ ^^^^ 67 | # $1 $2 $3 68 | # 69 | # -------------------------------- 70 | # 71 | # Temperature output example from sensors: 72 | # * Note that the degree character is replaced by a space, as we are running 73 | # with LC_ALL=C and LANG=C. 74 | # --------------------------------------- 75 | # Sys Temp: +41.0 C (high = -128.0 C, hyst = +24.0 C) ALARM sensor = thermistor 76 | # CPU Temp: +40.5 C (high = +80.0 C, hyst = +75.0 C) sensor = thermistor 77 | # AUX Temp: +39.0 C (high = +80.0 C, hyst = +75.0 C) sensor = thermistor 78 | # 79 | # ^^^^^^^^ ^^ ^^ ^^ 80 | # $1 $2 $3 $4 81 | # 82 | # --------------------------------------- 83 | # 84 | # Voltage output example from sensors: 85 | # ------------------------------------ 86 | # 87 | # VCore: +1.09 V (min = +0.00 V, max = +1.74 V) 88 | # in1: +12.14 V (min = +10.51 V, max = +2.38 V) ALARM 89 | # 90 | # ^^^ ^^^ ^^^ ^^ 91 | # $1 $2 $3 $4 92 | # 93 | # 94 | # ------------------------------------ 95 | 96 | 97 | my %config = ( 98 | fan => { 99 | regex => qr/ 100 | ^ # String must start with: 101 | ([^:\n]*) # Match any non-whitespace char, except ':' and new line 102 | # (Match label as \$1) 103 | \s* # Zero or more spaces followed by 104 | : # : character 105 | \s* # Zero or more spaces followed by 106 | \+? # Zero or one '+' char. Note: This might not be needed 107 | # as FAN speeds don't have + signs in front of them. 108 | # This can be probably be removed as the 109 | # sensors program never prints a + char in front of 110 | # RPM values. Verified in lm-sensors-3-3.1.2 111 | (\d+) # Match one or more digits (Match current value as \$2) 112 | \s # Exactly one space followed by 113 | (?: # a optional group, which might contain the minimum value: 114 | RPM.*? # RPM string, and then any chars (but no newlines) 115 | (\d+) # Match one or more digits (Match minimum value as \$3) 116 | \s # Exactly one space followed by 117 | )? # end of optional group 118 | RPM # RPM string 119 | /xm, # Use extended regular expressions and treat string as multiple lines. 120 | title => 'Fans', 121 | vlabel => 'RPM', 122 | print_threshold => \&fan_threshold, 123 | graph_args => '--base 1000 -l 0' 124 | }, 125 | 126 | temp => { 127 | regex => qr/ 128 | ^ # String must start with: 129 | ([^:\n]*) # Match any non-whitespace char, except ':' and new line 130 | # (Match label as \$1) 131 | \s* # Zero or more spaces followed by 132 | : # ':' character 133 | \s* # Zero or more spaces followed by 134 | \+? # Zero or one '+' char followed by 135 | 136 | (-? # Match zero or one '-' char 137 | \d+ # Match one or more digits 138 | # (Match current value as \$2) followed by 139 | 140 | (?:\.\d+)?)# Zero or one match of '.' char followed by one or more 141 | # digits. '?:' means it is not a numbered capture group. 142 | [°\s] # Match degree char or space char 143 | C # Match 'C' char 144 | 145 | (?: # >>>>Match the following statement zero or one time. 146 | # '?:' means it is not a numbered capture group. 147 | \s+ # One or more space followed by 148 | \( # '(' char 149 | (?:high|limit|crit) # 'high' or 'limit' or 'crit' string. 150 | # '?:' means it is not a numbered capture group. 151 | \s*=\s* # Match zero or more spaces and then '=' char and then 152 | # zero or more spaces, followed by 153 | \+? # Zero or one '+' char 154 | (\d+ # Match one or more digits 155 | # (Match high value as \$3) followed by 156 | 157 | (?:\.\d+)?)# Zero or one match of '.' char followed by one or more 158 | # digits. '?:' means it is not a numbered capture group. 159 | [°\s] # Match degree char or space char 160 | C,?\s* # 'C' followed by optional comma and zero or more spaces 161 | (?: # >>>Match the following non-capture group zero or more times 162 | (?:crit|hyst(?:eresis)?) # 'crit' or 'hyst' string followed by optional 'eresis' string. 163 | # '?:' means it is not a numbered capture group. 164 | \s*=\s* # Match zero or more spaces and then '=' char and then 165 | # zero or more spaces, followed by 166 | \+? # Zero or one '+' char 167 | (\d+ # Match one or more digits 168 | # (Match hyst value as \$4) followed by 169 | (?:\.\d+)?)# Zero or one match of '.' char followed by one or more 170 | # digits. '?:' means it is not a numbered capture group. 171 | [°\s]C # Match degree char or space char, and then 'C' char 172 | )? # >>>end of group 173 | \) # ')' char 174 | )? # >>>>end of group 175 | /xm, # Use extended regular expressions and treat string as multiple lines. 176 | title => 'Temperatures', 177 | vlabel => 'degrees Celsius', 178 | print_threshold => \&temp_threshold, 179 | graph_args => '--base 1000 -l 0' 180 | }, 181 | 182 | volt => { 183 | regex => qr/ 184 | ^ # String must start with: 185 | ([^:\n]*) # Match any non-whitespace char, except ':' and new line 186 | # one space in front of them. 187 | # (match the label as \$1) 188 | 189 | \s*:\s* # Zero or more spaces followed by ':' and 190 | # zero or more spaces followed by 191 | \+? # Zero or one '+' char followed by 192 | (-? # Match zero or one '-' char 193 | \d+ # Match one or more digits 194 | # (match the current voltage as \$2) followed by 195 | (?:\.\d+)?) # Zero or one match of '.' char followed by one or more digits. 196 | # '?:' means it is not a numbered capture group. 197 | \sV # one space, 'V' char 198 | 199 | (?: # >>>>Match the following statement. 200 | # '?:' means it is not a numbered capture group. 201 | \s+ # One or more space followed by 202 | \( # '(' char 203 | min # Match min string 204 | \s*=\s* # Match zero or more spaces and then '=' char and 205 | # then zero or more spaces, followed by 206 | \+? # Zero or one '+' char 207 | (-? # Match zero or one '-' char 208 | \d+ # Match one or more digits 209 | # (Match the minimum value as \$3) followed by 210 | (?:\.\d+)?) # Zero or one match of '.' char followed by one or more 211 | # digits. '?:' means it is not a numbered capture group. 212 | \sV,\s* # One space char, 'V,' string followed by zero or 213 | # more spaces 214 | 215 | max # Match 'max' string 216 | \s*=\s* # Match zero or more spaces and then '=' char and 217 | # then zero or more spaces, followed by 218 | \+? # Zero or one '+' char 219 | (-? # Match zero or one '-' char 220 | \d+ # Match one or more digits 221 | # (Match the max value as \$4) followed by 222 | (?:\.\d+)?) # Zero or one match of '.' char followed by one or more digits. 223 | # '?:' means passive group (does not match) 224 | \sV # one space, 'V' char 225 | \) # ')' char 226 | )? # >>>>end of statement 227 | /xm, # Use extended regular expressions and treat string as multiple lines. 228 | 229 | title => 'Voltages', 230 | vlabel => 'Volt', 231 | print_threshold => \&volt_threshold, 232 | graph_args => '--base 1000 --logarithmic' 233 | }, 234 | 235 | power => { 236 | regex => qr/ 237 | ^ # String must start with: 238 | ([^:\n]*) # Match any non-whitespace char, except ':' and new line 239 | # one space in front of them. 240 | # (match the label as \$1) 241 | 242 | \s*:\s* # Zero or more spaces followed by ':' and 243 | # zero or more spaces followed by 244 | (\d+ # Match one or more digits 245 | # (match the power as \$2) followed by 246 | (?:\.\d+)?) # Zero or one match of '.' char followed by one or more digits. 247 | # '?:' means it is not a numbered capture group. 248 | \sW # one space, 'W' char 249 | 250 | (?: # >>>>Match the following statement. 251 | # '?:' means it is not a numbered capture group. 252 | \s+ # One or more space followed by 253 | \( # '(' char 254 | crit # Match crit string 255 | \s*=\s* # Match zero or more spaces and then '=' char and 256 | # then zero or more spaces, followed by 257 | (\d+ # Match one or more digits 258 | # (Match the minimum value as \$3) followed by 259 | (?:\.\d+)?) # Zero or one match of '.' char followed by one or more 260 | # digits. '?:' means it is not a numbered capture group. 261 | \sW\s* # One space char, 'W' character followed by zero or 262 | # more spaces 263 | \) # ')' char 264 | )? # >>>>end of statement 265 | /xm, # Use extended regular expressions and treat string as multiple lines. 266 | 267 | title => 'Power', 268 | vlabel => 'Watts', 269 | print_threshold => \&power_threshold, 270 | graph_args => '--base 1000 --logarithmic' 271 | }, 272 | ); 273 | 274 | if ( defined $ARGV[0] and $ARGV[0] eq 'autoconf' ) { 275 | # Now see if "sensors" can run 276 | my $text = `$SENSORS 2>/dev/null`; 277 | if ($?) { 278 | if ($? == -1) { 279 | print "no (program $SENSORS not found)\n"; 280 | } else { 281 | print "no (program $SENSORS died)\n"; 282 | } 283 | exit 0; 284 | } 285 | 286 | unless ($text =~ /[° ]C/) { 287 | print "no (no temperature readings)\n"; 288 | exit 0; 289 | } 290 | 291 | print "yes\n"; 292 | exit 0; 293 | } 294 | 295 | if (defined $ARGV[0] and $ARGV[0] eq 'suggest') { 296 | my $text = `$SENSORS 2>/dev/null`; 297 | foreach my $func (keys %config) { 298 | print $func, "\n" if $text =~ $config{$func}->{regex}; 299 | } 300 | exit; 301 | } 302 | 303 | $0 =~ /sensors_(.+)*$/; 304 | my $func = $1; 305 | exit 2 unless defined $func; 306 | 307 | if ( defined $ARGV[0] and $ARGV[0] eq 'config' ) { 308 | print "graph_title $config{$func}->{title}\n"; 309 | print "graph_vlabel $config{$func}->{vlabel}\n"; 310 | print "graph_args $config{$func}->{graph_args}\n"; 311 | print "graph_category sensors\n"; 312 | my $text = `$SENSORS`; 313 | my $sensor = 1; 314 | while ($text =~ /$config{$func}->{regex}/g) { 315 | my ($label, undef, $max, $min) = ($1, $2, $3, $4); 316 | print "$func$sensor.label $label\n"; 317 | $config{$func}->{print_threshold}->($func.$sensor, $3, $4); 318 | print "$func$sensor.graph no\n" if exists $ENV{"ignore_$func$sensor"}; 319 | $sensor++; 320 | } 321 | exit 0; 322 | } 323 | 324 | my $text = `$SENSORS`; 325 | my $sensor = 1; 326 | while ($text =~ /$config{$func}->{regex}/g) { 327 | print "$func$sensor.value $2\n"; 328 | $sensor++; 329 | } 330 | 331 | sub fan_threshold { 332 | my $name = shift; 333 | my $min = shift; 334 | 335 | my $warn_percent = exists $ENV{fan_warn_percent} ? $ENV{fan_warn_percent} : 5; 336 | 337 | return unless defined $min; 338 | 339 | printf "$name.warning %d:\n", $min * (100 + $warn_percent) / 100; 340 | printf "$name.critical %d:\n", $min; 341 | } 342 | 343 | sub temp_threshold { 344 | my $name = shift; 345 | my $max = shift; 346 | my $min = shift; 347 | 348 | if (defined($min) and defined($max) and $min > $max) { 349 | ($min, $max) = ($max, $min); 350 | } 351 | 352 | printf "$name.warning $min\n" if $min; 353 | printf "$name.critical $max\n" if $max; 354 | } 355 | 356 | sub volt_threshold { 357 | my $name = shift; 358 | my $min = shift; 359 | my $max = shift; 360 | my $warn_percent = exists $ENV{volt_warn_percent} ? $ENV{volt_warn_percent} : 20; 361 | 362 | return unless defined ($min && $max); 363 | 364 | my $diff = $max - $min; 365 | my $dist = $diff * $warn_percent / 100; 366 | # printf "$name.warning %.2f:%.2f\n", $min + $dist, $max - $dist; 367 | # printf "$name.critical $min:$max\n"; 368 | } 369 | 370 | sub power_threshold { 371 | my $name = shift; 372 | my $crit = shift; 373 | my $warn_percent = exists $ENV{watt_warn_percent} ? $ENV{watt_warn_percent} : 20; 374 | 375 | return unless defined ($crit); 376 | 377 | printf "$name.warning :%.2f\n", $crit * (100-$warn_percent)/100; 378 | printf "$name.critical :$crit\n"; 379 | } 380 | 381 | # vim:syntax=perl 382 | -------------------------------------------------------------------------------- /munin-mikrotik-scripts/README.md: -------------------------------------------------------------------------------- 1 | munin-mikrotik-scripts 2 | ====================== 3 | Munin data collection scripts (plugins) to monitor MikroTik devices. 4 | 5 | I have updated and fixed some of the outdated munin scripts/plugins from http://wiki.mikrotik.com/wiki/Munin_Monitoring, mainly updating OID's, datastructures or a complete rewrite. 6 | 7 | The scripts are written in php or perl. Check the scripts to see which modules or classes you need to install for them to function properly. The scripts themselves communicate with the MikroTik devices thought several protocols, either SNMP, telnet or PHP API. 8 | 9 | All munin plugins have been developed and tested on Munin 2.0.24 and MikroTik RouterOS 6.24. 10 | 11 | Please use the bugtracker @ https://github.com/acidsploit/munin-scripts/issues to leave any comments, issues or feedback. 12 | 13 | Updated plugins: 14 | - /munin-mikrotik-scripts/mikrotikcpu_ 15 | - hostname 16 | - /munin-mikrotik-scripts/mikrotikdiskspace_ 17 | - hostname 18 | - /munin-mikrotik-scripts/mikrotikifrate_ 19 | - hostname_ifname 20 | - /munin-mikrotik-scripts/mikrotikmemory_ 21 | - hostname 22 | 23 | New pugins: 24 | - /munin-mikrotik-scripts/mikrotikuptime_ 25 | - hostname 26 | - /munin-mikrotik-scripts/mikrotiksensors_ 27 | - hostname_temperature 28 | - hostname_voltage 29 | - /munin-mikrotik-scripts/mikrotikwificlients_ 30 | - hostname_ifname 31 | 32 | 33 | 34 | Dependencies: 35 | - PHP: 36 | - routeros_api.class.php 37 | - Perl: 38 | - Net::SNMP 39 | 40 | -------------------------------------------------------------------------------- /munin-mikrotik-scripts/mikrotikcpu_: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Original script from: http://wiki.mikrotik.com/wiki/Munin_Monitoring 4 | 5 | # USAGE 6 | # 7 | # place the script in the munin plugins folder and use the following naming convention: 8 | # 9 | # mikrotikcpu_router-hostname 10 | # 11 | # example: 12 | # mikrotikcpu_router01.local.net 13 | # 14 | # Configuration: 15 | # - Set your SNMP community string $SNMPCommunity 16 | # 17 | # 18 | 19 | ############################################################################### 20 | use diagnostics; 21 | use Net::SNMP; 22 | use strict; 23 | use warnings; 24 | ############################################################################### 25 | my $CPUOID = ".1.3.6.1.2.1.25.3.3.1.2.1"; 26 | 27 | # Set your SNMP community string 28 | my $SNMPCommunity = "community"; 29 | my $SNMPPort = "161"; 30 | 31 | ############################################################################### 32 | ## Determine Hostname 33 | my $Host = undef; 34 | $0 =~ /mikrotikcpu_(.+)*$/; 35 | unless ($Host = $1) { 36 | exit 2; 37 | } 38 | 39 | ############################################################################### 40 | ## Initiate SNMP Session 41 | my ($Session, $Error) = Net::SNMP->session (-hostname => $Host, 42 | -community => $SNMPCommunity, 43 | -port => $SNMPPort, 44 | -timeout => 60, 45 | -retries => 5, 46 | -version => 1); 47 | if (!defined($Session)) { 48 | die "Croaking: $Error"; 49 | } 50 | 51 | ############################################################################### 52 | ## Configuration 53 | if ($ARGV[0] && $ARGV[0] eq "config") { 54 | print "host_name " . $Host . "\n"; 55 | print "graph_args -l 0 -r --vertical-label percent --lower-limit 0 --upper-limit 100\n"; 56 | print "graph_title CPU usage\n"; 57 | print "graph_category system\n"; 58 | print "graph_info This graph shows the router's CPU usage.\n"; 59 | print "graph_order Total\n"; 60 | print "graph_vlabel %\n"; 61 | print "graph_scale no\n"; 62 | print "Total.label CPU Usage\n"; 63 | print "Total.draw AREA\n"; 64 | print "Total.warning 60\n"; 65 | print "Total.critical 90\n"; 66 | $Session->close; 67 | exit; 68 | } 69 | 70 | ############################################################################### 71 | ## Execution 72 | if (my $Result = $Session->get_request(-varbindlist => [$CPUOID])) { 73 | print "Total.value " . $Result->{$CPUOID} . "\n"; 74 | $Session->close; 75 | exit; 76 | } 77 | 78 | -------------------------------------------------------------------------------- /munin-mikrotik-scripts/mikrotikdiskspace_: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | 3 | connect connection string. 19 | # 20 | # 21 | 22 | // Change the following path as appropriate 23 | require('/srv/http/munin/ros/routeros_api.class.php'); 24 | 25 | $API = new routeros_api(); 26 | 27 | // debug 28 | $API->debug = false; 29 | 30 | // Work out hostname 31 | $param = explode("_",$argv[0],2); 32 | 33 | if (isset($param[1])) { 34 | $hostname = $param[1]; 35 | } else { 36 | die("No hostname available. Filename should be like: mikrotikmemory_example.changeip.net"); 37 | } 38 | 39 | //if (isset($param[2])) { 40 | // $ifname = $param[2]; 41 | //} else { 42 | // die("No interface name available. Filename should be like: mikrotikifrate_example.changeip.net_ether1"); 43 | //} 44 | 45 | // change username/password as appropriate 46 | if ($API->connect($hostname, 'munin', 'munin')) { 47 | 48 | //$API->write('/system/resource/print',false); 49 | $API->write('/system/resource/print'); 50 | 51 | $READ = $API->read(false); 52 | $resources = $API->parse_response($READ); 53 | //print_r($resources); 54 | $API->disconnect(); 55 | 56 | $connect = 'yes'; 57 | } else { 58 | $connect = 'no (could not connect)'; 59 | } 60 | 61 | if ($argc > 1 && $argv[1] == 'autoconf') { 62 | print $connect . "\n"; 63 | exit; 64 | } 65 | 66 | // Output configuration information 67 | if ($argc > 1 && $argv[1] == 'config') { 68 | print "host_name $hostname\n"; 69 | #print "graph_args --base 1024 -l 0 --vertical-label Bytes --upper-limit " . ($resources[0]['total-hdd-space'] * 1024) . "\n"; 70 | print "graph_args --base 1024 -l 0 --vertical-label Bytes --upper-limit " . ($resources[0]['total-hdd-space']) . "\n"; 71 | print "graph_title Internal disk usage\n"; 72 | print "graph_vlabel bytes\n"; 73 | print "graph_category system\n"; 74 | print "graph_info This graph shows the internal storage disk usage\n"; 75 | print "graph_order Total Used\n"; 76 | print "Total.label Total Disk\n"; 77 | print "Total.draw AREA\n"; 78 | print "Used.label Used Disk\n"; 79 | print "Used.draw AREA\n"; 80 | 81 | exit; 82 | } 83 | 84 | // Exit if we don't have any servers to report on. 85 | if (empty($resources)) { 86 | exit; 87 | } 88 | 89 | // Finally, print it all out. 90 | foreach ($resources as $resource) 91 | { 92 | //debug 93 | //print_r($resource); 94 | 95 | print "Total.value " . $resource['total-hdd-space'] . "\n"; 96 | 97 | //debug 98 | //print $resource['free-hdd-space'] . "\n"; 99 | 100 | print "Used.value " . ($resource['total-hdd-space'] - $resource['free-hdd-space']) . "\n"; 101 | } 102 | 103 | exit; 104 | 105 | ?> 106 | -------------------------------------------------------------------------------- /munin-mikrotik-scripts/mikrotikifrate_: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | connect connection string. 18 | # 19 | # 20 | 21 | // Change the following path as appropriate 22 | require('/srv/http/munin/ros/routeros_api.class.php'); 23 | 24 | $API = new routeros_api(); 25 | 26 | // debug 27 | $API->debug = false; 28 | 29 | // Work out hostname and interface name 30 | $param = explode("_",$argv[0],3); 31 | 32 | if (isset($param[1])) { 33 | $hostname = $param[1]; 34 | } else { 35 | die("No hostname available. Filename should be like: mikrotikifrate_example.changeip.net_ether1"); 36 | } 37 | 38 | if (isset($param[2])) { 39 | $ifname = $param[2]; 40 | } else { 41 | die("No interface name available. Filename should be like: mikrotikifrate_example.changeip.net_ether1"); 42 | } 43 | 44 | // change username/password as appropriate 45 | if ($API->connect($hostname, 'munin', 'munin')) { 46 | 47 | $API->write('/interface/print',false); 48 | $API->write('=stats='); 49 | 50 | $READ = $API->read(false); 51 | $interfaces = $API->parse_response($READ); 52 | # print_r($interfaces); 53 | $API->disconnect(); 54 | 55 | $connect = 'yes'; 56 | } else { 57 | $connect = 'no (could not connect)'; 58 | } 59 | 60 | if ($argc > 1 && $argv[1] == 'autoconf') { 61 | print $connect . "\n"; 62 | exit; 63 | } 64 | 65 | // Output configuration information 66 | if ($argc > 1 && $argv[1] == 'config') { 67 | print "host_name $hostname\n"; 68 | print "graph_args --base 1000\n"; 69 | print "graph_title $ifname traffic\n"; 70 | print "graph_vlabel bits per second\n"; 71 | print "graph_category network\n"; 72 | print "graph_info This graph shows the incoming and outgoing traffic rate of an interface\n"; 73 | print "in.label received\n"; 74 | print "in.type DERIVE\n"; 75 | print "in.draw AREA\n"; 76 | print "in.min 0\n"; 77 | print "in.graph no\n"; 78 | print "in.cdef in,8,*\n"; 79 | print "out.label bps\n"; 80 | print "out.type DERIVE\n"; 81 | print "out.draw LINE1\n"; 82 | print "out.min 0\n"; 83 | print "out.negative in\n"; 84 | print "out.cdef out,8,*\n"; 85 | 86 | exit; 87 | } 88 | 89 | // Exit if we don't have any servers to report on. 90 | if (empty($interfaces)) { 91 | exit; 92 | } 93 | 94 | // Finally, print it all out. 95 | foreach ($interfaces as $interface) 96 | { 97 | if ($interface['name']==$ifname) 98 | { 99 | //print_r($interface); 100 | $rxbytes = $interface['rx-byte']; 101 | $txbytes = $interface['tx-byte']; 102 | print ("in.value ") . $rxbytes . "\n"; 103 | print ("out.value ") . $txbytes . "\n"; 104 | } 105 | } 106 | 107 | exit; 108 | 109 | ?> 110 | -------------------------------------------------------------------------------- /munin-mikrotik-scripts/mikrotikmemory_: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Original script from: http://wiki.mikrotik.com/wiki/Munin_Monitoring 4 | 5 | # USAGE 6 | # 7 | # place the script in the munin plugins folder and use the following naming convention: 8 | # 9 | # mikrotikcpu_router-hostname 10 | # 11 | # example: 12 | # mikrotikcpu_router01.local.net 13 | # 14 | # Configuration: 15 | # - Set your SNMP community string $SNMPCommunity 16 | # 17 | # 18 | 19 | 20 | ############################################################################### 21 | use diagnostics; 22 | use Net::SNMP; 23 | use strict; 24 | use warnings; 25 | ############################################################################### 26 | my $MemTotalOID = ".1.3.6.1.2.1.25.2.3.1.5.65536"; 27 | my $MemUsedOID = ".1.3.6.1.2.1.25.2.3.1.6.65536"; 28 | my $SNMPCommunity = "community"; 29 | my $SNMPPort = "161"; 30 | 31 | ############################################################################### 32 | ## Determine Hostname 33 | my $Host = undef; 34 | $0 =~ /mikrotikmemory_(.+)*$/; 35 | unless ($Host = $1) { 36 | exit 2; 37 | } 38 | 39 | ############################################################################### 40 | ## Initiate SNMP Session 41 | my ($Session, $Error) = Net::SNMP->session (-hostname => $Host, 42 | -community => $SNMPCommunity, 43 | -port => $SNMPPort, 44 | -timeout => 60, 45 | -retries => 5, 46 | -version => 1); 47 | if (!defined($Session)) { 48 | die "Croaking: $Error"; 49 | } 50 | 51 | ############################################################################### 52 | ## Configuration 53 | if ($ARGV[0] && $ARGV[0] eq "config") { 54 | my $Result = $Session->get_request(-varbindlist => [$MemTotalOID]); 55 | print "host_name " . $Host . "\n"; 56 | print "graph_args --base 1024 -l 0 --vertical-label Bytes --upper-limit " . ($Result->{$MemTotalOID} * 1024) . "\n"; 57 | print "graph_title Memory usage\n"; 58 | print "graph_category system\n"; 59 | print "graph_info This graph shows the router's memory usage.\n"; 60 | print "graph_order Total Used\n"; 61 | print "graph_vlabel bytes\n"; 62 | print "Total.label Total Memory\n"; 63 | print "Total.draw AREA\n"; 64 | print "Used.label Used Memory\n"; 65 | print "Used.draw AREA\n"; 66 | $Session->close; 67 | exit; 68 | } 69 | 70 | ############################################################################### 71 | ## Execution 72 | if (my $Result = $Session->get_request(-varbindlist => [$MemTotalOID, $MemUsedOID])) { 73 | print "Total.value " . ($Result->{$MemTotalOID} * 1024) . "\n"; 74 | print "Used.value " . ($Result->{$MemUsedOID} * 1024) . "\n"; 75 | $Session->close; 76 | exit; 77 | } 78 | 79 | -------------------------------------------------------------------------------- /munin-mikrotik-scripts/mikrotiksensors_: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Original script from: http://wiki.mikrotik.com/wiki/Munin_Monitoring 4 | 5 | # USAGE 6 | # 7 | # place the script in the munin plugins folder and use the following naming convention: 8 | # 9 | # mikrotikcpu_router-hostname_sensor 10 | # 11 | # sensors: 12 | # - voltage 13 | # - temperature 14 | # 15 | # example: 16 | # mikrotikcpu_router01.local.net_voltage 17 | # 18 | # Configuration: 19 | # - Set your SNMP community string $SNMPCommunity 20 | # 21 | # 22 | 23 | 24 | ############################################################################### 25 | use diagnostics; 26 | use Net::SNMP; 27 | use strict; 28 | use warnings; 29 | ############################################################################### 30 | #my $ActiveFanOID = ".1.3.6.1.4.1.14988.1.1.3.9.0"; 31 | my $VoltageOID = ".1.3.6.1.4.1.14988.1.1.3.8.0"; 32 | my $TemperatureOID = ".1.3.6.1.4.1.14988.1.1.3.10.0"; 33 | #my $CPUTemperatureOID = ".1.3.6.1.4.1.14988.1.1.3.11.0"; 34 | #my $CurrentOID = ".1.3.6.1.4.1.14988.1.1.3.13.0"; 35 | #my $PowerConsumptionOID = ".1.3.6.1.4.1.14988.1.1.3.12.0"; 36 | #my $PSU1StateOID = ".1.3.6.1.4.1.14988.1.1.3.15.0"; 37 | #my $PSU2StateOID = ".1.3.6.1.4.1.14988.1.1.3.16.0"; 38 | my $SNMPCommunity = "community"; 39 | my $SNMPPort = "161"; 40 | 41 | ############################################################################### 42 | ## Determine Hostname 43 | my $Host = undef; 44 | my $sensor = undef; 45 | $0 =~ /mikrotiksensors_(.+)_(temperature|voltage)*$/; 46 | unless ($Host = $1) { 47 | die "Could not detect the hostname in the script name. Naming convention: mikrotikcpu_router-hostname_sensor Example: mikrotikcpu_router01.local.net_voltage. E: $!\n"; 48 | } 49 | unless ($sensor = $2){ 50 | die "Could not detect the sensor in the script name. Naming convention: mikrotikcpu_router-hostname_sensor Example: mikrotikcpu_router01.local.net_voltage. E: $!\n"; 51 | } 52 | 53 | ############################################################################### 54 | ## Initiate SNMP Session 55 | my ($Session, $Error) = Net::SNMP->session (-hostname => $Host, 56 | -community => $SNMPCommunity, 57 | -port => $SNMPPort, 58 | -timeout => 60, 59 | -retries => 5, 60 | -version => 1); 61 | if (!defined($Session)) { 62 | die "Croaking: $Error"; 63 | } 64 | 65 | ############################################################################### 66 | ## Configuration 67 | if ($ARGV[0] && $ARGV[0] eq "config") { 68 | if ($sensor eq "temperature"){ 69 | print "host_name " . $Host . "\n"; 70 | print "graph_title Temperature Sensor\n"; 71 | print "graph_vlabel Degrees Celcius\n"; 72 | print "graph_category sensors\n"; 73 | print "temp.label temp\n"; 74 | print "temp.type GAUGE\n"; 75 | print "temp.warning 80\n"; 76 | print "temp.critical 90\n"; 77 | 78 | exit 0; 79 | } 80 | 81 | if ($sensor eq "voltage"){ 82 | print "host_name " . $Host . "\n"; 83 | print "graph_title Voltage Sensor\n"; 84 | print "graph_vlabel Volts\n"; 85 | print "graph_category sensors\n"; 86 | print "voltage.label voltage\n"; 87 | print "voltage.type GAUGE\n"; 88 | 89 | exit 0; 90 | } 91 | 92 | # my $Result = $Session->get_request(-varbindlist => [$MemTotalOID]); 93 | # print "host_name " . $Host . "\n"; 94 | # print "graph_args --base 1024 -l 0 --vertical-label Bytes --upper-limit " . ($Result->{$MemTotalOID} * 1024) . "\n"; 95 | # print "graph_title Memory usage\n"; 96 | # print "graph_category system\n"; 97 | # print "graph_info This graph shows the router's memory usage.\n"; 98 | # print "graph_order Total Used\n"; 99 | # print "graph_vlabel bytes\n"; 100 | # print "Total.label Total Memory\n"; 101 | # print "Total.draw AREA\n"; 102 | # print "Used.label Used Memory\n"; 103 | # print "Used.draw AREA\n"; 104 | # $Session->close; 105 | exit 0; 106 | } 107 | 108 | ############################################################################### 109 | ## Execution 110 | #if (my $Result = $Session->get_request(-varbindlist => [$ActiveFanOID, $VoltageOID, $TemperatureOID, $CPUTemperatureOID, $CurrentOID, $PowerConsumptionOID, $PSU1StateOID, $PSU2StateOID])) { 111 | if (my $Result = $Session->get_request(-varbindlist => [$VoltageOID, $TemperatureOID])) { 112 | 113 | # debug 114 | # print "ActiveFanOID " . $Result->{$ActiveFanOID} . "\n"; 115 | # print "VoltageOID " . $Result->{$VoltageOID} . "\n"; 116 | # print "TemperatureOID " . $Result->{$TemperatureOID} . "\n"; 117 | # print "CPUTemperatureOID " . $Result->{$CPUTemperatureOID} . "\n"; 118 | # print "CurrentOID " . $Result->{$CurrentOID} . "\n"; 119 | # print "PowerConsumptionOID " . $Result->{$PowerConsumptionOID} . "\n"; 120 | # print "PSU1StateOID " . $Result->{$PSU1StateOID,} . "\n"; 121 | # print "PSU2StateOID " . $Result->{$PSU2StateOID} . "\n"; 122 | 123 | if ($sensor eq "temperature"){ 124 | my $temp = ($Result->{$TemperatureOID} / 10); 125 | print "temp.value " . $temp . "\n"; 126 | } 127 | 128 | if ($sensor eq "voltage"){ 129 | my $voltage = ($Result->{$VoltageOID} / 10); 130 | print "voltage.value " . $voltage . "\n"; 131 | } 132 | 133 | 134 | $Session->close; 135 | exit; 136 | } 137 | #else { 138 | # print "something failed\n"; 139 | #} 140 | 141 | -------------------------------------------------------------------------------- /munin-mikrotik-scripts/mikrotikuptime_: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Original script from: http://wiki.mikrotik.com/wiki/Munin_Monitoring 4 | 5 | # USAGE 6 | # 7 | # place the script in the munin plugins folder and use the following naming convention: 8 | # 9 | # mikrotikuptime_router-hostname 10 | # 11 | # example: 12 | # mikrotikuptime_router01.local.net 13 | # 14 | # Configuration: 15 | # - Set your SNMP community string $SNMPCommunity 16 | # 17 | # 18 | 19 | ############################################################################### 20 | use diagnostics; 21 | use Net::SNMP; 22 | use strict; 23 | use warnings; 24 | ############################################################################### 25 | my $UPTOID = ".1.3.6.1.2.1.1.3.0"; 26 | 27 | # Set your SNMP community string 28 | my $SNMPCommunity = "community"; 29 | my $SNMPPort = "161"; 30 | 31 | ############################################################################### 32 | ## Determine Hostname 33 | my $Host = undef; 34 | $0 =~ /mikrotikuptime_(.+)*$/; 35 | unless ($Host = $1) { 36 | exit 2; 37 | } 38 | 39 | ############################################################################### 40 | ## Initiate SNMP Session 41 | my ($Session, $Error) = Net::SNMP->session (-hostname => $Host, 42 | -community => $SNMPCommunity, 43 | -port => $SNMPPort, 44 | -timeout => 60, 45 | -retries => 5, 46 | -version => 1); 47 | if (!defined($Session)) { 48 | die "Croaking: $Error"; 49 | } 50 | 51 | ############################################################################### 52 | ## Configuration 53 | if ($ARGV[0] && $ARGV[0] eq "config") { 54 | print "host_name " . $Host . "\n"; 55 | print "graph_args --base 1000 -l 0\n"; 56 | print "graph_title Uptime\n"; 57 | print "graph_category system\n"; 58 | print "graph_info This graph shows the router's uptime.\n"; 59 | print "graph_vlabel uptime in days\n"; 60 | print "graph_scale no\n"; 61 | print "uptime.label uptime\n"; 62 | print "uptime.draw AREA\n"; 63 | $Session->close; 64 | exit; 65 | } 66 | 67 | ############################################################################### 68 | ## Execution 69 | if (my $Result = $Session->get_request(-varbindlist => [$UPTOID])) { 70 | #debug 71 | #print "Total.value " . $Result->{$UPTOID} . "\n"; 72 | # 1 day, 21:23:18.00 73 | if ($Result->{$UPTOID} =~ m/(\d*)\sday(s,|,)\s(\d\d):(\d\d):(\d\d)\.\d\d/){ 74 | #debug 75 | #print "Days:" . $1 . "\n"; 76 | my $days = $1; 77 | #print "Hours:" . $3 . "\n"; 78 | my $hours = $3; 79 | #print "Minutes:" . $4 . "\n"; 80 | my $minutes = $4; 81 | #print "Seconds:" . $5 . "\n"; 82 | my $seconds = $5; 83 | 84 | my $totalseconds = ($days*86400) + ($hours*3600) + ($minutes*60) + $seconds; 85 | #print $totalseconds . "\n"; 86 | my $decimaluptime = $totalseconds / 86400; 87 | print "uptime.value " . $decimaluptime . "\n"; 88 | } 89 | $Session->close; 90 | exit; 91 | } 92 | 93 | -------------------------------------------------------------------------------- /munin-mikrotik-scripts/mikrotikwificlients_: -------------------------------------------------------------------------------- 1 | #!/usr/bin/php 2 | connect connection string. 18 | # 19 | # 20 | 21 | // Change the following path as appropriate 22 | require('/srv/http/munin/ros/routeros_api.class.php'); 23 | 24 | $API = new routeros_api(); 25 | 26 | // debug 27 | $API->debug = false; 28 | 29 | // Work out hostname and interface name 30 | $param = explode("_",$argv[0],3); 31 | 32 | if (isset($param[1])) { 33 | $hostname = $param[1]; 34 | } else { 35 | die("No hostname available. Filename should be like: mikrotikwificlients_example.changeip.net_ether1"); 36 | } 37 | 38 | if (isset($param[2])) { 39 | $ifname = $param[2]; 40 | } else { 41 | die("No interface name available. Filename should be like: mikrotikwificlients_example.changeip.net_ether1"); 42 | } 43 | 44 | // change username/password as appropriate 45 | if ($API->connect($hostname, 'munin', 'munin')) { 46 | 47 | $API->write('/interface/wireless/monitor',false); 48 | $API->write('=numbers='.$ifname,false); 49 | $API->write('=once='); 50 | 51 | $READ = $API->read(false); 52 | $interfaces = $API->parse_response($READ); 53 | // print_r($interfaces); 54 | $API->disconnect(); 55 | 56 | $connect = 'yes'; 57 | } else { 58 | $connect = 'no (could not connect)'; 59 | } 60 | 61 | if ($argc > 1 && $argv[1] == 'autoconf') { 62 | print $connect . "\n"; 63 | exit; 64 | } 65 | 66 | // Output configuration information 67 | if ($argc > 1 && $argv[1] == 'config') { 68 | print "host_name $hostname\n"; 69 | print "graph_args --base 1000 -l 0\n"; 70 | print "graph_title $ifname clients\n"; 71 | print "graph_vlabel clients\n"; 72 | print "graph_scale no\n"; 73 | print "graph_category network\n"; 74 | print "graph_info This graph shows the registered and authenticated clients of a wireless interface\n"; 75 | print "reg.label registered\n"; 76 | // print "reg.draw AREA\n"; 77 | print "auth.label authenticated\n"; 78 | // print "auth.draw AREA\n"; 79 | 80 | exit; 81 | } 82 | 83 | // Exit if we don't have any servers to report on. 84 | if (empty($interfaces)) { 85 | exit; 86 | } 87 | 88 | // Finally, print it all out. 89 | foreach ($interfaces as $interface) 90 | { 91 | //print_r($interface); 92 | $rxbytes = $interface['registered-clients']; 93 | $txbytes = $interface['authenticated-clients']; 94 | print ("reg.value ") . $rxbytes . "\n"; 95 | print ("auth.value ") . $txbytes . "\n"; 96 | } 97 | 98 | exit; 99 | 100 | ?> 101 | -------------------------------------------------------------------------------- /munin-mikrotik-scripts/routeros_api.class.php: -------------------------------------------------------------------------------- 1 | debug) 39 | echo $text . "\n"; 40 | } 41 | 42 | 43 | /** 44 | * 45 | * 46 | * @param string $length 47 | * 48 | * @return void 49 | */ 50 | function encode_length($length) 51 | { 52 | if ($length < 0x80) { 53 | $length = chr($length); 54 | } else if ($length < 0x4000) { 55 | $length |= 0x8000; 56 | $length = chr(($length >> 8) & 0xFF) . chr($length & 0xFF); 57 | } else if ($length < 0x200000) { 58 | $length |= 0xC00000; 59 | $length = chr(($length >> 16) & 0xFF) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF); 60 | } else if ($length < 0x10000000) { 61 | $length |= 0xE0000000; 62 | $length = chr(($length >> 24) & 0xFF) . chr(($length >> 16) & 0xFF) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF); 63 | } else if ($length >= 0x10000000) 64 | $length = chr(0xF0) . chr(($length >> 24) & 0xFF) . chr(($length >> 16) & 0xFF) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF); 65 | return $length; 66 | } 67 | 68 | 69 | /** 70 | * Login to RouterOS 71 | * 72 | * @param string $ip Hostname (IP or domain) of the RouterOS server 73 | * @param string $login The RouterOS username 74 | * @param string $password The RouterOS password 75 | * 76 | * @return boolean If we are connected or not 77 | */ 78 | function connect($ip, $login, $password) 79 | { 80 | for ($ATTEMPT = 1; $ATTEMPT <= $this->attempts; $ATTEMPT++) { 81 | $this->connected = false; 82 | $this->debug('Connection attempt #' . $ATTEMPT . ' to ' . $ip . ':' . $this->port . '...'); 83 | $this->socket = @fsockopen($ip, $this->port, $this->error_no, $this->error_str, $this->timeout); 84 | if ($this->socket) { 85 | socket_set_timeout($this->socket, $this->timeout); 86 | $this->write('/login'); 87 | $RESPONSE = $this->read(false); 88 | if ($RESPONSE[0] == '!done') { 89 | $MATCHES = array(); 90 | if (preg_match_all('/[^=]+/i', $RESPONSE[1], $MATCHES)) { 91 | if ($MATCHES[0][0] == 'ret' && strlen($MATCHES[0][1]) == 32) { 92 | $this->write('/login', false); 93 | $this->write('=name=' . $login, false); 94 | $this->write('=response=00' . md5(chr(0) . $password . pack('H*', $MATCHES[0][1]))); 95 | $RESPONSE = $this->read(false); 96 | if ($RESPONSE[0] == '!done') { 97 | $this->connected = true; 98 | break; 99 | } 100 | } 101 | } 102 | } 103 | fclose($this->socket); 104 | } 105 | sleep($this->delay); 106 | } 107 | if ($this->connected) 108 | $this->debug('Connected...'); 109 | else 110 | $this->debug('Error...'); 111 | return $this->connected; 112 | } 113 | 114 | 115 | /** 116 | * Disconnect from RouterOS 117 | * 118 | * @return void 119 | */ 120 | function disconnect() 121 | { 122 | fclose($this->socket); 123 | $this->connected = false; 124 | $this->debug('Disconnected...'); 125 | } 126 | 127 | 128 | /** 129 | * Parse response from Router OS 130 | * 131 | * @param array $response Response data 132 | * 133 | * @return array Array with parsed data 134 | */ 135 | function parse_response($response) 136 | { 137 | if (is_array($response)) { 138 | $PARSED = array(); 139 | $CURRENT = null; 140 | $singlevalue = null; 141 | foreach ($response as $x) { 142 | if (in_array($x, array( 143 | '!fatal', 144 | '!re', 145 | '!trap' 146 | ))) { 147 | if ($x == '!re') { 148 | $CURRENT =& $PARSED[]; 149 | } else 150 | $CURRENT =& $PARSED[$x][]; 151 | } else if ($x != '!done') { 152 | $MATCHES = array(); 153 | if (preg_match_all('/[^=]+/i', $x, $MATCHES)) { 154 | if ($MATCHES[0][0] == 'ret') { 155 | $singlevalue = $MATCHES[0][1]; 156 | } 157 | $CURRENT[$MATCHES[0][0]] = (isset($MATCHES[0][1]) ? $MATCHES[0][1] : ''); 158 | } 159 | } 160 | } 161 | if (empty($PARSED) && !is_null($singlevalue)) { 162 | $PARSED = $singlevalue; 163 | } 164 | return $PARSED; 165 | } else 166 | return array(); 167 | } 168 | 169 | 170 | /** 171 | * Parse response from Router OS 172 | * 173 | * @param array $response Response data 174 | * 175 | * @return array Array with parsed data 176 | */ 177 | function parse_response4smarty($response) 178 | { 179 | if (is_array($response)) { 180 | $PARSED = array(); 181 | $CURRENT = null; 182 | $singlevalue = null; 183 | foreach ($response as $x) { 184 | if (in_array($x, array( 185 | '!fatal', 186 | '!re', 187 | '!trap' 188 | ))) { 189 | if ($x == '!re') 190 | $CURRENT =& $PARSED[]; 191 | else 192 | $CURRENT =& $PARSED[$x][]; 193 | } else if ($x != '!done') { 194 | $MATCHES = array(); 195 | if (preg_match_all('/[^=]+/i', $x, $MATCHES)) { 196 | if ($MATCHES[0][0] == 'ret') { 197 | $singlevalue = $MATCHES[0][1]; 198 | } 199 | $CURRENT[$MATCHES[0][0]] = (isset($MATCHES[0][1]) ? $MATCHES[0][1] : ''); 200 | } 201 | } 202 | } 203 | foreach ($PARSED as $key => $value) { 204 | $PARSED[$key] = $this->array_change_key_name($value); 205 | } 206 | return $PARSED; 207 | if (empty($PARSED) && !is_null($singlevalue)) { 208 | $PARSED = $singlevalue; 209 | } 210 | } else { 211 | return array(); 212 | } 213 | } 214 | 215 | 216 | /** 217 | * Change "-" and "/" from array key to "_" 218 | * 219 | * @param array $array Input array 220 | * 221 | * @return array Array with changed key names 222 | */ 223 | function array_change_key_name(&$array) 224 | { 225 | if (is_array($array)) { 226 | foreach ($array as $k => $v) { 227 | $tmp = str_replace("-", "_", $k); 228 | $tmp = str_replace("/", "_", $tmp); 229 | if ($tmp) { 230 | $array_new[$tmp] = $v; 231 | } else { 232 | $array_new[$k] = $v; 233 | } 234 | } 235 | return $array_new; 236 | } else { 237 | return $array; 238 | } 239 | } 240 | 241 | 242 | /** 243 | * Read data from Router OS 244 | * 245 | * @param boolean $parse Parse the data? default: true 246 | * 247 | * @return array Array with parsed or unparsed data 248 | */ 249 | function read($parse = true) 250 | { 251 | $RESPONSE = array(); 252 | $receiveddone = false; 253 | while (true) { 254 | // Read the first byte of input which gives us some or all of the length 255 | // of the remaining reply. 256 | $BYTE = ord(fread($this->socket, 1)); 257 | $LENGTH = 0; 258 | // If the first bit is set then we need to remove the first four bits, shift left 8 259 | // and then read another byte in. 260 | // We repeat this for the second and third bits. 261 | // If the fourth bit is set, we need to remove anything left in the first byte 262 | // and then read in yet another byte. 263 | if ($BYTE & 128) { 264 | if (($BYTE & 192) == 128) { 265 | $LENGTH = (($BYTE & 63) << 8) + ord(fread($this->socket, 1)); 266 | } else { 267 | if (($BYTE & 224) == 192) { 268 | $LENGTH = (($BYTE & 31) << 8) + ord(fread($this->socket, 1)); 269 | $LENGTH = ($LENGTH << 8) + ord(fread($this->socket, 1)); 270 | } else { 271 | if (($BYTE & 240) == 224) { 272 | $LENGTH = (($BYTE & 15) << 8) + ord(fread($this->socket, 1)); 273 | $LENGTH = ($LENGTH << 8) + ord(fread($this->socket, 1)); 274 | $LENGTH = ($LENGTH << 8) + ord(fread($this->socket, 1)); 275 | } else { 276 | $LENGTH = ord(fread($this->socket, 1)); 277 | $LENGTH = ($LENGTH << 8) + ord(fread($this->socket, 1)); 278 | $LENGTH = ($LENGTH << 8) + ord(fread($this->socket, 1)); 279 | $LENGTH = ($LENGTH << 8) + ord(fread($this->socket, 1)); 280 | } 281 | } 282 | } 283 | } else { 284 | $LENGTH = $BYTE; 285 | } 286 | // If we have got more characters to read, read them in. 287 | if ($LENGTH > 0) { 288 | $_ = ""; 289 | $retlen = 0; 290 | while ($retlen < $LENGTH) { 291 | $toread = $LENGTH - $retlen; 292 | $_ .= fread($this->socket, $toread); 293 | $retlen = strlen($_); 294 | } 295 | $RESPONSE[] = $_; 296 | $this->debug('>>> [' . $retlen . '/' . $LENGTH . '] bytes read.'); 297 | } 298 | // If we get a !done, make a note of it. 299 | if ($_ == "!done") 300 | $receiveddone = true; 301 | $STATUS = socket_get_status($this->socket); 302 | if ($LENGTH > 0) 303 | $this->debug('>>> [' . $LENGTH . ', ' . $STATUS['unread_bytes'] . ']' . $_); 304 | if ((!$this->connected && !$STATUS['unread_bytes']) || ($this->connected && !$STATUS['unread_bytes'] && $receiveddone)) 305 | break; 306 | } 307 | if ($parse) 308 | $RESPONSE = $this->parse_response($RESPONSE); 309 | return $RESPONSE; 310 | } 311 | 312 | 313 | /** 314 | * Write (send) data to Router OS 315 | * 316 | * @param string $command A string with the command to send 317 | * @param mixed $param2 If we set an integer, the command will send this data as a "tag" 318 | * If we set it to boolean true, the funcion will send the comand and finish 319 | * If we set it to boolean false, the funcion will send the comand and wait for next command 320 | * Default: true 321 | * 322 | * @return boolean Return false if no command especified 323 | */ 324 | function write($command, $param2 = true) 325 | { 326 | if ($command) { 327 | $data = explode("\n", $command); 328 | foreach ($data as $com) { 329 | $com = trim($com); 330 | fwrite($this->socket, $this->encode_length(strlen($com)) . $com); 331 | $this->debug('<<< [' . strlen($com) . '] ' . $com); 332 | } 333 | if (gettype($param2) == 'integer') { 334 | fwrite($this->socket, $this->encode_length(strlen('.tag=' . $param2)) . '.tag=' . $param2 . chr(0)); 335 | $this->debug('<<< [' . strlen('.tag=' . $param2) . '] .tag=' . $param2); 336 | } else if (gettype($param2) == 'boolean') 337 | fwrite($this->socket, ($param2 ? chr(0) : '')); 338 | return true; 339 | } else 340 | return false; 341 | } 342 | 343 | 344 | /** 345 | * Write (send) data to Router OS 346 | * 347 | * @param string $com A string with the command to send 348 | * @param array $arr An array with arguments or queries 349 | * 350 | * @return array Array with parsed 351 | */ 352 | function comm($com, $arr = array()) 353 | { 354 | $count = count($arr); 355 | $this->write($com, !$arr); 356 | $i = 0; 357 | foreach ($arr as $k => $v) { 358 | switch ($k[0]) { 359 | case "?": 360 | $el = "$k=$v"; 361 | break; 362 | case "~": 363 | $el = "$k~$v"; 364 | break; 365 | default: 366 | $el = "=$k=$v"; 367 | break; 368 | } 369 | $last = ($i++ == $count - 1); 370 | $this->write($el, $last); 371 | } 372 | return $this->read(); 373 | } 374 | } 375 | ?> 376 | 377 | -------------------------------------------------------------------------------- /munin-munin-scripts/munin_stats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # -*- perl -*- 3 | # 4 | # Copyright (C) 2006-2009 Rodolphe Quiedeville 5 | # Edited by acidsploit@github on 20150104 6 | # 7 | # 8 | # This program is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU General Public License 10 | # as published by the Free Software Foundation; version 2 dated June, 11 | # 1991. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | # 22 | # $Id$ 23 | # 24 | # Magic markers (used by munin-node-configure and some installation scripts): 25 | #%# family=auto 26 | #%# capabilities=autoconf 27 | 28 | use strict; 29 | use warnings; 30 | 31 | use Munin::Plugin; 32 | 33 | my @logs = qw/update graph html limits/; 34 | my $logdir = ($ENV{'logdir'} || $ENV{'MUNIN_LOGDIR'} || '/var/log/munin'); 35 | 36 | if ($ARGV[0] and $ARGV[0] eq 'autoconf') { 37 | my $munin_update_location = 38 | "$Munin::Common::Defaults::MUNIN_LIBDIR/munin-update"; 39 | 40 | if (! -e $munin_update_location) { 41 | print "no (munin-update was not found at $munin_update_location)\n"; 42 | exit 0; 43 | } 44 | 45 | if (! -x $munin_update_location) { 46 | print "no ($munin_update_location was found, but is not executable)\n"; 47 | exit 0; 48 | } 49 | else { 50 | print "yes\n"; 51 | exit 0; 52 | } 53 | } 54 | 55 | if ($ARGV[0] and $ARGV[0] eq "config") { 56 | print "graph_title Munin processing time\n", 57 | "graph_info This graph shows the run time of the four different processes making up a munin-master run. Munin-master is run from cron every 5 minutes and we want each of the programmes in munin-master to complete before the next instance starts. Especially munin-update and munin-graph are time consuming and their run time bears watching. If munin-update uses too long time to run please see the munin-update graph to determine which host is slowing it down. If munin-graph is running too slow you need to get clever (email the munin-users mailing list) unless you can buy a faster computer with better disks to run munin on.\n", 58 | "graph_args --base 1000 -l 0\n", 59 | "graph_scale yes\n", 60 | "graph_vlabel seconds\n", 61 | "graph_category munin\n"; 62 | foreach my $log (@logs) { 63 | print "$log.label munin $log\n"; 64 | print "$log.draw AREASTACK\n"; 65 | } 66 | print "update.warning 240\n"; 67 | print "update.critical 285\n"; 68 | print "graph.warning 240\n"; 69 | print "graph.critical 285\n"; 70 | exit 0; 71 | } 72 | 73 | my %positions = restore_state(); 74 | my %times; 75 | 76 | foreach my $log (@logs) { 77 | my $logfile = "$logdir/munin-$log.log"; 78 | my $time = 'U'; 79 | 80 | if (! -r $logfile) { 81 | print "$log.extinfo Can't open $logfile for reading\n"; 82 | print "$log.value $time\n"; 83 | next; 84 | } 85 | 86 | if (exists $positions{$log}) { 87 | my ($LOGFILE, undef) = tail_open($logfile, $positions{$log}); 88 | while (<$LOGFILE>) { 89 | $time = $1 if (/finished \((\d+\.\d+)\ssec\)$/); 90 | } 91 | $positions{$log} = tail_close($LOGFILE); 92 | } 93 | else { 94 | # Do nothing on first run except find the current file end. 95 | $positions{$log} = (stat $logfile)[7]; 96 | } 97 | 98 | # TODO: find this file in the fs (Maybe with Munin::Plugin?) 99 | my $graphstatfile = "/var/lib/munin/munin-graph.stats"; 100 | if ($log eq "graph"){ 101 | if (! -r $graphstatfile) { 102 | print "$log.extinfo Can't open $graphstatfile for reading\n"; 103 | print "$log.value $time\n"; 104 | next; 105 | } 106 | 107 | open(my $STATFILE, "<", $graphstatfile) 108 | or die "Can't open < $graphstatfile: $!"; 109 | while (<$STATFILE>) { 110 | $time = $1 if (/GS\|(\d+\.\d+)/); 111 | } 112 | } 113 | 114 | print "$log.value $time\n"; 115 | } 116 | 117 | save_state(%positions); 118 | 119 | # vim: ft=perl : ts=4 : expandtab 120 | -------------------------------------------------------------------------------- /munin-nvidia-scripts/README.md: -------------------------------------------------------------------------------- 1 | munin-nvidia-scripts 2 | ==================== 3 | 4 | All munin plugins have been developed and tested on Munin 2.0.24. 5 | 6 | Please use the bugtracker @ https://github.com/acidsploit/munin-scripts/issues to leave any comments, issues or feedback. 7 | 8 | -------------------------------------------------------------------------------- /munin-nvidia-scripts/nvidiasmi_: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # -*- cperl -*- 3 | 4 | use strict; 5 | 6 | use Munin::Plugin; 7 | 8 | my @dircomponents = split('/',$0); 9 | my $me = pop(@dircomponents); 10 | 11 | my @suggest=qw(memory temp fan); 12 | 13 | =head1 NAME 14 | 15 | nvidia_ - Munin wildcard plugin to monitor nvidia graphics cards with 16 | the help of the nvclock command. 17 | 18 | Run as nvidia_memory, nvidia_temp or nvidia_fan 19 | 20 | =cut 21 | 22 | =head1 APPLICABLE SYSTEMS 23 | 24 | Any system with a nvidia-smi command. 25 | 26 | =head1 CONFIGURATION 27 | 28 | Usually none is needed. This shows the default configuration: 29 | 30 | [nvidiasmi_*] 31 | env.nvidiasmi = /usr/bin/nvidia-smi 32 | 33 | =cut 34 | 35 | my $nvidiasmi = $ENV{nvidiasmi} || '/usr/bin/nvidia-smi'; 36 | 37 | =head1 INTERPRETATION 38 | 39 | The plugin invoked under the different aliases listed above will run 40 | the nvidia-smi command and show the different measurements as found in 41 | the output of the program. 42 | 43 | =head1 VERSION 44 | 45 | $Id$ 46 | 47 | Tested with NVIDIA System Management Interface -- v343.36 on a NVIDIA GeForce GTX 650 48 | 49 | =head1 BUGS 50 | 51 | None known 52 | 53 | =head1 FEATURES 54 | 55 | Requires Munin::Plugin as supplied in Munin 1.3.3 and 1.2.5. If the 56 | plugin complains about "Use of uninitialized value in string eq at 57 | /usr/lib/perl/5.8/lib.pm line 29." and so on please make this plugin 58 | configuration: 59 | 60 | [*] 61 | env.MUNIN_LIBDIR /usr/share/munin 62 | 63 | using the correct LIBDIR for your installation of course (the other 64 | standard value is /opt/munin/lib). 65 | 66 | 67 | =head1 AUTHOR 68 | 69 | Copyright (C) 2008-2009 Nicolai Langfeldt / Linpro AS, Oslo 70 | 71 | =head1 LICENSE 72 | 73 | GPLv2 74 | 75 | =head1 MAGIC MARKERS 76 | 77 | #%# family=auto 78 | #%# capabilities=autoconf suggest 79 | 80 | =cut 81 | 82 | delete $ENV{'DISPLAY'}; 83 | 84 | sub collect_and_print ($$) { 85 | 86 | my ($todo,$function)=@_; 87 | 88 | my $cardinfo; 89 | 90 | my $config = $todo eq 'config'; 91 | 92 | my $NVSMI; 93 | 94 | open($NVSMI,"$nvidiasmi -q |") or die "Could not run $nvidiasmi: $!\n"; 95 | 96 | my @nvidiasmi; 97 | 98 | @nvidiasmi = <$NVSMI>; 99 | close($NVSMI) or die "Could not close command $nvidiasmi: $!\n"; 100 | 101 | my $section; 102 | 103 | foreach (@nvidiasmi) { 104 | 105 | if (/^-- (.*) --/) { 106 | $section=$1; 107 | 108 | # Remove the "info" or "informaiton" part 109 | $section =~ s/\s+info.*//; 110 | 111 | next; 112 | } 113 | 114 | my ($key,$value); 115 | ( $key,$value ) = split(':\s+',$_,2); 116 | 117 | next if ! defined($value); 118 | 119 | chomp $value; 120 | 121 | # Preprocessing special cases 122 | ($key eq 'Clock' ) && do { $key = "$section $key"; }; 123 | ($key eq 'Card' ) && do { $cardinfo = $value; }; 124 | ($key eq 'Version') && do { $cardinfo .= " Version $value"; }; 125 | ($key =~ /^Signon/) && do { $cardinfo .= " $value"; }; 126 | ($key eq 'Amount' ) && 127 | ($section eq 'Memory') && do { $cardinfo .= ", with $value"; }; 128 | ($key =~ 'Type' ) && 129 | ($section eq 'Memory') && do { $cardinfo .= " $value memory"; }; 130 | 131 | # Yes, the apperance of the $cardinfo related things will be 132 | # fairly order sensitive, tell me if it breaks. 133 | 134 | my $label = clean_fieldname($key); 135 | 136 | # Processing each case of the plugin 137 | 138 | ($key =~ /voltage/i) && ($function eq 'volt') && do { 139 | if ($config) { 140 | print "$label.label $key\n"; 141 | print "$label.type GAUGE\n"; 142 | } else { 143 | my ($volt) = $value =~ m/\s*(\d+\.\d+)V/; 144 | $volt = 'U' unless defined $volt; 145 | print "$label.value $volt\n"; 146 | } 147 | next; 148 | }; 149 | 150 | ($key =~ /clock/i) && ($function eq 'clock') && do { 151 | if ($config) { 152 | print "$label.label $key\n"; 153 | print "$label.type GAUGE\n"; 154 | } else { 155 | my ($hz,$scale) = $value =~ m/\s*(\d+\.\d+)\s*([Mk]?)Hz/; 156 | if (defined($hz)) { 157 | $scale = '' unless defined($scale); 158 | $hz=$hz*1000*1000 if $scale eq 'M'; 159 | $hz=$hz*1000 if $scale eq 'k'; 160 | } else { 161 | $hz='U'; 162 | } 163 | print "$label.value $hz\n"; 164 | } 165 | next; 166 | }; 167 | 168 | ($key =~ /temp/i) && ($function eq 'temp') && do { 169 | if ($config) { 170 | print "$label.label $key\n"; 171 | print "$label.type GAUGE\n"; 172 | } else { 173 | my ($temp) = $value =~ m/\s*(\d+(\.\d+)?)C/; 174 | $temp='U' unless defined($temp); 175 | print "$label.value $temp\n"; 176 | } 177 | next; 178 | } 179 | } 180 | 181 | if ($config) { 182 | if ($function eq 'memory') { 183 | print "graph_title GPU Memory usage\n"; 184 | print "graph_vlabel megabyte (MB)\n"; 185 | } elsif ($function eq 'temp') { 186 | print "graph_title GPU Temperature\n"; 187 | print "graph_vlabel Degrees Celcius\n"; 188 | } elsif ($function eq 'fan') { 189 | print "graph_title GPU Percentage of intended fan speed\n"; 190 | print "graph_vlabel %\n"; 191 | } else { 192 | die "$me: Unknown function!\n"; 193 | } 194 | print "graph_category sensors\n"; 195 | print "graph_info Graphics card is a $cardinfo\n"; 196 | } 197 | } 198 | 199 | 200 | # Main 201 | 202 | my ($function) = ( $me =~ m/.*_(.*)/ ); 203 | 204 | if (defined($ARGV[0])) { 205 | if ($ARGV[0] eq 'autoconf') { 206 | if (-x $nvidiasmi) { 207 | print "yes\n"; 208 | exit 0; 209 | } else { 210 | print "no (no nvidia-smi executable at $nvidiasmi, please configure)\n"; 211 | exit 0; 212 | } 213 | } elsif ($ARGV[0] eq 'suggest') { 214 | print join("\n",@suggest),"\n"; 215 | exit 0; 216 | } elsif ($ARGV[0] eq 'config') { 217 | collect_and_print('config',$function); 218 | exit 0; 219 | } elsif ($ARGV[0] eq '') { 220 | collect_and_print('fetch',$function); 221 | exit 0; 222 | } else { 223 | die "$me: Unknown argument: $ARGV[0]\n"; 224 | } 225 | } else { 226 | collect_and_print('fetch',$function); 227 | exit 0; 228 | } 229 | 230 | die "$me: Running over the edge of the plugin. Why?" 231 | --------------------------------------------------------------------------------