File Coverage

lib/VM/EC2.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             package VM::EC2;
2              
3             =head1 NAME
4              
5             VM::EC2 - Control the Amazon EC2 and Eucalyptus Clouds
6              
7             =head1 SYNOPSIS
8              
9             # set environment variables EC2_ACCESS_KEY, EC2_SECRET_KEY and/or EC2_URL
10             # to fill in arguments automatically
11              
12             ## IMAGE AND INSTANCE MANAGEMENT
13             # get new EC2 object
14             my $ec2 = VM::EC2->new(-access_key => 'access key id',
15             -secret_key => 'aws_secret_key',
16             -endpoint => 'http://ec2.amazonaws.com');
17              
18             # fetch an image by its ID
19             my $image = $ec2->describe_images('ami-12345');
20              
21             # get some information about the image
22             my $architecture = $image->architecture;
23             my $description = $image->description;
24             my @devices = $image->blockDeviceMapping;
25             for my $d (@devices) {
26             print $d->deviceName,"\n";
27             print $d->snapshotId,"\n";
28             print $d->volumeSize,"\n";
29             }
30              
31             # run two instances
32             my @instances = $image->run_instances(-key_name =>'My_key',
33             -security_group=>'default',
34             -min_count =>2,
35             -instance_type => 't1.micro')
36             or die $ec2->error_str;
37              
38             # wait for both instances to reach "running" or other terminal state
39             $ec2->wait_for_instances(@instances);
40              
41             # print out both instance's current state and DNS name
42             for my $i (@instances) {
43             my $status = $i->current_status;
44             my $dns = $i->dnsName;
45             print "$i: [$status] $dns\n";
46             }
47              
48             # tag both instances with Role "server"
49             foreach (@instances) {$_->add_tag(Role=>'server');
50              
51             # stop both instances
52             foreach (@instances) {$_->stop}
53            
54             # find instances tagged with Role=Server that are
55             # stopped, change the user data and restart.
56             @instances = $ec2->describe_instances({'tag:Role' => 'Server',
57             'instance-state-name' => 'stopped'});
58             for my $i (@instances) {
59             $i->userData('Secure-mode: off');
60             $i->start or warn "Couldn't start $i: ",$i->error_str;
61             }
62              
63             # create an image from both instance, tag them, and make
64             # them public
65             for my $i (@instances) {
66             my $img = $i->create_image("Autoimage from $i","Test image");
67             $img->add_tags(Name => "Autoimage from $i",
68             Role => 'Server',
69             Status=> 'Production');
70             $img->make_public(1);
71             }
72              
73             ## KEY MANAGEMENT
74              
75             # retrieve the name and fingerprint of the first instance's
76             # key pair
77             my $kp = $instances[0]->keyPair;
78             print $instances[0], ": keypair $kp=",$kp->fingerprint,"\n";
79              
80             # create a new key pair
81             $kp = $ec2->create_key_pair('My Key');
82            
83             # get the private key from this key pair and write it to a disk file
84             # in ssh-compatible format
85             my $private_key = $kp->private_key;
86             open (my $f,'>MyKeypair.rsa') or die $!;
87             print $f $private_key;
88             close $f;
89              
90             # Import a preexisting SSH key
91             my $public_key = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8o...';
92             $key = $ec2->import_key_pair('NewKey',$public_key);
93              
94             ## SECURITY GROUPS AND FIREWALL RULES
95             # Create a new security group
96             my $group = $ec2->create_security_group(-name => 'NewGroup',
97             -description => 'example');
98              
99             # Add a firewall rule
100             $group->authorize_incoming(-protocol => 'tcp',
101             -port => 80,
102             -source_ip => ['192.168.2.0/24','192.168.2.1/24'});
103              
104             # Write rules back to Amazon
105             $group->update;
106              
107             # Print current firewall rules
108             print join ("\n",$group->ipPermissions),"\n";
109              
110             ## VOLUME && SNAPSHOT MANAGEMENT
111              
112             # find existing volumes that are available
113             my @volumes = $ec2->describe_volumes({status=>'available'});
114              
115             # back 'em all up to snapshots
116             foreach (@volumes) {$_->snapshot('Backup on '.localtime)}
117              
118             # find a stopped instance in first volume's availability zone and
119             # attach the volume to the instance using /dev/sdg
120             my $vol = $volumes[0];
121             my $zone = $vol->availabilityZone;
122             @instances = $ec2->describe_instances({'availability-zone'=> $zone,
123             'run-state-name' => $stopped);
124             $instances[0]->attach_volume($vol=>'/dev/sdg') if @instances;
125              
126             # create a new 20 gig volume
127             $vol = $ec2->create_volume(-availability_zone=> 'us-east-1a',
128             -size => 20);
129             $ec2->wait_for_volumes($vol);
130             print "Volume $vol is ready!\n" if $vol->current_status eq 'available';
131              
132             # create a new elastic address and associate it with an instance
133             my $address = $ec2->allocate_address();
134             $instances[0]->associate_address($address);
135              
136             =head1 DESCRIPTION
137              
138             This is an interface to the 2013-07-15 version of the Amazon AWS API
139             (http://aws.amazon.com/ec2). It was written provide access to the new
140             tag and metadata interface that is not currently supported by
141             Net::Amazon::EC2, as well as to provide developers with an extension
142             mechanism for the API. This library will also support the Eucalyptus
143             open source cloud (http://open.eucalyptus.com).
144              
145             The main interface is the VM::EC2 object, which provides methods for
146             interrogating the Amazon EC2, launching instances, and managing
147             instance lifecycle. These methods return the following major object
148             classes which act as specialized interfaces to AWS:
149              
150             VM::EC2::BlockDevice -- A block device
151             VM::EC2::BlockDevice::Attachment -- Attachment of a block device to an EC2 instance
152             VM::EC2::BlockDevice::EBS -- An elastic block device
153             VM::EC2::BlockDevice::Mapping -- Mapping of a virtual storage device to a block device
154             VM::EC2::BlockDevice::Mapping::EBS -- Mapping of a virtual storage device to an EBS block device
155             VM::EC2::Group -- Security groups
156             VM::EC2::Image -- Amazon Machine Images (AMIs)
157             VM::EC2::Instance -- Virtual machine instances
158             VM::EC2::Instance::Metadata -- Access to runtime metadata from running instances
159             VM::EC2::Region -- Availability regions
160             VM::EC2::Snapshot -- EBS snapshots
161             VM::EC2::Tag -- Metadata tags
162              
163             In addition, there is a high level interface for interacting with EC2
164             servers and volumes, including file transfer and remote shell facilities:
165              
166             VM::EC2::Staging::Manager -- Manage a set of servers and volumes.
167             VM::EC2::Staging::Server -- A staging server, with remote shell and file transfer
168             facilities.
169             VM::EC2::Staging::Volume -- A staging volume with the ability to copy itself between
170             availability zones and regions.
171              
172             and a few specialty classes:
173              
174             VM::EC2::Security::Token -- Temporary security tokens for granting EC2 access to
175             non-AWS account holders.
176             VM::EC2::Security::Credentials -- Credentials for use by temporary account holders.
177             VM::EC2::Security::Policy -- Policies that restrict what temporary account holders
178             can do with EC2 resources.
179             VM::EC2::Security::FederatedUser -- Account name information for temporary account holders.
180              
181             Lastly, there are several utility classes:
182              
183             VM::EC2::Generic -- Base class for all AWS objects
184             VM::EC2::Error -- Error messages
185             VM::EC2::Dispatch -- Maps AWS XML responses onto perl object classes
186             VM::EC2::ReservationSet -- Hidden class used for describe_instances() request;
187             The reservation Ids are copied into the Instance
188             object.
189              
190             There is also a high-level API called "VM::EC2::Staging::Manager" for
191             managing groups of staging servers and volumes which greatly
192             simplifies the task of creating and updating instances that mount
193             multiple volumes. The API also provides a one-line command for
194             migrating EBS-backed AMIs from one zone to another. See
195             L.
196              
197             The interface provided by these modules is based on that described at
198             http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/. The
199             following caveats apply:
200              
201             1) Not all of the Amazon API is currently implemented. Specifically,
202             a handful calls dealing with cluster management and VM importing
203             are missing. See L for a list of all the
204             unimplemented API calls. Volunteers to fill in these gaps are
205             most welcome!
206              
207             2) For consistency with common Perl coding practices, method calls
208             are lowercase and words in long method names are separated by
209             underscores. The Amazon API prefers mixed case. So in the Amazon
210             API the call to fetch instance information is "DescribeInstances",
211             while in VM::EC2, the method is "describe_instances". To avoid
212             annoyance, if you use the mixed case form for a method name, the
213             Perl autoloader will automatically translate it to underscores for
214             you, and vice-versa; this means you can call either
215             $ec2->describe_instances() or $ec2->DescribeInstances().
216              
217             3) Named arguments passed to methods are all lowercase, use
218             underscores to separate words and start with hyphens.
219             In other words, if the AWS API calls for an argument named
220             "InstanceId" to be passed to the "DescribeInstances" call, then
221             the corresponding Perl function will look like:
222              
223             $instance = $ec2->describe_instances(-instance_id=>'i-12345')
224              
225             In most cases automatic case translation will be performed for you
226             on arguments. So in the previous example, you could use
227             -InstanceId as well as -instance_id. The exception
228             is when an absurdly long argument name was replaced with an
229             abbreviated one as described below. In this case, you must use
230             the documented argument name.
231              
232             In a small number of cases, when the parameter name was absurdly
233             long, it has been abbreviated. For example, the
234             "Placement.AvailabilityZone" parameter has been represented as
235             -placement_zone and not -placement_availability_zone. See the
236             documentation for these cases.
237              
238             4) For each of the describe_foo() methods (where "foo" is a type of
239             resource such as "instance"), you can fetch the resource by using
240             their IDs either with the long form:
241              
242             $ec2->describe_foo(-foo_id=>['a','b','c']),
243              
244             or a shortcut form:
245              
246             $ec2->describe_foo('a','b','c');
247              
248             Both forms are listed in the headings in the documentation.
249              
250             5) When the API calls for a list of arguments named Arg.1, Arg.2,
251             then the Perl interface allows you to use an anonymous array for
252             the consecutive values. For example to call describe_instances()
253             with multiple instance IDs, use:
254              
255             @i = $ec2->describe_instances(-instance_id=>['i-12345','i-87654'])
256              
257             6) All Filter arguments are represented as a -filter argument whose value is
258             an anonymous hash:
259              
260             @i = $ec2->describe_instances(-filter=>{architecture=>'i386',
261             'tag:Name' =>'WebServer'})
262              
263             If there are no other arguments you wish to pass, you can omit the
264             -filter argument and just pass a hashref:
265              
266             @i = $ec2->describe_instances({architecture=>'i386',
267             'tag:Name' =>'WebServer'})
268              
269             For any filter, you may represent multiple OR arguments as an arrayref:
270              
271             @i = $ec2->describe-instances({'instance-state-name'=>['stopped','terminated']})
272              
273             When adding or removing tags, the -tag argument uses the same syntax.
274              
275             7) The tagnames of each XML object returned from AWS are converted into methods
276             with the same name and typography. So the tag in a
277             DescribeInstancesResponse, becomes:
278              
279             $instance->privateIpAddress
280              
281             You can also use the more Perlish form -- this is equivalent:
282              
283             $instance->private_ip_address
284              
285             Methods that correspond to complex objects in the XML hierarchy
286             return the appropriate Perl object. For example, an instance's
287             blockDeviceMapping() method returns an object of type
288             VM::EC2::BlockDevice::Mapping.
289              
290             All objects have a fields() method that will return the XML
291             tagnames listed in the AWS specifications.
292              
293             @fields = sort $instance->fields;
294             # 'amiLaunchIndex', 'architecture', 'blockDeviceMapping', ...
295              
296             8) Whenever an object has a unique ID, string overloading is used so that
297             the object interpolates the ID into the string. For example, when you
298             print a VM::EC2::Volume object, or use it in another string context,
299             then it will appear as the string "vol-123456". Nevertheless, it will
300             continue to be usable for method calls.
301              
302             ($v) = $ec2->describe_volumes();
303             print $v,"\n"; # prints as "vol-123456"
304             $zone = $v->availabilityZone; # acts like an object
305              
306             9) Many objects have convenience methods that invoke the AWS API on your
307             behalf. For example, instance objects have a current_status() method that returns
308             the run status of the object, as well as start(), stop() and terminate()
309             methods that control the instance's lifecycle.
310              
311             if ($instance->current_status eq 'running') {
312             $instance->stop;
313             }
314              
315             10) Calls to AWS that have failed for one reason or another (invalid
316             arguments, communications problems, service interruptions) will
317             return undef and set the VM::EC2->is_error() method to true. The
318             error message and its code can then be recovered by calling
319             VM::EC2->error.
320              
321             $i = $ec2->describe_instance('i-123456');
322             unless ($i) {
323             warn 'Got no instance. Message was: ',$ec2->error;
324             }
325              
326             You may also elect to raise an exception when an error occurs.
327             See the new() method for details.
328              
329             =head1 ASYNCHRONOUS CALLS
330              
331             As of version 1.24, VM::EC2 supports asynchronous calls to AWS using
332             AnyEvent::HTTP. This allows you to make multiple calls in parallel for
333             a significant improvement in performance.
334              
335             In asynchronous mode, VM::EC2 calls that ordinarily wait for AWS to
336             respond and then return objects corresponding to EC2 instances,
337             volumes, images, and so forth, will instead immediately return an
338             AnyEvent condition variable. You can retrieve the result of the call
339             by calling the condition variable's recv() method, or by setting a
340             callback to be executed when the call is complete.
341              
342             To make an asynchronous call, you can set the global variable
343             $VM::EC2::ASYNC to a true value
344              
345             Here is an example of a normal synchronous call:
346            
347             my @instances = $ec2->describe_instances();
348              
349             Here is the asynchronous version initiated after setting
350             $VM::EC2::ASYNC (using a local block to limit its effects).
351              
352             {
353             local $VM::EC2::ASYNC=1;
354             my $cv = $ec2->describe_instances(); # returns immediately
355             my @instances = $cv->recv;
356             }
357              
358             In case of an error recv() will return undef and the error object can
359             be recovered using the condition variable's error() method (this is an
360             enhancement over AnyEvent's standard condition variable class):
361              
362             my @instances = $cv->recv
363             or die "No instances found! error = ",$cv->error();
364              
365             You may attach a callback CODE reference to the condition variable using
366             its cb() method, in which case the callback will be invoked when the
367             APi call is complete. The callback will be invoked with a single
368             argument consisting of the condition variable. Ordinarily you will
369             call recv() on the variable and then do something with the result:
370              
371             {
372             local $VM::EC2::ASYNC=1;
373             my $cv = $ec2->describe_instances();
374             $cv->cb(sub {my $v = shift;
375             my @i = $v->recv;
376             print "instances = @i\n";
377             });
378             }
379              
380             For callbacks to be invoked, someone must be run an event loop
381             using one of the event frameworks that AnyEvent supports (e.g. Coro,
382             Tk or Gtk). Alternately, you may simply run:
383              
384             AnyEvent->condvar->recv();
385            
386             If $VM::EC2::ASYNC is false, you can issue a single asynchronous call
387             by appending "_async" to the name of the method call. Similarly, if
388             $VM::EC2::ASYNC is true, you can make a single normal synchrous call
389             by appending "_sync" to the method name.
390              
391             For example, this is equivalent to the above:
392              
393             my $cv = $ec2->describe_instances_async(); # returns immediately
394             my @instances = $cv->recv;
395              
396             You may stack multiple asynchronous calls on top of one another. When
397             you call recv() on any of the returned condition variables, they will
398             all run in parallel. Hence the three calls will take no longer than
399             the longest individual one:
400              
401             my $cv1 = $ec2->describe_instances_async({'instance-state-name'=>'running'});
402             my $cv2 = $ec2->describe_instances_async({'instance-state-name'=>'stopped'});
403             my @running = $cv1->recv;
404             my @stopped = $cv2->recv;
405              
406             Same thing with callbacks:
407              
408             my (@running,@stopped);
409             my $cv1 = $ec2->describe_instances_async({'instance-state-name'=>'running'});
410             $cv1->cb(sub {@running = shift->recv});
411              
412             my $cv2 = $ec2->describe_instances_async({'instance-state-name'=>'stopped'});
413             $cv1->cb(sub {@stopped = shift->recv});
414              
415             AnyEvent->condvar->recv;
416              
417             And here it is using a group conditional variable to block until all
418             pending describe_instances() requests have completed:
419              
420             my %instances;
421             my $group = AnyEvent->condvar;
422             $group->begin;
423             for my $state (qw(pending running stopping stopped)) {
424             $group->begin;
425             my $cv = $ec2->describe_instances_async({'instance-state-name'=>$state});
426             $cv->cb(sub {my @i = shift->recv;
427             $instances{$state}=\@i;
428             $group->end});
429             }
430             $group->recv;
431             # when we get here %instances will be populated by all instances,
432             # sorted by their state.
433              
434             If this looks mysterious, please consult L for full
435             documentation and examples.
436              
437             Lastly, be advised that some of the objects returned by calls to
438             VM::EC2, such as the VM::EC2::Instance object, will make their own
439             calls into VM::EC2 for certain methods. Some of these methods will
440             block (be synchronous) of necessity, even if you have set
441             $VM::EC2::ASYNC. For example, the instance object's current_status()
442             method must block in order to update the object and return the current
443             status. Other object methods may behave unpredictably in async
444             mode. Caveat emptor!
445              
446             =head1 API GROUPS
447              
448             The extensive (and growing) Amazon API has many calls that you may
449             never need. To avoid the performance overhead of loading the
450             interfaces to all these calls, you may use Perl's import mechanism to
451             load only those modules you care about. By default, all methods are
452             loaded.
453              
454             Loading is controlled by the "use" import list, and follows the
455             conventions described in the Exporter module:
456              
457             use VM::EC2; # load all methods!
458              
459             use VM::EC2 'key','elastic_ip'; # load Key Pair and Elastic IP
460             # methods only
461              
462             use VM::EC2 ':standard'; # load all the standard methods
463              
464             use VM::EC2 ':standard','!key'; # load standard methods but not Key Pair
465              
466             Related API calls are grouped together using the scheme described at
467             http://docs.aws.amazon.com/AWSEC2/latest/APIReference/OperationList-query.html. The
468             modules that define the API calls can be found in VM/EC2/REST/; you
469             can read their documentation by running perldoc VM::EC2::REST::"name
470             of module":
471              
472             perldoc VM::EC2::REST::elastic_ip
473              
474             The groups that you can import are as follows:
475            
476             :standard => ami, ebs, elastic_ip, instance, keys, general,
477             monitoring, tag, security_group, security_token, zone
478              
479             :vpc => customer_gateway, dhcp, elastic_network_interface,
480             private_ip, internet_gateway, network_acl, route_table,
481             vpc, vpn, vpn_gateway
482              
483             :misc => devpay, monitoring, reserved_instance,
484             spot_instance, vm_export, vm_import, windows
485              
486             :scaling => elastic_load_balancer,autoscaling
487              
488             :hpc => placement_group
489              
490             :all => :standard, :vpn, :misc
491              
492             :DEFAULT => :all
493              
494             The individual modules are:
495              
496             ami -- Control Amazon Machine Images
497             autoscaling -- Control autoscaling
498             customer_gateway -- VPC/VPN gateways
499             devpay -- DevPay API
500             dhcp -- VPC DHCP options
501             ebs -- Elastic Block Store volumes & snapshots
502             elastic_ip -- Elastic IP addresses
503             elastic_load_balancer -- The Elastic Load Balancer service
504             elastic_network_interface -- VPC Elastic Network Interfaces
505             general -- Get console output and account attributes
506             instance -- Control EC2 instances
507             internet_gateway -- VPC connections to the internet
508             keys -- Manage SSH keypairs
509             monitoring -- Control instance monitoring
510             network_acl -- Control VPC network access control lists
511             placement_group -- Control the placement of HPC instances
512             private_ip -- VPC private IP addresses
513             reserved_instance -- Reserve instances and view reservations
514             route_table -- VPC network routing
515             security_group -- Security groups for VPCs and normal instances
516             security_token -- Temporary credentials for use with IAM roles
517             spot_instance -- Request and manage spot instances
518             subnet -- VPC subnets
519             tag -- Create and interrogate resource tags.
520             vm_export -- Export VMs
521             vm_import -- Import VMs
522             vpc -- Create and manipulate virtual private clouds
523             vpn_gateway -- Create and manipulate VPN gateways within VPCs
524             vpn -- Create and manipulate VPNs within VPCs
525             windows -- Windows operating system-specific API calls.
526             zone -- Interrogate availability zones
527            
528             =head1 EXAMPLE SCRIPT
529              
530             The script sync_to_snapshot.pl, distributed with this module,
531             illustrates a relatively complex set of steps on EC2 that does
532             something useful. Given a list of directories or files on the local
533             filesystem it copies the files into an EBS snapshot with the desired
534             name by executing the following steps:
535              
536             1. Provisions a new EBS volume on EC2 large enough to hold the data.
537              
538             2. Spins up a staging instance to manage the network transfer of data
539             from the local machine to the staging volume.
540              
541             3. Creates a temporary ssh keypair and a security group that allows an
542             rsync-over-ssh.
543              
544             4. Formats and mounts the volume if necessary.
545              
546             5. Initiates an rsync-over-ssh for the designated files and
547             directories.
548              
549             6. Unmounts and snapshots the volume.
550              
551             7. Cleans up.
552              
553             If a snapshot of the same name already exists, then it is used to
554             create the staging volume, enabling network-efficient synchronization
555             of the files. A snapshot tag named "Version" is incremented each time
556             you synchronize.
557              
558             =head1 CORE METHODS
559              
560             This section describes the VM::EC2 constructor, accessor methods, and
561             methods relevant to error handling.
562              
563             =cut
564              
565 7     7   4937 use strict;
  7         12  
  7         233  
