File Coverage

blib/lib/Opsview/StatusAPI.pm
Criterion Covered Total %
statement 36 71 50.7
branch 7 32 21.8
condition 0 3 0.0
subroutine 11 15 73.3
pod 6 6 100.0
total 60 127 47.2


line stmt bran cond sub pod time code
1             package Opsview::StatusAPI;
2              
3             #################### main pod documentation begin ###################
4             ## Below is the stub of documentation for your module.
5             ## You better edit it!
6              
7              
8             =head1 NAME
9              
10             Opsview::StatusAPI - Module to help you query the Opsview Status API
11              
12             =head1 SYNOPSIS
13              
14             use Opsview::StatusAPI;
15            
16             my $api = Opsview::StatusAPI->new(
17             'user' => 'opsview_user',
18             'password' => 'opsview_password',
19             'host' => 'opsview.example.com',
20             'secure' => 1
21             );
22              
23             my $status = $api->hostgroup();
24              
25             =head1 DESCRIPTION
26              
27             This module queries the Opsview Status API for you, returning data structures as appropiate.
28              
29             Documetation of the Status API is here: http://docs.opsview.com/doku.php?id=opsview-community:api
30              
31             Note: this module only queries the "status API", it doesn't understand about the API to create/delete objects
32              
33             Note2: the data structures returned are only deserialized by this module. Different versions of Opsview
34             may return different data structures.
35              
36             =cut
37              
38 2     2   64350 use strict;
  2         5  
  2         75  
39 2     2   9 use warnings;
  2         6  
  2         54  
40 2     2   10 use Carp;
  2         9  
  2         186  
41 2     2   2195 use HTTP::Request;
  2         74857  
  2         75  
42 2     2   5965 use LWP::UserAgent;
  2         62847  
  2         73  
43 2     2   2487 use JSON::Any;
  2         63423  
  2         13  
