File Coverage

lib/Consul/Simple.pm
Criterion Covered Total %
statement 123 125 98.4
branch 22 32 68.7
condition 11 17 64.7
subroutine 16 17 94.1
pod 4 4 100.0
total 176 195 90.2


line stmt bran cond sub pod time code
1             package Consul::Simple;
2             $Consul::Simple::VERSION = '1.142390';
3 8     8   5400 use strict;use warnings;
  8     8   16  
  8         268  
  8         66  
  8         12  
  8         348  
4 8     8   9218 use LWP::UserAgent;
  8         557920  
  8         280  
5 8     8   94 use HTTP::Response;
  8         12  
  8         9480  
6 8     8   8752 use HTTP::Request::Common;
  8         18358  
  8         688  
7 8     8   7370 use MIME::Base64;
  8         6508  
  8         508  
8 8     8   60 use JSON;
  8         18  
  8         76  
9 8     8   1208 use Data::Dumper;
  8         16  
  8         9978  
10              
11             sub new {
12 5     5 1 4236 my $class = shift;
13 5         38 my $self = {};
14 5         47 bless ($self,$class);
15 5         17 my %args;
16 5         17 { my @args = @_;
  5         47  
17 5 50       36 die 'Consul::Simple::new: even number of arguments required'
18             if scalar @args % 2;
19 5         409 %args = @args;
20             }
21 5   100     122 $self->{consul_server} = $args{consul_server} || 'localhost';
22 5   100     48 $self->{kvPrefix} = $args{kvPrefix} || '/';
23 5         33 $self->{kvPrefix} =~ s/\/\//\//g;
24 5         221 $self->{kvPrefix} =~ s/\/\//\//g;
25 5         13 $self->{kvPrefix} =~ s/\/\//\//g;
26 5 100       54 if($self->{kvPrefix} !~ /^\//) {
27 3         16 $self->{kvPrefix} = '/' . $self->{kvPrefix};
28             }
29 5 100       36 if($self->{kvPrefix} !~ /\/$/) {
30 3         11 $self->{kvPrefix} = $self->{kvPrefix} . '/';
31             }
32 5         10 { my %ua_args = ();
  5         11  
33 5 50       22 $ua_args{ssl_opts} = $args{ssl_opts} if $args{ssl_opts};
34 5         119 $self->{ua} = LWP::UserAgent->new(%ua_args);
35             }
36              
37 5   50     40273 $self->{proto} = $args{proto} || 'http';
38 5   50     42 $self->{consul_port} = $args{port} || 8500;
39 5         20 $self->{constructor_args} = \%args;
40             $self->{warning_handler} = $args{warning_handler} || sub {
41 2     2   16 my $warnstr = shift;
42 2         7 my %args = @_;
43 2         170 print STDERR "[WARN]: $warnstr\n";
44 5   50     160 };
45 5         113 return $self;
46             }
47              
48             sub _warn {
49 2     2   5 my $self = shift;
50 2         10 $self->{warning_handler}->(@_);
51             }
52              
53             sub _do_request {
54 12     12   50756 my $self = shift;
55 12         26 my $req = shift;
56 12         31 my %req_args = @_;
57 12         22 my $ret;
58 12   50     107 my $tries = $self->{constructor_args}->{retries} || 5;
59 12   50     74 my $timeout = $self->{constructor_args}->{timeout} || 2;
60 12         42 while($tries--) {
61 14         34 eval {
62 14     0   404 local $SIG{ALRM} = sub { die "timed out\n"; };
  0         0  
63 14         103 alarm $timeout;
64 14         129 $ret = $self->{ua}->request($req, %req_args);
65             };
66 14         800561 alarm 0;
67 14 100 66     172 last if $ret and $ret->is_success;
68 2         29 my $err;
69 2 50       8 if($@) {
70 0         0 $err = $@;
71             } else {
72 2         13 $err = 'http request failed with ' . $ret->status_line;
73             }
74 2         33 $self->_warn("request failed: $err", response => $ret);
75 2         2009873 sleep 1;
76             }
77 12         229 return $ret;
78             }
79              
80             sub KVGet {
81 5     5 1 16 my $self = shift;
82 5 50       33 my $key = shift or die 'Consul::Simple::KVGet: key required as first argument';
83 5         11 my %args;
84 5         9 { my @args = @_;
  5         14  
85 5 50       24 die 'Consul::Simple::KVGet: even number of arguments required'
86             if scalar @args % 2;
87 5         15 %args = @args;
88             }
89 5         12 my @entries = ();
90 5         8 eval {
91 5         24 my $url = $self->_mk_kv_url($key);
92 5 100       16 $url .= '?recurse' if $args{recurse};
93 5         28 my $res = $self->_do_request(GET $url);
94 5         66 my $content = $res->content;
95 5         191 my $values = JSON::decode_json($content);
96 5         74 @entries = @$values;
97             };
98 5         13 my @ret = ();
99 5         16 foreach my $entry (@entries) {
100             #The returned entry Value is always base64 encoded
101 6         54 $entry->{Value} = MIME::Base64::decode_base64($entry->{Value});
102              
103             #the idea below is to try to JSON decode it. If that works,
104             #return the JSON decoded value. Otherwise, return it un-decoded
105 6         10 my $value;
106 6         12 eval {
107 6         59 $value = JSON::decode_json($entry->{Value});
108             };
109 6 100       28 $value = $entry->{Value} unless $value;
110 6         10 $entry->{Value} = $value;
111 6         21 push @ret, $entry;
112             }
113              
114 5         55 return @ret;
115             }
116              
117              
118             sub KVPut {
119 4     4 1 11 my $self = shift;
120 4 50       22 my $key = shift or die 'Consul::Simple::KVPut: key required as first argument';
121 4 50       25 my $value = shift or die 'Consul::Simple::KVPut: value required as second argument';
122 4 100       19 if(ref $value) {
123 2         53 $value = JSON::encode_json($value);
124             }
125 4         7 my %args;
126 4         8 { my @args = @_;
  4         10  
127 4 50       18 die 'Consul::Simple::KVPut: even number of arguments required'
128             if scalar @args % 2;
129 4         11 %args = @args;
130             }
131 4         19 my $res = $self->_do_request(PUT $self->_mk_kv_url($key), Content => $value);
132 4         42 return $res;
133             }
134              
135             sub _mk_kv_url {
136 12     12   32 my $self = shift;
137 12         22 my $key = shift;
138 12         136 return $self->{proto} . '://' . $self->{consul_server} . ':' . $self->{consul_port} . '/v1/kv' . $self->{kvPrefix} . $key;
139             }
140              
141             sub KVDelete {
142 3     3 1 2446 my $self = shift;
143 3 50       21 my $key = shift or die 'Consul::Simple::KVDelete: key required as first argument';
144 3         10 my %args;
145 3         6 { my @args = @_;
  3         9  
146 3 50       17 die 'Consul::Simple::KVPut: even number of arguments required'
147             if scalar @args % 2;
148 3         13 %args = @args;
149             }
150 3         17 my $res = $self->_do_request(
151             HTTP::Request::Common::_simple_req(
152             'DELETE',
153             $self->_mk_kv_url($key)
154             )
155             );
156 3         37 return $res;
157             }
158             1;
159              
160             __END__