File Coverage

lib/Rex/Cloud/Jiffybox.pm
Criterion Covered Total %
statement 23 155 14.8
branch 0 36 0.0
condition 0 6 0.0
subroutine 8 21 38.1
pod 0 10 0.0
total 31 228 13.6


line stmt bran cond sub pod time code
1             #
2             # (c) Jan Gehring
3             #
4              
5             package Rex::Cloud::Jiffybox;
6              
7 1     1   14 use v5.12.5;
  1         4  
8 1     1   9 use warnings;
  1         1  
  1         46  
9              
10             our $VERSION = '1.14.3'; # VERSION
11              
12 1     1   7 use Rex::Logger;
  1         5  
  1         25  
13              
14             BEGIN {
15 1     1   33 use Rex::Require;
  1         13  
  1         10  
16 1     1   118 LWP::UserAgent->use;
17 1         36 HTTP::Request::Common->use;
18 1         11 JSON::MaybeXS->use;
19             }
20 1     1   7 use Data::Dumper;
  1         4  
  1         40  
21              
22 1     1   6 use Rex::Cloud::Base;
  1         4  
  1         8  
23              
24 1     1   24 use base qw(Rex::Cloud::Base);
  1         2  
  1         1963  
25              
26             sub new {
27 0     0 0   my $that = shift;
28 0   0       my $proto = ref($that) || $that;
29 0           my $self = {@_};
30              
31 0           bless( $self, $proto );
32              
33 0           $self->{"__endpoint"} = "https://api.jiffybox.de/%s/v1.0/%s";
34             Rex::Logger::debug(
35 0           "Creating new Jiffybox Object, with endpoint: " . $self->{"__endpoint"} );
36              
37 0           return $self;
38             }
39              
40             sub _auth_key {
41 0     0     my ($self) = @_;
42 0           return $self->{"__auth_key"};
43             }
44              
45             sub _do_request {
46 0     0     my ( $self, $type, $action, @params ) = @_;
47              
48 0           my $url = sprintf( $self->{"__endpoint"}, $self->_auth_key, $action );
49              
50 0           Rex::Logger::debug("Requesting $url");
51              
52 0           my $ua = LWP::UserAgent->new;
53 0           $ua->env_proxy;
54 0           my ($res);
55              
56 0 0         if ( $type eq "GET" ) {
    0          
    0          
    0          
57 0           $res = $ua->request( GET $url);
58             }
59             elsif ( $type eq "POST" ) {
60 0           $res = $ua->request( POST $url, \@params );
61             }
62             elsif ( $type eq "PUT" ) {
63 0           my $req = POST $url, \@params;
64 0           $req->method("PUT");
65 0           $res = $ua->request($req);
66             }
67             elsif ( $type eq "DELETE" ) {
68 0           my $req = GET $url;
69 0           $req->method("DELETE");
70 0           $res = $ua->request($req);
71             }
72              
73 0 0         if ( $res->code >= 500 ) {
74 0           Rex::Logger::info( $res->content );
75 0           die("Error on request.");
76             }
77              
78 0           my $json = JSON::MaybeXS->new;
79 0           my $data = $json->decode( $res->decoded_content );
80              
81 0           Rex::Logger::debug( Dumper($data) );
82              
83 0 0         unless ( $data->{"result"} ) {
84             die(
85 0           "Error talking to jiffybox: " . $data->{"messages"}->[0]->{"message"} );
86             }
87              
88 0           return $data;
89             }
90              
91             sub _result_to_array {
92 0     0     my ( $self, $data, $with_key ) = @_;
93              
94 0           my @ret = ();
95              
96 0           for my $key ( keys %{ $data->{"result"} } ) {
  0            
97 0 0         if ($with_key) {
98 0           $data->{"result"}->{$key}->{$with_key} = $key;
99             }
100 0           push( @ret, $data->{"result"}->{$key} );
101             }
102              
103 0           return @ret;
104             }
105              
106             sub set_auth {
107 0     0 0   my ( $self, $key ) = @_;
108 0           $self->{"__auth_key"} = $key;
109             }
110              
111             sub list_plans {
112 0     0 0   my ($self) = @_;
113              
114 0           Rex::Logger::debug("Listing plans");
115              
116 0           my $data = $self->_do_request( "GET", "plans" );
117              
118 0           return $self->_result_to_array($data);
119             }
120              
121             sub list_operating_systems {
122 0     0 0   my ($self) = @_;
123              
124 0           Rex::Logger::debug("Listing operating systems");
125              
126 0           my $data = $self->_do_request( "GET", "distributions" );
127              
128 0           return $self->_result_to_array( $data, "os_id" );
129             }
130              
131             sub run_instance {
132 0     0 0   my ( $self, %data ) = @_;
133              
134 0           my @jiffy_data;
135              
136 0           Rex::Logger::debug("Trying to start a new instance with data:");
137             Rex::Logger::debug( " $_ -> " . ( $data{$_} ? $data{$_} : "undef" ) )
138 0 0         for keys %data;
139              
140             push(
141             @jiffy_data,
142             "name" => $data{"name"},
143             "planid" => $data{"plan_id"},
144 0           "distribution" => $data{"image_id"}
145             );
146              
147 0 0         if ( exists $data{"password"} ) {
148 0           push( @jiffy_data, "password" => $data{"password"} );
149             }
150              
151 0 0         if ( exists $data{"key"} ) {
152 0           push( @jiffy_data, "use_sshkey" => $data{"key"} );
153             }
154              
155 0 0         if ( exists $data{"metadata"} ) {
156 0           push( @jiffy_data, "metadata" => $data{"metadata"} );
157             }
158              
159 0           my $data;
160 0 0         if ( exists $data{"clone_id"} ) {
161             $data =
162 0           $self->_do_request( "POST", "jiffyBoxes/" . $data{"clone_id"},
163             @jiffy_data );
164             }
165             else {
166 0           $data = $self->_do_request( "POST", "jiffyBoxes", @jiffy_data );
167             }
168              
169 0           my $instance_id = $data->{"result"}->{"id"};
170              
171 0           my $sleep_countdown = 10;
172 0           sleep $sleep_countdown; # wait 10 seconds
173              
174 0           ($data) = grep { $_->{"id"} eq $instance_id } $self->list_instances();
  0            
175 0   0       while ( $data->{"state"} ne "STOPPED" && $data->{"state"} ne "RUNNING" ) {
176 0           Rex::Logger::debug("Waiting for instance to be created...");
177 0           ($data) = grep { $_->{"id"} eq $instance_id } $self->list_instances();
  0            
178              
179 0           sleep $sleep_countdown;
180              
181 0           --$sleep_countdown;
182              
183 0 0         if ( $sleep_countdown <= 3 ) {
184 0           $sleep_countdown = 7;
185             }
186             }
187              
188 0           $self->start_instance( instance_id => $instance_id );
189              
190 0           ($data) = grep { $_->{"id"} eq $instance_id } $self->list_instances();
  0            
191 0           while ( $data->{"state"} ne "RUNNING" ) {
192 0           Rex::Logger::debug("Waiting for instance to be started...");
193 0           ($data) = grep { $_->{"id"} eq $instance_id } $self->list_instances();
  0            
194              
195 0           sleep $sleep_countdown;
196              
197 0           --$sleep_countdown;
198              
199 0 0         if ( $sleep_countdown <= 3 ) {
200 0           $sleep_countdown = 7;
201             }
202             }
203              
204 0           return $data;
205              
206             }
207              
208             sub start_instance {
209 0     0 0   my ( $self, %data ) = @_;
210              
211 0           my $instance_id = $data{"instance_id"};
212 0           Rex::Logger::debug("Starting instance $instance_id");
213 0           $self->_do_request( "PUT", "jiffyBoxes/$instance_id", status => "START" );
214              
215             }
216              
217             sub terminate_instance {
218 0     0 0   my ( $self, %data ) = @_;
219              
220 0           my $instance_id = $data{"instance_id"};
221 0           Rex::Logger::debug("Terminating instance $instance_id");
222 0           $self->stop_instance(%data);
223 0           $self->_do_request( "DELETE", "jiffyBoxes/$instance_id" );
224              
225             }
226              
227             sub stop_instance {
228 0     0 0   my ( $self, %data ) = @_;
229              
230 0           my $instance_id = $data{"instance_id"};
231 0           Rex::Logger::debug("Stopping instance $instance_id");
232 0           $self->_do_request( "PUT", "jiffyBoxes/$instance_id", status => "SHUTDOWN" );
233              
234 0           my $sleep_countdown = 10;
235 0           sleep $sleep_countdown; # wait 10 seconds
236              
237 0           my ($data) = grep { $_->{"id"} eq $instance_id } $self->list_instances();
  0            
238              
239 0           while ( $data->{"state"} ne "STOPPED" ) {
240 0           Rex::Logger::debug("Waiting for instance to be stopped...");
241 0           ($data) = grep { $_->{"id"} eq $instance_id } $self->list_instances();
  0            
242              
243 0           sleep $sleep_countdown;
244              
245 0           --$sleep_countdown;
246              
247 0 0         if ( $sleep_countdown <= 3 ) {
248 0           $sleep_countdown = 7;
249             }
250             }
251              
252 0           return 1;
253             }
254              
255             sub list_instances {
256 0     0 0   my ($self) = @_;
257              
258 0           my @ret;
259 0           my $data = $self->_do_request( "GET", "jiffyBoxes" );
260              
261 0           for my $instance_id ( keys %{ $data->{"result"} } ) {
  0            
262 0           my $state = $data->{"result"}->{$instance_id}->{"status"};
263              
264 0 0         if ( $state eq "READY" ) {
265 0 0         if ( $data->{"result"}->{$instance_id}->{"running"} ) {
266 0           $state = "RUNNING";
267             }
268             else {
269 0           $state = "STOPPED";
270             }
271             }
272              
273             push(
274             @ret,
275             {
276             ip => $data->{"result"}->{$instance_id}->{"ips"}->{"public"}->[0],
277             id => $instance_id,
278             architecture => undef,
279             type => $data->{"result"}->{$instance_id}->{"plan"}->{"name"},
280             dns_name => "j$instance_id.servers.jiffybox.net",
281             state => $state,
282             __state => $data->{"result"}->{$instance_id}->{"status"},
283             launch_time => undef,
284 0           name => $data->{"result"}->{$instance_id}->{"name"},
285             }
286             );
287             }
288              
289 0           return @ret;
290             }
291              
292             sub list_running_instances {
293 0     0 0   my ($self) = @_;
294              
295             return
296 0 0         grep { $_->{"__state"} eq "READY" || $_->{"__state"} eq "UPDATING" }
  0            
297             $self->list_instances();
298             }
299              
300             1;