File Coverage

lib/Rex/Commands/Cloud.pm
Criterion Covered Total %
statement 23 82 28.0
branch 0 30 0.0
condition 0 2 0.0
subroutine 8 26 30.7
pod 18 18 100.0
total 49 158 31.0


line stmt bran cond sub pod time code
1             #
2             # (c) Jan Gehring
3             #
4              
5             =head1 NAME
6              
7             Rex::Commands::Cloud - Cloud Management Commands
8              
9             =head1 DESCRIPTION
10              
11             With this Module you can manage different Cloud services. Currently it supports Amazon EC2, Jiffybox and OpenStack.
12              
13             Version <= 1.0: All these functions will not be reported.
14              
15             =head1 SYNOPSIS
16              
17             use Rex::Commands::Cloud;
18              
19             cloud_service "Amazon";
20             cloud_auth "your-access-key", "your-private-access-key";
21             cloud_region "ec2.eu-west-1.amazonaws.com";
22              
23             task "list", sub {
24             print Dumper cloud_instance_list;
25             print Dumper cloud_volume_list;
26             };
27              
28             task "create", sub {
29             my $vol_id = cloud_volume create => { size => 1, zone => "eu-west-1a", };
30              
31             cloud_instance create => {
32             image_id => "ami-xxxxxxx",
33             name => "test01",
34             key => "my-key",
35             volume => $vol_id,
36             zone => "eu-west-1a",
37             };
38             };
39              
40             task "destroy", sub {
41             cloud_volume detach => "vol-xxxxxxx";
42             cloud_volume delete => "vol-xxxxxxx";
43              
44             cloud_instance terminate => "i-xxxxxxx";
45             };
46              
47             =head1 EXPORTED FUNCTIONS
48              
49             =cut
50              
51             package Rex::Commands::Cloud;
52              
53 1     1   14 use v5.12.5;
  1         4  
54 1     1   5 use warnings;
  1         2  
  1         111  
55              
56             our $VERSION = '1.14.3'; # VERSION
57              
58             require Rex::Exporter;
59 1     1   7 use base qw(Rex::Exporter);
  1         2  
  1         132  
60 1     1   8 use vars qw(@EXPORT $cloud_service $cloud_region @cloud_auth);
  1         3  
  1         71  
61              
62 1     1   6 use Rex::Logger;
  1         8  
  1         11  
63 1     1   25 use Rex::Config;
  1         2  
  1         8  
64 1     1   6 use Rex::Cloud;
  1         5  
  1         77  
65 1     1   9 use Rex::Group::Entry::Server;
  1         3  
  1         16  
