File Coverage

blib/lib/Monitoring/Icinga2/Client/Simple.pm
Criterion Covered Total %
statement 126 126 100.0
branch 37 40 100.0
condition 21 34 82.3
subroutine 31 31 100.0
pod 13 13 100.0
total 228 244 97.5


line stmt bran cond sub pod time code
1             # ABSTRACT: Simpler REST client for Icinga2
2              
3             package Monitoring::Icinga2::Client::Simple;
4             $Monitoring::Icinga2::Client::Simple::VERSION = '0.002001';
5 2     2   158460 use strict;
  2         14  
  2         57  
6 2     2   11 use warnings;
  2         4  
  2         59  
7 2     2   42 use 5.010_001;
  2         6  
8 2     2   944 use Monitoring::Icinga2::Client::REST 2;
  2         127472  
  2         76  
9 2     2   16 use parent -norequire, 'Monitoring::Icinga2::Client::REST';
  2         4  
  2         14  
10 2     2   87 use Carp;
  2         5  
  2         128  
11 2     2   12 use List::Util qw/ all any first /;
  2         4  
  2         227  
12 2     2   16 use constant DEBUG => $ENV{DEBUG};
  2         5  
  2         3879  
13              
14             sub new {
15 34     34 1 46794 my $class = shift;
16 34 100       319 croak( "only hash-style args are supported" ) if @_ % 2;
17 33         104 my %args = @_;
18             # uncoverable condition false
19 33   66     207 my $server = delete $args{server} // croak( "`server' arg is required" );
20 32         65 my $ua = delete $args{useragent};
21 32         187 my $self = $class->SUPER::new( $server, %args );
22 32 100       12017 if( defined $ua ) {
23             # This is a hack as I don't maintain the superclass. However, I wrote its
24             # constructor and we'll check whether it has changed so it should be fine.
25             # uncoverable branch true
26 30 50       78 defined $self->{ua} or croak( 'Monitoring::Icinga2::Client::REST seems to have changed internals; '. 'passing `useragent\' does not work. Please notify mbethke@cpan.org');
27 30         113 $ua->default_header( 'Accept' => 'application/json' );
28 30         851 $self->{ua} = $ua;
29             }
30             # uncoverable condition false
31             # uncoverable branch right
32 32   33     3975 $self->{_mics_author} = getlogin || getpwuid($<);
33 32         280 return $self;
34             }
35              
36             sub schedule_downtime {
37 6     6 1 415 my ($self, %args) = @_;
38 6         22 _checkargs(\%args, qw/ start_time end_time comment host /);
39             # uncoverable condition true
40 5   66     29 $args{author} //= $self->{_mics_author};
41              
42 5 100 100     20 if( $args{service} and not $args{services} ) {
43 1         4 return [ $self->_schedule_downtime_type( 'Service', \%args) ];
44             }
45              
46 4         9 delete $args{service}; # make sure _schedule_downtime_type doesn't set a wrong filter
47 4         13 my @results = $self->_schedule_downtime_type( 'Host', \%args );
48 4 100       14 push @results, $self->_schedule_downtime_type( 'Service', \%args ) if $args{services};
49 4         17 return \@results;
50             }
51              
52             sub _schedule_downtime_type {
53 7     7   15 my ($self, $type, $args) = @_;
54             my $req_results = $self->_request('POST',
55             '/actions/schedule-downtime',
56             {
57             type => $type,
58             joins => [ "host.name" ],
59             filter => _create_filter( $args ),
60 7         23 map { $_ => $args->{$_} } qw/ author start_time end_time comment duration fixed /
  42         117  
61             }
62             );
63 7         38 return @$req_results;
64             }
65              
66             sub remove_downtime {
67 3     3 1 200 my ($self, %args) = @_;
68              
69             defined $args{name}
70 3 100       12 and return $self->_remove_downtime_type( 'Downtime', "downtime=$args{name}" );
71              
72 2         8 _checkargs(\%args, 'host');
73              
74             defined $args{service}
75 2 100       12 and return $self->_remove_downtime_type( 'Service', \%args );
76              
77 1         4 return $self->_remove_downtime_type( 'Host', \%args );
78             }
79              
80             sub _remove_downtime_type {
81 3     3   8 my ($self, $type, $args) = @_;
82 3         6 my @post_args;
83              
84 3 100       9 if(ref $args) {
85 2         8 @post_args = (
86             undef,
87             {
88             type => $type,
89             joins => [ "host.name" ],
90             filter => _create_filter( $args ),
91             }
92             );
93             } else {
94 1         4 @post_args = ( $args, { type => $type } );
95             }
96 3         11 my $req_results = $self->_request('POST',
97             "/actions/remove-downtime",
98             @post_args,
99             );
100 3         16 return $req_results;
101             }
102              
103             sub send_custom_notification {
104 3     3 1 203 my ($self, %args) = @_;
105 3         10 _checkargs(\%args, qw/ comment /);
106 3         15 _checkargs_any(\%args, qw/ host service /);
107              
108 3 100       13 my $obj_type = defined $args{host} ? 'host' : 'service';
109              
110             return $self->_request('POST',
111             '/actions/send-custom-notification',
112             {
113             type => ucfirst $obj_type,
114             filter => "$obj_type.name==\"$args{$obj_type}\"",
115             comment => $args{comment},
116             # uncoverable condition false
117             # uncoverable branch right
118             author => $args{author} // $self->{_mics_author},
119             }
120 3   66     29 );
121             }
122              
123             sub set_notifications {
124 4     4 1 321 my ($self, %args) = @_;
125 4         14 _checkargs(\%args, qw/ state /);
126 3         13 _checkargs_any(\%args, qw/ host service /);
127 3 100       11 my $uri_object = $args{service} ? 'services' : 'hosts';
128              
129             return $self->_request('POST',
130             "/objects/$uri_object",
131             {
132             attrs => { enable_notifications => !!$args{state} },
133 3         17 filter => _create_filter( \%args ),
134             }
135             );
136             }
137              
138             sub query_app_attrs {
139 1     1 1 65 my ($self) = @_;
140              
141 1         4 my $r = $self->_request('GET',
142             "/status/IcingaApplication",
143             );
144             # uncoverable branch true
145             # uncoverable condition left
146             # uncoverable condition right
147 1 50 33     16 ref $r eq 'ARRAY' and defined $r->[0] and defined $r->[0]{status}{icingaapplication}{app} or die "Invalid result from Icinga";
      33        
148              
149 1         5 return $r->[0]{status}{icingaapplication}{app};
150             }
151              
152             {
153             my %legal_attrs = map { $_ => 1 } qw/
154             event_handlers
155             flapping
156             host_checks
157             notifications
158             perfdata
159             service_checks
160             /;
161              
162             sub set_app_attrs {
163 4     4 1 202 my ($self, %args) = @_;
164 4         20 _checkargs_any(\%args, keys %legal_attrs);
165 3         15 my @unknown_attrs = grep { not exists $legal_attrs{$_} } keys %args;
  7         17  
166 3 100       107 @unknown_attrs and croak(
167             sprintf "Unknown attributes: %s; legal attributes are: %s",
168             join(",", sort @unknown_attrs),
169             join(",", sort keys %legal_attrs),
170             );
171              
172             return $self->_request('POST',
173             '/objects/icingaapplications/app',
174             {
175             attrs => {
176 2         6 map { 'enable_' . $_ => !!$args{$_} } keys %args
  4         20  
177             },
178             }
179             );
180             }
181             }
182              
183             sub set_global_notifications {
184 1     1 1 65 my ($self, $state) = @_;
185 1         4 $self->set_app_attrs( notifications => $state );
186             }
187              
188             sub query_hosts {
189 5     5 1 81 my ($self, %args) = @_;
190 5         15 _checkargs(\%args, qw/ hosts /);
191             my $result = $self->_request('GET',
192             '/objects/hosts',
193 5         19 { filter => _filter_expr( "host.name", $args{hosts} ) },
194             );
195             }
196              
197             sub query_host {
198 3     3 1 73 my ($self, %args) = @_;
199 3         10 _checkargs(\%args, qw/ host /);
200 3         16 return $self->query_hosts( hosts => $args{host} )->[0];
201             }
202              
203             sub query_child_hosts {
204 1     1 1 82 my ($self, %args) = @_;
205 1         5 _checkargs(\%args, qw/ host /);
206 1         7 return $self->_request('GET',
207             '/objects/hosts',
208             { filter => "\"$args{host}\" in host.vars.parents" }
209             );
210             }
211              
212             sub query_parent_hosts {
213 2     2 1 132 my ($self, %args) = @_;
214 2         6 my $expand = delete $args{expand};
215             # uncoverable condition right
216 2   50     8 my $results = $self->query_host( %args ) // {};
217             # uncoverable condition right
218 2   50     10 my $names = $results->{attrs}{vars}{parents} // [];
219 2         5 undef $results;
220             # uncoverable condition right
221 2 100 66     12 return $names unless $expand and @$names;
222 1         3 return $self->query_hosts( hosts => $names );
223             }
224              
225             sub query_services {
226 2     2 1 133 my ($self, %args) = @_;
227 2         7 _checkargs_any(\%args, qw/ service services /);
228 2   66     13 my $srv = $args{service} // $args{services};
229 2         6 return $self->_request('GET',
230             '/objects/services',
231             { filter => _filter_expr( "service.name", $srv ) },
232             );
233             }
234              
235             sub _request {
236 26     26   69 my ($self, $method, $url, $getargs, $postdata) = @_;
237              
238 26 100 100     105 if(defined $getargs and ref $getargs) {
239             # getargs must be a string. if it ain't, it's actually postdata
240 22         40 $postdata = $getargs;
241 22         42 undef $getargs;
242             }
243             # uncoverable branch true
244 26 50       91 my $r = $self->do_request($method, $url, $getargs, $postdata)
245             or die $self->request_status_line . "\n";
246 26         17370 return $r->{results};
247             }
248              
249             # Make sure at all keys are defined in the hash referenced by the first arg
250             # Not a method!
251             sub _checkargs {
252 24     24   42 my $args = shift;
253              
254 39     39   166 all { defined $args->{$_} } @_ or croak(
255             sprintf "missing or undefined argument `%s' to %s()",
256 24 100   2   104 ( first { not defined $args->{$_} } @_ ),
  2         227  
257             (caller(1))[3]
258             );
259             }
260              
261             # Make sure at least one key is defined in the hash referenced by the first arg
262             # Not a method!
263             sub _checkargs_any {
264 12     12   23 my $args = shift;
265              
266 12 100   11   41 any { defined $args->{$_} } grep { exists $args->{$_} } @_ or croak(
  11         38  
  40         206  
267             sprintf "need at least one argument of: %s to %s()",
268             join(',', @_), (caller(1))[3]
269             );
270             }
271              
272             # Create a filter for a hostname in $args->{host} and optionally a service name in $args->{service}
273             # Not a method!
274             sub _create_filter {
275 12     12   20 my $args = shift;
276 12 100       173 defined $args->{host} or croak(
277             sprintf( "missing or undefined argument `host' to %s()", (caller(1))[3] )
278             );
279 11         25 my $filter = _filter_expr( "host.name", $args->{host} );
280 11 100       45 return $filter unless $args->{service};
281 3         10 return "$filter && " . _filter_expr( "service.name", $args->{service} );
282             }
283              
284             # Return an == or `in' expression depending on the type of argument.
285             # Only scalars and arrayrefs make sense!
286             sub _filter_expr {
287 21     21   46 my ($what, $arg) = @_;
288 21 100       91 return "$what==\"$arg\"" unless ref $arg;
289 3         10 return "$what in [" . join( ',', map { "\"$_\"" } @$arg ) . ']';
  6         29  
290             }
291              
292             1;
293              
294             __END__