Plugin:check vwmare esx


 * 1) !/usr/bin/perl -w
 * 2) Nagios plugin to monitor vmware ESX and vSphere servers
 * 3) License: GPL
 * 4) This plugin is a forked by Martin Fuerstenau from the original one from op5
 * 5) Copyright (c) 2008 op5 AB
 * 6) Author: Kostyantyn Hushchyn 
 * 7) Contributor(s): Patrick MÃ¼ller, Jeremy Martin, Eric Jonsson, stumpr, John Cavanaugh, Libor Klepac, maikmayers, Steffen Poulsen, Mark Elliott, simeg, sebastien.prudhomme, Raphael Schitz
 * 8) This program is free software; you can redistribute it and/or modify
 * 9) it under the terms of the GNU General Public License version 2 as
 * 10) published by the Free Software Foundation.
 * 11) This program is distributed in the hope that it will be useful,
 * 12) but WITHOUT ANY WARRANTY; without even the implied warranty of
 * 13) MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * 14) GNU General Public License for more details.
 * 15) You should have received a copy of the GNU General Public License
 * 16) along with this program.  If not, see .
 * 17) History and Changes:
 * 18) - 22 Mar 2012 M.Fuerstenau
 * 19)   - Started with actual version 0.5.0
 * 20)   - Impelemented check_esx3new2.diff from Simon (simeg / simmerl)
 * 21)   - Reimplemented the changes of Markus Obstmayer for the actual version
 * 22)   - Comments within the code inform you about the changes
 * 23)   - It may happen that controllers has been found which are not active.
 * 24)     Therefor around line 2300        the following was added:
 * 25)     # M.Fuerstenau - additional to avoid using inactive controllers --
 * 26)      elsif (uc($dev->status) eq "3")
 * 27)            $status = 0;
 * 28)            }
 * 29)           else
 * 30)            $state = 3;
 * 31)           }
 * 32)            $actual_state = Nagios::Plugin::Functions::max_state($actual_state, $status);
 * 33)            }
 * 34)            $perfdata = $perfdata . " adapters=" . $count . ";"$perf_thresholds . ";;";
 * 35)           # M.Fuerstenau - changed the output a little bit
 * 36)           $output .= $count . " of " . @{$storage->storageDeviceInfo->hostBusAdapter} . " defined/possible adapters online, ";
 * 37) - 30 Mar 2012 M.Fuerstenau
 * 38)   - added --ignore_unknown. This maps 3 to 0. Why? You have for example several host adapters. Some are reported as
 * 39)     unknown by the plugin because they are not used or have not the capability to reports something senseful.
 * 40) - 02 Apr 2012 M.Fuerstenau
 * 41)   - _info (Adapter/LUN/Path). Removed perfdata. To count such items and display as perfdata doesn't make sense
 * 42)   - Changed PATH to MPATH and help from "path - list logical unit paths" to "mpath - list logical unit multipath info" because
 * 43)     it is NOT an information about a path - it is an information about multipathing.
 * 44) - 08 Jan 2013 M.Fuerstenau
 * 45)   - Removed installation informations for the perl SDK from VMware. This informations are part of the SDK and have nothing to do
 * 46)     with this plugin.
 * 47)   - Replaced global variables with my variables. Instead of "define every variable on the fly as needed it is a good practice
 * 48)     to define variables at the beginning and place a comment within it. It gives you better readability.
 * 49) - 22 Jan 2013 M.Fuerstenau
 * 50)   - Merged with the actual version from op5. Therfore all changes done to the op5 version:
 * 51)   - 2012-05-28  Kostyantyn Hushchyn
 * 52)     Rename check_esx3 to check_vmware_api(Fixed issue #3745)
 * 53)   - 2012-05-28  Kostyantyn Hushchyn
 * 54)     Minor cosmetic changes
 * 55)   - 2012-05-29  Kostyantyn Hushchyn
 * 56)     Clear cluster failover perfdata units, as it describes count of possible failures
 * 57)     to tolerate, so can't be mesured in MB
 * 58)   - 2012-05-30  Kostyantyn Hushchyn
 * 59)     Minor help message changes
 * 60)   - 2012-05-30  Kostyantyn Hushchyn
 * 61)     Implemented timeshift for cluster checks, which could fix data retrievel issues. Small refactoring.
 * 62)   - 2012-05-31  Kostyantyn Hushchyn
 * 63)     Remove dependency on inteval value for cluster checks, which allows to run commands that doesn't require historical intervals
 * 64)   - 2012-05-31  Kostyantyn Hushchyn
 * 65)     Remove unnecessary/unimplemented function which caused cluster effectivecpu subcheck to fail
 * 66)   - 2012-06-01  Kostyantyn Hushchyn
 * 67)     Hide NIC status output for net check in case of empty perf data result(Fixed issue #5450)
 * 68)   - 2012-06-07  Kostyantyn Hushchyn
 * 69)     Fixed manipulation with undefined values, which caused perl interpreter warnings output
 * 70)   - 2012-06-08  Kostyantyn Hushchyn
 * 71)     Moved out global variables from perfdata functions. Added '-M' max sample number argument, which specify maximum data count to retrive.
 * 72)   - 2012-06-08  Kostyantyn Hushchyn
 * 73)     Added help text for Cluster checks.
 * 74)   - 2012-06-08  Kostyantyn Hushchyn
 * 75)     Increment version number Kostyantyn Hushchyn
 * 76)   - 2012-06-11  Kostyantyn Hushchyn
 * 77)     Reimplemented csv parser to process all values in sequence. Now all required functionality for max sample number argument are present in the plugin.
 * 78)   - 2012-06-13  Kostyantyn Hushchyn
 * 79)     Fixed cluster failover perf counter output.
 * 80)   - 2012-06-22  Kostyantyn Hushchyn
 * 81)     Added help message for literal values in interval argument.
 * 82)   - 2012-06-22  Kostyantyn Hushchyn
 * 83)     Added nicknames for intervals(-i argument), which helps to provide correct values in case you can not find them in GUI.
 * 84)     Supported values are: r - realtime interval, h - historical interval at position, starting from 0.
 * 85)   - 2012-07-02  Kostyantyn Hushchyn
 * 86)     Reimplemented Datastore checking in Datacenter using different approach(Might fix issue #5712)
 * 87)   - 2012-07-06  Kostyantyn Hushchyn
 * 88)     Fixed Datacenter runtime check Kostyantyn Hushchyn
 * 89)   - 2012-07-06  Kostyantyn Hushchyn
 * 90)     Fixed Datastore checking in Datacenter(Might fix issue #5712)
 * 91)   - 2012-07-09  Kostyantyn Hushchyn
 * 92)     Added help info for Host runtime 'sensor' subcheck
 * 93)   - 2012-07-09  Kostyantyn Hushchyn
 * 94)     Added Host runtime subcheck to threshold sensor data
 * 95)   - 2012-07-09  Kostyantyn Hushchyn
 * 96)     Fixed Host temperature subcheck causing perl interpreter messages output
 * 97)   - 2012-07-10  Kostyantyn Hushchyn
 * 98)     Added listall option to output all available sensors. Sensor name now trieted as regexp, so result will be outputed for the first match.
 * 99)   - 2012-07-26  Fixed issue which prevents plugin...   v2.8.8 v2.8.8-beta1 Kostyantyn Hushchyn
 * 100)     Fixed issue which prevents plugin from executing under EPN(Fixed issue #5796)
 * 101)   - 2012-09-03  Kostyantyn Hushchyn
 * 102)     Implemented plugin timeout(returns 3).
 * 103)   - 2012-09-05  Kostyantyn Hushchyn
 * 104)     Added storage refresh functionality in case when it's present(Fixed issue #5787)
 * 105)   - 2012-09-21  Kostyantyn Hushchyn
 * 106)     Added check for dead pathes, which generates 2 in case when at least one is present(Fixed issue #5811)
 * 107)   - 2012-09-25  Kostyantyn Hushchyn
 * 108)     Changed comparison logic in storage path check
 * 109)   - 2012-09-26  Kostyantyn Hushchyn
 * 110)     Fixed 'Global symbol normalizedPathState requires explicit package name'
 * 111)   - 2012-10-02  Kostyantyn Hushchyn
 * 112)     Changed timeshift argument type to integer, so that non number values will be treated as invalid.
 * 113)   - 2012-10-02  Kostyantyn Hushchyn
 * 114)     Changed to a conditional datastore refresh(Reduce overhead of solution suggested in issue #5787)
 * 115)   - 2012-10-05  Kostyantyn Hushchyn
 * 116)     Updated description so now almost all options are documented, though somewhere should be documented arguments like timeshift(-T),
 * 117)     max samples(-M) and interval(-i) (Solve ticket #5950)
 * 118)   General statement for all changes done by me:
 * 119)   Nagios, Icingia etc. are tools for
 * 120)   a) Alarming. That means checking values against thresholds (internal or handed over)
 * 121)   b) Collecting performance data. These data, collected with the checks, like network traffic, cpu usage or so should be
 * 122)      interpretable without a lot of other data.
 * 123)   So as a conclusion collecting historic performance data collected by a monitored system should not be done using Nagios,
 * 124)   pnp4nagios etc.. It should be interpreted with the approriate admin tools of the relevant system. For vmware it means use
 * 125)   the (web)client for this and not Nagios. Same for performance counters not self explaining.
 * 126)   Example:
 * 127)   Monitoring swapped memory of a vmware guest system seems to makes sense. But on the second look it doesn't because on Nagios
 * 128)   you do not have the surrounding conditions in one view like
 * 129)   - the number of the running guest systems on the vmware server.
 * 130)   - the swap every guest system needs
 * 131)   - the total space allocated for all systems
 * 132)   - swap/memory usage of the hostcheck_vmware_esx.pl
 * 133)   - and a lot more
 * 134)   So monitoring memory of a host makes sense but the same for the guest via vmtools makes only a limited sense.
 * 135)   Martin Fuerstenau
 * 136) - 31 Jan 2013 M.Fuerstenau version 0.7.1
 * 137)   - Replaced most die with a normal if statement and an exit.
 * 138) - 1 Feb 2013 M.Fuerstenau version 0.7.2
 * 139)   - Replaced unless with if. unless was only used eight times in the program. In all other statements we had an if statement
 * 140)     with the appropriate negotiation for the statement.
 * 141) - 5 Feb 2013 M.Fuerstenau version 0.7.3
 * 142)   - Replaced all add_perfdata statements with simple concatenated variable $perfdata
 * 143) - 6 Feb 2013 M.Fuerstenau version 0.7.4
 * 144)   - Corrected bug. Name of subroutine was sub check_percantage but this was a typo.
 * 145) - 7 Feb 2013 M.Fuerstenau version 0.7.5
 * 146)   - Replaced $percc and $percw with $crit_is_percent and $warn_versionis_percent. This was just cosmetic for better readability.
 * 147)   - Removed check_percentage. It was replaced by two one liners directly in the code. Easier to read.
 * 148)   - The only codeblocks using check_percentage were the blocks checking warning and critical. But unfortunately the
 * 149)     plausability check was not sufficient. Now it is tested that no other values than numbers and the % sign can be
 * 150)     submitted. It is also checked that in case of percent the values are in a valid level between 0 and 100
 * 151) - 12 Feb 2013 M.Fuerstenau version 0.7.8
 * 152)   - Replaced literals like CRITICAL with numerical values. Easier to type and anyone developing plugins should be
 * 153)     safe with the use
 * 154)   - Replaced $state with $actual_state and $res with $state. More for cosmetical issues but the state is returned
 * 155)     to Nagios.
 * 156)   - check_against_threshold from Nagios::Plugin replaced with a little own subroutine check_against_threshold.
 * 157)   - Nagios::Plugin::Functions::max_state replaced with own routine check_state
 * 158) - 14 Feb 2013 M.Fuerstenau version 0.7.9
 * 159)   - Replaced hash %STATUS_TEXT from Nagios::Plugin::Functions with own hash %status2text.
 * 160) - 15 Feb 2013 M.Fuerstenau version 0.7.10
 * 161)   - Own help (print_help) and usage (print_usage) function.
 * 162)   - Nagios::plugin kicked finally out.
 * 163)   - Mo more global variables.
 * 164) - 25 Feb 2013 M.Fuerstenau version 0.7.11
 * 165)   - $quickstats instead of $quickStats for better readability.
 * 166) - 5 Mar 2013 M.Fuerstenau version 0.7.12
 * 167)   - Removed return_cluster_DRS_recommendations because for daily use this was more of an exotical feature
 * 168)   - Removed --quickstats for host_cpu_info and dc_cpu_info because quickstats is not a valid option here.
 * 169) - 6 Mar 2013 M.Fuerstenau version 0.7.13
 * 170)   - Replaced -o listitems with --listitems
 * 171) - 8 Mar 2013 M.Fuerstenau version 0.7.14
 * 172)   - --usedspace replaces -o used. $usedflag has been replaced by $usedflag.
 * 173)   - --listvms replaces -o listvm. $outputlist has been replaced by $listvms.
 * 174)   - --alertonly replaces -o brief. $briefflag has been replaced by $alertonly.
 * 175)   - --blacklistregexp replaces -o blacklistregexp. $blackregexpflag has been replaced by $blacklistregexp.
 * 176)   - --isregexp replaces -o regexp. $regexpflag has been replaced by $isregexp.
 * 177) - 9 Mar 2013 M.Fuerstenau version 0.7.15
 * 178)   - Main selection is now transfered to a subroutine main_select because after
 * 179)     a successfull if statement the rest can be skipped leaving the subroutine
 * 180)     with return
 * 181) - 19 Mar 2013 M.Fuerstenau version 0.7.16
 * 182)   - Reformatted and cleaned up a lot of code. Variable definitions are now at the beginning of each
 * 183)     subroutine instead of defining them "on the fly" as needed with "my". Especially using "my" for
 * 184)     definition in a loop is not goog coding style
 * 185) - 21 Mar 2013 M.Fuerstenau version 0.7.17
 * 186)   - --listvms removed as extra switch. Ballooning or swapping VMs will always be listed.
 * 187)   - Changed subselect list(vm) to listvm for better readability. listvm was accepted  before (equal to list)
 * 188)     but not mentioned in the help. To have list or listvm for the same is a little bit exotic. Fixed this inconsistency.
 * 189) - 22 Mar 2013 M.Fuerstenau version 0.7.18
 * 190)   - Removed timeshift, interval and maxsamples. If needed use original program from op5.
 * 191) - 25 Mar 2013 M.Fuerstenau version 0.7.19
 * 192)   - Removed $defperfargs because no values will be handled over. Only performance check that needed another
 * 193)     another sampling invel was cluster. This is now fix with 3000.
 * 194) - 11 Apr 2013 M.Fuerstenau version 0.7.20
 * 195)   - Rewritten and cleaned subroutine host_mem_info. Removed $value1 - $value5. Stepwise completion of $output makes
 * 196)     this unsophisticated construct obsolete.
 * 197) - 16 Apr 2013 M.Fuerstenau version 0.7.21
 * 198)   - Stripped down vm_cpu_info. Monitoring CPU usage in Mhz makes no sense under normal circumstances
 * 199)     Mhz is no valid unit for performance data according to the plugin developer guide. I have never found
 * 200)     a reason to monitor wait time or ready time in a normal alerting evironment. This data has some interest
 * 201)     for performance analysis. But this can be done better with the vmware tools.
 * 202)   - Rewritten and cleaned subroutine vm_mem_info. Removed $value1 - $value5. Stepwise completion of $output makes
 * 203)     this unsophisticated construct obsolete.
 * 204) - 24 Apr 2013 M.Fuerstenau version 0.7.22
 * 205)   - Because there is a lot of different performance counters for memory in vmware we ave changed something to be
 * 206)     more specific.
 * 207)     - Enhenced explanations in help.
 * 208)     - Changed swap to swapUSED in host_mem_info.
 * 209)     - Changed usageMB to CONSUMED in host_mem_info. Same for variables.
 * 210)     - Removed overall in host_mem_info. After reading the documentation carefully the addition of consumed.average + overhead.average
 * 211)       seems a little bit senseless because consumed.average includes overhead.average.
 * 212)     - Changed usageMB to CONSUMED in vm_mem_info. Same for variables.
 * 213)     - Removed swapIN and swapOUT in vm_mem_info. Not so sensefull for Nagios alerting because it is hard to find
 * 214)       valid thresholds
 * 215)     - Removed swap in vm_mem_info. From the vmware documentation:
 * 216)       "Current amount of guest physical memory swapped out to the virtual machine's swap file by the VMkernel. Swapped
 * 217)        memory stays on disk until the virtual machine needs it. This statistic refers to VMkernel swapping and not
 * 218)        to guest OS swapping. swapped = swapin + swapout"
 * 219)       This is more an issue of performance tuning rather than alerting. It is not swapping inside the virtual machine.
 * 220)       it is not possible to do any alerting here because (especially with vmotion) you have no thresholds.
 * 221)     - Removed OVERHEAD in vm_mem_info. From the vmware documentation:
 * 222)       "Amount of machine memory used by the VMkernel to run the virtual machine."
 * 223)       So using this we have a useless information about a virtual machine because we have no valid context and we
 * 224)       have no valid thresholds. More important is overhead for the host system. And if we are running in problems here
 * 225)       we have to look which machine must be moved to another host.
 * 226)     - As a result of this overall in vm_mem_info makes no sense.
 * 227) - 25 Apr 2013 M.Fuerstenau version 0.7.23
 * 228)   - Removed swap in vm_mem_info. From vmware documentation:
 * 229)     "Amount of guest physical memory that is currently reclaimed from the virtual machine through ballooning.
 * 230)      This is the amount of guest physical memory that has been allocated and pinned by the balloon driver."
 * 231)     So here we have again data which makes no sense used alone. You need the context for interpreting them
 * 232)     and there are no thresholds for alerting.
 * 233) - 29 Apr 2013 M.Fuerstenau version 0.7.24
 * 234)   - Renamed $esx to $esx_server. This is only for cosmetics and better reading of the code.
 * 235)   - Reimplmented subselect ready in vm_cpu_info and implemented it new in host_cpu_info.
 * 236)     From the vmware documentation:
 * 237)     "Percentage of time that the virtual machine was ready, but could not get scheduled
 * 238)      to run on the physical CPU. CPU ready time is dependent on the number of virtual
 * 239)      machines on the host and their CPU loads."
 * 240)     High or growing ready time can be a hint CPU bottlenecks (host and guest system)
 * 241)   - Reimplmented subselect wait in vm_cpu_info and implemented it new in host_cpu_info.
 * 242)     From the vmware documentation:
 * 243)     "CPU time spent in wait state. The wait total includes time spent the CPU Idle, CPU Swap Wait,
 * 244)      and CPU I/O Wait states. "
 * 245)     High or growing wait time can be a hint I/O bottlenecks (host and guest system)
 * 246) - 30 Apr 2013 M.Fuerstenau version 0.7.25
 * 247)   - Removed subroutines return_dc_performance_values, dc_cpu_info, dc_mem_info, dc_net_info and dc_disk_io_info.
 * 248)     Monitored entity was view type HostSystem. This means, that the CPU of the data center server is monitored.
 * 249)     The data center server (vcenter) is either a physical MS Windows serversionver (which can be monitored better
 * 250)     directly with SNMP and/or NSClient++) or the new Linux based appliance which is a virtual machine and
 * 251)     can be monitored as any virtual machine. The OS (Linux) on that virtual machine can be monitored like
 * 252)     any standard Linux.
 * 253) - 5 May 2013 M.Fuerstenau version 0.7.26
 * 254)   - Revised the code of dc_list_vm_volumes_info
 * 255) - 9 May 2013 M.Fuerstenau version 0.7.27
 * 256)   - Revised the code of host_net_info. The function was devided in two parts (like others):
 * 257)     - subselects
 * 258)     - else which included all.
 * 259)     So most of the code existed twice. One for each subselect and nearly the same for all together.
 * 260)     The else block was removed and in case no subselect was defined we defined all as $subselect.
 * 261)     With the variable set to all we can decide wether to leave the function after a subselect section
 * 262)     has been processed or stay and enhance $output and $perfdata. So the code is more clear and
 * 263)     has nearly half the lines of code left.
 * 264)   - Removed KBps as unit in performance data. This unit is not specified in the plugin developer
 * 265)     guide. Performance data is now just a number without a unit. Adding the unit has to be done
 * 266)     in the graphing tool (like pnp4nagios).
 * 267)   - Removed the number of NICs as performance data. A little bit senseless to have those data here.
 * 268) - 10 May 2013 M.Fuerstenau version 0.7.27
 * 269)   - Revised the code of vm_net_info. Same changes as for host_net_info exept the NIC section.
 * 270)     This is not available for VMs.
 * 271) - 14 May 2013 M.Fuerstenau version 0.7.28
 * 272)   - Replaced $command and $subselect with $select and $subselect. Therfore also the options --command
 * 273)     --subselect changed to --select and --subselect. This has been done to become it more clear.
 * 274)     In fact these items where no commands (or subselects). It were selections from the amount of
 * 275)     performance counters available in vmware.
 * 276) - 15 May 2013 M.Fuerstenau version 0.7.29
 * 277)   - Kicked out all (I hope so) code for processing historic data from generic_performance_values.
 * 278)     generic_performance_values is called by return_host_performance_values, return_host_vmware_performance_values
 * 279)     and return_cluster_performance_values (return_cluster_performance_values must be rewritten now).
 * 280)     The code length of generic_performance_values was reduced to one third by doing this.
 * 281) - 6 Jun 2013 M.Fuerstenau version 0.7.30
 * 282)   - Substituted commandline option for select -l with -S. Therefore -S can't be used as option for the sessionfile
 * 283)     Only --sessionfile is accepted nor the name of the sessionfile.
 * 284)   - Corrected some bugs in check_against_threshold
 * 285)   - Ensured that in case of thresholds critical must be greater than warning.
 * 286) - 11 Jun 2013 M.Fuerstenau version 0.7.31
 * 287)   - Changed select option for datastore from vmfs to volumes because we will have volumes on nfs AND vmfs on local or
 * 288)     SAN disks.
 * 289)   - Changed output for datastore check to use the option --multiline. This will add a \n (unset -> default) for
 * 290)     every line of output. If set it will use HTML tag.
 * 291)     The option --multiline sets a tag instead of \n. This must be filtered out
 * 292)     before using the output in notifications like an email. sed will do the job:
 * 293)     sed 's/<[Bb][Rr]>/&\n/g' | sed 's/<[^<>]*>//g'
 * 294)     Example:
 * 295)    # 'notify-by-email' command definition
 * 296)    define command{
 * 297)    	command_name	notify-by-email
 * 298)    	command_line	/usr/bin/printf "%b" "Message from Nagios:\n\nNotification Type: $NOTIFICATIONTYPE$\n\nService: $SERVICEDESC$\nHost: $HOSTNAME$\nHostalias: $HOSTALIAS$\nAddress: $HOSTADDRESS$\nState: $SERVICESTATE$\n\nDate/Time: $SHORTDATETIME$\n\nAdditional Info:\n\n$SERVICEOUTPUT$\n$LONGSERVICEOUTPUT$" | sed 's/<[Bb][Rr]>/&\n/g' | sed 's/<[^<>]*>//g' | /bin/mail -s "** $NOTIFICATIONTYPE$ alert - $HOSTNAME$/$SERVICEDESC$ is $SERVICESTATE$ **" $CONTACTEMAIL$
 * 299)    	}
 * 300) - 13 Jun 2013 M.Fuerstenau version 0.7.32
 * 301)   - Replaced a previous change because it was wrong done:
 * 302)     - --listvms replaced by subselect listvms
 * 303) - 14 Jun 2013 M.Fuerstenau version 0.7.33
 * 304)   - Some minor corrections like a doubled chop in datastore_volumes_info
 * 305)   - Added volume type to datastore_volumes_info. So you can see whether the volume is vmfs (local or SAN) or NFS.
 * 306)   - variables like $subselect or $blacklist are global there is no need to handle them over to subroutines like
 * 307)     ($result, $output) = vm_cpu_info($vmname, local_uc($subselect)) . For $subselect we have now one uppercase
 * 308)     (around line 580) instead of having one with each call in the main selection.
 * 309)   - Later on I renamed local_uc to local_lc because I recognized that in cases the subselect is a volume name
 * 310)     upper cases won't work.
 * 311)   - replaced last -o $addopts (only for the name of a sensor) with --sensorname
 * 312) - 18 Jun 2013 M.Fuerstenau version 0.7.34
 * 313)   - Rewritten and cleaned subroutine host_disk_io_info. Removed $value1 - $value7. Stepwise completion of $output makes
 * 314)     this unsophisticated construct obsolete.
 * 315)   - Removed use of performance thresholds in performance data when used disk io without subselect because threshold
 * 316)     can only be used for one item not for all. Therefore they weren't checked in that section. Senseless.
 * 317)   - Changed the output. Opposite to vm_disk_io_info most values in host_disk_io_info are not transfer rates
 * 318)     but latency in milliseconds. The output is now clearly understandable.
 * 319)   - Added subselect read. Average number of kilobytes read from the disk each second. Rate at which data is read
 * 320)     from each LUN on the host.read rate = # blocksRead per second x blockSize.
 * 321)   - Added subselect write. Average number of kilobytes written to disk each second. Rate at which data is written
 * 322)     to each LUN on the host.write rate = # blocksRead per second x blockSize
 * 323)   - Added subselect usage. Aggregated disk I/O rate. For hosts, this metric versionincludes the rates for all virtual
 * 324)     machines running on the host.
 * 325) - 21 Jun 2013 M.Fuerstenau version 0.7.35
 * 326)   - Rewritten and cleaned subroutine vm_disk_io_info. Removed $value1 - $valuen. Stepwise completion of $output makes
 * 327)     this unsophisticated construct obsolete.
 * 328)   - Removed use of performance thresholds in performance data when used disk io without subselect because threshold
 * 329)     can only be used for on item not for all. Therefore they weren't checked in that section. Senseless.
 * 330) - 24 Jun 2013 M.Fuerstenau version 0.7.36
 * 331)   - Changed all .= (for example $output .= $xxx.....) to = $var... (for example $output = $output . $xxx...). .= is shorter
 * 332)     but the longer form of notification is better readable. The probability of overlooking the dot (especially for older eyes
 * 333)     like mine) is smaller.
 * 334) - 07 Aug 2013 M.Fuerstenau version 0.8.0
 * 335)   - Changed "eval { require VMware::VIRuntime };" to "use VMware::VIRuntime;".  The eval construct
 * 336)     made no sense. If the module isn't available the program will crash with a compile error.
 * 337)   - Removed own subroutine format_uptime only used by host_uptime_info. The complete work of this function
 * 338)     was done converting seconds to days, hours etc.. Instead of the we use the perl module Time::Duration.
 * 339)     So instead of
 * 340)        $output = "uptime=" . format_uptime($value);
 * 341)     we simply use
 * 342)        $output =  "uptime=" . duration_exact($value);
 * 343)   - Removed perfdata from host_uptime_info. Perfdata for uptime seems senseless. Same for threshold.
 * 344)   - Started modularization of the plugin. The reason is that it is much more easier to
 * 345)     patch modules than to patch a large file.
 * 346)   - Variables used in that functions which are defined on the top level
 * 347)     with "my" must now be defined with "our".
 * 348)     BEWARE! Using "our" with unknown modules can lead to curious results if
 * 349)     in this functions are variables with the same name. But in this
 * 350)     case it is no risk because the modules are not generic. We have only
 * 351)     broken the plugin in handy pieces.
 * 352)   - Made an seperate modules:
 * 353)     - help.pm -> print_help
 * 354)     - process_perfdata.pm  -> get_key_metrices
 * 355)                            -> generic_performance_values
 * 356)                            -> return_host_performance_values
 * 357)                            -> return_host_vmware_performance_values
 * 358)                            -> return_cluster_performance_values
 * 359)                            -> return_host_temporary_vc_4_1_network_performance_values
 * 360)     - host_cpu_info.pm -> host_cpu_info
 * 361)     - host_mem_info.pm -> host_mem_info
 * 362)     - host_net_info.pm -> host_net_info
 * 363)     - host_disk_io_info.pm -> host_disk_io_info
 * 364)     - datastore_volumes_info.pm -> datastore_volumes_info
 * 365)     - host_list_vm_volumes_info.pm -> host_list_vm_volumes_info
 * 366)     - host_runtime_info.pm -> host_runtime_info
 * 367)     - host_service_info.pm -> host_service_info
 * 368)     - host_storage_info.pm -> host_storage_info
 * 369)     - host_uptime_info.pm -> host_uptime_info
 * 370) - 13 Aug 2013 M.Fuerstenau version 0.8.1
 * 371)   - Moved host_device_info to host_mounted_media_info. Opposite to it's name
 * 372)     and the description this function wasn't designed to list all devices
 * 373)     on a host. It was designed to show host cds/dvds mounted to one or more
 * 374)     virtual machines. This is important for monitoring because a virtual machine
 * 375)     with a mount cd or dvd drive can not be moved to another host.
 * 376)   - Made an seperate modules:
 * 377)     - host_mounted_media_info.pm -> host_mounted_media_info
 * 378) - 19 Aug 2013 M.Fuerstenau version 0.8.2
 * 379)   - Added SOAP check from Simon Meggle, Consol. Slightly modified to fit.
 * 380)   - Added isblacklisted and isnotwhitelisted from Simon Meggle, Consol. . Same as above.
 * 381)     Following subroutines or modules are affected:
 * 382)     - datastore_volumes_info.pm
 * 383)     - host_runtime_info.pm
 * 384)   - Enhanced host_mounted_media_info.pm
 * 385)     - Added check for host floppy
 * 386)     - Added isblacklisted and isnotwhitelisted
 * 387)     - Added $multiline
 * 388) - 21 Aug 2013 M.Fuerstenau version 0.8.3
 * 389)   - Reformatted and cleaned up host_runtime_info.
 * 390)   - A lot of bugs in it.
 * 391) - 17 Aug 2013 M.Fuerstenau version 0.8.4
 * 392)   - Minor bug fix.
 * 393)     - $subselect was always converted to lower case characters.
 * 394)       This is correct exect $subselect contains a name (e.g. volumes). Volume names
 * 395)       can contain upper and lower letters. Fixed.
 * 396)     - datastore_volumes_info.pm had  my ($datastore, $subselect) = @_; as second line
 * 397)       This was incorrect because "global" variables (defined as our in the main program)
 * 398)       are not handled over via function call. (Yes - may be handling over maybe more ok
 * 399)       in the sense of structured programming. But really - does handling over and giving back
 * 400)       a variable makes the code so much clearer? More a kind of philosophy :-)) )
 * 401) - 27 Oct 2013 M.Fuerstenau version 0.8.5
 * 402)   - Made an seperate modules:
 * 403)     - vm_cpu_info.pm -> vm_cpu_info
 * 404)     - vm_mem_info.pm -> vm_mem_info
 * 405)     - dc_list_vm_volumes_info.pm -> dc_list_vm_volumes_info
 * 406)     - vm_net_info.pm -> vm_net_info
 * 407)     - vm_disk_io_info.pm -> vm_disk_io_info
 * 408) - 31 Oct 2013 M.Fuerstenau version 0.8.9
 * 409)   - Readded -V|--version to display the version number.
 * 410) - 01 Nov 2013 M.Fuerstenau version 0.8.10
 * 411)   - removed return_host_temporary_vc_4_1_network_performance_values from
 * 412)     process_perfdata.pm. Not needed in ESX version 5 and above.
 * 413)     Affected subroutine:
 * 414)     host_net_info.
 * 415)   - Bug fixed in generic_performance_values. Unfortunaltely I had moved
 * 416)     my @values =  to main function. Therefore instead of containing a
 * 417)     new array reference with each run the new references were added to the array
 * 418)     but only the first one was processed. Thanks to Timo Weber for discovering this bug.
 * 419) - 20 Nov 2013 M.Fuerstenau version 0.8.11
 * 420)   - check_state. Bugfix. Logical error. Complete rewrite.
 * 421)   - host_net_info
 * 422)     - Minor bugfix. Added exit 2 in case of unallowed thresholds
 * 423)     - Simplified the output. Instead of doing it for every subselect (or not
 * 424)       if subselect=all for selecting all info) we have a new helper variable
 * 425)       called $true_sub_sel.
 * 426)       0 means not a true subselect.
 * 427)       1 means a true subselect (including all)
 * 428)   - host_runtime_info.
 * 429)     - Filtered out the sensor type "software components". Makes no sense for alerting.
 * 430)     - The complete else tree (no subselect) was scrap due to the fact that the return code
 * 431)       was always ok. There would never be any alarm. Kicked out.
 * 432)     - The else tree was replaced by a $subselect=all as in host_net_info.
 * 433)     - Same for output.
 * 434)     - subselect listvms.
 * 435)       - The (OK) in the output was a hardcoded. Replaced by the deliverd value (UP). (in my oipinion senseless)
 * 436)       - Removed perfdata. The number of virtual machines as perfdata doesn't
 * 437)         make so much sense.
 * 438)     - Rearranged the order of subselects. Must be the same as the statements
 * 439)       in the kicked out else sequence to get the same order in output
 * 440)     - connection state.
 * 441)       From the docs:
 * 442)       connected      Connected to the server. For ESX Server, this is always
 * 443)                      the setting.
 * 444)       disconnected   The user has explicitly taken the host down. VirtualCenter
 * 445)                      does not expect to receive heartbeats from the host. The
 * 446)                      next time a heartbeat is received, the host is moved to
 * 447)                      the connected state again and an event is logged.
 * 448)       notResponding  VirtualCenter is not receiving heartbeats from the server
 * 449)                    . The state automatically changes to connected once
 * 450)                      heartbeats are received again. This state is typically
 * 451)                      used to trigger an alarm on the host.
 * 452)       In the past the presset of returncode was 2. It was set to 0 in case of a
 * 453)       connected. But disconnected doesn' mean a critical error. It means main-
 * 454)       tenance or somesting like that. Therefore we now return a 1 for warning.
 * 455)       notResonding will cause a 2 for critical.
 * 456)     - Kicked out maintenance info in runtime summary and as subselect. In the beginning of
 * 457)       the function is a check for maintenance. In the original program in this case
 * 458)       the program will be left with a die which caused a red alert in Nagios. Now an info
 * 459)       is displayed and a return code of 1 (warning) is deliverd because a maintenance is
 * 460)       regular work. Although monitoring should take notice of it. Therefore a warning.
 * 461)       Therefor the maintenence check in the else tree was scrap. It was never reached.
 * 462)     - listvms
 * 463)       In case of no VMs the plugin returned a critical. But this is not correct. No VMs
 * 464)       on a host is not an error. It is simply what it says: No VMs.
 * 465)     - Replaced --listitems and --listall with --listsensors because there were two options
 * 466)       for the same use.
 * 467)     - Later on I decided to kick out the complete sensorname construction. To monitor a seperate sensor
 * 468)       by name (a string which ist different for each sensor) seems not to make so much sense. To monitor
 * 469)       sensors by type gave no usefull information (exept temperature which is still monitored. All usefull
 * 470)       informations are in the health section. Better to implement some out here if needed.
 * 471)       renamed -s temperature to -s temp (because I am lazy).
 * 472)     - Changed output of --listsensors. | is the seperation symbol for performance data. So it should not be
 * 473)       used in output strings.
 * 474)     - Same for the error output of sensors in case of a problem.
 * 475)     - subselect=health. Filter out sensors which have not valid data. Often a sensor is
 * 476)       reckognizedby vmware but has not the ability to report something senseful. In this
 * 477)       case an unknown is reported and the message "Cannot report on the current health state of
 * 478)       the element". This it can be skipped.
 * 479)   - Bugfix for vm_net_info. It worked perfectly for -H but produced bullshit with the -D option.
 * 480)     With -D in PerfQuerySpec->new(...) intervalId and maxSample must be set. Default was 20 for intervalId
 * 481)     and 1 for maxSample
 * 482)   - datastore_volumes_info
 * 483)     - New option --gigabyte
 * 484)     - Fixed bug for treating name as regexp (--isregexp).
 * 485)     - Fixed bug in perfdata (%:MB). Is now MB or GB.
 * 486)     - If no single volume is selected warning/critical threshold can be given
 * 487)       only in percent.
 * 488)   - Fixed bug in regexp for blacklists and whitelists and replace --blacklistregexp and --whitelistregexp with
 * 489)     --isregexp. Used in
 * 490)       - host_mounted_media_info
 * 491)       - datastore_volumes_info
 * 492)       - host_runtime_info
 * 493)     All subroutines revised later will include it automatically
 * 494)   - Fixed bug in regexp for blacklists and whitelists and replace --blacklistregexp and --whitelistregexp with
 * 495)   - Opposite to the op5 original blacklists and whitelists can now contain true reular expressions.
 * 496)   - help.pm rewritten. It was too much output. Now the user has several choices:
 * 497)     -h|--help=                    The complete help for all.
 * 498)     -h|--help=  Help for datacenter/vcenter checks.
 * 499)     -h|--help=                   Help for vmware host checks.
 * 500)     -h|--help=                     Help for virtual machines checks.
 * 501)     -h|--help=                Help for cluster checks.
 * 502)   - host_service_info rewritten.
 * 503)     - No longer a list of services via subselect.
 * 504)     - Instead full blacklist/whitelist support
 * 505)     - With --isregexp blacklist/whitelist items are interpreted as regular expressions
 * 506)   - Changed switch of blacklist from -x to -B
 * 507)   - Changed switch of whitelist from -y to -W
 * 508)   - main_select. Something for the scatterbrained of us. Replaced string compare (eq,ne etc.) with
 * 509)     a regexp pattern matching. So it is possible to type in services or Services instead of service.
 * 510) - 29 Nov 2013 M.Fuerstenau version 0.8.13
 * 511)   - In all functions checking host for maintenance we had the following contruction:
 * 512)     if (uc($host_view->get_property('runtime.inMaintenanceMode')) eq "TRUE")
 * 513)     This is quite stupid. runtime.inMaintenanceMode is xsd:boolean wich means true or false (in
 * 514)     lower cas letters. So a uc make no sense. Removed
 * 515)   - Bypass SSL certificate validation - thanks Robert Karliczek for the hint
 * 516)   - Added --sslport if any port other port than 443 is wanted. 443 is used as default.
 * 517)   - Rewritten authorization part. Sessionfiles are working now.
 * 518)   - Updated README.
 * 519) - 03 Dec 2013 M.Fuerstenau version 0.8.14
 * 520)   - host_runtime_info
 * 521)     - Fixed minor bug. In case of an unknown with sensors the unknown was always mapped to
 * 522)       a warning. This wasn't sensefull under all circumstances. Now it is only mapped to warning
 * 523)       if --ignoreunknow is not set.
 * 524)   - README
 * 525)     - Updated installation notes
 * 526)   - Optional pathname for sessionfile
 * 527) - 10 Dec 2013 M.Fuerstenau version 0.8.15
 * 528)   - datastore_volumes_info
 * 529)     - Changed "For all volumes" to "For all selected volumes". This should fit all. The subroutine datastore_volumes_info
 * 530)       is called from several subroutines and to make a difference here for a single volume or more volumes will cause
 * 531)       a lot of unnecessary work just for cosmetics.
 * 532)     - Fixed typo in error message.
 * 533)     - Modified error messages
 * 534)   - Removed plausibility check whether critical must be greater than warning. In case of freespace for example it must
 * 535)     be the other way round. The plausibility check was nice but too complicated for all the different conditions.
 * 536)   - check_against_threshold - Cleaned up and partially rewritten.
 * 537) - 12 Dec 2013 M.Fuerstenau version 0.8.16
 * 538)   - datastore_volumes_info
 * 539)     - Some small fixes
 * 540)       - Changed the output for OK from  "For all selected volumes" to "OK for all seleted volumes."
 * 541)       -  Same for error plus an error counter for the alarms
 * 542)     - Parameter usedspace was ignored on volume checks because a local variable defined with my instead of a more global
 * 543)       one. Changed it from my to our fixed it. Thanks to dgoetz for reporting (and fixing) this.
 * 544)     - Capacity is now displayed and deliverd as perfdata
 * 545)   - Main selection - GetOptions. Unce upon a time I had kicked out $timeout unintended. Fixed now. Thanks to
 * 546)     Andreas Daubner for the hint.
 * 547) - 12 Dec 2013 M.Fuerstenau version 0.8.17
 * 548)   - host_net_info
 * 549)     - Changed output
 * 550)     - Added total number of NICs
 * 551) - 13 Dec 2013 M.Fuerstenau version 0.8.18
 * 552)   - host_mounted_media
 * 553)     - Delivers now a warning instead of a critical
 * 554) - 25 Dec 2013 M.Fuerstenau version 0.9.0
 * 555)   - help
 * 556)     - Removed -v/--verbose. The code was not debugging the plugin but not for working with it.
 * 557)   - host_storage_info
 * 558)     - Removed optional switch for adaptermodel. Displaying the adapter model is default now.
 * 559)     - Removed upper case conversion for status. The status was converted (for examplele online to ONLINE) and
 * 560)       compared with a upper case string like "ONLINE". Sensefull like a second asshole.
 * 561)     - Added working blacklist/whitelist.
 * 562)       - Blacklist: blacklisted adapters will not be displayed.
 * 563)       - Whitelist: only whitelisted adapters will be displayed.
 * 564)     - Removed perfdata for the number of hostbusadapters. These perfdata was absolutely senseless.
 * 565)     - Status for hostbusadapters was not checked correctly. The check was only done for online and unknown but NOT(!!)
 * 566)       for offline and unbound.
 * 567)     - LUN states were not correct. UNKNOWN is not a valid state. Not all states different from unknown are
 * 568)       supposed to be critical. From the docs:
 * 569)       degraded             One or more paths to the LUN are down, but I/O is still possible. Further
 * 570)                            path failures may result in lost connectivity.
 * 571)       error                The LUN is dead and/or not reachable.
 * 572)       lostCommunication    No more paths are available to the LUN.
 * 573)       off                  The LUN is off.
 * 574)       ok                   The LUN is on and available.
 * 575)       quiesced             The LUN is inactive.
 * 576)       timeout              All Paths have been down for the timeout condition determined by a
 * 577)                            user-configurable host advanced option.
 * 578)       unknownState         The LUN state is unknown.
 * 579)     - Removed number of LUNs as perfdata. Senseless (again).
 * 580)     - In the original selection for the displayed LUN the displayName was used first, then the deviceName and
 * 581)       the last one was the canonical name. Unfortunately in the GUI SCSI ID, canonical name an runtime name is
 * 582)       displayed. So using the freely configurable DisplayName is senseless. The device name is formed from the
 * 583)       path (/vmfs/devices/disks/) followed by the canonical name. So it is either senseless.
 * 584)     - The real numeric LUN number wasn'nt display. Fixed. Output is now LUN, canonical name, everything from
 * 585)       the display name not equal canonical name and status.
 * 586)     - Complete rewrite of the paths part. Only the state of the multipath was checked but not the state of the
 * 587)       paths. So a multipath can be "Active" which is ok but the second line is dead. So if the active path becomes
 * 588)       dead the failover won't work.There must be an alarm for a standby path too. It is now grouped in the output.
 * 589)     - Multiline support for this.
 * 590) - 03 Jan 2014 M.Fuerstenau version 0.9.1
 * 591)   - check_vmware_esx.pl
 * 592)     Added new flag --ignore_warning. This will map a warning to ok.
 * 593)   - host_runtime_info - some minor changes
 * 594)     - Changed state to powerstate. In the original version the power state was mapped:
 * 595)       poweredOn => UP
 * 596)       poweredOff => DOWN
 * 597)       suspended => SUSPENDED
 * 598)       This suggested a machine state but it is only a powerstate. All other than UP caused a critical. But this is
 * 599)       not true. A power off machine can also be ok. But to be sure that it is noticed we will have a warning for
 * 600)       powerd off and suspended
 * 601)     - Perfdata changed.
 * 602)       - vm_up -> vm_powerdon
 * 603)       - New: vm_poweroff
 * 604)       - New: vm_suspended
 * 605)   - vm_runtime_info -> vm_runtime_info.pm
 * 606)     - Removed a lot of unnecessary variables and hashes. Rewritten a lot.
 * 607)     - Connection state. Only "connected" was checked. All other caused a critical error without a usefull message.
 * 608)       This wa a little bit incomplete. Corrected. States delivered from VMware are connected, disconnected,
 * 609)       inaccessible, invalid and orphaned.
 * 610)     - Removed cpu. VirtualMachineRuntimeInfo maxCpuUsage (in Mhz) doesn't make so much sense for monitoring/alerting.
 * 611)       See VMware docs for further information for this performance counter.
 * 612)     - Removed mem. VirtualMachineRuntimeInfo maxMemoryUsage doesn't make so much sense for monitoring/alerting.
 * 613)       See VMware docs for further information for this performance counter.
 * 614)     - Changed state to powerstate. In the original version the power state was mapped:
 * 615)       poweredOn => UP
 * 616)       poweredOff => DOWN
 * 617)       suspended => SUSPENDED
 * 618)       This suggested a machine state but it is only a powerstate. All other than UP caused a critical. But this is
 * 619)       not true. A power off machine can also be ok. But to be sure that it is noticed we will have a warning for
 * 620)       powerd off and suspended
 * 621)     - Changed guest to gueststate. This is more descriptive.
 * 622)       Removed mapping in guest state. Mapping was "running" => "Running", "notrunning" => "Not running",
 * 623)       "shuttingdown" => "Shutting down", "resetting" => "Resetting", "standby" => "Standby", "unknown" => "Unknown".
 * 624)       This was not necessary from a technical point of view. The original messages are clearly understandable.
 * 625)     - The guest states were not interpreted correctly. In check_vmware_api.pl all states different from running
 * 626)       caused a "Critical" error. But this is nonsense. A planned shutted down machine is not an error. It's daily
 * 627)       business. But the operator should probably have a notice of that. So it causing a "Warning".
 * 628)       The states are (from the docs):
 * 629)       running      -> Guest is running normally. (returns 0)
 * 630)       shuttingdown -> Guest has a pending shutdown command. (returns 1)
 * 631)       resetting    -> Guest has a pending reset command. (returns 1)
 * 632)       standby      -> Guest has a pending standby command. (returns 1)
 * 633)       notrunning   -> Guest is not running. (returns 1)
 * 634)       unknown      -> Guest information is not available. (returns 3)
 * 635)     - Rewritten subselect tools. VirtualMachineToolsStatus was deprecated. As of vSphere API 4.0
 * 636)       VirtualMachineToolsVersionStatus and VirtualMachineToolsRunningStatus
 * 637)       has to be used. So a great part of this subselect was not working.
 * 638)   - vm_disk_io_info
 * 639)     - Minor bug in output and perfdata corrected. I/O is not in MB but in MB/s. Some
 * 640)       of the counters were in MB.
 * 641)     - Corrected help. The original on was nonsense.
 * 642)     - Changed all values to KB/s because so it is equal to host disk I/O and so it
 * 643)       it is deleverd from the API.
 * 644)   - help
 * 645)     - Some small bug fixes.
 * 646)   - host_disk_io_info
 * 647)     - added total_latency.
 * 648) - 08 Jan 2014 M.Fuerstenau version 0.9.2
 * 649)   - help
 * 650)     - Some small bug fixes.
 * 651)   - vm_disk_io_info
 * 652)     - Removed duplicated code. (if subselect ..... else ....)
 * 653)       The code was 90% identical.
 * 654)   - host_disk_io_info
 * 655)     - Removed duplicated code. (if subselect ..... else ....)
 * 656)       The code was 90% identical.
 * 657)     - Bug fix. Usage was given without subselect but missing as subselect. Not
 * 658)       detected earlier due to the duplicate code.
 * 659)   - host_cpu_info
 * 660)     - Removed duplicated code. (if subselect ..... else ....)
 * 661)       The code was 90% identical.
 * 662)     - Added usage as subselect.
 * 663)   - vm_cpu_info
 * 664)     - Removed duplicated code. (if subselect ..... else ....)
 * 665)       The code was 90% identical.
 * 666)     - Added usage as subselect.
 * 667)   - host_mem_info
 * 668)     - Removed duplicated code. (if subselect ..... else ....)
 * 669)       The code was 90% identical.
 * 670)     - swapused
 * 671)       - I swapused is a subselect there should be enhanced information about
 * 672)         the virtual machines and should be available. If this won't work
 * 673)         nothing will happen. In the past this caused a critical error which
 * 674)         is nonsense here.
 * 675)      - memctl
 * 676)        - Same as swapused
 * 677)   - vm_mem_info
 * 678)     - Removed duplicated code. (if subselect ..... else ....)
 * 679)       The code was 90% identical.
 * 680)     - Added vmmemctl.average (memctl) to monitor balloning.
 * 681) - 16 Jan 2014 M.Fuerstenau version 0.9.3
 * 682)   - All modules
 * 683)     - Corrected typo at the end. common instead of commen
 * 684)   - host_storage_info
 * 685)     - Removed ignored counter for whitelisted items. A typical copy and paste
 * 686)       b...shit.
 * 687)   - vm_runtime_info
 * 688)     - issues
 * 689)       - Some bugs with the output. Corrected.
 * 690)     - tools
 * 691)       - Minor bug fixed. Previously used variable was not removed.
 * 692)   - host_runtime_info
 * 693)     - issues.
 * 694)       - Some bugs with the output. Corrected.
 * 695)     - listvms
 * 696)       - output now sorted by powerstate (suspended, poweredoff, powerdon)
 * 697)     - Corrected some minor bugs
 * 698)   - dc_list_vm_volumes_info
 * 699)     - Removed handing over of unnecessary parameters
 * 700)   - dc_runtime_info -> dc_runtime_info.pm
 * 701)     - Code cleaned up and reformated
 * 702)     - listvms
 * 703)       - output now sorted by powerstate (suspended, poweredoff, powerdon)
 * 704)       - Added working blacklist/whitelist with the ability to use regular
 * 705)         expressions
 * 706)       - Added --alertonly here
 * 707)       - Added --multiline here
 * 708)     - listhosts
 * 709)       - %host_state_strings was mostly nonsense. The mapped poser states from
 * 710)         for virtual machines were used. Hash removed. Using now the orginal
 * 711)         power states from the system (from the docs):
 * 712)         - poweredOff -> The host was specifically powered off by the user
 * 713)                         through VirtualCenter. This state is not a certain
 * 714)                         state, because after VirtualCenter issues the command
 * 715)                         to power off the host, the host might crash, or kill
 * 716)                         all the processes but fail to power off.
 * 717)         - poweredOn  -> The host is powered on
 * 718)         - standBy    -> The host was specifically put in standby mode, either
 * 719)                         explicitly by the user, or automatically by DPM. This
 * 720)                         state is not a cetain state, because after VirtualCenter
 * 721)                         issues the command to put the host in stand-by state,
 * 722)                         the host might crash, or kill all the processes but fail
 * 723)                         to power off.
 * 724)         - unknown    -> If the host is disconnected, or notResponding, we can
 * 725)                         not possibly have knowledge of its power state. Hence,
 * 726)                         the host is marked as unknown.
 * 727)       - Added working blacklist/whitelist with the ability to use regular
 * 728)         expressions
 * 729)       - Added --alertonly here
 * 730)       - Added --multiline here
 * 731)     - listcluster
 * 732)       - Removed senseless perf data
 * 733)       - More detailed check than before
 * 734)       - Added working blacklist/whitelist with the ability to use regular
 * 735)         expressions
 * 736)       - Added --alertonly here
 * 737)       - Added --multiline here
 * 738)     - status
 * 739)       - Rewritten and reformatted
 * 740)     - tools
 * 741)       - Rewritten and reformatted
 * 742)       - Improved more detailed output.
 * 743)         expressions
 * 744)       - Added --alertonly here
 * 745)       - Added --multiline here
 * 746) - 24 Jan 2014 M.Fuerstenau version 0.9.4
 * 747)   - Merged pull request from Sven Nierlein
 * 748)     - Modified hel to work with Thruk
 * 749)     - Added Makefile. This is optional. Calling it generates a single file
 * 750)       from all the modules. Maybe it is a little bit slower than the modules.
 * 751)       The readon for modules was speed and better maintenance.
 * 752)   - host_runtime_info
 * 753)     - Added quotes in perfdata for temp.
 * 754)   - Enhanced README. Explained the differences un host_storage_info between
 * 755)     the original one and this one
 * 756)   - host_net_info
 * 757)     - Minor bugfix in output. Corrected typo.
 * 758) - 29 Jan 2014 M.Fuerstenau version 0.9.5
 * 759)   - host_runtime_info
 * 760)     - Minor bug. Corrected quotes in perfdata for temp.
 * 761)   - vm_net_info
 * 762)     - Quotes in perfdata
 * 763)     - Removed VM name from output
 * 764)   - vm_mem_info
 * 765)     - Quotes in perfdata
 * 766)   - vm_disk_io_info
 * 767)     - Quotes in perfdata
 * 768)   - vm_cpu_info
 * 769)     - Quotes in perfdata
 * 770)   - host_net_info
 * 771)     - Quotes in perfdata
 * 772)   - host_mem_info
 * 773)     - Quotes in perfdata
 * 774)   - host_disk_io_info
 * 775)     - Quotes in perfdata
 * 776)   - host_cpu_info
 * 777)     - Quotes in perfdata
 * 778)   - dc_runtime_info
 * 779)     - Quotes in perfdata
 * 780)   - datastore_volumes_info
 * 781)     - Quotes in perfdata
 * 782) - 04 Feb 2014 M.Fuerstenau version 0.9.6
 * 783)   - host_storage_info
 * 784)     - New switch --standbyok for storage systems where a standby multipath is ok
 * 785)       and not a warning
 * 786) - 06 Feb 2014 M.Fuerstenau version 0.9.7
 * 787)   - Bugfixes/Enhancements
 * 788)     - In some cases it might happen that no performance counters are delivered
 * 789)       by VMware. Especially if the version is old (4.x, 3.x). Under these
 * 790)       circumstances an undef was returned by the routines from process_perfdata.pm
 * 791)       and not handled correctly in the calling subroutines. Fixed.
 * 792)       Affected subroutines:
 * 793)       - host_cpu_info
 * 794)       - vm_net_info
 * 795)       - vm_mem_info
 * 796)       - vm_net_info
 * 797)       - vm_disk_io_info
 * 798)       - vm_cpu_info
 * 799)       - host_net_info
 * 800)       - host_mem_info
 * 801)       - host_disk_io_info
 * 802)   - vm_net_info
 * 803)     - Rewritten to the same structure as similar modules
 * 804)   - host_net_info
 * 805)     - Rewritten to the same structure as similar modules
 * 806) - 24 Feb 2014 M.Fuerstenau version 0.9.8
 * 807)   - Corrected a type in the help
 * 808)   - Moved the block for constructing the full path of the sessionfile downward to the authentication
 * 809)     stuff to have all in one place.
 * 810)   - Authentication:
 * 811)     - To reduce amounts of login/logout events in the vShpere logfiles or a lot of open sessions using
 * 812)       sessionfiles the login part has been rewritten. Using session files is now the default. Only one
 * 813)       session file per host or vCenter is used as default
 * 814)       The sessionfile name is automatically set to the vSphere host or the vCenter (IP or name - whatever
 * 815)       is used in the check).
 * 816)       Multiple sessions are possible using different session file names. To form different session file
 * 817)       names the default name is enhenced by the value you set with --sessionfile.
 * 818)       NOTICE! All checks using the same session are serialized. So a lot of checks using only one session
 * 819)       can cause timeouts. In this case you should enhence the number of sessions by using --sessionfile
 * 820)       in the command definition and define the value in the service definition command as an extra argument
 * 821)       so it can be used in the command definition as $ARGn$.
 * 822)     - --sessionfile is now optional and only used to enhance the sessionfile name to have multiple sessions.
 * 823)     - If a session logs in it sets a lock file (sessionfilename_locked).
 * 824)     - The lock file is been set when the session starts and removed at the end of the plugin run.
 * 825)     - A newly started check looks for the lock file and waits until it is no longer there. So here we
 * 826)       have a serialization now. It will not hang forever due to the alarm routine.
 * 827)     - Fixed bug "Can't call method "unset_logout_on_disconnect"". I mixed object orientated code and classical
 * 828)       code. (Thanks copy & paste for this bug)
 * 829)   - $timeout set to 40 seconds instead of 30 to have a little longer waiting before automatic cancelling
 * 830)     the check to prevent unwanted cancelling due to longer waiting caused by serialization.
 * 831) - 25 Feb 2014 M.Fuerstenau version 0.9.9
 * 832)   - Bugfix and improvement for "lost" lock files. In case of a Nagios reload (or kill -HUP) Nagios is restarted with the
 * 833)     same PID as before. Unfortunately Nagios sends a SIGINT or SIGTERM to the plugins. This causes the plugin
 * 834)     to terminate without removing the lockfile.
 * 835)     - So we have to catch several signals now
 * 836)       - SIGINT and SIGTERM. One of this will be send from Nagios
 * 837)       - SIGALRM. Caused by alarm. Now with output usable in Nagios.
 * 838)     - Instead of generating an empty file as lock file we write the process identifier of the running plugin
 * 839)       process into the lock file. If a session crashes for some reason an a lock file is left we are in a
 * 840)       situation where signal processing won't help. But here the next run of the plugin reads the PID and checks
 * 841)       for the process. If there is no process anymore it will remove the lock file and create a new one.
 * 842)       Thanks to Simon Meggle, Consol, for the idea.
 * 843)   - Removed "die" for opening the authfile or the session lock file with an unless construct. The plugin will
 * 844)     report an "understandable" message to the monitor instead of causing an internal error code.
 * 845)   - vm_cpu_info and host_cpu_info
 * 846)     - Removed threshold for ready and wait. Therefore thresholds are no possible
 * 847)       without subselect.
 * 848) - 26 Feb 2014 M.Fuerstenau version 0.9.10
 * 849)   - Bugfixes.
 * 850)     - Corrected typo in dc_runtime_info line 660.
 * 851)     - Corrected typo in help.
 * 852)     - Corrected bug in datastore_volumes_info. Giving absolute thresholds
 * 853)       for a single volume was not possible. Fixed.
 * 854)   - Removed print_usage. Due to mass of parameters it is not possible to display
 * 855)     a short usage message. Instead of that the output of the help is included
 * 856)     in the package as a file.
 * 857)   - Updated default timeout to 90 secs. to avoid timeouts.
 * 858)   - Before accessing the session file (and lock file) we have a random sleep up
 * 859)     7 secs.. This is to avoid a concurrent access in case of a monitor restart
 * 860)     or a "Schedule a check of all services on this host"
 * 861)   - In case of a locked session file the wait loop is not fix to 1 sec any more.
 * 862)     Instead of this it uses a random period up to 5 sec.. So we minimize the risc
 * 863)     of concurrent access.
 * 864) - 7 Mar 2014 M.Fuerstenau version 0.9.11
 * 865)   - Updated README
 * 866)     - Section for removing HTML tags was reworked
 * 867)   - Added blacklist to host_net_info so that interfaces with -S net can
 * 868)     be blacklisted.
 * 869) - 11 Mar 2014 M.Fuerstenau version 0.9.12
 * 870)   - Changed sleep to usleep and using now microseconds instead of seconds
 * 871)   - So before accessing the session file (and lock file) we now have a random sleep
 * 872)     up to 1500 milliseconds (default - see $ms_ts). This is to avoid a concurrent access
 * 873)     in case of a monitor restart or a "Schedule a check of all services on this host"
 * 874)     but takes much less time while having much more alternatives.
 * 875)   - In case of a locked session file the wait loop is not fix to a random period up to
 * 876)     5 sec. any more. Instead of this it uses also $ms_ts which means a max of 1.5 secs.
 * 877)     instead of 5.
 * 878) - 3 Apr 2014 M.Fuerstenau version 0.9.13
 * 879)   - --trace= was not working. Fixed. Small typo.
 * 880)   - Removed comment sign in front of unlink around. It was there due to some
 * 881)     some tests and I had forgotten to remove it.
 * 882)   - datastore_volumes_info. Some bugs corrected.
 * 883)     - Wrong percent calculation
 * 884)     - Wrong processing of thresholds for usedspace
 * 885)     - Wrong processing for thresholds which are not percent
 * 886)     - If threshold is in percent it is calculated in MB/GB for perfdata
 * 887)       because mixing percent and MB/GB doesn't make sense.
 * 888) - 5 Apr 2014 M.Fuerstenau version 0.9.14
 * 889)   - host_runtime_info
 * 890)     - Fixed some bugs with issues ignored and whitelist. Some counters were calculated
 * 891)       wrong
 * 892) - 29 Apr 2014 M.Fuerstenau version 0.9.15
 * 893)   - host_mem_info, vm_mem_info, host_cpu_info and vm_cpu_info.
 * 894)     - Sometimes it may happen on Vmware 5.5 (not seen when testing with Update 1) that getting
 * 895)       the perfdata for cpu and/or memory will result in an empty construct because one
 * 896)       or more values are not delivered. In this case we have a fallback and and every value
 * 897)   - dc_runtime_info
 * 898)     - New option --poweredonly to list only machines which are powered on
 * 899) - 20 May 2014 M.Fuerstenau version 0.9.16
 * 900)   - New option --nosession.
 * 901)     - This was implemented for 2 reasons.
 * 902)       - First when testing from the commandline using this switch to avoid
 * 903)         waiting and timeouts while the monitor system is checking the the same host.
 * 904)         This is the important reason.
 * 905)       - Second is that some people don't like sessionfiles and prefer full logs as
 * 906)         it was in the past. Good ol' times.
 * 907)   - host_runtime_info
 * 908)     - added --nostoragestatus to -S runtime -s health to avoid a double alarm
 * 909)       when also doing a check with -S runtime -s storagehealth for the same
 * 910)       host.
 * 911)   - dc_runtime_info
 * 912)     - changed
 * 913)       if (($subselect eq "listcluster") || ($subselect eq "all"))
 * 914)       to
 * 915)       if (($subselect =~ m/listcluster.*$/) || ($subselect eq "all"))
 * 916)       This is to avoid unnecessary typos because it covers listcluster and listclusters ;-)
 * 917)   - datastore_volumes_info
 * 918)     -  Heavily reworked lot of the logical structure. There were too much changes
 * 919)        changes after changes which lead to bugs. Now it is cleaned up.
 * 920)   - cluster_list_vm_volumes_info
 * 921)     - Seperate module now
 * 922)   - cluster_cpu_info
 * 923)     - Seperate module now but still not working.
 * 924) - 1 Jul 2014 M.Fuerstenau version 0.9.16a
 * 925)   - Unfortunately published some modules containing debugging outpu. Fixed.
 * 926)     - host_disk_io_info.pm
 * 927)     - process_perfdata.pm
 * 928)     - vm_disk_io_info.pm
 * 929) - 20 Jul 2014 M.Fuerstenau version 0.9.17
 * 930)   - Removing the last multiline character (\n or ) was moved
 * 931)     from several subroutines to the main exit in check_vmware_esx.pl.
 * 932)     This was based this was implemented based on a proposal of Dietmar Eberth
 * 933)     Affected subroutines:
 * 934)     - vm_runtime_info
 * 935)     - host_storage_info
 * 936)     - host_runtime_info
 * 937)     - dc_runtime_info
 * 938)     -datastore_volumes_info
 * 939)   - Fixed a bug on line 139 and 172. Thanks for fixing it to Dietmar Eberth.
 * 940)     - Instead of
 * 941)       if ( $state >= 0 )
 * 942)          $alertcnt++;
 * 943)          }
 * 944)       it must be:
 * 945)       if ( $alertcnt > 0 )
 * 946)          $alertcnt++;
 * 947)          }
 * 948)   - Fixed a bug on line 139 and 172. Thanks for fixing it to Dietmar Eberth.
 * 949)   - If only one volume is selected we have a better output now. Also thanks
 * 950)     to Dietmar Eberth.
 * 951) - 21 Jul 2014 M.Fuerstenau version 0.9.17a
 * 952)   - Bugfix line 139 and 172 (now 140 and 173). It must be
 * 953)     if ( $actual_state > 0 )
 * 954)     instead of
 * 955)     if ( $alertcnt > 0
 * 956) - 25 Jul 2014 M.Fuerstenau version 0.9.18
 * 957)   - New option --perf_free_space for checking volumes. It must be used
 * 958)     with --usedspace. In versions prior to 0.9.18 perfdata was always
 * 959)     deliverd as free space even if --usedspace was selected. From 0.9.18
 * 960)     on when using --usedspace perfdata is recorded as used space. To prevent
 * 961)     old perfdata use this option.
 * 962)   - Cluster - removed checks for CPU and MEM
 * 963)     - Both checks were senseless for alarming because there are no thresholds.
 * 964)       A cluster or resource group is a group of Vmware hosts. Not a logical
 * 965)       construct taking parts of the hosts in a resource group in a manner
 * 966)       that several clusters are using the same hosts. So the amount of CPU
 * 967)       and memory of all hosts is the CPU and memory of the cluster. Monitoring
 * 968)       this makes no sense because there are no thresholds for alerting. For
 * 969)       example 50% CPU usage of a cluster can be one host with 90%, and two
 * 970)       with 30% each. With an average of 50% everything seems to be ok but one
 * 971)       machine has definetely a problem. Same for memory.
 * 972) - 21 Aug 2014 M.Fuerstenau version 0.9.19
 * 973)   - host_runtime_info
 * 974)     - Some minor corrections in output.
 * 975)   - host_storage_info
 * 976)     - Some corrections in output for LUNs. Using in output was a
 * 977)       really stupid idea because the code (like ok,error-lostCommunication or
 * 978)       whatever is valid there) was interpreted as non existing HTML code.
 * 979)     - Some corrections in output for multipath/paths.
 * 980)     - Bugfix. Due to a wrong placed curly bracked the output was doubled. Fixed.
 * 981)   - host_runtime_info
 * 982)     - Small bugfix. It may happen within the heath check that some values are not set
 * 983)       by VMware/hardware. In this case we have an
 * 984)       "[Use of uninitialized value in concatenation (.) or string ..."
 * 985)       To avoid this we check the values of the hash with each loop an in case a value
 * 986)       is not set we replace it whit the string "Unknown".
 * 1) - 26 Feb 2014 M.Fuerstenau version 0.9.10
 * 2)   - Bugfixes.
 * 3)     - Corrected typo in dc_runtime_info line 660.
 * 4)     - Corrected typo in help.
 * 5)     - Corrected bug in datastore_volumes_info. Giving absolute thresholds
 * 6)       for a single volume was not possible. Fixed.
 * 7)   - Removed print_usage. Due to mass of parameters it is not possible to display
 * 8)     a short usage message. Instead of that the output of the help is included
 * 9)     in the package as a file.
 * 10)   - Updated default timeout to 90 secs. to avoid timeouts.
 * 11)   - Before accessing the session file (and lock file) we have a random sleep up
 * 12)     7 secs.. This is to avoid a concurrent access in case of a monitor restart
 * 13)     or a "Schedule a check of all services on this host"
 * 14)   - In case of a locked session file the wait loop is not fix to 1 sec any more.
 * 15)     Instead of this it uses a random period up to 5 sec.. So we minimize the risc
 * 16)     of concurrent access.
 * 17) - 7 Mar 2014 M.Fuerstenau version 0.9.11
 * 18)   - Updated README
 * 19)     - Section for removing HTML tags was reworked
 * 20)   - Added blacklist to host_net_info so that interfaces with -S net can
 * 21)     be blacklisted.
 * 22) - 11 Mar 2014 M.Fuerstenau version 0.9.12
 * 23)   - Changed sleep to usleep and using now microseconds instead of seconds
 * 24)   - So before accessing the session file (and lock file) we now have a random sleep
 * 25)     up to 1500 milliseconds (default - see $ms_ts). This is to avoid a concurrent access
 * 26)     in case of a monitor restart or a "Schedule a check of all services on this host"
 * 27)     but takes much less time while having much more alternatives.
 * 28)   - In case of a locked session file the wait loop is not fix to a random period up to
 * 29)     5 sec. any more. Instead of this it uses also $ms_ts which means a max of 1.5 secs.
 * 30)     instead of 5.
 * 31) - 3 Apr 2014 M.Fuerstenau version 0.9.13
 * 32)   - --trace= was not working. Fixed. Small typo.
 * 33)   - Removed comment sign in front of unlink around. It was there due to some
 * 34)     some tests and I had forgotten to remove it.
 * 35)   - datastore_volumes_info. Some bugs corrected.
 * 36)     - Wrong percent calculation
 * 37)     - Wrong processing of thresholds for usedspace
 * 38)     - Wrong processing for thresholds which are not percent
 * 39)     - If threshold is in percent it is calculated in MB/GB for perfdata
 * 40)       because mixing percent and MB/GB doesn't make sense.
 * 41) - 5 Apr 2014 M.Fuerstenau version 0.9.14
 * 42)   - host_runtime_info
 * 43)     - Fixed some bugs with issues ignored and whitelist. Some counters were calculated
 * 44)       wrong
 * 45) - 29 Apr 2014 M.Fuerstenau version 0.9.15
 * 46)   - host_mem_info, vm_mem_info, host_cpu_info and vm_cpu_info.
 * 47)     - Sometimes it may happen on Vmware 5.5 (not seen when testing with Update 1) that getting
 * 48)       the perfdata for cpu and/or memory will result in an empty construct because one
 * 49)       or more values are not delivered. In this case we have a fallback and and every value
 * 50)   - dc_runtime_info
 * 51)     - New option --poweredonly to list only machines which are powered on
 * 52) - 20 May 2014 M.Fuerstenau version 0.9.16
 * 53)   - New option --nosession.
 * 54)     - This was implemented for 2 reasons.
 * 55)       - First when testing from the commandline using this switch to avoid
 * 56)         waiting and timeouts while the monitor system is checking the the same host.
 * 57)         This is the important reason.
 * 58)       - Second is that some people don't like sessionfiles and prefer full logs as
 * 59)         it was in the past. Good ol' times.
 * 60)   - host_runtime_info
 * 61)     - added --nostoragestatus to -S runtime -s health to avoid a double alarm
 * 62)       when also doing a check with -S runtime -s storagehealth for the same
 * 63)       host.
 * 64)   - dc_runtime_info
 * 65)     - changed
 * 66)       if (($subselect eq "listcluster") || ($subselect eq "all"))
 * 67)       to
 * 68)       if (($subselect =~ m/listcluster.*$/) || ($subselect eq "all"))
 * 69)       This is to avoid unnecessary typos because it covers listcluster and listclusters ;-)
 * 70)   - datastore_volumes_info
 * 71)     -  Heavily reworked lot of the logical structure. There were too much changes
 * 72)        changes after changes which lead to bugs. Now it is cleaned up.
 * 73)   - cluster_list_vm_volumes_info
 * 74)     - Seperate module now
 * 75)   - cluster_cpu_info
 * 76)     - Seperate module now but still not working.
 * 77) - 1 Jul 2014 M.Fuerstenau version 0.9.16a
 * 78)   - Unfortunately published some modules containing debugging outpu. Fixed.
 * 79)     - host_disk_io_info.pm
 * 80)     - process_perfdata.pm
 * 81)     - vm_disk_io_info.pm
 * 82) - 20 Jul 2014 M.Fuerstenau version 0.9.17
 * 83)   - Removing the last multiline character (\n or ) was moved
 * 84)     from several subroutines to the main exit in check_vmware_esx.pl.
 * 85)     This was based this was implemented based on a proposal of Dietmar Eberth
 * 86)     Affected subroutines:
 * 87)     - vm_runtime_info
 * 88)     - host_storage_info
 * 89)     - host_runtime_info
 * 90)     - dc_runtime_info
 * 91)     -datastore_volumes_info
 * 92)   - Fixed a bug on line 139 and 172. Thanks for fixing it to Dietmar Eberth.
 * 93)     - Instead of
 * 94)       if ( $state >= 0 )
 * 95)          $alertcnt++;
 * 96)          }
 * 97)       it must be:
 * 98)       if ( $alertcnt > 0 )
 * 99)          $alertcnt++;
 * 100)          }
 * 101)   - Fixed a bug on line 139 and 172. Thanks for fixing it to Dietmar Eberth.
 * 102)   - If only one volume is selected we have a better output now. Also thanks
 * 103)     to Dietmar Eberth.
 * 104) - 21 Jul 2014 M.Fuerstenau version 0.9.17a
 * 105)   - Bugfix line 139 and 172 (now 140 and 173). It must be
 * 106)     if ( $actual_state > 0 )
 * 107)     instead of
 * 108)     if ( $alertcnt > 0
 * 109) - 25 Jul 2014 M.Fuerstenau version 0.9.18
 * 110)   - New option --perf_free_space for checking volumes. It must be used
 * 111)     with --usedspace. In versions prior to 0.9.18 perfdata was always
 * 112)     deliverd as free space even if --usedspace was selected. From 0.9.18
 * 113)     on when using --usedspace perfdata is recorded as used space. To prevent
 * 114)     old perfdata use this option.
 * 115)   - Cluster - removed checks for CPU and MEM
 * 116)     - Both checks were senseless for alarming because there are no thresholds.
 * 117)       A cluster or resource group is a group of Vmware hosts. Not a logical
 * 118)       construct taking parts of the hosts in a resource group in a manner
 * 119)       that several clusters are using the same hosts. So the amount of CPU
 * 120)       and memory of all hosts is the CPU and memory of the cluster. Monitoring
 * 121)       this makes no sense because there are no thresholds for alerting. For
 * 122)       example 50% CPU usage of a cluster can be one host with 90%, and two
 * 123)       with 30% each. With an average of 50% everything seems to be ok but one
 * 124)       machine has definetely a problem. Same for memory.
 * 125) - 21 Aug 2014 M.Fuerstenau version 0.9.19
 * 126)   - host_runtime_info
 * 127)     - Some minor corrections in output.
 * 128)   - host_storage_info
 * 129)     - Some corrections in output for LUNs. Using in output was a
 * 130)       really stupid idea because the code (like ok,error-lostCommunication or
 * 131)       whatever is valid there) was interpreted as non existing HTML code.
 * 132)     - Some corrections in output for multipath/paths.
 * 133)     - Bugfix. Due to a wrong placed curly bracked the output was doubled. Fixed.
 * 134)   - host_runtime_info
 * 135)     - Small bugfix. It may happen within the heath check that some values are not set
 * 136)       by VMware/hardware. In this case we have an
 * 137)       "[Use of uninitialized value in concatenation (.) or string ..."
 * 138)       To avoid this we check the values of the hash with each loop an in case a value
 * 139)       is not set we replace it whit the string "Unknown".
 * 1)       this makes no sense because there are no thresholds for alerting. For
 * 2)       example 50% CPU usage of a cluster can be one host with 90%, and two
 * 3)       with 30% each. With an average of 50% everything seems to be ok but one
 * 4)       machine has definetely a problem. Same for memory.
 * 5) - 21 Aug 2014 M.Fuerstenau version 0.9.19
 * 6)   - host_runtime_info
 * 7)     - Some minor corrections in output.
 * 8)   - host_storage_info
 * 9)     - Some corrections in output for LUNs. Using in output was a
 * 10)       really stupid idea because the code (like ok,error-lostCommunication or
 * 11)       whatever is valid there) was interpreted as non existing HTML code.
 * 12)     - Some corrections in output for multipath/paths.
 * 13)     - Bugfix. Due to a wrong placed curly bracked the output was doubled. Fixed.
 * 14)   - host_runtime_info
 * 15)     - Small bugfix. It may happen within the heath check that some values are not set
 * 16)       by VMware/hardware. In this case we have an
 * 17)       "[Use of uninitialized value in concatenation (.) or string ..."
 * 18)       To avoid this we check the values of the hash with each loop an in case a value
 * 19)       is not set we replace it whit the string "Unknown".
 * 1)       is not set we replace it whit the string "Unknown".

