File Coverage

blib/lib/Net/OpenStack/Client/API/Magic.pm
Criterion Covered Total %
statement 103 116 88.7
branch 30 42 71.4
condition 6 8 75.0
subroutine 16 16 100.0
pod 3 3 100.0
total 158 185 85.4


line stmt bran cond sub pod time code
1             package Net::OpenStack::Client::API::Magic;
2             $Net::OpenStack::Client::API::Magic::VERSION = '0.1.4';
3 10     10   71132 use strict;
  10         33  
  10         270  
4 10     10   62 use warnings;
  10         27  
  10         252  
5              
6 10     10   4239 use Module::Load;
  10         9839  
  10         53  
7 10     10   862 use Net::OpenStack::Client::Request qw(@SUPPORTED_METHODS @METHODS_REQUIRE_OPTIONS);
  10         20  
  10         1156  
8              
9 10     10   63 use Readonly;
  10         19  
  10         317  
10 10     10   3262 use version;
  10         14717  
  10         50  
11              
12 10     10   694 use base qw(Exporter);
  10         19  
  10         4157  
13              
14             our @EXPORT_OK = qw(retrieve version);
15              
16             # hashref to store cached command data
17             my $cache;
18             # Init the cache
19             $cache = flush_cache();
20              
21             =head2 Public functions
22              
23             =over
24              
25             =item flush_cache
26              
27             Reset the cache
28              
29             =cut
30              
31             sub flush_cache
32             {
33 11     11 1 1598 $cache = {cmd => {}, api => {}};
34 11         26 return $cache;
35             }
36              
37             =item cache
38              
39             Given C command hashref,
40             cache and return the relevant (filtered) command data.
41              
42             If C is defined, store the data as
43             the service C.
44              
45             =cut
46              
47             sub cache
48             {
49 40     40 1 155 my ($data, $api_service) = @_;
50              
51 40 100       85 if ($api_service) {
52 9         26 $cache->{api}->{$api_service} = $data;
53             } else {
54 31         53 my $service = $data->{service};
55 31         56 my $name = $data->{name};
56              
57 31         74 $cache->{cmd}->{$service}->{$name} = $data;
58             }
59              
60 40         136 return $data;
61             }
62              
63             =item retrieve
64              
65             Retrieve the command data for service C, name C
66             and version C.
67              
68             Returns the tuple with cache command hashref and undef errormessage on SUCCESS,
69             an emptyhashref and actual errormessage otherwise.
70             If the command is already in cache, returns the cached version
71             (and undef errormessage).
72              
73             =cut
74              
75             sub retrieve
76             {
77 105     105 1 8043 my ($service, $name, $version) = @_;
78              
79             # Return already cached data
80 105 100 100     506 return ($cache->{cmd}->{$service}->{$name}, undef) if defined(($cache->{cmd}->{$service} || {})->{$name});
81              
82 33         105 my $err_prefix = "retrieve name $name for service $service";
83              
84 33 50       246 if ($version) {
85 33 100       98 if (ref($version) ne 'version') {
86 13 50       55 $version = "v$version" if $version !~ m/^v/;
87 13         112 $version = version->new($version);
88             }
89             } else {
90 0         0 return {}, "$err_prefix no version defined";
91             }
92              
93 33         219 $err_prefix .= " version $version failed:";
94              
95 33         92 my $versionpackagename = "$version";
96 33         90 $versionpackagename =~ s/[.]/DOT/g; # cannot have a . in the package name
97              
98 33         80 my $servicepackagename = ucfirst($service);
99              
100 33         75 my $apidata = $cache->{api}->{$service};
101 33         47 my $result;
102              
103 33 100       76 if (!$apidata) {
104 10         30 my $package = "Net::OpenStack::Client::API::${servicepackagename}::${versionpackagename}";
105              
106 10         55 local $@;
107 10         22 eval {
108 10         44 load $package;
109             };
110 10 100       3966 if ($@) {
111 1         9 return {}, "$err_prefix no API module $package: $@";
112             }
113              
114 9         32 my $varname = "${package}::API_DATA";
115 0         0 eval {
116 10     10   75 no strict 'refs';
  10         23  
  10         694  
117 9         16 $apidata = ${$varname};
  9         48  
118 10     10   57 use strict 'refs';
  10         19  
  10         1924  
119 9         19 };
120 9 50       88 if ($@) {
    50          
    50          
121 0         0 return {}, "$err_prefix somthing went wrong while looking for variable $varname: $@";
122             } elsif (!defined $apidata) {
123 0         0 return {}, "$err_prefix no variable $varname";
124             } elsif (ref($apidata) ne 'HASH') {
125 0         0 return {}, "$err_prefix variable $varname not a hash (got ".ref($apidata).")";
126             };
127              
128             # cache this data
129 9         35 cache($apidata, $service);
130             }
131              
132 32         61 my $data = $apidata->{$name};
133 32 100       73 if (! $data) {
134             # Try custom functions
135 14         33 my $package = "Net::OpenStack::Client::${servicepackagename}::${versionpackagename}";
136              
137 14         22 local $@;
138 14         22 eval {
139 14         39 load $package;
140             };
141              
142 14 50       1599 if ($@) {
143 0         0 my $msg = "$err_prefix no API data or client module";
144 0 0       0 if ($@ !~ m/^can.*locate.*in.*INC/i) {
145             # if you can't locate the module, it's probably ok no to mention it
146             # but anything else (eg syntax error) should be reported
147 0         0 $msg .= " (client module load failed: $@)"
148             }
149 0         0 return {}, $msg;
150             } else {
151             # Retrieve the function in the package
152 10     10   68 no strict 'refs';
  10         21  
  10         508  
153 14         21 my %symbol_table = %{"${package}::"};
  14         249  
154 10     10   57 use strict 'refs';
  10         16  
  10         525  
155              
156 14         46 my $something = $symbol_table{$name};
157 14 100       66 if (defined $something) {
158             # magic bits from Package::Stash list_all_symbols
159 13 100 66     79 if (ref \$something eq 'GLOB' &&
160             defined *$something{CODE}) {
161 10     10   65 no strict 'refs';
  10         19  
  10         526  
162 12         20 my $function = \&{"${package}::$name"};
  12         45  
163 10     10   58 use strict 'refs';
  10         19  
  10         3130  
164              
165 12         93 $result = {
166             name => $name, # human readable function/method name
167             service => $service,
168             code => $function,
169             };
170             } else {
171 1         8 return {}, "$err_prefix found in client module, but not a function";
172             }
173             } else {
174 1         8 return {}, "$err_prefix no API data or function from client module";
175             }
176             }
177             } else {
178             # data is a hashref
179             # sanity check
180 18 50       57 if (!exists($data->{endpoint})) {
181 0         0 return {}, "$err_prefix data should at least contain the endpoint";
182             }
183              
184 18 50       45 if (!exists($data->{method})) {
185 0         0 return {}, "$err_prefix data should at least contain the method";
186             }
187              
188 18         35 my $method = $data->{method};
189 18 50       66 if (!grep {$_ eq $method} @SUPPORTED_METHODS) {
  90         582  
190 0         0 return {}, "$err_prefix method $method is not supported";
191             }
192 18 50 66     70 if ((grep {$method eq $_} @METHODS_REQUIRE_OPTIONS) && !exists($data->{options})) {
  54         387  
193 0         0 return {}, "$err_prefix data should contain options for method $method";
194             }
195              
196             $result = {
197             name => $name, # human readable function/method name
198             method => $method, # HTTP method
199             service => $service,
200             endpoint => $data->{endpoint},
201 18         94 version => $version,
202             };
203              
204 18 100       71 $result->{result} = $data->{result} if defined($data->{result});
205              
206 18         49 foreach my $k (qw(templates parameters options)) {
207 54 100       143 $result->{$k} = $data->{$k} if exists($data->{$k});
208             }
209             }
210 30         81 return cache($result), undef;
211             }
212              
213              
214             =pod
215              
216             =back
217              
218             =cut
219              
220              
221             1;