File Coverage

blib/lib/Zabbix/Tiny.pm
Criterion Covered Total %
statement 118 125 94.4
branch 33 40 82.5
condition 2 5 40.0
subroutine 15 15 100.0
pod 2 6 33.3
total 170 191 89.0


line stmt bran cond sub pod time code
1             package Zabbix::Tiny;
2 8     8   223436 use strict;
  8         47  
  8         238  
3 8     8   49 use warnings;
  8         35  
  8         189  
4 8     8   4865 use Moo;
  8         69855  
  8         38  
5 8     8   12510 use Carp;
  8         20  
  8         498  
6 8     8   1198 use LWP;
  8         112920  
  8         229  
7 8     8   1416 use JSON;
  8         19675  
  8         77  
8 8     8   4822 use version;
  8         15539  
  8         51  
9              
10             our $VERSION = "2.0.1";
11              
12             has 'server' => (
13             is => 'rw',
14             required => 1,
15             );
16             has 'user' => (
17             is => 'rw',
18             required => 1,
19             );
20             has 'password' => (
21             is => 'rw',
22             required => 1,
23             );
24             has 'zabbix_method' => ( is => 'ro' );
25             has 'zabbix_params' => ( is => 'ro' );
26             has 'auth' => ( is => 'ro' );
27             has 'ua' => (
28             is => 'ro',
29             lazy => 1,
30             default => sub { LWP::UserAgent->new },
31             );
32             has 'id' => ( is => 'ro', default => sub { 1 } );
33             has 'post_response' => ( is => 'ro' );
34             has 'last_response' => ( is => 'ro' );
35             has 'json_request' => ( is => 'ro' );
36             has 'json_response' => ( is => 'ro' );
37             has 'verify_hostname' => ( is => 'rw', default => sub { 1 } );
38             has 'ssl_opts' => ( is => 'rw' );
39             has 'delay' => ( is => 'rw' );
40             has 'request' => ( is => 'ro' );
41             has 'json_prepared' => ( is => 'ro' );
42             has 'json_executed' => ( is => 'ro', default => sub { 0 } );
43             has 'redo' => ( is => 'ro' );
44             has 'version' => ( is => 'lazy' );
45              
46             my @content_type = ( 'content-type', 'application/json', );
47              
48             sub BUILD {
49 8     8 0 54 my $self = shift;
50 8         156 my $ua = $self->ua;
51 8         120 my $url = $self->server;
52              
53 8         71 my $json_data = {
54             jsonrpc => '2.0',
55             id => $self->id,
56             method => 'user.login',
57             params => {
58             user => $self->user,
59             password => $self->password,
60             },
61             };
62              
63 8 50       46 if ( $self->verify_hostname == 0 ) {
64 0         0 $ua->ssl_opts( verify_hostname => 0 );
65             }
66              
67 8 50       67 if ( $self->ssl_opts ) {
68 0         0 $ua->ssl_opts( %{ $self->{ssl_opts} } );
  0         0  
69             }
70             }
71              
72              
73             sub _build_version {
74 7     7   69 my $self = shift;
75 7         26 my $id = $self->id;
76 7         139 my $ua = $self->ua;
77 7         67 my $url = $self->server;
78              
79 7         39 my $json_data = {
80             jsonrpc => '2.0',
81             id => $self->id,
82             method => 'apiinfo.version',
83             params => {
84             },
85             };
86              
87 7         90 my $encoded_json = encode_json ($json_data);
88              
89 7         66 my $post_response = $ua->post(
90             $self->server,
91             @content_type,
92             Content => $encoded_json
93             );
94              
95 7         68801 _validate_http_response($post_response);
96              
97 6         47 my $response_content = decode_json( $post_response->{_content} );
98              
99 6 50       25 if ( $response_content->{error} ) {
100 0         0 my $error = $response_content->{error}->{data};
101 0         0 croak("Error: $error");
102             }
103             else {
104 6         66 my $version = version->new($response_content->{'result'});
105 6         184 return($version);
106             }
107             }
108              
109              
110             sub login {
111 8     8 0 3863 my $self = shift;
112 8         30 my $id = $self->id;
113 8         231 my $ua = $self->ua;
114 8         83 my $url = $self->server;
115              
116 8         45 my $json_data = {
117             jsonrpc => '2.0',
118             id => $id,
119             method => 'user.login',
120             };
121              
122 8 100       162 if ( $self->version lt "6.0" ) {
123             $json_data->{params} = {
124 1         9 user => $self->user,
125             password => $self->password,
126             };
127             } else {
128             $json_data->{params} = {
129 6         62 username => $self->user,
130             password => $self->password,
131             };
132             }
133              
134 7         53 my $json = encode_json($json_data);
135 7         30 my $response = $ua->post( $url, @content_type, Content => $json );
136              
137 7         10368 _validate_http_response($response);
138              
139 7 50       65 my $content = decode_json( $response->{_content} ) or die($!);
140              
141 7 100       28 if ( $content->{error} ) {
142 1         2 my $error_data = $content->{error}->{data};
143 1         3 my $error_msg = $content->{error}->{message};
144 1         3 my $error_code = $content->{error}->{code};
145 1         5 my $error = "Error from Zabbix (code $error_code): $error_msg $error_data";
146 1         19 croak($error);
147             }
148              
149 6         53 $self->{auth} = $content->{'result'};
150             }
151              
152              
153             sub _validate_http_response {
154 14     14   29 my $response = shift;
155              
156 14 100       101 if ( $response->{_rc} !~ /2\d\d/ ) {
157 1         2 my $error_message = "HTTP error ";
158 1         5 $error_message .= "(code $response->{_rc}) ";
159 1   50     4 $error_message .= $response->{_msg} // q{};
160 1         19 croak($error_message);
161             }
162             }
163              
164             sub prepare {
165 13     13 1 41 my $self = shift;
166 13         24 my $method = shift;
167 13         21 $self->{ id }++;
168 13 100       34 if ($method) {
169 6         14 $self->{zabbix_method} = $method;
170 6         10 undef $self->{zabbix_params};
171 6         14 my @args = @_;
172 6 100       21 if ( scalar @args == 1 ) {
173 3         8 $self->{zabbix_params} = $args[0];
174             }
175             else {
176 3         7 my %params = @args;
177 3         11 $self->{zabbix_params} = \%params;
178             }
179             }
180 13 100       35 unless ($self->{zabbix_method} eq 'apiinfo.version') {
181 9 100       32 login($self) if ( !$self->auth );
182             }
183 13 50       38 if ( !$self->zabbix_method ) {
184 0         0 croak("No Zabbix API method defined");
185             }
186             $self->{request} = {
187 13         70 jsonrpc => '2.0',
188             id => $self->id,
189             method => $self->zabbix_method,
190             params => $self->zabbix_params,
191             };
192 13 100       35 unless ($self->{zabbix_method} eq 'apiinfo.version') {
193 9         19 $self->{request}->{auth} = $self->auth;
194             }
195 13 50       105 $self->{json_prepared} = encode_json( $self->request ) or die($!);
196             }
197              
198             sub execute {
199 7     7 0 19 my $self = shift;
200 7         181 my $ua = $self->ua;
201 7         90 $self->{post_response} = $ua->post( $self->server, @content_type,
202             Content => $self->json_prepared );
203 7         21988 $self->{json_request} = $self->{post_response}->{'_request'}->{_content};
204 7         46 $self->{json_response} = $self->post_response->{_content};
205 7 100       35 if ( $self->post_response->{_content} eq q{} ) {
206 1         17 croak( "Empty response received from the Zabbix API. This can indicate an error on the API side like running out of memory." );
207             }
208 6         49 $self->{last_response} = decode_json( $self->{post_response}->{_content} );
209 6         22 my $method = $self->zabbix_method;
210 6         12 my $params = $self->zabbix_params;
211 6         14 prepare($self); ## Rerun prepare to get the new request id.
212             }
213              
214             sub do {
215 7     7 1 1920 my $self = shift;
216 7         14 my $method = shift;
217 7         17 my @args = @_;
218 7 100       24 if ($method) {
219 5         16 prepare( $self, $method, @args );
220             }
221 7         19 execute($self);
222 6 100       24 if ( $self->{last_response}->{error} ) {
223 1         4 my $error = $self->{last_response}->{error}->{data};
224 1 50 33     9 if ( ( !$self->{redo} )
225             && ( $error eq 'Session terminated, re-login, please.' ) )
226             {
227 1         2 $self->{redo}++;
228 1         3 delete( $self->{auth} );
229 1         3 prepare($self);
230 1         6 &do($self); ## Need to use "&" because "do" is a perl keyword.
231             }
232             else {
233 0         0 croak("Error: $error");
234             }
235             }
236             else {
237 5 100       18 delete( $self->{redo} ) if $self->redo;
238 5         10 $self->{json_executed} = 1;
239 5         33 return $self->{last_response}->{'result'};
240             }
241             }
242              
243             sub DEMOLISH {
244 9     9 0 15832 my $self = shift;
245 9         26 my $method = shift;
246 9         171 my $ua = $self->ua;
247 9         139 my $auth = $self->auth;
248 9         39 my $url = $self->server;
249            
250 9 100       55 return unless ($ua);
251            
252             my $json_data = {
253             jsonrpc => '2.0',
254             id => ++$self->{ id },
255 7         39 method => 'user.logout',
256             auth => $auth,
257             };
258 7         57 my $json = encode_json($json_data);
259 7         42 $self->{post_response} = $ua->post( $url, @content_type, Content => $json );
260             }
261              
262             1;
263              
264             __END__