check_speedtest-cli.sh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. #! /bin/bash
  2. #
  3. # Script to check Internet connection speed using speedtest-cli
  4. #
  5. # Jon Witts - 20150228
  6. #
  7. #########################################################################################################################################################
  8. #
  9. # Nagios Exit Codes
  10. #
  11. # 0 = OK = The plugin was able to check the service and it appeared to be functioning properly
  12. # 1 = Warning = The plugin was able to check the service, but it appeared to be above some warning
  13. # threshold or did not appear to be working properly
  14. # 2 = Critical = The plugin detected that either the service was not running or it was above some critical threshold
  15. # 3 = Unknown = Invalid command line arguments were supplied to the plugin or low-level failures internal
  16. # to the plugin (such as unable to fork, or open a tcp socket) that prevent it from performing the specified operation.
  17. # Higher-level errors (such as name resolution errors, socket timeouts, etc) are outside of the control of plugins
  18. # and should generally NOT be reported as UNKNOWN states.
  19. #
  20. ########################################################################################################################################################
  21. plugin_name="Nagios speedtest-cli plugin"
  22. version="1.2 2015022818.19"
  23. #####################################################################
  24. #
  25. # CHANGELOG
  26. #
  27. # Version 1.0 - Initial Release
  28. #
  29. # Version 1.1 - Added requirement to use server id in test and need to define
  30. # full path to speedtest binary - thanks to Sigurdur Bjarnason
  31. # for changes and improvements
  32. #
  33. # Version 1.2 - Added ability to check speed from an internal Speedtest Mini
  34. # server. Idea sugested by Erik Brouwer
  35. #
  36. #
  37. #
  38. #####################################################################
  39. # function to output script usage
  40. usage()
  41. {
  42. cat << EOF
  43. ******************************************************************************************
  44. $plugin_name - Version: $version
  45. OPTIONS:
  46. -h Show this message
  47. -w Download Warning Level - *Required* - integer or floating point
  48. -c Download Critical Level - *Required* - integer or floating point
  49. -W Upload Warning Level - *Required* - integer or floating point
  50. -C Upload Critical Level - *Required* - integer or floating point
  51. -l Location of speedtest server - *Required * - takes either "i" or "e". If you pass "i" for
  52. Internal then you will need to pass the URL of the Mini Server to the "s" option. If you pass
  53. "e" for External then you must pass the server integer to the "s" option.
  54. -s Server integer or URL for the speedtest server to test against - *Required* - Run
  55. "speedtest --list | less" to find your nearest server and note the number of the server
  56. or use the URL of an internal Speedtest Mini Server
  57. -p Output Performance Data
  58. -v Output plugin version
  59. -V Output debug info for testing
  60. This script will output the Internet Connection Speed using speedtest-cli to Nagios.
  61. You need to have installed speedtest-cli on your system first and ensured that it is
  62. working by calling "speedtest --simple".
  63. See here: https://github.com/sivel/speedtest-cli for info about speedtest-cli
  64. First you MUST define the location of your speedtest install in the script or this will
  65. not work.
  66. The speedtest-cli can take some time to return its result. I recommend that you set the
  67. service_check_timeout value in your main nagios.cfg to 120 to allow time for
  68. this script to run; but test yourself and adjust accordingly.
  69. You also need to have access to bc on your system for this script to work and that it
  70. exists in your path.
  71. Your warning levels must be higher than your critical levels for both upload and download.
  72. Performance Data will output upload and download speed against matching warning and
  73. critical levels.
  74. Jon Witts
  75. ******************************************************************************************
  76. EOF
  77. }
  78. #####################################################################
  79. # function to output error if speedtest binary location not set
  80. locundef()
  81. {
  82. cat << EOF
  83. ******************************************************************************************
  84. $plugin_name - Version: $version
  85. You have not defined the location of the speedtest binary in the script! You MUST do
  86. this before running the script. See line 170 of the script!
  87. ******************************************************************************************
  88. EOF
  89. }
  90. #####################################################################
  91. # function to check if a variable is numeric
  92. # expects variable to check as first argument
  93. # and human description of variable as second
  94. isnumeric()
  95. {
  96. re='^[0-9]+([.][0-9]+)?$'
  97. if ! [[ $1 =~ $re ]]; then
  98. echo $2" with a value of: "$1" is not a number!"
  99. usage
  100. exit 3
  101. fi
  102. }
  103. #####################################################################
  104. # functions for floating point operations - require bc!
  105. #####################################################################
  106. # Default scale used by float functions.
  107. float_scale=3
  108. #####################################################################
  109. # Evaluate a floating point number expression.
  110. function float_eval()
  111. {
  112. local stat=0
  113. local result=0.0
  114. if [[ $# -gt 0 ]]; then
  115. result=$(echo "scale=$float_scale; $*" | bc -q 2>/dev/null)
  116. stat=$?
  117. if [[ $stat -eq 0 && -z "$result" ]]; then stat=1; fi
  118. fi
  119. echo $result
  120. return $stat
  121. }
  122. #####################################################################
  123. # Evaluate a floating point number conditional expression.
  124. function float_cond()
  125. {
  126. local cond=0
  127. if [[ $# -gt 0 ]]; then
  128. cond=$(echo "$*" | bc -q 2>/dev/null)
  129. if [[ -z "$cond" ]]; then cond=0; fi
  130. if [[ "$cond" != 0 && "$cond" != 1 ]]; then cond=0; fi
  131. fi
  132. local stat=$((cond == 0))
  133. return $stat
  134. }
  135. ########### End of functions ########################################
  136. # Set up the variable for the location of the speedtest binary.
  137. # Edit the line below so that the variable is defined as the location
  138. # to speedtest on your system. On mine it is /usr/local/bin
  139. # Ensure to leave the last slash off!
  140. # You MUST define this or the script will not run!
  141. STb=/usr/bin
  142. # Set up the variables to take the arguments
  143. DLw=
  144. DLc=
  145. ULw=
  146. ULc=
  147. Loc=e
  148. SEs=
  149. PerfData=
  150. debug=
  151. # Retrieve the arguments using getopts
  152. while getopts "hw:c:W:C:l:s:pvV" OPTION
  153. do
  154. case $OPTION in
  155. h)
  156. usage
  157. exit 3
  158. ;;
  159. w)
  160. DLw=$OPTARG
  161. ;;
  162. c)
  163. DLc=$OPTARG
  164. ;;
  165. W)
  166. ULw=$OPTARG
  167. ;;
  168. C)
  169. ULc=$OPTARG
  170. ;;
  171. l)
  172. Loc=$OPTARG
  173. ;;
  174. s)
  175. SEs=$OPTARG
  176. ;;
  177. p)
  178. PerfData="TRUE"
  179. ;;
  180. v)
  181. echo "$plugin_name. Version number: $version"
  182. exit 3
  183. ;;
  184. V)
  185. debug="TRUE"
  186. ;;
  187. esac
  188. done
  189. # Check if the Speedtest binary variable $STb has been defined and exit with warning if not
  190. if [[ -z $STb ]]
  191. then
  192. locundef
  193. exit 3
  194. fi
  195. # Check for empty arguments and exit to usage if found
  196. if [[ -z $DLw ]] || [[ -z $DLc ]] || [[ -z $ULw ]] || [[ -z $ULc ]] || [[ -z $Loc ]] || [[ -z $SEs ]]
  197. then
  198. usage
  199. exit 3
  200. fi
  201. # Check for invalid argument passed to $Loc and exit to usage if found
  202. if [[ "$Loc" != "e" ]] && [[ "$Loc" != "i" ]]
  203. then
  204. usage
  205. exit 3
  206. fi
  207. # Check for non-numeric arguments
  208. isnumeric $DLw "Download Warning Level"
  209. isnumeric $DLc "Download Critical Level"
  210. isnumeric $ULw "Upload Warning Level"
  211. isnumeric $ULc "Upload Critical Level"
  212. #isnumeric $Serv "Server Number ID"
  213. # Check that warning levels are not less than critical levels
  214. if float_cond "$DLw < $DLc"; then
  215. echo "\$DLw is less than \$DLc!"
  216. usage
  217. exit 3
  218. elif float_cond "$ULw < $ULc"; then
  219. echo "\$ULw is less than \$ULc!"
  220. usage
  221. exit 3
  222. fi
  223. # Output arguments for debug
  224. if [ "$debug" == "TRUE" ]; then
  225. echo "Download Warning Level = "$DLw
  226. echo "Download Critical Level = "$DLc
  227. echo "Upload Warning Level = "$ULw
  228. echo "Upload Critical Level = "$ULc
  229. echo "Server Location = "$Loc
  230. echo "Server URL or Integer = "$SEs
  231. fi
  232. #Set command up depending upon internal or external
  233. if [ "$Loc" == "e" ]; then
  234. if [ "$debug" == "TRUE" ]; then
  235. echo "External Server defined"
  236. fi
  237. command=$($STb/speedtest --server=$SEs --simple)
  238. elif [ "$Loc" == "i" ]; then
  239. if [ "$debug" == "TRUE" ]; then
  240. echo "Internal Server defined"
  241. fi
  242. command=$($STb/speedtest --mini=$SEs --simple)
  243. else
  244. if [ "$debug" == "TRUE" ]; then
  245. echo "We should never get here as we checked the contents of Location variable earlier!"
  246. fi
  247. usage
  248. exit 3
  249. fi
  250. # Get the output of the speedtest into an array
  251. # so we can begin to process it
  252. i=1
  253. typeset -a array
  254. array=($command)
  255. # Check if array empty or not having at least 9 indicies
  256. element_count=${#array[@]}
  257. expected_count="9"
  258. # Output array indicies count for debug
  259. if [ "$debug" == "TRUE" ]; then
  260. echo "count = $element_count"
  261. fi
  262. if [ "$element_count" -ne "$expected_count" ]; then
  263. echo "You do not have the expected number of indices in your output from SpeedTest. Is it correctly installed?"
  264. usage
  265. exit 3
  266. fi
  267. # echo contents of speedtest for debug
  268. if [ "$debug" == "TRUE" ]; then
  269. echo "$command"
  270. fi
  271. # split array into our variables for processing
  272. ping=${array[1]}
  273. pingUOM=${array[2]}
  274. download=${array[4]}
  275. downloadUOM=${array[5]}
  276. upload=${array[7]}
  277. uploadUOM=${array[8]}
  278. # echo each array for debug
  279. if [ "$debug" == "TRUE" ]; then
  280. echo "Ping = "$ping
  281. echo "Download = "$download
  282. echo "Upload = "$upload
  283. fi
  284. #set up our nagios status and exit code variables
  285. status=
  286. nagcode=
  287. # now we check to see if returned values are within defined ranges
  288. # we will make use of bc for our math!
  289. if float_cond "$download < $DLc"; then
  290. if [ "$debug" == "TRUE" ]; then
  291. echo "Download less than critical limit. \$download = $download and \$DLc = $DLc "
  292. fi
  293. status="CRITICAL"
  294. nagcode=2
  295. elif float_cond "$upload < $ULc"; then
  296. if [ "$debug" == "TRUE" ]; then
  297. echo "Upload less than critical limit. \$upload = $upload and \$ULc = $ULc"
  298. fi
  299. status="CRITICAL"
  300. nagcode=2
  301. elif float_cond "$download < $DLw"; then
  302. if [ "$debug" == "TRUE" ]; then
  303. echo "Download less than warning limit. \$download = $download and \$DLw = $DLw"
  304. fi
  305. status="WARNING"
  306. nagcode=1
  307. elif float_cond "$upload < $ULw"; then
  308. if [ "$debug" == "TRUE" ]; then
  309. echo "Upload less than warning limit. \$upload = $upload and \$ULw = $ULw"
  310. fi
  311. status="WARNING"
  312. nagcode=1
  313. else
  314. if [ "$debug" == "TRUE" ]; then
  315. echo "Everything within bounds!"
  316. fi
  317. status="OK"
  318. nagcode=0
  319. fi
  320. nagout="$status - Ping = $ping $pingUOM Download = $download $downloadUOM Upload = $upload $uploadUOM"
  321. perfout="|'download'=$download;$DLw;$DLc 'upload'=$upload;$ULw;$ULc"
  322. # append perfout if argument was passed to script
  323. if [ "$PerfData" == "TRUE" ]; then
  324. if [ "$debug" == "TRUE" ]; then
  325. echo "PerfData requested!"
  326. fi
  327. nagout=$nagout$perfout
  328. fi
  329. echo $nagout
  330. exit $nagcode