use strict; use warnings; use File::Basename; use HTTP::Date; use Getopt::Long; use VMware::VIRuntime; use Time::Duration; use Time::HiRes qw(usleep);

use lib "modules"; use lib "/usr/lib/nagios/plugins/check_vmware_esx_0.9.19/modules"; use help; use process_perfdata; use datastore_volumes_info;
 * 1) Own modules


 * 1) Prevent SSL certificate validation

$ENV{'PERL_LWP_SSL_VERIFY_HOSTNAME'} = 0;

use Data::Dumper; $Data::Dumper::Indent = 1;
 * 1) Only for debugging
 * 1) print "--\n" . Dumper ($store) . "\n" . "--\n";

if ( $@ ) {  print "No VMware::VIRuntime found. Please download "; print "latest version of VMware-vSphere-SDK-for-Perl from VMware "; print "and install it.\n"; exit 2; }

$SIG{ALRM} = 'catch_alarm'; $SIG{INT} = 'catch_intterm'; $SIG{TERM} = 'catch_intterm';
 * 1) Let's catch some signals
 * 2) Handle SIGALRM (timeout triggered by alarm call)


 * 1) --- Start presets and declarations -
 * 2) 1. Define variables

our $version;                                 # Only for showing the version our $prog_version = '0.9.19';                 # Contains the program version number our $ProgName = basename($0);
 * 1) General stuff

