File Coverage

blib/lib/Monitoring/Livestatus.pm
Criterion Covered Total %
statement 202 565 35.7
branch 87 322 27.0
condition 22 96 22.9
subroutine 24 41 58.5
pod 17 17 100.0
total 352 1041 33.8


line stmt bran cond sub pod time code
1             package Monitoring::Livestatus;
2              
3 5     5   15250 use 5.006;
  5         13  
4 5     5   20 use strict;
  5         4  
  5         82  
5 5     5   21 use warnings;
  5         6  
  5         158  
6 5     5   1791 use Data::Dumper qw/Dumper/;
  5         22034  
  5         326  
7 5     5   25 use Carp qw/carp croak confess/;
  5         6  
  5         232  
8 5     5   21 use Digest::MD5 qw(md5_hex);
  5         6  
  5         195  
9 5     5   3233 use JSON::XS ();
  5         20330  
  5         132  
10 5     5   2887 use Storable qw/dclone/;
  5         12932  
  5         357  
11              
12 5     5   1854 use Monitoring::Livestatus::INET qw//;
  5         10  
  5         91  
13 5     5   1372 use Monitoring::Livestatus::UNIX qw//;
  5         7  
  5         25442  
14              
15             our $VERSION = '0.78';
16              
17              
18             # list of allowed options
19             my $allowed_options = {
20             'addpeer' => 1,
21             'backend' => 1,
22             'columns' => 1,
23             'deepcopy' => 1,
24             'header' => 1,
25             'limit' => 1,
26             'limit_start' => 1,
27             'limit_length' => 1,
28             'rename' => 1,
29             'slice' => 1,
30             'sum' => 1,
31             'callbacks' => 1,
32             'wrapped_json' => 1,
33             'sort' => 1,
34             'offset' => 1,
35             };
36              
37             =head1 NAME
38              
39             Monitoring::Livestatus - Perl API for check_mk livestatus to access runtime
40             data from Nagios and Icinga
41              
42             =head1 SYNOPSIS
43              
44             use Monitoring::Livestatus;
45             my $ml = Monitoring::Livestatus->new(
46             socket => '/var/lib/livestatus/livestatus.sock'
47             );
48             my $hosts = $ml->selectall_arrayref("GET hosts");
49              
50             =head1 DESCRIPTION
51              
52             This module connects via socket/tcp to the livestatus addon for Naemon, Nagios,
53             Icinga and Shinken. You first have to install and activate the livestatus addon
54             in your monitoring installation.
55              
56             =head1 CONSTRUCTOR
57              
58             =head2 new ( [ARGS] )
59              
60             Creates an C object. C takes at least the
61             socketpath. Arguments are in key-value pairs.
62              
63             =over 4
64              
65             =item socket
66              
67             path to the UNIX socket of check_mk livestatus
68              
69             =item server
70              
71             uses this server for a TCP connection
72              
73             =item peer
74              
75             alternative way to set socket or server, if value contains ':' server is used,
76             else socket
77              
78             =item name
79              
80             human readable name for this connection, defaults to the the socket/server
81             address
82              
83             =item verbose
84              
85             verbose mode
86              
87             =item line_separator
88              
89             ascii code of the line separator, defaults to 10, (newline)
90              
91             =item column_separator
92              
93             ascii code of the column separator, defaults to 0 (null byte)
94              
95             =item list_separator
96              
97             ascii code of the list separator, defaults to 44 (comma)
98              
99             =item host_service_separator
100              
101             ascii code of the host/service separator, defaults to 124 (pipe)
102              
103             =item keepalive
104              
105             enable keepalive. Default is off
106              
107             =item errors_are_fatal
108              
109             errors will die with an error message. Default: on
110              
111             =item warnings
112              
113             show warnings
114             currently only querys without Columns: Header will result in a warning
115              
116             =item timeout
117              
118             set a general timeout. Used for connect and querys, no default
119              
120             =item query_timeout
121              
122             set a query timeout. Used for retrieving querys, Default 60sec
123              
124             =item connect_timeout
125              
126             set a connect timeout. Used for initial connections, default 5sec
127              
128             =back
129              
130             If the constructor is only passed a single argument, it is assumed to
131             be a the C specification. Use either socker OR server.
132              
133             =cut
134              
135             sub new {
136 26     26 1 3197 my($class,@args) = @_;
137 26 100       58 unshift(@args, 'peer') if scalar @args == 1;
138 26         77 my(%options) = @args;
139              
140 26         198 my $self = {
141             'verbose' => 0, # enable verbose output
142             'socket' => undef, # use unix sockets
143             'server' => undef, # use tcp connections
144             'peer' => undef, # use for socket / server connections
145             'name' => undef, # human readable name
146             'line_separator' => 10, # defaults to newline
147             'column_separator' => 0, # defaults to null byte
148             'list_separator' => 44, # defaults to comma
149             'host_service_separator' => 124, # defaults to pipe
150             'keepalive' => 0, # enable keepalive?
151             'errors_are_fatal' => 1, # die on errors
152             'backend' => undef, # should be keept undef, used internally
153             'timeout' => undef, # timeout for tcp connections
154             'query_timeout' => 60, # query timeout for tcp connections
155             'connect_timeout' => 5, # connect timeout for tcp connections
156             'warnings' => 1, # show warnings, for example on querys without Column: Header
157             'logger' => undef, # logger object used for statistical informations and errors / warnings
158             'deepcopy' => undef, # copy result set to avoid errors with tied structures
159             'retries_on_connection_error' => 3, # retry x times to connect
160             'retry_interval' => 1, # retry after x seconds
161             };
162              
163 26         71 my %old_key = (
164             line_seperator => 'line_separator',
165             column_seperator => 'column_separator',
166             list_seperator => 'list_separator',
167             host_service_seperator => 'host_service_separator',
168             );
169              
170             # previous versions had spelling errors in the key name
171 26         54 for my $opt_key (keys %old_key) {
172 104 50       154 if(exists $options{$opt_key}) {
173 0         0 my $value = $options{$opt_key};
174 0         0 $options{ $old_key{$opt_key} } = $value;
175 0         0 delete $options{$opt_key};
176             }
177             }
178              
179 26         47 for my $opt_key (keys %options) {
180 97 50       106 if(exists $self->{$opt_key}) {
181 97         94 $self->{$opt_key} = $options{$opt_key};
182             }
183             else {
184 0         0 croak("unknown option: $opt_key");
185             }
186             }
187              
188 26 50 33     61 if($self->{'verbose'} && !defined $self->{'logger'}) {
189 0         0 croak('please specify a logger object when using verbose mode');
190             }
191              
192             # setting a general timeout?
193 26 100       45 if(defined $self->{'timeout'}) {
194 2         3 $self->{'query_timeout'} = $self->{'timeout'};
195 2         2 $self->{'connect_timeout'} = $self->{'timeout'};
196             }
197              
198 26         24 bless $self, $class;
199              
200             # set our peer(s) from the options
201 26         51 my $peer = $self->_get_peer();
202              
203 26 100       52 if(!defined $self->{'backend'}) {
204 11         15 $options{'name'} = $peer->{'name'};
205 11         12 $options{'peer'} = $peer->{'peer'};
206 11 100       24 if($peer->{'type'} eq 'UNIX') {
    50          
207 8         62 $self->{'CONNECTOR'} = Monitoring::Livestatus::UNIX->new(%options);
208             }
209             elsif($peer->{'type'} eq 'INET') {
210 3         20 $self->{'CONNECTOR'} = Monitoring::Livestatus::INET->new(%options);
211             }
212 11         18 $self->{'peer'} = $peer->{'peer'};
213             }
214              
215             # set names and peer for non multi backends
216 26 100 66     91 if(defined $self->{'CONNECTOR'}->{'name'} && !defined $self->{'name'}) {
217 11         10 $self->{'name'} = $self->{'CONNECTOR'}->{'name'};
218             }
219 26 50 66     67 if(defined $self->{'CONNECTOR'}->{'peer'} && !defined $self->{'peer'}) {
220 0         0 $self->{'peer'} = $self->{'CONNECTOR'}->{'peer'};
221             }
222              
223 26         94 return $self;
224             }
225              
226              
227             ########################################
228              
229             =head1 METHODS
230              
231             =head2 do
232              
233             do($statement)
234             do($statement, %opts)
235              
236             Send a single statement without fetching the result.
237             Always returns true.
238              
239             =cut
240              
241             sub do {
242 0     0 1 0 my($self, $statement, $opt) = @_;
243 0         0 $self->_send($statement, $opt);
244 0         0 return(1);
245             }
246              
247              
248             ########################################
249              
250             =head2 selectall_arrayref
251              
252             selectall_arrayref($statement)
253             selectall_arrayref($statement, %opts)
254             selectall_arrayref($statement, %opts, $limit )
255              
256             Sends a query and returns an array reference of arrays
257              
258             my $arr_refs = $ml->selectall_arrayref("GET hosts");
259              
260             to get an array of hash references do something like
261              
262             my $hash_refs = $ml->selectall_arrayref(
263             "GET hosts", { Slice => {} }
264             );
265              
266             to get an array of hash references from the first 2 returned rows only
267              
268             my $hash_refs = $ml->selectall_arrayref(
269             "GET hosts", { Slice => {} }, 2
270             );
271              
272             you may use limit to limit the result to this number of rows
273              
274             column aliases can be defined with a rename hash
275              
276             my $hash_refs = $ml->selectall_arrayref(
277             "GET hosts", {
278             Slice => {},
279             rename => {
280             'name' => 'host_name'
281             }
282             }
283             );
284              
285             =cut
286              
287             sub selectall_arrayref {
288 1     1 1 411330 my($self, $statement, $opt, $limit, $result) = @_;
289 1 50       8 $limit = 0 unless defined $limit;
290              
291             # make opt hash keys lowercase
292 1 50       24 $opt = &_lowercase_and_verify_options($self, $opt) unless $result;
293              
294 1 50 33     12 $self->_log_statement($statement, $opt, $limit) if !$result && $self->{'verbose'};
295              
296 1 50       3 if(!defined $result) {
297 1         6 $result = &_send($self, $statement, $opt);
298 0 0       0 return $result if $ENV{'THRUK_SELECT'};
299              
300 0 0       0 if(!defined $result) {
301 0 0       0 return unless $self->{'errors_are_fatal'};
302 0         0 croak("got undef result for: $statement");
303             }
304             }
305              
306             # trim result set down to excepted row count
307 0 0 0     0 if(!$opt->{'offset'} && defined $limit && $limit >= 1) {
      0        
308 0 0       0 if(scalar @{$result->{'result'}} > $limit) {
  0         0  
309 0         0 @{$result->{'result'}} = @{$result->{'result'}}[0..$limit-1];
  0         0  
  0         0  
310             }
311             }
312              
313 0 0       0 if($opt->{'slice'}) {
314 0         0 my $callbacks = $opt->{'callbacks'};
315             # make an array of hashes, inplace to safe memory
316 0         0 my $keys = $result->{'keys'};
317             # renamed columns
318 0 0       0 if($opt->{'rename'}) {
319 0         0 $keys = dclone($result->{'keys'});
320 0         0 my $keysize = scalar @{$keys};
  0         0  
321 0         0 for(my $x=0; $x<$keysize;$x++) {
322 0         0 my $old = $keys->[$x];
323 0 0       0 if($opt->{'rename'}->{$old}) {
324 0         0 $keys->[$x] = $opt->{'rename'}->{$old};
325             }
326             }
327             }
328 0         0 $result = $result->{'result'};
329 0         0 my $rnum = scalar @{$result};
  0         0  
330 0         0 for(my $x=0;$x<$rnum;$x++) {
331             # sort array into hash slices
332 0         0 my %hash;
333 0         0 @hash{@{$keys}} = @{$result->[$x]};
  0         0  
  0         0  
334             # add callbacks
335 0 0       0 if($callbacks) {
336 0         0 for my $key (keys %{$callbacks}) {
  0         0  
337 0         0 $hash{$key} = $callbacks->{$key}->(\%hash);
338             }
339             }
340 0         0 $result->[$x] = \%hash;
341             }
342 0         0 return($result);
343             }
344              
345 0 0       0 if(exists $opt->{'callbacks'}) {
346 0         0 for my $res (@{$result->{'result'}}) {
  0         0  
347             # add callbacks
348 0 0       0 if(exists $opt->{'callbacks'}) {
349 0         0 for my $key (keys %{$opt->{'callbacks'}}) {
  0         0  
350 0         0 push @{$res}, $opt->{'callbacks'}->{$key}->($res);
  0         0  
351             }
352             }
353             }
354              
355 0         0 for my $key (keys %{$opt->{'callbacks'}}) {
  0         0  
356 0         0 push @{$result->{'keys'}}, $key;
  0         0  
357             }
358             }
359 0         0 return($result->{'result'});
360             }
361              
362              
363             ########################################
364              
365             =head2 selectall_hashref
366              
367             selectall_hashref($statement, $key_field)
368             selectall_hashref($statement, $key_field, %opts)
369              
370             Sends a query and returns a hashref with the given key
371              
372             my $hashrefs = $ml->selectall_hashref("GET hosts", "name");
373              
374             =cut
375              
376             sub selectall_hashref {
377 0     0 1 0 my($self, $statement, $key_field, $opt) = @_;
378              
379 0         0 $opt = &_lowercase_and_verify_options($self, $opt);
380              
381 0         0 $opt->{'slice'} = 1;
382              
383 0 0       0 croak('key is required for selectall_hashref') if !defined $key_field;
384              
385 0         0 my $result = $self->selectall_arrayref($statement, $opt);
386              
387 0         0 my %indexed;
388 0         0 for my $row (@{$result}) {
  0         0  
389 0 0       0 if($key_field eq '$peername') {
    0          
390 0         0 $indexed{$self->peer_name} = $row;
391             }
392             elsif(!defined $row->{$key_field}) {
393 0         0 my %possible_keys = keys %{$row};
  0         0  
394 0         0 croak("key $key_field not found in result set, possible keys are: ".join(', ', sort keys %possible_keys));
395             } else {
396 0         0 $indexed{$row->{$key_field}} = $row;
397             }
398             }
399 0         0 return(\%indexed);
400             }
401              
402              
403             ########################################
404              
405             =head2 selectcol_arrayref
406              
407             selectcol_arrayref($statement)
408             selectcol_arrayref($statement, %opt )
409              
410             Sends a query an returns an arrayref for the first columns
411              
412             my $array_ref = $ml->selectcol_arrayref("GET hosts\nColumns: name");
413              
414             $VAR1 = [
415             'localhost',
416             'gateway',
417             ];
418              
419             returns an empty array if nothing was found
420              
421             to get a different column use this
422              
423             my $array_ref = $ml->selectcol_arrayref(
424             "GET hosts\nColumns: name contacts",
425             { Columns => [2] }
426             );
427              
428             you can link 2 columns in a hash result set
429              
430             my %hash = @{
431             $ml->selectcol_arrayref(
432             "GET hosts\nColumns: name contacts",
433             { Columns => [1,2] }
434             )
435             };
436              
437             produces a hash with host the contact assosiation
438              
439             $VAR1 = {
440             'localhost' => 'user1',
441             'gateway' => 'user2'
442             };
443              
444             =cut
445              
446             sub selectcol_arrayref {
447 0     0 1 0 my($self, $statement, $opt) = @_;
448              
449             # make opt hash keys lowercase
450 0         0 $opt = &_lowercase_and_verify_options($self, $opt);
451              
452             # if now colums are set, use just the first one
453 0 0 0     0 if(!defined $opt->{'columns'} || ref $opt->{'columns'} ne 'ARRAY') {
454 0         0 @{$opt->{'columns'}} = qw{1};
  0         0  
455             }
456              
457 0         0 my $result = $self->selectall_arrayref($statement);
458              
459 0         0 my @column;
460 0         0 for my $row (@{$result}) {
  0         0  
461 0         0 for my $nr (@{$opt->{'columns'}}) {
  0         0  
462 0         0 push @column, $row->[$nr-1];
463             }
464             }
465 0         0 return(\@column);
466             }
467              
468              
469             ########################################
470              
471             =head2 selectrow_array
472              
473             selectrow_array($statement)
474             selectrow_array($statement, %opts)
475              
476             Sends a query and returns an array for the first row
477              
478             my @array = $ml->selectrow_array("GET hosts");
479              
480             returns undef if nothing was found
481              
482             =cut
483             sub selectrow_array {
484 0     0 1 0 my($self, $statement, $opt) = @_;
485              
486             # make opt hash keys lowercase
487 0         0 $opt = &_lowercase_and_verify_options($self, $opt);
488              
489 0         0 my @result = @{$self->selectall_arrayref($statement, $opt, 1)};
  0         0  
490 0 0       0 return @{$result[0]} if scalar @result > 0;
  0         0  
491 0         0 return;
492             }
493              
494              
495             ########################################
496              
497             =head2 selectrow_arrayref
498              
499             selectrow_arrayref($statement)
500             selectrow_arrayref($statement, %opts)
501              
502             Sends a query and returns an array reference for the first row
503              
504             my $arrayref = $ml->selectrow_arrayref("GET hosts");
505              
506             returns undef if nothing was found
507              
508             =cut
509             sub selectrow_arrayref {
510 0     0 1 0 my($self, $statement, $opt) = @_;
511              
512             # make opt hash keys lowercase
513 0         0 $opt = &_lowercase_and_verify_options($self, $opt);
514              
515 0         0 my $result = $self->selectall_arrayref($statement, $opt, 1);
516 0 0       0 return if !defined $result;
517 0 0       0 return $result->[0] if scalar @{$result} > 0;
  0         0  
518 0         0 return;
519             }
520              
521              
522             ########################################
523              
524             =head2 selectrow_hashref
525              
526             selectrow_hashref($statement)
527             selectrow_hashref($statement, %opt)
528              
529             Sends a query and returns a hash reference for the first row
530              
531             my $hashref = $ml->selectrow_hashref("GET hosts");
532              
533             returns undef if nothing was found
534              
535             =cut
536             sub selectrow_hashref {
537 0     0 1 0 my($self, $statement, $opt) = @_;
538              
539             # make opt hash keys lowercase
540 0         0 $opt = &_lowercase_and_verify_options($self, $opt);
541 0         0 $opt->{slice} = 1;
542              
543 0         0 my $result = $self->selectall_arrayref($statement, $opt, 1);
544 0 0       0 return if !defined $result;
545 0 0       0 return $result->[0] if scalar @{$result} > 0;
  0         0  
546 0         0 return;
547             }
548              
549              
550             ########################################
551              
552             =head2 selectscalar_value
553              
554             selectscalar_value($statement)
555             selectscalar_value($statement, %opt)
556              
557             Sends a query and returns a single scalar
558              
559             my $count = $ml->selectscalar_value("GET hosts\nStats: state = 0");
560              
561             returns undef if nothing was found
562              
563             =cut
564             sub selectscalar_value {
565 0     0 1 0 my($self, $statement, $opt) = @_;
566              
567             # make opt hash keys lowercase
568 0         0 $opt = &_lowercase_and_verify_options($self, $opt);
569              
570 0         0 my $row = $self->selectrow_arrayref($statement);
571 0 0       0 return if !defined $row;
572 0 0       0 return $row->[0] if scalar @{$row} > 0;
  0         0  
573 0         0 return;
574             }
575              
576             ########################################
577              
578             =head2 errors_are_fatal
579              
580             errors_are_fatal()
581             errors_are_fatal($value)
582              
583             Enable or disable fatal errors. When enabled the module will croak on any error.
584              
585             returns the current setting if called without new value
586              
587             =cut
588             sub errors_are_fatal {
589 0     0 1 0 my($self, $value) = @_;
590 0         0 my $old = $self->{'errors_are_fatal'};
591              
592 0         0 $self->{'errors_are_fatal'} = $value;
593 0 0       0 $self->{'CONNECTOR'}->{'errors_are_fatal'} = $value if defined $self->{'CONNECTOR'};
594              
595 0         0 return $old;
596             }
597              
598             ########################################
599              
600             =head2 warnings
601              
602             warnings()
603             warnings($value)
604              
605             Enable or disable warnings. When enabled the module will carp on warnings.
606              
607             returns the current setting if called without new value
608              
609             =cut
610             sub warnings {
611 0     0 1 0 my($self, $value) = @_;
612 0         0 my $old = $self->{'warnings'};
613              
614 0         0 $self->{'warnings'} = $value;
615 0 0       0 $self->{'CONNECTOR'}->{'warnings'} = $value if defined $self->{'CONNECTOR'};
616              
617 0         0 return $old;
618             }
619              
620              
621              
622             ########################################
623              
624             =head2 verbose
625              
626             verbose()
627             verbose($values)
628              
629             Enable or disable verbose output. When enabled the module will dump out debug output
630              
631             returns the current setting if called without new value
632              
633             =cut
634             sub verbose {
635 0     0 1 0 my($self, $value) = @_;
636 0         0 my $old = $self->{'verbose'};
637              
638 0         0 $self->{'verbose'} = $value;
639 0 0       0 $self->{'CONNECTOR'}->{'verbose'} = $value if defined $self->{'CONNECTOR'};
640              
641 0         0 return $old;
642             }
643              
644              
645             ########################################
646              
647             =head2 peer_addr
648              
649             $ml->peer_addr()
650              
651             returns the current peer address
652              
653             when using multiple backends, a list of all addresses is returned in list context
654              
655             =cut
656             sub peer_addr {
657 9     9 1 11 my($self) = @_;
658 9         32 return ''.$self->{'peer'};
659             }
660              
661              
662             ########################################
663              
664             =head2 peer_name
665              
666             $ml->peer_name()
667             $ml->peer_name($string)
668              
669             if new value is set, name is set to this value
670              
671             always returns the current peer name
672              
673             when using multiple backends, a list of all names is returned in list context
674              
675             =cut
676             sub peer_name {
677 9     9 1 3593 my($self, $value) = @_;
678              
679 9 50 33     25 if(defined $value and $value ne '') {
680 0         0 $self->{'name'} = $value;
681             }
682              
683 9         36 return ''.$self->{'name'};
684             }
685              
686              
687             ########################################
688              
689             =head2 peer_key
690              
691             $ml->peer_key()
692              
693             returns a uniq key for this peer
694              
695             when using multiple backends, a list of all keys is returned in list context
696              
697             =cut
698             sub peer_key {
699 0     0 1 0 my($self) = @_;
700              
701 0 0       0 if(!defined $self->{'key'}) { $self->{'key'} = md5_hex($self->peer_addr.' '.$self->peer_name); }
  0         0  
702              
703 0         0 return $self->{'key'};
704             }
705              
706             ########################################
707             # INTERNAL SUBS
708             ########################################
709             sub _send {
710 1     1   2 my($self, $statement, $opt) = @_;
711              
712 1 50       7 confess('duplicate data') if $opt->{'data'};
713              
714 1         2 delete $self->{'meta_data'};
715              
716 1         3 my $header = '';
717 1         1 my $keys;
718              
719 1         4 $Monitoring::Livestatus::ErrorCode = 0;
720 1         2 undef $Monitoring::Livestatus::ErrorMessage;
721              
722 1 50       5 return(490, $self->_get_error(490), undef) if !defined $statement;
723 1         2 chomp($statement);
724              
725 1         1 my($status,$msg,$body);
726 1 50 33     55 if($statement =~ m/^Separators:/mx) {
    50 33        
    50 33        
    50 33        
    50 33        
    50          
    50          
    50          
    50          
727 0         0 $status = 492;
728 0         0 $msg = $self->_get_error($status);
729             }
730              
731             elsif($statement =~ m/^KeepAlive:/mx) {
732 0         0 $status = 496;
733 0         0 $msg = $self->_get_error($status);
734             }
735              
736             elsif($statement =~ m/^ResponseHeader:/mx) {
737 0         0 $status = 495;
738 0         0 $msg = $self->_get_error($status);
739             }
740              
741             elsif($statement =~ m/^ColumnHeaders:/mx) {
742 0         0 $status = 494;
743 0         0 $msg = $self->_get_error($status);
744             }
745              
746             elsif($statement =~ m/^OuputFormat:/mx) {
747 0         0 $status = 493;
748 0         0 $msg = $self->_get_error($status);
749             }
750              
751             # should be cought in mlivestatus directly
752             elsif($statement =~ m/^Limit:\ (.*)$/mx and $1 !~ m/^\d+$/mx) {
753 0         0 $status = 403;
754 0         0 $msg = $self->_get_error($status);
755             }
756             elsif($statement =~ m/^GET\ (.*)$/mx and $1 =~ m/^\s*$/mx) {
757 0         0 $status = 403;
758 0         0 $msg = $self->_get_error($status);
759             }
760              
761             elsif($statement =~ m/^Columns:\ (.*)$/mx and ($1 =~ m/,/mx or $1 =~ /^\s*$/mx)) {
762 0         0 $status = 405;
763 0         0 $msg = $self->_get_error($status);
764             }
765             elsif($statement !~ m/^GET\ /mx and $statement !~ m/^COMMAND\ /mx) {
766 0         0 $status = 401;
767 0         0 $msg = $self->_get_error($status);
768             }
769              
770             else {
771              
772             # Add Limits header
773 1 50       4 if(defined $opt->{'limit_start'}) {
774 0         0 $statement .= "\nLimit: ".($opt->{'limit_start'} + $opt->{'limit_length'});
775             }
776              
777             # for querys with column header, no seperate columns will be returned
778 1 50 0     7 if($statement =~ m/^Columns:\ (.*)$/mx) {
    0          
779 1         6 ($statement,$keys) = $self->_extract_keys_from_columns_header($statement);
780             } elsif($statement =~ m/^Stats:\ (.*)$/mx or $statement =~ m/^StatsGroupBy:\ (.*)$/mx) {
781 0         0 ($statement,$keys) = extract_keys_from_stats_statement($statement);
782             }
783              
784             # Offset header (currently naemon only)
785 1 50       7 if(defined $opt->{'offset'}) {
786 0         0 $statement .= "\nOffset: ".$opt->{'offset'};
787             }
788              
789             # Sort header (currently naemon only)
790 1 50       4 if(defined $opt->{'sort'}) {
791 0         0 for my $sort (@{$opt->{'sort'}}) {
  0         0  
792 0         0 $statement .= "\nSort: ".$sort;
793             }
794             }
795              
796             # Commands need no additional header
797 1 50       5 if($statement !~ m/^COMMAND/mx) {
798 1 50       2 if($opt->{'wrapped_json'}) {
799 0         0 $header .= "OutputFormat: wrapped_json\n";
800             } else {
801 1         2 $header .= "OutputFormat: json\n";
802             }
803 1         3 $header .= "ResponseHeader: fixed16\n";
804 1 50       5 if($self->{'keepalive'}) {
805 0         0 $header .= "KeepAlive: on\n";
806             }
807             # remove empty lines from statement
808 1         5 $statement =~ s/\n+/\n/gmx;
809             }
810              
811             # add additional headers
812 1 50 33     7 if(defined $opt->{'header'} and ref $opt->{'header'} eq 'HASH') {
813 0         0 for my $key ( keys %{$opt->{'header'}}) {
  0         0  
814 0         0 $header .= $key.': '.$opt->{'header'}->{$key}."\n";
815             }
816             }
817              
818 1         1 chomp($statement);
819 1         3 my $send = "$statement\n$header";
820 1 50       2 $self->{'logger'}->debug('> '.Dumper($send)) if $self->{'verbose'};
821 1         6 ($status,$msg,$body) = &_send_socket($self, $send);
822 0 0       0 return([$status, $opt, $keys]) if $ENV{'THRUK_SELECT'};
823 0 0       0 if($self->{'verbose'}) {
824             #$self->{'logger'}->debug("got:");
825             #$self->{'logger'}->debug(Dumper(\@erg));
826 0         0 $self->{'logger'}->debug('status: '.Dumper($status));
827 0         0 $self->{'logger'}->debug('msg: '.Dumper($msg));
828 0         0 $self->{'logger'}->debug('< '.Dumper($body));
829             }
830             }
831              
832 0 0 0     0 if(!$status || $status >= 300) {
833 0 0       0 $body = '' if !defined $body;
834 0 0       0 $status = 300 if !defined $status;
835 0         0 chomp($body);
836 0         0 $Monitoring::Livestatus::ErrorCode = $status;
837 0 0 0     0 if(defined $body and $body ne '') {
838 0         0 $Monitoring::Livestatus::ErrorMessage = $body;
839             } else {
840 0         0 $Monitoring::Livestatus::ErrorMessage = $msg;
841             }
842 0 0       0 $self->{'logger'}->error($status.' - '.$Monitoring::Livestatus::ErrorMessage." in query:\n".$statement) if $self->{'verbose'};
843 0 0       0 if($self->{'errors_are_fatal'}) {
844 0         0 croak('ERROR '.$status.' - '.$Monitoring::Livestatus::ErrorMessage." in query:\n".$statement."\n");
845             }
846 0         0 return;
847             }
848              
849             # return a empty result set if nothing found
850 0 0       0 return({ keys => [], result => []}) if !defined $body;
851              
852 0         0 my $limit_start = 0;
853 0 0       0 if(defined $opt->{'limit_start'}) { $limit_start = $opt->{'limit_start'}; }
  0         0  
854             # body is already parsed
855 0         0 my $result;
856 0 0       0 if($status == 200) {
857 0         0 $result = $body;
858             } else {
859 0         0 my $json_decoder = JSON::XS->new->utf8->relaxed;
860             # fix json output
861 0         0 eval {
862 0         0 $result = $json_decoder->decode($body);
863             };
864             # fix low/high surrogate errors
865             # missing high surrogate character in surrogate pair
866             # surrogate pair expected
867 0 0       0 if($@) {
868             # replace u+D800 to u+DFFF (reserved utf-16 low/high surrogates)
869 0         0 $body =~ s/\\ud[89a-f]\w{2}/\\ufffd/gmxi;
870 0         0 eval {
871 0         0 $result = $json_decoder->decode($body);
872             };
873             }
874 0 0       0 if($@) {
875 0         0 my $message = 'ERROR '.$@." in text: '".$body."'\" for statement: '$statement'\n";
876 0 0       0 $self->{'logger'}->error($message) if $self->{'verbose'};
877 0 0       0 if($self->{'errors_are_fatal'}) {
878 0         0 croak($message);
879             }
880 0         0 return({ keys => [], result => []});
881             }
882             }
883 0 0       0 if(!defined $result) {
884 0         0 my $message = "ERROR undef result for text: '".$body."'\" for statement: '$statement'\n";
885 0 0       0 $self->{'logger'}->error($message) if $self->{'verbose'};
886 0 0       0 if($self->{'errors_are_fatal'}) {
887 0         0 croak($message);
888             }
889 0         0 return({ keys => [], result => []});
890             }
891              
892             # for querys with column header, no separate columns will be returned
893 0 0       0 if(!defined $keys) {
894 0 0       0 $self->{'logger'}->warn('got statement without Columns: header!') if $self->{'verbose'};
895 0 0       0 if($self->{'warnings'}) {
896 0         0 carp('got statement without Columns: header! -> '.$statement);
897             }
898 0         0 $keys = shift @{$result};
  0         0  
899             }
900              
901 0         0 return(&post_processing($self, $result, $opt, $keys));
902             }
903              
904             ########################################
905              
906             =head2 post_processing
907              
908             $ml->post_processing($result, $options, $keys)
909              
910             returns postprocessed result.
911              
912             Useful when using select based io.
913              
914             =cut
915             sub post_processing {
916 0     0 1 0 my($self, $result, $opt, $keys) = @_;
917              
918 0         0 my $orig_result;
919 0 0       0 if($opt->{'wrapped_json'}) {
920 0         0 $orig_result = $result;
921 0         0 $result = $result->{'data'};
922             }
923              
924             # add peer information?
925 0         0 my $with_peers = 0;
926 0 0 0     0 if(defined $opt->{'addpeer'} and $opt->{'addpeer'}) {
927 0         0 $with_peers = 1;
928             }
929              
930 0 0 0     0 if(defined $with_peers and $with_peers == 1) {
931 0         0 my $peer_name = $self->peer_name;
932 0         0 my $peer_addr = $self->peer_addr;
933 0         0 my $peer_key = $self->peer_key;
934              
935 0         0 unshift @{$keys}, 'peer_name';
  0         0  
936 0         0 unshift @{$keys}, 'peer_addr';
  0         0  
937 0         0 unshift @{$keys}, 'peer_key';
  0         0  
938              
939 0         0 for my $row (@{$result}) {
  0         0  
940 0         0 unshift @{$row}, $peer_name;
  0         0  
941 0         0 unshift @{$row}, $peer_addr;
  0         0  
942 0         0 unshift @{$row}, $peer_key;
  0         0  
943             }
944             }
945              
946             # set some metadata
947             $self->{'meta_data'} = {
948 0         0 'result_count' => scalar @{$result},
  0         0  
949             };
950 0 0       0 if($opt->{'wrapped_json'}) {
951 0         0 for my $key (keys %{$orig_result}) {
  0         0  
952 0 0       0 next if $key eq 'data';
953 0         0 $self->{'meta_data'}->{$key} = $orig_result->{$key};
954             }
955             }
956              
957 0         0 return({ keys => $keys, result => $result });
958             }
959              
960             ########################################
961             sub _open {
962 1     1   1 my($self) = @_;
963              
964             # return the current socket in keep alive mode
965 1 0 33     9 if($self->{'keepalive'} and defined $self->{'sock'} and $self->{'sock'}->connected) {
      33        
966 0 0       0 $self->{'logger'}->debug('reusing old connection') if $self->{'verbose'};
967 0         0 return($self->{'sock'});
968             }
969              
970 1         9 my $sock = $self->{'CONNECTOR'}->_open();
971              
972             # store socket for later retrieval
973 1 50       3 if($self->{'keepalive'}) {
974 0         0 $self->{'sock'} = $sock;
975             }
976              
977 1 50       3 $self->{'logger'}->debug('using new connection') if $self->{'verbose'};
978 1         6 return($sock);
979             }
980              
981             ########################################
982             sub _close {
983 0     0   0 my($self, $sock) = @_;
984 0         0 undef $self->{'sock'};
985 0         0 return($self->{'CONNECTOR'}->_close($sock));
986             }
987              
988              
989             ########################################
990              
991             =head1 QUERY OPTIONS
992              
993             In addition to the normal query syntax from the livestatus addon, it is
994             possible to set column aliases in various ways.
995              
996             =head2 AddPeer
997              
998             adds the peers name, addr and key to the result set:
999              
1000             my $hosts = $ml->selectall_hashref(
1001             "GET hosts\nColumns: name alias state",
1002             "name",
1003             { AddPeer => 1 }
1004             );
1005              
1006             =head2 Backend
1007              
1008             send the query only to some specific backends. Only
1009             useful when using multiple backends.
1010              
1011             my $hosts = $ml->selectall_arrayref(
1012             "GET hosts\nColumns: name alias state",
1013             { Backends => [ 'key1', 'key4' ] }
1014             );
1015              
1016             =head2 Columns
1017              
1018             only return the given column indexes
1019              
1020             my $array_ref = $ml->selectcol_arrayref(
1021             "GET hosts\nColumns: name contacts",
1022             { Columns => [2] }
1023             );
1024              
1025             see L for more examples
1026              
1027             =head2 Deepcopy
1028              
1029             deep copy/clone the result set.
1030              
1031             Only effective when using multiple backends and threads.
1032             This can be safely turned off if you don't change the
1033             result set.
1034             If you get an error like "Invalid value for shared scalar" error" this
1035             should be turned on.
1036              
1037             my $array_ref = $ml->selectcol_arrayref(
1038             "GET hosts\nColumns: name contacts",
1039             { Deepcopy => 1 }
1040             );
1041              
1042             =head2 Limit
1043              
1044             Just like the Limit: option from livestatus itself.
1045             In addition you can add a start,length limit.
1046              
1047             my $array_ref = $ml->selectcol_arrayref(
1048             "GET hosts\nColumns: name contacts",
1049             { Limit => "10,20" }
1050             );
1051              
1052             This example will return 20 rows starting at row 10. You will
1053             get row 10-30.
1054              
1055             Cannot be combined with a Limit inside the query
1056             because a Limit will be added automatically.
1057              
1058             Adding a limit this way will greatly increase performance and
1059             reduce memory usage.
1060              
1061             This option is multibackend safe contrary to the "Limit: " part of a statement.
1062             Sending a statement like "GET...Limit: 10" with 3 backends will result in 30 rows.
1063             Using this options, you will receive only the first 10 rows.
1064              
1065             =head2 Rename
1066              
1067             see L for detailed explainaton
1068              
1069             =head2 Slice
1070              
1071             see L for detailed explainaton
1072              
1073             =head2 Sum
1074              
1075             The Sum option only applies when using multiple backends.
1076             The values from all backends with be summed up to a total.
1077              
1078             my $stats = $ml->selectrow_hashref(
1079             "GET hosts\nStats: state = 0\nStats: state = 1",
1080             { Sum => 1 }
1081             );
1082              
1083             =cut
1084              
1085              
1086             ########################################
1087             # wrapper around _send_socket_do
1088             sub _send_socket {
1089 1     1   1 my($self, $statement) = @_;
1090              
1091 1         3 my $retries = 0;
1092 1         1 my($status, $msg, $recv, $sock);
1093              
1094             # try to avoid connection errors
1095 1         2 eval {
1096             local $SIG{PIPE} = sub {
1097 0     0   0 die('broken pipe');
1098 1         21 };
1099              
1100 1 50       4 if($self->{'retries_on_connection_error'} <= 0) {
1101 0         0 ($sock, $msg, $recv) = &_send_socket_do($self, $statement);
1102 0 0       0 return($sock, $msg, $recv) if $msg;
1103 0 0       0 return $sock if $ENV{'THRUK_SELECT'};
1104 0         0 ($status, $msg, $recv) = &_read_socket_do($self, $sock, $statement);
1105 0         0 return($status, $msg, $recv);
1106             }
1107              
1108 1   33     10 while((!defined $status || ($status == 491 || $status == 497 || $status == 500)) && $retries < $self->{'retries_on_connection_error'}) {
      33        
1109 1         1 $retries++;
1110 1         7 ($sock, $msg, $recv) = &_send_socket_do($self, $statement);
1111 1 50       8 return($status, $msg, $recv) if $msg;
1112 0 0       0 return $sock if $ENV{'THRUK_SELECT'};
1113 0         0 ($status, $msg, $recv) = &_read_socket_do($self, $sock, $statement);
1114 0 0       0 $self->{'logger'}->debug('query status '.$status) if $self->{'verbose'};
1115 0 0 0     0 if($status == 491 or $status == 497 or $status == 500) {
      0        
1116 0 0       0 $self->{'logger'}->debug('got status '.$status.' retrying in '.$self->{'retry_interval'}.' seconds') if $self->{'verbose'};
1117 0         0 $self->_close();
1118 0 0       0 sleep($self->{'retry_interval'}) if $retries < $self->{'retries_on_connection_error'};
1119             }
1120             }
1121             };
1122 1 50       4 if($@) {
1123 0 0       0 $self->{'logger'}->debug("try 1 failed: $@") if $self->{'verbose'};
1124 0 0 0     0 if(defined $@ and $@ =~ /broken\ pipe/mx) {
1125 0         0 ($sock, $msg, $recv) = &_send_socket_do($self, $statement);
1126 0 0       0 return($status, $msg, $recv) if $msg;
1127 0 0       0 return $sock if $ENV{'THRUK_SELECT'};
1128 0         0 return(&_read_socket_do($self, $sock, $statement));
1129             }
1130 0 0       0 croak($@) if $self->{'errors_are_fatal'};
1131             }
1132              
1133 1 50       3 $status = $sock unless $status;
1134 1 50       3 return $sock if $ENV{'THRUK_SELECT'};
1135 1 50 33     89 croak($msg) if($status >= 400 and $self->{'errors_are_fatal'});
1136              
1137 0         0 return($status, $msg, $recv);
1138             }
1139              
1140             ########################################
1141             sub _send_socket_do {
1142 1     1   2 my($self, $statement) = @_;
1143 1 50       4 my $sock = $self->_open() or return(491, $self->_get_error(491, $!), $!);
1144 0         0 utf8::decode($statement);
1145 0         0 utf8::encode($statement);
1146 0 0       0 print $sock $statement or return($self->_socket_error($statement, $sock, 'write to socket failed: '.$!));
1147 0         0 print $sock "\n";
1148 0         0 return $sock;
1149             }
1150              
1151             ########################################
1152             sub _read_socket_do {
1153 0     0   0 my($self, $sock, $statement) = @_;
1154 0         0 my($recv,$header);
1155              
1156             # COMMAND statements never return something
1157 0 0 0     0 if($statement && $statement =~ m/^COMMAND/mx) {
1158 0         0 return('201', $self->_get_error(201), undef);
1159             }
1160              
1161 0 0       0 $sock->read($header, 16) or return($self->_socket_error($statement, $sock, 'reading header from socket failed, check your livestatus logfile: '.$!));
1162 0 0       0 $self->{'logger'}->debug("header: $header") if $self->{'verbose'};
1163 0         0 my($status, $msg, $content_length) = &_parse_header($self, $header, $sock);
1164 0 0       0 return($status, $msg, undef) if !defined $content_length;
1165 0         0 our $json_decoder;
1166 0 0       0 if($json_decoder) {
1167 0         0 $json_decoder->incr_reset;
1168             } else {
1169 0         0 $json_decoder = JSON::XS->new->utf8->relaxed;
1170             }
1171 0 0       0 if($content_length > 0) {
1172 0 0       0 if($status == 200) {
1173 0         0 my $remaining = $content_length;
1174 0         0 my $length = 32768;
1175 0 0       0 if($remaining < $length) { $length = $remaining; }
  0         0  
1176 0   0     0 while($length > 0 && $sock->read(my $buf, $length)) {
1177             # replace u+D800 to u+DFFF (reserved utf-16 low/high surrogates)
1178 0         0 $buf =~ s/\\ud[89a-f]\w{2}/\\ufffd/gmxio;
1179 0         0 $json_decoder->incr_parse($buf);
1180 0         0 $remaining = $remaining -$length;
1181 0 0       0 if($remaining < $length) { $length = $remaining; }
  0         0  
1182             }
1183 0 0       0 $recv = $json_decoder->incr_parse or return($self->_socket_error($statement, $sock, 'reading body from socket failed: '.$json_decoder->incr_text.$json_decoder->incr_reset));
1184 0         0 $json_decoder->incr_reset;
1185             } else {
1186 0 0       0 $sock->read($recv, $content_length) or return($self->_socket_error($statement, $sock, 'reading body from socket failed'));
1187             }
1188             }
1189              
1190 0 0       0 $self->_close($sock) unless $self->{'keepalive'};
1191 0         0 return($status, $msg, $recv);
1192             }
1193              
1194             ########################################
1195             sub _socket_error {
1196             #my($self, $statement, $sock, $body)...
1197 0     0   0 my($self, $statement, undef, $body) = @_;
1198              
1199 0         0 my $message = "\n";
1200 0         0 $message .= "peer ".Dumper($self->peer_name);
1201 0         0 $message .= "statement ".Dumper($statement);
1202 0         0 $message .= "message ".Dumper($body);
1203              
1204 0 0       0 $self->{'logger'}->error($message) if $self->{'verbose'};
1205              
1206 0 0       0 if($self->{'retries_on_connection_error'} <= 0) {
1207 0 0       0 if($self->{'errors_are_fatal'}) {
1208 0         0 croak($message);
1209             }
1210             else {
1211 0         0 carp($message);
1212             }
1213             }
1214 0         0 $self->_close();
1215 0         0 return(500, $self->_get_error(500), $message);
1216             }
1217              
1218             ########################################
1219             sub _parse_header {
1220 1     1   2 my($self, $header, $sock) = @_;
1221              
1222 1 50       3 if(!defined $header) {
1223 0         0 return(497, $self->_get_error(497), undef);
1224             }
1225              
1226 1         2 my $headerlength = length($header);
1227 1 50       2 if($headerlength != 16) {
1228 0         0 return(498, $self->_get_error(498)."\ngot: ".$header.<$sock>, undef);
1229             }
1230 1         3 chomp($header);
1231              
1232 1         3 my $status = substr($header,0,3);
1233 1         1 my $content_length = substr($header,5);
1234 1 50       7 if($content_length !~ m/^\s*(\d+)$/mx) {
1235 0         0 return(499, $self->_get_error(499)."\ngot: ".$header.<$sock>, undef);
1236             } else {
1237 1         2 $content_length = $1;
1238             }
1239              
1240 1         3 return($status, $self->_get_error($status), $content_length);
1241             }
1242              
1243             ########################################
1244              
1245             =head1 COLUMN ALIAS
1246              
1247             In addition to the normal query syntax from the livestatus addon, it is
1248             possible to set column aliases in various ways.
1249              
1250             A valid Columns: Header could look like this:
1251              
1252             my $hosts = $ml->selectall_arrayref(
1253             "GET hosts\nColumns: state as status"
1254             );
1255              
1256             Stats queries could be aliased too:
1257              
1258             my $stats = $ml->selectall_arrayref(
1259             "GET hosts\nStats: state = 0 as up"
1260             );
1261              
1262             This syntax is available for: Stats, StatsAnd, StatsOr and StatsGroupBy
1263              
1264              
1265             An alternative way to set column aliases is to define rename option key/value
1266             pairs:
1267              
1268             my $hosts = $ml->selectall_arrayref(
1269             "GET hosts\nColumns: name", {
1270             rename => { 'name' => 'hostname' }
1271             }
1272             );
1273              
1274             =cut
1275              
1276             ########################################
1277              
1278             =head2 extract_keys_from_stats_statement
1279              
1280             extract_keys_from_stats_statement($statement)
1281              
1282             Extract column keys from statement.
1283              
1284             =cut
1285             sub extract_keys_from_stats_statement {
1286 2     2 1 1197 my($statement) = @_;
1287              
1288 2         2 my(@header, $new_statement);
1289              
1290 2         15 for my $line (split/\n/mx, $statement) {
1291 44 100       55 if(substr($line, 0, 5) ne 'Stats') { # faster shortcut for non-stats lines
1292 2         4 $new_statement .= $line."\n";
1293 2         3 next;
1294             }
1295 42 100       120 if($line =~ m/^Stats:\ (.*)\s+as\s+(.*?)$/mxo) {
    100          
    100          
    100          
    100          
    50          
    0          
    0          
1296 5         10 push @header, $2;
1297 5         8 $line = 'Stats: '.$1;
1298             }
1299             elsif($line =~ m/^Stats:\ (.*)$/mxo) {
1300 27         38 push @header, $1;
1301             }
1302              
1303             elsif($line =~ m/^StatsAnd:\ (\d+)\s+as\s+(.*?)$/mxo) {
1304 4         10 for(my $x = 0; $x < $1; $x++) {
1305 9         15 pop @header;
1306             }
1307 4         5 $line = 'StatsAnd: '.$1;
1308 4         5 push @header, $2;
1309             }
1310             elsif($line =~ m/^StatsAnd:\ (\d+)$/mxo) {
1311 4         3 my @to_join;
1312 4         11 for(my $x = 0; $x < $1; $x++) {
1313 9         18 unshift @to_join, pop @header;
1314             }
1315 4         8 push @header, join(' && ', @to_join);
1316             }
1317              
1318             elsif($line =~ m/^StatsOr:\ (\d+)\s+as\s+(.*?)$/mxo) {
1319 1         4 for(my $x = 0; $x < $1; $x++) {
1320 2         4 pop @header;
1321             }
1322 1         2 $line = 'StatsOr: '.$1;
1323 1         2 push @header, $2;
1324             }
1325             elsif($line =~ m/^StatsOr:\ (\d+)$/mxo) {
1326 1         1 my @to_join;
1327 1         3 for(my $x = 0; $x < $1; $x++) {
1328 2         5 unshift @to_join, pop @header;
1329             }
1330 1         2 push @header, join(' || ', @to_join);
1331             }
1332              
1333             # StatsGroupBy header are always sent first
1334             elsif($line =~ m/^StatsGroupBy:\ (.*)\s+as\s+(.*?)$/mxo) {
1335 0         0 unshift @header, $2;
1336 0         0 $line = 'StatsGroupBy: '.$1;
1337             }
1338             elsif($line =~ m/^StatsGroupBy:\ (.*)$/mxo) {
1339 0         0 unshift @header, $1;
1340             }
1341 42         47 $new_statement .= $line."\n";
1342             }
1343              
1344 2         10 return($new_statement, \@header);
1345             }
1346              
1347             ########################################
1348             sub _extract_keys_from_columns_header {
1349 2     2   466 my($self, $statement) = @_;
1350              
1351 2         4 my(@header, $new_statement);
1352 2         8 for my $line (split/\n/mx, $statement) {
1353 4 100       21 if($line =~ m/^Columns:\s+(.*)$/mx) {
1354 2         13 for my $column (split/\s+/mx, $1) {
1355 11 100       16 if($column eq 'as') {
1356 2         2 pop @header;
1357             } else {
1358 9         11 push @header, $column;
1359             }
1360             }
1361 2         10 $line =~ s/\s+as\s+([^\s]+)/\ /gmx;
1362             }
1363 4         9 $new_statement .= $line."\n";
1364             }
1365              
1366 2         7 return($new_statement, \@header);
1367             }
1368              
1369             ########################################
1370              
1371             =head1 ERROR HANDLING
1372              
1373             Errorhandling can be done like this:
1374              
1375             use Monitoring::Livestatus;
1376             my $ml = Monitoring::Livestatus->new(
1377             socket => '/var/lib/livestatus/livestatus.sock'
1378             );
1379             $ml->errors_are_fatal(0);
1380             my $hosts = $ml->selectall_arrayref("GET hosts");
1381             if($Monitoring::Livestatus::ErrorCode) {
1382             croak($Monitoring::Livestatus::ErrorMessage);
1383             }
1384              
1385             =cut
1386             sub _get_error {
1387 2     2   7 my($self, $code, $append) = @_;
1388              
1389 2         54 my $codes = {
1390             '200' => 'OK. Reponse contains the queried data.',
1391             '201' => 'COMMANDs never return something',
1392             '400' => 'The request contains an invalid header.',
1393             '401' => 'The request contains an invalid header.',
1394             '402' => 'The request is completely invalid.',
1395             '403' => 'The request is incomplete.',
1396             '404' => 'The target of the GET has not been found (e.g. the table).',
1397             '405' => 'A non-existing column was being referred to',
1398             '452' => 'internal livestatus error',
1399             '490' => 'no query',
1400             '491' => 'failed to connect',
1401             '492' => 'Separators not allowed in statement. Please use the separator options in new()',
1402             '493' => 'OuputFormat not allowed in statement. Header will be set automatically',
1403             '494' => 'ColumnHeaders not allowed in statement. Header will be set automatically',
1404             '495' => 'ResponseHeader not allowed in statement. Header will be set automatically',
1405             '496' => 'Keepalive not allowed in statement. Please use the keepalive option in new()',
1406             '497' => 'got no header',
1407             '498' => 'header is not exactly 16byte long',
1408             '499' => 'not a valid header (no content-length)',
1409             '500' => 'socket error',
1410             };
1411              
1412 2 50       7 confess('non existant error code: '.$code) if !defined $codes->{$code};
1413 2         3 my $msg = $codes->{$code};
1414 2 100       7 $msg .= ' - '.$append if $append;
1415              
1416 2         18 return($msg);
1417             }
1418              
1419             ########################################
1420             sub _get_peer {
1421 26     26   23 my($self) = @_;
1422              
1423             # check if the supplied peer is a socket or a server address
1424 26 100       54 if(defined $self->{'peer'}) {
1425 23 100       46 if(ref $self->{'peer'} eq '') {
    50          
    0          
1426 19   66     54 my $name = $self->{'name'} || ''.$self->{'peer'};
1427 19 100       40 if(index($self->{'peer'}, ':') > 0) {
1428 7         27 return({ 'peer' => ''.$self->{'peer'}, type => 'INET', name => $name });
1429             } else {
1430 12         42 return({ 'peer' => ''.$self->{'peer'}, type => 'UNIX', name => $name });
1431             }
1432             }
1433             elsif(ref $self->{'peer'} eq 'ARRAY') {
1434 4         3 for my $peer (@{$self->{'peer'}}) {
  4         9  
1435 4 50       7 if(ref $peer eq 'HASH') {
1436 0 0       0 next if !defined $peer->{'peer'};
1437 0 0       0 $peer->{'name'} = ''.$peer->{'peer'} unless defined $peer->{'name'};
1438 0 0       0 if(!defined $peer->{'type'}) {
1439 0         0 $peer->{'type'} = 'UNIX';
1440 0 0       0 if(index($peer->{'peer'}, ':') >= 0) {
1441 0         0 $peer->{'type'} = 'INET';
1442             }
1443             }
1444 0         0 return $peer;
1445             } else {
1446 4         4 my $type = 'UNIX';
1447 4 50       10 if(index($peer, ':') >= 0) {
1448 0         0 $type = 'INET';
1449             }
1450 4         15 return({ 'peer' => ''.$peer, type => $type, name => ''.$peer });
1451             }
1452             }
1453             }
1454             elsif(ref $self->{'peer'} eq 'HASH') {
1455 0         0 for my $peer (keys %{$self->{'peer'}}) {
  0         0  
1456 0         0 my $name = $self->{'peer'}->{$peer};
1457 0         0 my $type = 'UNIX';
1458 0 0       0 if(index($peer, ':') >= 0) {
1459 0         0 $type = 'INET';
1460             }
1461 0         0 return({ 'peer' => ''.$peer, type => $type, name => ''.$name });
1462             }
1463             } else {
1464 0         0 confess('type '.(ref $self->{'peer'}).' is not supported for peer option');
1465             }
1466             }
1467 3 100       9 if(defined $self->{'socket'}) {
1468 2   33     12 my $name = $self->{'name'} || ''.$self->{'socket'};
1469 2         11 return({ 'peer' => ''.$self->{'socket'}, type => 'UNIX', name => $name });
1470             }
1471 1 50       3 if(defined $self->{'server'}) {
1472 1   33     7 my $name = $self->{'name'} || ''.$self->{'server'};
1473 1         5 return({ 'peer' => ''.$self->{'server'}, type => 'INET', name => $name });
1474             }
1475              
1476             # check if we got a peer
1477 0         0 croak('please specify a peer');
1478             }
1479              
1480              
1481             ########################################
1482             sub _lowercase_and_verify_options {
1483 1     1   3 my($self, $opts) = @_;
1484 1         2 my $return = {};
1485              
1486             # make keys lowercase
1487 1         3 %{$return} = map { lc($_) => $opts->{$_} } keys %{$opts};
  1         4  
  1         5  
  1         4  
1488              
1489 1 50       12 if($self->{'warnings'}) {
1490 1         3 for my $key (keys %{$return}) {
  1         4  
1491 1 50       6 if(!defined $allowed_options->{$key}) {
1492 0         0 carp("unknown option used: $key - please use only: ".join(', ', keys %{$allowed_options}));
  0         0  
1493             }
1494             }
1495             }
1496              
1497             # set limits
1498 1 50       5 if(defined $return->{'limit'}) {
1499 0 0       0 if(index($return->{'limit'}, ',') != -1) {
1500 0         0 my($limit_start,$limit_length) = split /,/mx, $return->{'limit'};
1501 0         0 $return->{'limit_start'} = $limit_start;
1502 0         0 $return->{'limit_length'} = $limit_length;
1503             }
1504             else {
1505 0         0 $return->{'limit_start'} = 0;
1506 0         0 $return->{'limit_length'} = $return->{'limit'};
1507             }
1508 0         0 delete $return->{'limit'};
1509             }
1510              
1511 1         2 return($return);
1512             }
1513              
1514             ########################################
1515             sub _log_statement {
1516 0     0     my($self, $statement, $opt, $limit) = @_;
1517 0           my $d = Data::Dumper->new([$opt]);
1518 0           $d->Indent(0);
1519 0           my $optstring = $d->Dump;
1520 0           $optstring =~ s/^\$VAR1\s+=\s+//mx;
1521 0           $optstring =~ s/;$//mx;
1522              
1523             # remove empty lines from statement
1524 0           $statement =~ s/\n+/\n/gmx;
1525              
1526 0           my $cleanstatement = $statement;
1527 0           $cleanstatement =~ s/\n/\\n/gmx;
1528 0           $self->{'logger'}->debug('selectall_arrayref("'.$cleanstatement.'", '.$optstring.', '.$limit.')');
1529 0           return 1;
1530             }
1531              
1532             ########################################
1533              
1534             1;
1535              
1536             =head1 SEE ALSO
1537              
1538             For more information about the query syntax and the livestatus plugin installation
1539             see the Livestatus page: http://mathias-kettner.de/checkmk_livestatus.html
1540              
1541             =head1 AUTHOR
1542              
1543             Sven Nierlein, 2009-present,
1544              
1545             =head1 COPYRIGHT AND LICENSE
1546              
1547             Copyright (C) by Sven Nierlein
1548              
1549             This library is free software; you can redistribute it and/or modify
1550             it under the same terms as Perl itself.
1551              
1552             =cut
1553              
1554             __END__