File Coverage

blib/lib/Mojo/Cloudstack.pm
Criterion Covered Total %
statement 58 111 52.2
branch 0 30 0.0
condition 0 5 0.0
subroutine 15 21 71.4
pod 1 1 100.0
total 74 168 44.0


line stmt bran cond sub pod time code
1             package Mojo::Cloudstack;
2              
3 1     1   351590 use Mojo::Base 'Mojo::UserAgent';
  1         2  
  1         8  
4 1     1   183 use Mojo::Parameters;
  1         2  
  1         7  
5 1     1   31 use Mojo::URL;
  1         6  
  1         7  
6 1     1   26 use Mojo::UserAgent;
  1         2  
  1         8  
7 1     1   29 use Mojo::JSON 'j';
  1         2  
  1         48  
8 1     1   5 use Mojo::Util 'slurp';
  1         1  
  1         38  
9 1     1   5 use Mojo::Collection 'c';
  1         1  
  1         53  
10 1     1   495 use Mojo::Cloudstack::Base;
  1         2  
  1         8  
11 1     1   490 use Mojo::Cloudstack::Api;
  1         2  
  1         7  
12 1     1   707 use Digest::HMAC_SHA1 qw(hmac_sha1 hmac_sha1_hex);
  1         1572  
  1         66  
13 1     1   9 use MIME::Base64;
  1         2  
  1         50  
14 1     1   934 use URI::Encode 'uri_encode';
  1         1265  
  1         52  
15 1     1   722 use File::HomeDir;
  1         102855  
  1         128  
16 1     1   13 use Data::Dumper 'Dumper';
  1         3  
  1         2683  