my $PID = $$;                                 # Stores the process identifier of the actual run. This will be                                              # be stored in the lock file. my $PID_exists;                               # For testing for the process that wrote the lock file the last time my $PID_old;                                  # PID read from lock file

my $help;                                     # If some help is wanted.... my $NoA="";                                   # Number of arguments handled over # the program my $username;                                 # Username for vmware host or vsphere server (datacenter) my $password;                                 # Password for vmware host or vsphere server (datacenter) my $authfile;                                 # If username/password should read from a file .... my $sessionfile_name;                         # Contains the name of the sessionfile if a                                               # a sessionfile is used for faster authentication my $sessionlockfile;                          # Lockfile to protect the session my $sessionfile_dir;                          # Optinal. Contains the path to the sessionfile. Used in conjunction # with sessionfile my $nosession;                                # Just a flag to avoid using a sessionfile my $vim;                                       # Needed to stroe results ov Vim.
 * 1) Login options

our $host;                                    # Name of the vmware server my $cluster;                                  # Name of the monitored cluster our $datacenter;                              # Name of the vCenter server our $vmname;                                  # Name of the virtual machine

my $output;                                   # Contains the output string my $values; my $result;                                   # Contains the output string our $perfdata;                                # Contains the perfdata string. my $perfdata_init = "perfdata:";              # Contains the perfdata init string. We init $perfdata with # a stupid string because in case of concatenate perfdata # it is much more simple to remove a leading string with # a regular expression than to decide in every case wether # the variablecontains content or not. $perfdata = $perfdata_init;                   # Init of perfdata. Using variables instead of literals ensures # that the string can be changed here without harm the function. our $perf_thresholds = ";";                   # This contains the string with $warning, $critical or nothing # for $perfdata. If no thresold is set it is just ;