566              
567 7     7   2833 use VM::EC2::Dispatch;
  0            
  0            
568             use VM::EC2::ParmParser;
569              
570             use MIME::Base64 qw(encode_base64 decode_base64);
571             use Digest::SHA qw(hmac_sha256 sha1_hex);
572             use POSIX 'strftime';
573             use URI;
574             use URI::Escape;
575             use AnyEvent;
576             use AnyEvent::HTTP;
577             use HTTP::Request::Common;
578             use VM::EC2::Error;
579             use Carp 'croak','carp';
580             use JSON;
581              
582             our $VERSION = '1.25';
583             our $AUTOLOAD;
584             our @CARP_NOT = qw(VM::EC2::Image VM::EC2::Volume
585             VM::EC2::Snapshot VM::EC2::Instance
586             VM::EC2::ReservedInstance);
587             our $ASYNC;
588              
589             # hard-coded timeout for several wait_for_terminal_state() calls.
590             use constant WAIT_FOR_TIMEOUT => 600;
591              
592             sub AUTOLOAD {
593             my $self = shift;
594             my ($pack,$func_name) = $AUTOLOAD=~/(.+)::([^:]+)$/;
595             return if $func_name eq 'DESTROY';
596             my $proper = VM::EC2->canonicalize($func_name);
597             $proper =~ s/^-//;
598              
599             my $async;
600             if ($proper =~ /^(\w+)_(a?sync)$/i) {
601             $proper = $1;
602             $async = $2 eq 'async' ? 1 : 0;
603             }
604              
605             if ($self->can($proper)) {
606             my $local = defined $async ? "local \$ASYNC=$async;" : '';
607             eval "sub $pack\:\:$func_name {$local shift->$proper(\@_)}; 1" or die $@;
608             $self->$func_name(@_);
609             }
610              
611             else {
612             croak "Can't locate object method \"$func_name\" via package \"$pack\"";
613             }
614             }
615              
616             use constant import_tags => {
617             ':standard' => [qw(instance elastic_ip ebs ami keys monitoring zone general tag security_group security_token)],
618             ':vpc' => [qw(customer_gateway dhcp elastic_network_interface private_ip
619             internet_gateway network_acl route_table subnet vpc vpn vpn_gateway)],
620             ':hpc' => ['placement_group'],
621             ':scaling' => ['elastic_load_balancer','autoscaling'],
622             ':elb' => ['elastic_load_balancer'],
623             ':misc' => ['devpay','reserved_instance', 'spot_instance','vm_export','vm_import','windows'],
624             ':all' => [qw(:standard :vpc :hpc :scaling :misc)],
625             ':DEFAULT' => [':all'],
626             };
627              
628             # e.g. use VM::EC2 ':default','!ami';
629             sub import {
630             my $self = shift;
631             my @args = @_;
632             @args = ':DEFAULT' unless @args;
633             while (1) {
634             my @processed = map {/^:/ && import_tags->{$_} ? @{import_tags->{$_}} : $_ } @args;
635             last if "@processed" eq "@args"; # no more expansion needed
636             @args = @processed;
637             }
638             my (%excluded,%included);
639             foreach (@args) {
640             if (/^!(\S+)/) {
641             $excluded{$1}++ ;
642             $_ = $1;
643             }
644             }
645             foreach (@args) {
646             next unless /^\S/;
647             next if $excluded{$_};
648             next if $included{$_}++;
649             croak "'$_' is not a valid import tag" if /^[!:]/;
650             next if $INC{"VM/EC2/REST/$_.pm"};
651             my $class = "VM::EC2::REST::$_";
652             eval "require $class; 1" or die $@;
653             }
654             }
655              
656             =head2 $ec2 = VM::EC2->new(-access_key=>$id,-secret_key=>$key,-endpoint=>$url)
657              
658             Create a new Amazon access object. Required arguments are:
659              
660             -access_key Access ID for an authorized user
661              
662             -secret_key Secret key corresponding to the Access ID
663              
664             -security_token Temporary security token obtained through a call to the
665             AWS Security Token Service
666              
667             -endpoint The URL for making API requests
668              
669             -region The region to receive the API requests
670              
671             -raise_error If true, throw an exception.
672              
673             -print_error If true, print errors to STDERR.
674              
675             One or more of -access_key or -secret_key can be omitted if the
676             environment variables EC2_ACCESS_KEY and EC2_SECRET_KEY are
677             defined. If no endpoint is specified, then the environment variable
678             EC2_URL is consulted; otherwise the generic endpoint
679             http://ec2.amazonaws.com/ is used. You can also select the endpoint by
680             specifying one of the Amazon regions, such as "us-west-2", with the
681             -region argument. The endpoint specified by -region will override
682             -endpoint.
683              
684             -security_token is used in conjunction with temporary security tokens
685             returned by $ec2->get_federation_token() and $ec2->get_session_token()
686             to grant restricted, time-limited access to some or all your EC2
687             resources to users who do not have access to your account. If you pass
688             either a VM::EC2::Security::Token object, or the
689             VM::EC2::Security::Credentials object contained within the token
690             object, then new() does not need the -access_key or -secret_key
691             arguments. You may also pass a session token string scalar to
692             -security_token, in which case you must also pass the access key ID
693             and secret keys generated at the same time the session token was
694             created. See
695             http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/UsingIAM.html
696             and L.
697              
698             To use a Eucalyptus cloud, please provide the appropriate endpoint
699             URL.
700              
701             By default, when the Amazon API reports an error, such as attempting
702             to perform an invalid operation on an instance, the corresponding
703             method will return empty and the error message can be recovered from
704             $ec2->error(). However, if you pass -raise_error=>1 to new(), the module
705             will instead raise a fatal error, which you can trap with eval{} and
706             report with $@:
707              
708             eval {
709             $ec2->some_dangerous_operation();
710             $ec2->another_dangerous_operation();
711             };
712             print STDERR "something bad happened: $@" if $@;
713              
714             The error object can be retrieved with $ec2->error() as before.
715              
716             =cut
717              
718             sub new {
719             my $self = shift;
720             my %args = @_;
721              
722             my ($id,$secret,$token);
723             if (ref $args{-security_token} && $args{-security_token}->can('access_key_id')) {
724             $id = $args{-security_token}->accessKeyId;
725             $secret = $args{-security_token}->secretAccessKey;
726             $token = $args{-security_token}->sessionToken;
727             }
728              
729             $id ||= $args{-access_key} || $ENV{EC2_ACCESS_KEY}
730             or croak "Please provide -access_key parameter or define environment variable EC2_ACCESS_KEY";
731             $secret ||= $args{-secret_key} || $ENV{EC2_SECRET_KEY}
732             or croak "Please provide -secret_key or define environment variable EC2_SECRET_KEY";
733             $token ||= $args{-security_token};
734              
735             my $endpoint_url = $args{-endpoint} || $ENV{EC2_URL} || 'https://ec2.amazonaws.com/';
736             $endpoint_url .= '/' unless $endpoint_url =~ m!/$!;
737             $endpoint_url = "https://".$endpoint_url unless $endpoint_url =~ m!https?://!;
738              
739             my $raise_error = $args{-raise_error};
740             my $print_error = $args{-print_error};
741             my $obj = bless {
742             id => $id,
743             secret => $secret,
744             security_token => $token,
745             endpoint => $endpoint_url,
746             idempotent_seed => sha1_hex(rand()),
747             raise_error => $raise_error,
748             print_error => $print_error,
749             },ref $self || $self;
750              
751             if ($args{-region}) {
752             $self->import('zone');
753             my $region = eval{$obj->describe_regions($args{-region})};
754             my $endpoint = $region ? $region->regionEndpoint :"ec2.$args{-region}.amazonaws.com";
755             $obj->endpoint($endpoint);
756             }
757              
758             return $obj;
759             }
760              
761             =head2 $access_key = $ec2->access_key([$new_access_key])
762              
763             Get or set the ACCESS KEY. In this and all similar get/set methods,
764             call the method with no arguments to get the current value, and with a
765             single argument to change the value:
766              
767             $current_key = $ec2->access_key;
768             $ec2->access_key('XYZZY');
769              
770             In the case of setting the value, these methods will return the old
771             value as their result:
772              
773             $old_key = $ec2->access_key($new_key);
774              
775             =cut
776              
777             sub access_key {shift->id(@_)}
778              
779             sub id {
780             my $self = shift;
781             my $d = $self->{id};
782             $self->{id} = shift if @_;
783             $d;
784             }
785              
786             =head2 $secret = $ec2->secret([$new_secret])
787              
788             Get or set the SECRET KEY
789              
790             =cut
791              
792             sub secret {
793             my $self = shift;
794             my $d = $self->{secret};
795             $self->{secret} = shift if @_;
796             $d;
797             }
798              
799             =head2 $secret = $ec2->security_token([$new_token])
800              
801             Get or set the temporary security token. See L.
802              
803             =cut
804              
805             sub security_token {
806             my $self = shift;
807             my $d = $self->{security_token};
808             $self->{security_token} = shift if @_;
809             $d;
810             }
811              
812             =head2 $endpoint = $ec2->endpoint([$new_endpoint])
813              
814             Get or set the ENDPOINT URL.
815              
816             =cut
817              
818             sub endpoint {
819             my $self = shift;
820             my $d = $self->{endpoint};
821             if (@_) {
822             my $new_endpoint = shift;
823             $new_endpoint = 'https://'.$new_endpoint
824             unless $new_endpoint =~ /^https?:/;
825             $self->{endpoint} = $new_endpoint;
826             }
827             $d;
828             }
829              
830             =head2 $region = $ec2->region([$new_region])
831              
832             Get or set the EC2 region manipulated by this module. This has the side effect
833             of changing the endpoint.
834              
835             =cut
836              
837             sub region {
838             my $self = shift;
839              
840             my $d = $self->{endpoint};
841             $d =~ s!^https?://!!;
842             $d =~ s!/$!!;
843              
844             $self->import('zone');
845             my @regions = $self->describe_regions;
846             my ($current_region) = grep {$_->regionEndpoint eq $d} @regions;
847              
848             if (@_) {
849             my $new_region = shift;
850             my ($region) = grep {/$new_region/} @regions;
851             $region or croak "unknown region $new_region";
852             $self->endpoint($region->regionEndpoint);
853             }
854             return $current_region;
855             }
856              
857             =head2 $ec2->raise_error($boolean)
858              
859             Change the handling of error conditions. Pass a true value to cause
860             Amazon API errors to raise a fatal error. Pass false to make methods
861             return undef. In either case, you can detect the error condition
862             by calling is_error() and fetch the error message using error(). This
863             method will also return the current state of the raise error flag.
864              
865             =cut
866              
867             sub raise_error {
868             my $self = shift;
869             my $d = $self->{raise_error};
870             $self->{raise_error} = shift if @_;
871             $d;
872             }
873              
874             =head2 $ec2->print_error($boolean)
875              
876             Change the handling of error conditions. Pass a true value to cause
877             Amazon API errors to print error messages to STDERR. Pass false to
878             cancel this behavior.
879              
880             =cut
881              
882             sub print_error {
883             my $self = shift;
884             my $d = $self->{print_error};
885             $self->{print_error} = shift if @_;
886             $d;
887             }
888              
889             =head2 $boolean = $ec2->is_error
890              
891             If a method fails, it will return undef. However, some methods, such
892             as describe_images(), will also return undef if no resources matches
893             your search criteria. Call is_error() to distinguish the two
894             eventualities:
895              
896             @images = $ec2->describe_images(-owner=>'29731912785');
897             unless (@images) {
898             die "Error: ",$ec2->error if $ec2->is_error;
899             print "No appropriate images found\n";
900             }
901              
902             =cut
903              
904             sub is_error {
905             defined shift->error();
906             }
907              
908             =head2 $err = $ec2->error
909              
910             If the most recently-executed method failed, $ec2->error() will return
911             the error code and other descriptive information. This method will
912             return undef if the most recently executed method was successful.
913              
914             The returned object is actually an AWS::Error object, which
915             has two methods named code() and message(). If used in a string
916             context, its operator overloading returns the composite string
917             "$message [$code]".
918              
919             =cut
920              
921             sub error {
922             my $self = shift;
923             my $d = $self->{error};
924             $self->{error} = shift if @_;
925             $d;
926             }
927              
928             =head2 $err = $ec2->error_str
929              
930             Same as error() except it returns the string representation, not the
931             object. This works better in debuggers and exception handlers.
932              
933             =cut
934              
935             sub error_str {
936             my $e = shift->{error};
937             $e ||= '';
938             return "$e";
939             }
940              
941             =head2 $account_id = $ec2->account_id
942              
943             Looks up the account ID corresponding to the credentials provided when
944             the VM::EC2 instance was created. The way this is done is to fetch the
945             "default" security group, which is guaranteed to exist, and then
946             return its groupId field. The result is cached so that subsequent
947             accesses are fast.
948              
949             =head2 $account_id = $ec2->userId
950              
951             Same as above, for convenience.
952              
953             =cut
954              
955             sub account_id {
956             my $self = shift;
957             return $self->{account_id} if exists $self->{account_id};
958             my $sg = $self->describe_security_groups(-group_name=>'default') or return;
959             return $self->{account_id} ||= $sg->ownerId;
960             }
961              
962             sub userId { shift->account_id }
963              
964             =head2 $new_ec2 = $ec2->clone
965              
966             This method creates an identical copy of the EC2 object. It is used
967             occasionally internally for creating an EC2 object in a different AWS
968             region:
969              
970             $singapore = $ec2->clone;
971             $singapore->region('ap-souteast-1');
972              
973             =cut
974              
975             sub clone {
976             my $self = shift;
977             my %contents = %$self;
978             return bless \%contents,ref $self;
979             }
980              
981             =head1 INSTANCES
982              
983             Load the 'instances' module to bring in methods for interrogating,
984             launching and manipulating EC2 instances. This module is part of
985             the ':standard' API group. The methods are described in detail in
986             L. Briefly:
987              
988             @i = $ec2->describe_instances(-instance_id=>\@ids,-filter=>\%filters)
989             @i = $ec2->run_instances(-image_id=>$id,%other_args)
990             @s = $ec2->start_instances(-instance_id=>\@instance_ids)
991             @s = $ec2->stop_instances(-instance_id=>\@instance_ids,-force=>1)
992             @s = $ec2->reboot_instances(-instance_id=>\@instance_ids)
993             $b = $ec2->confirm_product_instance($instance_id,$product_code)
994             $m = $ec2->instance_metadata
995             @d = $ec2->describe_instance_attribute($instance_id,$attribute)
996             $b = $ec2->modify_instance_attribute($instance_id,-$attribute_name=>$value)
997             $b = $ec2->reset_instance_attribute($instance_id,$attribute)
998             @s = $ec2->describe_instance_status(-instance_id=>\@ids,-filter=>\%filters,%other_args);
999              
1000             =head1 VOLUMES
1001              
1002             Load the 'ebs' module to bring in methods specific for elastic block
1003             storage volumes and snapshots. This module is part of the ':standard'
1004             API group. The methods are described in detail in
1005             L. Briefly:
1006              
1007             @v = $ec2->describe_volumes(-volume_id=>\@ids,-filter=>\%filters)
1008             $v = $ec2->create_volume(%args)
1009             $b = $ec2->delete_volume($volume_id)
1010             $a = $ec2->attach_volume($volume_id,$instance_id,$device)
1011             $a = $ec2->detach_volume($volume_id)
1012             $ec2->wait_for_attachments(@attachment)
1013             @v = $ec2->describe_volume_status(-volume_id=>\@ids,-filter=>\%filters)
1014             $ec2->wait_for_volumes(@volumes)
1015             @d = $ec2->describe_volume_attribute($volume_id,$attribute)
1016             $b = $ec2->enable_volume_io(-volume_id=>$volume_id)
1017             @s = $ec2->describe_snapshots(-snapshot_id=>\@ids,%other_args)
1018             @d = $ec2->describe_snapshot_attribute($snapshot_id,$attribute)
1019             $b = $ec2->modify_snapshot_attribute($snapshot_id,-$argument=>$value)
1020             $b = $ec2->reset_snapshot_attribute($snapshot_id,$attribute)
1021             $s = $ec2->create_snapshot(-volume_id=>$vol,-description=>$desc)
1022             $b = $ec2->delete_snapshot($snapshot_id)
1023             $s = $ec2->copy_snapshot(-source_region=>$region,-source_snapshot_id=>$id,-description=>$desc)
1024             $ec2->wait_for_snapshots(@snapshots)
1025              
1026             =head1 AMAZON MACHINE IMAGES
1027              
1028             Load the 'ami' module to bring in methods for creating and
1029             manipulating Amazon Machine Images. This module is part of the
1030             ':standard" group. Full details are in L. Briefly:
1031              
1032             @i = $ec2->describe_images(@image_ids)
1033             $i = $ec2->create_image(-instance_id=>$id,-name=>$name,%other_args)
1034             $i = $ec2->register_image(-name=>$name,%other_args)
1035             $r = $ec2->deregister_image($image_id)
1036             @d = $ec2->describe_image_attribute($image_id,$attribute)
1037             $b = $ec2->modify_image_attribute($image_id,-$attribute_name=>$value)
1038             $b = $ec2->reset_image_attribute($image_id,$attribute_name)
1039              
1040             =head1 KEYS
1041              
1042             Load the 'keys' module to bring in methods for creating and
1043             manipulating SSH keypairs. This module is loaded with the ':standard'
1044             group and documented in L
1045              
1046             @k = $ec2->describe_key_pairs(@names);
1047             $k = $ec2->create_key_pair($name)
1048             $k = $ec2->import_key_pair($name,$public_key)
1049             $b = $ec2->delete_key_pair($name)
1050              
1051             =head1 TAGS
1052              
1053             The methods in this module (loaded with ':standard') allow you to
1054             create, delete and fetch resource tags. You may find that you rarely
1055             need to use these methods directly because every object produced by
1056             VM::EC2 supports a simple tag interface:
1057            
1058             $object = $ec2->describe_volumes(-volume_id=>'vol-12345'); # e.g.
1059             $tags = $object->tags();
1060             $name = $tags->{Name};
1061             $object->add_tags(Role => 'Web Server', Status=>'development);
1062             $object->delete_tags(Name=>undef);
1063              
1064             See L for a full description of the uniform object
1065             tagging interface, and L for methods that allow
1066             you to manipulate the tags on multiple objects simultaneously. The
1067             methods defined by this module are:
1068              
1069             @t = $ec2->describe_tags(-filter=>\%filters);
1070             $b = $ec2->create_tags(-resource_id=>\@ids,-tag=>{key1=>value1...})
1071             $b = $ec2->delete_tags(-resource_id=>$id1,-tag=>{key1=>value1...})
1072            
1073             =head1 VIRTUAL PRIVATE CLOUDS
1074              
1075             EC2 virtual private clouds (VPCs) provide facilities for creating
1076             tiered applications combining public and private subnetworks, and for
1077             extending your home/corporate network into the cloud. VPC-related
1078             methods are defined in the customer_gateway, dhcp,
1079             elastic_network_interface, private_ip, internet_gateway, network_acl,
1080             route_table, vpc, vpn, and vpn_gateway modules, and are loaded by
1081             importing ':vpc'. See L for an introduction.
1082              
1083             The L and L modules define
1084             convenience methods that simplify working with VPC objects. This
1085             allows for steps that typically follow each other, such as creating a
1086             route table and associating it with a subnet, happen
1087             automatically. For example, this series of calls creates a VPC with a
1088             single subnet, creates an Internet gateway attached to the VPC,
1089             associates a new route table with the subnet and then creates a
1090             default route from the subnet to the Internet gateway:
1091              
1092             $vpc = $ec2->create_vpc('10.0.0.0/16') or die $ec2->error_str;
1093             $subnet1 = $vpc->create_subnet('10.0.0.0/24') or die $vpc->error_str;
1094             $gateway = $vpc->create_internet_gateway or die $vpc->error_str;
1095             $routeTbl = $subnet->create_route_table or die $vpc->error_str;
1096             $routeTbl->create_route('0.0.0.0/0' => $gateway) or die $vpc->error_str;
1097              
1098             =head1 ELASTIC LOAD BALANCERS (ELB) AND AUTOSCALING
1099              
1100             The methods in the 'elastic_load_balancer' and 'autoscaling' modules
1101             allow you to retrieve information about Elastic Load Balancers, create
1102             new ELBs, and change the properties of the ELBs, as well as define
1103             autoscaling groups and their launch configurations. These modules are
1104             both imported by the ':scaling' import group. See
1105             L and
1106             L for descriptions of the facilities
1107             enabled by this module.
1108              
1109             =head1 AWS SECURITY POLICY
1110              
1111             The VM::EC2::Security::Policy module provides a simple Identity and
1112             Access Management (IAM) policy statement generator geared for use with
1113             AWS security tokens (see next section). Its facilities are defined in
1114             L.
1115              
1116             =head1 AWS SECURITY TOKENS
1117              
1118             AWS security tokens provide a way to grant temporary access to
1119             resources in your EC2 space without giving them permanent
1120             accounts. They also provide the foundation for mobile services and
1121             multifactor authentication devices (MFA). These methods are defined in
1122             'security_token', which is part of the ':standard' group. See
1123             L for details. Here is a quick example:
1124              
1125             Here is an example:
1126              
1127             # on your side of the connection
1128             $ec2 = VM::EC2->new(...); # as usual
1129             my $policy = VM::EC2::Security::Policy->new;
1130             $policy->allow('DescribeImages','RunInstances');
1131             my $token = $ec2->get_federation_token(-name => 'TemporaryUser',
1132             -duration => 60*60*3, # 3 hrs, as seconds
1133             -policy => $policy);
1134             my $serialized = $token->credentials->serialize;
1135             send_data_to_user_somehow($serialized);
1136              
1137             # on the temporary user's side of the connection
1138             my $serialized = get_data_somehow();
1139             my $token = VM::EC2::Security::Credentials->new_from_serialized($serialized);
1140             my $ec2 = VM::EC2->new(-security_token => $token);
1141             print $ec2->describe_images(-owner=>'self');
1142              
1143             =head1 SPOT AND RESERVED INSTANCES
1144              
1145             The 'spot_instance' and 'reserved_instance' modules allow you to
1146             create and manipulate spot and reserved instances. They are both part
1147             of the ':misc' import group. See L and
1148             L. For example:
1149              
1150             @offerings = $ec2->describe_reserved_instances_offerings(
1151             {'availability-zone' => 'us-east-1a',
1152             'instance-type' => 'c1.medium',
1153             'product-description' =>'Linux/UNIX',
1154             'duration' => 31536000, # this is 1 year
1155             });
1156             $offerings[0]->purchase(5) and print "Five reserved instances purchased\n";
1157              
1158              
1159              
1160             =head1 WAITING FOR STATE CHANGES
1161              
1162             VM::EC2 provides a series of methods that allow your script to wait in
1163             an efficient manner for desired state changes in instances, volumes
1164             and other objects. They are described in detail the individual modules
1165             to which they apply, but in each case the method will block until each
1166             member of a list of objects transitions to a terminal state
1167             (e.g. "completed" in the case of a snapshot). Briefly:
1168              
1169             $ec2->wait_for_instances(@instances)
1170             $ec2->wait_for_snapshots(@snapshots)
1171             $ec2->wait_for_volumes(@volumes)
1172             $ec2->wait_for_attachments(@attachment)
1173              
1174             There is also a generic version of this defined in the VM::EC2 core:
1175              
1176             =head2 $ec2->wait_for_terminal_state(\@objects,['list','of','states'] [,$timeout])
1177              
1178             Generic version of the last four methods. Wait for all members of the
1179             provided list of Amazon objects instances to reach some terminal state
1180             listed in the second argument, and then return a hash reference that
1181             maps each object ID to its final state.
1182              
1183             If a timeout is provided, in seconds, then the method will abort after
1184             waiting the indicated time and return undef.
1185              
1186             =cut
1187              
1188             sub wait_for_terminal_state {
1189             my $self = shift;
1190             my ($objects,$terminal_states,$timeout) = @_;
1191             my %terminal_state = map {$_=>1} @$terminal_states;
1192             my %status = ();
1193             my @pending = grep {defined $_} @$objects; # in case we're passed an undef
1194              
1195             my %timers;
1196             my $done = $self->condvar();
1197             $done->begin(sub {
1198             my $cv = shift;
1199             if ($cv->error) {
1200             $self->error($cv->error);
1201             $cv->send();
1202             } else {
1203             $cv->send(\%status);
1204             }
1205             }
1206             );
1207            
1208             for my $obj (@pending) {
1209             $done->begin;
1210             my $timer = AnyEvent->timer(interval => 3,
1211             cb => sub {
1212             $obj->current_status_async->cb(
1213             sub {
1214             my $state = shift->recv;
1215             if (!$state || $terminal_state{$state}) {
1216             $status{$obj} = $state;
1217             $done->end;
1218             undef $timers{$obj};
1219             }})});
1220             $timers{$obj} = $timer;
1221             }
1222              
1223             # timeout
1224             my $timeout_event;
1225             $timeout_event = AnyEvent->timer(after=> $timeout,
1226             cb => sub {
1227             undef %timers; # cancel all timers
1228             undef $timeout_event;
1229             $done->error('timeout waiting for terminal state');
1230             $done->end foreach @pending;
1231             }) if $timeout;
1232             $done->end;
1233              
1234             return $ASYNC ? $done : $done->recv;
1235             }
1236              
1237             =head2 $timeout = $ec2->wait_for_timeout([$new_timeout]);
1238              
1239             Get or change the timeout for wait_for_instances(), wait_for_attachments(),
1240             and wait_for_volumes(). The timeout is given in seconds, and defaults to
1241             600 (10 minutes). You can set this to 0 to wait forever.
1242              
1243             =cut
1244              
1245             sub wait_for_timeout {
1246             my $self = shift;
1247             $self->{wait_for_timeout} = WAIT_FOR_TIMEOUT
1248             unless defined $self->{wait_for_timeout};
1249             my $d = $self->{wait_for_timeout};
1250             $self->{wait_for_timeout} = shift if @_;
1251             return $d;
1252             }
1253              
1254             # ------------------------------------------------------------------------------------------
1255              
1256             =head1 INTERNAL METHODS
1257              
1258             These methods are used internally and are listed here without
1259             documentation (yet).
1260              
1261             =head2 $underscore_name = $ec2->canonicalize($mixedCaseName)
1262              
1263             =cut
1264              
1265             sub canonicalize {
1266             my $self = shift;
1267             my $name = shift;
1268             while ($name =~ /\w[A-Z.]/) {
1269             $name =~ s/([a-zA-Z])\.?([A-Z])/\L$1_$2/g or last;
1270             }
1271             return $name =~ /^-/ ? lc $name : '-'.lc $name;
1272             }
1273              
1274             sub uncanonicalize {
1275             my $self = shift;
1276             my $name = shift;
1277             $name =~ s/_([a-z])/\U$1/g;
1278             return $name;
1279             }
1280              
1281             =head2 $instance_id = $ec2->instance_parm(@args)
1282              
1283             =cut
1284              
1285             sub instance_parm {
1286             my $self = shift;
1287             my %args;
1288             if ($_[0] =~ /^-/) {
1289             %args = @_;
1290             } elsif (@_ > 1) {
1291             %args = (-instance_id => [@_]);
1292             } else {
1293             %args = (-instance_id => shift);
1294             }
1295             my $id = $args{-instance_id};
1296             return ref $id && ref $id eq 'ARRAY' ? @$id : $id;
1297             }
1298              
1299             =head2 @arguments = $ec2->value_parm(ParameterName => \%args)
1300              
1301             =cut
1302              
1303             sub value_parm {
1304             my $self = shift;
1305             my ($argname,$args) = @_;
1306             my $name = $self->canonicalize($argname);
1307             return unless exists $args->{$name} || exists $args->{"-$argname"};
1308             my $val = $args->{$name} || $args->{"-$argname"};
1309             return ("$argname.Value"=>$val);
1310             }
1311              
1312             =head2 @arguments = $ec2->single_parm(ParameterName => \%args)
1313              
1314             =cut
1315              
1316             sub single_parm {
1317             my $self = shift;
1318             my ($argname,$args) = @_;
1319             my $name = $self->canonicalize($argname);
1320             my $val = $args->{$name} || $args->{"-$argname"};
1321             defined $val or return;
1322             my $v = ref $val && ref $val eq 'ARRAY' ? $val->[0] : $val;
1323             return ($argname=>$v);
1324             }
1325              
1326             =head2 @parameters = $ec2->prefix_parm($prefix, ParameterName => \%args)
1327              
1328             =cut
1329              
1330             sub prefix_parm {
1331             my $self = shift;
1332             my ($prefix,$argname,$args) = @_;
1333             my $name = $self->canonicalize($argname);
1334             my $val = $args->{$name} || $args->{"-$argname"};
1335             defined $val or return;
1336             my $v = ref $val && ref $val eq 'ARRAY' ? $val->[0] : $val;
1337             return ("$prefix.$argname"=>$v);
1338             }
1339              
1340             =head2 @parameters = $ec2->member_list_parm(ParameterName => \%args)
1341              
1342             =cut
1343              
1344             sub member_list_parm {
1345             my $self = shift;
1346             my ($argname,$args) = @_;
1347             my $name = $self->canonicalize($argname);
1348              
1349             my @params;
1350             if (my $a = $args->{$name}||$args->{"-$argname"}) {
1351             my $c = 1;
1352             for (ref $a && ref $a eq 'ARRAY' ? @$a : $a) {
1353             push @params,("$argname.member.".$c++ => $_);
1354             }
1355             }
1356             return @params;
1357             }
1358              
1359             =head2 @arguments = $ec2->list_parm(ParameterName => \%args)
1360              
1361             =cut
1362              
1363             sub list_parm {
1364             my $self = shift;
1365             my ($argname,$args) = @_;
1366             my $name = $self->canonicalize($argname);
1367              
1368             my @params;
1369             if (my $a = $args->{$name}||$args->{"-$argname"}) {
1370             my $c = 1;
1371             for (ref $a && ref $a eq 'ARRAY' ? @$a : $a) {
1372             push @params,("$argname.".$c++ => $_);
1373             }
1374             }
1375              
1376             return @params;
1377             }
1378              
1379             =head2 @arguments = $ec2->filter_parm(\%args)
1380              
1381             =cut
1382              
1383             sub filter_parm {
1384             my $self = shift;
1385             my $args = shift;
1386             return $self->key_value_parameters('Filter','Name','Value',$args);
1387             }
1388              
1389             =head2 @arguments = $ec2->key_value_parameters($param_name,$keyname,$valuename,\%args,$skip_undef_values)
1390              
1391             =cut
1392              
1393             sub key_value_parameters {
1394             my $self = shift;
1395             # e.g. 'Filter', 'Name','Value',{-filter=>{a=>b}}
1396             my ($parameter_name,$keyname,$valuename,$args,$skip_undef_values) = @_;
1397             my $arg_name = $self->canonicalize($parameter_name);
1398            
1399             my @params;
1400             if (my $a = $args->{$arg_name}||$args->{"-$parameter_name"}) {
1401             my $c = 1;
1402             if (ref $a && ref $a eq 'HASH') {
1403             while (my ($name,$value) = each %$a) {
1404             push @params,("$parameter_name.$c.$keyname" => $name);
1405             if (ref $value && ref $value eq 'ARRAY') {
1406             for (my $m=1;$m<=@$value;$m++) {
1407             push @params,("$parameter_name.$c.$valuename.$m" => $value->[$m-1])
1408             }
1409             } else {
1410             push @params,("$parameter_name.$c.$valuename" => $value)
1411             unless !defined $value && $skip_undef_values;
1412             }
1413             $c++;
1414             }
1415             } else {
1416             for (ref $a ? @$a : $a) {
1417             my ($name,$value) = /([^=]+)\s*=\s*(.+)/;
1418             push @params,("$parameter_name.$c.$keyname" => $name);
1419             push @params,("$parameter_name.$c.$valuename" => $value)
1420             unless !defined $value && $skip_undef_values;
1421             $c++;
1422             }
1423             }
1424             }
1425              
1426             return @params;
1427             }
1428              
1429             =head2 @arguments = $ec2->launch_perm_parm($prefix,$suffix,$value)
1430              
1431             =cut
1432              
1433             sub launch_perm_parm {
1434             my $self = shift;
1435             my ($prefix,$suffix,$value) = @_;
1436             return unless defined $value;
1437             $self->_perm_parm('LaunchPermission',$prefix,$suffix,$value);
1438             }
1439              
1440             sub create_volume_perm_parm {
1441             my $self = shift;
1442             my ($prefix,$suffix,$value) = @_;
1443             return unless defined $value;
1444             $self->_perm_parm('CreateVolumePermission',$prefix,$suffix,$value);
1445             }
1446              
1447             sub _perm_parm {
1448             my $self = shift;
1449             my ($base,$prefix,$suffix,$value) = @_;
1450             return unless defined $value;
1451             my @list = ref $value && ref $value eq 'ARRAY' ? @$value : $value;
1452             my $c = 1;
1453             my @param;
1454             for my $v (@list) {
1455             push @param,("$base.$prefix.$c.$suffix" => $v);
1456             $c++;
1457             }
1458             return @param;
1459             }
1460              
1461             =head2 @arguments = $ec2->iam_parm($args)
1462              
1463             =cut
1464              
1465             sub iam_parm {
1466             my $self = shift;
1467             my $args = shift;
1468             my @p;
1469             push @p,('IamInstanceProfile.Arn' => $args->{-iam_arn}) if $args->{-iam_arn};
1470             push @p,('IamInstanceProfile.Name' => $args->{-iam_name}) if $args->{-iam_name};
1471             return @p;
1472             }
1473              
1474             =head2 @arguments = $ec2->block_device_parm($block_device_mapping_string)
1475              
1476             =cut
1477              
1478             sub block_device_parm {
1479             my $self = shift;
1480             my $devlist = shift or return;
1481              
1482             my @dev = ref $devlist && ref $devlist eq 'ARRAY' ? @$devlist : $devlist;
1483              
1484             my @p;
1485             my $c = 1;
1486             for my $d (@dev) {
1487             $d =~ /^([^=]+)=([^=]+)$/ or croak "block device mapping must be in format /dev/sdXX=device-name";
1488              
1489             my ($devicename,$blockdevice) = ($1,$2);
1490             push @p,("BlockDeviceMapping.$c.DeviceName"=>$devicename);
1491              
1492             if ($blockdevice =~ /^vol-/) { # this is a volume, and not a snapshot
1493             my ($volume,$delete_on_term) = split ':',$blockdevice;
1494             push @p,("BlockDeviceMapping.$c.Ebs.VolumeId" => $volume);
1495             push @p,("BlockDeviceMapping.$c.Ebs.DeleteOnTermination"=>$delete_on_term)
1496             if defined $delete_on_term && $delete_on_term=~/^(true|false|1|0)$/
1497             }
1498             elsif ($blockdevice eq 'none') {
1499             push @p,("BlockDeviceMapping.$c.NoDevice" => '');
1500             } elsif ($blockdevice =~ /^ephemeral\d$/) {
1501             push @p,("BlockDeviceMapping.$c.VirtualName"=>$blockdevice);
1502             } else {
1503             my ($snapshot,$size,$delete_on_term,$vtype,$iops) = split ':',$blockdevice;
1504              
1505             # Workaround for apparent bug in 2012-12-01 API; instances will crash without volume size
1506             # even if a snapshot ID is provided
1507             if ($snapshot) {
1508             $size ||= eval{$self->describe_snapshots($snapshot)->volumeSize};
1509             push @p,("BlockDeviceMapping.$c.Ebs.SnapshotId" =>$snapshot);
1510             }
1511              
1512             push @p,("BlockDeviceMapping.$c.Ebs.VolumeSize" =>$size) if $size;
1513             push @p,("BlockDeviceMapping.$c.Ebs.DeleteOnTermination"=>$delete_on_term)
1514             if defined $delete_on_term && $delete_on_term=~/^(true|false|1|0)$/;
1515             push @p,("BlockDeviceMapping.$c.Ebs.VolumeType"=>$vtype) if $vtype;
1516             push @p,("BlockDeviceMapping.$c.Ebs.Iops"=>$iops) if $iops;
1517             }
1518             $c++;
1519             }
1520             return @p;
1521             }
1522              
1523             # ['eth0=eni-123456','eth1=192.168.2.1,192.168.3.1,192.168.4.1:subnet-12345:sg-12345:true:My Weird Network']
1524             # form 1: ethX=network device id
1525             # form 2: ethX=primary_address,secondary_address1,secondary_address2...:subnetId:securityGroupId:deleteOnTermination:description:AssociatePublicIpAddress
1526             # form 3: ethX=primary_address,secondary_address_count:subnetId:securityGroupId:deleteOnTermination:description:AssociatePublicIpAddress
1527             sub network_interface_parm {
1528             my $self = shift;
1529             my $args = shift;
1530             my $devlist = $args->{-network_interfaces} or return;
1531             my @dev = ref $devlist && ref $devlist eq 'ARRAY' ? @$devlist : $devlist;
1532              
1533             my @p;
1534             my $c = 0;
1535             for my $d (@dev) {
1536             $d =~ /^eth(\d+)\s*=\s*([^=]+)$/ or croak "network device mapping must be in format ethX=option-string";
1537              
1538             my ($device_index,$device_options) = ($1,$2);
1539             push @p,("NetworkInterface.$c.DeviceIndex" => $device_index);
1540             my @options = split ':',$device_options;
1541             if (@options == 1) {
1542             push @p,("NetworkInterface.$c.NetworkInterfaceId" => $options[0]);
1543             }
1544             else {
1545             my ($ip_addresses,$subnet_id,$security_group_id,$delete_on_termination,$description,$assoc_public_ip_addr) = @options;
1546             # if assoc_public_ip_addr is true, the following conditions must be met:
1547             # * can only associate a public address with a single network interface with a device index of 0
1548             # * cannot associate a public ip with a second network interface
1549             # * cannot assoicate a public ip when launching more than one network interface
1550             # NOTE: This option defaults to true in a default VPC
1551             if ($assoc_public_ip_addr) {
1552             $assoc_public_ip_addr = (($assoc_public_ip_addr eq 'true') &&
1553             ($device_index == 0) &&
1554             (@dev == 1)) ? 'true' : 'false';
1555             }
1556             my @addresses = split /\s*,\s*/,$ip_addresses;
1557             for (my $a = 0; $a < @addresses; $a++) {
1558             if ($addresses[$a] =~ /^\d+\.\d+\.\d+\.\d+$/ ) {
1559             push @p,("NetworkInterface.$c.PrivateIpAddresses.$a.PrivateIpAddress" => $addresses[$a]);
1560             push @p,("NetworkInterface.$c.PrivateIpAddresses.$a.Primary" => $a == 0 ? 'true' : 'false');
1561             }
1562             elsif ($addresses[$a] =~ /^\d+$/ && $a > 0) {
1563             push @p,("NetworkInterface.$c.SecondaryPrivateIpAddressCount" => $addresses[$a]);
1564             }
1565             }
1566             my @sgs = split ',',$security_group_id;
1567             for (my $i=0;$i<@sgs;$i++) {
1568             push @p,("NetworkInterface.$c.SecurityGroupId.$i" => $sgs[$i]);
1569             }
1570              
1571             push @p,("NetworkInterface.$c.SubnetId" => $subnet_id) if length $subnet_id;
1572             push @p,("NetworkInterface.$c.DeleteOnTermination" => $delete_on_termination) if length $delete_on_termination;
1573             push @p,("NetworkInterface.$c.Description" => $description) if length $description;
1574             push @p,("NetworkInterface.$c.AssociatePublicIpAddress" => $assoc_public_ip_addr) if $assoc_public_ip_addr;
1575             }
1576             $c++;
1577             }
1578             return @p;
1579             }
1580              
1581             sub boolean_parm {
1582             my $self = shift;
1583             my ($argname,$args) = @_;
1584             my $name = $self->canonicalize($argname);
1585             return unless exists $args->{$name} || exists $args->{$argname};
1586             my $val = $args->{$name} || $args->{$argname};
1587             return ($argname => $val ? 'true' : 'false');
1588             }
1589              
1590             =head2 $version = $ec2->version()
1591              
1592             Returns the API version to be sent to the endpoint. Calls
1593             guess_version_from_endpoint() to determine this.
1594              
1595             =cut
1596              
1597             sub version {
1598             my $self = shift;
1599             return $self->{version} ||= $self->guess_version_from_endpoint();
1600             }
1601              
1602             =head2 $version = $ec2->guess_version_from_endpoint()
1603              
1604             This method attempts to guess what version string to use when
1605             communicating with various endpoints. When talking to endpoints that
1606             contain the string "Eucalyptus" uses the old EC2 API
1607             "2009-04-04". When talking to other endpoints, uses the latest EC2
1608             version string.
1609              
1610             =cut
1611              
1612             sub guess_version_from_endpoint {
1613             my $self = shift;
1614             my $endpoint = $self->endpoint;
1615             return '2009-04-04' if $endpoint =~ /Eucalyptus/; # eucalyptus version according to http://www.eucalyptus.com/participate/code
1616             return '2013-07-15'; # most recent AWS version that we support
1617             }
1618              
1619             =head2 $ts = $ec2->timestamp
1620              
1621             =cut
1622              
1623             sub timestamp {
1624             return strftime("%Y-%m-%dT%H:%M:%SZ",gmtime);
1625             }
1626              
1627              
1628             =head2 @obj = $ec2->call($action,@param);
1629              
1630             Make a call to Amazon using $action and the passed arguments, and
1631             return a list of objects.
1632              
1633             if $VM::EC2::ASYNC is set to true, then will return a
1634             AnyEvent::CondVar object instead of a list of objects. You may
1635             retrieve the objects by calling recv() or setting a callback:
1636              
1637             $VM::EC2::ASYNC = 1;
1638             my $cv = $ec2->call('DescribeInstances');
1639             my @obj = $cv->recv;
1640              
1641             or
1642              
1643             $VM::EC2::ASYNC = 1;
1644             my $cv = $ec2->call('DescribeInstances');
1645             $cv->cb(sub { my @objs = shift->recv;
1646             do_something(@objs);
1647             });
1648              
1649             =cut
1650              
1651             sub call {
1652             my $self = shift;
1653             return $ASYNC ? $self->_call_async(@_) : $self->_call_sync(@_);
1654             }
1655             sub _call_sync {
1656             my $self = shift;
1657             my $cv = $self->_call_async(@_);
1658             my @obj = $cv->recv;
1659             $self->error($cv->error) if $cv->error;
1660             if (!wantarray) { # scalar context
1661             return $obj[0] if @obj == 1;
1662             return if @obj == 0;
1663             return @obj;
1664             } else {
1665             return @obj;
1666             }
1667             }
1668              
1669             sub _call_async {
1670             my $self = shift;
1671             my ($action,@param) = @_;
1672             my $post = $self->_signature(Action=>$action,@param);
1673             my $u = URI->new($self->endpoint);
1674             $u->query_form(@$post);
1675             $self->async_post($action,$self->endpoint,$u->query);
1676             }
1677              
1678             sub async_post {
1679             my $self = shift;
1680             my ($action,$endpoint,$query) = @_;
1681              
1682             my $cv = $self->condvar;
1683             my $callback = sub {
1684             my $timer = shift;
1685             http_post($endpoint,
1686             $query,
1687             headers => {
1688             'Content-Type' => 'application/x-www-form-urlencoded',
1689             'User-Agent' => 'VM::EC2-perl',
1690             },
1691             sub {
1692             my ($body,$hdr) = @_;
1693             if ($hdr->{Status} !~ /^2/) { # an error
1694             if ($body =~ /RequestLimitExceeded/) {
1695             warn "RequestLimitExceeded. Retry in ",$timer->next_interval()," seconds\n";
1696             $timer->retry();
1697             return;
1698             } else {
1699             $self->async_send_error($action,$hdr,$body,$cv);
1700             $timer->success();
1701             return;
1702             }
1703             } else { # success
1704             $self->error(undef);
1705             my @obj = VM::EC2::Dispatch->content2objects($action,$body,$self);
1706             $cv->send(@obj);
1707             $timer->success();
1708             }
1709             })
1710             };
1711             RetryTimer->new(on_retry => $callback,
1712             interval => 1,
1713             max_retries => 12,
1714             on_max_retries => sub { $cv->error(VM::EC2::Error->new({Code=>500,Message=>'RequestLimitExceeded'},$self)) });
1715              
1716             return $cv;
1717             }
1718              
1719             sub async_send_error {
1720             my $self = shift;
1721             my ($action,$hdr,$body,$cv) = @_;
1722             my $error;
1723              
1724             if ($body =~ //) {
1725             $error = VM::EC2::Dispatch->create_error_object($body,$self,$action);
1726             } elsif ($body =~ / 1727             $error = VM::EC2::Dispatch->create_alt_error_object($body,$self,$action);
1728             } else {
1729             my $code = $hdr->{Status};
1730             my $msg = $code =~ /^59[0-9]/ ? $hdr->{Reason} : $body;
1731             $error = VM::EC2::Error->new({Code=>$code,Message=>"$msg, at API call '$action')"},$self);
1732             }
1733              
1734             $cv->error($error);
1735              
1736             # this is probably not want we want to do, because it will cause error messages to
1737             # appear in random places nested into some deep callback.
1738             carp "$error" if $self->print_error;
1739              
1740             if ($self->raise_error) {
1741             $cv->croak($error);
1742             } else {
1743             $cv->send;
1744             }
1745             }
1746              
1747             sub signin_call {
1748             my $self = shift;
1749             my ($action,%args) = @_;
1750             my $endpoint = 'https://signin.aws.amazon.com/federation';
1751              
1752             $args{'Action'} = $action;
1753              
1754             my @param;
1755             for my $p (sort keys %args) {
1756             push @param , join '=' , map { uri_escape($_,"^A-Za-z0-9\-_.~") } ($p,$args{$p});
1757             }
1758            
1759             my $request = GET "$endpoint?" . join '&', @param;
1760              
1761             my $response = $self->ua->request($request);
1762              
1763             return JSON::decode_json($response->content);
1764             }
1765              
1766             =head2 $url = $ec2->login_url(-credentials => $credentials, -issuer => $issuer_url, -destination => $console_url);
1767              
1768             Returns an HTTP::Request object that points to the URL to login a user with STS credentials
1769              
1770             -credentials => $fed_token->credentials - Credentials from an $ec2->get_federation_token call
1771             -token => $token - a SigninToken from $ec2->get_signin_token call
1772             -issuer => $issuer_url
1773             -destination => $console_url - URL of the AWS console. Defaults to https://console.aws.amazon.com/console/home
1774             -auto_scaling_group_names List of auto scaling groups to describe
1775             -names Alias of -auto_scaling_group_names
1776              
1777             -credentials or -token are required for this method to work
1778              
1779             Usage can be:
1780              
1781             my $fed_token = $ec2->get_federation_token(...);
1782             my $token = $ec2->get_signin_token(-credentials => $fed_token->credentials);
1783             my $url = $ec2->login_url(-token => $token->{SigninToken}, -issuer => $issuer_url, -destination => $console_url);
1784              
1785             Or:
1786              
1787             my $fed_token = $ec2->get_federation_token(...);
1788             my $url = $ec2->login_url(-credentials => $fed_token->credentials, -issuer => $issuer_url, -destination => $console_url);
1789              
1790             =cut
1791              
1792             sub login_url {
1793             my $self = shift;
1794             my %args = @_;
1795             my $endpoint = 'https://signin.aws.amazon.com/federation';
1796              
1797             my %parms;
1798             $parms{Action} = 'login';
1799             $parms{Destination} = $args{-destination} if ($args{-destination});
1800             $parms{Issuer} = $args{-issuer} if ($args{-issuer});
1801             $parms{SigninToken} = $args{-token} if ($args{-token});
1802              
1803             if (defined $args{-credentials} and not defined $parms{SigninToken}) {
1804             $parms{SigninToken} = $self->get_signin_token(-credentials => $args{-credentials})->{SigninToken};
1805             }
1806              
1807              
1808             my @param;
1809             for my $p (sort keys %parms) {
1810             push @param , join '=' , map { uri_escape($_,"^A-Za-z0-9\-_.~") } ($p,$parms{$p});
1811             }
1812              
1813             GET "$endpoint?" . join '&', @param;
1814             }
1815              
1816             =head2 $request = $ec2->_sign(@args)
1817              
1818             Create and sign an HTTP::Request.
1819              
1820             =cut
1821              
1822             # adapted from Jeff Kim's Net::Amazon::EC2 module
1823             sub _sign {
1824             my $self = shift;
1825             my $signature = $self->_signature(@_);
1826             return POST $self->endpoint,$signature;
1827             }
1828              
1829             sub _signature {
1830             my $self = shift;
1831             my @args = @_;
1832              
1833             my $action = 'POST';
1834             my $uri = URI->new($self->endpoint);
1835             my $host = $uri->host_port;
1836             $host =~ s/:(80|443)$//; # default ports will break
1837             my $path = $uri->path||'/';
1838              
1839             my %sign_hash = @args;
1840             $sign_hash{AWSAccessKeyId} = $self->id;
1841             $sign_hash{Timestamp} = $self->timestamp;
1842             $sign_hash{Version} = $self->version;
1843             $sign_hash{SignatureVersion} = 2;
1844             $sign_hash{SignatureMethod} = 'HmacSHA256';
1845             $sign_hash{SecurityToken} = $self->security_token if $self->security_token;
1846              
1847             my @param;
1848             my @parameter_keys = sort keys %sign_hash;
1849             for my $p (@parameter_keys) {
1850             push @param,join '=',map {uri_escape($_,"^A-Za-z0-9\-_.~")} ($p,$sign_hash{$p});
1851             }
1852             my $to_sign = join("\n",
1853             $action,$host,$path,join('&',@param));
1854             my $signature = encode_base64(hmac_sha256($to_sign,$self->secret),'');
1855             $sign_hash{Signature} = $signature;
1856             return [%sign_hash];
1857             }
1858              
1859             =head2 @param = $ec2->args(ParamName=>@_)
1860              
1861             Set up calls that take either method(-resource_id=>'foo') or method('foo').
1862              
1863             =cut
1864              
1865             sub args {
1866             my $self = shift;
1867             my $default_param_name = shift;
1868             return unless @_;
1869             return @_ if $_[0] =~ /^-/;
1870             return (-filter=>shift) if @_==1 && ref $_[0] && ref $_[0] eq 'HASH';
1871             return ($default_param_name => \@_);
1872             }
1873              
1874             sub condvar {
1875             bless AnyEvent->condvar,'VM::EC2::CondVar';
1876             }
1877              
1878             # utility - retry a call with exponential backoff until it succeeds
1879             package RetryTimer;
1880             use AnyEvent;
1881             use Carp 'croak';
1882              
1883             # try a subroutine multiple times with exponential backoff
1884             # until it succeeds. Subroutine must call timer's success() method
1885             # if it succeds, retry() otherwise.
1886              
1887             # Arguments
1888             # on_retry=>CODEREF,
1889             # on_max_retries=>CODEREF,
1890             # interval => $seconds, # defaults to 1
1891             # multiplier=>$fraction, # defaults to 1.5
1892             # max_retries=>$integer, # defaults to 10
1893             sub new {
1894             my $class = shift;
1895             my @args = @_;
1896              
1897             my $self;
1898             $self = bless {
1899             timer => AE::timer(0,0, sub {
1900             delete $self->{timer};
1901             $self->{on_retry}->($self) if $self->{on_retry};
1902             }),
1903             tries => 0,
1904             current_interval => 0,
1905             @args,
1906             },ref $class || $class;
1907              
1908             croak "need a on_retry argument" unless $self->{on_retry};
1909             $self->{interval} ||= 1;
1910             $self->{multiplier} ||= 1.5;
1911             $self->{max_retries} = 10 unless defined $self->{max_retries};
1912             return $self;
1913             }
1914              
1915             sub retry {
1916             my $self = shift;
1917             return if $self->{timer};
1918             $self->{current_interval} = $self->next_interval;
1919             $self->{tries}++;
1920              
1921             if ($self->{max_retries} && $self->{max_retries} <= $self->{tries}) {
1922             delete $self->{timer};
1923             delete $self->{current_interval};
1924             $self->{on_max_retries}->($self) if $self->{on_max_retries};
1925             return;
1926             }
1927             $self->{timer} = AE::timer ($self->{current_interval},0,
1928             sub {
1929             delete $self->{timer};
1930             $self->{on_retry}->($self)
1931             if $self && $self->{on_retry};
1932             });
1933             }
1934              
1935             sub next_interval {
1936             my $self = shift;
1937             if ($self->{current_interval}) {
1938             return $self->{current_interval} * $self->{multiplier};
1939             } else {
1940             return $self->{interval};
1941             }
1942             }
1943              
1944             sub current_interval { shift->{current_interval} };
1945              
1946             sub success {
1947             my $self = shift;
1948             delete $self->{current_interval};
1949             delete $self->{timer};
1950             }
1951              
1952             package VM::EC2::CondVar;
1953             use base 'AnyEvent::CondVar';
1954              
1955             sub error {
1956             my $self = shift;
1957             my $d = $self->{error};
1958             $self->{error} = shift if @_;
1959             return $d;
1960             }
1961              
1962             sub recv {
1963             my $self = shift;
1964             my @obj = $self->SUPER::recv;
1965             if (!wantarray) { # scalar context
1966             return $obj[0] if @obj == 1;
1967             return if @obj == 0;
1968             return @obj;
1969             } else {
1970             return @obj;
1971             }
1972             }
1973              
1974             =head1 OTHER INFORMATION
1975              
1976             This section contains technical information that may be of interest to developers.
1977              
1978             =head2 Signing and authentication protocol
1979              
1980             This module uses Amazon AWS signing protocol version 2, as described at
1981             http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/index.html?using-query-api.html.
1982             It uses the HmacSHA256 signature method, which is the most secure
1983             method currently available. For additional security, use "https" for
1984             the communications endpoint:
1985              
1986             $ec2 = VM::EC2->new(-endpoint=>'https://ec2.amazonaws.com');
1987              
1988             =head2 Subclassing VM::EC2 objects
1989              
1990             To subclass VM::EC2 objects (or implement your own from scratch) you
1991             will need to override the object dispatch mechanism. Fortunately this
1992             is very easy. After "use VM::EC2" call
1993             VM::EC2::Dispatch->register() one or more times:
1994              
1995             VM::EC2::Dispatch->register($call_name => $dispatch).
1996              
1997             The first argument, $call_name, is name of the Amazon API call, such as "DescribeImages".
1998              
1999             The second argument, $dispatch, instructs VM::EC2::Dispatch how to
2000             create objects from the parsed XML. There are three possible syntaxes:
2001              
2002             1) A CODE references, such as an anonymous subroutine.
2003              
2004             In this case the code reference will be invoked to handle the
2005             parsed XML returned from the request. The code will receive
2006             two arguments consisting of the parsed
2007             content of the response, and the VM::EC2 object used to generate the
2008             request.
2009              
2010             2) A VM::EC2::Dispatch method name, optionally followed by its arguments
2011             delimited by commas. Example:
2012              
2013             "fetch_items,securityGroupInfo,VM::EC2::SecurityGroup"
2014              
2015             This tells Dispatch to invoke its fetch_items() method with
2016             the following arguments:
2017              
2018             $dispatch->fetch_items($parsed_xml,$ec2,'securityGroupInfo','VM::EC2::SecurityGroup')
2019              
2020             The fetch_items() method is used for responses in which a
2021             list of objects is embedded within a series of tags.
2022             See L for more information.
2023              
2024             Other commonly-used methods are "fetch_one", and "boolean".
2025              
2026             3) A class name, such as 'MyVolume'
2027              
2028             In this case, class MyVolume is loaded and then its new() method
2029             is called with the four arguments ($parsed_xml,$ec2,$xmlns,$requestid),
2030             where $parsed_xml is the parsed XML response, $ec2 is the VM::EC2
2031             object that generated the request, $xmlns is the XML namespace
2032             of the XML response, and $requestid is the AWS-generated ID for the
2033             request. Only the first two arguments are really useful.
2034              
2035             I suggest you inherit from VM::EC2::Generic and use the inherited new()
2036             method to store the parsed XML object and other arguments.
2037              
2038             Dispatch tries each of (1), (2) and (3), in order. This means that
2039             class names cannot collide with method names.
2040              
2041             The parsed content is the result of passing the raw XML through a
2042             XML::Simple object created with:
2043              
2044             XML::Simple->new(ForceArray => ['item'],
2045             KeyAttr => ['key'],
2046             SuppressEmpty => undef);
2047              
2048             In general, this will give you a hash of hashes. Any tag named 'item'
2049             will be forced to point to an array reference, and any tag named "key"
2050             will be flattened as described in the XML::Simple documentation.
2051              
2052             A simple way to examine the raw parsed XML is to invoke any
2053             VM::EC2::Generic's as_string() method:
2054              
2055             my ($i) = $ec2->describe_instances;
2056             print $i->as_string;
2057              
2058             This will give you a Data::Dumper representation of the XML after it
2059             has been parsed.
2060              
2061             The suggested way to override the dispatch table is from within a
2062             subclass of VM::EC2:
2063            
2064             package 'VM::EC2New';
2065             use base 'VM::EC2';
2066             sub new {
2067             my $self=shift;
2068             VM::EC2::Dispatch->register('call_name_1'=>\&subroutine1).
2069             VM::EC2::Dispatch->register('call_name_2'=>\&subroutine2).
2070             $self->SUPER::new(@_);
2071             }
2072              
2073             See L for a working example of subclassing VM::EC2
2074             and one of its object classes.
2075              
2076             =head1 DEVELOPING
2077              
2078             The git source for this library can be found at https://github.com/lstein/LibVM-EC2-Perl,
2079             To contribute to development, please obtain a github account and then either:
2080            
2081             1) Fork a copy of the repository, make your changes against this repository,
2082             and send a pull request to me to incorporate your changes.
2083              
2084             2) Contact me by email and ask for push privileges on the repository.
2085              
2086             See http://help.github.com/ for help getting started.
2087              
2088             =head1 SEE ALSO
2089              
2090             L
2091             L
2092             L
2093             L
2094             L
2095             L
2096             L
2097             L
2098             L
2099             L
2100             L
2101             L
2102             L
2103             L
2104             L
2105             L
2106             L
2107             L
2108             L
2109             L
2110             L
2111             L
2112             L
2113             L
2114             L
2115             L
2116             L
2117             L
2118             L
2119             L
2120             L
2121              
2122             =head1 AUTHOR
2123              
2124             Lincoln Stein Elincoln.stein@gmail.comE.
2125              
2126             Copyright (c) 2011 Ontario Institute for Cancer Research
2127              
2128             This package and its accompanying libraries is free software; you can
2129             redistribute it and/or modify it under the terms of the GPL (either
2130             version 1, or at your option, any later version) or the Artistic
2131             License 2.0. Refer to LICENSE for the full license text. In addition,
2132             please see DISCLAIMER.txt for disclaimers of warranty.
2133              
2134             =cut
2135              
2136              
2137             1;