Rev 29 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4 | daniel-mar | 1 | <?php /* <ViaThinkSoftSignature> |
31 | daniel-mar | 2 | trfGwmF3j+VtYsqXNFrLSDAmu8hPGkJ8Q6jpk9i+ZpM7rofOeRS5Pm8v0SSoGarjI |
3 | XHBoAzxEnyIlEO6HeF3gEZ0UGCm2LeQpcKy/92b1/L/B0ll+yW1+qPbkj/0SKSwbK |
||
4 | NmtDKM39a9XIZSzvBVus/znDRTVdNPeZsgs0fJr+iGkgjsUcefXXuGAUI+Lc89KrK |
||
5 | Ef7NAI95yBXwRmlqD504kM/l/iYOB0nbDAbBaxKQz1cG3YOnyiT8ayE4yqHL4rmXq |
||
6 | VI14mYnmiKBbV0ZXEGp6oDBEX5lEqUM6TgtKp2wxXE/M0RZzF0jWxKZH96Cds+qvT |
||
7 | s6XBZFFDufRO4XdOgjWBzRLikyeuWEMgSeVzvfV6N6KWGzNbCAshuRb/ncxdvtFC3 |
||
8 | qmCIao9tNixbhuxGBgE+vPG3EwlWCP8V6HMvIEcF863sOVmZouMIKxki5RUd7aHcD |
||
9 | +bjy1PoNWHlc+wAIfVIf/nPg43awQAjDCCVvh5HZZTqaAHeiwT441AhnePVcxv3Ds |
||
10 | QFqiY20F2j/KuPk9Ek7+8TI9By+y+GVSJyMxm8rC0H2rwyNDuk5qiw77WRstsRG2S |
||
11 | 6sa352zH8SzoWJmtwFH5zu8yZMknL4K4ToGcoX+4NBC+wEgJk/5GTOTxcRlFRVrfF |
||
12 | pIhUJPu0wYnFmsrvM3reHVyAueHuSO1TOCIJ+IFWYQzBQZpA3JpuNclK03ws0PEzH |
||
13 | qfoD/UhYU/TvSxPxGGE6ddwfMIZcqK7zdMz6CrdjI/ZSXsSQqUZCDhhf4nt5JqapO |
||
14 | FFL0OYk+EhXtGKqP/HClYwq4n1i03+5oE34nKFkZdPEGK/c/VgoJ1sZpKycCQplhw |
||
15 | 8sJNiZIEI/sdWZ4z1S/G7Stl182Def3TYkgDbQj7wEo3fqZXajHIF2fRlxqT3g6fV |
||
16 | S/xxjS9Sauz1pZilSqGsF+d+s5yYfgWrfLgSQyuJoxFdhU/B6PLVnry7RKoFUH3Ju |
||
17 | REKzVECnyM/UK/Viil4yZ+CIvpfyZcecAt4BrtyCq9SkjQNkIxzu61uautZF0f3v9 |
||
18 | BXTQGf2/oH0v37Bhm3Xofn+hQ6J15H4a1lVcp2FPB87/eQ3cpBkSjryG2Xa/Eft2U |
||
19 | A+mv+HMpbhraGRJvGUzRy04XBg8yRHes8vfaEau3czfWQlsmEIyWpvKgXwhtpeOfK |
||
20 | ciQexRuCrjTH9zQy1InaANAo95P2YeQxgzJcppMZ44eLlHEuku949UijxYzjTJxsv |
||
21 | pdYT2j93XHikUsADBQJAkhRzQ6shNxK8dMEdLoBgg1mL9IYvY3z81YVe/wy2fBkWx |
||
22 | 44y5aSSMj2L7un0uwwOnrPC++JbKAos8y4Ez4FZL17Y0lZyRb5mx/jptGcBF/HIOy |
||
27 | daniel-mar | 23 | A== |
4 | daniel-mar | 24 | </ViaThinkSoftSignature> */ ?> |
2 | daniel-mar | 25 | <?php |
26 | |||
27 | /* |
||
28 | |||
24 | daniel-mar | 29 | VNag - Nagios Framework for PHP (C) 2014-2021 |
2 | daniel-mar | 30 | __ ___ _____ _ _ _ ____ __ _ |
31 | \ \ / (_) __ |_ _| |__ (_)_ __ | | __/ ___| ___ / _| |_ |
||
32 | \ \ / /| |/ _` || | | '_ \| | '_ \| |/ /\___ \ / _ \| |_| __| |
||
33 | \ V / | | (_| || | | | | | | | | | < ___) | (_) | _| |_ |
||
34 | \_/ |_|\__,_||_| |_| |_|_|_| |_|_|\_\|____/ \___/|_| \__| |
||
35 | |||
36 | Developed by Daniel Marschall www.viathinksoft.com |
||
37 | Licensed under the terms of the Apache 2.0 license |
||
31 | daniel-mar | 38 | Revision 2021-06-24 |
2 | daniel-mar | 39 | |
40 | */ |
||
41 | |||
42 | /**************************************************************************************************** |
||
43 | |||
44 | Introduction: |
||
45 | |||
46 | VNag is a small framework for Nagios Plugin Developers who use PHP CLI scripts. |
||
47 | The main purpose of VNag is to make the development of plugins as easy as possible, so that |
||
48 | the developer can concentrate on the actual work. VNag will try to automate as much |
||
49 | as possible. |
||
50 | |||
51 | Please note that your script should include the +x chmod flag: |
||
52 | chmod +x myscript.php |
||
53 | |||
54 | Please see the the demo/ folder for a few examples how to use this framework. |
||
55 | |||
56 | Arguments: |
||
57 | |||
58 | Example: |
||
59 | $this->addExpectedArgument($argSilent = new VNagArgument('s', 'silent', VNagArgument::VALUE_FORBIDDEN, null, 'Description for the --silent output', $defaultValue)); |
||
60 | $this->addExpectedArgument($argHost = new VNagArgument('H', 'host', VNagArgument::VALUE_REQUIRED, 'hostname', 'Description for the --host output', $defaultValue)); |
||
61 | |||
62 | In the example above, the two argument objects $argSilent and $argHost were created. |
||
63 | With these objects of the type VNagArgument, you can query the argument's value, |
||
64 | how often the argument was passed and if it is set: |
||
65 | |||
66 | $argSilent->count(); // 1 if "-s" is passed, 2 if "-s -s" is passed etc. |
||
67 | $argSilent->available(); // true if "-s" is passed, false otherwise |
||
68 | $argHost->getValue(); // "example.com" if "-h example.com" is passed |
||
69 | |||
70 | It is recommended that you pass every argument to $this->addExpectedArgument() . |
||
71 | Using this way, VNag can generate a --help page for you, which lists all your arguments. |
||
72 | Future version of VNag may also require to have a complete list of all valid arguments, |
||
73 | since the Nagios Development Guidelines recommend to output the usage information if an illegal |
||
74 | argument is passed. Due to PHP's horrible bad implementation of GNU's getopt(), this check for |
||
75 | unknown arguments is currently not possible, and the developer of VNag does not want to use |
||
76 | dirty hacks/workarounds, which would not match to all argument notation variations/styles. |
||
77 | See: https://bugs.php.net/bug.php?id=68806 |
||
78 | https://bugs.php.net/bug.php?id=65673 |
||
79 | https://bugs.php.net/bug.php?id=26818 |
||
80 | |||
81 | Setting the status: |
||
82 | |||
83 | You can set the status with: |
||
84 | $this->setStatus(VNag::STATUS_OK); |
||
85 | If you don't set a status, the script will return Unknown instead. |
||
86 | setStatus($status) will keep the most severe status, e.g. |
||
87 | $this->setStatus(VNag::STATUS_CRITICAL); |
||
88 | $this->setStatus(VNag::STATUS_OK); |
||
89 | will result in a status "Critical". |
||
90 | If you want to completely overwrite the status, use $force=true: |
||
91 | $this->setStatus(VNag::STATUS_CRITICAL); |
||
92 | $this->setStatus(VNag::STATUS_OK, true); |
||
93 | The status will now be "OK". |
||
94 | |||
95 | Possible status codes are: |
||
96 | (For service plugins:) |
||
97 | VNag::STATUS_OK = 0; |
||
98 | VNag::STATUS_WARNING = 1; |
||
99 | VNag::STATUS_CRITICAL = 2; |
||
100 | VNag::STATUS_UNKNOWN = 3; |
||
101 | |||
102 | (For host plugins:) |
||
103 | VNag::STATUS_UP = 0; |
||
104 | VNag::STATUS_DOWN = 1; |
||
105 | |||
106 | Output: |
||
107 | |||
108 | After the callback function cbRun() of your job has finished, |
||
109 | the framework will automatically output the results in the Nagios console output format, |
||
110 | the visual HTML output and/or the invisible HTML output. |
||
111 | |||
112 | In case of CLI invokation, the Shell exit code will be remembered and |
||
113 | automatically returned by the shutdown handler once the script normally |
||
114 | terminates. (In case you run different jobs, which is not recommended, the |
||
115 | shutdown handler will output the baddest exit code). |
||
116 | |||
117 | The Shell output format will be: |
||
118 | <Service status text>: <Comma separates messages> | <whitespace separated primary performance data> |
||
119 | "Verbose information:" |
||
120 | <Multiline verbose output> | <Multiline secondary performance data> |
||
121 | |||
122 | <Service status text> will be automatically created by VNag. |
||
123 | |||
124 | Verbose information are printed below the first line. Most Nagios clients will only print the first line. |
||
125 | If you have important output, use $this->setHeadline() instead. |
||
126 | You can add verbose information with following method: |
||
127 | $this->addVerboseMessage('foobar', $verbosity); |
||
128 | |||
129 | Following verbosity levels are defined: |
||
130 | VNag::VERBOSITY_SUMMARY = 0; // always printed |
||
131 | VNag::VERBOSITY_ADDITIONAL_INFORMATION = 1; // requires at least -v |
||
132 | VNag::VERBOSITY_CONFIGURATION_DEBUG = 2; // requiers at least -vv |
||
133 | VNag::VERBOSITY_PLUGIN_DEBUG = 3; // requiers at least -vvv |
||
134 | |||
135 | All STDOUT outputs of your script (e.g. by echo) will be interpreted as "verbose" output |
||
136 | and is automatically collected, so |
||
137 | echo "foobar"; |
||
138 | has the same functionality as |
||
139 | $this->addVerboseMessage('foobar', VNag::VERBOSITY_SUMMARY); |
||
140 | |||
141 | You can set messages (which will be added into the first line, which is preferred for plugin outputs) |
||
142 | using |
||
143 | $this->setHeadline($msg, $append, $verbosity); |
||
144 | Using the flag $append, you can choose if you want to append or replace the message. |
||
145 | |||
146 | VNag will catch Exceptions of your script and will automatically end the plugin, |
||
147 | returning a valid Nagios output. |
||
148 | |||
149 | Automatic handling of basic arguments: |
||
150 | |||
151 | VNag will automatic handle of following CLI arguments: |
||
152 | -? |
||
153 | -V --version |
||
154 | -h --help |
||
155 | -v --verbose |
||
156 | -t --timeout (only works if you set declare(ticks=1) at the beginning of each of your scripts) |
||
157 | -w --warning |
||
158 | -c --critical |
||
159 | |||
160 | You can performe range checking by using: |
||
161 | $example_value = '10MB'; |
||
162 | $this->checkAgainstWarningRange($example_value); |
||
163 | this is more or less the same as: |
||
164 | $example_value = '10MB'; |
||
165 | $wr = $this->getWarningRange(); |
||
166 | if (isset($wr) && $wr->checkAlert($example_value)) { |
||
167 | $this->setStatus(VNag::STATUS_WARNING); |
||
168 | } |
||
169 | |||
170 | In case that your script allows ranges which can be relative and absolute, you can provide multiple arguments; |
||
171 | $wr->checkAlert() will be true, as soon as one of the arguments is in the warning range. |
||
172 | The check will be done in this way: |
||
173 | $example_values = array('10MB', '5%'); |
||
174 | $this->checkAgainstWarningRange($example_values); |
||
175 | this is more or less the same as: |
||
176 | $example_values = array('10MB', '5%'); |
||
177 | $wr = $this->getWarningRange(); |
||
178 | if (isset($wr) && $wr->checkAlert($example_values)) { |
||
179 | $this->setStatus(VNag::STATUS_WARNING); |
||
180 | } |
||
181 | |||
182 | Note that VNag will automatically detect the UOM (Unit of Measurement) and is also able to convert them, |
||
183 | e.g. if you use the range "-w 20MB:40MB", your script will be able to use $wr->checkAlert('3000KB') |
||
184 | |||
185 | Please note that only following UOMs are accepted (as defined in the Plugin Development Guidelines): |
||
186 | - no unit specified: assume a number (int or float) of things (eg, users, processes, load averages) |
||
187 | - s, ms, us: seconds |
||
188 | - %: percentage |
||
189 | - B, KB, MB, TB: bytes // NOTE: GB is not in the official development guidelines,probably due to an error, so I've added them anyway |
||
190 | - c: a continous counter (such as bytes transmitted on an interface) |
||
191 | |||
192 | Multiple warning/critical ranges: |
||
193 | |||
194 | The arguments -w and -c can have many different values, separated by comma. |
||
195 | We can see this feature e.g. with the official plugin /usr/lib/nagios/plugins/check_ping: |
||
196 | It has following syntax for the arguments -w and -c: <latency>,<packetloss>% |
||
197 | |||
198 | When you are using checkAgainstWarningRange, you can set the fourth argument to the range number |
||
199 | you would like to check (beginning with 0). |
||
200 | |||
201 | Example: |
||
202 | // -w 1MB:5MB,5%:10% |
||
203 | $this->checkAgainstWarningRange('4MB', true, true, 0); // check value 4MB against range "1MB:5MB" (no warning) |
||
204 | $this->checkAgainstWarningRange('15%', true, true, 1); // check value 15% gainst range "5%:10%" (gives warning) |
||
205 | |||
206 | Visual HTTP output: |
||
207 | |||
208 | Can be enabled/disabled with $this->http_visual_output |
||
209 | |||
210 | Valid values: |
||
211 | |||
212 | VNag::OUTPUT_SPECIAL = 1; // illegal usage / help page, version page |
||
213 | VNag::OUTPUT_NORMAL = 2; |
||
214 | VNag::OUTPUT_EXCEPTION = 4; |
||
215 | VNag::OUTPUT_ALWAYS = 7; |
||
216 | VNag::OUTPUT_NEVER = 0; |
||
217 | |||
218 | Encryption and Decryption: |
||
219 | |||
21 | daniel-mar | 220 | In case you are emitting machine-readable code in your HTTP output |
2 | daniel-mar | 221 | (can be enabled/disabled by $this->http_invisible_output), |
21 | daniel-mar | 222 | you can encrypt the machine-readable part of your HTTP output by |
2 | daniel-mar | 223 | setting $this->password_out . If you want to read the information, |
224 | you need to set $this->password_in at the web-reader plugin. |
||
24 | daniel-mar | 225 | The visual output is not encrypted. So, if you want to hide the information, |
226 | then you must not enable visual HTML output. |
||
25 | daniel-mar | 227 | If you don't want to encrypt the machine-readable output, |
228 | please set $this->password_out to null or empty string. |
||
2 | daniel-mar | 229 | |
24 | daniel-mar | 230 | Attention! |
231 | - Encryption and decryption require the OpenSSL extension in PHP. |
||
232 | |||
233 | Digital signature: |
||
234 | |||
2 | daniel-mar | 235 | You can sign the output by setting $this->privkey with a filename containing |
236 | a private key created by OpenSSL. If it is encrypted, please also set |
||
237 | $this->privkey_password . |
||
238 | To check the signature, set $this->pubkey at your web-reader plugin with |
||
239 | the filename of the public key file. |
||
240 | |||
241 | Attention! |
||
24 | daniel-mar | 242 | - Signatures require the OpenSSL extension in PHP. |
2 | daniel-mar | 243 | |
244 | Performance data: |
||
245 | |||
246 | You can add performance data using |
||
247 | $this->addPerformanceData(new VNagPerformanceData($label, $value, $warn, $crit, $min, $max)); |
||
248 | or by the alternative constructor |
||
249 | $this->addPerformanceData(VNagPerformanceData::createByString("'XYZ'=100;120;130;0;500")); |
||
250 | $value may contain an UOM, e.g. "10MB". All other parameters may not contain an UOM. |
||
251 | |||
252 | Guidelines: |
||
253 | |||
254 | This framework currently supports meets following guidelines: |
||
255 | - https://nagios-plugins.org/doc/guidelines.html#PLUGOUTPUT (Plugin Output for Nagios) |
||
256 | - https://nagios-plugins.org/doc/guidelines.html#AEN33 (Print only one line of text) |
||
257 | - https://nagios-plugins.org/doc/guidelines.html#AEN41 (Verbose output) |
||
258 | - https://nagios-plugins.org/doc/guidelines.html#AEN78 (Plugin Return Codes) |
||
259 | - https://nagios-plugins.org/doc/guidelines.html#THRESHOLDFORMAT (Threshold and ranges) |
||
260 | - https://nagios-plugins.org/doc/guidelines.html#AEN200 (Performance data) |
||
261 | - https://nagios-plugins.org/doc/guidelines.html#PLUGOPTIONS (Plugin Options) |
||
262 | - https://nagios-plugins.org/doc/guidelines.html#AEN302 (Option Processing) |
||
263 | Note: The screen output of the help page will (mostly) be limited to 80 characters width; but the max recommended length of 23 lines cannot be guaranteed. |
||
264 | |||
265 | This framework does currently NOT support following guidelines: |
||
266 | - https://nagios-plugins.org/doc/guidelines.html#AEN74 (Screen Output) |
||
267 | - https://nagios-plugins.org/doc/guidelines.html#AEN239 (Translations) |
||
268 | - https://nagios-plugins.org/doc/guidelines.html#AEN293 (Use DEFAULT_SOCKET_TIMEOUT) |
||
269 | - https://nagios-plugins.org/doc/guidelines.html#AEN296 (Add alarms to network plugins) |
||
270 | - https://nagios-plugins.org/doc/guidelines.html#AEN245 (Don't execute system commands without specifying their full path) |
||
271 | - https://nagios-plugins.org/doc/guidelines.html#AEN249 (Use spopen() if external commands must be executed) |
||
272 | - https://nagios-plugins.org/doc/guidelines.html#AEN253 (Don't make temp files unless absolutely required) |
||
273 | - https://nagios-plugins.org/doc/guidelines.html#AEN259 (Validate all input) |
||
274 | - https://nagios-plugins.org/doc/guidelines.html#AEN317 (Plugins with more than one type of threshold, or with threshold ranges) |
||
275 | |||
276 | We will intentionally NOT follow the following guidelines: |
||
277 | - https://nagios-plugins.org/doc/guidelines.html#AEN256 (Don't be tricked into following symlinks) |
||
278 | Reason: We believe that this guideline is contraproductive. |
||
279 | Nagios plugins usually run as user 'nagios'. It is the task of the system administrator |
||
280 | to ensure that the user 'nagios' must not read/write to files which are not intended |
||
281 | for access by the Nagios service. Instead, symlinks are useful for several tasks. |
||
282 | See also http://stackoverflow.com/questions/27112949/nagios-plugins-why-not-following-symlinks |
||
283 | |||
284 | VNag over HTTP: |
||
285 | |||
286 | A script that uses the VNag framework can run as CLI script (normal Nagios plugin) or as web site (or both). |
||
287 | Having the script run as website, you can include a Nagios information combined with a human friendly HTML output which can |
||
288 | include colors, graphics (like charts) etc. |
||
289 | |||
290 | For example: |
||
291 | A script that measures traffic can have a website which shows graphs, |
||
292 | and has a hidden Nagios output included, which can be read by a Nagios plugin that |
||
293 | converts the hidden information on that website into an output that Nagios can evaluate. |
||
294 | |||
295 | Here is a comparison of the usage and behavior of VNag in regards to CLI and HTTP calls: |
||
296 | |||
297 | ------------------------------------------------------------------------------------------ |
||
298 | CLI script HTTP script |
||
299 | ------------------------------------------------------------------------------------------ |
||
300 | * "echo" will be discarded. * "echo" output will be discarded. |
||
301 | |||
302 | * Exceptions will be handled. * Exceptions will be handled. |
||
303 | |||
304 | * outputHTML() will be ignored. * outputHTML() will be handled. |
||
305 | (This allows you to have the same script |
||
306 | running as CLI and HTML) |
||
307 | |||
308 | * Arguments are passed via CLI. * Arguments are passed via $_REQUEST |
||
309 | (i.e. GET or POST) |
||
310 | |||
311 | * Arguments: "-vvv" * Arguments: GET ?v[]=&v[]=&v[]= or POST |
||
312 | |||
313 | * When run() has finished, the program * When run() has finished, the program |
||
314 | flow continues, although it is not flow continues. |
||
315 | recommended that you do anything after it. |
||
316 | (The exit code is remembered for the |
||
317 | shutdown handler) |
||
318 | |||
319 | * Exactly 1 job must be called, resulting * You can call as many jobs as you want. |
||
320 | in a single output of that job. A website can include more than one |
||
321 | Nagios output which are enumerated with |
||
322 | a serial number (0,1,2,3,...) or manual ID. |
||
323 | ------------------------------------------------------------------------------------------ |
||
324 | |||
325 | ****************************************************************************************************/ |
||
326 | |||
22 | daniel-mar | 327 | if (!VNag::is_http_mode()) error_reporting(E_ALL); |
2 | daniel-mar | 328 | |
329 | # If you want to use -t/--timeout with your module, you must add following line in your module code: |
||
330 | // WONTFIX: declare(ticks=1) is deprecated? http://www.hackingwithphp.com/4/21/0/the-declare-function-and-ticks |
||
331 | // WONTFIX: check is the main script used declare(ticks=1). (Not possible in PHP) |
||
332 | declare(ticks=1); |
||
333 | |||
334 | # Attention: The -t/--timeout parameter does not respect the built-in set_time_limit() of PHP. |
||
335 | # PHP should set this time limit to infinite. |
||
336 | set_time_limit(0); |
||
337 | |||
13 | daniel-mar | 338 | define('VNAG_JSONDATA_V1', 'oid:1.3.6.1.4.1.37476.2.3.1.1'); // {iso(1) identified-organization(3) dod(6) internet(1) private(4) enterprise(1) 37476 products(2) vnag(3) jsondata(1) v1(1)} |
2 | daniel-mar | 339 | |
340 | // Set this to an array to overwrite getopt() and $_REQUEST[], respectively. |
||
341 | // Useful for mock tests. |
||
342 | $OVERWRITE_ARGUMENTS = null; |
||
343 | |||
344 | function _empty($x) { |
||
345 | // Returns true for '' or null. Does not return true for value 0 or '0' (like empty() does) |
||
346 | return trim($x) == ''; |
||
347 | } |
||
348 | |||
349 | abstract class VNag { |
||
31 | daniel-mar | 350 | /*public*/ const VNAG_VERSION = '2021-06-24'; |
2 | daniel-mar | 351 | |
352 | // Status 0..3 for STATUSMODEL_SERVICE (the default status model): |
||
353 | # The guideline states: "Higher-level errors (such as name resolution errors, socket timeouts, etc) are outside of the control of plugins and should generally NOT be reported as UNKNOWN states." |
||
354 | # We choose 4 as exitcode. The plugin developer is free to return any other status. |
||
20 | daniel-mar | 355 | /*public*/ const STATUS_OK = 0; |
356 | /*public*/ const STATUS_WARNING = 1; |
||
357 | /*public*/ const STATUS_CRITICAL = 2; |
||
358 | /*public*/ const STATUS_UNKNOWN = 3; |
||
359 | /*public*/ const STATUS_ERROR = 4; // and upwards |
||
2 | daniel-mar | 360 | |
361 | // Status 0..1 for STATUSMODEL_HOST: |
||
362 | // The page https://blog.centreon.com/good-practices-how-to-develop-monitoring-plugin-nagios/ |
||
363 | // states that host plugins may return following status codes: |
||
364 | // 0=UP, 1=DOWN, Other=Maintains last known state |
||
20 | daniel-mar | 365 | /*public*/ const STATUS_UP = 0; |
366 | /*public*/ const STATUS_DOWN = 1; |
||
367 | /*public*/ const STATUS_MAINTAIN = 2; // and upwards |
||
2 | daniel-mar | 368 | |
20 | daniel-mar | 369 | /*public*/ const VERBOSITY_SUMMARY = 0; |
370 | /*public*/ const VERBOSITY_ADDITIONAL_INFORMATION = 1; |
||
371 | /*public*/ const VERBOSITY_CONFIGURATION_DEBUG = 2; |
||
372 | /*public*/ const VERBOSITY_PLUGIN_DEBUG = 3; |
||
373 | /*public*/ const MAX_VERBOSITY = self::VERBOSITY_PLUGIN_DEBUG; |
||
2 | daniel-mar | 374 | |
20 | daniel-mar | 375 | /*public*/ const STATUSMODEL_SERVICE = 0; |
376 | /*public*/ const STATUSMODEL_HOST = 1; |
||
2 | daniel-mar | 377 | |
378 | private $initialized = false; |
||
379 | |||
380 | private $status = null; |
||
381 | private $messages = array(); // array of messages which are all put together into the headline, comma separated |
||
382 | private $verbose_info = ''; // all other lines |
||
383 | private $warningRanges = array(); |
||
384 | private $criticalRanges = array(); |
||
385 | private $performanceDataObjects = array(); |
||
386 | private static $exitcode = 0; |
||
387 | |||
388 | private $helpObj = null; |
||
389 | private $argHandler = null; |
||
390 | |||
20 | daniel-mar | 391 | /*public*/ const OUTPUT_NEVER = 0; |
392 | /*public*/ const OUTPUT_SPECIAL = 1; // illegal usage / help page, version page |
||
393 | /*public*/ const OUTPUT_NORMAL = 2; |
||
394 | /*public*/ const OUTPUT_EXCEPTION = 4; |
||
395 | /*public*/ const OUTPUT_ALWAYS = 7; // = OUTPUT_SPECIAL+OUTPUT_NORMAL+OUTPUT_EXCEPTION |
||
2 | daniel-mar | 396 | |
19 | daniel-mar | 397 | public $http_visual_output = self::OUTPUT_ALWAYS; // show a human-readable panel? ... |
398 | public $http_invisible_output = self::OUTPUT_ALWAYS; // ... and/or show an invisible machine-readable tag? |
||
2 | daniel-mar | 399 | |
400 | // $html_before and $html_after contain the output HTML which were sent by the user |
||
401 | |||
402 | // before and after the visual output |
||
403 | protected $html_before = ''; |
||
404 | protected $html_after = ''; |
||
405 | |||
406 | protected $statusmodel = self::STATUSMODEL_SERVICE; |
||
407 | |||
408 | protected $show_status_in_headline = true; |
||
409 | |||
410 | protected $default_status = self::STATUS_UNKNOWN; |
||
411 | protected $default_warning_range = null; |
||
412 | protected $default_critical_range = null; |
||
413 | |||
414 | protected $argWarning; |
||
415 | protected $argCritical; |
||
416 | protected $argVersion; |
||
417 | protected $argVerbosity; |
||
418 | protected $argTimeout; |
||
419 | protected $argHelp; |
||
420 | protected $argUsage; |
||
421 | |||
422 | // ----------------------------------------------------------- |
||
423 | |||
21 | daniel-mar | 424 | // The ID will be used for writing AND reading of the machine-readable |
2 | daniel-mar | 425 | // Nagios output embedded in a website. (A web-reader acts as proxy, so the |
426 | // input and output ID will be equal) |
||
427 | // Attention: Once you run run(), $id will be "used" and resetted to null. |
||
428 | // The ID can be any string, e.g. a GUID, an OID, a package name or something else. |
||
429 | // It should be unique. If you don't set an ID, a serial number (0, 1, 2, 3, ...) will be |
||
430 | // used for your outputs. |
||
431 | public $id = null; |
||
432 | protected static $http_serial_number = 0; |
||
433 | |||
434 | // ----------------------------------------------------------- |
||
435 | |||
21 | daniel-mar | 436 | // Private key: Optional feature used in writeInvisibleHTML (called by run in HTTP mode) in order to sign/encrypt the output |
2 | daniel-mar | 437 | public $privkey = null; |
438 | public $privkey_password = null; |
||
21 | daniel-mar | 439 | public $sign_algo = null; // default: OPENSSL_ALGO_SHA256 |
2 | daniel-mar | 440 | |
21 | daniel-mar | 441 | // Public key: Optional feature used in a web-reader [readInvisibleHTML) to check the integrity of a message |
2 | daniel-mar | 442 | public $pubkey = null; |
443 | |||
444 | // ----------------------------------------------------------- |
||
445 | |||
446 | // These settings should be set by derivated classes where the user intuitively expects the |
||
447 | // warning (w) or critical (c) parameter to mean something else than defined in the development guidelines. |
||
448 | // Usually, the single value "-w X" means the same like "-w X:X", which means everything except X is bad. |
||
449 | // This behavior is VNag::SINGLEVALUE_RANGE_DEFAULT. |
||
450 | // But for plugins e.g. for checking disk space, the user expects the argument "-w X" to mean |
||
451 | // "everything below X is bad" (if X is defined as free disk space). |
||
452 | // So we would choose the setting VNag::SINGLEVALUE_RANGE_VAL_LT_X_BAD. |
||
453 | // Note: This setting is implemented as array, so that each range number (in case you want to have more |
||
454 | // than one range, like in the PING plugin that checks latency and package loss) |
||
455 | // can have its individual behavior for single values. |
||
456 | protected $warningSingleValueRangeBehaviors = array(self::SINGLEVALUE_RANGE_DEFAULT); |
||
457 | protected $criticalSingleValueRangeBehaviors = array(self::SINGLEVALUE_RANGE_DEFAULT); |
||
458 | |||
459 | // Default behavior according to the development guidelines: |
||
460 | // x means x:x, which means, everything except x% is bad. |
||
461 | // @x means @x:x, which means, x is bad and everything else is good. |
||
462 | const SINGLEVALUE_RANGE_DEFAULT = 0; |
||
463 | |||
464 | // The single value x means, everything > x is bad. @x is not defined. |
||
465 | const SINGLEVALUE_RANGE_VAL_GT_X_BAD = 1; |
||
466 | |||
467 | // The single value x means, everything >= x is bad. @x is not defined. |
||
468 | const SINGLEVALUE_RANGE_VAL_GE_X_BAD = 2; |
||
469 | |||
470 | // The single value x means, everything < x is bad. @x is not defined. |
||
471 | const SINGLEVALUE_RANGE_VAL_LT_X_BAD = 3; |
||
472 | |||
473 | // The single value x means, everything <= x is bad. @x is not defined. |
||
474 | const SINGLEVALUE_RANGE_VAL_LE_X_BAD = 4; |
||
475 | |||
476 | // ----------------------------------------------------------- |
||
477 | |||
478 | // Encryption password: Optional feature used in writeInvisibleHTML (called by run in HTTP mode) |
||
479 | public $password_out = null; |
||
480 | |||
21 | daniel-mar | 481 | // Decryption password: Used in readInvisibleHTML to decrypt an encrypted machine-readable info |
2 | daniel-mar | 482 | public $password_in = null; |
483 | |||
484 | // ----------------------------------------------------------- |
||
485 | |||
486 | public static function is_http_mode() { |
||
487 | return php_sapi_name() !== 'cli'; |
||
488 | } |
||
489 | |||
490 | public function getHelpManager() { |
||
491 | return $this->helpObj; |
||
492 | } |
||
493 | |||
494 | public function getArgumentHandler() { |
||
495 | return $this->argHandler; |
||
496 | } |
||
497 | |||
498 | public function outputHTML($text, $after_visual_output=true) { |
||
499 | if ($this->is_http_mode()) { |
||
500 | if ($this->initialized) { |
||
501 | if ($after_visual_output) { |
||
502 | $this->html_after .= $text; |
||
503 | } else { |
||
504 | $this->html_before .= $text; |
||
505 | } |
||
506 | } else { |
||
507 | echo $text; |
||
508 | } |
||
509 | } |
||
510 | } |
||
511 | |||
512 | protected function resetArguments() { |
||
513 | $this->argWarning = null; |
||
514 | $this->argCritical = null; |
||
515 | $this->argVersion = null; |
||
516 | $this->argVerbosity = null; |
||
517 | $this->argTimeout = null; |
||
518 | $this->argHelp = null; |
||
519 | // $this->argUsage = null; |
||
520 | |||
521 | // Also remove cache |
||
23 | daniel-mar | 522 | $this->argWarning = null; |
523 | $this->argCritical = null; |
||
2 | daniel-mar | 524 | } |
525 | |||
526 | // e.g. $args = "wcVvht" |
||
527 | public function registerExpectedStandardArguments($args) { |
||
528 | $this->resetArguments(); |
||
529 | |||
530 | for ($i=0; $i<strlen($args); $i++) { |
||
531 | switch ($args[$i]) { |
||
532 | case 'w': |
||
533 | $this->addExpectedArgument($this->argWarning = new VNagArgument('w', 'warning', VNagArgument::VALUE_REQUIRED, VNagLang::$argname_value, VNagLang::$warning_range)); |
||
534 | break; |
||
535 | case 'c': |
||
536 | $this->addExpectedArgument($this->argCritical = new VNagArgument('c', 'critical', VNagArgument::VALUE_REQUIRED, VNagLang::$argname_value, VNagLang::$critical_range)); |
||
537 | break; |
||
538 | case 'V': |
||
539 | $this->addExpectedArgument($this->argVersion = new VNagArgument('V', 'version', VNagArgument::VALUE_FORBIDDEN, null, VNagLang::$prints_version)); |
||
540 | break; |
||
541 | case 'v': |
||
542 | // In HTTP: -vvv is &v[]=&v[]=&v[]= |
||
543 | $this->addExpectedArgument($this->argVerbosity = new VNagArgument('v', 'verbose', VNagArgument::VALUE_FORBIDDEN, null, VNagLang::$verbosity_helptext)); |
||
544 | break; |
||
545 | case 't': |
||
546 | // Attention: not every plugin supports it because of declare(ticks=1) needs to be written in the main script |
||
547 | $this->addExpectedArgument($this->argTimeout = new VNagArgument('t', 'timeout', VNagArgument::VALUE_REQUIRED, VNagLang::$argname_seconds, VNagLang::$timeout_helptext)); |
||
548 | break; |
||
549 | // case '?': |
||
550 | case 'h': |
||
551 | $this->addExpectedArgument($this->argHelp = new VNagArgument('h', 'help', VNagArgument::VALUE_FORBIDDEN, null, VNagLang::$help_helptext)); |
||
552 | break; |
||
553 | default: |
||
554 | $letter = $args[$i]; |
||
555 | throw new VNagInvalidStandardArgument(sprintf(VNagLang::$no_standard_arguments_with_letter, $letter)); |
||
29 | daniel-mar | 556 | #break; |
2 | daniel-mar | 557 | } |
558 | } |
||
559 | } |
||
560 | |||
561 | public function addExpectedArgument($argObj) { |
||
562 | // Emulate C++ "friend" access to hidden functions |
||
563 | |||
564 | // $this->helpObj->_addOption($argObj); |
||
565 | $helpObjAddEntryMethod = new ReflectionMethod($this->helpObj, '_addOption'); |
||
566 | $helpObjAddEntryMethod->setAccessible(true); |
||
567 | $helpObjAddEntryMethod->invoke($this->helpObj, $argObj); |
||
568 | |||
569 | // $this->argHandler->_addExpectedArgument($argObj); |
||
570 | $argHandlerAddEntryMethod = new ReflectionMethod($this->argHandler, '_addExpectedArgument'); |
||
571 | $argHandlerAddEntryMethod->setAccessible(true); |
||
572 | $argHandlerAddEntryMethod->invoke($this->argHandler, $argObj); |
||
573 | } |
||
574 | |||
575 | protected function createArgumentHandler() { |
||
576 | $this->argHandler = new VNagArgumentHandler(); |
||
577 | } |
||
578 | |||
579 | protected function createHelpObject() { |
||
580 | $this->helpObj = new VNagHelp(); |
||
581 | } |
||
582 | |||
583 | protected function checkInitialized() { |
||
584 | if (!$this->initialized) throw new VNagFunctionCallOutsideSession(); |
||
585 | } |
||
586 | |||
587 | protected function getVerbosityLevel() { |
||
588 | $this->checkInitialized(); // if (!$this->initialized) return false; |
||
589 | |||
590 | if (!isset($this->argVerbosity)) { |
||
591 | //The verbose argument is always optional |
||
592 | //throw new VNagRequiredArgumentNotRegistered('-v'); |
||
593 | return self::VERBOSITY_SUMMARY; |
||
594 | } else { |
||
595 | $level = $this->argVerbosity->count(); |
||
596 | if ($level > self::MAX_VERBOSITY) $level = self::MAX_VERBOSITY; |
||
597 | return $level; |
||
598 | } |
||
599 | } |
||
600 | |||
601 | public function getWarningRange($argumentNumber=0) { |
||
602 | $this->checkInitialized(); // if (!$this->initialized) return false; |
||
603 | |||
604 | if (!isset($this->warningRanges[$argumentNumber])) { |
||
605 | if (!is_null($this->argWarning)) { |
||
606 | $warning = $this->argWarning->getValue(); |
||
607 | if (!is_null($warning)) { |
||
608 | $vals = explode(',',$warning); |
||
609 | foreach ($vals as $number => $val) { |
||
610 | if (_empty($val)) { |
||
611 | $this->warningRanges[$number] = null; |
||
612 | } else { |
||
613 | $singleValueBehavior = isset($this->warningSingleValueRangeBehaviors[$number]) ? $this->warningSingleValueRangeBehaviors[$number] : VNag::SINGLEVALUE_RANGE_DEFAULT; |
||
614 | $this->warningRanges[$number] = new VNagRange($val, $singleValueBehavior); |
||
615 | } |
||
616 | } |
||
617 | } else { |
||
618 | $this->warningRanges[0] = $this->default_warning_range; |
||
619 | } |
||
620 | } else { |
||
621 | return null; |
||
622 | } |
||
623 | } |
||
624 | |||
625 | if (isset($this->warningRanges[$argumentNumber])) { |
||
626 | return $this->warningRanges[$argumentNumber]; |
||
627 | } else { |
||
628 | return null; |
||
629 | } |
||
630 | } |
||
631 | |||
632 | public function getCriticalRange($argumentNumber=0) { |
||
633 | $this->checkInitialized(); // if (!$this->initialized) return false; |
||
634 | |||
635 | if (!isset($this->criticalRanges[$argumentNumber])) { |
||
636 | if (!is_null($this->argCritical)) { |
||
637 | $critical = $this->argCritical->getValue(); |
||
638 | if (!is_null($critical)) { |
||
639 | $vals = explode(',',$critical); |
||
640 | foreach ($vals as $number => $val) { |
||
641 | $singleValueBehavior = isset($this->criticalSingleValueRangeBehaviors[$number]) ? $this->criticalSingleValueRangeBehaviors[$number] : VNag::SINGLEVALUE_RANGE_DEFAULT; |
||
642 | $this->criticalRanges[$number] = new VNagRange($val, $singleValueBehavior); |
||
643 | } |
||
644 | } else { |
||
645 | $this->criticalRanges[0] = $this->default_critical_range; |
||
646 | } |
||
647 | } else { |
||
648 | return null; |
||
649 | } |
||
650 | } |
||
651 | |||
652 | if (isset($this->criticalRanges[$argumentNumber])) { |
||
653 | return $this->criticalRanges[$argumentNumber]; |
||
654 | } else { |
||
655 | return null; |
||
656 | } |
||
657 | } |
||
658 | |||
659 | public function checkAgainstWarningRange($values, $force=true, $autostatus=true, $argumentNumber=0) { |
||
660 | $this->checkInitialized(); // if (!$this->initialized) return; |
||
661 | |||
662 | if (!$this->getArgumentHandler()->isArgRegistered('w')) { |
||
663 | // Developer's mistake: The argument is not in the list of expected arguments |
||
664 | throw new VNagRequiredArgumentNotRegistered('-w'); |
||
665 | } |
||
666 | |||
667 | $wr = $this->getWarningRange($argumentNumber); |
||
668 | if (isset($wr)) { |
||
669 | if ($wr->checkAlert($values)) { |
||
670 | if ($autostatus) $this->setStatus(VNag::STATUS_WARNING); |
||
671 | return true; |
||
672 | } else { |
||
673 | if ($autostatus) $this->setStatus(VNag::STATUS_OK); |
||
674 | return false; |
||
675 | } |
||
676 | } else { |
||
677 | if ($force) { |
||
678 | // User's mistake: They did not pass the argument to the plugin |
||
679 | if (($argumentNumber > 0) && (count($this->warningRanges) > 0)) { |
||
680 | throw new VNagInvalidArgumentException(sprintf(VNagLang::$too_few_warning_ranges, $argumentNumber+1)); |
||
681 | } else { |
||
682 | throw new VNagRequiredArgumentMissing('-w'); |
||
683 | } |
||
684 | } |
||
685 | } |
||
686 | } |
||
687 | |||
688 | public function checkAgainstCriticalRange($values, $force=true, $autostatus=true, $argumentNumber=0) { |
||
689 | $this->checkInitialized(); // if (!$this->initialized) return; |
||
690 | |||
691 | if (!$this->getArgumentHandler()->isArgRegistered('c')) { |
||
692 | // Developer's mistake: The argument is not in the list of expected arguments |
||
693 | throw new VNagRequiredArgumentNotRegistered('-c'); |
||
694 | } |
||
695 | |||
696 | $cr = $this->getCriticalRange($argumentNumber); |
||
697 | if (isset($cr)) { |
||
698 | if ($cr->checkAlert($values)) { |
||
699 | if ($autostatus) $this->setStatus(VNag::STATUS_CRITICAL); |
||
700 | return true; |
||
701 | } else { |
||
702 | if ($autostatus) $this->setStatus(VNag::STATUS_OK); |
||
703 | return false; |
||
704 | } |
||
705 | } else { |
||
706 | if ($force) { |
||
707 | // User's mistake: They did not pass the argument to the plugin |
||
708 | if (($argumentNumber > 0) && (count($this->warningRanges) > 0)) { |
||
709 | throw new VNagInvalidArgumentException(sprintf(VNagLang::$too_few_critical_ranges, $argumentNumber+1)); |
||
710 | } else { |
||
711 | throw new VNagRequiredArgumentMissing('-c'); |
||
712 | } |
||
713 | } |
||
714 | } |
||
715 | } |
||
716 | |||
717 | protected static function getBaddestExitcode($code1, $code2) { |
||
718 | return max($code1, $code2); |
||
719 | } |
||
720 | |||
721 | # DO NOT CALL MANUALLY |
||
722 | # Unfortunately, this function has to be public, otherwise register_shutdown_function() wouldn't work |
||
723 | public static function _shutdownHandler() { |
||
724 | if (!self::is_http_mode()) { |
||
725 | exit((int)self::$exitcode); |
||
726 | } |
||
727 | } |
||
728 | |||
729 | protected function _exit($code) { |
||
730 | self::$exitcode = $this->getBaddestExitcode($code, self::$exitcode); |
||
731 | } |
||
732 | |||
733 | private $constructed = false; |
||
734 | function __construct() { |
||
735 | $this->createHelpObject(); |
||
736 | $this->createArgumentHandler(); |
||
737 | |||
738 | $this->addExpectedArgument($this->argUsage = new VNagArgument('?', '', VNagArgument::VALUE_FORBIDDEN, null, VNagLang::$prints_usage)); |
||
739 | |||
740 | $this->constructed = true; |
||
741 | } |
||
742 | |||
743 | function __destruct() { |
||
744 | if (Timeouter::started()) { |
||
745 | Timeouter::end(); |
||
746 | } |
||
747 | } |
||
748 | |||
29 | daniel-mar | 749 | public function run() { |
19 | daniel-mar | 750 | global $inside_vnag_run; |
20 | daniel-mar | 751 | |
19 | daniel-mar | 752 | $inside_vnag_run = true; |
2 | daniel-mar | 753 | try { |
19 | daniel-mar | 754 | if (!$this->constructed) { |
755 | throw new VNagNotConstructed(VNagLang::$notConstructed); |
||
756 | } |
||
2 | daniel-mar | 757 | |
19 | daniel-mar | 758 | try { |
759 | $this->initialized = true; |
||
760 | $this->html_before = ''; |
||
761 | $this->html_after = ''; |
||
762 | $this->setStatus(null, true); |
||
763 | $this->messages = array(); |
||
2 | daniel-mar | 764 | |
19 | daniel-mar | 765 | register_shutdown_function(array($this, '_shutdownHandler')); |
2 | daniel-mar | 766 | |
19 | daniel-mar | 767 | if ($this->argHandler->illegalUsage()) { |
768 | $content = $this->helpObj->printUsagePage(); |
||
769 | $this->setStatus(VNag::STATUS_UNKNOWN); |
||
770 | |||
771 | if ($this->is_http_mode()) { |
||
772 | echo $this->html_before; |
||
773 | if ($this->http_visual_output & VNag::OUTPUT_SPECIAL) echo $this->writeVisualHTML($content); |
||
774 | if ($this->http_invisible_output & VNag::OUTPUT_SPECIAL) echo $this->writeInvisibleHTML($content); |
||
775 | echo $this->html_after; |
||
776 | return; // cancel |
||
777 | } else { |
||
778 | echo $content; |
||
779 | return $this->_exit($this->status); |
||
780 | } |
||
2 | daniel-mar | 781 | } |
782 | |||
19 | daniel-mar | 783 | if (!is_null($this->argVersion) && ($this->argVersion->available())) { |
784 | $content = $this->helpObj->printVersionPage(); |
||
785 | $this->setStatus(VNag::STATUS_UNKNOWN); |
||
2 | daniel-mar | 786 | |
19 | daniel-mar | 787 | if ($this->is_http_mode()) { |
788 | echo $this->html_before; |
||
789 | if ($this->http_visual_output & VNag::OUTPUT_SPECIAL) echo $this->writeVisualHTML($content); |
||
790 | if ($this->http_invisible_output & VNag::OUTPUT_SPECIAL) echo $this->writeInvisibleHTML($content); |
||
791 | echo $this->html_after; |
||
792 | return; // cancel |
||
793 | } else { |
||
794 | echo $content; |
||
795 | return $this->_exit($this->status); |
||
796 | } |
||
2 | daniel-mar | 797 | } |
798 | |||
19 | daniel-mar | 799 | if (!is_null($this->argHelp) && ($this->argHelp->available())) { |
800 | $content = $this->helpObj->printHelpPage(); |
||
801 | $this->setStatus(VNag::STATUS_UNKNOWN); |
||
2 | daniel-mar | 802 | |
19 | daniel-mar | 803 | if ($this->is_http_mode()) { |
804 | echo $this->html_before; |
||
805 | if ($this->http_visual_output & VNag::OUTPUT_SPECIAL) echo $this->writeVisualHTML($content); |
||
806 | if ($this->http_invisible_output & VNag::OUTPUT_SPECIAL) echo $this->writeInvisibleHTML($content); |
||
807 | echo $this->html_after; |
||
808 | return; // cancel |
||
809 | } else { |
||
810 | echo $content; |
||
811 | return $this->_exit($this->status); |
||
812 | } |
||
2 | daniel-mar | 813 | } |
814 | |||
19 | daniel-mar | 815 | // Initialize ranges (and check their validity) |
816 | $this->getWarningRange(); |
||
817 | $this->getCriticalRange(); |
||
2 | daniel-mar | 818 | |
19 | daniel-mar | 819 | if (!is_null($this->argTimeout)) { |
820 | $timeout = $this->argTimeout->getValue(); |
||
821 | if (!is_null($timeout)) { |
||
822 | Timeouter::start($timeout); |
||
823 | } |
||
2 | daniel-mar | 824 | } |
825 | |||
19 | daniel-mar | 826 | ob_start(); |
827 | $init_ob_level = ob_get_level(); |
||
828 | try { |
||
29 | daniel-mar | 829 | $this->cbRun(); |
2 | daniel-mar | 830 | |
19 | daniel-mar | 831 | // This will NOT be put in the 'finally' block, because otherwise it would trigger if an Exception happened (Which clears the OB) |
832 | if (ob_get_level() < $init_ob_level) throw new VNagImplementationErrorException(VNagLang::$output_level_lowered); |
||
833 | } finally { |
||
834 | while (ob_get_level() > $init_ob_level) @ob_end_clean(); |
||
835 | } |
||
2 | daniel-mar | 836 | |
19 | daniel-mar | 837 | if (is_null($this->status)) $this->setStatus($this->default_status,true); |
2 | daniel-mar | 838 | |
19 | daniel-mar | 839 | $outputType = VNag::OUTPUT_NORMAL; |
840 | } catch (Exception $e) { |
||
841 | $this->handleException($e); |
||
842 | $outputType = VNag::OUTPUT_EXCEPTION; |
||
843 | } |
||
2 | daniel-mar | 844 | |
19 | daniel-mar | 845 | if ($this->is_http_mode()) { |
846 | echo $this->html_before; |
||
847 | if ($this->http_invisible_output & $outputType) { |
||
848 | echo $this->writeInvisibleHTML(); |
||
849 | } |
||
850 | if ($this->http_visual_output & $outputType) { |
||
851 | echo $this->writeVisualHTML(); |
||
852 | } |
||
853 | echo $this->html_after; |
||
854 | } else { |
||
855 | echo $this->getNagiosConsoleText(); |
||
856 | return $this->_exit($this->status); |
||
2 | daniel-mar | 857 | } |
19 | daniel-mar | 858 | |
859 | Timeouter::end(); |
||
860 | } finally { |
||
861 | $inside_vnag_run = false; |
||
2 | daniel-mar | 862 | } |
863 | } |
||
864 | |||
865 | private function getNagiosConsoleText() { |
||
866 | // see https://nagios-plugins.org/doc/guidelines.html#AEN200 |
||
867 | // 1. space separated list of label/value pairs |
||
868 | $ary_perfdata = $this->getPerformanceData(); |
||
869 | $performancedata_first = array_shift($ary_perfdata); |
||
870 | $performancedata_rest = implode(' ', $ary_perfdata); |
||
871 | |||
872 | $status_text = VNagLang::status($this->status, $this->statusmodel); |
||
873 | if (_empty($this->getHeadline())) { |
||
874 | $content = $status_text; |
||
875 | } else { |
||
876 | if ($this->show_status_in_headline) { |
||
877 | $content = $status_text.': '.$this->getHeadline(); |
||
878 | } else { |
||
879 | $content = $this->getHeadline(); |
||
880 | } |
||
881 | } |
||
882 | |||
883 | if (!_empty($performancedata_first)) $content .= '|'.trim($performancedata_first); |
||
884 | $content .= "\n"; |
||
885 | if (!_empty($this->verbose_info)) { |
||
886 | //$content .= "\n".VNagLang::$verbose_info.":\n\n"; |
||
887 | $content .= trim($this->verbose_info); |
||
888 | } |
||
889 | if (!_empty($performancedata_rest)) $content .= '|'.trim($performancedata_rest); |
||
890 | $content .= "\n"; |
||
891 | |||
892 | return trim($content)."\n"; |
||
893 | } |
||
894 | |||
895 | abstract protected function cbRun(); |
||
896 | |||
897 | public function addPerformanceData($prefDataObj, $move_to_font=false, $verbosityLevel=VNag::VERBOSITY_SUMMARY) { |
||
898 | $this->checkInitialized(); // if (!$this->initialized) return; |
||
899 | |||
900 | if ((!isset($this->argVerbosity)) && ($verbosityLevel > VNag::VERBOSITY_SUMMARY)) throw new VNagRequiredArgumentNotRegistered('-v'); |
||
901 | if (self::getVerbosityLevel() < $verbosityLevel) return false; |
||
902 | |||
903 | if ($move_to_font) { |
||
904 | array_unshift($this->performanceDataObjects, $prefDataObj); |
||
905 | } else { |
||
906 | $this->performanceDataObjects[] = $prefDataObj; |
||
907 | } |
||
908 | |||
909 | return true; |
||
910 | } |
||
911 | |||
912 | public function getPerformanceData() { |
||
913 | $this->checkInitialized(); // if (!$this->initialized) return null; |
||
914 | |||
915 | // see https://nagios-plugins.org/doc/guidelines.html#AEN200 |
||
916 | // 1. space separated list of label/value pairs |
||
917 | return $this->performanceDataObjects; |
||
918 | } |
||
919 | |||
920 | public function removePerformanceData($prefDataObj) { |
||
921 | if (($key = array_search($prefDataObj, $this->performanceDataObjects, true)) !== false) { |
||
922 | unset($this->performanceDataObjects[$key]); |
||
923 | return true; |
||
924 | } else { |
||
925 | return false; |
||
926 | } |
||
927 | } |
||
928 | |||
929 | public function clearPerformanceData() { |
||
930 | $this->performanceDataObjects = array(); |
||
931 | } |
||
932 | |||
933 | public function getVerboseInfo() { |
||
934 | return $this->verbose_info; |
||
935 | } |
||
936 | |||
937 | public function clearVerboseInfo() { |
||
938 | $this->verbose_info = ''; |
||
939 | } |
||
940 | |||
941 | private function writeVisualHTML($special_content=null) { |
||
942 | if (!_empty($special_content)) { |
||
943 | $content = $special_content; |
||
944 | } else { |
||
945 | $content = strtoupper(VNagLang::$status.': '.VNagLang::status($this->status, $this->statusmodel))."\n\n"; |
||
946 | |||
947 | $content .= strtoupper(VNagLang::$message).":\n"; |
||
948 | $status_text = VNagLang::status($this->status, $this->statusmodel); |
||
949 | if (_empty($this->getHeadline())) { |
||
950 | $content .= $status_text; |
||
951 | } else { |
||
952 | if ($this->show_status_in_headline) { |
||
953 | $content .= $status_text.': '.trim($this->getHeadline()); |
||
954 | } else { |
||
955 | $content .= trim($this->getHeadline()); |
||
956 | } |
||
957 | } |
||
958 | $content .= "\n\n"; |
||
959 | |||
960 | if (!_empty($this->verbose_info)) { |
||
961 | $content .= strtoupper(VNagLang::$verbose_info).":\n".trim($this->verbose_info)."\n\n"; |
||
962 | } |
||
963 | |||
964 | $perfdata = $this->getPerformanceData(); |
||
965 | if (count($perfdata) > 0) { |
||
966 | $content .= strtoupper(VNagLang::$performance_data).":\n"; |
||
967 | foreach ($perfdata as $pd) { |
||
968 | $content .= trim($pd)."\n"; |
||
969 | } |
||
970 | $content .= "\n"; |
||
971 | } |
||
972 | } |
||
973 | |||
974 | $colorinfo = ''; |
||
975 | $status = $this->getStatus(); |
||
976 | |||
977 | if ($status == VNag::STATUS_OK) $colorinfo = ' style="background-color:green;color:white;font-weight:bold"'; |
||
978 | else if ($status == VNag::STATUS_WARNING) $colorinfo = ' style="background-color:yellow;color:black;font-weight:bold"'; |
||
979 | else if ($status == VNag::STATUS_CRITICAL) $colorinfo = ' style="background-color:red;color:white;font-weight:bold"'; |
||
980 | else if ($status == VNag::STATUS_ERROR) $colorinfo = ' style="background-color:purple;color:white;font-weight:bold"'; |
||
981 | else /* if ($status == VNag::STATUS_UNKNOWN) */ $colorinfo = ' style="background-color:lightgray;color:black;font-weight:bold"'; |
||
982 | |||
983 | $html_content = trim($content); |
||
984 | $html_content = htmlentities($html_content); |
||
985 | $html_content = str_replace(' ', ' ', $html_content); |
||
986 | $html_content = nl2br($html_content); |
||
987 | |||
988 | // FUT: Allow individual design via CSS |
||
989 | return '<table border="1" cellspacing="2" cellpadding="2" style="width:100%" class="vnag_table">'. |
||
990 | '<tr'.$colorinfo.' class="vnag_title_row">'. |
||
991 | '<td>'.VNagLang::$nagios_output.'</td>'. |
||
992 | '</tr>'. |
||
993 | '<tr class="vnag_message_row">'. |
||
994 | '<td><code>'. |
||
995 | $html_content. |
||
996 | '</code></td>'. |
||
997 | '</tr>'. |
||
998 | '</table>'; |
||
999 | } |
||
1000 | |||
1001 | protected function readInvisibleHTML($html) { |
||
1002 | $this->checkInitialized(); // if (!$this->initialized) return; |
||
1003 | |||
1004 | $doc = new DOMDocument(); // Requires: aptitude install php-dom |
||
1005 | @$doc->loadHTML($html); // added '@' because we don't want a warning for the non-standard <vnag> tag |
||
1006 | |||
1007 | $tags = $doc->getElementsByTagName('script'); |
||
1008 | foreach ($tags as $tag) { |
||
1009 | $type = $tag->getAttribute('type'); |
||
1010 | if ($type !== 'application/json') continue; |
||
1011 | |||
1012 | $json = $tag->nodeValue; |
||
1013 | if (!$json) continue; |
||
1014 | |||
1015 | $data = @json_decode($json,true); |
||
1016 | if (!is_array($data)) continue; |
||
1017 | |||
1018 | if (!isset($data['type'])) continue; |
||
1019 | if ($data['type'] === VNAG_JSONDATA_V1) { |
||
1020 | if (!isset($data['datasets'])) throw new VNagWebInfoException(VNagLang::$dataset_missing); |
||
1021 | foreach ($data['datasets'] as $dataset) { |
||
1022 | $payload = base64_decode($dataset['payload']); |
||
1023 | if (!$payload) { |
||
1024 | throw new VNagWebInfoException(VNagLang::$payload_not_base64); |
||
1025 | } |
||
1026 | |||
1027 | if (isset($dataset['encryption'])) { |
||
1028 | // The dataset is encrypted. We need to decrypt it first. |
||
1029 | |||
1030 | $cryptInfo = $dataset['encryption']; |
||
1031 | if (!is_array($cryptInfo)) { |
||
1032 | throw new VNagWebInfoException(VNagLang::$dataset_encryption_no_array); |
||
1033 | } |
||
1034 | |||
1035 | $password = is_null($this->password_in) ? '' : $this->password_in; |
||
1036 | |||
1037 | $salt = base64_decode($cryptInfo['salt']); |
||
1038 | |||
1039 | if ($cryptInfo['hash'] != hash('sha256',$salt.$password)) { |
||
1040 | if ($password == '') { |
||
1041 | throw new VNagWebInfoException(VNagLang::$require_password); |
||
1042 | } else { |
||
1043 | throw new VNagWebInfoException(VNagLang::$wrong_password); |
||
1044 | } |
||
1045 | } |
||
1046 | |||
21 | daniel-mar | 1047 | if (!function_exists('openssl_decrypt')) { |
1048 | throw new VNagException(VNagLang::$openssl_missing); |
||
1049 | } |
||
1050 | |||
2 | daniel-mar | 1051 | $payload = openssl_decrypt($payload, $cryptInfo['method'], $password, 0, $cryptInfo['iv']); |
1052 | } |
||
1053 | |||
27 | daniel-mar | 1054 | if (!is_null($this->pubkey) && ($this->pubkey !== '')) { |
24 | daniel-mar | 1055 | if (substr($this->pubkey,0,3) === '---') { |
1056 | $public_key = $this->pubkey; |
||
1057 | } else { |
||
1058 | if (!file_exists($this->pubkey)) { |
||
1059 | throw new VNagInvalidArgumentException(sprintf(VNagLang::$pubkey_file_not_found, $this->pubkey)); |
||
1060 | } |
||
2 | daniel-mar | 1061 | |
24 | daniel-mar | 1062 | $public_key = @file_get_contents($this->pubkey); |
1063 | if (!$public_key) { |
||
1064 | throw new VNagPublicKeyException(sprintf(VNagLang::$pubkey_file_not_readable, $this->pubkey)); |
||
1065 | } |
||
2 | daniel-mar | 1066 | } |
1067 | |||
1068 | if (!isset($dataset['signature'])) { |
||
1069 | throw new VNagSignatureException(VNagLang::$signature_missing); |
||
1070 | } |
||
1071 | |||
1072 | $signature = base64_decode($dataset['signature']); |
||
1073 | if (!$signature) { |
||
1074 | throw new VNagSignatureException(VNagLang::$signature_not_bas64); |
||
1075 | } |
||
1076 | |||
21 | daniel-mar | 1077 | if (!function_exists('openssl_verify')) { |
1078 | throw new VNagException(VNagLang::$openssl_missing); |
||
1079 | } |
||
1080 | |||
1081 | $sign_algo = is_null($this->sign_algo) ? OPENSSL_ALGO_SHA256 : $this->sign_algo; |
||
1082 | if (!openssl_verify($payload, $signature, $public_key, $sign_algo)) { |
||
2 | daniel-mar | 1083 | throw new VNagSignatureException(VNagLang::$signature_invalid); |
1084 | } |
||
1085 | } |
||
1086 | |||
1087 | $payload = @json_decode($payload,true); |
||
1088 | if (!$payload) { |
||
1089 | throw new VNagWebInfoException(VNagLang::$payload_not_json); |
||
1090 | } |
||
1091 | |||
1092 | if ($payload['id'] == $this->id) { |
||
1093 | return $payload; |
||
1094 | } |
||
1095 | } |
||
1096 | } |
||
1097 | } |
||
1098 | |||
1099 | return null; |
||
1100 | } |
||
1101 | |||
1102 | private function getNextMonitorID($peek=false) { |
||
1103 | $result = is_null($this->id) ? self::$http_serial_number : $this->id; |
||
1104 | |||
1105 | if (!$peek) { |
||
1106 | $this->id = null; // use manual ID only once |
||
1107 | self::$http_serial_number++; |
||
1108 | } |
||
1109 | |||
1110 | return $result; |
||
1111 | } |
||
1112 | |||
1113 | private function writeInvisibleHTML($special_content=null) { |
||
1114 | // 1. Create the payload |
||
1115 | |||
1116 | $payload['id'] = $this->getNextMonitorID(); |
||
1117 | |||
1118 | $payload['status'] = $this->getStatus(); |
||
1119 | |||
1120 | if (!_empty($special_content)) { |
||
1121 | $payload['text'] = $special_content; |
||
1122 | } else { |
||
1123 | $payload['headline'] = $this->getHeadline(); |
||
1124 | $payload['verbose_info'] = $this->verbose_info; |
||
1125 | |||
1126 | $payload['performance_data'] = array(); |
||
1127 | foreach ($this->performanceDataObjects as $perfdata) { |
||
1128 | $payload['performance_data'][] = (string)$perfdata; |
||
1129 | } |
||
1130 | } |
||
1131 | |||
1132 | $payload = json_encode($payload); |
||
1133 | |||
1134 | // 2. Encode the payload as JSON and optionally sign and/or encrypt it |
||
1135 | |||
1136 | $dataset = array(); |
||
1137 | |||
27 | daniel-mar | 1138 | if (!is_null($this->privkey) && ($this->privkey !== '')) { |
21 | daniel-mar | 1139 | if (!function_exists('openssl_pkey_get_private') || !function_exists('openssl_sign')) { |
1140 | throw new VNagException(VNagLang::$openssl_missing); |
||
1141 | } |
||
1142 | |||
24 | daniel-mar | 1143 | if (substr($this->privkey,0,3) === '---') { |
1144 | $pkeyid = @openssl_pkey_get_private($this->privkey, $this->privkey_password); |
||
1145 | if (!$pkeyid) { |
||
1146 | throw new VNagPrivateKeyException(sprintf(VNagLang::$privkey_not_readable)); |
||
1147 | } |
||
1148 | } else { |
||
1149 | if (!file_exists($this->privkey)) { |
||
1150 | throw new VNagInvalidArgumentException(sprintf(VNagLang::$privkey_file_not_found, $this->privkey)); |
||
1151 | } |
||
1152 | $pkeyid = @openssl_pkey_get_private('file://'.$this->privkey, $this->privkey_password); |
||
1153 | if (!$pkeyid) { |
||
1154 | throw new VNagPrivateKeyException(sprintf(VNagLang::$privkey_file_not_readable, $this->privkey)); |
||
1155 | } |
||
2 | daniel-mar | 1156 | } |
1157 | |||
22 | daniel-mar | 1158 | $signature = ''; |
24 | daniel-mar | 1159 | $sign_algo = is_null($this->sign_algo) ? OPENSSL_ALGO_SHA256 : $this->sign_algo; |
1160 | if (@openssl_sign($payload, $signature, $pkeyid, $sign_algo)) { |
||
19 | daniel-mar | 1161 | openssl_free_key($pkeyid); |
2 | daniel-mar | 1162 | |
19 | daniel-mar | 1163 | $dataset['signature'] = base64_encode($signature); |
24 | daniel-mar | 1164 | } else { |
1165 | throw new VNagPrivateKeyException(sprintf(VNagLang::$signature_failed)); |
||
19 | daniel-mar | 1166 | } |
2 | daniel-mar | 1167 | } |
1168 | |||
25 | daniel-mar | 1169 | if (!is_null($this->password_out) && ($this->password_out !== '')) { |
21 | daniel-mar | 1170 | if (!function_exists('openssl_encrypt')) { |
1171 | throw new VNagException(VNagLang::$openssl_missing); |
||
1172 | } |
||
1173 | |||
2 | daniel-mar | 1174 | $password = $this->password_out; |
1175 | |||
1176 | $method = 'aes-256-ofb'; |
||
1177 | $iv = substr(hash('sha256', openssl_random_pseudo_bytes(32)), 0, 16); |
||
1178 | $salt = openssl_random_pseudo_bytes(32); |
||
1179 | |||
1180 | $cryptInfo = array(); |
||
1181 | $cryptInfo['method'] = $method; |
||
1182 | $cryptInfo['iv'] = $iv; |
||
1183 | $cryptInfo['salt'] = base64_encode($salt); |
||
1184 | $cryptInfo['hash'] = hash('sha256', $salt.$password); |
||
1185 | |||
1186 | $payload = openssl_encrypt($payload, $method, $password, 0, $iv); |
||
1187 | $dataset['encryption'] = $cryptInfo; |
||
1188 | } |
||
1189 | |||
1190 | $dataset['payload'] = base64_encode($payload); |
||
1191 | |||
1192 | // 3. Encode everything as JSON+Base64 (again) and put it into the data block |
||
1193 | |||
1194 | $json = array(); |
||
1195 | $json['type'] = VNAG_JSONDATA_V1; |
||
1196 | $json['datasets'] = array($dataset); // we only output 1 dataset. We could technically output more than one into this data block. |
||
1197 | |||
21 | daniel-mar | 1198 | // Include the machine-readable information as data block |
2 | daniel-mar | 1199 | // This method was chosen to support HTML 4.01, XHTML and HTML5 as well without breaking the standards |
1200 | // see https://stackoverflow.com/questions/51222713/using-an-individual-tag-without-breaking-the-standards/51223609#51223609 |
||
1201 | return '<script type="application/json">'. |
||
1202 | json_encode($json). |
||
1203 | '</script>'; |
||
1204 | } |
||
1205 | |||
1206 | protected function appendHeadline($msg) { |
||
1207 | $this->checkInitialized(); // if (!$this->initialized) return; |
||
1208 | |||
1209 | if (_empty($msg)) return false; |
||
1210 | $this->messages[] = $msg; |
||
1211 | |||
1212 | return true; |
||
1213 | } |
||
1214 | |||
1215 | protected function changeHeadline($msg) { |
||
1216 | $this->checkInitialized(); // if (!$this->initialized) return; |
||
1217 | |||
1218 | if (_empty($msg)) { |
||
1219 | $this->messages = array(); |
||
1220 | } else { |
||
1221 | $this->messages = array($msg); |
||
1222 | } |
||
1223 | |||
1224 | return true; |
||
1225 | } |
||
1226 | |||
1227 | public function setHeadline($msg, $append=false, $verbosityLevel=VNag::VERBOSITY_SUMMARY) { |
||
1228 | $this->checkInitialized(); // if (!$this->initialized) return; |
||
1229 | |||
1230 | if ((!isset($this->argVerbosity)) && ($verbosityLevel > VNag::VERBOSITY_SUMMARY)) throw new VNagRequiredArgumentNotRegistered('-v'); |
||
1231 | if (self::getVerbosityLevel() < $verbosityLevel) $msg = ''; |
||
1232 | |||
1233 | if ($append) { |
||
1234 | return $this->appendHeadline($msg); |
||
1235 | } else { |
||
1236 | return $this->changeHeadline($msg); |
||
1237 | } |
||
1238 | } |
||
1239 | |||
1240 | public function getHeadline() { |
||
1241 | $this->checkInitialized(); // if (!$this->initialized) return ''; |
||
1242 | |||
1243 | return implode(', ', $this->messages); |
||
1244 | } |
||
1245 | |||
1246 | public function addVerboseMessage($msg, $verbosityLevel=VNag::VERBOSITY_SUMMARY) { |
||
1247 | $this->checkInitialized(); // if (!$this->initialized) return; |
||
1248 | |||
1249 | if (self::getVerbosityLevel() >= $verbosityLevel) { |
||
1250 | $this->verbose_info .= $msg."\n"; |
||
1251 | } |
||
1252 | } |
||
1253 | |||
1254 | public function setStatus($status, $force=false) { |
||
1255 | $this->checkInitialized(); // if (!$this->initialized) return; |
||
1256 | |||
1257 | if (($force) || is_null($this->status) || ($status > $this->status)) { |
||
1258 | $this->status = $status; |
||
1259 | } |
||
1260 | } |
||
1261 | |||
1262 | public function getStatus() { |
||
1263 | $this->checkInitialized(); // if (!$this->initialized) return; |
||
1264 | |||
1265 | return $this->status; |
||
1266 | } |
||
1267 | |||
1268 | protected static function exceptionText($exception) { |
||
1269 | // $this->checkInitialized(); // if (!$this->initialized) return false; |
||
1270 | |||
1271 | $class = get_class($exception); |
||
1272 | $msg = $exception->getMessage(); |
||
1273 | |||
1274 | if (!_empty($msg)) { |
||
1275 | return sprintf(VNagLang::$exception_x, $msg, $class); |
||
1276 | } else { |
||
1277 | return sprintf(VNagLang::$unhandled_exception_without_msg, $class); |
||
1278 | } |
||
1279 | } |
||
1280 | |||
1281 | protected function handleException($exception) { |
||
1282 | $this->checkInitialized(); // if (!$this->initialized) return; |
||
1283 | |||
19 | daniel-mar | 1284 | if (!VNag::is_http_mode()) { |
1285 | // On console output, remove anything we have written so far! |
||
1286 | while (ob_get_level() > 0) @ob_end_clean(); |
||
1287 | } |
||
2 | daniel-mar | 1288 | $this->clearVerboseInfo(); |
1289 | $this->clearPerformanceData(); |
||
1290 | |||
1291 | if ($exception instanceof VNagException) { |
||
1292 | $this->setStatus($exception->getStatus()); |
||
1293 | } else { |
||
1294 | $this->setStatus(self::STATUS_ERROR); |
||
1295 | } |
||
1296 | |||
1297 | $this->setHeadline($this->exceptionText($exception), false); |
||
1298 | |||
22 | daniel-mar | 1299 | if ($exception instanceof VNagImplementationErrorException) { |
2 | daniel-mar | 1300 | $this->addVerboseMessage($exception->getTraceAsString(), VNag::VERBOSITY_SUMMARY); |
1301 | } else { |
||
1302 | if (isset($this->argVerbosity)) { |
||
1303 | $this->addVerboseMessage($exception->getTraceAsString(), VNag::VERBOSITY_ADDITIONAL_INFORMATION); |
||
1304 | } else { |
||
1305 | // $this->addVerboseMessage($exception->getTraceAsString(), VNag::VERBOSITY_SUMMARY); |
||
1306 | } |
||
1307 | } |
||
1308 | } |
||
1309 | } |
||
1310 | |||
1311 | |||
1312 | class VNagException extends Exception { |
||
1313 | public function getStatus() { |
||
1314 | return VNag::STATUS_ERROR; |
||
1315 | } |
||
1316 | } |
||
1317 | |||
1318 | class VNagTimeoutException extends VNagException {} |
||
1319 | |||
1320 | class VNagWebInfoException extends VNagException {} |
||
1321 | class VNagSignatureException extends VNagException {} |
||
1322 | class VNagPublicKeyException extends VNagException {} |
||
1323 | class VNagPrivateKeyException extends VNagException {} |
||
1324 | |||
1325 | // VNagInvalidArgumentException are exceptions which result from a wrong use |
||
1326 | // of arguments by the USER (CLI arguments or HTTP parameters) |
||
1327 | class VNagInvalidArgumentException extends VNagException { |
||
1328 | public function getStatus() { |
||
1329 | return VNag::STATUS_UNKNOWN; |
||
1330 | } |
||
1331 | } |
||
1332 | |||
1333 | class VNagValueUomPairSyntaxException extends VNagInvalidArgumentException { |
||
1334 | public function __construct($str) { |
||
1335 | $e_msg = sprintf(VNagLang::$valueUomPairSyntaxError, $str); |
||
1336 | parent::__construct($e_msg); |
||
1337 | } |
||
1338 | } |
||
1339 | |||
1340 | class VNagInvalidTimeoutException extends VNagInvalidArgumentException {} |
||
1341 | |||
1342 | class VNagInvalidRangeException extends VNagInvalidArgumentException { |
||
1343 | public function __construct($msg) { |
||
1344 | $e_msg = VNagLang::$range_is_invalid; |
||
1345 | if (!_empty($msg)) $e_msg .= ': '.trim($msg); |
||
1346 | parent::__construct($e_msg); |
||
1347 | } |
||
1348 | } |
||
1349 | |||
1350 | class VNagInvalidShortOpt extends VNagImplementationErrorException {} |
||
1351 | class VNagInvalidLongOpt extends VNagImplementationErrorException {} |
||
1352 | class VNagInvalidValuePolicy extends VNagImplementationErrorException {} |
||
1353 | class VNagIllegalStatusModel extends VNagImplementationErrorException {} |
||
1354 | class VNagNotConstructed extends VNagImplementationErrorException {} |
||
1355 | |||
1356 | // To enforce that people use the API correctly, we report flaws in the implementation |
||
1357 | // as Exception. |
||
1358 | class VNagImplementationErrorException extends VNagException {} |
||
1359 | |||
1360 | class VNagInvalidStandardArgument extends VNagImplementationErrorException {} |
||
1361 | class VNagFunctionCallOutsideSession extends VNagImplementationErrorException {} |
||
1362 | class VNagIllegalArgumentValuesException extends VNagImplementationErrorException {} |
||
1363 | |||
1364 | class VNagRequiredArgumentNotRegistered extends VNagImplementationErrorException { |
||
1365 | // Developer's mistake: The argument is not in the list of expected arguments |
||
1366 | public function __construct($required_argument) { |
||
1367 | $e_msg = sprintf(VNagLang::$query_without_expected_argument, $required_argument); |
||
1368 | parent::__construct($e_msg); |
||
1369 | } |
||
1370 | } |
||
1371 | |||
1372 | class VNagRequiredArgumentMissing extends VNagInvalidArgumentException { |
||
1373 | // User's mistake: They did not pass the argument to the plugin |
||
1374 | public function __construct($required_argument) { |
||
1375 | $e_msg = sprintf(VNagLang::$required_argument_missing, $required_argument); |
||
1376 | parent::__construct($e_msg); |
||
1377 | } |
||
1378 | } |
||
1379 | |||
1380 | class VNagUnknownUomException extends VNagInvalidArgumentException { |
||
1381 | public function __construct($uom) { |
||
1382 | $e_msg = sprintf(VNagLang::$perfdata_uom_not_recognized, $uom); |
||
1383 | parent::__construct($e_msg); |
||
1384 | } |
||
1385 | } |
||
1386 | |||
1387 | class VNagNoCompatibleRangeUomFoundException extends VNagException {} |
||
1388 | |||
1389 | class VNagMixedUomsNotImplemented extends VNagInvalidArgumentException { |
||
1390 | public function __construct($uom1, $uom2) { |
||
1391 | if (_empty($uom1)) $uom1 = VNagLang::$none; |
||
1392 | if (_empty($uom2)) $uom2 = VNagLang::$none; |
||
1393 | $e_msg = sprintf(VNagLang::$perfdata_mixed_uom_not_implemented, $uom1, $uom2); |
||
1394 | parent::__construct($e_msg); |
||
1395 | } |
||
1396 | } |
||
1397 | |||
1398 | class VNagUomConvertException extends VNagInvalidArgumentException { |
||
1399 | // It is unknown where the invalid UOM that was passed to the normalize() function came from, |
||
1400 | // so it is not clear what parent this Exception class should have... |
||
1401 | // If the value comes from the developer: VNagImplementationErrorException |
||
1402 | // If the value came from the user: VNagInvalidArgumentException |
||
1403 | |||
1404 | public function __construct($uom1, $uom2) { |
||
1405 | if (_empty($uom1)) $uom1 = VNagLang::$none; |
||
1406 | if (_empty($uom2)) $uom2 = VNagLang::$none; |
||
1407 | $e_msg = sprintf(VNagLang::$convert_x_y_error, $uom1, $uom2); |
||
1408 | parent::__construct($e_msg); |
||
1409 | } |
||
1410 | } |
||
1411 | |||
1412 | class VNagInvalidPerformanceDataException extends VNagInvalidArgumentException { |
||
1413 | public function __construct($msg) { |
||
1414 | $e_msg = VNagLang::$performance_data_invalid; |
||
1415 | if (!_empty($msg)) $e_msg .= ': '.trim($msg); |
||
1416 | parent::__construct($e_msg); |
||
1417 | } |
||
1418 | } |
||
1419 | |||
1420 | class Timeouter { |
||
1421 | // based on http://stackoverflow.com/questions/7493676/detecting-a-timeout-for-a-block-of-code-in-php |
||
1422 | |||
1423 | private static $start_time = false; |
||
1424 | private static $timeout; |
||
1425 | private static $fired = false; |
||
1426 | private static $registered = false; |
||
1427 | |||
1428 | private function __construct() { |
||
1429 | } |
||
1430 | |||
1431 | public static function start($timeout) { |
||
1432 | if (!is_numeric($timeout) || ($timeout <= 0)) { |
||
1433 | throw new VNagInvalidTimeoutException(sprintf(VNagLang::$timeout_value_invalid, $timeout)); |
||
1434 | } |
||
1435 | |||
1436 | self::$start_time = microtime(true); |
||
1437 | self::$timeout = (float) $timeout; |
||
1438 | self::$fired = false; |
||
1439 | if (!self::$registered) { |
||
1440 | self::$registered = true; |
||
1441 | register_tick_function(array('Timeouter', 'tick')); |
||
1442 | } |
||
1443 | } |
||
1444 | |||
1445 | public static function started() { |
||
1446 | return self::$registered; |
||
1447 | } |
||
1448 | |||
1449 | public static function end() { |
||
1450 | if (self::$registered) { |
||
1451 | unregister_tick_function(array('Timeouter', 'tick')); |
||
1452 | self::$registered = false; |
||
1453 | } |
||
1454 | } |
||
1455 | |||
1456 | public static function tick() { |
||
1457 | if ((!self::$fired) && ((microtime(true) - self::$start_time) > self::$timeout)) { |
||
1458 | self::$fired = true; // do not fire again |
||
1459 | throw new VNagTimeoutException(VNagLang::$timeout_exception); |
||
1460 | } |
||
1461 | } |
||
1462 | } |
||
1463 | |||
1464 | class VNagArgument { |
||
1465 | const VALUE_FORBIDDEN = 0; |
||
1466 | const VALUE_REQUIRED = 1; |
||
1467 | const VALUE_OPTIONAL = 2; |
||
1468 | |||
1469 | protected $shortopt; |
||
1470 | protected $longopts; |
||
1471 | protected $valuePolicy; |
||
1472 | protected $valueName; |
||
1473 | protected $helpText; |
||
1474 | protected $defaultValue = null; |
||
1475 | |||
1476 | protected static $all_short = ''; |
||
1477 | protected static $all_long = array(); |
||
1478 | |||
1479 | public function getShortOpt() { |
||
1480 | return $this->shortopt; |
||
1481 | } |
||
1482 | |||
1483 | public function getLongOpts() { |
||
1484 | return $this->longopts; |
||
1485 | } |
||
1486 | |||
1487 | public function getValuePolicy() { |
||
1488 | return $this->valuePolicy; |
||
1489 | } |
||
1490 | |||
1491 | public function getValueName() { |
||
1492 | return $this->valueName; |
||
1493 | } |
||
1494 | |||
1495 | public function getHelpText() { |
||
1496 | return $this->helpText; |
||
1497 | } |
||
1498 | |||
1499 | static private function validateShortOpt($shortopt) { |
||
22 | daniel-mar | 1500 | $m = array(); |
2 | daniel-mar | 1501 | return preg_match('@^[a-zA-Z0-9\\+\\-\\?]$@', $shortopt, $m); |
1502 | } |
||
1503 | |||
1504 | static private function validateLongOpt($longopt) { |
||
1505 | // FUT: Check if this is accurate |
||
22 | daniel-mar | 1506 | $m = array(); |
2 | daniel-mar | 1507 | return preg_match('@^[a-zA-Z0-9\\+\\-\\?]+$@', $longopt, $m); |
1508 | } |
||
1509 | |||
1510 | // Note: Currently, we do not support following: |
||
1511 | // 1. How many times may a value be defined (it needs to be manually described in $helpText) |
||
1512 | // 2. Is this argument mandatory? (No exception will be thrown if the plugin will be started without this argument) |
||
1513 | public function __construct($shortopt, $longopts, $valuePolicy, $valueName, $helpText, $defaultValue=null) { |
||
1514 | // Check if $valueName is defined correctly in regards to the policy $valuePolicy |
||
1515 | switch ($valuePolicy) { |
||
1516 | case VNagArgument::VALUE_FORBIDDEN: |
||
1517 | if (!_empty($valueName)) { |
||
1518 | throw new VNagImplementationErrorException(sprintf(VNagLang::$value_name_forbidden)); |
||
1519 | } |
||
1520 | break; |
||
1521 | case VNagArgument::VALUE_REQUIRED: |
||
1522 | if (_empty($valueName)) { |
||
1523 | throw new VNagImplementationErrorException(sprintf(VNagLang::$value_name_required)); |
||
1524 | } |
||
1525 | break; |
||
1526 | case VNagArgument::VALUE_OPTIONAL: |
||
1527 | if (_empty($valueName)) { |
||
1528 | throw new VNagImplementationErrorException(sprintf(VNagLang::$value_name_required)); |
||
1529 | } |
||
1530 | break; |
||
1531 | default: |
||
1532 | throw new VNagInvalidValuePolicy(sprintf(VNagLang::$illegal_valuepolicy, $valuePolicy)); |
||
1533 | } |
||
1534 | |||
1535 | // We'll check: Does the shortopt contain illegal characters? |
||
1536 | // http://stackoverflow.com/questions/28522387/which-chars-are-valid-shortopts-for-gnu-getopt |
||
1537 | // We do not filter +, - and ?, since we might need it for other methods, e.g. VNagArgumentHandler::_addExpectedArgument |
||
1538 | if (!_empty($shortopt)) { |
||
1539 | if (!self::validateShortOpt($shortopt)) { |
||
1540 | throw new VNagInvalidShortOpt(sprintf(VNagLang::$illegal_shortopt, $shortopt)); |
||
1541 | } |
||
1542 | } |
||
1543 | |||
1544 | if (is_array($longopts)) { // $longopts is an array |
||
29 | daniel-mar | 1545 | foreach ($longopts as $longopt) { |
1546 | if (!self::validateLongOpt($longopt)) { |
||
1547 | throw new VNagInvalidLongOpt(sprintf(VNagLang::$illegal_longopt, $longopt)); |
||
2 | daniel-mar | 1548 | } |
1549 | } |
||
1550 | } else if (!_empty($longopts)) { // $longopts is a string |
||
1551 | if (!self::validateLongOpt($longopts)) { |
||
1552 | throw new VNagInvalidLongOpt(sprintf(VNagLang::$illegal_longopt, $longopts)); |
||
1553 | } |
||
1554 | $longopts = array($longopts); |
||
1555 | } else { |
||
1556 | $longopts = array(); |
||
1557 | } |
||
1558 | |||
1559 | # valuePolicy must be between 0..2 and being int |
||
1560 | switch ($valuePolicy) { |
||
1561 | case VNagArgument::VALUE_FORBIDDEN: |
||
1562 | $policyApdx = ''; |
||
1563 | break; |
||
1564 | case VNagArgument::VALUE_REQUIRED: |
||
1565 | $policyApdx = ':'; |
||
1566 | break; |
||
1567 | case VNagArgument::VALUE_OPTIONAL: |
||
1568 | $policyApdx = '::'; |
||
1569 | break; |
||
1570 | default: |
||
1571 | throw new VNagInvalidValuePolicy(sprintf(VNagLang::$illegal_valuepolicy, $valuePolicy)); |
||
1572 | } |
||
1573 | |||
1574 | if ((!is_null($shortopt)) && ($shortopt != '?')) self::$all_short .= $shortopt.$policyApdx; |
||
29 | daniel-mar | 1575 | if (is_array($longopts)) { |
2 | daniel-mar | 1576 | foreach ($longopts as $longopt) { |
1577 | self::$all_long[] = $longopt.$policyApdx; |
||
1578 | } |
||
1579 | } |
||
1580 | |||
1581 | $this->shortopt = $shortopt; |
||
1582 | $this->longopts = $longopts; |
||
1583 | $this->valuePolicy = $valuePolicy; |
||
1584 | $this->valueName = $valueName; |
||
1585 | $this->helpText = $helpText; |
||
1586 | $this->defaultValue = $defaultValue; |
||
1587 | } |
||
1588 | |||
1589 | protected static function getOptions() { |
||
1590 | // Attention: In PHP 5.6.19-0+deb8u1 (cli), $_REQUEST is always set, so we need is_http_mode() instead of isset($_REQUEST)! |
||
1591 | global $OVERWRITE_ARGUMENTS; |
||
1592 | |||
1593 | if (!is_null($OVERWRITE_ARGUMENTS)) { |
||
1594 | return $OVERWRITE_ARGUMENTS; |
||
1595 | } else if (VNag::is_http_mode()) { |
||
1596 | return $_REQUEST; |
||
1597 | } else { |
||
1598 | return getopt(self::$all_short, self::$all_long); |
||
1599 | } |
||
1600 | } |
||
1601 | |||
1602 | public function count() { |
||
1603 | $options = self::getOptions(); |
||
1604 | |||
1605 | $count = 0; |
||
1606 | |||
1607 | if (isset($options[$this->shortopt])) { |
||
1608 | if (is_array($options[$this->shortopt])) { |
||
1609 | // e.g. -vvv |
||
1610 | $count += count($options[$this->shortopt]); |
||
1611 | } else { |
||
1612 | // e.g. -v |
||
1613 | $count += 1; |
||
1614 | } |
||
1615 | } |
||
1616 | |||
1617 | if (!is_null($this->longopts)) { |
||
1618 | foreach ($this->longopts as $longopt) { |
||
1619 | if (isset($options[$longopt])) { |
||
1620 | if (is_array($options[$longopt])) { |
||
1621 | // e.g. --verbose --verbose --verbose |
||
1622 | $count += count($options[$longopt]); |
||
1623 | } else { |
||
1624 | // e.g. --verbose |
||
1625 | $count += 1; |
||
1626 | } |
||
1627 | } |
||
1628 | } |
||
1629 | } |
||
1630 | |||
1631 | return $count; |
||
1632 | } |
||
1633 | |||
1634 | public function available() { |
||
1635 | $options = self::getOptions(); |
||
1636 | |||
1637 | if (isset($options[$this->shortopt])) return true; |
||
1638 | if (!is_null($this->longopts)) { |
||
1639 | foreach ($this->longopts as $longopt) { |
||
1640 | if (isset($options[$longopt])) return true; |
||
1641 | } |
||
1642 | } |
||
1643 | return false; |
||
1644 | } |
||
1645 | |||
1646 | public function require() { |
||
1647 | if (!$this->available() && is_null($this->defaultValue)) { |
||
1648 | $opt = $this->shortopt; |
||
1649 | $opt = !_empty($opt) ? '-'.$opt : (isset($this->longopts[0]) ? '--'.$this->longopts[0] : '?'); |
||
1650 | throw new VNagRequiredArgumentMissing($opt); |
||
1651 | } |
||
1652 | } |
||
1653 | |||
1654 | public function getValue() { |
||
1655 | $options = self::getOptions(); |
||
1656 | |||
1657 | if (isset($options[$this->shortopt])) { |
||
1658 | $x = $options[$this->shortopt]; |
||
1659 | if (is_array($x) && (count($x) <= 1)) $options[$this->shortopt] = $options[$this->shortopt][0]; |
||
1660 | return $options[$this->shortopt]; |
||
1661 | } |
||
1662 | |||
1663 | if (!is_null($this->longopts)) { |
||
1664 | foreach ($this->longopts as $longopt) { |
||
1665 | if (isset($options[$longopt])) { |
||
1666 | $x = $options[$longopt]; |
||
1667 | if (is_array($x) && (count($x) <= 1)) $options[$longopt] = $options[$longopt][0]; |
||
1668 | return $options[$longopt]; |
||
1669 | } |
||
1670 | } |
||
1671 | } |
||
1672 | |||
1673 | return $this->defaultValue; |
||
1674 | } |
||
1675 | } |
||
1676 | |||
1677 | class VNagArgumentHandler { |
||
1678 | protected $expectedArgs = array(); |
||
1679 | |||
1680 | // Will be called by VNag via ReflectionMethod (like C++ style friends), because it should not be called manually. |
||
1681 | // Use VNag's function instead (since it adds to the helpObj too) |
||
1682 | protected function _addExpectedArgument($argObj) { |
||
1683 | // -? is always illegal, so it will trigger illegalUsage(). So we don't add it to the list of |
||
1684 | // expected arguments, otherwise illegalUsage() would be true. |
||
1685 | if ($argObj->getShortOpt() == '?') return false; |
||
1686 | |||
1687 | // GNU extensions with a special meaning |
||
1688 | if ($argObj->getShortOpt() == '-') return false; // cancel parsing |
||
1689 | if ($argObj->getShortOpt() == '+') return false; // enable POSIXLY_CORRECT |
||
1690 | |||
1691 | $this->expectedArgs[] = $argObj; |
||
1692 | return true; |
||
1693 | } |
||
1694 | |||
1695 | public function getArgumentObj($shortopt) { |
||
1696 | foreach ($this->expectedArgs as $argObj) { |
||
1697 | if ($argObj->getShortOpt() == $shortopt) return $argObj; |
||
1698 | } |
||
1699 | return null; |
||
1700 | } |
||
1701 | |||
1702 | public function isArgRegistered($shortopt) { |
||
1703 | return !is_null($this->getArgumentObj($shortopt)); |
||
1704 | } |
||
1705 | |||
1706 | public function illegalUsage() { |
||
1707 | // In this function, we should check if $argv (resp. getopts) contains stuff which is not expected or illegal, |
||
1708 | // so the script can show an usage information and quit the program. |
||
1709 | |||
1710 | // WONTFIX: PHP's horrible implementation of GNU's getopt does not allow following intended tasks: |
||
1711 | // - check for illegal values/arguments (e.g. the argument -? which is always illegal) |
||
1712 | // - check for missing values (e.g. -H instead of -H localhost ) |
||
1713 | // - check for unexpected arguments (e.g. -x if only -a -b -c are defined in $expectedArgs as expected arguments) |
||
1714 | // - Of course, everything behind "--" may not be evaluated |
||
1715 | // see also http://stackoverflow.com/questions/25388130/catch-unexpected-options-with-getopt |
||
1716 | |||
1717 | // So the only way is to do this stupid hard coded check for '-?' |
||
1718 | // PHP sucks... |
||
1719 | global $argv; |
||
1720 | return (isset($argv[1])) && (($argv[1] == '-?') || ($argv[1] == '/?')); |
||
1721 | } |
||
1722 | } |
||
1723 | |||
1724 | class VNagRange { |
||
1725 | // see https://nagios-plugins.org/doc/guidelines.html#THRESHOLDFORMAT |
||
1726 | // We allow UOMs inside the range definition, e.g. "-w @10M:50M" |
||
1727 | |||
1728 | public /*VNagValueUomPair|'inf'*/ $start; |
||
1729 | public /*VNagValueUomPair|'inf'*/ $end; |
||
1730 | public /*boolean*/ $warnInsideRange; |
||
1731 | |||
1732 | public function __construct($rangeDef, $singleValueBehavior=VNag::SINGLEVALUE_RANGE_DEFAULT) { |
||
22 | daniel-mar | 1733 | $m = array(); |
2 | daniel-mar | 1734 | //if (!preg_match('|(@){0,1}(\d+)(:){0,1}(\d+){0,1}|', $rangeDef, $m)) { |
1735 | if (!preg_match('|^(@){0,1}([^:]+)(:){0,1}(.*)$|', $rangeDef, $m)) { |
||
1736 | throw new VNagInvalidRangeException(sprintf(VNagLang::$range_invalid_syntax, $rangeDef)); |
||
1737 | } |
||
1738 | |||
1739 | $this->warnInsideRange = $m[1] === '@'; |
||
1740 | |||
1741 | $this->start = null; |
||
1742 | $this->end = null; |
||
1743 | |||
1744 | if ($m[3] === ':') { |
||
1745 | if ($m[2] === '~') { |
||
1746 | $this->start = 'inf'; |
||
1747 | } else { |
||
1748 | $this->start = new VNagValueUomPair($m[2]); |
||
1749 | } |
||
1750 | |||
1751 | if (_empty($m[4])) { |
||
1752 | $this->end = 'inf'; |
||
1753 | } else { |
||
1754 | $this->end = new VNagValueUomPair($m[4]); |
||
1755 | } |
||
1756 | } else { |
||
1757 | assert(_empty($m[4])); |
||
1758 | assert(!_empty($m[2])); |
||
1759 | |||
1760 | $x = $m[2]; |
||
1761 | |||
1762 | if ($singleValueBehavior == VNag::SINGLEVALUE_RANGE_DEFAULT) { |
||
1763 | // Default behavior according to the development guidelines: |
||
1764 | // x means x:x, which means, everything except x% is bad. |
||
1765 | // @x means @x:x, which means, x is bad and everything else is good. |
||
1766 | $this->start = new VNagValueUomPair($x); |
||
1767 | $this->end = new VNagValueUomPair($x); |
||
1768 | } else if ($singleValueBehavior == VNag::SINGLEVALUE_RANGE_VAL_GT_X_BAD) { |
||
1769 | // The single value x means, everything > x is bad. @x is not defined. |
||
1770 | if ($this->warnInsideRange) throw new VNagInvalidRangeException(VNagLang::$singlevalue_unexpected_at_symbol); |
||
1771 | $this->warnInsideRange = 0; |
||
1772 | $this->start = 'inf'; |
||
1773 | $this->end = new VNagValueUomPair($x); |
||
1774 | } else if ($singleValueBehavior == VNag::SINGLEVALUE_RANGE_VAL_GE_X_BAD) { |
||
1775 | // The single value x means, everything >= x is bad. @x is not defined. |
||
1776 | if ($this->warnInsideRange) throw new VNagInvalidRangeException(VNagLang::$singlevalue_unexpected_at_symbol); |
||
1777 | $this->warnInsideRange = 1; |
||
1778 | $this->start = new VNagValueUomPair($x); |
||
1779 | $this->end = 'inf'; |
||
1780 | } else if ($singleValueBehavior == VNag::SINGLEVALUE_RANGE_VAL_LT_X_BAD) { |
||
1781 | // The single value x means, everything < x is bad. @x is not defined. |
||
1782 | if ($this->warnInsideRange) throw new VNagInvalidRangeException(VNagLang::$singlevalue_unexpected_at_symbol); |
||
1783 | $this->warnInsideRange = 0; |
||
1784 | $this->start = new VNagValueUomPair($x); |
||
1785 | $this->end = 'inf'; |
||
1786 | } else if ($singleValueBehavior == VNag::SINGLEVALUE_RANGE_VAL_LE_X_BAD) { |
||
1787 | // The single value x means, everything <= x is bad. @x is not defined. |
||
1788 | if ($this->warnInsideRange) throw new VNagInvalidRangeException(VNagLang::$singlevalue_unexpected_at_symbol); |
||
1789 | $this->warnInsideRange = 1; |
||
1790 | $this->start = 'inf'; |
||
1791 | $this->end = new VNagValueUomPair($x); |
||
1792 | } else { |
||
1793 | throw new VNagException(VNagLang::$illegalSingleValueBehavior); |
||
1794 | } |
||
1795 | } |
||
1796 | |||
1797 | // Check if range is valid |
||
1798 | if (is_null($this->start)) { |
||
1799 | throw new VNagInvalidRangeException(VNagLang::$invalid_start_value); |
||
1800 | } |
||
1801 | if (is_null($this->end)) { |
||
1802 | throw new VNagInvalidRangeException(VNagLang::$invalid_end_value); |
||
1803 | } |
||
1804 | if (($this->start instanceof VNagValueUomPair) && ($this->end instanceof VNagValueUomPair) && |
||
1805 | (VNagValueUomPair::compare($this->start,$this->end) > 0)) { |
||
1806 | throw new VNagInvalidRangeException(VNagLang::$start_is_greater_than_end); |
||
1807 | } |
||
1808 | } |
||
1809 | |||
1810 | public function __toString() { |
||
1811 | // Attention: |
||
1812 | // - this function assumes that $start and $end are valid. |
||
1813 | // - not the shortest result will be chosen |
||
1814 | |||
1815 | $ret = ''; |
||
1816 | if ($this->warnInsideRange) { |
||
1817 | $ret = '@'; |
||
1818 | } |
||
1819 | |||
1820 | if ($this->start === 'inf') { |
||
1821 | $ret .= '~'; |
||
1822 | } else { |
||
1823 | $ret .= $this->start; |
||
1824 | } |
||
1825 | |||
1826 | $ret .= ':'; |
||
1827 | |||
1828 | if ($this->end !== 'inf') { |
||
1829 | $ret .= $this->end; |
||
1830 | } |
||
1831 | |||
1832 | return $ret; |
||
1833 | } |
||
1834 | |||
1835 | public function checkAlert($values) { |
||
1836 | $compatibleCount = 0; |
||
1837 | |||
1838 | if (!is_array($values)) $values = array($values); |
||
1839 | foreach ($values as $value) { |
||
1840 | if (!($value instanceof VNagValueUomPair)) $value = new VNagValueUomPair($value); |
||
1841 | |||
8 | daniel-mar | 1842 | assert(($this->start === 'inf') || ($this->start instanceof VNagValueUomPair)); |
1843 | assert(($this->end === 'inf') || ($this->end instanceof VNagValueUomPair)); |
||
2 | daniel-mar | 1844 | |
1845 | if (($this->start !== 'inf') && (!$this->start->compatibleWith($value))) continue; |
||
1846 | if (($this->end !== 'inf') && (!$this->end->compatibleWith($value))) continue; |
||
1847 | $compatibleCount++; |
||
1848 | |||
1849 | if ($this->warnInsideRange) { |
||
1850 | return (($this->start === 'inf') || (VNagValueUomPair::compare($value,$this->start) >= 0)) && |
||
1851 | (($this->end === 'inf') || (VNagValueUomPair::compare($value,$this->end) <= 0)); |
||
1852 | } else { |
||
1853 | return (($this->start !== 'inf') && (VNagValueUomPair::compare($value,$this->start) < 0)) || |
||
1854 | (($this->end !== 'inf') && (VNagValueUomPair::compare($value,$this->end) > 0)); |
||
1855 | } |
||
1856 | } |
||
1857 | |||
1858 | if ((count($values) > 0) and ($compatibleCount == 0)) { |
||
1859 | throw new VNagNoCompatibleRangeUomFoundException(VNagLang::$no_compatible_range_uom_found); |
||
1860 | } |
||
1861 | |||
1862 | return false; |
||
1863 | } |
||
1864 | } |
||
1865 | |||
1866 | class VNagValueUomPair { |
||
1867 | protected $value; |
||
1868 | protected $uom; |
||
1869 | public $roundTo = -1; |
||
1870 | |||
1871 | public function isRelative() { |
||
1872 | return $this->uom === '%'; |
||
1873 | } |
||
1874 | |||
1875 | public function getValue() { |
||
1876 | return $this->value; |
||
1877 | } |
||
1878 | |||
1879 | public function getUom() { |
||
1880 | return $this->uom; |
||
1881 | } |
||
1882 | |||
1883 | public function __toString() { |
||
1884 | if ($this->roundTo == -1) { |
||
1885 | return $this->value.$this->uom; |
||
1886 | } else { |
||
1887 | return round($this->value,$this->roundTo).$this->uom; |
||
1888 | } |
||
1889 | } |
||
1890 | |||
1891 | public function __construct($str) { |
||
22 | daniel-mar | 1892 | $m = array(); |
2 | daniel-mar | 1893 | if (!preg_match('/^([\d\.]+)(.*)$/ism', $str, $m)) { |
1894 | throw new VNagValueUomPairSyntaxException($str); |
||
1895 | } |
||
1896 | $this->value = $m[1]; |
||
1897 | $this->uom = isset($m[2]) ? $m[2] : ''; |
||
1898 | |||
1899 | if (!self::isKnownUOM($this->uom)) { |
||
1900 | throw new VNagUnknownUomException($this->uom); |
||
1901 | } |
||
1902 | } |
||
1903 | |||
29 | daniel-mar | 1904 | public static function isKnownUOM(string $uom) { |
2 | daniel-mar | 1905 | // see https://nagios-plugins.org/doc/guidelines.html#AEN200 |
1906 | // 10. UOM (unit of measurement) is one of: |
||
31 | daniel-mar | 1907 | |
1908 | // no unit specified - assume a number (int or float) of things (eg, users, processes, load averages) |
||
1909 | $no_unit = ($uom === ''); |
||
1910 | // s - seconds (also us, ms) |
||
1911 | $seconds = ($uom === 's') || ($uom === 'ms') || ($uom === 'us'); |
||
1912 | // % - percentage |
||
1913 | $percentage = ($uom === '%'); |
||
1914 | // B - bytes (also KB, MB, TB) |
||
1915 | // NOTE: GB is not in the official development guidelines,probably due to an error, so I've added them anyway |
||
1916 | $bytes = ($uom === 'B') || ($uom === 'KB') || ($uom === 'MB') || ($uom === 'GB') || ($uom === 'TB'); |
||
1917 | // c - a continous counter (such as bytes transmitted on an interface) |
||
1918 | $counter = ($uom === 'c'); |
||
1919 | |||
1920 | return ($no_unit || $seconds || $percentage || $bytes || $counter); |
||
2 | daniel-mar | 1921 | } |
1922 | |||
1923 | public function normalize($target=null) { |
||
1924 | $res = clone $this; |
||
1925 | |||
1926 | // The value is normalized to seconds or megabytes |
||
1927 | if ($res->uom === 'ms') { |
||
1928 | $res->uom = 's'; |
||
1929 | $res->value /= 1000; |
||
1930 | } |
||
1931 | if ($res->uom === 'us') { |
||
1932 | $res->uom = 's'; |
||
1933 | $res->value /= 1000 * 1000; |
||
1934 | } |
||
1935 | if ($res->uom === 'B') { |
||
1936 | $res->uom = 'MB'; |
||
1937 | $res->value /= 1024 * 1024; |
||
1938 | } |
||
1939 | if ($res->uom === 'KB') { |
||
1940 | $res->uom = 'MB'; |
||
1941 | $res->value /= 1024; |
||
1942 | } |
||
1943 | if ($res->uom === 'GB') { |
||
1944 | $res->uom = 'MB'; |
||
1945 | $res->value *= 1024; |
||
1946 | } |
||
1947 | if ($res->uom === 'TB') { |
||
1948 | $res->uom = 'MB'; |
||
1949 | $res->value *= 1024 * 1024; |
||
1950 | } |
||
1951 | if ($res->uom === 'c') { |
||
1952 | $res->uom = ''; |
||
1953 | } |
||
1954 | |||
1955 | // Now, if the user wishes, convert to another unit |
||
1956 | if (!is_null($target)) { |
||
1957 | if ($res->uom == 'MB') { |
||
1958 | if ($target == 'B') { |
||
1959 | $res->uom = 'B'; |
||
1960 | $res->value *= 1024 * 1024; |
||
1961 | } else if ($target == 'KB') { |
||
1962 | $res->uom = 'KB'; |
||
1963 | $res->value *= 1024; |
||
1964 | } else if ($target == 'GB') { |
||
1965 | $res->uom = 'GB'; |
||
1966 | $res->value /= 1024; |
||
1967 | } else if ($target == 'TB') { |
||
1968 | $res->uom = 'TB'; |
||
1969 | $res->value /= 1024 * 1024; |
||
1970 | } else { |
||
1971 | throw new VNagUomConvertException($res->uom, $target); |
||
1972 | } |
||
1973 | } else if ($res->uom == 's') { |
||
1974 | if ($target == 'ms') { |
||
1975 | $res->uom = 'ms'; |
||
1976 | $res->value /= 1000; |
||
1977 | } else if ($target == 'us') { |
||
1978 | $res->uom = 'us'; |
||
1979 | $res->value /= 1000 * 1000; |
||
1980 | } else { |
||
1981 | throw new VNagUomConvertException($res->uom, $target); |
||
1982 | } |
||
1983 | } else { |
||
1984 | throw new VNagUomConvertException($res->uom, $target); |
||
1985 | } |
||
1986 | } |
||
1987 | |||
1988 | return $res; |
||
1989 | } |
||
1990 | |||
1991 | public function compatibleWith(VNagValueUomPair $other) { |
||
1992 | $a = $this->normalize(); |
||
1993 | $b = $other->normalize(); |
||
1994 | |||
1995 | return ($a->uom == $b->uom); |
||
1996 | } |
||
1997 | |||
1998 | public static function compare(VNagValueUomPair $left, VNagValueUomPair $right) { |
||
1999 | $a = $left->normalize(); |
||
2000 | $b = $right->normalize(); |
||
2001 | |||
2002 | // FUT: Also accept mixed UOMs, e.g. MB and % |
||
2003 | // To translate between an absolute and a relative value, the |
||
2004 | // reference value (100%=?) needs to be passed through this comparison |
||
2005 | // function somehow. |
||
2006 | if ($a->uom != $b->uom) throw new VNagMixedUomsNotImplemented($a->uom, $b->uom); |
||
2007 | |||
2008 | if ($a->value > $b->value) return 1; |
||
2009 | if ($a->value == $b->value) return 0; |
||
2010 | if ($a->value < $b->value) return -1; |
||
2011 | } |
||
2012 | } |
||
2013 | |||
2014 | class VNagPerformanceData { |
||
2015 | // see https://nagios-plugins.org/doc/guidelines.html#AEN200 |
||
2016 | // https://www.icinga.com/docs/icinga1/latest/en/perfdata.html#formatperfdata |
||
2017 | |||
2018 | protected $label; |
||
2019 | protected /*VNagValueUomPair*/ $value; |
||
2020 | protected $warn = null; |
||
2021 | protected $crit = null; |
||
2022 | protected $min = null; |
||
2023 | protected $max = null; |
||
2024 | |||
2025 | public static function createByString($perfdata) { |
||
2026 | $perfdata = trim($perfdata); |
||
2027 | |||
2028 | $ary = explode('=',$perfdata); |
||
2029 | if (count($ary) != 2) { |
||
2030 | throw new VNagInvalidPerformanceDataException(sprintf(VNagLang::$perfdata_line_invalid, $perfdata)); |
||
2031 | } |
||
2032 | $label = $ary[0]; |
||
2033 | $bry = explode(';',$ary[1]); |
||
2034 | if (substr($label,0,1) === "'") $label = substr($label, 1, strlen($label)-2); |
||
2035 | $value = $bry[0]; |
||
2036 | $warn = isset($bry[1]) ? $bry[1] : null; |
||
2037 | $crit = isset($bry[2]) ? $bry[2] : null; |
||
2038 | $min = isset($bry[3]) ? $bry[3] : null; |
||
2039 | $max = isset($bry[4]) ? $bry[4] : null; |
||
2040 | |||
2041 | // Guideline "7. min and max are not required if UOM=%" makes no sense, because |
||
2042 | // actually, all fields (except label and value) are optional. |
||
2043 | |||
2044 | return new self($label, $value, $warn, $crit, $min, $max); |
||
2045 | } |
||
2046 | |||
2047 | public function __construct($label, $value/*may include UOM*/, $warn=null, $crit=null, $min=null, $max=null) { |
||
2048 | // Not checked / Nothing to check: |
||
2049 | // - 4. label length is arbitrary, but ideally the first 19 characters are unique (due to a limitation in RRD). Be aware of a limitation in the amount of data that NRPE returns to Nagios |
||
2050 | // - 6. warn, crit, min or max may be null (for example, if the threshold is not defined or min and max do not apply). Trailing unfilled semicolons can be dropped |
||
2051 | // - 9. warn and crit are in the range format (see the Section called Threshold and ranges). Must be the same UOM |
||
2052 | // - 7. min and max are not required if UOM=% |
||
2053 | |||
2054 | // 2. label can contain any characters except the equals sign or single quote (') |
||
2055 | if (strpos($label, '=') !== false) throw new VNagInvalidPerformanceDataException(VNagLang::$perfdata_label_equal_sign_forbidden); |
||
2056 | |||
2057 | // 5. to specify a quote character, use two single quotes |
||
2058 | $label = str_replace("'", "''", $label); |
||
2059 | |||
2060 | // 8. value, min and max in class [-0-9.]. Must all be the same UOM. |
||
2061 | // value may be a literal "U" instead, this would indicate that the actual value couldn't be determined |
||
2062 | /* |
||
2063 | if (($value != 'U') && (!preg_match('|^[-0-9\\.]+$|', $value, $m))) { |
||
2064 | throw new VNagInvalidPerformanceDataException(VNagLang::$perfdata_value_must_be_in_class); |
||
2065 | } |
||
2066 | */ |
||
22 | daniel-mar | 2067 | $m = array(); |
2 | daniel-mar | 2068 | if ((!_empty($min)) && (!preg_match('|^[-0-9\\.]+$|', $min, $m))) { |
2069 | throw new VNagInvalidPerformanceDataException(VNagLang::$perfdata_min_must_be_in_class); |
||
2070 | } |
||
2071 | if ((!_empty($max)) && (!preg_match('|^[-0-9\\.]+$|', $max, $m))) { |
||
2072 | throw new VNagInvalidPerformanceDataException(VNagLang::$perfdata_max_must_be_in_class); |
||
2073 | } |
||
2074 | |||
2075 | // 10. UOM (unit of measurement) is one of .... |
||
2076 | // => This rule is checked in the VNagValueUomPair constructor. |
||
2077 | |||
2078 | $this->label = $label; |
||
2079 | $this->value = ($value == 'U') ? 'U' : new VNagValueUomPair($value); |
||
2080 | $this->warn = $warn; |
||
2081 | $this->crit = $crit; |
||
2082 | $this->min = $min; |
||
2083 | $this->max = $max; |
||
2084 | } |
||
2085 | |||
2086 | public function __toString() { |
||
2087 | $label = $this->label; |
||
2088 | $value = $this->value; |
||
2089 | $warn = $this->warn; |
||
2090 | $crit = $this->crit; |
||
2091 | $min = $this->min; |
||
2092 | $max = $this->max; |
||
2093 | |||
2094 | // 5. to specify a quote character, use two single quotes |
||
2095 | $label = str_replace("''", "'", $label); |
||
2096 | |||
2097 | // 'label'=value[UOM];[warn];[crit];[min];[max] |
||
2098 | // 3. the single quotes for the label are optional. Required if spaces are in the label |
||
2099 | return "'$label'=$value". |
||
2100 | ';'.(is_null($warn) ? '' : $warn). |
||
2101 | ';'.(is_null($crit) ? '' : $crit). |
||
2102 | ';'.(is_null($min) ? '' : $min). |
||
2103 | ';'.(is_null($max) ? '' : $max); |
||
2104 | } |
||
2105 | } |
||
2106 | |||
2107 | class VNagHelp { |
||
2108 | public $word_wrap_width = 80; // -1 = disable |
||
2109 | public $argument_indent = 7; |
||
2110 | |||
2111 | public function printUsagePage() { |
||
2112 | $usage = $this->getUsage(); |
||
2113 | |||
2114 | if (_empty($usage)) { |
||
2115 | $usage = VNagLang::$no_syntax_defined; |
||
2116 | } |
||
2117 | |||
2118 | return trim($usage)."\n"; |
||
2119 | } |
||
2120 | |||
2121 | public function printVersionPage() { |
||
2122 | $out = trim($this->getNameAndVersion())."\n"; |
||
2123 | |||
2124 | if ($this->word_wrap_width > 0) $out = wordwrap($out, $this->word_wrap_width, "\n", false); |
||
2125 | |||
2126 | return $out; |
||
2127 | } |
||
2128 | |||
2129 | static private function _conditionalLine($line, $terminator='', $prefix='') { |
||
2130 | if (!_empty($line)) { |
||
2131 | return trim($line).$terminator; |
||
2132 | } |
||
2133 | return ''; |
||
2134 | } |
||
2135 | |||
2136 | public function printHelpPage() { |
||
2137 | $out = ''; |
||
2138 | $out .= self::_conditionalLine($this->getNameAndVersion(), "\n"); |
||
2139 | $out .= self::_conditionalLine($this->getCopyright(), "\n"); |
||
2140 | $out .= ($out != '') ? "\n" : ''; |
||
2141 | $out .= self::_conditionalLine($this->getShortDescription(), "\n\n\n"); |
||
2142 | $out .= self::_conditionalLine($this->getUsage(), "\n\n"); |
||
2143 | |||
2144 | $out .= VNagLang::$options."\n"; |
||
2145 | foreach ($this->options as $argObj) { |
||
2146 | $out .= $this->printArgumentHelp($argObj); |
||
2147 | } |
||
2148 | |||
2149 | $out .= self::_conditionalLine($this->getFootNotes(), "\n\n", "\n"); |
||
2150 | |||
2151 | if ($this->word_wrap_width > 0) $out = wordwrap($out, $this->word_wrap_width, "\n", false); |
||
2152 | |||
2153 | return $out; |
||
2154 | } |
||
2155 | |||
2156 | protected /* VNagArgument[] */ $options = array(); |
||
2157 | |||
2158 | // Will be called by VNag via ReflectionMethod (like C++ style friends), because it should not be called manually. |
||
2159 | // Use VNag's function instead (since it adds to the argHandler too) |
||
2160 | protected function _addOption($argObj) { |
||
2161 | $this->options[] = $argObj; |
||
2162 | } |
||
2163 | |||
2164 | # FUT: Automatic creation of usage page. Which arguments are necessary? |
||
2165 | protected function printArgumentHelp($argObj) { |
||
2166 | $identifiers = array(); |
||
2167 | |||
2168 | $shortopt = $argObj->getShortopt(); |
||
2169 | if (!_empty($shortopt)) $identifiers[] = '-'.$shortopt; |
||
2170 | |||
2171 | $longopts = $argObj->getLongopts(); |
||
2172 | if (!is_null($longopts)) { |
||
2173 | foreach ($longopts as $longopt) { |
||
2174 | if (!_empty($longopt)) $identifiers[] = '--'.$longopt; |
||
2175 | } |
||
2176 | } |
||
2177 | |||
2178 | if (count($identifiers) == 0) return; |
||
2179 | |||
2180 | $valueName = $argObj->getValueName(); |
||
2181 | |||
2182 | $arginfo = ''; |
||
2183 | switch ($argObj->getValuePolicy()) { |
||
2184 | case VNagArgument::VALUE_FORBIDDEN: |
||
2185 | $arginfo = ''; |
||
2186 | break; |
||
2187 | case VNagArgument::VALUE_REQUIRED: |
||
2188 | $arginfo = '='.$valueName; |
||
2189 | break; |
||
2190 | case VNagArgument::VALUE_OPTIONAL: |
||
2191 | $arginfo = '[='.$valueName.']'; |
||
2192 | break; |
||
2193 | } |
||
2194 | |||
2195 | $out = ''; |
||
2196 | $out .= implode(', ', $identifiers).$arginfo."\n"; |
||
2197 | |||
2198 | // https://nagios-plugins.org/doc/guidelines.html#AEN302 recommends supporting a 80x23 screen resolution. |
||
2199 | // While we cannot guarantee the vertical height, we can limit the width at least... |
||
2200 | |||
2201 | $content = trim($argObj->getHelpText()); |
||
2202 | if ($this->word_wrap_width > 0) $content = wordwrap($content, $this->word_wrap_width-$this->argument_indent, "\n", false); |
||
2203 | $lines = explode("\n", $content); |
||
2204 | |||
2205 | foreach ($lines as $line) { |
||
2206 | $out .= str_repeat(' ', $this->argument_indent).$line."\n"; |
||
2207 | } |
||
2208 | $out .= "\n"; |
||
2209 | |||
2210 | return $out; |
||
2211 | } |
||
2212 | |||
2213 | // $pluginName should contain the name of the plugin, without version. |
||
2214 | protected $pluginName; |
||
2215 | public function setPluginName($pluginName) { |
||
2216 | $this->pluginName = $this->replaceStuff($pluginName); |
||
2217 | } |
||
2218 | public function getPluginName() { |
||
2219 | if (_empty($this->pluginName)) { |
||
2220 | global $argv; |
||
2221 | return basename($argv[0]); |
||
2222 | } else { |
||
2223 | return $this->pluginName; |
||
2224 | } |
||
2225 | } |
||
2226 | |||
2227 | private static function isCertified($file) { |
||
2228 | $cont = file_get_contents($file); |
||
2229 | |||
2230 | $regex = '@<\?php /\* <ViaThinkSoftSignature>(.+)</ViaThinkSoftSignature> \*/ \?>\n@ismU'; |
||
2231 | |||
22 | daniel-mar | 2232 | $m = array(); |
2 | daniel-mar | 2233 | if (!preg_match($regex, $cont, $m)) { |
2234 | return false; |
||
2235 | } |
||
2236 | $signature = base64_decode($m[1]); |
||
2237 | |||
2238 | $naked = preg_replace($regex, '', $cont); |
||
2239 | $hash = hash("sha256", $naked.basename($file)); |
||
2240 | |||
2241 | $public_key = <<<'VTSKEY' |
||
2242 | -----BEGIN PUBLIC KEY----- |
||
2243 | MIIEIjANBgkqhkiG9w0BAQEFAAOCBA8AMIIECgKCBAEA4UEmad2KHWzfGLcAzbOD |
||
2244 | IhqWyoPA1Cg4zN5YK/CWUiE7sh2CNinIwYqGnIOhZLp54/Iyv3H05QeWJU7kD+jQ |
||
2245 | 5JwR8+pqk8ZGBfqlxXUBJ2bZhYIBJZYfilSROa7jgPPrrw0CjdGLmM3wmc8ztQRv |
||
2246 | 4GpP7MaKVyVOsRz5xEcpzghWZ+Cl8Nxq1Vo02RkMYOOPA16abxZ65lVM8Vv2EKGf |
||
2247 | /VAVViTFvLWPxggvt1fbJJniC0cwt8gjzFXt6IJJSRlqc1lOO9ZIa/EWDKuHKQ1n |
||
2248 | ENQCqnuVPFDZU3lU20Z+6+EA0YngcvNYi3ucdIvgBd4Yv5FetzuxiOZUoDRfh/3R |
||
2249 | 6dCJ8CvRiq0BSZcynTIWNmF3AVsH7vjxZe8kMDbwZNnR0suZ5MfBh6L/s1lCEWlS |
||
2250 | GwmCLc3MnOLxq3JLnfmbVa509YxlUamdSswnvzes28AjnzQ3LQchspP2a8bSXH6/ |
||
2251 | qpbwvmV5WiNgwJck04VhaXrRRy3XFSwuk7KU/L4aqadXP26kgDqIYNvPXSa9JyGc |
||
2252 | 14zwdmAtn36o8vpXM/A7GhdWqgPLlJbdTdK6IfwpBs8P/JB6y3t6RzAGiEOITdj9 |
||
2253 | QUhW+sAoKno0j4WT7s80vWNWz37WoFJcvVLnVEYitnW6DqM+GOt2od3g6WgI6dOa |
||
2254 | MESA4J44Y4x1gXBw/M6F/ZngP4EJoAUG0GbzsaZ6HKLt4pDTZmw8PnNcXrOMYkr/ |
||
2255 | N5EliTXil45DCaLkgNJmpdXjNpIvShW4ogq2osw+SQUalnAbW8ddiaOVCdgXkDFq |
||
2256 | gvnl5QSeUrKPF5v+vlnwWar6Rp7iInQpnA+PTSbAlO3Dd9WqbWx+uNoI/kXUlN0O |
||
2257 | a/vi5Uwat2Bz3N+jIpnBqg4+O+SG0z3UCVmT6Leg+kqO/rXbzoVv/DV7E30vTqdo |
||
2258 | wsswdJEM1BI7Wyid6HPwBek+rdv77gUg3W37vUcdfKxsYRcoHriXLHpmENznJcEx |
||
2259 | /nvilw6To1zx2LKmM/p56MQriKkXnqoOBpkpn3PaWyXZKY9xJNTAbcSP3haE7z9p |
||
2260 | PzJw88KI8dnYuFg4yS/AgmVGAUtu3bhDG4qF9URu2ck868zViH996lraYkmFIWJG |
||
2261 | r7h1LImhrwDEJvb/rOW8QvOZBX9H6pcSKs/LQbeoy6HMIOTlny+S15xtiS4t6Ayv |
||
2262 | 3m0ry5c0qkl/mgKvGpeRnNlrcr6mb2fzxxGvcuBzi25wgIbRLPgJoqsmeBvW1OLU |
||
2263 | +9DpkNvitEJnPRo86v0VF86aou12Sm8Wb4mtrQ7h3qLIYvw2LN2mYh4WlgrSwPpx |
||
2264 | YvE2+vWapilnnDWoiu2ZmDWa7WW/ihqvX9fmp/qzxQvJmBYIN8dFpgcNLqSx526N |
||
2265 | bwIDAQAB |
||
2266 | -----END PUBLIC KEY----- |
||
2267 | VTSKEY; |
||
2268 | |||
21 | daniel-mar | 2269 | if (!function_exists('openssl_verify')) return null; |
2270 | |||
2 | daniel-mar | 2271 | if (!openssl_verify($hash, $signature, $public_key, OPENSSL_ALGO_SHA256)) { |
2272 | return false; |
||
2273 | } |
||
2274 | |||
2275 | return true; |
||
2276 | } |
||
2277 | |||
2278 | // $version should contain the version, not the program name or copyright. |
||
2279 | protected $version; |
||
2280 | public function setVersion($version) { |
||
2281 | $this->version = $this->replaceStuff($version); |
||
2282 | } |
||
2283 | public function getVersion() { |
||
2284 | return $this->version; |
||
2285 | } |
||
2286 | public function getNameAndVersion() { |
||
2287 | $ret = $this->getPluginName(); |
||
2288 | if (_empty($ret)) return null; |
||
2289 | |||
2290 | $ver = $this->getVersion(); |
||
2291 | if (!_empty($ver)) { |
||
2292 | $ret = sprintf(VNagLang::$x_version_x, $ret, $ver); |
||
2293 | } |
||
2294 | $ret = trim($ret); |
||
2295 | |||
2296 | $certified = true; |
||
2297 | foreach (get_included_files() as $file) { |
||
2298 | $certified &= self::isCertified($file); |
||
2299 | } |
||
2300 | if ($certified) { |
||
2301 | $ret .= ' (' . VNagLang::$certified . ')'; |
||
2302 | } |
||
2303 | |||
2304 | return $ret; |
||
2305 | } |
||
2306 | |||
2307 | // $copyright should contain the copyright only, no program name or version. |
||
2308 | // $CURYEAR$ will be replaced by the current year |
||
2309 | protected $copyright; |
||
2310 | public function setCopyright($copyright) { |
||
2311 | $this->copyright = $this->replaceStuff($copyright); |
||
2312 | } |
||
2313 | |||
2314 | private function getVNagCopyright() { |
||
2315 | if (VNag::is_http_mode()) { |
||
2316 | $vts_email = 'www.viathinksoft.com'; // don't publish email address at web services because of spam bots |
||
2317 | } else { |
||
2318 | $vts_email = base64_decode('aW5mb0B2aWF0aGlua3NvZnQuZGU='); // protect email address from spambots which might parse this code |
||
2319 | } |
||
2320 | return "VNag Framework ".VNag::VNAG_VERSION." (C) 2014-".date('Y')." ViaThinkSoft <$vts_email>"; |
||
2321 | } |
||
2322 | |||
2323 | public function getCopyright() { |
||
2324 | if (_empty($this->copyright)) { |
||
2325 | return sprintf(VNagLang::$plugin_uses, $this->getVNagCopyright()); |
||
2326 | } else { |
||
2327 | return trim($this->copyright)."\n".sprintf(VNagLang::$uses, $this->getVNagCopyright()); |
||
2328 | } |
||
2329 | } |
||
2330 | |||
2331 | // $shortDescription should describe what this plugin does. |
||
2332 | protected $shortDescription; |
||
2333 | public function setShortDescription($shortDescription) { |
||
2334 | $this->shortDescription = $this->replaceStuff($shortDescription); |
||
2335 | } |
||
2336 | public function getShortDescription() { |
||
2337 | if (_empty($this->shortDescription)) { |
||
2338 | return null; |
||
2339 | } else { |
||
2340 | $content = $this->shortDescription; |
||
2341 | if ($this->word_wrap_width > 0) $content = wordwrap($content, $this->word_wrap_width, "\n", false); |
||
2342 | return $content; |
||
2343 | } |
||
2344 | } |
||
2345 | |||
2346 | protected function replaceStuff($text) { |
||
2347 | global $argv; |
||
2348 | $text = str_replace('$SCRIPTNAME$', $argv[0], $text); |
||
2349 | $text = str_replace('$CURYEAR$', date('Y'), $text); |
||
2350 | return $text; |
||
2351 | } |
||
2352 | |||
2353 | // $syntax should contain the option syntax only, no explanations. |
||
2354 | // $SCRIPTNAME$ will be replaced by the actual script name |
||
2355 | // $CURYEAR$ will be replaced by the current year |
||
2356 | # FUT: Automatically generate syntax? |
||
2357 | protected $syntax; |
||
2358 | public function setSyntax($syntax) { |
||
2359 | $syntax = $this->replaceStuff($syntax); |
||
2360 | $this->syntax = $syntax; |
||
2361 | } |
||
2362 | public function getUsage() { |
||
2363 | if (_empty($this->syntax)) { |
||
2364 | return null; |
||
2365 | } else { |
||
2366 | return sprintf(VNagLang::$usage_x, $this->syntax); |
||
2367 | } |
||
2368 | } |
||
2369 | |||
2370 | // $footNotes can be contact information or other notes which should appear in --help |
||
2371 | protected $footNotes; |
||
2372 | public function setFootNotes($footNotes) { |
||
2373 | $this->footNotes = $this->replaceStuff($footNotes); |
||
2374 | } |
||
2375 | public function getFootNotes() { |
||
2376 | return $this->footNotes; |
||
2377 | } |
||
2378 | } |
||
2379 | |||
2380 | class VNagLang { |
||
2381 | public static function status($code, $statusmodel) { |
||
2382 | switch ($statusmodel) { |
||
2383 | case VNag::STATUSMODEL_SERVICE: |
||
2384 | switch ($code) { |
||
2385 | case VNag::STATUS_OK: |
||
2386 | return 'OK'; |
||
29 | daniel-mar | 2387 | #break; |
2 | daniel-mar | 2388 | case VNag::STATUS_WARNING: |
2389 | return 'Warning'; |
||
29 | daniel-mar | 2390 | #break; |
2 | daniel-mar | 2391 | case VNag::STATUS_CRITICAL: |
2392 | return 'Critical'; |
||
29 | daniel-mar | 2393 | #break; |
2 | daniel-mar | 2394 | case VNag::STATUS_UNKNOWN: |
2395 | return 'Unknown'; |
||
29 | daniel-mar | 2396 | #break; |
2 | daniel-mar | 2397 | default: |
2398 | return sprintf('Error (%d)', $code); |
||
29 | daniel-mar | 2399 | #break; |
2 | daniel-mar | 2400 | } |
29 | daniel-mar | 2401 | #break; |
2 | daniel-mar | 2402 | case VNag::STATUSMODEL_HOST: |
2403 | switch ($code) { |
||
2404 | case VNag::STATUS_UP: |
||
2405 | return 'Up'; |
||
29 | daniel-mar | 2406 | #break; |
2 | daniel-mar | 2407 | case VNag::STATUS_DOWN: |
2408 | return 'Down'; |
||
29 | daniel-mar | 2409 | #break; |
2 | daniel-mar | 2410 | default: |
2411 | return sprintf('Maintain last state (%d)', $code); |
||
29 | daniel-mar | 2412 | #break; |
2 | daniel-mar | 2413 | } |
29 | daniel-mar | 2414 | #break; |
2 | daniel-mar | 2415 | default: |
2416 | throw new VNagIllegalStatusModel(sprintf(self::$illegal_statusmodel, $statusmodel)); |
||
29 | daniel-mar | 2417 | #break; |
2 | daniel-mar | 2418 | } |
2419 | } |
||
2420 | |||
2421 | static $nagios_output = 'VNag-Output'; |
||
2422 | static $verbose_info = 'Verbose information'; |
||
2423 | static $status = 'Status'; |
||
2424 | static $message = 'Message'; |
||
2425 | static $performance_data = 'Performance data'; |
||
2426 | static $status_ok = 'OK'; |
||
2427 | static $status_warn = 'Warning'; |
||
2428 | static $status_critical = 'Critical'; |
||
2429 | static $status_unknown = 'Unknown'; |
||
2430 | static $status_error = 'Error'; |
||
2431 | static $unhandled_exception_without_msg = "Unhandled exception of type %s"; |
||
2432 | static $plugin_uses = 'This plugin uses %s'; |
||
2433 | static $uses = 'uses %s'; |
||
2434 | static $x_version_x = '%s, version %s'; |
||
2435 | |||
2436 | // Argument names (help page) |
||
2437 | static $argname_value = 'value'; |
||
2438 | static $argname_seconds = 'seconds'; |
||
2439 | static $certified = 'Certified by ViaThinkSoft'; |
||
2440 | |||
2441 | // Exceptions |
||
2442 | static $query_without_expected_argument = "The argument '%s' is queried, but was not added to the list of expected arguments. Please contact the plugin author."; |
||
2443 | static $required_argument_missing = "The argument '%s' is required."; |
||
2444 | static $performance_data_invalid = 'Performance data invalid.'; |
||
2445 | static $no_standard_arguments_with_letter = "No standard argument with letter '%s' exists."; |
||
2446 | static $invalid_start_value = 'Invalid start value.'; |
||
2447 | static $invalid_end_value = 'Invalid end value.'; |
||
2448 | static $start_is_greater_than_end = 'Start is greater than end value.'; |
||
2449 | static $value_name_forbidden = "Implementation error: You may not define a value name for the argument, because the value policy is VALUE_FORBIDDEN."; |
||
2450 | static $value_name_required = "Implementation error: Please define a name for the argument (so it can be shown in the help page)."; |
||
2451 | static $illegal_shortopt = "Illegal shortopt '-%s'."; |
||
2452 | static $illegal_longopt = "Illegal longopt '--%s'."; |
||
2453 | static $illegal_valuepolicy = "valuePolicy has illegal value '%s'."; |
||
2454 | static $range_invalid_syntax = "Syntax error in range '%s'."; |
||
2455 | static $timeout_value_invalid = "Timeout value '%s' is invalid."; |
||
2456 | static $range_is_invalid = 'Range is invalid.'; |
||
2457 | static $timeout_exception = 'Timeout!'; |
||
2458 | static $perfdata_label_equal_sign_forbidden = 'Label may not contain an equal sign.'; |
||
2459 | static $perfdata_value_must_be_in_class = 'Value must be in class [-0-9.] or be \'U\' if the actual value can\'t be determined.'; |
||
2460 | static $perfdata_min_must_be_in_class = 'Min must be in class [-0-9.] or empty.'; |
||
2461 | static $perfdata_max_must_be_in_class = 'Max must be in class [-0-9.] or empty.'; |
||
2462 | static $perfdata_uom_not_recognized = 'UOM (unit of measurement) "%s" is not recognized.'; |
||
2463 | static $perfdata_mixed_uom_not_implemented = 'Mixed UOMs (%s and %s) are currently not supported.'; |
||
2464 | static $no_compatible_range_uom_found = 'Measured values are not compatible with the provided warning/critical parameter. Most likely, the UOM is incompatible.'; |
||
2465 | static $exception_x = '%s (%s)'; |
||
2466 | static $no_syntax_defined = 'The author of this plugin has not defined a syntax for this plugin.'; |
||
2467 | static $usage_x = "Usage:\n%s"; |
||
2468 | static $options = "Options:"; |
||
2469 | static $illegal_statusmodel = "Invalid statusmodel %d."; |
||
2470 | static $none = '[none]'; |
||
2471 | static $valueUomPairSyntaxError = 'Syntax error at "%s". Syntax must be Value[UOM].'; |
||
2472 | static $too_few_warning_ranges = "You have too few warning ranges (currently trying to get element %d)."; |
||
2473 | static $too_few_critical_ranges = "You have too few critical ranges (currently trying to get element %d)."; |
||
2474 | static $dataset_missing = 'Dataset missing.'; |
||
2475 | static $payload_not_base64 = 'The payload is not valid Base64.'; |
||
2476 | static $payload_not_json = 'The payload is not valid JSON.'; |
||
2477 | static $signature_missing = 'The signature is missing.'; |
||
2478 | static $signature_not_bas64 = 'The signature is not valid Base64.'; |
||
2479 | static $signature_invalid = 'The signature is invalid. The connection might have been tampered, or a different key is used.'; |
||
2480 | static $pubkey_file_not_found = "Public key file %s was not found."; |
||
2481 | static $pubkey_file_not_readable = "Public key file %s is not readable."; |
||
2482 | static $privkey_file_not_found = "Private key file %s was not found."; |
||
24 | daniel-mar | 2483 | static $privkey_not_readable = "Private key is not readable."; |
2 | daniel-mar | 2484 | static $privkey_file_not_readable = "Private key file %s is not readable."; |
24 | daniel-mar | 2485 | static $signature_failed = "Signature failed."; |
2 | daniel-mar | 2486 | static $perfdata_line_invalid = "Performance data line %s is invalid."; |
2487 | static $singlevalue_unexpected_at_symbol = 'This plugin does not allow the @-symbol at ranges for single values.'; |
||
2488 | static $illegalSingleValueBehavior = "Illegal value for 'singleValueBehavior'. Please contact the creator of the plugin."; |
||
2489 | static $dataset_encryption_no_array = 'Dataset encryption information invalid.'; |
||
2490 | static $require_password = 'This resource is protected with a password. Please provide a password.'; |
||
2491 | static $wrong_password = 'This resource is protected with a password. You have provided the wrong password, or it was changed.'; |
||
2492 | static $convert_x_y_error = 'Cannot convert from UOM %s to UOM %s.'; |
||
2493 | static $php_error = 'PHP has detected an error in the plugin. Please contact the plugin author.'; |
||
2494 | static $output_level_lowered = "Output Buffer level lowered during cbRun(). Please contact the plugin author."; |
||
21 | daniel-mar | 2495 | static $openssl_missing = "OpenSSL is missing. Therefore, encryption and signatures are not available."; |
2 | daniel-mar | 2496 | |
2497 | // Help texts |
||
2498 | static $warning_range = 'Warning range'; |
||
2499 | static $critical_range = 'Critical range'; |
||
2500 | static $prints_version = 'Prints version'; |
||
2501 | static $verbosity_helptext = 'Verbosity -v, -vv or -vvv'; |
||
2502 | static $timeout_helptext = 'Sets timeout in seconds'; |
||
2503 | static $help_helptext = 'Prints help page'; |
||
2504 | static $prints_usage = 'Prints usage'; |
||
2505 | |||
2506 | static $notConstructed = 'Parent constructor not called with parent::__construct().'; |
||
2507 | } |
||
2508 | |||
2509 | function vnagErrorHandler($errorkind, $errortext, $file, $line) { |
||
20 | daniel-mar | 2510 | // This function "converts" PHP runtime errors into Exceptions, which can then be handled by VNag::handleException() |
19 | daniel-mar | 2511 | global $inside_vnag_run; |
20 | daniel-mar | 2512 | |
19 | daniel-mar | 2513 | if (!$inside_vnag_run && VNag::is_http_mode()) { |
2514 | // We want to avoid that the VNag-Exception will show up in a website that contains |
||
2515 | // an embedded VNag monitor, so if we are not inside a running VNag code, |
||
2516 | // we will call the normal PHP error handler. |
||
2517 | return false; |
||
2518 | } |
||
20 | daniel-mar | 2519 | |
2 | daniel-mar | 2520 | if (!(error_reporting() & $errorkind)) { |
2521 | // Code is not included in error_reporting. Don't do anything. |
||
19 | daniel-mar | 2522 | return true; |
2 | daniel-mar | 2523 | } |
2524 | |||
2525 | // We want 100% clean scripts, so any error, warning or notice will shutdown the script |
||
2526 | // This also fixes the issue that PHP will end with result code 0, showing an error. |
||
2527 | |||
2528 | // Error kinds see http://php.net/manual/en/errorfunc.constants.php |
||
2529 | if (defined('E_ERROR') && ($errorkind == E_ERROR)) $errorkind = 'Error'; |
||
2530 | if (defined('E_WARNING') && ($errorkind == E_WARNING)) $errorkind = 'Warning'; |
||
2531 | if (defined('E_PARSE') && ($errorkind == E_PARSE)) $errorkind = 'Parse'; |
||
2532 | if (defined('E_NOTICE') && ($errorkind == E_NOTICE)) $errorkind = 'Notice'; |
||
2533 | if (defined('E_CORE_ERROR') && ($errorkind == E_CORE_ERROR)) $errorkind = 'Core Error'; |
||
2534 | if (defined('E_CORE_WARNING') && ($errorkind == E_CORE_WARNING)) $errorkind = 'Core Warning'; |
||
2535 | if (defined('E_COMPILE_ERROR') && ($errorkind == E_COMPILE_ERROR)) $errorkind = 'Compile Error'; |
||
2536 | if (defined('E_COMPILE_WARNING') && ($errorkind == E_COMPILE_WARNING)) $errorkind = 'Compile Warning'; |
||
2537 | if (defined('E_USER_ERROR') && ($errorkind == E_USER_ERROR)) $errorkind = 'User Error'; |
||
2538 | if (defined('E_USER_WARNING') && ($errorkind == E_USER_WARNING)) $errorkind = 'User Warning'; |
||
2539 | if (defined('E_USER_NOTICE') && ($errorkind == E_USER_NOTICE)) $errorkind = 'User Notice'; |
||
2540 | if (defined('E_STRICT') && ($errorkind == E_STRICT)) $errorkind = 'Strict'; |
||
2541 | if (defined('E_RECOVERABLE_ERROR') && ($errorkind == E_RECOVERABLE_ERROR)) $errorkind = 'Recoverable Error'; |
||
2542 | if (defined('E_DEPRECATED') && ($errorkind == E_DEPRECATED)) $errorkind = 'Deprecated'; |
||
2543 | if (defined('E_USER_DEPRECATED') && ($errorkind == E_USER_DEPRECATED)) $errorkind = 'User Deprecated'; |
||
2544 | throw new VNagException(VNagLang::$php_error . " $errortext at $file:$line (kind $errorkind)"); |
||
2545 | |||
19 | daniel-mar | 2546 | // true = the PHP internal error handling will NOT be called. |
29 | daniel-mar | 2547 | #return true; |
2 | daniel-mar | 2548 | } |
2549 | |||
19 | daniel-mar | 2550 | $inside_vnag_run = false; |
2 | daniel-mar | 2551 | $old_error_handler = set_error_handler("vnagErrorHandler"); |
2552 | |||
2553 | // === End of document === |