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