PageRenderTime 47ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/VM/EC2/REST/ebs.pm

http://github.com/lstein/LibVM-EC2-Perl
Perl | 705 lines | 526 code | 178 blank | 1 comment | 46 complexity | 984ee11ba23959ba84ab150fa399912a MD5 | raw file
Possible License(s): AGPL-1.0
  1. package VM::EC2::REST::ebs;
  2. use strict;
  3. use VM::EC2 ''; # important not to import anything!
  4. package VM::EC2; # add methods to VM::EC2
  5. VM::EC2::Dispatch->register(
  6. AttachVolume => 'VM::EC2::BlockDevice::Attachment',
  7. CopySnapshot => sub { shift->{snapshotId} },
  8. CreateSnapshot => 'VM::EC2::Snapshot',
  9. CreateVolume => 'VM::EC2::Volume',
  10. DeleteSnapshot => 'boolean',
  11. DeleteVolume => 'boolean',
  12. DescribeAvailabilityZones => 'fetch_items,availabilityZoneInfo,VM::EC2::AvailabilityZone',
  13. DescribeImages => 'fetch_items,imagesSet,VM::EC2::Image',
  14. DescribeInstanceStatus => 'fetch_items_iterator,instanceStatusSet,VM::EC2::Instance::StatusItem,instance_status',
  15. DescribeRegions => 'fetch_items,regionInfo,VM::EC2::Region',
  16. DescribeSecurityGroups => 'fetch_items,securityGroupInfo,VM::EC2::SecurityGroup',
  17. DescribeSnapshots => 'fetch_items,snapshotSet,VM::EC2::Snapshot',
  18. DescribeVolumeStatus => 'fetch_items_iterator,volumeStatusSet,VM::EC2::Volume::StatusItem,volume_status',
  19. DescribeVolumes => 'fetch_items,volumeSet,VM::EC2::Volume',
  20. DetachVolume => 'VM::EC2::BlockDevice::Attachment',
  21. EnableVolumeIO => 'boolean',
  22. ModifySnapshotAttribute => 'boolean',
  23. ResetSnapshotAttribute => 'boolean',
  24. );
  25. my $VEP = 'VM::EC2::ParmParser';
  26. =head1 NAME
  27. VM::EC2::REST::ebs - Modules for EC2 EBS volumes
  28. =head1 SYNOPSIS
  29. use VM::EC2 ':standard';
  30. =head1 METHODS
  31. The methods in this section allow you to query and manipulate EC2 EBS
  32. volumes and snapshots. See L<VM::EC2::Volume> and L<VM::EC2::Snapshot>
  33. for additional functionality provided through the object interface.
  34. Implemented:
  35. AttachVolume
  36. CopySnapshot
  37. CreateSnapshot
  38. CreateVolume
  39. DeleteSnapshot
  40. DeleteVolume
  41. DescribeSnapshotAttribute
  42. DescribeSnapshots
  43. DescribeVolumes
  44. DescribeVolumeAttribute
  45. DescribeVolumeStatus
  46. DetachVolume
  47. EnableVolumeIO
  48. ModifySnapshotAttribute
  49. ModifyVolumeAttribute
  50. ResetSnapshotAttribute
  51. Unimplemented:
  52. (none)
  53. =head2 @v = $ec2->describe_volumes(-volume_id=>\@ids,-filter=>\%filters)
  54. =head2 @v = $ec2->describe_volumes(@volume_ids)
  55. Return a series of VM::EC2::Volume objects. Optional arguments:
  56. -volume_id The id of the volume to fetch, either a string
  57. scalar or an arrayref.
  58. -filter One or more filters to apply to the search
  59. The -filter argument name can be omitted if there are no other
  60. arguments you wish to pass.
  61. The full list of volume filters can be found at:
  62. http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeVolumes.html
  63. =cut
  64. sub describe_volumes {
  65. my $self = shift;
  66. my %args = $VEP->args(-volume_id,@_);
  67. my @params = $VEP->format_parms(\%args,
  68. {
  69. list_parm => 'VolumeId',
  70. filter_parm => 'Filter'
  71. });
  72. return $self->call('DescribeVolumes',@params);
  73. }
  74. =head2 $v = $ec2->create_volume(-availability_zone=>$zone,-snapshot_id=>$snapshotId,-size=>$size,-volume_type=>$type,-iops=>$iops,-encrypted=>$boolean)
  75. Create a volume in the specified availability zone and return
  76. information about it.
  77. Arguments:
  78. -availability_zone -- An availability zone from
  79. describe_availability_zones (required)
  80. -snapshot_id -- ID of a snapshot to use to build volume from.
  81. -size -- Size of the volume, in GB (between 1 and 1024).
  82. One or both of -snapshot_id or -size are required. For convenience,
  83. you may abbreviate -availability_zone as -zone, and -snapshot_id as
  84. -snapshot.
  85. Optional Arguments:
  86. -volume_type -- The volume type. "standard", "io1", or "gp2"
  87. Default is "standard"
  88. -iops -- The number of I/O operations per second (IOPS) that
  89. the volume supports. Range is 100 to 4000. Required
  90. when volume type is io1. IOPS must be 30-to-1 ratio
  91. to size. ie: 3000 IOPS volume must be at least 100GB.
  92. -encrypted -- Specifies whether the volume should be encrypted.
  93. Encrypted Amazon EBS volumes may only be attached to
  94. instances that support them. Volumes created from
  95. encrypted snapshots are also encrypted using the same
  96. key as the original volume.
  97. See: http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html
  98. The returned object is a VM::EC2::Volume object.
  99. =cut
  100. sub create_volume {
  101. my $self = shift;
  102. my %args = @_;
  103. $args{-availability_zone} ||= $args{-zone} or croak "-availability_zone argument is required";
  104. $args{-snapshot_id} ||= $args{-snapshot};
  105. $args{-snapshot_id} || $args{-size} or croak "One or both of -snapshot_id or -size are required";
  106. if (exists $args{-volume_type} && $args{-volume_type} eq 'io1') {
  107. $args{-iops} or croak "Argument -iops required when -volume_type is 'io1'";
  108. }
  109. elsif ($args{-iops}) {
  110. croak "Argument -iops cannot be used when volume type is 'standard'";
  111. }
  112. my @params = $VEP->format_parms(\%args,
  113. {
  114. single_parm => [qw(AvailabilityZone SnapshotId Size VolumeType Iops)],
  115. boolean_parm => 'Encrypted'
  116. });
  117. return $self->call('CreateVolume',@params);
  118. }
  119. =head2 $result = $ec2->delete_volume($volume_id);
  120. Deletes the specified volume. Returns a boolean indicating success of
  121. the delete operation. Note that a volume will remain in the "deleting"
  122. state for some time after this call completes.
  123. =cut
  124. sub delete_volume {
  125. my $self = shift;
  126. my %args = $VEP->args(-volume_id => @_);
  127. my @param = $VEP->format_parms(\%args,
  128. {
  129. single_parm => 'VolumeId'
  130. });
  131. return $self->call('DeleteVolume',@param);
  132. }
  133. =head2 $attachment = $ec2->attach_volume($volume_id,$instance_id,$device);
  134. =head2 $attachment = $ec2->attach_volume(-volume_id=>$volume_id,-instance_id=>$instance_id,-device=>$device);
  135. Attaches the specified volume to the instance using the indicated
  136. device. All arguments are required:
  137. -volume_id -- ID of the volume to attach. The volume must be in
  138. "available" state.
  139. -instance_id -- ID of the instance to attach to. Both instance and
  140. attachment must be in the same availability zone.
  141. -device -- How the device is exposed to the instance, e.g.
  142. '/dev/sdg'.
  143. The result is a VM::EC2::BlockDevice::Attachment object which
  144. you can monitor by calling current_status():
  145. my $a = $ec2->attach_volume('vol-12345','i-12345','/dev/sdg');
  146. while ($a->current_status ne 'attached') {
  147. sleep 2;
  148. }
  149. print "volume is ready to go\n";
  150. or more simply
  151. my $a = $ec2->attach_volume('vol-12345','i-12345','/dev/sdg');
  152. $ec2->wait_for_attachments($a);
  153. =cut
  154. sub attach_volume {
  155. my $self = shift;
  156. my %args;
  157. if ($_[0] !~ /^-/ && @_ == 3) {
  158. @args{qw(-volume_id -instance_id -device)} = @_;
  159. } else {
  160. %args = @_;
  161. }
  162. $args{-volume_id} && $args{-instance_id} && $args{-device} or
  163. croak "-volume_id, -instance_id and -device arguments must all be specified";
  164. my @param = $VEP->format_parms(\%args,
  165. {
  166. single_parm => [qw(VolumeId InstanceId Device)]
  167. });
  168. return $self->call('AttachVolume',@param);
  169. }
  170. =head2 $attachment = $ec2->detach_volume($volume_id)
  171. =head2 $attachment = $ec2->detach_volume(-volume_id=>$volume_id,-instance_id=>$instance_id,
  172. -device=>$device, -force=>$force);
  173. Detaches the specified volume from an instance.
  174. -volume_id -- ID of the volume to detach. (required)
  175. -instance_id -- ID of the instance to detach from. (optional)
  176. -device -- How the device is exposed to the instance. (optional)
  177. -force -- Force detachment, even if previous attempts were
  178. unsuccessful. (optional)
  179. The result is a VM::EC2::BlockDevice::Attachment object which
  180. you can monitor by calling current_status():
  181. my $a = $ec2->detach_volume('vol-12345');
  182. while ($a->current_status ne 'detached') {
  183. sleep 2;
  184. }
  185. print "volume is ready to go\n";
  186. Or more simply:
  187. my $a = $ec2->detach_volume('vol-12345');
  188. $ec2->wait_for_attachments($a);
  189. print "volume is ready to go\n" if $a->current_status eq 'detached';
  190. =cut
  191. sub detach_volume {
  192. my $self = shift;
  193. my %args = $VEP->args(-volume_id => @_);
  194. my @param = $VEP->format_parms(\%args,
  195. {
  196. single_parm => [qw(VolumeId InstanceId Device)],
  197. boolean_parm => 'Force'
  198. });
  199. return $self->call('DetachVolume',@param);
  200. }
  201. =head2 $ec2->wait_for_attachments(@attachment)
  202. Wait for all members of the provided list of
  203. VM::EC2::BlockDevice::Attachment objects to reach some terminal state
  204. ("attached" or "detached"), and then return a hash reference that maps
  205. each attachment to its final state.
  206. Typical usage:
  207. my $i = 0;
  208. my $instance = 'i-12345';
  209. my @attach;
  210. foreach (@volume) {
  211. push @attach,$_->attach($instance,'/dev/sdf'.$i++;
  212. }
  213. my $s = $ec2->wait_for_attachments(@attach);
  214. my @failed = grep($s->{$_} ne 'attached'} @attach;
  215. warn "did not attach: ",join ', ',@failed;
  216. If no terminal state is reached within a set timeout, then this method
  217. returns undef and sets $ec2->error_str() to a suitable message. The
  218. timeout, which defaults to 10 minutes (600 seconds), can be get or set
  219. with $ec2->wait_for_timeout().
  220. =cut
  221. sub wait_for_attachments {
  222. my $self = shift;
  223. $self->wait_for_terminal_state(\@_,
  224. ['attached','detached'],
  225. $self->wait_for_timeout);
  226. }
  227. =head2 @v = $ec2->describe_volume_status(@volume_ids)
  228. =head2 @v = $ec2->describe_volume_status(\%filters)
  229. =head2 @v = $ec2->describe_volume_status(-volume_id=>\@ids,-filter=>\%filters)
  230. Return a series of VM::EC2::Volume::StatusItem objects. Optional arguments:
  231. -volume_id The id of the volume to fetch, either a string
  232. scalar or an arrayref.
  233. -filter One or more filters to apply to the search
  234. -max_results Maximum number of items to return (must be more than
  235. 5).
  236. The -filter argument name can be omitted if there are no other
  237. arguments you wish to pass.
  238. The full list of volume filters can be found at:
  239. http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeVolumeStatus.html
  240. If -max_results is specified, then the call will return at most the
  241. number of volume status items you requested. You may see whether there
  242. are additional results by calling more_volume_status(), and then
  243. retrieve the next set of results with additional call(s) to
  244. describe_volume_status():
  245. my @results = $ec2->describe_volume_status(-max_results => 10);
  246. do_something(\@results);
  247. while ($ec2->more_volume_status) {
  248. @results = $ec2->describe_volume_status;
  249. do_something(\@results);
  250. }
  251. =cut
  252. sub more_volume_status {
  253. my $self = shift;
  254. return $self->{volume_status_token} &&
  255. !$self->{volume_status_stop};
  256. }
  257. sub describe_volume_status {
  258. my $self = shift;
  259. my @parms;
  260. if (!@_ && $self->{volume_status_token} && $self->{volume_status_args}) {
  261. @parms = (@{$self->{volume_status_args}},NextToken=>$self->{volume_status_token});
  262. }
  263. else {
  264. my %args = $VEP->args('-volume_id',@_);
  265. my @parms = $VEP->format_parms(\%args,
  266. {
  267. list_parm => 'VolumeId',
  268. filter_parm => 'Filter',
  269. single_parm => 'MaxResults'
  270. });
  271. if ($args{-max_results}) {
  272. $self->{volume_status_token} = 'xyzzy'; # dummy value
  273. $self->{volume_status_args} = \@parms;
  274. }
  275. }
  276. return $self->call('DescribeVolumeStatus',@parms);
  277. }
  278. =head2 $ec2->wait_for_volumes(@volumes)
  279. Wait for all members of the provided list of volumes to reach some
  280. terminal state ("available", "in-use", "deleted" or "error"), and then
  281. return a hash reference that maps each volume ID to its final state.
  282. If no terminal state is reached within a set timeout, then this method
  283. returns undef and sets $ec2->error_str() to a suitable message. The
  284. timeout, which defaults to 10 minutes (600 seconds), can be get or set
  285. with $ec2->wait_for_timeout().
  286. =cut
  287. sub wait_for_volumes {
  288. my $self = shift;
  289. $self->wait_for_terminal_state(\@_,
  290. ['available','in-use','deleted','error'],
  291. $self->wait_for_timeout);
  292. }
  293. =head2 @data = $ec2->describe_volume_attribute($volume_id,$attribute)
  294. This method returns volume attributes. Only one attribute can be
  295. retrieved at a time. The following is the list of attributes that can be
  296. retrieved:
  297. autoEnableIO -- boolean
  298. productCodes -- list of scalar
  299. These values can be retrieved more conveniently from the
  300. L<VM::EC2::Volume> object returned from describe_volumes():
  301. $volume->auto_enable_io(1);
  302. @codes = $volume->product_codes;
  303. =cut
  304. sub describe_volume_attribute {
  305. my $self = shift;
  306. @_ == 2 or croak "Usage: describe_volume_attribute(\$instance_id,\$attribute_name)";
  307. my ($instance_id,$attribute) = @_;
  308. my @param = (VolumeId=>$instance_id,Attribute=>$attribute);
  309. my $result = $self->call('DescribeVolumeAttribute',@param);
  310. return $result && $result->attribute($attribute);
  311. }
  312. sub modify_volume_attribute {
  313. my $self = shift;
  314. my $volume_id = shift or croak "Usage: modify_volume_attribute(\$volumeId,%param)";
  315. my %args = @_;
  316. my @param = (VolumeId=>$volume_id);
  317. push @param,('AutoEnableIO.Value'=>$args{-auto_enable_io} ? 'true':'false');
  318. return $self->call('ModifyVolumeAttribute',@param);
  319. }
  320. =head2 $boolean = $ec2->enable_volume_io($volume_id)
  321. =head2 $boolean = $ec2->enable_volume_io(-volume_id=>$volume_id)
  322. Given the ID of a volume whose I/O has been disabled (e.g. due to
  323. hardware degradation), this method will reenable the I/O and return
  324. true if successful.
  325. =cut
  326. sub enable_volume_io {
  327. my $self = shift;
  328. my %args = $self->args('-volume_id',@_);
  329. $args{-volume_id} or croak "Usage: enable_volume_io(\$volume_id)";
  330. my @param = $self->single_parm('VolumeId',\%args);
  331. return $self->call('EnableVolumeIO',@param);
  332. }
  333. =head2 @snaps = $ec2->describe_snapshots(@snapshot_ids)
  334. =head2 @snaps = $ec2->describe_snapshots(-snapshot_id=>\@ids,%other_args)
  335. Returns a series of VM::EC2::Snapshot objects. All arguments
  336. are optional:
  337. -snapshot_id ID of the snapshot
  338. -owner Filter by owner ID
  339. -restorable_by Filter by IDs of a user who is allowed to restore
  340. the snapshot
  341. -filter Tags and other filters
  342. The -filter argument name can be omitted if there are no other
  343. arguments you wish to pass.
  344. The full list of applicable filters can be found at
  345. http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeSnapshots.html
  346. =cut
  347. sub describe_snapshots {
  348. my $self = shift;
  349. my %args = $VEP->args('-snapshot_id',@_);
  350. my @params = $VEP->format_parms(\%args,
  351. {
  352. list_parm => [qw(SnapshotId Owner RestorableBy)],
  353. filter_parm => 'Filter'
  354. });
  355. return $self->call('DescribeSnapshots',@params);
  356. }
  357. =head2 @data = $ec2->describe_snapshot_attribute($snapshot_id,$attribute)
  358. This method returns snapshot attributes. The first argument is the
  359. snapshot ID, and the second is the name of the attribute to
  360. fetch. Currently Amazon defines two attributes:
  361. createVolumePermission -- return a list of user Ids who are
  362. allowed to create volumes from this snapshot.
  363. productCodes -- product codes for this snapshot
  364. The result is a raw hash of attribute values. Please see
  365. L<VM::EC2::Snapshot> for a more convenient way of accessing and
  366. modifying snapshot attributes.
  367. =cut
  368. sub describe_snapshot_attribute {
  369. my $self = shift;
  370. @_ == 2 or croak "Usage: describe_snapshot_attribute(\$instance_id,\$attribute_name)";
  371. my ($snapshot_id,$attribute) = @_;
  372. my @param = (SnapshotId=>$snapshot_id,Attribute=>$attribute);
  373. my $result = $self->call('DescribeSnapshotAttribute',@param);
  374. return $result && $result->attribute($attribute);
  375. }
  376. =head2 $boolean = $ec2->modify_snapshot_attribute($snapshot_id,-$argument=>$value)
  377. This method changes snapshot attributes. The first argument is the
  378. snapshot ID, and this is followed by an attribute modification command
  379. and the value to change it to.
  380. Currently the only attribute that can be changed is the
  381. createVolumeAttribute. This is done through the following arguments
  382. -createvol_add_user -- scalar or arrayref of UserIds to grant create volume permissions to
  383. -createvol_add_group -- scalar or arrayref of Groups to remove create volume permissions from
  384. (only currently valid value is "all")
  385. -createvol_remove_user -- scalar or arrayref of UserIds to remove from create volume permissions
  386. -createvol_remove_group -- scalar or arrayref of Groups to remove from create volume permissions
  387. You can abbreviate these to -add_user, -add_group, -remove_user, -remove_group, etc.
  388. See L<VM::EC2::Snapshot> for more convenient methods for interrogating
  389. and modifying the create volume permissions.
  390. =cut
  391. sub modify_snapshot_attribute {
  392. my $self = shift;
  393. my $snapshot_id = shift or croak "Usage: modify_snapshot_attribute(\$snapshotId,%param)";
  394. my %args = @_;
  395. # shortcuts
  396. foreach (qw(add_user remove_user add_group remove_group)) {
  397. $args{"-createvol_$_"} ||= $args{"-$_"};
  398. }
  399. my @param = (SnapshotId=>$snapshot_id);
  400. push @param,$self->create_volume_perm_parm('Add','UserId', $args{-createvol_add_user});
  401. push @param,$self->create_volume_perm_parm('Remove','UserId',$args{-createvol_remove_user});
  402. push @param,$self->create_volume_perm_parm('Add','Group', $args{-createvol_add_group});
  403. push @param,$self->create_volume_perm_parm('Remove','Group', $args{-createvol_remove_group});
  404. return $self->call('ModifySnapshotAttribute',@param);
  405. }
  406. =head2 $boolean = $ec2->reset_snapshot_attribute($snapshot_id,$attribute)
  407. This method resets an attribute of the given snapshot to its default
  408. value. The only valid attribute at this time is
  409. "createVolumePermission."
  410. =cut
  411. sub reset_snapshot_attribute {
  412. my $self = shift;
  413. @_ == 2 or
  414. croak "Usage: reset_snapshot_attribute(\$snapshotId,\$attribute_name)";
  415. my ($snapshot_id,$attribute) = @_;
  416. my %valid = map {$_=>1} qw(createVolumePermission);
  417. $valid{$attribute} or croak "attribute to reset must be 'createVolumePermission'";
  418. return $self->call('ResetSnapshotAttribute',
  419. SnapshotId => $snapshot_id,
  420. Attribute => $attribute);
  421. }
  422. =head2 $snapshot = $ec2->create_snapshot($volume_id)
  423. =head2 $snapshot = $ec2->create_snapshot(-volume_id=>$vol,-description=>$desc)
  424. Snapshot the EBS volume and store it to S3 storage. To ensure a
  425. consistent snapshot, the volume should be unmounted prior to
  426. initiating this operation.
  427. Arguments:
  428. -volume_id -- ID of the volume to snapshot (required)
  429. -description -- A description to add to the snapshot (optional)
  430. The return value is a VM::EC2::Snapshot object that can be queried
  431. through its current_status() interface to follow the progress of the
  432. snapshot operation.
  433. Another way to accomplish the same thing is through the
  434. VM::EC2::Volume interface:
  435. my $volume = $ec2->describe_volumes(-filter=>{'tag:Name'=>'AccountingData'});
  436. $s = $volume->create_snapshot("Backed up at ".localtime);
  437. while ($s->current_status eq 'pending') {
  438. print "Progress: ",$s->progress,"% done\n";
  439. }
  440. print "Snapshot status: ",$s->current_status,"\n";
  441. =cut
  442. sub create_snapshot {
  443. my $self = shift;
  444. my %args = $VEP->args('-volume_id',@_);
  445. my @params = $VEP->format_parms(\%args,
  446. {
  447. single_parm => ['VolumeId','Description']
  448. });
  449. return $self->call('CreateSnapshot',@params);
  450. }
  451. =head2 $boolean = $ec2->delete_snapshot($snapshot_id)
  452. Delete the indicated snapshot and return true if the request was
  453. successful.
  454. =cut
  455. sub delete_snapshot {
  456. my $self = shift;
  457. my %args = $VEP->args('-snapshot_id',@_);
  458. my @params = $VEP->format_parms(\%args,
  459. {
  460. single_parm => 'SnapshotId'
  461. });
  462. return $self->call('DeleteSnapshot',@params);
  463. }
  464. =head2 $snapshot = $ec2->copy_snapshot(-source_region=>$region,-source_snapshot_id=>$id,-description=>$desc)
  465. =head2 $snapshot = $ec2->copy_snapshot(-region=>$region,-snapshot_id=>$id,-description=>$desc)
  466. Copies an existing snapshot within the same region or from one region to another.
  467. Required arguments:
  468. -source_region -- The region the existing snapshot to copy resides in
  469. -source_snapshot_id -- The snapshot ID of the snapshot to copy
  470. -region -- Alias for -source_region
  471. -snapshot_id -- Alias for -source_snapshot_id
  472. Currently, the DestinationRegion and PresignedUrl API arguments are not
  473. supported. Therefore, copying encrypted snapshots between regions is
  474. not yet possible.
  475. Optional arguments:
  476. -description -- A description of the new snapshot
  477. The return value is a VM::EC2::Snapshot object that can be queried
  478. through its current_status() interface to follow the progress of the
  479. snapshot operation.
  480. =cut
  481. sub copy_snapshot {
  482. my $self = shift;
  483. my %args = @_;
  484. $args{-description} ||= $args{-desc};
  485. $args{-source_region} ||= $args{-region};
  486. $args{-source_snapshot_id} ||= $args{-snapshot_id};
  487. $args{-source_region} or croak "copy_snapshot(): -source_region argument required";
  488. $args{-source_snapshot_id} or croak "copy_snapshot(): -source_snapshot_id argument required";
  489. my @params = $VEP->format_parms(\%args,
  490. {
  491. single_parm => [qw(SourceRegion SourceSnapshotId Description)]
  492. });
  493. my $snap_id = $self->call('CopySnapshot',@params) or return;
  494. return eval {
  495. my $snapshot;
  496. local $SIG{ALRM} = sub {die "timeout"};
  497. alarm(60);
  498. until ($snapshot = $self->describe_snapshots($snap_id)) { sleep 1 }
  499. alarm(0);
  500. $snapshot;
  501. };
  502. }
  503. =head2 $ec2->wait_for_snapshots(@snapshots)
  504. Wait for all members of the provided list of snapshots to reach some
  505. terminal state ("completed", "error"), and then return a hash
  506. reference that maps each snapshot ID to its final state.
  507. This method may potentially wait forever. It has no set timeout. Wrap
  508. it in an eval{} and set alarm() if you wish to timeout.
  509. =cut
  510. sub wait_for_snapshots {
  511. my $self = shift;
  512. $self->wait_for_terminal_state(\@_,
  513. ['completed','error'],
  514. 0); # no timeout on snapshots -- they may take days
  515. }
  516. =head1 SEE ALSO
  517. L<VM::EC2>
  518. =head1 AUTHOR
  519. Lincoln Stein E<lt>lincoln.stein@gmail.comE<gt>.
  520. Copyright (c) 2011 Ontario Institute for Cancer Research
  521. This package and its accompanying libraries is free software; you can
  522. redistribute it and/or modify it under the terms of the GPL (either
  523. version 1, or at your option, any later version) or the Artistic
  524. License 2.0. Refer to LICENSE for the full license text. In addition,
  525. please see DISCLAIMER.txt for disclaimers of warranty.
  526. =cut
  527. 1;