File Coverage

lib/Rex/Box/Amazon.pm
Criterion Covered Total %
statement 30 91 32.9
branch 0 10 0.0
condition 0 16 0.0
subroutine 11 25 44.0
pod 14 14 100.0
total 55 156 35.2


line stmt bran cond sub pod time code
1             #
2             # (c) Jan Gehring
3             #
4              
5             =head1 NAME
6              
7             Rex::Box::Amazon - Rex/Boxes Amazon Module
8              
9             =head1 DESCRIPTION
10              
11             This is a Rex/Boxes module to use Amazon EC2.
12              
13             =head1 EXAMPLES
14              
15             To use this module inside your Rexfile you can use the following commands.
16              
17             use Rex::Commands::Box;
18             set box => "Amazon", {
19             access_key => "your-access-key",
20             private_access_key => "your-private-access-key",
21             region => "ec2.eu-west-1.amazonaws.com",
22             zone => "eu-west-1a",
23             authkey => "default",
24             };
25              
26             task "prepare_box", sub {
27             box {
28             my ($box) = @_;
29              
30             $box->name("mybox");
31             $box->ami("ami-c1aaabb5");
32             $box->type("m1.large");
33              
34             $box->security_group("default");
35              
36             $box->auth(
37             user => "root",
38             password => "box",
39             );
40              
41             $box->setup("setup_task");
42             };
43             };
44              
45             If you want to use a YAML file you can use the following template.
46              
47             type: Amazon
48             amazon:
49             access_key: your-access-key
50             private_access_key: your-private-access-key
51             region: ec2.eu-west-1.amazonaws.com
52             zone: eu-west-1a
53             auth_key: default
54             vms:
55             vmone:
56             ami: ami-c1aaabb5
57             type: m1.large
58             security_group: default
59             setup: setup_task
60              
61             And then you can use it the following way in your Rexfile.
62              
63             use Rex::Commands::Box init_file => "file.yml";
64              
65             task "prepare_vms", sub {
66             boxes "init";
67             };
68              
69              
70             =head1 METHODS
71              
72             See also the Methods of Rex::Box::Base. This module inherits all methods of it.
73              
74             =cut
75              
76             package Rex::Box::Amazon;
77              
78 1     1   15 use v5.12.5;
  1         3  
79 1     1   16 use warnings;
  1         2  
  1         33  
80 1     1   11 use Data::Dumper;
  1         15  
  1         73  
81 1     1   8 use Rex::Box::Base;
  1         2  
  1         28  
82 1     1   35 use Rex::Commands -no => [qw/auth/];
  1         15  
  1         20  
83 1     1   9 use Rex::Commands::Fs;
  1         8  
  1         6  
84 1     1   10 use Rex::Commands::Cloud;
  1         3  
  1         7  
85              
86             our $VERSION = '1.14.3'; # VERSION
87              
88             BEGIN {
89 1     1   15 LWP::UserAgent->use;
90             }
91              
92 1     1   19 use Time::HiRes qw(tv_interval gettimeofday);
  1         4  
  1         11  
93 1     1   206 use File::Basename qw(basename);
  1         3  
  1         70  
94              
95 1     1   7 use base qw(Rex::Box::Base);
  1         2  
  1         1114  