my $url2connect;                              # Contains the URL to connect to the host # or the datacenter depending on the selected type my $sslport;                                  # If a port other than 443 is used. my $sslport_def = 443;                        # Default port my $select; our $subselect;

our $warning;                                 # Warning threshold. our $critical;                                # Critical threshold. our $reverse_threshold;                       # Flag. Needed if critical must be smaller than warning

our $crit_is_percent;                         # Flag. If it is set to one critical threshold is percent. our $warn_is_percent;                         # Flag. If it is set to one warning threshold is percent. my $thresholds_given = 0;                     # During checking the threshold it will be set to one. Only if                                              # it is set we will check the threshold against warning or critical my $plugin_cache="/var/nagios_plugin_cache/"; # Directory for caching plaugin data. Good idea to use a tmpfs # because it speeds up operation our $listsensors;                             # This flag set in conjunction with -l runtime -s health or -s sensors # will list all sensors our $usedspace;                               # Show used spaced instead of free our $gigabyte;                                # Output in gigabyte instead of megabyte our $perf_free_space;                         # To display perfdata as free space instead of used when using # --usedspace our $alertonly;                               # vmfs - list only alerting volumes

our $blacklist;                               # Contains the blacklist our $whitelist;                               # Contains the whitelist

our $isregexp;                                # treat names, blacklist and whitelists as regexp

