File Coverage

blib/lib/Zabbix/Tiny.pm
Criterion Covered Total %
statement 98 103 95.1
branch 30 36 83.3
condition 2 5 40.0
subroutine 12 12 100.0
pod 2 6 33.3
total 144 162 88.8


line stmt bran cond sub pod time code
1             package Zabbix::Tiny;
2 6     6   167168 use strict;
  6         22  
  6         133  
3 6     6   22 use warnings;
  6         9  
  6         109  
4 6     6   2609 use Moo;
  6         44232  
  6         24  
5 6     6   7386 use Carp;
  6         13  
  6         252  
6 6     6   913 use LWP;
  6         96468  
  6         129  
7 6     6   1237 use JSON;
  6         14960  
  6         29  
8              
9             our $VERSION = "1.11";
10              
11             has 'server' => (
12             is => 'rw',
13             required => 1,
14             );
15             has 'user' => (
16             is => 'rw',
17             required => 1,
18             );
19             has 'password' => (
20             is => 'rw',
21             required => 1,
22             );
23             has 'zabbix_method' => ( is => 'ro' );
24             has 'zabbix_params' => ( is => 'ro' );
25             has 'auth' => ( is => 'ro' );
26             has 'ua' => (
27             is => 'ro',
28             lazy => 1,
29             default => sub { LWP::UserAgent->new },
30             );
31             has 'id' => ( is => 'ro', default => sub { 1 } );
32             has 'post_response' => ( is => 'ro' );
33             has 'last_response' => ( is => 'ro' );
34             has 'json_request' => ( is => 'ro' );
35             has 'json_response' => ( is => 'ro' );
36             has 'verify_hostname' => ( is => 'rw', default => sub { 1 } );
37             has 'ssl_opts' => ( is => 'rw' );
38             has 'delay' => ( is => 'rw' );
39             has 'request' => ( is => 'ro' );
40             has 'json_prepared' => ( is => 'ro' );
41             has 'json_executed' => ( is => 'ro', default => sub { 0 } );
42             has 'redo' => ( is => 'ro' );
43              
44             my @content_type = ( 'content-type', 'application/json', );
45              
46             sub BUILD {
47 6     6 0 27 my $self = shift;
48 6         80 my $ua = $self->ua;
49 6         60 my $url = $self->server;
50 6         45 my $json_data = {
51             jsonrpc => '2.0',
52             id => $self->id,
53             method => 'user.login',
54             params => {
55             user => $self->user,
56             password => $self->password,
57             },
58             };
59 6 50       28 if ( $self->verify_hostname == 0 ) {
60 0         0 $ua->ssl_opts( verify_hostname => 0 );
61             }
62              
63 6 50       40 if ( $self->ssl_opts ) {
64 0         0 $ua->ssl_opts( %{ $self->{ssl_opts} } );
  0         0  
65             }
66             }
67              
68             sub login {
69 7     7 0 3065 my $self = shift;
70 7         23 my $id = $self->id;
71 7         146 my $ua = $self->ua;
72 7         62 my $url = $self->server;
73 7         45 my $json_data = {
74             jsonrpc => '2.0',
75             id => $id,
76             method => 'user.login',
77             params => {
78             user => $self->user,
79             password => $self->password,
80             },
81             };
82 7         79 my $json = encode_json($json_data);
83 7         49 my $response = $ua->post( $url, @content_type, Content => $json );
84              
85 7 100       43473 if ( $response->{_rc} !~ /2\d\d/ ) {
86 1         2 my $error_message = "HTTP error ";
87 1         12 $error_message .= "(code $response->{_rc}) ";
88 1   50     4 $error_message .= $response->{_msg} // q{};
89 1         16 croak($error_message);
90             }
91              
92 6 50       61 my $content = decode_json( $response->{_content} ) or die($!);
93              
94 6 100       22 if ( $content->{error} ) {
95 1         2 my $error_data = $content->{error}->{data};
96 1         3 my $error_msg = $content->{error}->{message};
97 1         2 my $error_code = $content->{error}->{code};
98 1         4 my $error = "Error from Zabbix (code $error_code): $error_msg $error_data";
99 1         24 croak($error);
100             }
101              
102 5         44 $self->{auth} = $content->{'result'};
103             }
104              
105             sub prepare {
106 13     13 1 22 my $self = shift;
107 13         19 my $method = shift;
108 13         20 $self->{ id }++;
109 13 100       35 if ($method) {
110 6         11 $self->{zabbix_method} = $method;
111 6         14 undef $self->{zabbix_params};
112 6         12 my @args = @_;
113 6 100       18 if ( scalar @args == 1 ) {
114 3         8 $self->{zabbix_params} = $args[0];
115             }
116             else {
117 3         6 my %params = @args;
118 3         8 $self->{zabbix_params} = \%params;
119             }
120             }
121 13 100       33 unless ($self->{zabbix_method} eq 'apiinfo.version') {
122 9 100       23 login($self) if ( !$self->auth );
123             }
124 13 50       34 if ( !$self->zabbix_method ) {
125 0         0 croak("No Zabbix API method defined");
126             }
127             $self->{request} = {
128 13         72 jsonrpc => '2.0',
129             id => $self->id,
130             method => $self->zabbix_method,
131             params => $self->zabbix_params,
132             };
133 13 100       37 unless ($self->{zabbix_method} eq 'apiinfo.version') {
134 9         17 $self->{request}->{auth} = $self->auth;
135             }
136 13 50       96 $self->{json_prepared} = encode_json( $self->request ) or die($!);
137             }
138              
139             sub execute {
140 7     7 0 12 my $self = shift;
141 7         157 my $ua = $self->ua;
142 7         98 $self->{post_response} = $ua->post( $self->server, @content_type,
143             Content => $self->json_prepared );
144 7         20673 $self->{json_request} = $self->{post_response}->{'_request'}->{_content};
145 7         26 $self->{json_response} = $self->post_response->{_content};
146 7 100       28 if ( $self->post_response->{_content} eq q{} ) {
147 1         21 croak( "Empty response received from the Zabbix API. This can indicate an error on the API side like running out of memory." );
148             }
149 6         49 $self->{last_response} = decode_json( $self->{post_response}->{_content} );
150 6         20 my $method = $self->zabbix_method;
151 6         12 my $params = $self->zabbix_params;
152 6         13 prepare($self); ## Rerun prepare to get the new request id.
153             }
154              
155             sub do {
156 7     7 1 1791 my $self = shift;
157 7         13 my $method = shift;
158 7         14 my @args = @_;
159 7 100       18 if ($method) {
160 5         17 prepare( $self, $method, @args );
161             }
162 7         26 execute($self);
163 6 100       20 if ( $self->{last_response}->{error} ) {
164 1         2 my $error = $self->{last_response}->{error}->{data};
165 1 50 33     8 if ( ( !$self->{redo} )
166             && ( $error eq 'Session terminated, re-login, please.' ) )
167             {
168 1         2 $self->{redo}++;
169 1         2 delete( $self->{auth} );
170 1         4 prepare($self);
171 1         5 &do($self); ## Need to use "&" because "do" is a perl keyword.
172             }
173             else {
174 0         0 croak("Error: $error");
175             }
176             }
177             else {
178 5 100       21 delete( $self->{redo} ) if $self->redo;
179 5         11 $self->{json_executed} = 1;
180 5         33 return $self->{last_response}->{'result'};
181             }
182             }
183              
184             sub DEMOLISH {
185 7     7 0 9372 my $self = shift;
186 7         17 my $method = shift;
187 7         114 my $ua = $self->ua;
188 7         90 my $auth = $self->auth;
189 7         20 my $url = $self->server;
190            
191 7 100       37 return unless ($ua);
192            
193             my $json_data = {
194             jsonrpc => '2.0',
195             id => ++$self->{ id },
196 5         23 method => 'user.logout',
197             auth => $auth,
198             };
199 5         34 my $json = encode_json($json_data);
200 5         24 $self->{post_response} = $ua->post( $url, @content_type, Content => $json );
201             }
202              
203             1;
204              
205             __END__