96              
97             $|++;
98              
99             ################################################################################
100             # BEGIN of class methods
101             ################################################################################
102              
103             =head2 new(name => $vmname)
104              
105             Constructor if used in OO mode.
106              
107             my $box = Rex::Box::VBox->new(name => "vmname");
108              
109             =cut
110              
111             sub new {
112 0     0 1   my $class = shift;
113 0   0       my $proto = ref($class) || $class;
114 0           my $self = $proto->SUPER::new(@_);
115              
116 0   0       bless( $self, ref($class) || $class );
117              
118 0           cloud_service "Amazon";
119             cloud_auth $self->{options}->{access_key},
120 0           $self->{options}->{private_access_key};
121 0           cloud_region $self->{options}->{region};
122              
123 0           return $self;
124             }
125              
126             sub import_vm {
127 0     0 1   my ($self) = @_;
128              
129             # check if machine already exists
130              
131             # Rex::Logger::debug("VM already exists. Don't import anything.");
132             #my @vms = cloud_instance_list;
133 0           my @vms = $self->list_boxes;
134              
135 0           my $vminfo;
136 0           my $vm_exists = 0;
137 0           for my $vm (@vms) {
138 0 0 0       if ( $vm->{name} && $vm->{name} eq $self->{name} ) {
139 0           Rex::Logger::debug("VM already exists. Don't import anything.");
140 0           $vm_exists = 1;
141 0           $vminfo = $vm;
142             }
143             }
144              
145 0 0         if ( !$vm_exists ) {
146              
147             # if not, create it
148 0           Rex::Logger::info("Creating Amazon instance $self->{name}.");
149             $vminfo = cloud_instance create => {
150             image_id => $self->{ami},
151             name => $self->{name},
152             key => $self->{options}->{auth_key},
153             zone => $self->{options}->{zone},
154             type => $self->{type} || "m1.large",
155 0   0       security_group => $self->{security_group} || "default",
      0        
156             options => $self->options,
157             };
158             }
159              
160             # start if stopped
161 0 0         if ( $vminfo->{state} eq "stopped" ) {
162 0           cloud_instance start => $vminfo->{id};
163             }
164              
165 0           $self->{info} = $vminfo;
166             }
167              
168             =head2 ami($ami_id)
169              
170             Set the AMI ID for the box.
171              
172             =cut
173              
174             sub ami {
175 0     0 1   my ( $self, $ami ) = @_;
176 0           $self->{ami} = $ami;
177             }
178              
179             =head2 type($type)
180              
181             Set the type of the Instance. For example "m1.large".
182              
183             =cut
184              
185             sub type {
186 0     0 1   my ( $self, $type ) = @_;
187 0           $self->{type} = $type;
188             }
189              
190             =head2 security_group($sec_group)
191              
192             Set the Amazon security group for this Instance.
193              
194             =cut
195              
196             sub security_group {
197 0     0 1   my ( $self, $sec_group ) = @_;
198 0           $self->{security_group} = $sec_group;
199             }
200              
201             =head2 forward_port(%option)
202              
203             Not available for Amazon Boxes.
204              
205             =cut
206              
207 0     0 1   sub forward_port { Rex::Logger::debug("Not available for Amazon Boxes."); }
208              
209             =head2 share_folder(%option)
210              
211             Not available for Amazon Boxes.
212              
213             =cut
214              
215 0     0 1   sub share_folder { Rex::Logger::debug("Not available for Amazon Boxes."); }
216              
217             sub list_boxes {
218 0     0 1   my ($self) = @_;
219              
220 0           my @vms = cloud_instance_list;
221             my @ret = grep {
222 0           $_->{name}
223             && $_->{state} ne "terminated"
224 0 0 0       && $_->{state} ne "shutting-down"
225             } @vms; # only vms with names...
226              
227 0           return @ret;
228             }
229              
230             sub status {
231 0     0 1   my ($self) = @_;
232              
233 0           $self->info;
234              
235 0 0         if ( $self->{info}->{state} eq "running" ) {
236 0           return "running";
237             }
238             else {
239 0           return "stopped";
240             }
241             }
242              
243             sub start {
244 0     0 1   my ($self) = @_;
245              
246 0           $self->info;
247              
248 0           Rex::Logger::info( "Starting instance: " . $self->{name} );
249              
250 0           cloud_instance start => $self->{info}->{id};
251             }
252              
253             sub stop {
254 0     0 1   my ($self) = @_;
255              
256 0           Rex::Logger::info( "Stopping instance: " . $self->{name} );
257              
258 0           $self->info;
259              
260 0           cloud_instance stop => $self->{info}->{id};
261             }
262              
263             sub destroy {
264 0     0 1   my ($self) = @_;
265              
266 0           Rex::Logger::info( "Destroying instance: " . $self->{name} );
267              
268 0           $self->info;
269              
270 0           cloud_instance terminate => $self->{info}->{id};
271             }
272              
273             =head2 info
274              
275             Returns a hashRef of vm information.
276              
277             =cut
278              
279             sub info {
280 0     0 1   my ($self) = @_;
281 0           ( $self->{info} ) = grep { $_->{name} eq $self->{name} } $self->list_boxes;
  0            
282 0           return $self->{info};
283             }
284              
285             sub ip {
286 0     0 1   my ($self) = @_;
287              
288             # get instance info
289 0           ( $self->{info} ) = grep { $_->{name} eq $self->{name} } $self->list_boxes;
  0            
290              
291 0           return $self->{info}->{ip};
292             }
293              
294             1;