├── .gitignore ├── LICENSE ├── README ├── README.md ├── nagios_downtime ├── nagios_downtime.conf-sample ├── nagios_downtime.init ├── nagios_downtime.vbs └── nagios_downtime.vbs.conf-sample /.gitignore: -------------------------------------------------------------------------------- 1 | nagios_downtime.conf 2 | nagios_downtime.vbs.conf 3 | .*.swp 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | README.md -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nagios_downtime - Script based downtime scheduling 2 | 3 | nagios_downtime can be used to schedule downtimes directly from monitored 4 | machines to automaticaly schedule downtimes in Nagios only with having access 5 | to the Nagios CGIs or Multisite with having access to the Web API. There is no additional connection needed. 6 | 7 | You can schedule those downtimes automaticaly on system reboot by an init 8 | script. You could also run the script to schedule downtimes for special 9 | services e.g. during backups of databases. nagios_downtime can create a 10 | downtime in Nagios/Multisite before shuting down the database to start the backup (add 11 | mode) and delete the downtime again when the backup is finished (del mode). 12 | 13 | Scheduling downtimes for planned downtimes gives you several advantages: 14 | 15 | * No alerts are raised by planned downtimes 16 | * The unplanned downtime in reporting is not affected by such downtimes 17 | 18 | Currently the nagios_downtime Scripts are shipped for Linux (written in Perl) 19 | and Windows (written in VBS). The intention was to have two scripts for the 20 | different platforms to reach one goal. During time both scripts diverged a 21 | bit. I started development of these scripts back in 2005, so please don't 22 | be too strict with the coding style, I am a bit unhappy with this for myself, 23 | but currently don't have the time to fix this. Maybe I find the time to fix 24 | this one day. You are welcome to send improvements! 25 | 26 | ## Linux (Perl script) 27 | 28 | ### Prerequisites (Perl) 29 | 30 | * Perl 31 | * Perl Modules: 32 | * LWP 33 | * Switch 34 | * Net::Ping 35 | * Sys::Hostname 36 | * Getopt::Long 37 | 38 | ### Usage 39 | 40 | You can use the provided init script to set up a basic downtime scheduling. In 41 | some cases you may need to change the parameter in the init script calls or the 42 | options in the nagios_downtime file to fit your needs. For example the options 43 | for accessing the CGI files will be needed to be changed in most environments. 44 | 45 | You basicaly have two ways to provide the options to the script: 46 | 47 | a) via command line 48 | b) via editing the options in the script 49 | 50 | For details about the single command line parameters please execute this: 51 | 52 | ``` 53 | # nagios_downtime -h 54 | ``` 55 | 56 | You may create a configuration file with the basic parameters like Nagios host, cgi path, cgi user and password 57 | using the options in the nagios_downtime script. This way you don't need to 58 | provide the parameters on each call. 59 | 60 | #### Examples: 61 | ##### OMD with Multisite 62 | This command can be used to schedule a downtime of 15 minutes on a OMD host (`omd.my-domain.com`) with Multisite enabled. The path `/omdsite/check_mk`, the user `automationuser` and its password `automationpassword` will be used to access the API. A host-downtime for the host `webserver.my-domain.com` will be scheduled. 63 | ``` 64 | # nagios_downtime -m add -t 15 -i multisite -S omd.my-domain.com -p /omdsite/check_mk \ 65 | -u automationuser -P automationpassword -H webserver.my-domain.com 66 | ``` 67 | 68 | With this command you can terminate the downtime. You need to have the 69 | saving of the downtime ids enabled. 70 | 71 | ``` 72 | # nagios_downtime -m del -i multisite -S omd.my-domain.com -p /omdsite/check_mk \ 73 | -u nagiosadmin -P nagiosadmin -H webserver.my-domain.com 74 | ``` 75 | ##### Nagios 76 | This command can be used to schedule a downtime of 15 minutes on the nagios 77 | host (`nagios.my-domain.com`). The CGIs are located at `/nagios/cgi-bin`. The 78 | CGIs can be accessed by the user `nagiosadmin` with password `nagiosadmin`. A 79 | host-downtime for the host `webserver.my-domain.com` will be scheduled. 80 | 81 | ``` 82 | # nagios_downtime -m add -t 15 -S nagios.my-domain.com -p /nagios/cgi-bin \ 83 | -u nagiosadmin -P nagiosadmin -H webserver.my-domain.com 84 | ``` 85 | 86 | With this command you can terminate the downtime. You need to have the 87 | saving of the downtime ids enabled. 88 | 89 | ``` 90 | # nagios_downtime -m del -S nagios.my-domain.com -p /nagios/cgi-bin \ 91 | -u nagiosadmin -P nagiosadmin -H webserver.my-domain.com 92 | ``` 93 | 94 | ### Init script installation (Should work on SuSE, RedHat, CentOS, Fedora) 95 | 96 | Copy the file `nagios_downtime` to `/usr/bin`. And make sure it is executable. 97 | 98 | ``` 99 | # cp -p nagios_downtime /usr/bin 100 | # chmod +x /usr/bin/nagios_downtime 101 | ``` 102 | 103 | Copy the init script `nagios_downtime.init` to `/etc/init.d`. Also make sure it is 104 | executable. 105 | 106 | ``` 107 | # cp -p nagios_downtime.init /etc/init.d 108 | # chmod +x /etc/init.d/nagios_downtime.init 109 | ``` 110 | 111 | Activate the init script to be executed on system shutdown. 112 | 113 | ``` 114 | # chkconfig --add nagios_downtime 115 | # chkconfig nagios_downtime on 116 | ``` 117 | 118 | ### Downtime deletion 119 | 120 | The deletion of downtimes is a new feature in nagios_downtime 0.5. 121 | 122 | You need to set the vars `$storeDowntimeIds` and `$downtimePath` in the head of the 123 | nagios_downtime file to be able to use the feature. Once enabled newly 124 | scheduled downtimes can be deleted by calling nagios_downtime in deletion mode 125 | (`-m del`). 126 | 127 | ## Bugs and Support 128 | 129 | I decided to use GitHub for managing project related communication, you 130 | can find the project at (https://github.com/LaMi-/nagios_downtime). 131 | 132 | The nagios_downtime scripts were previously homed on my personal, a bit outdated, blog. 133 | You might find some useful information there in the related articles or commennts 134 | (http://larsmichelsen.com/nagios-downtime/). 135 | 136 | ## Thanks 137 | 138 | Thanks to all supporters of open source software. Keep up the great work! 139 | 140 | ## Licensing 141 | 142 | Copyright (C) 2014 Lars Michelsen 143 | 144 | All outcome of the project is licensed under the terms of the GNU GPL v2. 145 | Take a look at the LICENSE file for details. 146 | -------------------------------------------------------------------------------- /nagios_downtime: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # ############################################################################## 3 | # nagios_downtime 4 | # 5 | # Copyright (c) 2007-2012 Lars Michelsen 6 | # http://larsmichelsen.com 7 | # 8 | # Permission is hereby granted, free of charge, to any person 9 | # obtaining a copy of this software and associated documentation 10 | # files (the "Software"), to deal in the Software without 11 | # restriction, including without limitation the rights to use, 12 | # copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the 14 | # Software is furnished to do so, subject to the following 15 | # conditions: 16 | # 17 | # The above copyright notice and this permission notice shall be 18 | # included in all copies or substantial portions of the Software. 19 | # 20 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | # OTHER DEALINGS IN THE SOFTWARE. 28 | # ############################################################################## 29 | # SCRIPT: nagios_downtime 30 | # AUTHOR: Lars Michelsen 31 | # DECRIPTION: Sends a HTTP(S)-GET to the nagios web server to 32 | # enter a downtime for a host or service. 33 | # CHANGES: 34 | # 2008-05-19 v0.4 - Some code formating 35 | # - The downtime type is now automaticaly detected on given params 36 | # - Changed case of the parameters 37 | # - Added proxy configuration options 38 | # - User Agent is now "nagios_downtime.pl / " 39 | # - Added parameter -S and -p for setting server options via param 40 | # 2009-10-13 v0.5 - Added new "run modes": add (default) and del to schedule 41 | # or remove downtimes 42 | # - Using the del mode the last scheduled downtime will be removed 43 | # - Added the params -u and -P for giving the username and password 44 | # for accessing the CGIs by the command line 45 | # - Several code cleanups 46 | # 2009-11-30 v0.5.1 - Fixed service downtime deletion 47 | # 2010-04-05 v0.6 - Chomping newlines from stored downtimes now 48 | # 2010-06-20 v0.6.1 - Fixed env_proxy calls to LWP object 49 | # - Explicitly unsetting env_proxy when no proxy set 50 | # - Checking for Crypt::SSLeay module to load when https 51 | # url given 52 | # 2012-12-04 v0.7 - Implemented support for setting downtimes via 53 | # JSON API of the Check_MK Multisite GUI 54 | # (only adding downtimes has been tested here, sorry) 55 | # - Restructured configuration parameters 56 | # - Added optional configuration nagios_downtime.conf 57 | # (no need to change this script anymore) 58 | # - LWP instance supports cookie handling now 59 | # - Code cleanups 60 | # 2013-07-31 v0.8 - Deleting of downtimes using multisite works now 61 | # (Needs Check_MK >= 1.2.3i2) 62 | # ############################################################################## 63 | 64 | # ############################################################################## 65 | # Configuration (-> Here you have to set some values!) 66 | # ############################################################################## 67 | use strict; 68 | use warnings; 69 | 70 | # Interface/API to use to set downtimes. Can be set to "nagios" to use the 71 | # default CGI based webinterface or "multisite" to set downtimes via Check_MK 72 | # Multisite 73 | my $type = "nagios"; 74 | 75 | # Protocol for the GET Request, In most cases "http", "https" is also possible 76 | my $webProto = "http"; 77 | # IP or FQDN of Nagios server (example: nagios.domain.de) 78 | my $server = "localhost"; 79 | # IP or FQDN of Nagios web server. In most cases same as $server, if 80 | # empty automaticaly using $server 81 | my $webServer = ""; 82 | # Port of Nagios webserver (If $webProto is set to https, this should be 83 | # SSL Port 443) 84 | my $webPort = 80; 85 | # Web path to Nagios cgi-bin (example: /nagios/cgi-bin) (NO trailing slash!) 86 | # Or if type is multisite, path to multisite (e.g. /check_mk) 87 | my $basePath = "/nagios/cgi-bin"; 88 | 89 | # When your interface is secured by basic authentication, you need to specify 90 | # the following three options. If you want to disable the basic authentication 91 | # support, just leave the password or the authName empty. 92 | # 93 | # User to take for authentication and author to enter the downtime (example: 94 | # nagiosadmin) 95 | my $user = "nagiosadmin"; 96 | # Password for above user. In case of multisite API you need the auth secret 97 | # of the user. 98 | my $userPw = ""; 99 | # Name of authentication realm, set in the Nagios .htaccess file 100 | # (example: "Nagios Access") 101 | my $authName = "Nagios Access"; 102 | 103 | # 104 | # Nagios CGI specific options 105 | # (only needed when $type is set to "nagios") 106 | # 107 | 108 | # Nagios date format (has to be set to the same value as "date_format" in nagios.cfg) 109 | my $nagiosDateFormat = "us"; 110 | 111 | # When you have to use a proxy server for access to the nagios server, set the 112 | # URL here. The proxy will be set for this script for the choosen web protocol 113 | # When this is set to 'env', the proxy settings will be read from the env. 114 | my $proxyAddress = ''; 115 | 116 | # Enable fetching and storing the downtime ids for later downtime removal 117 | # The downtime IDs will be stored in a defined temp directory 118 | my $storeDowntimeIds = 1; 119 | # The script will generate temporary files named (.txt or 120 | # -.txt). The files will contain the script internal 121 | # downtime ids and/or the nagios downtime ids. 122 | # These files are needed for later downtime removal 123 | my $downtimePath = '/tmp'; 124 | 125 | # Some default options (Usualy no changes needed below this) 126 | 127 | # Script internal downtime id for a new downtime 128 | # Using the current timestamp as script internal downtime identifier 129 | my $downtimeId = time; 130 | # Default downtime type (1: Host Downtime, 2: Service Downtime) 131 | my $downtimeType = 1; 132 | # Default Downtime duration in minutes 133 | my $downtimeDuration = 10; 134 | # Default Downtime text 135 | my $downtimeComment = "Perl Downtime-Script"; 136 | # Default Debugmode: off => 0 or on => 1 137 | my $debug = 0; 138 | # Script version 139 | my $version = "0.8"; 140 | 141 | # ############################################################################## 142 | # Don't change anything below, except you know what you are doing. 143 | # ############################################################################## 144 | 145 | use Net::Ping; 146 | use LWP 5.64; 147 | use Sys::Hostname; 148 | use Getopt::Long; 149 | use Switch; 150 | use JSON qw(decode_json); 151 | 152 | my $arg; 153 | my $p; 154 | my $i = 0; 155 | my $oBrowser; 156 | my $oResponse; 157 | my $hostname = ""; 158 | my $service = ""; 159 | my $start; 160 | my $end; 161 | my $url = ""; 162 | my $help = ""; 163 | my $now = time; 164 | my $timezone = "local"; 165 | my $mode = "add"; 166 | 167 | my %urls = ( 168 | nagios => { 169 | host_downtime => "[baseUrl]/cmd.cgi?cmd_typ=55&cmd_mod=2" 170 | ."&host=[hostname]&com_author=[user]&com_data=[comment]" 171 | ."&trigger=0&start_time=[start_time]&end_time=[end_time]" 172 | ."&fixed=1&childoptions=1&btnSubmit=Commit", 173 | service_downtime => "[baseUrl]/cmd.cgi?cmd_typ=56&cmd_mod=2" 174 | ."&host=[hostname]&service=[service]" 175 | ."&com_author=[user]&com_data=[comment]" 176 | ."&trigger=0&start_time=[start_time]&end_time=[end_time]" 177 | ."&fixed=1&btnSubmit=Commit", 178 | del_host_downtime => "[baseUrl]/cmd.cgi?cmd_typ=78&cmd_mod=2&down_id=[downtime_id]&btnSubmit=Commit", 179 | del_service_downtime => "[baseUrl]/cmd.cgi?cmd_typ=79&cmd_mod=2&down_id=[downtime_id]&btnSubmit=Commit", 180 | all_downtimes => "[baseUrl]/extinfo.cgi?type=6", 181 | }, 182 | multisite => { 183 | host_downtime => "[baseUrl]/view.py?output_format=json&_transid=-1&_do_confirm=yes&_do_actions=yes&&_username=[user]&_secret=[password]&view_name=hoststatus&host=[hostname]&_down_comment=[comment]&_down_from_now=yes&_down_minutes=[duration]", 184 | service_downtime => "[baseUrl]/view.py?output_format=json&_transid=-1&_do_confirm=yes&_do_actions=yes&&_username=[user]&_secret=[password]&view_name=service&host=[hostname]&service=[service]&_down_comment=[comment]&_down_from_now=yes&_down_minutes=[duration]", 185 | del_host_downtime => "[baseUrl]/view.py?output_format=json&_transid=-1&_do_confirm=yes&_do_actions=yes&&_username=[user]&_secret=[password]&view_name=api_downtimes&_remove_downtimes=Remove&downtime_id=[downtime_id]", 186 | del_service_downtime => "[baseUrl]/view.py?output_format=json&_transid=-1&_do_confirm=yes&_do_actions=yes&&_username=[user]&_secret=[password]&view_name=api_downtimes&_remove_downtimes=Remove&downtime_id=[downtime_id]", 187 | all_downtimes => "[baseUrl]/view.py?output_format=json&_transid=-1&_do_confirm=yes&_do_actions=yes&&_username=[user]&_secret=[password]&view_name=api_downtimes", 188 | }, 189 | ); 190 | 191 | my %messages = ( 192 | nagios => { 193 | success => "Your command request was successfully submitted to Nagios for processing", 194 | not_authorized => "Sorry, but you are not authorized to commit the specified command.", 195 | no_author => "Author was not entered", 196 | }, 197 | multisite => { 198 | success => "Successfully sent 1 commands", 199 | not_authorized => "Invalid automation secret", 200 | no_author => "TODO", 201 | } 202 | ); 203 | 204 | # Load optional config file to override hardcoded defaults 205 | my @config_files = qw(nagios_downtime.conf /etc/nagios_downtime.conf /usr/local/etc/conf.d/nagios_downtime.conf); 206 | foreach my $config_file ( @config_files ) 207 | { 208 | # load the config file first found 209 | if(-f $config_file) { 210 | local $/=undef; 211 | open IN, $config_file; 212 | eval ; 213 | close IN; 214 | last; 215 | } 216 | } 217 | 218 | # Load command line options to override hardcoded defaults 219 | Getopt::Long::Configure('bundling'); 220 | GetOptions( 221 | "h|help" => \$help, 222 | "d|debug" => \$debug, 223 | "i|interface=s" => \$type, 224 | "m|mode=s" => \$mode, 225 | "H|hostname=s" => \$hostname, 226 | "S|server=s" => \$server, 227 | "p|path=s" => \$basePath, 228 | "u|user=s" => \$user, 229 | "P|password=s" => \$userPw, 230 | "t|downtime=i" => \$downtimeDuration, 231 | "c|comment=s" => \$downtimeComment, 232 | "s|service=s" => \$service 233 | ); 234 | 235 | if($help) { 236 | about(); 237 | exit(0); 238 | } 239 | 240 | if($type ne "nagios" and $type ne "multisite") { 241 | error("Invalid interface type specified."); 242 | } 243 | 244 | # Mode can be add or del, default is "add" 245 | if($mode eq "") { 246 | $mode = "add"; 247 | } 248 | 249 | if(($webProto eq "https" || $webPort eq "443") && !eval "require Crypt::SSLeay") { 250 | error("LWP can not handle SSL urls without Crypt::SLeay module."); 251 | } 252 | 253 | # Get hostname if not set via param 254 | if($hostname eq "") { 255 | $hostname = hostname; 256 | } 257 | 258 | # When no nagios webserver is set the webserver and Nagios should be on the same 259 | # host 260 | if($webServer eq "") { 261 | $webServer = $server; 262 | } 263 | 264 | # When a service name is set, this will be a service downtime 265 | if($service ne "") { 266 | $downtimeType = 2; 267 | } 268 | 269 | # Append the script internal downtime id when id storing is enabled 270 | # The downtime ID is important to identify the just scheduled downtime for 271 | # later removal. The CGIs do not provide the downtime id right after sending 272 | # the schedule request. So it is important to tag the downtime with this. 273 | if($storeDowntimeIds == 1) { 274 | $downtimeComment .= " (ID:".$downtimeId.")"; 275 | } 276 | 277 | # Calculate the start of the downtime 278 | $start = gettime($now); 279 | 280 | # Calculate the end of the downtime 281 | $end = gettime($now+$downtimeDuration*60); 282 | 283 | # Check if web server is reachable via ping, if not, terminate the script 284 | $p = Net::Ping->new("icmp"); 285 | if(!$p->ping($webServer)) { 286 | error("Given Nagios web server \"" . $webServer . "\" not reachable via ping.") 287 | } 288 | 289 | # Initialize the browser 290 | $oBrowser = LWP::UserAgent->new(keep_alive => 1,timeout => 10); 291 | $oBrowser->cookie_jar({}); 292 | $oBrowser->agent("nagios_downtime.pl / " . $version); 293 | 294 | # Set the proxy address depending on the configured option 295 | if($proxyAddress eq 'env') { 296 | $oBrowser->env_proxy(1); 297 | } else { 298 | $oBrowser->env_proxy(0); 299 | $oBrowser->proxy([$webProto], $proxyAddress); 300 | } 301 | 302 | # Only try to auth if auth informations are given 303 | if($authName ne "" && $userPw ne "") { 304 | # Set auth informations 305 | $oBrowser->credentials($webServer.':'.$webPort, $authName, $user => $userPw); 306 | } 307 | 308 | my $baseUrl = $webProto . "://" . $webServer . ":" . $webPort . $basePath; 309 | 310 | # Handle the given action 311 | switch($mode) { 312 | case 'add' { 313 | # Add a new scheduled downtime 314 | # ########################################################################## 315 | 316 | if($downtimeType == 1) { 317 | # Schedule Host Downtime 318 | $url = get_url("host_downtime", { 319 | baseUrl => $baseUrl, 320 | hostname => $hostname, 321 | user => $user, 322 | password => $userPw, 323 | comment => $downtimeComment, 324 | start_time => $start, 325 | end_time => $end, 326 | duration => $downtimeDuration, 327 | }); 328 | } else { 329 | # Schedule Service Downtime 330 | $url = get_url("service_downtime", { 331 | baseUrl => $baseUrl, 332 | hostname => $hostname, 333 | service => $service, 334 | user => $user, 335 | password => $userPw, 336 | comment => $downtimeComment, 337 | start_time => $start, 338 | end_time => $end, 339 | duration => $downtimeDuration, 340 | }); 341 | } 342 | 343 | debug("HTTP-GET: " . $url); 344 | 345 | # Send the get request to the web server 346 | $oResponse = $oBrowser->get($url); 347 | 348 | debug("HTTP-Response: " . $oResponse->content); 349 | 350 | # Handle response code, not in detail, only first char 351 | switch(substr($oResponse->code,0,1)) { 352 | # 2xx response code is OK 353 | case 2 { 354 | # Do some basic handling with the response content 355 | my $content = $oResponse->content; 356 | 357 | switch($content) { 358 | case { index($content, get_msg("success")) != -1 } { 359 | # Save the id of the just scheduled downtime 360 | if($storeDowntimeIds == 1) { 361 | saveDowntimeId(); 362 | } 363 | 364 | success("Downtime was submitted successfully"); 365 | } 366 | case { index($content, get_msg("not_authorized")) != -1 } { 367 | error("Maybe not authorized or wrong hostname or servicename."); 368 | } 369 | case { index($content, get_msg("no_author")) != -1 } { 370 | error("No Author entered, define Author in \$user var."); 371 | } 372 | else { 373 | error("Some undefined error occured, turn debug mode on to view what happened."); 374 | } 375 | } 376 | } 377 | case 3 { 378 | error("HTTP Response code 3xx says \"moved url\" (".$oResponse->code.")"); 379 | } 380 | case 4 { 381 | error("HTTP Response code 4xx says \"client error\" (".$oResponse->code.")\n" 382 | ."Hint: This could be caused by wrong auth credentials and/or datetime settings in this script."); 383 | } 384 | case 5 { 385 | error("HTTP Response code 5xx says \"server error\" (".$oResponse->code.")."); 386 | } 387 | else { 388 | error("HTTP Response code unhandled by script (".$oResponse->code.")."); 389 | } 390 | } 391 | } 392 | case 'del' { 393 | # Delete the last scheduled downtime 394 | # ########################################################################## 395 | 396 | if($storeDowntimeIds != 1) { 397 | error("Unable to remove a downtime. The storingDowntimeIds option is set to disabled."); 398 | } 399 | 400 | # Read all internal downtime ids for this host/service 401 | my @downtimes = sort({ $b <=> $a } @{getDowntimeIds()}); 402 | 403 | # Only proceed when downtimes found 404 | if (0 < scalar @downtimes) { 405 | # Get the nagios downtime id for the last scheduled downtime 406 | my $nagiosDowntimeId = getNagiosDowntimeId($downtimes[0]); 407 | 408 | debug("nagiosDowntimeId: $nagiosDowntimeId (". $downtimes[0] .")"); 409 | if($nagiosDowntimeId ne "") { 410 | deleteDowntime($nagiosDowntimeId); 411 | } 412 | 413 | # Delete internal downtime id from downtime file 414 | # This only gets executed on successfull deleteDowntime() cause the 415 | # function terminates the script on any problem 416 | delDowntimeId($downtimes[0]); 417 | } else { 418 | error("Unable to remove a downtime. No previously scheduled downtime found."); 419 | } 420 | } 421 | else { 422 | error("Unknown mode was set (Available: add, del)."); 423 | } 424 | } 425 | 426 | # Regular end of script 427 | # ############################################################################## 428 | 429 | # ############################################################# 430 | # Subs 431 | # ############################################################# 432 | 433 | sub get_msg { 434 | my ($msg_key) = @_; 435 | return $messages{$type}{$msg_key}; 436 | } 437 | 438 | sub get_url { 439 | my ($url_key, $map) = @_; 440 | my $this_url = $urls{$type}{$url_key}; 441 | my $key; 442 | 443 | foreach $key (sort keys %$map) { 444 | my $tmpTmp = $map->{$key}; 445 | $this_url =~ s/\[$key\]/$tmpTmp/g; 446 | } 447 | 448 | return $this_url; 449 | } 450 | 451 | sub error { 452 | my $msg = shift; 453 | print "ERROR: " . $msg . "\n"; 454 | exit(1); 455 | } 456 | 457 | sub debug { 458 | if($debug) { 459 | my $msg = shift; 460 | print "Debug: " . $msg . "\n"; 461 | } 462 | } 463 | 464 | sub success { 465 | my $msg = shift; 466 | print "OK: " . $msg . "\n"; 467 | exit(0); 468 | } 469 | 470 | sub delDowntimeId { 471 | my $internalId = shift; 472 | 473 | my $file = $downtimePath.'/'; 474 | if($downtimeType == 1) { 475 | $file .= $hostname.'.txt'; 476 | } else { 477 | $file .= $hostname.'-'.$service.'.txt'; 478 | } 479 | 480 | if(-f $file) { 481 | if(open(IN, "<", $file)) { 482 | my @contents = ; 483 | close(IN); 484 | 485 | @contents = grep { !/^$internalId$/i } @contents; 486 | chomp @contents; 487 | 488 | if (0 < scalar @contents) { 489 | if(open(OUT, ">", $file)) { 490 | print OUT @contents; 491 | close OUT; 492 | } 493 | } 494 | } 495 | } 496 | } 497 | 498 | sub getDowntimeIds { 499 | my @arr = (); 500 | 501 | my $file = $downtimePath.'/'; 502 | if($downtimeType == 1) { 503 | $file .= $hostname.'.txt'; 504 | } else { 505 | $file .= $hostname.'-'.$service.'.txt'; 506 | } 507 | 508 | if(-f $file) { 509 | if(open(DAT, "<".$file)) { 510 | while(my $line = ) { 511 | next if $line =~ m/^$/; 512 | 513 | # Do some validation 514 | if($line =~ m/[0-9]+/i) { 515 | chomp($line); 516 | push(@arr, $line); 517 | } 518 | } 519 | 520 | close(DAT); 521 | } else { 522 | error("Could not open temporary file (".$file.")."); 523 | } 524 | } 525 | 526 | return \@arr; 527 | } 528 | 529 | sub saveDowntimeId { 530 | my $file = $downtimePath.'/'; 531 | if($downtimeType == 1) { 532 | $file .= $hostname.'.txt'; 533 | } else { 534 | $file .= $hostname.'-'.$service.'.txt'; 535 | } 536 | 537 | if(open(DAT, ">>".$file)) { 538 | print DAT "\n$downtimeId"; 539 | close(DAT); 540 | } else { 541 | error("Could not write downtime to temporary file (".$file.")."); 542 | } 543 | } 544 | 545 | sub getNagiosDowntimeId { 546 | my $internalId = shift; 547 | 548 | # Get all downtimes 549 | my @aDowntimes = @{getAllDowntimes()}; 550 | 551 | # Filter the just scheduled downtime 552 | for my $i ( 0 .. $#aDowntimes ) { 553 | # Matching by: 554 | # - internal id in comment field 555 | # - triggerId: N/A 556 | if($aDowntimes[$i]{'triggerId'} eq 'N/A' && $aDowntimes[$i]{'comment'} =~ m/\(ID:$internalId\)/) { 557 | 558 | debug("Found matching downtime (Host: ".$aDowntimes[$i]{'host'}.", " 559 | ."Service: ".$aDowntimes[$i]{'service'}.", Entry-Time: ".$aDowntimes[$i]{'entryTime'}.", " 560 | ."Downtime-Id: ".$aDowntimes[$i]{'downtimeId'}.")"); 561 | return $aDowntimes[$i]{'downtimeId'}; 562 | } 563 | } 564 | 565 | return ""; 566 | } 567 | 568 | sub deleteDowntime { 569 | my $nagiosDowntimeId = shift; 570 | 571 | if($downtimeType == 1) { 572 | # Host downtime 573 | $url = get_url("del_host_downtime", { 574 | baseUrl => $baseUrl, 575 | user => $user, 576 | password => $userPw, 577 | downtime_id => $nagiosDowntimeId, 578 | }); 579 | } else { 580 | # Service downtime 581 | $url = get_url("del_service_downtime", { 582 | baseUrl => $baseUrl, 583 | user => $user, 584 | password => $userPw, 585 | downtime_id => $nagiosDowntimeId, 586 | }); 587 | } 588 | 589 | my $oResponse; 590 | 591 | debug("HTTP-GET: " . $url); 592 | 593 | # Send the get request to the web server 594 | $oResponse = $oBrowser->get($url); 595 | 596 | debug("HTTP-Response: " . $oResponse->content); 597 | 598 | # Handle response code, not in detail, only first char 599 | switch(substr($oResponse->code,0,1)) { 600 | # 2xx response code is OK 601 | case 2 { 602 | # Do some basic handling with the response content 603 | switch($oResponse->content) { 604 | case { index($_[0], get_msg("success")) != -1 } { 605 | print "OK: Downtime (ID: ".$nagiosDowntimeId.") has been deleted\n"; 606 | } 607 | case { index($_[0], get_msg("not_authorized")) != -1 } { 608 | error("Maybe not authorized or wrong host- or servicename."); 609 | } 610 | case { index($_[0], get_msg("no_author")) != -1 } { 611 | error("No Author entered, define Author in \$user var."); 612 | } 613 | else { 614 | error("Some undefined error occured, turn debug mode on to view what happened."); 615 | } 616 | } 617 | } 618 | case 3 { 619 | error("HTTP Response code 3xx says \"moved url\" (".$oResponse->code.")."); 620 | } 621 | case 4 { 622 | error("HTTP Response code 4xx says \"client error\" (".$oResponse->code.")." 623 | ."Hint: This could be caused by wrong auth credentials and/or datetime settings in this script."); 624 | } 625 | case 5 { 626 | error("HTTP Response code 5xx says \"server error\" (".$oResponse->code.")."); 627 | } 628 | else { 629 | error("HTTP Response code unhandled by script (".$oResponse->code.")."); 630 | } 631 | } 632 | } 633 | 634 | sub getAllDowntimes { 635 | my @arr = (); 636 | my $url; 637 | my $oResponse; 638 | 639 | # Url to downtime page 640 | $url = get_url("all_downtimes", { 641 | baseUrl => $baseUrl, 642 | user => $user, 643 | password => $userPw, 644 | }); 645 | 646 | debug("HTTP-GET: " . $url); 647 | 648 | # Fetch information via HTTP-GET 649 | $oResponse = $oBrowser->get($url); 650 | 651 | debug("HTTP-Response: " . $oResponse->content); 652 | 653 | # Parse all downtimes to an array 654 | if ($type eq 'nagios') { 655 | my $lineType = ''; 656 | foreach my $line (split(/\n/, $oResponse->content)) { 657 | # Filter only downtime lines 658 | if($line =~ m/CLASS=\'downtime(Odd|Even)\'/) { 659 | my $lineType = 'downtime' . $1; 660 | if($line =~ m/[^<]+<\/A><\/td>([^<]+)<\/td>([^<]+)<\/td>([^<]+)<\/td>([^<]+)<\/td>([^<]+)<\/td>([^<]+)<\/td>([^<]+)<\/td>([^<]+)<\/td>([^<]+)<\/td>/i) { 661 | debug("Found host downtime:\n" 662 | ."Host: ".$1." EntryTime: ".$2." User: ".$3 663 | ." Comment: ".$4." Start: ".$5." End: ".$6 664 | ." Type: ".$7." Duration: ".$8." DowntimeID: ".$9 665 | ." TriggerID: ".$10); 666 | 667 | push @arr, { host => $1, service => '', entryTime => $2, user => $3, comment => $4, start => $5, end => $6, type => $7, duration => $8, downtimeId => $9, triggerId => $10 }; 668 | } elsif($line =~ m/[^<]+<\/A><\/td>[^<]+<\/A><\/td>([^<]+)<\/td>([^<]+)<\/td>([^<]+)<\/td>([^<]+)<\/td>([^<]+)<\/td>([^<]+)<\/td>([^<]+)<\/td>([^<]+)<\/td>([^<]+)<\/td>/i) { 669 | 670 | debug("Found service downtime:\n" 671 | ."Host: ".$1." Service: ".$2." EntryTime: ".$3 672 | ." User: ".$4." Comment: ".$5." Start: ".$6 673 | ." End: ".$7." Type: ".$8." Duration: ".$9 674 | ." DowntimeID: ".$10." TriggerID: ".$11); 675 | 676 | push @arr, { host => $1, service => $2, entryTime => $3, user => $4, comment => $5, start => $6, end => $7, type => $8, duration => $9, downtimeId => $10, triggerId => $11 }; 677 | } 678 | } 679 | } 680 | } elsif ($type eq 'multisite') { 681 | my @downtimes = @{decode_json($oResponse->content)}; 682 | my @header = @{ shift(@downtimes) }; # remove the header 683 | 684 | # header2index map 685 | my %h2i; 686 | for my $idx (0 .. $#header) { 687 | $h2i{ ${header[$idx]} } = $idx; 688 | } 689 | 690 | foreach my $row (@downtimes) { 691 | my @row = @{$row}; 692 | 693 | push @arr, { 694 | host => $row[ $h2i{host} ], 695 | service => $row[ $h2i{service_description} ], 696 | entryTime => $row[ $h2i{downtime_entry_time} ], 697 | user => $row[ $h2i{downtime_author} ], 698 | comment => $row[ $h2i{downtime_comment} ], 699 | start => $row[ $h2i{downtime_start_time} ], 700 | end => $row[ $h2i{downtime_end_time} ], 701 | type => $row[ $h2i{downtime_fixed} ], 702 | duration => $row[ $h2i{downtime_duration} ], 703 | downtimeId => $row[ $h2i{downtime_id} ], 704 | origin => $row[ $h2i{downtime_origin} || 0 ], 705 | recurring => $row[ $h2i{downtime_recurring} || 0 ], 706 | triggerId => 'N/A', 707 | }; 708 | 709 | if (scalar(@row) < 10) { 710 | error("The \"downtime_id\" field is missing in the \"downtime\" view. Please add it as last field."); 711 | } 712 | } 713 | } 714 | 715 | # return array of hashes 716 | return \@arr; 717 | } 718 | 719 | sub about { 720 | print <<'ABOUT'; 721 | Usage: 722 | nagios_downtime [-i ] [-m add] [-H ] [-s ] 723 | [-t ] [-S ] [-p ] 724 | [-u ] [-p ] [-d] 725 | nagios_downtime -m del [-i ] [-H ] [-s ] 726 | [-S ] [-p ] [-u ] 727 | [-p ] [-d] 728 | nagios_downtime -h 729 | 730 | Nagios Downtime Script by Lars Michelsen 731 | Sends a HTTP(S) request to the nagios cgis to add a downtime for a host or 732 | service. Since version 0.5 the script can remove downtimes too when being 733 | called in "del" mode. 734 | 735 | Parameters: 736 | -i, --interface Type of interface to be used to set downtimes (nagios or 737 | multisite). Defaults to nagios. If OMD with Multisite or Check_MK is used set to multisite. 738 | 739 | -m, --mode Mode to run the script in (Available: add, del) 740 | 741 | -H, --hostname Name of the host the downtime should be scheduled for. 742 | Important: The name must be same as in Nagios. 743 | -s, --service Name of the service the downtime should be scheduled for. 744 | Important: The name must be same as in Nagios. 745 | When empty or not set a host downtime is being submited. 746 | -t, --downtime Duration of the fixed downtime in minutes 747 | -c, --comment Comment for the downtime 748 | 749 | -S, --server Nagios Webserver address (IP or DNS) 750 | -p, --path Web path to API url. In case of nagios interface, the 751 | path to the Nagios cgi-bin (Default: /nagios/cgi-bin). 752 | In case of multisite API this path should point to 753 | the base path of multisite (e.g. /check_mk or /omdsite/check_mk) 754 | -u, --user Username to be used for accessing the API 755 | -P, --password Password for accessing the API 756 | 757 | -d, --debug Enable debug mode 758 | -h, --help Show this message 759 | 760 | If you call nagios_downtime without parameters the script takes the default options which are 761 | hardcoded in the script. 762 | 763 | ABOUT 764 | } 765 | 766 | sub gettime { 767 | my $timestamp; 768 | $timestamp = shift; 769 | 770 | if($timestamp eq "") { 771 | $timestamp = time; 772 | } 773 | 774 | my ($sec,$min,$hour,$mday,$month,$year,$wday,$yday,$isdst) = localtime($timestamp); 775 | # correct values 776 | $year += 1900; 777 | $month += 1; 778 | 779 | # add leading 0 to values lower than 10 780 | $month = $month < 10 ? $month = "0".$month : $month; 781 | $mday = $mday < 10 ? $mday = "0".$mday : $mday; 782 | $hour = $hour < 10 ? $hour = "0".$hour : $hour; 783 | $min = $min < 10 ? $min = "0".$min : $min; 784 | $sec = $sec < 10 ? $sec = "0".$sec : $sec; 785 | 786 | switch ($nagiosDateFormat) { 787 | case "euro" { 788 | return $mday."-".$month."-".$year." ".$hour.":".$min.":".$sec; 789 | } 790 | case "us" { 791 | return $month."-".$mday."-".$year." ".$hour.":".$min.":".$sec; 792 | } 793 | case "iso8601" { 794 | return $year."-".$month."-".$mday." ".$hour.":".$min.":".$sec; 795 | } 796 | case "strict-iso8601" { 797 | return $year."-".$month."-".$mday."T".$hour.":".$min.":".$sec; 798 | } 799 | else { 800 | error("No valid date format given in \$nagiosDateFormat"); 801 | } 802 | } 803 | } 804 | 805 | # ############################################################# 806 | # EOF 807 | # ############################################################# 808 | -------------------------------------------------------------------------------- /nagios_downtime.conf-sample: -------------------------------------------------------------------------------- 1 | $type = "multisite"; 2 | $server = "monitoring-host.local"; 3 | $basePath = "/sysmon/check_mk"; 4 | 5 | $user = "svc-downtime"; 6 | $userPw = "test-password"; 7 | 8 | $hostname = hostname; 9 | -------------------------------------------------------------------------------- /nagios_downtime.init: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright (c) 2008-2009 Lars Michelsen 3 | # All rights reserved. 4 | # 5 | # Author: Lars Michelsen 6 | # 7 | # chkconfig: 345 99 01 8 | # description: Schedules a downtime in Nagios 9 | # 10 | ### BEGIN INIT INFO 11 | # Provides: nagios_downtime 12 | # Required-Start: $network 13 | # Required-Stop: 14 | # Default-Start: 3 4 5 15 | # Default-Stop: 0 1 2 6 16 | # Short-Description: nagios_downtime schedules a downtime to Nagios 17 | # Description: The nagios_downtime script schedules a downtime 18 | # to the specified Nagios host. The downtime script needs HTTP-access 19 | # to the Nagios cmd.cgi to be able to post a downtime. 20 | ### END INIT INFO 21 | 22 | BAR_BIN=/usr/bin/nagios_downtime 23 | #BAR_BIN=./nagios_downtime 24 | 25 | # Source function library, for e.g. echo_success or echo_failure 26 | if [ -f /etc/rc.d/init.d/functions ]; then 27 | . /etc/rc.d/init.d/functions 28 | else 29 | echo_success() { 30 | return 0 31 | } 32 | echo_failure() { 33 | return 1 34 | } 35 | fi 36 | 37 | # Check for missing binaries 38 | test -x $BAR_BIN || { 39 | echo "$BAR_BIN not installed"; 40 | if [ "$1" = "stop" ]; then 41 | exit 0; 42 | else 43 | exit 5; 44 | fi; 45 | } 46 | 47 | case "$1" in 48 | stop) 49 | echo -n "Scheduling Nagios downtime (nagios_downtime)... " 50 | $BAR_BIN 51 | 52 | if [ $? -eq 0 ]; then 53 | if [ -f /var/lock/subsys/nagios_downtime ]; then 54 | rm -f /var/lock/subsys/nagios_downtime 55 | fi 56 | echo_success 57 | echo "done." 58 | exit 0 59 | else 60 | if [ -f /var/lock/subsys/nagios_downtime ]; then 61 | rm -f /var/lock/subsys/nagios_downtime 62 | fi 63 | echo_failure 64 | echo "ERROR" 65 | exit 1 66 | fi 67 | ;; 68 | start) 69 | echo -n "Removing Nagios downtime (nagios_downtime)... " 70 | $BAR_BIN -m del 71 | 72 | if [ $? -eq 0 ]; then 73 | if [ -d /var/lock/subsys ]; then 74 | touch /var/lock/subsys/nagios_downtime 75 | fi 76 | echo_success 77 | echo "done." 78 | exit 0 79 | else 80 | if [ -d /var/lock/subsys ]; then 81 | touch /var/lock/subsys/nagios_downtime 82 | fi 83 | echo_failure 84 | echo "ERROR" 85 | exit 1 86 | fi 87 | ;; 88 | status) 89 | echo -n "Script only running while start or stop the System..." 90 | ;; 91 | *) 92 | # If no parameters are given, print which are avaiable 93 | echo "Usage: $0 {stop|start}" 94 | exit 1 95 | ;; 96 | esac 97 | -------------------------------------------------------------------------------- /nagios_downtime.vbs: -------------------------------------------------------------------------------- 1 | ' ############################################################################## 2 | ' nagios_downtime.vbs 3 | ' 4 | ' Copyright (c) 2005-2015 Lars Michelsen 5 | ' http://larsmichelsen.com/ 6 | ' 7 | ' Permission is hereby granted, free of charge, to any person 8 | ' obtaining a copy of this software and associated documentation 9 | ' files (the "Software"), to deal in the Software without 10 | ' restriction, including without limitation the rights to use, 11 | ' copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | ' copies of the Software, and to permit persons to whom the 13 | ' Software is furnished to do so, subject to the following 14 | ' conditions: 15 | ' 16 | ' The above copyright notice and this permission notice shall be 17 | ' included in all copies or substantial portions of the Software. 18 | ' 19 | ' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | ' EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 | ' OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | ' NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 | ' HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 | ' WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | ' FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 | ' OTHER DEALINGS IN THE SOFTWARE. 27 | ' ############################################################################## 28 | ' SCRIPT: nagios_downtime 29 | ' AUTHOR: Lars Michelsen 30 | ' DECRIPTION: Sends a HTTP(S)-GET to the nagios web server to 31 | ' enter a downtime for a host or service. 32 | ' CHANGES: 33 | ' 2005-07-11 v0.1 First creation of the script 34 | ' | 35 | ' | 36 | ' changes not tracked in details 37 | ' | 38 | ' V 39 | ' 2006-03-22 v0.6 - Added basic auth support 40 | ' - Several doc changes 41 | ' 42 | ' 2009-10-20 v0.7 - Complete recode according to current perl script 43 | ' - Reworked command line parameters 44 | ' - Script can handle different Nagios date formats now 45 | ' - Script can now delete downtimes when downtime id has been 46 | ' saved while scheduling the downtime before 47 | ' 48 | ' 2009-11-04 v0.8 - Default http/https ports are not added to the url anymore 49 | ' - Added option to ignore certificate problems 50 | ' - Fixed problem deleting service downtimes 51 | ' 52 | ' 2010-12-02 v0.8.1 - Fixed / in to \ in path definitions (Thx Ronny Bunke) 53 | ' - Modify Messages for Icinga (Thx Ronny Bunke) 54 | ' 55 | ' 2011-01-26 v0.8.2 - Applied changes to better handle nagios response texts. 56 | ' Might fix a problem with deleting downtims (Thx Rob Sampson) 57 | ' 2012-03-14 v0.8.3 Big thanks to Olaf Morgenstern for the following points: 58 | ' - Added the logEvt procedure to write messages to the 59 | ' Windows eventlog 60 | ' - Added the -e switch to enable Windows event logging 61 | ' - Added logEvt calls for relevant Wscript.echo's 62 | ' - Better handling of expired downtimes: If the downtime was 63 | ' not found on the nagios server, delete it from the local 64 | ' downtime ID savefile. To prevent from deleting downtimes 65 | ' on nagios server errors, the procedure getNagiosDowntimeId 66 | ' was changed to exit the script on errors. 67 | ' - Added the cleanupDowntimeIds procedure to cleanup the 68 | ' internal downtime ID savefile 69 | ' - Added an additional "clean" mode 70 | ' - Reindented code to 4 spaces for each level 71 | ' 2012-03-22 v0.8.4 Again thanks to Olaf Morgenstern for improving the script 72 | ' - Added clean mode to some remarks and an error message 73 | ' - Changed about() function to show "cscript WScript.ScriptName" 74 | ' - Corrected indenting of one line 75 | ' - In del mode, print more details if downtime could not be 76 | ' found on nagios server 77 | ' 2012-12-05 v0.9 - Added support for scheduling downtimes via the JSON API of 78 | ' Check_MK Multisite 79 | ' - Internal recode of variables 80 | ' 2013-07-31 v0.10 - Added support for deleting downtimes via Check_MK multisite 81 | ' 2015-08-25 v0.11 - Fixed downtime deletion with Check_MK newer than 1.2.7 82 | ' ############################################################################## 83 | 84 | Option Explicit 85 | 86 | Dim ty, webProto, server, webServer, webPort, basePath 87 | Dim user, userPw, authName, nagiosDateFormat, proxyAddress 88 | Dim storeDowntimeIds, downtimePath, downtimeId, downtimeType, downtimeDuration 89 | Dim downtimeComment, debug, version, ignoreCertProblems, evtlog 90 | 91 | ' ############################################################################## 92 | ' Configuration (-> Here you have to set some values!) 93 | ' ############################################################################## 94 | 95 | ' Interface/API to use to set downtimes. Can be set to "nagios" to use the 96 | ' default CGI based webinterface or "multisite" to set downtimes via Check_MK 97 | ' Multisite 98 | ty = "nagios" 99 | 100 | ' Protocol for the GET Request, In most cases "http", "https" is also possible 101 | webProto = "http" 102 | ' IP or FQDN of Nagios server (example: nagios.domain.de) 103 | server = "localhost" 104 | ' IP or FQDN of Nagios web server. In most cases same as $server, if 105 | ' empty automaticaly using $server 106 | webServer = "" 107 | ' Port of Nagios webserver 108 | ' This option is only being recognized when it is not the default port for the 109 | ' choosen protocol in "webProto" option 110 | webPort = 80 111 | ' Web path to Nagios cgi-bin (example: /nagios/cgi-bin) (NO trailing slash!) 112 | ' In case of Icinga this would be "/icinga/cgi-bin" by default 113 | ' Or if type is multisite, path to multisite (e.g. /check_mk) 114 | basePath = "/nagios/cgi-bin" 115 | 116 | ' User to take for authentication and author to enter the downtime (example: 117 | ' nagiosadmin). In case of Icinga this would be "icingaadmin" by default 118 | user = "nagiosadmin" 119 | ' Password for above user 120 | userPw = "nagiosadmin" 121 | ' Name of authentication realm, set in the Nagios .htaccess file 122 | ' (example: "Nagios Access") 123 | authName = "Nagios Access" 124 | 125 | ' 126 | ' Nagios CGI specific options 127 | ' (only needed when $ty is set to "nagios") 128 | ' 129 | ' Nagios date format (same like set in value "date_format" in nagios.cfg) 130 | nagiosDateFormat = "us" 131 | 132 | ' When you have to use a proxy server for access to the nagios server, set the 133 | ' URL here. The proxy will be set for this script for the choosen web protocol 134 | ' When this is set to 'env', the proxy settings will be read from IE settings 135 | ' When this is set to '', the script will use a direct connection 136 | proxyAddress = "" 137 | ' When using ssl it may be ok for you to ignore untrusted/expired certificats 138 | ' Setting this to 1 all ssl certificate related problems should be ignored 139 | ignoreCertProblems = 0 140 | 141 | ' Enable fetching and storing the downtime ids for later downtime removal 142 | ' The downtime IDs will be stored in a defined temp directory 143 | storeDowntimeIds = 1 144 | ' The script will generate temporary files named (.txt or 145 | ' -.txt). The files will contain the script internal 146 | ' downtime ids and/or the nagios downtime ids. 147 | ' These files are needed for later downtime removal 148 | downtimePath = "%temp%" 149 | 150 | ' Some default options (Usualy no changes needed below this) 151 | 152 | ' Script internal downtime id for a new downtime 153 | ' Using the current timestamp as script internal downtime identifier 154 | ' Not important to have the real timestamp but having a uniq counter 155 | ' which increases 156 | downtimeId = CLng(DateDiff("s", "01/01/1970 00:00:00", Now) - 3600) 157 | ' Default downtime type (1: Host Downtime, 2: Service Downtime) 158 | downtimeType = 1 159 | ' Default Downtime duration in minutes 160 | downtimeDuration = 10 161 | ' Default Downtime text 162 | downtimeComment = "Downtime-Script" 163 | ' Default mode for Windows event logging: off => 0 or on => 1 164 | evtlog = 0 165 | ' Default Debugmode: off => 0 or on => 1 166 | debug = 0 167 | ' Script version 168 | version = "0.10" 169 | 170 | ' ############################################################################## 171 | ' Don't change anything below, except you know what you are doing. 172 | ' ############################################################################## 173 | 174 | Dim arg, p, i, oBrowser, oResponse, hostname, service, timeStart, timeEnd, url 175 | Dim help, timeNow, timezone, mode, oFs, oFile, oNetwork, oShell, baseUrl, params 176 | 177 | Const HTTPREQUEST_PROXYSETTING_PRECONFIG = 0 178 | Const HTTPREQUEST_PROXYSETTING_DIRECT = 1 179 | Const HTTPREQUEST_PROXYSETTING_PROXY = 2 180 | Const FOR_READING = 1 181 | Const FOR_WRITING = 2 182 | Const FOR_APPENDING = 8 183 | Const CREATE_IF_NOT_EXISTS = True 184 | Const HTTPREQUEST_SSLERROR_IGNORE_FLAG = 4 185 | Const HTTPREQUEST_SECURITY_IGNORE_ALL = 13056 186 | 187 | ' Constants for type of event log entry 188 | const EVENTLOG_SUCCESS = 0 189 | const EVENTLOG_ERROR = 1 190 | const EVENTLOG_WARNING = 2 191 | const EVENTLOG_INFORMATION = 4 192 | const EVENTLOG_AUDIT_SUCCESS = 8 193 | const EVENTLOG_AUDIT_FAILURE = 16 194 | 195 | Set oShell = CreateObject("WScript.Shell") 196 | Set oFS = CreateObject("Scripting.FilesystemObject") 197 | 198 | hostname = "" 199 | service = "" 200 | url = "" 201 | timeNow = Now 202 | timezone = "local" 203 | mode = "add" 204 | help = 0 205 | 206 | Dim urls 207 | Set urls = CreateObject("Scripting.Dictionary") 208 | urls.Add "nagios", CreateObject("Scripting.Dictionary") 209 | urls.Item("nagios").Add "host_downtime", "[baseUrl]/cmd.cgi?cmd_typ=55&cmd_mod=2" & _ 210 | "&host=[hostname]&com_author=[user]&com_data=[comment]" & _ 211 | "&trigger=0&start_time=[start_time]&end_time=[end_time]" & _ 212 | "&fixed=1&childoptions=1&btnSubmit=Commit" 213 | urls.Item("nagios").Add "service_downtime", "[baseUrl]/cmd.cgi?cmd_typ=56&cmd_mod=2" & _ 214 | "&host=[hostname]&service=[service]" & _ 215 | "&com_author=[user]&com_data=[comment]" & _ 216 | "&trigger=0&start_time=[start_time]&end_time=[end_time]" & _ 217 | "&fixed=1&btnSubmit=Commit" 218 | urls.Item("nagios").Add "del_host_downtime", "[baseUrl]/cmd.cgi?cmd_typ=78&cmd_mod=2&down_id=[downtime_id]&btnSubmit=Commit" 219 | urls.Item("nagios").Add "del_service_downtime", "[baseUrl]/cmd.cgi?cmd_typ=79&cmd_mod=2&down_id=[downtime_id]&btnSubmit=Commit" 220 | urls.Item("nagios").Add "all_downtimes", "[baseUrl]/extinfo.cgi?type=6" 221 | 222 | urls.Add "multisite", CreateObject("Scripting.Dictionary") 223 | urls.Item("multisite").Add "host_downtime", "[baseUrl]/view.py?output_format=json&_transid=-1&" & _ 224 | "_do_confirm=yes&_do_actions=yes&_username=[user]&_secret=[password]&" & _ 225 | "view_name=hoststatus&host=[hostname]&_down_comment=[comment]&" & _ 226 | "_down_from_now=yes&_down_minutes=[duration]" 227 | urls.Item("multisite").Add "service_downtime", "[baseUrl]/view.py?output_format=json&_transid=-1&" & _ 228 | "_do_confirm=yes&_do_actions=yes&_username=[user]&_secret=[password]&" & _ 229 | "view_name=service&host=[hostname]&service=[service]&" & _ 230 | "_down_comment=[comment]&_down_from_now=yes&_down_minutes=[duration]" 231 | urls.Item("multisite").Add "del_host_downtime", "[baseUrl]/view.py?output_format=json&_transid=-1" & _ 232 | "&_do_confirm=yes&_do_actions=yes&_username=[user]&_secret=[password]" & _ 233 | "&view_name=api_downtimes&_remove_downtimes=Remove&downtime_id=[downtime_id]" 234 | urls.Item("multisite").Add "del_service_downtime", "[baseUrl]/view.py?output_format=json&_transid=-1" & _ 235 | "&_do_confirm=yes&_do_actions=yes&_username=[user]&_secret=[password]" & _ 236 | "&view_name=api_downtimes&_remove_downtimes=Remove&downtime_id=[downtime_id]" 237 | urls.Item("multisite").Add "all_downtimes", "[baseUrl]/view.py?output_format=json&_transid=-1" & _ 238 | "&_do_confirm=yes&_do_actions=yes&_username=[user]&_secret=[password]" & _ 239 | "&view_name=api_downtimes" 240 | 241 | Dim messages 242 | Set messages = CreateObject("Scripting.Dictionary") 243 | messages.Add "nagios", CreateObject("Scripting.Dictionary") 244 | messages.Item("nagios").Add "success", "Your command request was successfully submitted to Nagios for processing" 245 | messages.Item("nagios").Add "not_authorized", "Sorry, but you are not authorized to commit the specified command." 246 | messages.Item("nagios").Add "no_author", "Author was not entered" 247 | 248 | messages.Add "multisite", CreateObject("Scripting.Dictionary") 249 | messages.Item("multisite").Add "success", "Successfully sent 1 commands" 250 | messages.Item("multisite").Add "not_authorized", "Invalid automation secret" 251 | messages.Item("multisite").Add "no_author", "TODO" 252 | 253 | ' Read all params 254 | i = 0 255 | Do While i < Wscript.Arguments.Count 256 | If WScript.Arguments(i) = "/H" or WScript.Arguments(i) = "-H" or UCase(WScript.Arguments(i)) = "-HOSTNAME" or UCase(WScript.Arguments(i)) = "/HOSTNAME" then 257 | ' Hostname: /H, /hostname, -H, -hostname 258 | i = i + 1 259 | 260 | If i < Wscript.Arguments.Count Then 261 | hostname = WScript.Arguments(i) 262 | Else 263 | err "No hostname given" 264 | End If 265 | ElseIf WScript.Arguments(i) = "/i" or WScript.Arguments(i) = "-i" or UCase(WScript.Arguments(i) = "-INTERFACE") or UCase(WScript.Arguments(i)) = "/INTERFACE" then 266 | ' Type: /i, /interface, -i, -interface 267 | i = i + 1 268 | 269 | ty = WScript.Arguments(i) 270 | 271 | ElseIf WScript.Arguments(i) = "/m" or WScript.Arguments(i) = "-m" or UCase(WScript.Arguments(i) = "-MODE") or UCase(WScript.Arguments(i)) = "/MODE" then 272 | ' Mode: /m, /mode, -m, -mode 273 | i = i + 1 274 | 275 | mode = WScript.Arguments(i) 276 | ElseIf WScript.Arguments(i) = "/S" or WScript.Arguments(i) = "-S" or UCase(WScript.Arguments(i)) = "/SERVER" or UCase(WScript.Arguments(i)) = "-SERVER" then 277 | ' Nagios Server: /S, /server, -S, -server 278 | i = i + 1 279 | 280 | server = WScript.Arguments(i) 281 | ElseIf WScript.Arguments(i) = "/p" or WScript.Arguments(i) = "-p" or UCase(WScript.Arguments(i)) = "/PATH" or UCase(WScript.Arguments(i)) = "-PATH" then 282 | ' Nagios CGI Path: /p, /path, -p, -path 283 | i = i + 1 284 | 285 | basePath = WScript.Arguments(i) 286 | ElseIf WScript.Arguments(i) = "/u" or WScript.Arguments(i) = "-u" or UCase(WScript.Arguments(i)) = "/USER" or UCase(WScript.Arguments(i)) = "-USER" then 287 | ' Nagios User: /u, /user, -u, -user 288 | i = i + 1 289 | 290 | user = WScript.Arguments(i) 291 | ElseIf WScript.Arguments(i) = "/P" or WScript.Arguments(i) = "-P" or UCase(WScript.Arguments(i)) = "/PASSWORD" or UCase(WScript.Arguments(i)) = "-PASSWORD" then 292 | ' Nagios Password: /P, /password, -P, -password 293 | i = i + 1 294 | 295 | userPw = WScript.Arguments(i) 296 | ElseIf WScript.Arguments(i) = "/s" or WScript.Arguments(i) = "-s" or UCase(WScript.Arguments(i)) = "/SERVICE" or UCase(WScript.Arguments(i)) = "-SERVICE" then 297 | ' Servicename: /s, /service, -s, -service 298 | i = i + 1 299 | 300 | service = WScript.Arguments(i) 301 | ElseIf WScript.Arguments(i) = "/t" or WScript.Arguments(i) = "-t" or UCase(WScript.Arguments(i)) = "/DOWNTIME" or UCase(WScript.Arguments(i)) = "-DOWNTIME" Then 302 | ' downtime duration: /t, /downtime, -t, -downtime 303 | i = i + 1 304 | 305 | downtimeDuration = WScript.Arguments(i) 306 | ElseIf WScript.Arguments(i) = "/c" or WScript.Arguments(i) = "-c" or UCase(WScript.Arguments(i)) = "/COMMENT" or UCase(WScript.Arguments(i)) = "-COMMENT" Then 307 | ' downtime comment: /c, /comment, -c, -comment 308 | i = i + 1 309 | 310 | downtimeComment = WScript.Arguments(i) 311 | 312 | ElseIf UCase(WScript.Arguments(i)) = "/E" or UCase(WScript.Arguments(i)) = "-E" or UCase(WScript.Arguments(i)) = "/EVTLOG" or UCase(WScript.Arguments(i)) = "-EVTLOG" Then 313 | ' log to Window event log: /e, -e, /evtlog, -evtlog 314 | evtlog = 1 315 | 316 | ElseIf UCase(WScript.Arguments(i)) = "/D" or UCase(WScript.Arguments(i)) = "-D" or UCase(WScript.Arguments(i)) = "/DEBUG" or UCase(WScript.Arguments(i)) = "-DEBUG" Then 317 | ' debug mode: /d, -d, /debug, -debug 318 | debug = 1 319 | ElseIf WScript.Arguments(i) = "/?" or WScript.Arguments(i) = "-?" or WScript.Arguments(i) = "/h" or WScript.Arguments(i) = "-h" or WScript.Arguments(i) = "-help" or WScript.Arguments(i) = "/help" Then 320 | ' help: /?, /h, /help, -?, -h, -help 321 | help = 1 322 | Else 323 | ' .... 324 | End If 325 | 326 | i = i + 1 327 | Loop 328 | 329 | ' Read optional config 330 | If oFS.FileExists("nagios_downtime.vbs.conf") Then 331 | ExecuteGlobal(oFS.OpenTextFile("nagios_downtime.vbs.conf").ReadAll()) 332 | End If 333 | 334 | If help = 1 Then 335 | Call about() 336 | WScript.Quit(1) 337 | End If 338 | 339 | ' Mode can be add, del or clean, default is "add" 340 | If mode = "" Then 341 | mode = "add" 342 | End If 343 | 344 | ' Get hostname if not set via param 345 | If hostname = "" Then 346 | ' Read the hostname 347 | Set oNetwork = WScript.CreateObject("WScript.Network") 348 | hostname = LCase(oNetwork.ComputerName) 349 | End If 350 | 351 | ' When no nagios webserver is set the webserver and Nagios should be on the same 352 | ' host 353 | If webServer = "" Then 354 | webServer = server 355 | End If 356 | 357 | ' When a service name is set, this will be a service downtime 358 | If service <> "" Then 359 | downtimeType = 2 360 | End If 361 | 362 | ' Initialize the port to be added to the url. If default http port (80) or 363 | ' default ssl port don't add anything 364 | If webProto = "http" And webPort = 80 Then 365 | webPort = "" 366 | ElseIf webProto = "https" And webPort <> 443 Then 367 | webPort = "" 368 | Else 369 | webPort = ":" & webPort 370 | End If 371 | 372 | ' Append the script internal downtime id when id storing is enabled 373 | ' The downtime ID is important to identify the just scheduled downtime for 374 | ' later removal. The CGIs do not provide the downtime id right after sending 375 | ' the schedule request. So it is important to tag the downtime with this. 376 | If storeDowntimeIds = 1 Then 377 | downtimeComment = downtimeComment & " (ID:" & downtimeId & ")" 378 | End If 379 | 380 | ' Expand the environment string in downtime path 381 | If storeDowntimeIds = 1 Then 382 | downtimePath = oShell.ExpandEnvironmentStrings(downtimePath) 383 | End If 384 | 385 | ' Calculate the start of the downtime 386 | timeStart = gettime(timeNow) 387 | 388 | ' Calculate the end of the downtime 389 | timeEnd = gettime(DateAdd("n", downtimeDuration, timeNow)) 390 | 391 | ' Check if Nagios web server is reachable via ping, if not, terminate the script 392 | If PingTest(webServer) Then 393 | err "Given Nagios web server """ & webServer & """ not reachable via ping!" 394 | End If 395 | 396 | ' Initialize the browser 397 | Set oBrowser = CreateObject("WinHttp.WinHttpRequest.5.1") 398 | 399 | ' Set the proxy address depending on the configured option 400 | If proxyAddress = "env" Then 401 | oBrowser.SetProxy HTTPREQUEST_PROXYSETTING_PRECONFIG 402 | dbg "Proxy-Mode: Env (" & HTTPREQUEST_PROXYSETTING_PRECONFIG & ")" 403 | 404 | ElseIf proxyAddress = "" Then 405 | oBrowser.SetProxy HTTPREQUEST_PROXYSETTING_DIRECT 406 | dbg "Proxy-Mode: Direct (" & HTTPREQUEST_PROXYSETTING_DIRECT & ")" 407 | 408 | Else 409 | oBrowser.SetProxy HTTPREQUEST_PROXYSETTING_PROXY, proxyAddress 410 | dbg "Proxy-Mode: Proxy (" & HTTPREQUEST_PROXYSETTING_PROXY & "): " & proxyAddress 411 | End If 412 | 413 | ' When enabled ignore all certificate problems 414 | If ignoreCertProblems = 1 Then 415 | oBrowser.Option(HTTPREQUEST_SSLERROR_IGNORE_FLAG) = HTTPREQUEST_SECURITY_IGNORE_ALL 416 | End If 417 | 418 | baseUrl = webProto & "://" & webServer & webPort & basePath 419 | 420 | ' Handle the given action 421 | Select Case mode 422 | Case "add" 423 | ' Add a new scheduled downtime 424 | ' ########################################################################## 425 | Set params = CreateObject("Scripting.Dictionary") 426 | params.add "baseUrl", baseUrl 427 | params.add "hostname", hostname 428 | params.add "user", user 429 | params.add "password", userPw 430 | params.add "comment", downtimeComment 431 | params.add "start_time", timeStart 432 | params.add "end_time", timeEnd 433 | params.add "duration", downtimeDuration 434 | 435 | If downtimeType = 1 Then 436 | ' Schedule Host Downtime 437 | url = get_url("host_downtime", params) 438 | Else 439 | ' Schedule Service Downtime 440 | params.add "service", service 441 | url = get_url("service_downtime", params) 442 | End If 443 | 444 | dbg "HTTP-GET: " & url 445 | 446 | oBrowser.Open "GET", url 447 | setBrowserOptions() 448 | oBrowser.Send 449 | 450 | dbg "HTTP-Response (" & oBrowser.Status & "): " & oBrowser.ResponseText 451 | 452 | ' Handle response code, not in detail, only first char 453 | Select Case Left(oBrowser.Status, 1) 454 | ' 2xx response code is OK 455 | Case 2 456 | If InStr(oBrowser.ResponseText, get_msg("success")) > 0 Then 457 | 458 | ' Save the id of the just scheduled downtime 459 | If storeDowntimeIds = 1 Then 460 | saveDowntimeId() 461 | log EVENTLOG_SUCCESS, "OK: Downtime was submitted successfully" 462 | WScript.Quit(0) 463 | Else 464 | log EVENTLOG_INFORMATION, "Downtime IDs are not set to be stored" 465 | WScript.Quit(1) 466 | End If 467 | ElseIf InStr(oBrowser.ResponseText, get_msg("not_authorized")) > 0 Then 468 | err "Maybe not authorized or wrong host- or servicename" 469 | 470 | ElseIf InStr(oBrowser.ResponseText, get_msg("no_author")) > 0 Then 471 | err "No Author entered, define Author in user var" 472 | 473 | Else 474 | err "Some undefined error occured, turn debug mode on to view what happened" 475 | End If 476 | Case 3 477 | err "HTTP Response code 3xx says ""moved url"" (" & oBrowser.Status & ")" 478 | Case 4 479 | err "HTTP Response code 4xx says ""client error"" (" & oBrowser.Status & ")" & _ 480 | "Hint: This could be caused by wrong auth credentials and/or datetime settings in this script" 481 | Case 5 482 | err "HTTP Response code 5xx says ""server Error"" (" & oBrowser.Status & ")" 483 | Case Else 484 | err "HTTP Response code unhandled by script (" & oBrowser.Status & ")" 485 | End Select 486 | Case "del" 487 | ' Delete the last scheduled downtime 488 | ' ########################################################################## 489 | 490 | If storeDowntimeIds <> 1 Then 491 | err "Unable to remove a downtime. The storingDowntimeIds option is set to disabled." 492 | End If 493 | 494 | ' Read all internal downtime ids for this host/service 495 | Dim aDowntimes 496 | aDowntimes = getDowntimeIds() 497 | 498 | ' Only proceed when downtimes found 499 | If UBound(aDowntimes)+1 > 0 Then 500 | ' Sort downtimes (lowest number at top) 501 | aDowntimes = bubblesort(aDowntimes) 502 | 503 | dbg "Trying to delete with internal downtime id: " & aDowntimes(0) 504 | 505 | ' Get the nagios downtime id for the last scheduled downtime 506 | Dim nagiosDowntimeId 507 | nagiosDowntimeId = getNagiosDowntimeId(aDowntimes(0)) 508 | 509 | dbg "Translated downtime id: " & aDowntimes(0) & "(internal) => " & nagiosDowntimeId & " (Nagios)" 510 | 511 | If nagiosDowntimeId <> "" Then 512 | deleteDowntime(nagiosDowntimeId) 513 | End If 514 | 515 | ' We can safely delete the downtime from the list of saved downtimes, 516 | ' because getNagiosDowntimeId(aDowntimes(0)) will exit the script if 517 | ' it can't get the downtimes from the nagios server. 518 | delDowntimeId(aDowntimes(0)) 519 | Else 520 | err "Unable to remove a downtime. No previously scheduled downtime found." 521 | End If 522 | Case "clean" 523 | ' Cleanup the stored downtime ids 524 | ' ########################################################################## 525 | dbg "Cleanup mode selected." 526 | cleanupDowntimeIds 527 | Case Else 528 | err "Unknown mode was set (Available: add, del, clean)" 529 | WScript.Quit(1) 530 | End Select 531 | 532 | Set oBrowser = Nothing 533 | Set oShell = Nothing 534 | Set oFile = Nothing 535 | Set oFS = Nothing 536 | 537 | ' Regular end of script 538 | ' ############################################################################## 539 | 540 | ' ############################################################# 541 | ' Subs 542 | ' ############################################################# 543 | 544 | sub dbg(msg) 545 | If debug = 1 Then 546 | log EVENTLOG_INFORMATION, msg 547 | End If 548 | End Sub 549 | 550 | sub err(msg) 551 | log EVENTLOG_ERROR, "ERROR: " & msg 552 | WScript.Quit(1) 553 | End Sub 554 | 555 | Sub log(logType, msg) 556 | WScript.echo msg 557 | If evtlog = 1 Then 558 | oShell.LogEvent logType, WScript.ScriptName & ":" & VBCRLF & msg 559 | End If 560 | End Sub 561 | 562 | Sub setBrowserOptions() 563 | oBrowser.SetRequestHeader "User-Agent", "nagios_downtime.vbs / " & version 564 | 565 | dbg "User-Agent: " & "nagios_downtime.vbs / " & version 566 | 567 | ' Only try to auth if auth informations are given 568 | If authName <> "" And userPw <> "" Then 569 | 570 | dbg "Nagios Auth: " & authName 571 | dbg "Nagios User: " & user 572 | dbg "Nagios Password: " & userPw 573 | 574 | ' Set the login information (0: Server auth / 1: Proxy auth) 575 | oBrowser.SetCredentials user, userPw, 0 576 | End If 577 | End Sub 578 | 579 | Function get_url(key, params) 580 | url = urls.Item(ty).Item(key) 581 | Dim k 582 | For Each k In params.Keys 583 | url = Replace(url, "[" & k & "]", params.Item(k)) 584 | Next 585 | get_url = url 586 | End Function 587 | 588 | Function get_msg(key) 589 | get_msg = messages.Item(ty).Item(key) 590 | End Function 591 | 592 | Function bubblesort(arrSort) 593 | Dim i, j, arrTemp 594 | For i = 0 to UBound(arrSort) 595 | For j = i + 1 to UBound(arrSort) 596 | If arrSort(i) < arrSort(j) Then 597 | arrTemp = arrSort(i) 598 | arrSort(i) = arrSort(j) 599 | arrSort(j) = arrTemp 600 | End If 601 | Next 602 | Next 603 | bubblesort = arrSort 604 | End Function 605 | 606 | 607 | Sub about() 608 | WScript.echo "Usage:" & vbcrlf & vbcrlf & _ 609 | "cscript " & WScript.ScriptName & " [-i ] [-m add] [-H ] [-s ] [-t ]" & vbcrlf & _ 610 | " [-S ] [-p ] [-u ]" & vbcrlf & _ 611 | " [-p ] [-e] [-d]" & vbcrlf & _ 612 | "cscript " & WScript.ScriptName & " -m del [-i ] [-H ] [-s ] [-S ]" & vbcrlf & _ 613 | " [-p ] [-u ] [-p ] [-e] [-d]" & vbcrlf & _ 614 | "cscript " & WScript.ScriptName & " -m clean [-i ] [-H ] [-s ] [-S ]" & vbcrlf & _ 615 | " [-p ] [-u ] [-p ] [-e] [-d]" & vbcrlf & _ 616 | "cscript " & WScript.ScriptName & " -h" & vbcrlf & _ 617 | "" & vbcrlf & _ 618 | "Nagios Downtime Script by Lars Michelsen " & vbcrlf & _ 619 | "Sends a HTTP(S) request to the nagios cgis to add a downtime for a host or" & vbcrlf & _ 620 | "service. Since version 0.7 the script can remove downtimes too when being" & vbcrlf & _ 621 | "called in ""del"" mode." & vbcrlf & _ 622 | "" & vbcrlf & _ 623 | "Parameters:" & vbcrlf & _ 624 | " -i, --interface Type of interface to be used to set downtimes (nagios or" & vbcrlf & _ 625 | " multisite). Defaults to nagios." & vbcrlf & _ 626 | " -m, --mode Mode to run the script in (Available: add, del, clean)" & vbcrlf & _ 627 | "" & vbcrlf & _ 628 | " -H, --hostname Name of the host the downtime should be scheduled for." & vbcrlf & _ 629 | " Important: The name must be same as in Nagios." & vbcrlf & _ 630 | " -s, --service Name of the service the downtime should be scheduled for." & vbcrlf & _ 631 | " Important: The name must be same as in Nagios. " & vbcrlf & _ 632 | " When empty or not set a host downtime is being submitted." & vbcrlf & _ 633 | " -t, --downtime Duration of the fixed downtime in minutes" & vbcrlf & _ 634 | " -c, --comment Comment for the downtime" & vbcrlf & _ 635 | " " & vbcrlf & _ 636 | " -S, --server Nagios Webserver address (IP or DNS)" & vbcrlf & _ 637 | " -p, --path Web path to Nagios cgi-bin (Default: /nagios/cgi-bin)" & vbcrlf & _ 638 | " -u, --user Usernate to be used for accessing the CGIs" & vbcrlf & _ 639 | " -P, --password Password for accessing the CGIs" & vbcrlf & _ 640 | " " & vbcrlf & _ 641 | " -e, --evtlog Enable logging to Windows event log " & vbcrlf & _ 642 | " -d, --debug Enable debug mode" & vbcrlf & _ 643 | " -h, --help Show this message" & vbcrlf & _ 644 | "" & vbcrlf & _ 645 | "If you call " & WScript.ScriptName & " without parameters the script takes the default" & vbcrlf & _ 646 | "options which are hardcoded in the script." & vbcrlf & _ 647 | "" 648 | End Sub 649 | 650 | Sub delDowntimeId(internalId) 651 | Dim file, aDowntimes, id 652 | 653 | file = downtimePath & "\" 654 | If downtimeType = 1 Then 655 | file = file & hostname & ".txt" 656 | Else 657 | file = file & hostname & "-" & service & ".txt" 658 | End If 659 | 660 | ' Read all downtimes to array 661 | 662 | Set oFile = oFS.OpenTextfile(file, FOR_READING) 663 | Do While Not oFile.AtEndOfStream 664 | Push aDowntimes, oFile.Readline 665 | Loop 666 | oFile.Close 667 | 668 | ' Filter downtime 669 | ArrayRemoveVal aDowntimes, internalId 670 | 671 | ' Write downtimes back to file 672 | Set oFile = oFS.OpenTextfile(file, FOR_WRITING, CREATE_IF_NOT_EXISTS) 673 | For Each id In aDowntimes 674 | dbg "Rewriting id to file: " & id 675 | oFile.Writeline id 676 | Next 677 | oFile.Close 678 | 679 | Set oFile = Nothing 680 | End Sub 681 | 682 | Sub cleanupDowntimeIds() 683 | Dim aDowntimes, nagiosDowntimeId, count, id 684 | ' Read all internal downtime ids for this host/service from file 685 | aDowntimes = getDowntimeIds() 686 | 687 | ' Only proceed when stored downtime ids found 688 | count = UBound(aDowntimes) 689 | If UBound(aDowntimes)+1 > 0 Then 690 | For Each id In aDowntimes 691 | ' Get the nagios downtime id 692 | nagiosDowntimeId = getNagiosDowntimeId(id) 693 | 694 | dbg "Translated downtime id: " & id & "(internal) => " & nagiosDowntimeId & " (Nagios)" 695 | 696 | If nagiosDowntimeId = "" Then 697 | ' no nagios downtime found -> delete the stored internal downtime id 698 | ' We can safely delete the downtime from the list of stored downtimes, 699 | ' because getNagiosDowntimeId(id) will exit the script if 700 | ' it can't get the downtimes from the nagios server. 701 | 702 | dbg "Internal downtime id " & id & " not found on nagios server" 703 | dbg "Deleting internal downtime id " & id & " from file" 704 | 705 | delDowntimeId(id) 706 | log EVENTLOG_INFORMATION, "Internal downtime id " & id & " deleted from file" 707 | End If 708 | Next 709 | Else 710 | log EVENTLOG_INFORMATION, "INFO: Nothing to do. No stored downtime ids found." 711 | End If 712 | End Sub 713 | 714 | Function getDowntimeIds() 715 | Dim file, aDowntimes, sLine, oRegex, oMatches 716 | aDowntimes = Array() 717 | 718 | file = downtimePath & "\" 719 | If downtimeType = 1 Then 720 | file = file & hostname & ".txt" 721 | Else 722 | file = file & hostname & "-" & service & ".txt" 723 | End If 724 | 725 | Set oRegex = New RegExp 726 | oRegex.Pattern = "[0-9]+" 727 | 728 | ' Read all downtimes to array 729 | 730 | If oFS.FileExists(file) Then 731 | Set oFile = oFS.OpenTextfile(file, FOR_READING) 732 | Do While Not oFile.AtEndOfStream 733 | sLine = oFile.Readline 734 | 735 | ' Do some validation 736 | If oRegex.Execute(sLine).Count > 0 Then 737 | Push aDowntimes, sLine 738 | End If 739 | Loop 740 | oFile.Close 741 | Else 742 | err "Could not open temporary file (" & file & ")" 743 | WScript.Quit(1) 744 | End If 745 | 746 | getDowntimeIds = aDowntimes 747 | End Function 748 | 749 | Sub saveDowntimeId() 750 | Dim file 751 | 752 | file = downtimePath & "\" 753 | If downtimeType = 1 Then 754 | file = file & hostname & ".txt" 755 | Else 756 | file = file & hostname & "-" & service & ".txt" 757 | End If 758 | 759 | dbg "Saving downtime to file: " & file 760 | 761 | Set oFile = oFS.OpenTextfile(file, FOR_APPENDING, CREATE_IF_NOT_EXISTS) 762 | oFile.Writeline downtimeId 763 | oFile.Close 764 | 765 | ' FIXME: Error handling 766 | 'err "Could not write downtime to temporary file (" & $file & ")" 767 | 'WScript.Quit(1) 768 | End Sub 769 | 770 | Function getNagiosDowntimeId(internalId) 771 | getNagiosDowntimeId = "" 772 | 773 | Dim aDowntimes, id 774 | ' Get all downtimes 775 | aDowntimes = getAllDowntimes() 776 | 777 | ' Filter the just scheduled downtime 778 | For Each id In aDowntimes 779 | ' Matching by: 780 | ' - internal id in comment field 781 | ' - triggerId: N/A 782 | If id("triggerId") = "N/A" And InStr(id("comment"), "(ID:" & internalId & ")") > 0 Then 783 | dbg "Found matching downtime: " & id("host") & " " & id("service") & " " & id("entryTime") & " " & id("downtimeId") 784 | 785 | getNagiosDowntimeId = id("downtimeId") 786 | End If 787 | Next 788 | End Function 789 | 790 | Sub deleteDowntime(nagiosDowntimeId) 791 | If nagiosDowntimeId = "" Then 792 | err "Unable to delete downtime. Nagios Downtime ID not given" 793 | End If 794 | 795 | Set params = CreateObject("Scripting.Dictionary") 796 | params.add "baseUrl", baseUrl 797 | params.add "user", user 798 | params.add "password", userPw 799 | params.add "downtime_id", nagiosDowntimeId 800 | 801 | If downtimeType = 1 Then 802 | ' Host downtime 803 | url = get_url("del_host_downtime", params) 804 | Else 805 | ' Service downtime 806 | url = get_url("del_service_downtime", params) 807 | End If 808 | 809 | dbg "HTTP-GET: " & url 810 | 811 | oBrowser.Open "GET", url 812 | setBrowserOptions() 813 | oBrowser.Send 814 | 815 | dbg "HTTP-Response (" & oBrowser.Status & "): " & oBrowser.ResponseText 816 | 817 | ' Handle response code, not in detail, only first char 818 | ' Exit the script if we can't get the downtimes from the nagios server 819 | Select Case Left(oBrowser.Status, 1) 820 | ' 2xx response code is OK 821 | Case 2 822 | If InStr(oBrowser.ResponseText, get_msg("success")) > 0 Then 823 | log EVENTLOG_SUCCESS, "OK: Downtime (ID: " & nagiosDowntimeId & ") has been deleted" 824 | ElseIf InStr(oBrowser.ResponseText, get_msg("not_authorized")) > 0 Then 825 | err "Maybe not authorized or wrong host- or servicename" 826 | 827 | ElseIf InStr(oBrowser.ResponseText, get_msg("no_author")) > 0 Then 828 | err "No Author entered, define Author in user var" 829 | 830 | Else 831 | err "Some undefined error occured, turn debug mode on to view what happened" 832 | End If 833 | Case 3 834 | err "HTTP Response code 3xx says ""moved url"" (" & oBrowser.Status & ")" 835 | 836 | Case 4 837 | err "HTTP Response code 4xx says ""client error"" (" & oBrowser.Status & ")" & _ 838 | "Hint: This could be caused by wrong auth credentials and/or datetime settings in this script" 839 | 840 | Case 5 841 | err "HTTP Response code 5xx says ""server Error"" (" & oBrowser.Status & ")" 842 | 843 | Case Else 844 | err "HTTP Response code unhandled by script (" & oBrowser.Status & ")" 845 | End Select 846 | End Sub 847 | 848 | Function getAllDowntimes() 849 | Dim aDowntimes, oRegex, oMatches, oDict 850 | aDowntimes = Array() 851 | 852 | ' Url to downtime page 853 | Set params = CreateObject("Scripting.Dictionary") 854 | params.add "baseUrl", baseUrl 855 | params.add "user", user 856 | params.add "password", userPw 857 | url = get_url("all_downtimes", params) 858 | 859 | dbg "HTTP-GET: " & url 860 | 861 | ' Fetch information via HTTP-GET 862 | oBrowser.Open "GET", url 863 | setBrowserOptions() 864 | oBrowser.Send 865 | 866 | dbg "HTTP-Response (" & oBrowser.Status & "): " & oBrowser.ResponseText 867 | 868 | ' Handle response code, not in detail, only first char 869 | ' Exit on error 870 | Select Case Left(oBrowser.Status, 1) 871 | ' 2xx response code is OK 872 | Case 2 873 | dbg "OK: Got downtime response from nagios server" 874 | Case 3 875 | err "HTTP Response code 3xx says ""moved url"" (" & oBrowser.Status & ")" 876 | Case 4 877 | err "HTTP Response code 4xx says ""client error"" (" & oBrowser.Status & ")" & VBCRLF & _ 878 | "Hint: This could be caused by wrong auth credentials and/or datetime settings in this script" 879 | Case 5 880 | err "HTTP Response code 5xx says ""server Error"" (" & oBrowser.Status & ")" 881 | Case Else 882 | err "HTTP Response code unhandled by script (" & oBrowser.Status & ")" 883 | End Select 884 | 885 | If ty = "nagios" Then 886 | Set oRegex = New RegExp 887 | oRegex.IgnoreCase = True 888 | 889 | ' Parse all downtimes to an array 890 | Dim lineType, sLine 891 | lineType = "" 892 | ' Removed vbCrLf here 893 | For Each sLine In Split(oBrowser.ResponseText, vblf) 894 | ' Filter only downtime lines 895 | oRegex.Pattern = "CLASS=\'downtime(Odd|Even)" 896 | Set oMatches = oRegex.Execute(sLine) 897 | 898 | If oMatches.Count > 0 Then 899 | lineType = "downtime" & oMatches(0).SubMatches(0) 900 | 901 | oRegex.Pattern = "[^<]+<\/A>" & _ 903 | "<\/td>([^<]+)<\/td>([^<]+)<\/td>([^<]+)" & _ 905 | "<\/td>([^<]+)<\/td>([^<]+)<\/td>([^<]+)" & _ 907 | "<\/td>([^<]+)<\/td>([^<]+)<\/td>([^<]+)<\/td>" 909 | Set oMatches = oRegex.Execute(sLine) 910 | 911 | If oMatches.Count > 0 Then 912 | ' Host downtime: 913 | ' dev.nagvis.org10-13-2009 09:15:35Nagios AdminPerl Downtime-Script01-10-2010 09:15:3501-10-2010 09:25:35Fixed0d 0h 10m 0s9N/A 914 | 915 | Set oDict = CreateObject("Scripting.Dictionary") 916 | 917 | dbg "Found host downtime:" & _ 918 | "Host: " & oMatches(0).SubMatches(0) & _ 919 | " EntryTime: " & oMatches(0).SubMatches(1) & _ 920 | " User: " & oMatches(0).SubMatches(2) & _ 921 | " Comment: " & oMatches(0).SubMatches(3) & _ 922 | " Start: " & oMatches(0).SubMatches(4) & _ 923 | " End: " & oMatches(0).SubMatches(5) & _ 924 | " Type: " & oMatches(0).SubMatches(6) & _ 925 | " Duration: " & oMatches(0).SubMatches(7) & _ 926 | " DowntimeID: " & oMatches(0).SubMatches(8) & _ 927 | " TriggerID: " & oMatches(0).SubMatches(9) 928 | 929 | oDict.Add "host", oMatches(0).SubMatches(0) 930 | oDict.Add "service", "" 931 | oDict.Add "entryTime", oMatches(0).SubMatches(1) 932 | oDict.Add "user", oMatches(0).SubMatches(2) 933 | oDict.Add "comment", oMatches(0).SubMatches(3) 934 | oDict.Add "start", oMatches(0).SubMatches(4) 935 | oDict.Add "end", oMatches(0).SubMatches(5) 936 | oDict.Add "type", oMatches(0).SubMatches(6) 937 | oDict.Add "duration", oMatches(0).SubMatches(7) 938 | oDict.Add "downtimeId", oMatches(0).SubMatches(8) 939 | oDict.Add "triggerId", oMatches(0).SubMatches(9) 940 | 941 | ' Push to array 942 | ReDim Preserve aDowntimes(UBound(aDowntimes) + 1) 943 | Set aDowntimes(UBound(aDowntimes)) = oDict 944 | Else 945 | oRegex.Pattern = "[^<]+" & _ 947 | "<\/A><\/td>[^<]+" & _ 949 | "<\/A><\/td>([^<]+)<\/td>" & _ 950 | "([^<]+)<\/td>([^<]+)<\/td>" & _ 952 | "([^<]+)<\/td>([^<]+)<\/td>" & _ 953 | "([^<]+)<\/td>([^<]+)<\/td>" & _ 955 | "([^<]+)<\/td>([^<]+)<\/td>" 956 | Set oMatches = oRegex.Execute(sLine) 957 | 958 | If oMatches.Count > 0 Then 959 | ' Service downtime: 960 | ' dev.nagvis.orgHTTP10-13-2009 10:28:30Nagios Admintest10-13-2009 10:28:1110-13-2009 12:28:11Fixed0d 2h 0m 0s145N/A 961 | 962 | Set oDict = CreateObject("Scripting.Dictionary") 963 | 964 | dbg "Found service downtime:" & _ 965 | "Host: " & oMatches(0).SubMatches(0) & _ 966 | " Service: " & oMatches(0).SubMatches(1) & _ 967 | " EntryTime: " & oMatches(0).SubMatches(2) & _ 968 | " User: " & oMatches(0).SubMatches(3) & _ 969 | " Comment: " & oMatches(0).SubMatches(4) & _ 970 | " Start: " & oMatches(0).SubMatches(5) & _ 971 | " End: " & oMatches(0).SubMatches(6) & _ 972 | " Type: " & oMatches(0).SubMatches(7) & _ 973 | " Duration: " & oMatches(0).SubMatches(8) & _ 974 | " DowntimeID: " & oMatches(0).SubMatches(9) & _ 975 | " TriggerID: " & oMatches(0).SubMatches(10) 976 | 977 | oDict.Add "host", oMatches(0).SubMatches(0) 978 | oDict.Add "service", oMatches(0).SubMatches(1) 979 | oDict.Add "entryTime", oMatches(0).SubMatches(2) 980 | oDict.Add "user", oMatches(0).SubMatches(3) 981 | oDict.Add "comment", oMatches(0).SubMatches(4) 982 | oDict.Add "start", oMatches(0).SubMatches(5) 983 | oDict.Add "end", oMatches(0).SubMatches(6) 984 | oDict.Add "type", oMatches(0).SubMatches(7) 985 | oDict.Add "duration", oMatches(0).SubMatches(8) 986 | oDict.Add "downtimeId", oMatches(0).SubMatches(9) 987 | oDict.Add "triggerId", oMatches(0).SubMatches(10) 988 | 989 | ' Push to array 990 | ReDim Preserve aDowntimes(UBound(aDowntimes) + 1) 991 | Set aDowntimes(UBound(aDowntimes)) = oDict 992 | End If 993 | End If 994 | End If 995 | Next 996 | ElseIf ty = "multisite" Then 997 | 998 | ' basic, simple json parsing 999 | Dim parsed, row 1000 | parsed = parseMultisiteData(oBrowser.ResponseText) 1001 | 1002 | For Each row In parsed 1003 | Set oDict = CreateObject("Scripting.Dictionary") 1004 | 1005 | If UBound(row) = 11 Then 1006 | ' Handle new indices since http://git.mathias-kettner.de/git/?p=check_mk.git;a=commitdiff;h=c909636fe1eb4085d346f650c9f8387d7780c913 1007 | ' It would be much better to work with the column names. I know... 1008 | oDict.Add "host", row(0) 1009 | oDict.Add "service", row(1) 1010 | oDict.Add "entryTime", row(4) 1011 | oDict.Add "user", row(3) 1012 | oDict.Add "comment", row(10) 1013 | oDict.Add "start", row(5) 1014 | oDict.Add "end", row(6) 1015 | oDict.Add "type", row(7) 1016 | oDict.Add "duration", row(8) 1017 | oDict.Add "downtimeId", row(11) 1018 | oDict.Add "triggerId", "N/A" 1019 | Else 1020 | oDict.Add "host", row(0) 1021 | oDict.Add "service", row(1) 1022 | oDict.Add "entryTime", row(3) 1023 | oDict.Add "user", row(2) 1024 | oDict.Add "comment", row(8) 1025 | oDict.Add "start", row(4) 1026 | oDict.Add "end", row(5) 1027 | oDict.Add "type", row(6) 1028 | oDict.Add "duration", row(7) 1029 | oDict.Add "downtimeId", row(9) 1030 | oDict.Add "triggerId", "N/A" 1031 | End If 1032 | 1033 | ' Push to array 1034 | ReDim Preserve aDowntimes(UBound(aDowntimes) + 1) 1035 | Set aDowntimes(UBound(aDowntimes)) = oDict 1036 | Next 1037 | End If 1038 | 1039 | getAllDowntimes = aDowntimes 1040 | End Function 1041 | 1042 | ' no real json parsing. Simply extracting all strings, then splitting by fields 1043 | Function parseMultisiteData(data) 1044 | Dim length, index, elem_start, element, rows, row, char, first_row 1045 | length = Len(data) 1046 | index = 0 1047 | elem_start = -1 1048 | rows = Array() 1049 | row = Array() 1050 | first_row = 1 1051 | While index < length 1052 | index = index + 1 1053 | char = Mid(data, index, 1) 1054 | 1055 | if elem_start = -1 Then 1056 | If char = """" Then 1057 | ' Initialize an element, search for starts 1058 | elem_start = index + 1 1059 | ElseIf char = vblf Then 1060 | ' Is the line complete? Then add it to the rows array. The 8 here is 1061 | ' a value just to te sure we do not add empty/incomplete rows. In old 1062 | ' cmk releases the number of columns was 9, currently we get 11 1063 | If UBound(row) > 8 Then 1064 | If first_row <> 1 Then 1065 | Push rows, row 1066 | Else 1067 | first_row = 0 ' simply drop the header row 1068 | End If 1069 | row = Array() 1070 | End If 1071 | End If 1072 | ElseIf char = """" Then 1073 | element = Mid(data, elem_start, index - elem_start) 1074 | Push row, element 1075 | elem_start = -1 1076 | End If 1077 | WEnd 1078 | 1079 | ' Unfished row? Add it! 1080 | If UBound(row) <> -1 Then 1081 | Push rows, row 1082 | End If 1083 | 1084 | parseMultisiteData = rows 1085 | End Function 1086 | 1087 | ' Test whether or not a host is reachable via ping. 1088 | ' Use hostname or ip address as ping target parameter 1089 | Function PingTest(strHostOrIP) 1090 | Dim strCommand, objSh 1091 | Set objSh = CreateObject("WScript.Shell") 1092 | strCommand = "%ComSpec% /C %SystemRoot%\system32\ping.exe -n 1 " & strHostOrIP & " | " & "%SystemRoot%\system32\find.exe /i " & Chr(34) & "TTL=" & Chr(34) 1093 | PingTest = CBool(objSh.Run(strCommand, 0, True)) 1094 | Set objSh = Nothing 1095 | End Function 1096 | 1097 | Function gettime(dateTime) 1098 | 1099 | If dateTime = "" Then 1100 | dateTime = Now 1101 | End If 1102 | 1103 | Dim sec, min, h, mday, m, y 1104 | sec = Second(dateTime) 1105 | min = Minute(dateTime) 1106 | h = Hour(dateTime) 1107 | mday = Day(dateTime) 1108 | m = Month(dateTime) 1109 | y = Year(dateTime) 1110 | 1111 | ' add leading 0 to values lower than 10 1112 | If m < 10 Then 1113 | m = "0" & m 1114 | End If 1115 | If mday < 10 Then 1116 | mday = "0" & mday 1117 | End If 1118 | If h < 10 Then 1119 | h = "0" & h 1120 | End If 1121 | If min < 10 Then 1122 | min = "0" & min 1123 | End If 1124 | If sec < 10 Then 1125 | sec = "0" & sec 1126 | End If 1127 | 1128 | Select Case nagiosDateFormat 1129 | Case "euro" 1130 | gettime = mday & "-" & m & "-" & y & " " & h & ":" & min & ":" & sec 1131 | Case "us" 1132 | gettime = m & "-" & mday & "-" & y & " " & h & ":" & min & ":" & sec 1133 | Case "iso8601" 1134 | gettime = y & "-" & m & "-" & mday & " " & h & ":" & min & ":" & sec 1135 | Case "strict-iso8601" 1136 | gettime = y & "-" & m & "-" & mday & "T" & h & ":" & min & ":" & sec 1137 | Case Else 1138 | err "No valid date format given in nagiosDateFormat var" 1139 | End Select 1140 | End Function 1141 | 1142 | Function Push(ByRef mArray, ByVal mValue) 1143 | Dim mValEl 1144 | 1145 | If IsArray(mArray) Then 1146 | Redim Preserve mArray(UBound(mArray) + 1) 1147 | mArray(UBound(mArray)) = mValue 1148 | Else 1149 | If IsArray(mValue) Then 1150 | mArray = mValue 1151 | Else 1152 | mArray = Array(mValue) 1153 | End If 1154 | End If 1155 | 1156 | Push = UBound(mArray) 1157 | End Function 1158 | 1159 | Sub ArrayRemoveVal(ByRef arr, ByVal val) 1160 | Dim i, j 1161 | If IsArray(arr) Then 1162 | i = 0 : j = -1 1163 | For i = 0 To UBound(arr) 1164 | If arr(i) <> val Then 1165 | j = j + 1 1166 | arr(j) = arr(i) 1167 | End If 1168 | Next 1169 | ReDim Preserve arr(j) 1170 | End If 1171 | End Sub 1172 | 1173 | 1174 | ' ############################################################# 1175 | ' EOF 1176 | ' ############################################################# 1177 | -------------------------------------------------------------------------------- /nagios_downtime.vbs.conf-sample: -------------------------------------------------------------------------------- 1 | server = "monitoring-server.local" 'ty = "nagios" 'authName = "OMD Monitoring Site sysmon" 'basePath = "/sysmon/nagios/cgi-bin" 'user = "omdadmin" 'userPw = "omd" 'nagiosDateFormat = "iso8601" ty = "multisite" basePath = "/sysmon/check_mk" user = "svc-downtime" userPw = "testpassword" Set oNetwork = WScript.CreateObject("WScript.Network") hostname = LCase(oNetwork.ComputerName) 2 | --------------------------------------------------------------------------------