my $sec;                                      # Seconds      - used for some date functions my $min;                                      # Minutes      - used for some date functions my $hour;                                     # Hour         - used for some date functions my $mday;                                     # Day of month - used for some date functions my $mon;                                      # Month        - used for some date functions my $year;                                     # Year         - used for some date functions

my $timeout = 90;                             # Time in seconds befor the plugin kills itself when it' not ready my $ms_ts = 1500;                             # Milliseconds to sleep for waiting for accessing the lockfile.

our $multiline;                               # Multiline output in overview. This mean technically that # a multiline output uses a HTML for the GUI instead of                                              # Be aware that your messing connections (email, SMS...) must use # a filter to file out the. A sed oneliner like the following # will do the job: # sed 's/<[^<>]*>//g' my $multiline_def="\n";                       # Default for $multiline;
 * 1) Output options

our $vm_tools_poweredon_only;                 # Used with Vcenter runtime check to list only powered on VMs when # checking the tools our $ignoreunknown;                           # Maps unknown to ok our $ignorewarning;                            # Maps warning to ok our $standbyok;                                # For multipathing if a standby multipath is ok our $listall;                                  # used for host. Lists all available devices(use for listing purpose only) our $nostoragestatus;                         # To avoid a double alarm when also doing a check with -S runtime -s health # and -S runtime -s storagehealth for the same host.