66              
67             @EXPORT = qw(cloud_instance cloud_volume cloud_network
68             cloud_instance_list cloud_volume_list cloud_network_list
69             cloud_service cloud_auth cloud_region
70             get_cloud_instances_as_group get_cloud_regions get_cloud_availability_zones
71             get_cloud_plans
72             get_cloud_operating_systems
73             cloud_image_list
74             cloud_object
75             get_cloud_floating_ip
76             cloud_upload_key);
77              
78             Rex::Config->register_set_handler(
79             "cloud" => sub {
80             my ( $name, @options ) = @_;
81             my $sub_name = "cloud_$name";
82              
83             if ( $name eq "service" ) {
84             cloud_service(@options);
85             }
86              
87             if ( $name eq "auth" ) {
88             cloud_auth(@options);
89             }
90              
91             if ( $name eq "region" ) {
92             cloud_region(@options);
93             }
94             }
95             );
96              
97             =head2 cloud_service($cloud_service)
98              
99             Define which cloud service to use.
100              
101             =over 4
102              
103             =item Services
104              
105             =over 4
106              
107             =item Amazon
108              
109             =item Jiffybox
110              
111             =item OpenStack
112              
113             =back
114              
115             =back
116              
117              
118             =cut
119              
120             sub cloud_service {
121 0     0 1   ($cloud_service) = @_;
122              
123             # set retry counter to a higher value
124 0 0         if ( Rex::Config->get_max_connect_fails() < 5 ) {
125 0           Rex::Config->set_max_connect_fails(15);
126             }
127             }
128              
129             =head2 cloud_auth($param1, $param2, ...)
130              
131             Set the authentication for the cloudservice.
132              
133             For example for Amazon it is:
134              
135             cloud_auth($access_key, $secret_access_key);
136              
137             For JiffyBox:
138              
139             cloud_auth($auth_key);
140              
141             For OpenStack:
142              
143             cloud_auth(
144             tenant_name => 'tenant',
145             username => 'user',
146             password => 'password',
147             );
148              
149             =cut
150              
151             sub cloud_auth {
152 0     0 1   @cloud_auth = @_;
153             }
154              
155             =head2 cloud_region($region)
156              
157             Set the cloud region.
158              
159             =cut
160              
161             sub cloud_region {
162 0     0 1   ($cloud_region) = @_;
163             }
164              
165             =head2 cloud_instance_list
166              
167             Get all instances of a cloud service.
168              
169             task "list", sub {
170             for my $instance (cloud_instance_list()) {
171             say "Arch : " . $instance->{"architecture"};
172             say "IP : " . $instance->{"ip"};
173             say "ID : " . $instance->{"id"};
174             say "State : " . $instance->{"state"};
175             }
176             };
177              
178             There are some parameters for this function that can change the gathering of ip addresses for some cloud providers (like OpenStack).
179              
180             task "list", sub {
181             my @instances = cloud_instance_list
182             private_network => 'private',
183             public_network => 'public',
184             public_ip_type => 'floating',
185             private_ip_type => 'fixed';
186             };
187              
188             =cut
189              
190             sub cloud_instance_list {
191 0     0 1   return cloud_object()->list_instances(@_);
192             }
193              
194             =head2 cloud_volume_list
195              
196             Get all volumes of a cloud service.
197              
198             task "list-volumes", sub {
199             for my $volume (cloud_volume_list()) {
200             say "ID : " . $volume->{"id"};
201             say "Zone : " . $volume->{"zone"};
202             say "State : " . $volume->{"state"};
203             say "Attached : " . $volume->{"attached_to"};
204             }
205             };
206              
207             =cut
208              
209             sub cloud_volume_list {
210 0     0 1   return cloud_object()->list_volumes();
211             }
212              
213             =head2 cloud_network_list
214              
215             Get all networks of a cloud service.
216              
217             task "network-list", sub {
218             for my $network (cloud_network_list()) {
219             say "network : " . $network->{network};
220             say "name : " . $network->{name};
221             say "id : " . $network->{id};
222             }
223             };
224              
225             =cut
226              
227             sub cloud_network_list {
228 0     0 1   return cloud_object()->list_networks();
229             }
230              
231             =head2 cloud_image_list
232              
233             Get a list of all available cloud images.
234              
235             =cut
236              
237             sub cloud_image_list {
238 0     0 1   return cloud_object()->list_images();
239             }
240              
241             =head2 cloud_upload_key
242              
243             Upload public SSH key to cloud provider
244              
245             private_key '~/.ssh/mykey
246             public_key '~/.ssh/mykey.pub';
247              
248             task "cloudprovider", sub {
249             cloud_upload_key;
250              
251             cloud_instance create => {
252             ...
253             };
254             };
255              
256             =cut
257              
258             sub cloud_upload_key {
259 0     0 1   return cloud_object()->upload_key();
260             }
261              
262             =head2 get_cloud_instances_as_group
263              
264             Get a list of all running instances of a cloud service. This can be used for a I definition.
265              
266             group fe => "fe01", "fe02", "fe03";
267             group ec2 => get_cloud_instances_as_group();
268              
269             =cut
270              
271             sub get_cloud_instances_as_group {
272              
273 0     0 1   my @list = cloud_object()->list_running_instances();
274              
275 0           my @ret;
276              
277 0           for my $instance (@list) {
278 0           push( @ret, Rex::Group::Entry::Server->new( name => $instance->{"ip"} ) );
279             }
280              
281 0           return @ret;
282             }
283              
284             =head2 cloud_instance($action, $data)
285              
286             This function controls all aspects of a cloud instance.
287              
288             =cut
289              
290             sub cloud_instance {
291              
292 0     0 1   my ( $action, $data ) = @_;
293 0           my $cloud = cloud_object();
294              
295 0 0         if ( $action eq "list" ) {
    0          
    0          
    0          
    0          
296 0           return $cloud->list_running_instances();
297             }
298              
299             =head2 create
300              
301             Create a new instance.
302              
303             cloud_instance create => {
304             image_id => "ami-xxxxxx",
305             key => "ssh-key",
306             name => "fe-ec2-01", # name is not necessary
307             volume => "vol-yyyyy", # volume is not necessary
308             zone => "eu-west-1a", # zone is not necessary
309             floating_ip => "89.39.38.160" # floating_ip is not necessary
310             };
311              
312             =cut
313              
314             elsif ( $action eq "create" ) {
315             my %data_hash = (
316              
317             # image_id => $data->{"image_id"},
318             # name => $data->{"name"} || undef,
319             # key => $data->{"key"} || undef,
320             # zone => $data->{"zone"} || undef,
321             # volume => $data->{"volume"} || undef,
322             # password => $data->{"password"} || undef,
323             # plan_id => $data->{"plan_id"} || undef,
324             # type => $data->{"type"} || undef,
325             # security_group => $data->{"security_group"} || undef,
326 0           %{$data},
  0            
327             );
328              
329 0           $cloud->run_instance(%data_hash);
330             }
331              
332             =head2 start
333              
334             Start an existing instance
335              
336             cloud_instance start => "instance-id";
337              
338             =cut
339              
340             elsif ( $action eq "start" ) {
341 0           $cloud->start_instance( instance_id => $data );
342             }
343              
344             =head2 stop
345              
346             Stop an existing instance
347              
348             cloud_instance stop => "instance-id";
349              
350             =cut
351              
352             elsif ( $action eq "stop" ) {
353 0           $cloud->stop_instance( instance_id => $data );
354             }
355              
356             =head2 terminate
357              
358             Terminate an instance. This will destroy all data and remove the instance.
359              
360             cloud_instance terminate => "i-zzzzzzz";
361              
362             =cut
363              
364             elsif ( $action eq "terminate" ) {
365 0           $cloud->terminate_instance( instance_id => $data );
366             }
367              
368             }
369              
370             =head2 get_cloud_regions
371              
372             Returns all regions as an array.
373              
374             =cut
375              
376             sub get_cloud_regions {
377 0     0 1   return cloud_object()->get_regions;
378             }
379              
380             =head2 cloud_volume($action , $data)
381              
382             This function controlls all aspects of a cloud volume.
383              
384             =cut
385              
386             sub cloud_volume {
387              
388 0     0 1   my ( $action, @_data ) = @_;
389 0           my $data;
390 0 0         if ( @_data == 1 ) {
391 0 0         if ( ref $_data[0] ) {
392 0           $data = $_data[0];
393             }
394             else {
395 0           $data = { id => $_data[0] };
396             }
397             }
398             else {
399 0           $data = { "id", @_data };
400             }
401              
402 0           my $cloud = cloud_object();
403              
404             =head2 create
405              
406             Create a new volume. Size is in Gigabytes.
407              
408             task "create-vol", sub {
409             my $vol_id = cloud_volume create => { size => 1, zone => "eu-west-1a", };
410             };
411              
412             =cut
413              
414 0 0         if ( $action eq "create" ) {
    0          
    0          
    0          
    0          
415             $cloud->create_volume(
416             size => $data->{"size"} || 1,
417 0   0       %{$data},
  0            
418             );
419             }
420              
421             =head2 attach
422              
423             Attach a volume to an instance.
424              
425             task "attach-vol", sub {
426             cloud_volume attach => "vol-xxxxxx", to => "server-id";
427             };
428              
429             =cut
430              
431             elsif ( $action eq "attach" ) {
432 0           my $vol_id = $data->{id};
433 0           my $srv_id = $data->{to};
434              
435             $cloud->attach_volume(
436             volume_id => $vol_id,
437             server_id => $srv_id,
438             device_name => $data->{device}
439 0           );
440             }
441              
442             =head2 detach
443              
444             Detach a volume from an instance.
445              
446             task "detach-vol", sub {
447             cloud_volume detach => "vol-xxxxxx", from => "server-id";
448             };
449              
450             =cut
451              
452             elsif ( $action eq "detach" ) {
453 0           my $vol_id = $data->{id};
454 0           my $srv_id = $data->{from};
455              
456             $cloud->detach_volume(
457             volume_id => $vol_id,
458             server_id => $srv_id,
459             attach_id => $data->{attach_id}
460 0           );
461             }
462              
463             =head2 delete
464              
465             Delete a volume. This will destroy all data.
466              
467             task "delete-vol", sub {
468             cloud_volume delete => "vol-xxxxxx";
469             };
470              
471             =cut
472              
473             elsif ( $action eq "delete" ) {
474 0           $cloud->delete_volume( volume_id => $data->{id} );
475             }
476              
477             elsif ( $action eq "list" ) {
478 0           return $cloud->list_volumes();
479             }
480              
481             }
482              
483             =head2 get_cloud_floating_ip
484              
485             Returns first available floating IP
486              
487             task "get_floating_ip", sub {
488              
489             my $ip = get_cloud_floating_ip;
490              
491             my $instance = cloud_instance create => {
492             image_id => 'edffd57d-82bf-4ffe-b9e8-af22563741bf',
493             name => 'instance1',
494             plan_id => 17,
495             floating_ip => $ip
496             };
497             };
498              
499             =cut
500              
501             sub get_cloud_floating_ip {
502 0     0 1   return cloud_object()->get_floating_ip;
503             }
504              
505             =head2 cloud_network
506              
507             =cut
508              
509             sub cloud_network {
510              
511 0     0 1   my ( $action, $data ) = @_;
512 0           my $cloud = cloud_object();
513              
514             =head2 create
515              
516             Create a new network.
517              
518             task "create-net", sub {
519             my $net_id = cloud_network create => { cidr => '192.168.0.0/24', name => "mynetwork", };
520             };
521              
522             =cut
523              
524 0 0         if ( $action eq "create" ) {
    0          
525 0           $cloud->create_network( %{$data} );
  0            
526             }
527              
528             =head2 delete
529              
530             Delete a network.
531              
532             task "delete-net", sub {
533             cloud_network delete => '18a4ccf8-f14a-a10d-1af4-4ac7fee08a81';
534             };
535              
536             =cut
537              
538             elsif ( $action eq "delete" ) {
539 0           $cloud->delete_network($data);
540             }
541             }
542              
543             =head2 get_cloud_availability_zones
544              
545             Returns all availability zones of a cloud services. If available.
546              
547             task "get-zones", sub {
548             print Dumper get_cloud_availability_zones;
549             };
550              
551             =cut
552              
553             sub get_cloud_availability_zones {
554 0     0 1   return cloud_object()->get_availability_zones();
555             }
556              
557             =head2 get_cloud_plans
558              
559             Retrieve information of the available cloud plans. If supported.
560              
561             =cut
562              
563             sub get_cloud_plans {
564 0     0 1   return cloud_object()->list_plans;
565             }
566              
567             =head2 get_cloud_operating_systems
568              
569             Retrieve information of the available cloud plans. If supported.
570              
571             =cut
572              
573             sub get_cloud_operating_systems {
574 0     0 1   return cloud_object()->list_operating_systems;
575             }
576              
577             =head2 cloud_object
578              
579             Returns the cloud object itself.
580              
581             =cut
582              
583             sub cloud_object {
584 0     0 1   my $cloud = get_cloud_service($cloud_service);
585              
586 0           $cloud->set_auth(@cloud_auth);
587 0           $cloud->set_endpoint($cloud_region);
588              
589 0           return $cloud;
590             }
591              
592             1;