File Coverage

blib/lib/Confman/API.pm
Criterion Covered Total %
statement 21 124 16.9
branch 0 26 0.0
condition 0 14 0.0
subroutine 7 24 29.1
pod 0 12 0.0
total 28 200 14.0


line stmt bran cond sub pod time code
1             package Confman::API;
2              
3 1     1   9 use strict;
  1         2  
  1         23  
4 1     1   775 use IO::File;
  1         10687  
  1         114  
5 1     1   1098 use JSON;
  1         26117  
  1         5  
6 1     1   1487 use REST::Client;
  1         53840  
  1         38  
7 1     1   981 use MIME::Base64;
  1         756  
  1         75  
8 1     1   6 use Digest::MD5 qw(md5_hex);
  1         1  
  1         949  
9              
10              
11             sub new {
12 0     0 0   my $class = shift;
13 0   0       my $self = bless({}, ref($class) || $class);
14              
15 0   0       $self->{config_dir} ||= "/etc/confman";
16 0           $self->{json} = JSON->new->allow_nonref;
17 0           $self;
18             }
19              
20             sub config_path {
21 0     0 0   my $self = shift;
22 0           return $self->{config_dir} . "/config.json"
23             }
24              
25             sub api_key {
26 0     0 0   my $self = shift;
27 0 0         $self->{api_key} = shift if scalar(@_) > 0;
28 0           return $self->{api_key};
29             }
30              
31             sub secret {
32 0     0 0   my $self = shift;
33 0 0         $self->{secret} = shift if scalar(@_) > 0;
34 0           return $self->{secret};
35             }
36              
37             sub endpoint_url {
38 0     0 0   my $self = shift;
39 0 0         $self->{endpoint_url} = shift if scalar(@_) > 0;
40 0           return $self->{endpoint_url};
41             }
42              
43             sub load_config {
44 0     0 0   my $self = shift;
45 0   0       my $config_path = shift || $self->config_path;
46 0 0         if(-e $config_path) {
47 0           my $fh = IO::File->new($config_path);
48 0           local $/ = undef;
49 0           my $config = $self->json->decode(<$fh>);
50 0           $fh->close();
51              
52 0           while(my ($key, $value) = each(%$config)) {
53 0           $self->{$key} = $value;
54             }
55             }
56 0           return $self;
57             }
58              
59             sub find_by_name {
60 0     0 0   my $self = shift;
61 0           my $name = shift;
62              
63 0           my $results = $self->search(name => $name);
64 0 0         return undef if($results->{count} == 0);
65 0           my $conf_set_data = $results->{results}[0];
66 0           return Confman::ConfSet->new(
67             $self,
68             %$conf_set_data
69             );
70             }
71              
72             sub search {
73 0     0 0   my $self = shift;
74 0           my %query = @_;
75              
76 0           my ($results, $response) = $self->request('GET', "confman/sets/search", \%query);
77 0           return $results;
78             }
79              
80              
81 0     0 0   sub json { my $self = shift; $self->{json}; }
  0            
82              
83             sub request {
84 0     0 0   my $self = shift;
85 0           my $method = shift;
86 0           my $path = shift;
87 0           my $object = shift;
88              
89 0           my $client = REST::Client->new();
90 0           $client->getUseragent()->ssl_opts(verify_hostname => 0);
91              
92 0           my $timestamp = time();
93 0           my $secret_hash = md5_hex($self->secret.":".$timestamp);
94              
95 0           my $body;
96 0 0         if($method eq 'GET') {
97 0           $path = $path.$client->buildQuery($object);
98             }
99             else {
100 0           $body = $self->json->encode($object);
101             }
102 0           my $cloud_meta = encode_base64($self->json->encode($self->cloud_metadata));
103 0           $cloud_meta =~ s/\s+//ism;
104 0           my $headers = {
105             Accept => 'application/json',
106             'Content-type' => 'application/json',
107             Authorization => 'Basic ' . encode_base64($self->api_key . ':' . "$secret_hash:$timestamp"),
108             HTTP_CLOUD_META => $cloud_meta
109             };
110              
111 0           $client->setHost($self->endpoint_url);
112 0           $client->request($method, $path, $body, $headers);
113              
114 0           my $response;
115 0 0         if($client->responseCode eq '200') {
116 0           $response = $self->json->decode($client->responseContent());
117             }
118 0           return $response, $client;
119             }
120              
121             sub cloud_metadata {
122 0     0 0   my $self = shift;
123 0 0         return if $self->{no_cloud};
124 0   0       $self->{cloud_metadata} ||= $self->aws_metadata;
125 0           $self->{cloud_metadata};
126             }
127              
128             sub aws_metadata {
129 0     0 0   my $self = shift;
130 0 0         return $self->{aws_metadata} if $self->{aws_metadata};
131              
132 0           my @fields = qw(
133             instance-id ami-id availability-zone
134             instance-type
135             kernel-id local-hostname
136             mac public-hostname
137             );
138              
139 0           $self->{aws_metadata} = {};
140              
141 0           my $client = REST::Client->new();
142 0           $client->setHost("http://169.254.169.254/latest/meta-data");
143 0           $client->setTimeout(1);
144              
145 0           foreach my $field (@fields) {
146 0           $client->GET($field);
147 0 0         if($client->responseCode() =~ /2\d\d/) {
  0 0          
148 0           $self->{aws_metadata}{$field} = $client->responseContent();
149 0           $self->{aws_metadata}{type} = 'aws';
150             }
151             elsif(scalar(keys %{$self->{aws_metadata}}) == 0) {
152 0           last;
153             }
154             }
155              
156 0           return $self->{aws_metadata};
157             }
158              
159              
160             package Confman::ConfSet;
161              
162             sub new {
163 0     0     my $class = shift;
164 0           my $api = shift;
165 0           my %conf = @_;
166 0   0       my $self = bless(\%conf, ref($class) || $class);
167 0           $self->{api} = $api;
168              
169             {
170 1     1   6 no strict 'refs';
  1         2  
  1         267  
  0            
171 0           foreach my $key (keys %{$self->pairs}) {
  0            
172 0           *{$class.'::'.$key} = sub {
173 0     0     my $self = shift;
174 0           $self->{pairs}{$key};
175 0 0         } unless($self->can($key));
176             }
177             }
178              
179 0           $self;
180             }
181              
182             sub update_pairs {
183 0     0     my $self = shift;
184 0           my %pairs = @_;
185 0           my ($results, $response) = $self->api->request('PUT', "confman/sets/$self->{id}/update_pairs", {
186             conf_pairs => \%pairs
187             });
188             }
189              
190             sub api {
191 0     0     my $self = shift;
192 0           return $self->{api};
193             }
194              
195             sub pairs {
196 0     0     my $self = shift;
197 0 0         unless($self->{pairs}) {
198 0           $self->{pairs} = {};
199 0           foreach my $pair (@{$self->{conf_pairs}}) {
  0            
200 0           $self->{pairs}{$pair->{name}} = $pair->{value};
201             }
202             }
203 0           return $self->{pairs};
204             }
205              
206             1;