my $trace;


 * 1) 2. Define arrays and hashes


 * 1) The same as in Nagios::plugin::functions but it is ridiculous to buy a truck for a
 * 2) "one time one box" transportations job.

our %status2text = (   0 => 'Ok',    1 => 'Warning',    2 => 'Critical',    3 => 'Unknown',    4 => 'Dependent', );


 * 1) --- End presets


 * 1) First we have to fix  the number of arguments

$NoA=$#ARGV;

Getopt::Long::Configure('bundling'); GetOptions ("h:s" => \$help,               "help:s"           => \$help,	 "H=s" => \$host,                "host=s"           => \$host,	 "C=s" => \$cluster,             "cluster=s"        => \$cluster,	 "D=s" => \$datacenter,          "datacenter=s"     => \$datacenter,	 "w=s" => \$warning,             "warning=s"        => \$warning,	 "c=s" => \$critical,            "critical=s"       => \$critical,	 "N=s" => \$vmname,              "name=s"           => \$vmname,	 "u=s" => \$username,            "username=s"       => \$username,	 "p=s" => \$password,            "password=s"       => \$password,	 "f=s" => \$authfile,            "authfile=s"       => \$authfile,	 "S=s" => \$select,              "select=s"         => \$select,	 "s=s" => \$subselect,           "subselect=s"      => \$subselect,	                                 "sessionfile=s"    => \$sessionfile_name,	                                 "sessionfiledir=s" => \$sessionfile_dir, "nosession"       => \$nosession, "B=s" => \$blacklist,          "exclude=s"        => \$blacklist, "W=s" => \$whitelist,          "include=s"        => \$whitelist, "t=s" => \$timeout,            "timeout=s"        => \$timeout, "ignore_unknown"  => \$ignoreunknown, "ignore_warning"  => \$ignorewarning, "trace=s"         => \$trace, "listsensors"     => \$listsensors, "usedspace"       => \$usedspace, "perf_free_space" => \$perf_free_space, "alertonly"       => \$alertonly, "multiline"       => \$multiline, "isregexp"        => \$isregexp, "listall"         => \$listall, "poweredonly"     => \$vm_tools_poweredon_only, "standbyok"       => \$standbyok, "sslport=s"       => \$sslport, "gigabyte"        => \$gigabyte, "nostoragestatus" => \$nostoragestatus, "V"  => \$version,             "version"          => \$version);