17              
18             has 'host' => "localhost";
19             has 'path' => "/client/api";
20             has 'port' => "8080";
21             has 'scheme' => "https";
22             has 'api_key' => "";
23             has 'secret_key' => "";
24             has 'responsetypes' => '';
25             has 'api_cache' => sub {
26             my $self = shift;
27             $self->_load_api_cache;
28             $self->__build_responsetypes;
29             };
30              
31             our $VERSION = '0.06';
32             our $AUTOLOAD;
33              
34             chomp(our $user = `whoami`);
35             our $cf = File::HomeDir->users_home($user) . "/.cloudmojo/api.json";
36              
37             sub _build_request {
38 1     1   875 my ($self, $params) = @_;
39 1         5 my $baseurl = sprintf ("%s://%s:%s%s?", $self->scheme, $self->host, $self->port, $self->path);
40 1         22 $params->{ apiKey } = $self->api_key;
41 1         7 $params->{ response } = 'json';
42 1         4 my $secret_key = $self->secret_key;
43              
44 1         6 my $req_params = Mojo::Parameters->new();
45 1         14 foreach my $p (sort keys %$params) {
46 3         2448 $req_params->param($p => uri_encode($params->{ $p }));
47             }
48 1         1033 my $params_str = lc ($req_params->to_string);
49 1         153 my $digest = hmac_sha1($params_str, $secret_key);
50 1         55 my $base64_encoded = encode_base64($digest);
51 1         2 chomp ($base64_encoded);
52              
53 1         3 my $uri_encoded = uri_encode($base64_encoded,1);
54 1         1061 my $url = Mojo::URL->new($baseurl);
55 1         281 $url->query($req_params->to_string);
56              
57 1         132 return $url->to_string . '&signature='.$uri_encoded;
58              
59             }
60              
61             sub AUTOLOAD {
62 0     0     my $self = shift;
63 0           (my $command = $AUTOLOAD) =~ s/.*:://;
64 0           my %params = @_;
65 0           $params{command} = $command;
66 0           my $req = $self->_build_request(\%params);
67 0           my $res = $self->post($req)->res;
68 0           my $items = $res->json;
69             #warn Dumper 'ITEMS', $items;
70 0 0         die sprintf("Could not get response for %s %s %s", $req, $res->code, $res->message) unless $items;
71 0           my $responsetype = (keys %$items)[0];
72              
73 0 0         if($responsetype =~ /^(login|activate|add|archive|assign|associate|attach|authorize|change|configure|copy|create|delete|deploy|destroy|detach|disable|disassociate|enable|error|expunge|extract|get|list|lock|migrate|query|reboot|recover|register|remove|replace|reset|resize|restart|restore|revert|revoke|scale|start|stop|suspend|update|upload)(.*)(response)$/){
74 0           my ($otype, $oname, $oresponse) = ($1, $2, $3);
75 0 0         $items->{$responsetype}{_cs} = $self unless $oname eq 'apis';
76 0 0         if($oname eq 'apis'){
    0          
    0          
    0          
    0          
77 0           $self->__write_api_cache($items);
78 0           return $items;
79             } elsif($otype eq 'list'){
80 0 0         if($oname =~ /(s)$/){
81 0           $oname =~ s/$1$//;
82             }
83             return c(
84             map {
85 0           $_->{_cs} = $self;
86 0           Mojo::Cloudstack::Base->new('Mojo::Cloudstack::' . ucfirst($oname),$_);
87 0           } @{$items->{$responsetype}{$oname}}
  0            
88             );
89             } elsif($otype eq 'query'){
90 0           return Mojo::Cloudstack::Base->new('Mojo::Cloudstack::AsyncJobResult', $items->{$responsetype});
91             } elsif(exists $items->{$responsetype}{errorcode}){
92 0           return Mojo::Cloudstack::Base->new('Mojo::Cloudstack::Error', $items->{$responsetype});
93             } elsif($otype =~ /^log(in|out)$/){
94 0           return Mojo::Cloudstack::Base->new('Mojo::Cloudstack::' . ucfirst($&), $items->{$responsetype});
95             } else {
96             return Mojo::Cloudstack::Base->new('Mojo::Cloudstack::' . (exists $items->{$responsetype}{jobid}
97             ? 'AsyncJobRequest'
98 0 0         : ucfirst($oname)), $items->{$responsetype});
99             }
100             } else {
101 0           die "unknown response type $responsetype for reqest \n$req";
102             }
103              
104             }
105              
106             sub sync {
107 0     0 1   return shift->_load_api_cache(1);
108             }
109              
110             sub _load_api_cache {
111 0     0     my ($self, $force) = @_;
112 0 0 0       $self->api_cache($self->__build_api_json($force))
      0        
113             and return $self->api_cache
114             if ($force or (not -f $cf));
115             #TODO File::ShareDir
116              
117 0 0         $self->api_cache(j(slurp $cf)) if -f $cf;
118 0           return $self->api_cache;
119             }
120              
121             sub __build_responsetypes {
122 0     0     my ($self) = @_;
123 0           my $apis = $self->api_cache;
124 0           my %responsetypes = map { (split(/[A-Z]/,$_->{name},2))[0] => 1 }
125 0           @{ $apis->{listapisresponse}{api} };
  0            
126 0           $responsetypes{error} = 1;
127 0           $self->responsetypes(join('|', sort keys %responsetypes));
128 0           die $self->responsetypes;
129             }
130              
131             sub __build_api_json {
132 0     0     my ($self, $force) = @_;
133 0           my $apis = $self->listApis;
134 0           $self->__write_api_cache($apis, $force);
135 0           return $apis;
136             }
137              
138             sub __write_api_cache {
139 0     0     my($self, $apis, $force) = @_;
140 0           my $cachedir = File::HomeDir->users_home($user) . "/.cloudmojo";
141 0 0         mkdir $cachedir unless -d $cachedir;
142 0           my $cachefile = "$cachedir/api.json";
143 0 0         unlink $cachefile if $force;
144 0 0         unless (-f $cachefile){
145 0           open my $cf, ">$cachefile";
146 0           print $cf j($apis);
147 0           close $cf;
148             }
149 0           return $apis;
150              
151             }
152              
153             1;
154              
155             __END__