| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | =head1 NAME | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | Monitoring::Icinga - An object oriented interface to Icinga | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 6 |  |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  | Simple example: | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | use Monitoring::Icinga; | 
| 10 |  |  |  |  |  |  |  | 
| 11 |  |  |  |  |  |  | my $api = Monitoring::Icinga->new( | 
| 12 |  |  |  |  |  |  | AuthKey => 'ThisIsTheAuthKey' | 
| 13 |  |  |  |  |  |  | ); | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | $api->set_columns('HOST_NAME', 'HOST_OUTPUT', 'HOST_CURRENT_STATE'); | 
| 16 |  |  |  |  |  |  | my $hosts = $api->get_hosts(1,2); | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  | This will query the Icinga Web REST API on localhost. $hosts is an array | 
| 19 |  |  |  |  |  |  | reference containing the information for every host object, which is currently | 
| 20 |  |  |  |  |  |  | is DOWN (1) or UNREACHABLE (2). | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | This module implements an object oriented interface to Icinga using its REST | 
| 25 |  |  |  |  |  |  | API. It is tested with the Icinga Web REST API v1.2 only, so sending commands | 
| 26 |  |  |  |  |  |  | via PUT is not yet supported (but will be in the future). | 
| 27 |  |  |  |  |  |  |  | 
| 28 |  |  |  |  |  |  | =head1 METHODS | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | =cut | 
| 31 |  |  |  |  |  |  |  | 
| 32 |  |  |  |  |  |  | package Monitoring::Icinga; | 
| 33 |  |  |  |  |  |  |  | 
| 34 | 1 |  |  | 1 |  | 24551 | use strict; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 35 |  | 
| 35 | 1 |  |  | 1 |  | 4 | use warnings; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 29 |  | 
| 36 | 1 |  |  | 1 |  | 6 | use Carp qw(carp croak); | 
|  | 1 |  |  |  |  | 6 |  | 
|  | 1 |  |  |  |  | 83 |  | 
| 37 | 1 |  |  | 1 |  | 890 | use HTTP::Request::Common qw(POST); | 
|  | 1 |  |  |  |  | 33313 |  | 
|  | 1 |  |  |  |  | 88 |  | 
| 38 | 1 |  |  | 1 |  | 1127 | use LWP::UserAgent; | 
|  | 1 |  |  |  |  | 29582 |  | 
|  | 1 |  |  |  |  | 35 |  | 
| 39 | 1 |  |  | 1 |  | 1202 | use JSON::XS; | 
|  | 1 |  |  |  |  | 7724 |  | 
|  | 1 |  |  |  |  | 1684 |  | 
| 40 |  |  |  |  |  |  |  | 
| 41 |  |  |  |  |  |  | our $VERSION = '0.02'; | 
| 42 |  |  |  |  |  |  |  | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | =over | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  | =item new (%config) | 
| 47 |  |  |  |  |  |  |  | 
| 48 |  |  |  |  |  |  | Constructor. You can set the following parameters during construction: | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  | BaseURL             - The URL pointing to the Icinga REST API (default: 'http://localhost/icinga-web/web/api'). | 
| 51 |  |  |  |  |  |  | AuthKey             - The Auth key to use (mandatory) | 
| 52 |  |  |  |  |  |  | Target              - 'host' or 'service' (default: 'host') | 
| 53 |  |  |  |  |  |  | Columns             - List (array) of columns to return from API calls | 
| 54 |  |  |  |  |  |  | Filters             - API filter as a hash reference | 
| 55 |  |  |  |  |  |  | ssl_verify_hostname - Verify the SSL hostname. Sets the 'verify_hostname' option of LWP::UserAgent (default: 1) | 
| 56 |  |  |  |  |  |  |  | 
| 57 |  |  |  |  |  |  | Example, that returns a hash reference containing some data of all hosts | 
| 58 |  |  |  |  |  |  | whose state is 1 (that means: WARNING): | 
| 59 |  |  |  |  |  |  |  | 
| 60 |  |  |  |  |  |  | my $api = Monitoring::Icinga->new( | 
| 61 |  |  |  |  |  |  | BaseURL      => 'https://your.icinga.host/icinga-web/web/api', | 
| 62 |  |  |  |  |  |  | AuthKey      => 'ThisIsTheAuthKey', | 
| 63 |  |  |  |  |  |  | Target       => 'host', | 
| 64 |  |  |  |  |  |  | Filters      => { | 
| 65 |  |  |  |  |  |  | 'type'  => 'AND', | 
| 66 |  |  |  |  |  |  | 'field' => [ | 
| 67 |  |  |  |  |  |  | { | 
| 68 |  |  |  |  |  |  | 'type'   => 'atom', | 
| 69 |  |  |  |  |  |  | 'field'  => [ 'HOST_CURRENT_STATE' ], | 
| 70 |  |  |  |  |  |  | 'method' => [ '=' ], | 
| 71 |  |  |  |  |  |  | 'value'  => [ 1 ], | 
| 72 |  |  |  |  |  |  | }, | 
| 73 |  |  |  |  |  |  | ], | 
| 74 |  |  |  |  |  |  | }, | 
| 75 |  |  |  |  |  |  | Columns      => [ 'HOST_NAME', 'HOST_OUTPUT', 'HOST_CURRENT_STATE' ], | 
| 76 |  |  |  |  |  |  | ); | 
| 77 |  |  |  |  |  |  |  | 
| 78 |  |  |  |  |  |  | my $result = $api->call; | 
| 79 |  |  |  |  |  |  |  | 
| 80 |  |  |  |  |  |  | You can recall the setters to thange the parameters, filters and columns for | 
| 81 |  |  |  |  |  |  | later API calls. | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | =cut | 
| 84 |  |  |  |  |  |  |  | 
| 85 |  |  |  |  |  |  | sub new { | 
| 86 | 0 |  |  | 0 | 1 |  | my ($class, %args) = @_; | 
| 87 | 0 |  |  |  |  |  | my $self = {}; | 
| 88 |  |  |  |  |  |  |  | 
| 89 | 0 | 0 |  |  |  |  | return undef unless defined $args{'AuthKey'}; | 
| 90 |  |  |  |  |  |  |  | 
| 91 | 0 |  | 0 |  |  |  | $self->{'baseurl'}             = $args{'BaseURL'}             || 'http://localhost/icinga-web/web/api'; | 
| 92 | 0 |  |  |  |  |  | $self->{'authkey'}             = $args{'AuthKey'}; | 
| 93 | 0 |  | 0 |  |  |  | $self->{'ssl_verify_hostname'} = $args{'ssl_verify_hostname'} || 1; | 
| 94 | 0 |  |  |  |  |  | $self->{'params'}              = []; | 
| 95 |  |  |  |  |  |  |  | 
| 96 | 0 |  |  |  |  |  | bless ($self, $class); | 
| 97 |  |  |  |  |  |  |  | 
| 98 |  |  |  |  |  |  | # Initialize some values | 
| 99 | 0 | 0 |  |  |  |  | $self->set_target( ($args{'Target'} ? $args{'Target'} : 'host') ); | 
| 100 | 0 | 0 |  |  |  |  | $self->set_filters($args{'Filters'})    if $args{'Filters'}; | 
| 101 |  |  |  |  |  |  |  | 
| 102 |  |  |  |  |  |  | # Initialize columns | 
| 103 | 0 | 0 |  |  |  |  | if ($args{'Columns'}) { | 
| 104 | 0 |  |  |  |  |  | $self->set_columns(@{$args{'Columns'}}); | 
|  | 0 |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  | } | 
| 106 |  |  |  |  |  |  | else { | 
| 107 |  |  |  |  |  |  | # Set some default columns | 
| 108 | 0 |  |  |  |  |  | $self->set_columns('HOST_NAME', 'SERVICE_NAME'); | 
| 109 |  |  |  |  |  |  | } | 
| 110 |  |  |  |  |  |  |  | 
| 111 |  |  |  |  |  |  | # Construct the complete URL | 
| 112 | 0 |  |  |  |  |  | $self->{'url'} = $self->{'baseurl'} . '/authkey=' . $self->{'authkey'} . '/json'; | 
| 113 |  |  |  |  |  |  |  | 
| 114 |  |  |  |  |  |  | # Exit if HTTPS requested, but LWP::Protocol::https not found | 
| 115 | 0 | 0 |  |  |  |  | if ($self->{'baseurl'} =~ /^https:/i) { | 
| 116 | 0 |  |  |  |  |  | eval { | 
| 117 | 0 |  |  |  |  |  | require LWP::Protocol::https; | 
| 118 |  |  |  |  |  |  | }; | 
| 119 | 0 | 0 |  |  |  |  | croak 'Error: HTTPS requested, but module \'LWP::Protocol::https\' not installed.' if $@; | 
| 120 |  |  |  |  |  |  | } | 
| 121 |  |  |  |  |  |  |  | 
| 122 |  |  |  |  |  |  | # Prepare the LWP::UserAgent object for later use | 
| 123 | 0 |  |  |  |  |  | $self->{'ua'} = LWP::UserAgent->new( ssl_opts => { verify_hostname => $self->{'ssl_verify_hostname'} } ); | 
| 124 | 0 |  |  |  |  |  | $self->{'ua'}->agent('Monitoring::Icinga/' . $VERSION . ' '); | 
| 125 |  |  |  |  |  |  |  | 
| 126 | 0 |  |  |  |  |  | return $self; | 
| 127 |  |  |  |  |  |  | } | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  |  | 
| 130 |  |  |  |  |  |  | =item set_target ($value) | 
| 131 |  |  |  |  |  |  |  | 
| 132 |  |  |  |  |  |  | Set target for API call. Can be 'host' or 'service'. See Icinga Web REST API | 
| 133 |  |  |  |  |  |  | Documentation at http://docs.icinga.org/latest/en/icinga-web-api.html for | 
| 134 |  |  |  |  |  |  | details on allowed targets. | 
| 135 |  |  |  |  |  |  |  | 
| 136 |  |  |  |  |  |  | =cut | 
| 137 |  |  |  |  |  |  |  | 
| 138 |  |  |  |  |  |  | sub set_target { | 
| 139 | 0 |  |  | 0 | 1 |  | my ($self, $target) = @_; | 
| 140 | 0 | 0 | 0 |  |  |  | unless (defined $target and ($target eq 'host' or $target eq 'service')) { | 
|  |  |  | 0 |  |  |  |  | 
| 141 | 0 |  |  |  |  |  | carp 'Invalid target specified'; | 
| 142 | 0 |  |  |  |  |  | return 0; | 
| 143 |  |  |  |  |  |  | } | 
| 144 |  |  |  |  |  |  |  | 
| 145 | 0 |  |  |  |  |  | $self->{'target'} = []; | 
| 146 | 0 |  |  |  |  |  | push @{$self->{'target'}}, 'target'; | 
|  | 0 |  |  |  |  |  |  | 
| 147 | 0 |  |  |  |  |  | push @{$self->{'target'}}, $target; | 
|  | 0 |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | } | 
| 149 |  |  |  |  |  |  |  | 
| 150 |  |  |  |  |  |  |  | 
| 151 |  |  |  |  |  |  | =item set_columns (@array) | 
| 152 |  |  |  |  |  |  |  | 
| 153 |  |  |  |  |  |  | Set columns that get returned by a call. The parameters are a list of columns. | 
| 154 |  |  |  |  |  |  | For a list of valid columns, see the source code of Icinga Web at: | 
| 155 |  |  |  |  |  |  |  | 
| 156 |  |  |  |  |  |  | app/modules/Api/models/Store/LegacyLayer/TargetModifierModel.class.php | 
| 157 |  |  |  |  |  |  |  | 
| 158 |  |  |  |  |  |  | Example: | 
| 159 |  |  |  |  |  |  |  | 
| 160 |  |  |  |  |  |  | $api->set_columns('HOST_NAME', 'HOST_CURRENT_STATE', 'HOST_OUTPUT'); | 
| 161 |  |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  | =cut | 
| 163 |  |  |  |  |  |  |  | 
| 164 |  |  |  |  |  |  | sub set_columns { | 
| 165 | 0 |  |  | 0 | 1 |  | my ($self, @columns) = @_; | 
| 166 |  |  |  |  |  |  |  | 
| 167 | 0 |  |  |  |  |  | my $columncount = 0; | 
| 168 | 0 |  |  |  |  |  | $self->{'columns'} = []; | 
| 169 | 0 |  |  |  |  |  | foreach (@columns) { | 
| 170 | 0 |  |  |  |  |  | push @{$self->{'columns'}}, 'columns[' . $columncount . ']'; | 
|  | 0 |  |  |  |  |  |  | 
| 171 | 0 |  |  |  |  |  | push @{$self->{'columns'}}, $_; | 
|  | 0 |  |  |  |  |  |  | 
| 172 | 0 |  |  |  |  |  | $columncount++; | 
| 173 |  |  |  |  |  |  | } | 
| 174 |  |  |  |  |  |  | } | 
| 175 |  |  |  |  |  |  |  | 
| 176 |  |  |  |  |  |  |  | 
| 177 |  |  |  |  |  |  | =item set_filters ($hash_reference) | 
| 178 |  |  |  |  |  |  |  | 
| 179 |  |  |  |  |  |  | Set filters for API call using a hash reference. See Icinga Web REST API | 
| 180 |  |  |  |  |  |  | Documentation at http://docs.icinga.org/latest/en/icinga-web-api.html for | 
| 181 |  |  |  |  |  |  | details on how filters need to be defined. Basically, they define it in JSON | 
| 182 |  |  |  |  |  |  | syntax, but this module requires a Perl hash reference instead. | 
| 183 |  |  |  |  |  |  |  | 
| 184 |  |  |  |  |  |  | Simple Example: | 
| 185 |  |  |  |  |  |  |  | 
| 186 |  |  |  |  |  |  | $api->set_filters( { | 
| 187 |  |  |  |  |  |  | 'type'  => 'AND', | 
| 188 |  |  |  |  |  |  | 'field' => [ | 
| 189 |  |  |  |  |  |  | { | 
| 190 |  |  |  |  |  |  | 'type'   => 'atom', | 
| 191 |  |  |  |  |  |  | 'field'  => [ 'HOST_CURRENT_STATE' ], | 
| 192 |  |  |  |  |  |  | 'method' => [ '>' ], | 
| 193 |  |  |  |  |  |  | 'value'  => [ 0 ], | 
| 194 |  |  |  |  |  |  | }, | 
| 195 |  |  |  |  |  |  | ], | 
| 196 |  |  |  |  |  |  | } ); | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  | More complex example: | 
| 199 |  |  |  |  |  |  |  | 
| 200 |  |  |  |  |  |  | $api->set_filters( { | 
| 201 |  |  |  |  |  |  | 'type' => 'AND', | 
| 202 |  |  |  |  |  |  | 'field' => [ | 
| 203 |  |  |  |  |  |  | { | 
| 204 |  |  |  |  |  |  | 'type' => 'atom', | 
| 205 |  |  |  |  |  |  | 'field' => [ 'SERVICE_NAME' ], | 
| 206 |  |  |  |  |  |  | 'method' => [ 'like' ], | 
| 207 |  |  |  |  |  |  | 'value' => [ '*pop*' ], | 
| 208 |  |  |  |  |  |  | }, | 
| 209 |  |  |  |  |  |  | { | 
| 210 |  |  |  |  |  |  | 'type' => 'OR', | 
| 211 |  |  |  |  |  |  | 'field' => [ | 
| 212 |  |  |  |  |  |  | { | 
| 213 |  |  |  |  |  |  | 'type' => 'atom', | 
| 214 |  |  |  |  |  |  | 'field' => [ 'SERVICE_CURRENT_STATE' ], | 
| 215 |  |  |  |  |  |  | 'method' => [ '>' ], | 
| 216 |  |  |  |  |  |  | 'value' => [ 0 ], | 
| 217 |  |  |  |  |  |  | }, | 
| 218 |  |  |  |  |  |  | { | 
| 219 |  |  |  |  |  |  | 'type' => 'atom', | 
| 220 |  |  |  |  |  |  | 'field' => [ 'SERVICE_IS_FLAPPING' ], | 
| 221 |  |  |  |  |  |  | 'method' => [ '=' ], | 
| 222 |  |  |  |  |  |  | 'value' => [ 1 ], | 
| 223 |  |  |  |  |  |  | }, | 
| 224 |  |  |  |  |  |  | ], | 
| 225 |  |  |  |  |  |  | }, | 
| 226 |  |  |  |  |  |  | ], | 
| 227 |  |  |  |  |  |  | }; | 
| 228 |  |  |  |  |  |  |  | 
| 229 |  |  |  |  |  |  | You don't actually need a filter for the API calls to work. But it is strongly | 
| 230 |  |  |  |  |  |  | recommended to define one whenever you fetch any data. Otherwise ALL host or | 
| 231 |  |  |  |  |  |  | service objects will be returned. | 
| 232 |  |  |  |  |  |  |  | 
| 233 |  |  |  |  |  |  | By the way: You should filter for host or service objects, not both. Otherwise | 
| 234 |  |  |  |  |  |  | you will most likely not get the results you want. I.e. if you want to get all | 
| 235 |  |  |  |  |  |  | hosts and services with problems, you better do two API calls. One for the | 
| 236 |  |  |  |  |  |  | hosts, another for the services. | 
| 237 |  |  |  |  |  |  |  | 
| 238 |  |  |  |  |  |  | =cut | 
| 239 |  |  |  |  |  |  |  | 
| 240 |  |  |  |  |  |  | sub set_filters { | 
| 241 | 0 |  |  | 0 | 1 |  | my ($self, $filters) = @_; | 
| 242 | 0 |  |  |  |  |  | my $json_data; | 
| 243 | 0 |  |  |  |  |  | eval { | 
| 244 | 0 |  |  |  |  |  | $json_data = encode_json($filters); | 
| 245 |  |  |  |  |  |  | }; | 
| 246 | 0 | 0 |  |  |  |  | if ($@) { | 
| 247 | 0 |  |  |  |  |  | chomp $@; | 
| 248 | 0 |  |  |  |  |  | carp 'JSON ERROR: '.$@; | 
| 249 | 0 |  |  |  |  |  | return 0; | 
| 250 |  |  |  |  |  |  | } | 
| 251 |  |  |  |  |  |  | else { | 
| 252 | 0 |  |  |  |  |  | $self->{'filters'} = []; | 
| 253 | 0 |  |  |  |  |  | push @{$self->{'filters'}}, 'filters_json'; | 
|  | 0 |  |  |  |  |  |  | 
| 254 | 0 |  |  |  |  |  | push @{$self->{'filters'}}, $json_data; | 
|  | 0 |  |  |  |  |  |  | 
| 255 |  |  |  |  |  |  | } | 
| 256 |  |  |  |  |  |  | } | 
| 257 |  |  |  |  |  |  |  | 
| 258 |  |  |  |  |  |  |  | 
| 259 |  |  |  |  |  |  | =item get_hosts (@states) | 
| 260 |  |  |  |  |  |  |  | 
| 261 |  |  |  |  |  |  | Return an array of all host objects matching the specified states. The | 
| 262 |  |  |  |  |  |  | parameters can be: | 
| 263 |  |  |  |  |  |  |  | 
| 264 |  |  |  |  |  |  | 0 - OK | 
| 265 |  |  |  |  |  |  | 1 - DOWN | 
| 266 |  |  |  |  |  |  | 2 - UNREACHABLE | 
| 267 |  |  |  |  |  |  |  | 
| 268 |  |  |  |  |  |  | You should set the desired columns first, using either the Columns parameter of | 
| 269 |  |  |  |  |  |  | the constructor or the set_columns() function, i.e.: | 
| 270 |  |  |  |  |  |  |  | 
| 271 |  |  |  |  |  |  | $api->set_columns('HOST_NAME', 'HOST_CURRENT_STATE', 'HOST_OUTPUT'); | 
| 272 |  |  |  |  |  |  | $hosts_array = $api->get_hosts(1,2); | 
| 273 |  |  |  |  |  |  |  | 
| 274 |  |  |  |  |  |  | That would return the name, state and check output of all hosts in state DOWN | 
| 275 |  |  |  |  |  |  | or UNREACHABLE. | 
| 276 |  |  |  |  |  |  |  | 
| 277 |  |  |  |  |  |  | =cut | 
| 278 |  |  |  |  |  |  |  | 
| 279 |  |  |  |  |  |  | sub get_hosts { | 
| 280 | 0 |  |  | 0 | 1 |  | my ($self, @states) = @_; | 
| 281 | 0 |  |  |  |  |  | return $self->_get('host', @states); | 
| 282 |  |  |  |  |  |  | } | 
| 283 |  |  |  |  |  |  |  | 
| 284 |  |  |  |  |  |  |  | 
| 285 |  |  |  |  |  |  | =item get_services (@states) | 
| 286 |  |  |  |  |  |  |  | 
| 287 |  |  |  |  |  |  | Return an array of all service objects matching the specified states. The | 
| 288 |  |  |  |  |  |  | parameters can be: | 
| 289 |  |  |  |  |  |  |  | 
| 290 |  |  |  |  |  |  | 0 - OK | 
| 291 |  |  |  |  |  |  | 1 - WARNING | 
| 292 |  |  |  |  |  |  | 2 - CRITICAL | 
| 293 |  |  |  |  |  |  | 3 - UNKNOWN | 
| 294 |  |  |  |  |  |  |  | 
| 295 |  |  |  |  |  |  | You should set the desired columns first, using either the Columns parameter of | 
| 296 |  |  |  |  |  |  | the constructor or the set_columns() function, i.e.: | 
| 297 |  |  |  |  |  |  |  | 
| 298 |  |  |  |  |  |  | $api->set_columns('HOST_NAME', 'SERVICE_NAME', 'HOST_CURRENT_STATE', 'HOST_OUTPUT'); | 
| 299 |  |  |  |  |  |  | $services_array = $api->get_services(1,2,3); | 
| 300 |  |  |  |  |  |  |  | 
| 301 |  |  |  |  |  |  | That would return the host name, service name, state and check output of all | 
| 302 |  |  |  |  |  |  | services in state WARNING, CRITICAL or UNKNOWN. | 
| 303 |  |  |  |  |  |  |  | 
| 304 |  |  |  |  |  |  | =cut | 
| 305 |  |  |  |  |  |  |  | 
| 306 |  |  |  |  |  |  | sub get_services { | 
| 307 | 0 |  |  | 0 | 1 |  | my ($self, @states) = @_; | 
| 308 | 0 |  |  |  |  |  | return $self->_get('service', @states); | 
| 309 |  |  |  |  |  |  | } | 
| 310 |  |  |  |  |  |  |  | 
| 311 |  |  |  |  |  |  |  | 
| 312 |  |  |  |  |  |  | =item call | 
| 313 |  |  |  |  |  |  |  | 
| 314 |  |  |  |  |  |  | Do an API call using the current settings (Target, Columns and Filters) and | 
| 315 |  |  |  |  |  |  | return the complete result as a hash reference. The data you usually want is in | 
| 316 |  |  |  |  |  |  | $hash->{'result'}. | 
| 317 |  |  |  |  |  |  |  | 
| 318 |  |  |  |  |  |  | =cut | 
| 319 |  |  |  |  |  |  |  | 
| 320 |  |  |  |  |  |  | sub call { | 
| 321 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 322 |  |  |  |  |  |  |  | 
| 323 | 0 |  |  |  |  |  | my @params; | 
| 324 | 0 |  |  |  |  |  | push @params, @{$self->{'target'}}; | 
|  | 0 |  |  |  |  |  |  | 
| 325 | 0 |  |  |  |  |  | push @params, @{$self->{'columns'}}; | 
|  | 0 |  |  |  |  |  |  | 
| 326 | 0 |  |  |  |  |  | push @params, @{$self->{'filters'}}; | 
|  | 0 |  |  |  |  |  |  | 
| 327 |  |  |  |  |  |  |  | 
| 328 | 0 |  |  |  |  |  | my $api_request = POST $self->{'url'}, \@params; | 
| 329 | 0 |  |  |  |  |  | my $api_result = $self->{'ua'}->request($api_request); | 
| 330 | 0 |  |  |  |  |  | my $content_type = $api_result->headers->header('Content-Type'); | 
| 331 |  |  |  |  |  |  |  | 
| 332 | 0 | 0 |  |  |  |  | if ($content_type =~ /^application\/json/) { | 
|  |  | 0 |  |  |  |  |  | 
| 333 |  |  |  |  |  |  | # We got a (hopefully) correct answer | 
| 334 | 0 |  |  |  |  |  | my $api_result_hash = decode_json($api_result->content); | 
| 335 | 0 |  |  |  |  |  | return $api_result_hash; | 
| 336 |  |  |  |  |  |  | } | 
| 337 |  |  |  |  |  |  | elsif ($content_type =~ /^text\/html/) { | 
| 338 |  |  |  |  |  |  | # We got an error from the API | 
| 339 | 0 |  |  |  |  |  | my $errormsg = 'unknown error'; | 
| 340 | 0 |  |  |  |  |  | foreach (split(/\n/, $api_result->content)) { | 
| 341 |  |  |  |  |  |  | #    SQLSTATE[42S22]: Column not found: 1054 Unknown column 'i.service_has_been_acknowleged' in 'field list' | 
| 342 | 0 | 0 |  |  |  |  | $errormsg = $1 if $_ =~ /(SQLSTATE\[.*\]: .*)<\/div>/; | 
| 343 | 0 |  |  |  |  |  | $errormsg =~ s/\s+$//g; | 
| 344 |  |  |  |  |  |  | } | 
| 345 | 0 |  |  |  |  |  | carp 'JSON ERROR: ' . $errormsg; | 
| 346 | 0 |  |  |  |  |  | return undef; | 
| 347 |  |  |  |  |  |  | } | 
| 348 |  |  |  |  |  |  | } | 
| 349 |  |  |  |  |  |  |  | 
| 350 |  |  |  |  |  |  |  | 
| 351 |  |  |  |  |  |  | sub _get { | 
| 352 | 0 |  |  | 0 |  |  | my ($self, $target, @states) = @_; | 
| 353 | 0 | 0 | 0 |  |  |  | unless (defined $target and ($target eq 'host' or $target eq 'service')) { | 
|  |  |  | 0 |  |  |  |  | 
| 354 | 0 |  |  |  |  |  | carp 'No valid target given'; | 
| 355 | 0 |  |  |  |  |  | return undef; | 
| 356 |  |  |  |  |  |  | } | 
| 357 | 0 | 0 |  |  |  |  | unless (scalar @states) { | 
| 358 | 0 |  |  |  |  |  | carp 'No state given'; | 
| 359 | 0 |  |  |  |  |  | return undef; | 
| 360 |  |  |  |  |  |  | } | 
| 361 |  |  |  |  |  |  |  | 
| 362 | 0 |  |  |  |  |  | my $field = 'HOST_CURRENT_STATE'; | 
| 363 | 0 | 0 |  |  |  |  | $field = 'SERVICE_CURRENT_STATE' if $target eq 'service'; | 
| 364 |  |  |  |  |  |  |  | 
| 365 | 0 |  |  |  |  |  | my $filters = { | 
| 366 |  |  |  |  |  |  | 'type'  => 'OR', | 
| 367 |  |  |  |  |  |  | 'field' => [], | 
| 368 |  |  |  |  |  |  | }; | 
| 369 |  |  |  |  |  |  |  | 
| 370 | 0 |  |  |  |  |  | foreach my $state (@states) { | 
| 371 | 0 | 0 | 0 |  |  |  | if ($target eq 'host' and $state !~ /^[012]$/) { | 
| 372 | 0 |  |  |  |  |  | carp 'Unknown host state: ' . $state; | 
| 373 | 0 |  |  |  |  |  | next; | 
| 374 |  |  |  |  |  |  | } | 
| 375 | 0 | 0 | 0 |  |  |  | if ($target eq 'service' and $state !~ /^[0123]$/) { | 
| 376 | 0 |  |  |  |  |  | carp 'Unknown service state: ' . $state; | 
| 377 | 0 |  |  |  |  |  | next; | 
| 378 |  |  |  |  |  |  | } | 
| 379 |  |  |  |  |  |  |  | 
| 380 | 0 |  |  |  |  |  | my $subfilter = { | 
| 381 |  |  |  |  |  |  | 'type'   => 'atom', | 
| 382 |  |  |  |  |  |  | 'field'  => [ $field ], | 
| 383 |  |  |  |  |  |  | 'method' => [ '=' ], | 
| 384 |  |  |  |  |  |  | 'value'  => [ $state ], | 
| 385 |  |  |  |  |  |  | }; | 
| 386 |  |  |  |  |  |  |  | 
| 387 | 0 |  |  |  |  |  | push @{$filters->{'field'}}, $subfilter; | 
|  | 0 |  |  |  |  |  |  | 
| 388 |  |  |  |  |  |  | } | 
| 389 |  |  |  |  |  |  |  | 
| 390 |  |  |  |  |  |  | # Remember the original values to restore them later | 
| 391 | 0 |  |  |  |  |  | my $temp = {}; | 
| 392 | 0 |  |  |  |  |  | $temp->{'target'}  = $self->{'target'}; | 
| 393 | 0 |  |  |  |  |  | $temp->{'filters'} = $self->{'filters'}; | 
| 394 |  |  |  |  |  |  |  | 
| 395 |  |  |  |  |  |  | # Set appropriate values for this call | 
| 396 | 0 |  |  |  |  |  | $self->set_target($target); | 
| 397 | 0 |  |  |  |  |  | $self->set_filters($filters); | 
| 398 |  |  |  |  |  |  |  | 
| 399 |  |  |  |  |  |  | # Do the call | 
| 400 | 0 |  |  |  |  |  | my $result = $self->call; | 
| 401 |  |  |  |  |  |  |  | 
| 402 |  |  |  |  |  |  | # Restore the original values | 
| 403 | 0 |  |  |  |  |  | $self->{'target'}  = $temp->{'target'}; | 
| 404 | 0 |  |  |  |  |  | $self->{'filters'} = $temp->{'filters'}; | 
| 405 |  |  |  |  |  |  |  | 
| 406 | 0 | 0 |  |  |  |  | return $result->{'result'} if $result->{'success'}; | 
| 407 | 0 | 0 |  |  |  |  | carp 'API Error: ' . $result->{'result'} if $result->{'result'}; | 
| 408 | 0 |  |  |  |  |  | return undef; | 
| 409 |  |  |  |  |  |  | } | 
| 410 |  |  |  |  |  |  |  | 
| 411 |  |  |  |  |  |  | 1; | 
| 412 |  |  |  |  |  |  |  | 
| 413 |  |  |  |  |  |  | __END__ |