if ($version) {  print "Version $prog_version\n"; print "This program is free software; you can redistribute it and/or modify\n"; print "it under the terms of the GNU General Public License version 2 as\n"; print "published by the Free Software Foundation.\n"; exit 0; }
 * 1) Show version

if (defined($help)) {  print_help($help); exit 0; }
 * 1) Several checks to check parameters

if (defined($blacklist) && defined($whitelist)) {  print "Error: -B|--exclude and -W|--include should not be used together.\n\n"; print_help($help); exit 1; }

if ($multiline) {  $multiline = " "; } else {  $multiline = $multiline_def; }
 * 1) Multiline output in GUI overview?


 * 1) Right number of arguments (therefore NoA :-)) )

if ( $NoA == -1 ) {  print_help($help); exit 1; }

if ($timeout) {  # Start the timer to script timeout alarm($timeout); }
 * 1) If you have set a timeout exit with alarm

$output = "Unknown ERROR!"; $result = 2;

if (defined($subselect)) {  if ($subselect eq '') {     $subselect = undef; }     else {     if ( $select ne "volumes") {        $subselect = local_lc($subselect) }     }   }
 * 1) Check $subselect and if defined set it to upper case letters


 * 1) Now we remove the percent sign if warning or critical is givenin percent
 * 2) Construct threshold part for perfomance data

if (defined($warning)) {  $warn_is_percent  = $warning =~ s/\%//;

if ($warning eq '') {     $warning = undef; $perf_thresholds = $perf_thresholds. ";";     }   else {     # Numeric now or not? if ($warning =~ m/^[0-9]+$/) {        $thresholds_given = 1; # If percent check a valid range if ($warn_is_percent eq 1) {           if (!($warning > 0 && $warning <= 100 )) {              print "Invalid warning threshold: $warning%\n\n"; exit 2; }           }         $perf_thresholds = $warning .$perf_thresholds; }     else {        print "Warning threshold contains unwanted characters: $warning\n\n"; exit 2; }     }   }

if (defined($critical)) {  $crit_is_percent  = $critical =~ s/\%//;

if ($critical eq '') {     $critical = undef; $perf_thresholds = $perf_thresholds. ";";     }   else {     # Numeric now or not? if ($critical =~ m/^[0-9]+$/) {        $thresholds_given = 1;

# If percent check a valid range if ($crit_is_percent eq 1) {           if (!($critical > 0 && $critical <= 100 )) {              print "\nInvalid critical threshold: $critical%\n"; exit 2; }           }         $perf_thresholds = $perf_thresholds. $critical; }     else {        print "Critical threshold contains unwanted characters: $critical\n\n"; exit 2; }     }   }


 * 1) Check for authfile or valid username/password

if ((!defined($password) || !defined($username) || defined($authfile)) && (defined($password) || defined($username) || !defined($authfile)) && (defined($password) || defined($username) || defined($authfile) || !defined($sessionfile_name))) {  print "Provide either Password/Username or Auth file or Session file\n"; exit 2; }


 * 1) Check threshold unit

if (($warn_is_percent && !$crit_is_percent && defined($critical)) || (!$warn_is_percent && $crit_is_percent && defined($warning))) {  print "Both threshold values must be the same units\n"; exit 2; }

if (defined($authfile)) {  unless(open AUTH_FILE, '<', $authfile) {        print "Unable to open auth file \"$authfile\"\n"; exit 3; }  while (  ) {        if (s/^[ \t]*username[ \t]*=//) {           s/^\s+//;s/\s+$//; $username = $_; }        if (s/^[ \t]*password[ \t]*=//) {           s/^\s+//;s/\s+$//; $password = $_; }        }   if (!(defined($username) && defined($password))) {     print "Auth file must contain both username and password\n"; exit 2; }  }


 * 1) Connection to a single host or a datacenter server?

if (defined($datacenter)) {  $url2connect = $datacenter; } else {  if (defined($host)) {     $url2connect = $host; }  else {     print "No Host or Datacenter specified\n"; exit 2; }  }

if (defined($sslport)) {  $url2connect = $url2connect. ":" . $sslport; }

$url2connect = "https://". $url2connect. "/sdk/webService";


 * 1) Now let's do the login stuff

if (!defined($nosession)) {  if (defined($datacenter)) {     if (defined($sessionfile_name)) {        $sessionfile_name =~ s/ +//g; $sessionfile_name = $datacenter. "_" . $sessionfile_name. "_session"; }     else {        $sessionfile_name = $datacenter. "_session"; }     }   else {     if (defined($sessionfile_name)) {        $sessionfile_name =~ s/ +//g; $sessionfile_name = $host. "_" . $sessionfile_name. "_session"; }     else {        $sessionfile_name = $host. "_session"; }     }   if (defined($sessionfile_dir)) {     # If path contains trailing slash remove it      $sessionfile_dir =~ s/\/$//; $sessionfile_name = $sessionfile_dir. "/" . $sessionfile_name; }  else {     $sessionfile_name = $plugin_cache. $sessionfile_name; }  $sessionlockfile = $sessionfile_name. "_locked"; if ( -e $sessionfile_name ) {     usleep(int(rand($ms_ts)) * 1000); if ( -e $sessionlockfile ) {        # Session locked? First open the lock file for reading unless(open SESSION_LOCK_FILE, '<', $sessionlockfile) {              print "Unable to open session lock file \"$sessionlockfile\"\n"; exit 3; }        # Second get the old PID while() {             $PID_old = $_; }        close (SESSION_LOCK_FILE); # Third - check for the process which wrote the lock file the last time $PID_exists = kill 0, $PID_old; # Fourth - if the process is not available any more remove the lock file if ( !$PID_exists ) {           unlink $sessionlockfile; }        }      # Now we are sure that we have no dead lock file and we will wait for free session while ( -e $sessionlockfile ) {           usleep(int(rand($ms_ts)) * 1000); }     unless(open SESSION_LOCK_FILE, '>', $sessionlockfile) {           print "Unable to create session lock file \"$sessionlockfile\"\n"; exit 3; }     print SESSION_LOCK_FILE "$PID\n"; close (SESSION_LOCK_FILE); eval {Vim::load_session(session_file => $sessionfile_name)}; if (($@ =~ /The session is not authenticated/gi) || (Opts::get_option("url") ne $url2connect)) {        unlink $sessionfile_name; Util::connect($url2connect, $username, $password); Vim::save_session(session_file => $sessionfile_name); }     else {        Vim::load_session(session_file => $sessionfile_name); }     }   else {     unless(open SESSION_LOCK_FILE, '>', $sessionlockfile) {           print "Unable to create session lock file \"$sessionlockfile\"\n"; exit 3; }     print SESSION_LOCK_FILE "$PID\n"; close (SESSION_LOCK_FILE); Util::connect($url2connect, $username, $password); Vim::save_session(session_file => $sessionfile_name); }  } else {  Util::connect($url2connect, $username, $password); }

if (defined($trace)) {  $Util::tracelevel = $Util::tracelevel;
 * 1) Tracemode?

if (($trace =~ m/^\d$/) && ($trace >= 0) && ($trace <= 4)) {     $Util::tracelevel = $trace; }  }

$select = lc($select);


 * 1) This calls the main selection. It is now in a subroutine
 * 2) because after a successfull if statement the rest can be skipped
 * 3) leaving the subroutine with return

main_select;

if ($@) {  if (uc(ref($@)) eq "HASH") {     $output = $@->{msg}; $result = $@->{code}; }  else {     $output = $@. "";     $result = 2; }  }

if (defined($sessionfile_name) and -e $sessionfile_name) {  Vim::unset_logout_on_disconnect; unlink $sessionlockfile; } else {  Util::disconnect; }


 * 1) Added for mapping unknown to ok - M.Fuerstenau - 30 Mar 2011

if (defined($ignoreunknown)) {  if ($result eq 3) {     $result = 0; }  }
 * 1) Added for mapping warning to ok - M.Fuerstenau - 31 Dec 2013

if (defined($ignorewarning)) {  if ($result eq 2) {     $result = 0; }  }

$perfdata =~ s/^$perfdata_init//; $perfdata =~ s/^[ \t]*//;
 * 1) Now we remove the leading init string and whitespaces from the perfdata

if ( $result == 0 ) {  print "$output"; if ($perfdata) {     print "|$perfdata\n"; }     else {     print "\n"; }  }

$output =~ s/$multiline$//;
 * 1) Remove the last multiline regardless whether it is \n or

if ( $result == 1 ) {  print "Warning! $output"; if ($perfdata) {     print "|$perfdata\n"; }     else {     print "\n"; }  }

if ( $result == 2 ) {  print "Critical! $output"; if ($perfdata) {     print "|$perfdata\n"; }     else {     print "\n"; }  }

if ( $result == 3 ) {  print "$output"; if ($perfdata) {     print "|$perfdata\n"; }     else {     print "\n"; }  }

exit $result;



sub main_select {   if (defined($vmname)) {      if ($select eq "cpu") {         require vm_cpu_info; import vm_cpu_info; ($result, $output) = vm_cpu_info($vmname); return($result, $output); }      if ($select eq "mem") {         require vm_mem_info; import vm_mem_info; ($result, $output) = vm_mem_info($vmname); return($result, $output); }      if ($select eq "net") {         require vm_net_info; import vm_net_info; ($result, $output) = vm_net_info($vmname); return($result, $output); }      if ($select eq "io") {         require vm_disk_io_info; import vm_disk_io_info; ($result, $output) = vm_disk_io_info($vmname); return($result, $output); }      if ($select eq "runtime") {         require vm_runtime_info; import vm_runtime_info; ($result, $output) = vm_runtime_info($vmname); return($result, $output); }      if ($select eq "soap") {         ($result, $output) = soap_check; return($result, $output); }

get_me_out("Unknown host-vm select"); }

if (defined($host)) {      # The following if black is only needed if we check a ESX server via the # the datacenten (vsphere server) instead of doing it directly. # Directly is better my $esx_server; if (defined($datacenter)) {         $esx_server = {name => $host}; }      if ($select eq "cpu") {         require host_cpu_info; import host_cpu_info; ($result, $output) = host_cpu_info($esx_server); return($result, $output); }      if ($select eq "mem") {         require host_mem_info; import host_mem_info; ($result, $output) = host_mem_info($esx_server); return($result, $output); }      if ($select eq "net") {         require host_net_info; import host_net_info; ($result, $output) = host_net_info($esx_server); return($result, $output); }      if ($select eq "io") {         require host_disk_io_info; import host_disk_io_info; ($result, $output) = host_disk_io_info($esx_server); return($result, $output); }      if ($select eq "volumes") {         require host_list_vm_volumes_info; import host_list_vm_volumes_info; ($result, $output) = host_list_vm_volumes_info($esx_server); return($result, $output); }      if ($select eq "runtime") {         require host_runtime_info; import host_runtime_info; ($result, $output) = host_runtime_info($esx_server); return($result, $output); }      # service OR services because I always type the wrong one :-)) - M.Fuerstenau if ($select =~ m/^service.?$/) {         require host_service_info; import host_service_info; ($result, $output) = host_service_info($esx_server); return($result, $output); }      if ($select eq "storage") {         require host_storage_info; import host_storage_info; ($result, $output) = host_storage_info($esx_server, $blacklist); return($result, $output); }      if ($select eq "uptime") {         require host_uptime_info; import host_uptime_info; ($result, $output) = host_uptime_info($esx_server); return($result, $output); }      if ($select eq "hostmedia") {         require host_mounted_media_info; import host_mounted_media_info; ($result, $output) = host_mounted_media_info($esx_server); return($result, $output); }      if ($select eq "soap") {         ($result, $output) = soap_check; return($result, $output); }

get_me_out("Unknown host select"); }

if (defined($cluster)) {      if ($select eq "cluster") {         ($result, $output) = cluster_cluster_info($cluster); return($result, $output); }      if ($select eq "volumes") {         require cluster_list_vm_volumes_info; import cluster_list_vm_volumes_info; ($result, $output) = cluster_list_vm_volumes_info($cluster); return($result, $output); }      if ($select eq "runtime") {         ($result, $output) = cluster_runtime_info($cluster, $blacklist); return($result, $output); }      if ($select eq "soap") {         ($result, $output) = soap_check; return($result, $output); }

get_me_out("Unknown cluster select"); }

if (defined($datacenter)) {      if ($select eq "volumes") {         require dc_list_vm_volumes_info; import dc_list_vm_volumes_info; ($result, $output) = dc_list_vm_volumes_info; return($result, $output); }      if ($select eq "runtime") {         require dc_runtime_info; import dc_runtime_info; ($result, $output) = dc_runtime_info; return($result, $output); }      if ($select eq "soap") {         ($result, $output) = soap_check; return($result, $output); }

get_me_out("Unknown datacenter select"); }   get_me_out("You should never end here. Totally unknown anything."); } sub check_against_threshold {   my $check_result = shift(@_); my $return_state = 0;

if ((defined($warning)) && (defined($critical))) {      if ( $warning >= $critical ) {         if ( $check_result <= $warning) {            $return_state = 1; }         if ( $check_result <= $critical) {            $return_state = 2; }         }       else {         if ( $check_result >= $warning) {            $return_state = 1; }         if ( $check_result >= $critical) {            $return_state = 2; }         }       }    else {      if (defined($warning)) {         if ( $check_result >= $warning) {            $return_state = 1; }         }

if (defined($critical)) {         if ( $check_result >= $critical) {            $return_state = 2; }         }       }    return $return_state; } sub check_state {   if (grep { $_ == 2 } @_) {      return 2; }   if (grep { $_ == 1 } @_) {      return 1; }   if (grep { $_ == 3 } @_) {      return 3; }   if (grep { $_ == 0 } @_) {      return 0; }   return 3; }