44              
45             our $VERSION = '0.02';
46              
47             our $states = { 'ok' => 0, 'warning' => '1', 'critical' => '2', 'unknown' => '3' };
48              
49             =head1 CONSTRUCTOR
50              
51             =head2 new(user => 'user', 'password' => 'pass', 'host' => 'host.name.com', secure => [0|1])
52              
53             Create the object. Only the host parameter is required. If not specified, the constructor will die.
54              
55             Optionally you can pass secure => 1 to make the object access the status API via HTTPS
56              
57             =cut
58              
59             sub new {
60 4     4 1 2238 my ($class, %params) = @_;
61 4 50       22 $params{'secure'} = 0 if (not defined $params{'secure'});
62 4 100       41 croak "Must specify host" if (not defined $params{'host'});
63              
64 3         15 my $self = { %params };
65              
66 3         9 bless $self, $class;
67              
68 3         11 $self->{'_url'} = $self->_get_url();
69 3         33 $self->{'_ua'} = LWP::UserAgent->new;
70 3         8141 $self->{'_json'} = JSON::Any->new;
71              
72 3         243 return $self;
73             }
74              
75             sub _get_url {
76 3     3   6 my $self = shift;
77 3 50       39 return sprintf('%s://%s/api/status/', ($self->{'secure'}==1?'https':'http'), $self->{'host'});
78             }
79              
80             sub _dorequest {
81 1     1   2 my ($self, $url) = @_;
82              
83 1 50       14 croak "Must specify user" if (not defined $self->{'user'});
84 0 0       0 croak "Must specify password" if (not defined $self->{'password'});
85              
86 0         0 my $req = HTTP::Request->new( GET => $url );
87 0         0 $req->header( 'Content-Type' => 'text/json' );
88 0         0 $req->header( 'X-Username' => $self->{'user'} );
89 0         0 $req->header( 'X-Password' => $self->{'password'} );
90            
91 0         0 my $res = $self->{'_ua'}->request($req);
92 0 0       0 if ($res->is_success){
93 0         0 return ($self->{'_json'}->decode($res->content));
94             } else {
95 0         0 die sprintf('Response from host: \'%s\' for \'%s\'', $res->status_line, $url);
96             }
97             }
98              
99             sub _resolve_filter {
100 0     0   0 my ($self, $filter) = @_;
101 0         0 my $params = '';
102 0 0       0 if (ref($filter) eq 'SCALAR') {
    0          
103 0         0 $params = $filter;
104             } elsif (ref($filter) eq 'HASH'){
105 0 0 0     0 if ((defined $filter->{'state'}) && (defined $states->{ $filter->{'state'} })) {
106 0         0 $filter->{'state'} = $states->{ $filter->{'state'} };
107             }
108             my $q = join '&', map {
109 0 0       0 if (ref($filter->{$_}) eq 'ARRAY'){
  0         0  
110 0         0 my $key = $_;
111 0         0 join '&', map { "$key=$_" } @{ $filter->{$_} }
  0         0  
  0         0  
112             } else {
113 0         0 "$_=$filter->{$_}";
114             }
115             } keys %$filter;
116 0 0       0 $params = "?$q" if ($q);
117             }
118 0         0 return $params;
119             }
120              
121             =head1 METHODS
122              
123             =head2 host($hostname [, $filter])
124              
125             retrieve monitoring information for $hostname. Additionally apply a filter.
126              
127             This is really a shortcut for:
128              
129             $api->service({'host' => $hostname, ...filter... })
130              
131             =cut
132              
133             sub host {
134 1     1 1 165 my ($self, $host, $filter) = @_;
135 1 50       12 croak "must specify host" if (not defined $host);
136 0 0       0 my $params = $self->_resolve_filter({ (defined $filter)?%$filter:() , host => $host });
137 0         0 return $self->_dorequest("$self->{'_url'}service$params");
138             }
139              
140             =head2 user([$value])
141              
142             Set/Retrieve the user for the API.
143              
144             =cut
145              
146             sub user {
147 0     0 1 0 my ($self, $value) = @_;
148 0 0       0 $self->{'user'} = $value if (defined $value);
149 0         0 return $self->{'user'};
150             }
151              
152             =head2 password([$value])
153              
154             Set/Retrieve the password for the API.
155              
156             =cut
157              
158             sub password {
159 0     0 1 0 my ($self, $value) = @_;
160 0 0       0 $self->{'password'} = $value if (defined $value);
161 0         0 return $self->{'password'};
162             }
163              
164              
165             =head2 service($filter)
166              
167             =head2 service()
168              
169             If called without parameters, will return info for all services.
170             See FILTERS for information on how
171              
172             The returned data structure will be something like this:
173              
174             { 'service' => {
175             'summary' => {
176             'handled' => 15,
177             'unhandled' => 0,
178             'service' => {
179             'ok' => 14,
180             'handled' => 14,
181             'unhandled' => 0,
182             'total' => 14
183             },
184             'total' => 15,
185             'host' => {
186             'handled' => 1,
187             'unhandled' => 0,
188             'up' => 1,
189             'total' => 1
190             }
191             },
192             'list' => [
193             { 'icon' => 'debian',
194             'summary' => {
195             'handled' => 14,
196             'unhandled' => 0,
197             'total' => 14
198             },
199             'unhandled' => '0',
200             'downtime' => 0,
201             'name' => 'servername.example.com',
202             'alias' => 'Description of the server',
203             'state' => 'up'
204             'services' => [
205             { 'max_check_attempts' => '3',
206             'state_duration' => 5893554,
207             'name' => '/',
208             'output' => 'DISK OK - free space: / 12207 MB (42% inode=-):',
209             'current_check_attempt' => '1',
210             'state' => 'ok',
211             'service_object_id' => '176',
212             'unhandled' => '0',
213             'downtime' => 0,
214             'last_check' => '2010-06-02 00:32:20',
215             'perfdata_available' => '1'
216             },
217             ... one hashref for each service in the host ...
218             ]
219             },
220             ... one hashref for each host returned ...
221             ]
222             }
223              
224             =cut
225              
226             sub service {
227 0     0 1 0 my ($self, $filter) = @_;
228 0         0 my $params = $self->_resolve_filter($filter);
229 0         0 return $self->_dorequest("$self->{'_url'}service$params")->{'service'};
230             }
231              
232             =head2 hostgroup()
233              
234             =head2 hostgroup($hostgroup_id)
235              
236             If called without parameters, it will return the information about the root hostgroup.
237             If hostgroup_id is passed, it will return information about the hostgroup with that ID.
238              
239             The returned data structure will be something like this:
240              
241             { 'summary' => {
242             'handled' => 20,
243             'unhandled' => 2,
244             'service' => {
245             'ok' => 14,
246             'critical' => 2,
247             'handled' => 16,
248             'unhandled' => 2,
249             'warning' => 4,
250             'total' => 18
251             },
252             'total' => 20,
253             'host' => {
254             'handled' => 2,
255             'unhandled' => 0,
256             'up' => 2,
257             'total' => 2
258             }
259             },
260             'list' => [
261             { 'hosts' => {
262             'handled' => 1,
263             'unhandled' => 0,
264             'up' => {
265             'handled' => 1
266             },
267             'total' => 1
268             },
269             'hostgroup_id' => '3',
270             'services' => {
271             'ok' => {
272             'handled' => 3
273             },
274             'handled' => 3,
275             'highest' => 'warning',
276             'unhandled' => 1,
277             'warning' => {
278             'unhandled' => 1
279             },
280             'total' => 4
281             },
282             'downtime' => undef,
283             'name' => 'Hostgroup Name'
284             },
285             ...
286             ]
287             }
288              
289             =cut
290              
291             sub hostgroup {
292 1     1 1 29 my ($self, $hg_id) = @_;
293            
294 1 50       7 $hg_id = '' if (not defined $hg_id);
295 1         6 return $self->_dorequest("$self->{'_url'}hostgroup/$hg_id")->{'hostgroup'};
296             }
297              
298             =head1 FILTERS
299              
300             A filter is a hashref that can contain the following keys with these values:
301              
302             hostgroupid => id, # the id of a hostgroup
303             host => 'host', # the name of a host
304             state => 0, 1, 2, 3, 'ok, 'warning', 'critical', 'unknown' # 0 == 'ok', 3 == 'unknown'
305             filter => 'handled' | 'unhandled' # filter by handled or unhandled services
306              
307             If you want all unhandled warnings, the filter would be
308              
309             { 'filter' => 'unhandled', 'state' => 'warning' }
310              
311             keys can also have multiple values: if you want only WARNINGS and CRITICALS
312              
313             { 'state' => [ 1, 2 ] }
314              
315             =head1 AUTHOR
316              
317             Jose Luis Martinez
318             CPAN ID: JLMARTIN
319             CAPSiDE
320             jlmartinez@capside.com
321             http://www.pplusdomain.net
322              
323             =head1 COPYRIGHT
324              
325             This program is free software; you can redistribute
326             it and/or modify it under the same terms as Perl itself.
327              
328             The full text of the license can be found in the
329             LICENSE file included with this module.
330              
331              
332             =head1 SEE ALSO
333              
334             http://www.opsview.org/
335              
336             http://docs.opsview.com/doku.php?id=opsview-community:api
337              
338             =cut
339              
340              
341             1;