sub local_lc {   my ($val) = shift(@_); if (defined($val)) {      return lc($val); }   else {      return undef; }   }

sub simplify_number {   my ($number, $cnt) = @_; if (!defined($cnt)) {      $cnt = 2; }   return sprintf("%.${cnt}f", "$number"); }

sub convert_number {   my @vals = split(/,/, shift(@_)); my $state = 0; my $value;

while (@vals) {         $value = pop(@vals); $value =~ s/^\s+//; $value =~ s/\s+$//; if (defined($value) && $value ne '') {            if ($value >= 0) {               return $value; }            if ($state == 0) {               $state = $value; }            }          }    return $state; }

sub check_health_state {   my ($actual_state) = shift(@_); my $state = 3;

if (lc($actual_state) eq "green") {      $state = 0 }

if (lc($actual_state) eq "yellow") {      $state = 1; }   if (lc($actual_state) eq "red") {      $state = 2; }   return $state; }

sub format_issue {   my ($issue) = shift(@_); my $output = '';

if (defined($issue->datacenter)) {      $output = $output. 'Datacenter "' . $issue->datacenter->name . '", '; }

if (defined($issue->host)) {      $output = $output. 'Host "' . $issue->host->name . '", '; }

if (defined($issue->vm)) {      $output = $output. 'VM "' . $issue->vm->name . '", '; }

if (defined($issue->computeResource)) {      $output = $output. 'Compute Resource "' . $issue->computeResource->name . '", '; }

if (exists($issue->{dvs}) && defined($issue->dvs)) {      # Since vSphere API 4.0 $output = $output. 'Virtual Switch "' . $issue->dvs->name . '", '; }

if (exists($issue->{ds}) && defined($issue->ds)) {      # Since vSphere API 4.0 $output = $output. 'Datastore "' . $issue->ds->name . '", '; }

if (exists($issue->{net}) && defined($issue->net)) {      # Since vSphere API 4.0 $output = $output. 'Network "' . $issue->net->name . '" '; }

$output =~ s/, $/ /; $output = $output. ": " . $issue->fullFormattedMessage; if ($issue->userName ne "") {         $output = $output. "(caused by " . $issue->userName . ")"; }

return $output; }


 * 1) SOAP check, isblacklisted and isnotwhitelisted from Simon Meggle, Consol.
 * 2)  Slightly modified to for this plugin by M.Fuerstenau. Oce Printing Systems

sub soap_check {   my $output = 'Fatal error: could not connect to the VMWare SOAP API.'; my $state = Vim::get_vim_service; if (defined($state)) {      $state=0; $output = 'Successfully connected to the VMWare SOAP API.'; }   else {      $state=2; }   return ($state, $output); }

sub isblacklisted {   my ($blacklist_ref,$regexpflag,$candidate) = @_; my $ret = 0; my @blacklist; my $blacklist; my $hitcount = 0; if (!defined $$blacklist_ref) {      return 0; }

if ($regexpflag == 0) {      $ret = grep(/$candidate/, $$blacklist_ref); }   else {      @blacklist = split(/,/, $$blacklist_ref);

foreach $blacklist (@blacklist) {              if ($candidate =~ m/$blacklist/) {                 $hitcount++; }              }

if ($hitcount >= 1) {         $ret = 1; }      }    return $ret; }

sub isnotwhitelisted {   my ($whitelist_ref,$regexpflag,$candidate) = @_; my $ret = 0; my @whitelist; my $whitelist; my $hitcount = 0;

if (!defined $$whitelist_ref) {      return $ret; }

if ($regexpflag == 0) {      $ret = ! grep(/$candidate/, $$whitelist_ref); }   else {      @whitelist = split(/,/, $$whitelist_ref);

foreach $whitelist (@whitelist) {              if ($candidate =~ m/$whitelist/) {                 $hitcount++; }              }

if ($hitcount == 0) {         $ret = 1; }      }    return $ret; }

sub get_me_out {   my ($msg) = @_; print "$msg\n"; print "\n"; print_help; exit 2; } sub catch_alarm {   print "UNKNOWN: Script timed out.\n"; exit 3; }
 * 1) The "ejection seat". Display error message and leaves the program.
 * 1) Catching some signals

sub catch_intterm {   print "UNKNOWN: Script killed by monitor.\n"; unlink $sessionlockfile; exit 3; }
 * 1) =====================================================================| Cluster |============================================================================#

sub cluster_cluster_info {       my ($cluster) = @_; my $state = 2; my $output = 'CLUSTER clusterServices Unknown error'; if (defined($subselect)) {               if ($subselect eq "effectivecpu") {                       $values = return_cluster_performance_values($cluster, 'clusterServices', ('effectivecpu.average')); if (defined($values)) {                               my $value = simplify_number(convert_number($$values[0][0]->value) * 0.01); $perfdata = $perfdata. " effective cpu=". $value. "Mhz;". $perf_thresholds. ";;";                               $output = "effective cpu=". $value. "%";                                $state = check_against_threshold($value); }               }                elsif ($subselect eq "effectivemem") {                       $values = return_cluster_performance_values($cluster, 'clusterServices', ('effectivemem.average')); if (defined($values)) {                               my $value = simplify_number(convert_number($$values[0][0]->value) / 1024); $perfdata = $perfdata. " effectivemem=". $value. "MB;". $perf_thresholds. ";;";                               $output = "effective mem=". $value. " MB"; $state = check_against_threshold($value); }               }                elsif ($subselect eq "failover") {                       $values = return_cluster_performance_values($cluster, 'clusterServices', ('failover.latest:*')); if (defined($values)) {                               my $value = simplify_number(convert_number($$values[0][0]->value)); $perfdata = $perfdata. " failover=". $value. ";" . $perf_thresholds. ";;";                               $output = "failover=". $value. " ";                               $state = check_against_threshold($value); }               }                elsif ($subselect eq "cpufairness") {                       $values = return_cluster_performance_values($cluster, 'clusterServices', ('cpufairness.latest')); if (defined($values)) {                               my $value = simplify_number(convert_number($$values[0][0]->value)); $perfdata = $perfdata. " cpufairness=". $value. "%;" . $perf_thresholds. ";;";                               $output = "cpufairness=". $value. "%";                               $state = check_against_threshold($value); }               }                elsif ($subselect eq "memfairness") {                       $values = return_cluster_performance_values($cluster, 'clusterServices', ('memfairness.latest')); if (defined($values)) {                               my $value = simplify_number((convert_number($$values[0][0]->value))); $perfdata = $perfdata. " memfairness=". $value. "%;" . $perf_thresholds. ";;";                               $output = "memfairness=". $value. "%";                               $state = check_against_threshold($value); }               }                else {               get_me_out("Unknown CLUSTER clusterservices subselect"); }       }        else {               $values = return_cluster_performance_values($cluster, 'clusterServices', ('effectivecpu.average', 'effectivemem.average')); if (defined($values)) {                       my $value1 = simplify_number(convert_number($$values[0][0]->value)); my $value2 = simplify_number(convert_number($$values[0][1]->value) / 1024); $perfdata = $perfdata. " effective cpu=". $value1. "Mhz;". $perf_thresholds. ";;";                       $perfdata = $perfdata. " effective mem=". $value2. "MB;". $perf_thresholds. ";;";                       $state = 0; $output = "effective cpu=". $value1. " Mhz, effective Mem=". $value2. " MB"; }       }

return ($state, $output); }

sub cluster_runtime_info {       my ($cluster, $blacklist) = @_;

my $state = 2; my $output = 'CLUSTER RUNTIME Unknown error'; my $runtime; my $cluster_view = Vim::find_entity_view(view_type => 'ClusterComputeResource', filter => { name => "$cluster" }, properties => ['name', 'overallStatus', 'configIssue']);

if (!defined($cluster_view)) {          print "Cluster ". $$cluster{"name"}. " does not exist.\n"; exit 2; }

$cluster_view->update_view_data;

if (defined($subselect)) {               if ($subselect eq "listvms") {                       my %vm_state_strings = ("poweredOn" => "UP", "poweredOff" => "DOWN", "suspended" => "SUSPENDED"); my $vm_views = Vim::find_entity_views(view_type => 'VirtualMachine', begin_entity => $cluster_view, properties => ['name', 'runtime']);

if (!defined($vm_views)) {                          print "Runtime error\n"; exit 2; }

if (!defined($vm_views)) {                          print "There are no VMs.\n"; exit 2; }

my $up = 0; $output = '';

foreach my $vm (@$vm_views) {                               my $vm_state = $vm_state_strings{$vm->runtime->powerState->val}; if ($vm_state eq "UP") {                                       $up++; $output = $output. $vm->name. "(0), ";                               }                                else {                                       $output = $vm->name. "(" . $vm_state . "), ". $output; }                       }

chop($output); chop($output); $state = 0; $output = $up. "/" . @$vm_views. " VMs up: ". $output; $perfdata = $perfdata. " vmcount=". $up. ";" . $perf_thresholds. ";;";

if ( $perf_thresholds eq 1 ) {                          $state = check_against_threshold($up); }               }                elsif ($subselect eq "listhost") {                       my %host_state_strings = ("poweredOn" => "UP", "poweredOff" => "DOWN", "suspended" => "SUSPENDED", "standBy" => "STANDBY", "MaintenanceMode" => "Maintenance Mode"); my $host_views = Vim::find_entity_views(view_type => 'HostSystem', begin_entity => $cluster_view, properties => ['name', 'runtime.powerState']);
 * 1) Reminder: Wie bei host_runtime_info die virtuellen Maschinen als performancedaten ausgeben

if (!defined($host_views)) {                          print "Runtime error\n"; exit 2; }

if (!defined($host_views)) {                          print "There are no hosts.\n" ; exit 2; }

my $up = 0; my $unknown = 0; $output = '';

foreach my $host (@$host_views) { $host->update_view_data(['name', 'runtime.powerState']); my $host_state = $host_state_strings{$host->get_property('runtime.powerState')->val}; $unknown += $host_state eq "3"; if ($host_state eq "UP" && $host_state eq "Maintenance Mode") { $up++; $output = $output. $host->name. "(UP), "; } else {                                       $output = $host->name. "(" . $host_state . "), ". $output; }                       }

chop($output); chop($output); $state = 0; $output = $up. "/" . @$host_views. " Hosts up: ". $output; $perfdata = $perfdata. " vmcount=". $up. ";" . $perf_thresholds. ";;";

if ( $perf_thresholds eq 1 ) {                          $state = check_against_threshold($up); }

$state = 3 if ($state == 0 && $unknown); }               elsif ($subselect eq "status") {                       if (defined($cluster_view->overallStatus)) {                               my $status = $cluster_view->overallStatus->val; $output = "overall status=". $status; $state = check_health_state($status); }                       else {                               $output = "Insufficient rights to access status info on the DC\n"; $state = 1; }               }                elsif ($subselect eq "issues") {                       my $issues = $cluster_view->configIssue; my $issues_count = 0;

$output = ''; if (defined($issues)) {                               foreach (@$issues) {                                       if (defined($blacklist)) {                                               my $name = ref($_); next if ($blacklist =~ m/(^|\s|\t|,)\Q$name\E($|\s|\t|,)/); }                                       $output = $output. format_issue($_). "; ";                                       $issues_count++; }                       }

if ($output eq '') {                               $state = 0; $output = 'No config issues'; }                       $perfdata = $perfdata. " issues=". $issues_count; }               else {               get_me_out("Unknown CLUSTER RUNTIME subselect"); }       }     else {               my %cluster_maintenance_state = (0 => "no", 1 => "yes"); my $vm_views = Vim::find_entity_views(view_type => 'VirtualMachine', begin_entity => $cluster_view, properties => ['name', 'runtime.powerState']); my $up = 0;

if (defined($vm_views)) {                       foreach my $vm (@$vm_views) { $up += $vm->get_property('runtime.powerState')->val eq "poweredOn"; }                       $perfdata = $perfdata. " vmcount=". $up. ";" . $perf_thresholds. ";;";                       $output = $up. "/" . @$vm_views. " VMs up"; }               else {                       $output = "No VMs installed"; }

my $AlertCount = 0; my $SensorCount = 0; my ($cpuStatusInfo, $storageStatusInfo, $memoryStatusInfo, $numericSensorInfo);

$state = 0; $output = $output. ", overall status=". $cluster_view->overallStatus->val. ", " if (defined($cluster_view->overallStatus));

my $issues = $cluster_view->configIssue; if (defined($issues)) {                       $output = $output. @$issues. " config issue(s)"; }               else {                       $output = $output. "no config issues"; }       }

return ($state, $output); }