Net-Amazon-EC2-0.24/000755 000765 000024 00000000000 12251246040 014366 5ustar00mallenstaff000000 000000 Net-Amazon-EC2-0.24/Changelog000644 000765 000024 00000006752 12251245141 016213 0ustar00mallenstaff000000 000000 0.24 2013-12-08 Jim Browne Add filter support to describe_snapshots Jim Browne Add support for IAM roles (RT #81664) Graham Knop Add stringification overloads to errors Graham Knop Follow Amazon's signing rules more closely Jim Browne Fix a spurious warn Masaaki Hirose Support BlockDeviceMapping in create_image Jim Browne Support IAM roles in run_instances Vincert K Add optional parameter 'AddressingType' to run_instance Brett Paden Tweak run_instance method to use group_id 0.23 2013-01-01 Mark Allen Decouple CIDR IPs from security groups (RT #80427) Mark Allen Allow undefs in region name (RT #81513) Etienne Michon Allow undefs in group_name (Github PR #16) Mark Allen Add AllocationId support for VPC/EIP (RT #82139) 0.22 2012-10-26 Mark Allen Use AWS signature v2 and SSL by default (RT #80407) Mark Allen Add URI::Escape, POSIX, Digest::SHA dependencies for signature v2. LWP::Protocol::https now required for SSL support. 0.21 2012-10-22 Mark Allen Allow undef or arrayref in AvailabilityZone Mark Phillips Update InstanceType docs Stephen Caldwell Support VolumeType and Iops on EBS volumes Mark Allen DeleteSnapshot does not take an array (Github Issue #13) Mark Allen Allow undef in TagSet values (RT#80071) 0.20 2012-08-10 Mark Allen Stop failing test 0.19 2012-08-08 Mark Allen Make filters optional on describe_tags as docs say RT#76140 Mark Allen Force XML::Simple to make empty elements undef RT#76139 Miquel Ruiz Support exceptions via croak Allard Hoeve Support tagsets on volumes Mark Allen Allow modify_instance_attribute to use a HASHREF Fixes RT #78779 (thanks to Andrew Solomon for the suggestion.) 0.18 2012-02-21 Chia-liang Kao Fix timestamp clear (RT#75194) 0.17 2012-02-20 Chia-liang Kao Support Client Token Chia-liang Kao Support instance filters Chia-liang Kao Don't cache timestamps (to prevent timeout errors) Chia-liang Kao Fix a problem with XML::Simple deserialization of empty value in image description Mark Allen Spelling fix RT #74239 0.16 2012-01-21 Mark Allen Remove union type in ReservationInfo 0.15 2012-01-18 Mark Allen Fix groupSet params RT#67145 Mark Allen Support proxy environment variables RT#67145 Mark Allen Update doc for 0.15 Mark Fowler fix all warnings podchecker warns us about Mark Allen Make tag creation use a hash instead of arrayrefs Jeff Finucane documentation fix Jeff Finucane avoid 'Request has expired' on long lived Net::Amazon::EC2 objects Jeff Finucane add group_name to NAE::GroupSet and fix live test "Checking for running instance" Jeff Finucane add in ssl support as suggested by Brad Barden bradford.barden@supervalu.com stanaka Accept an array for resourceId. toritori0318 remove debug code toritori0318 add delete tags and tags test toritori0318 add describe tags and instance name. stanaka add create_tags stanaka import 0.14 from cpan Net-Amazon-EC2-0.24/inc/000755 000765 000024 00000000000 12251246040 015137 5ustar00mallenstaff000000 000000 Net-Amazon-EC2-0.24/lib/000755 000765 000024 00000000000 12251246040 015134 5ustar00mallenstaff000000 000000 Net-Amazon-EC2-0.24/Makefile.PL000644 000765 000024 00000001553 12064473057 016360 0ustar00mallenstaff000000 000000 # Load the Module::Install bundled in ./inc/ use inc::Module::Install; # Define metadata name 'Net-Amazon-EC2'; all_from 'lib/Net/Amazon/EC2.pm'; # Specific dependencies requires 'LWP::Protocol::https' => 0; requires 'Digest::SHA' => 0; requires 'MIME::Base64' => 0; requires 'LWP::UserAgent' => 0; requires 'POSIX' => 0; requires 'URI' => 0; requires 'URI::Escape' => 0; requires 'Params::Validate' => 0; requires 'XML::Simple' => 2.18; requires 'Moose' => 0.38; requires 'Carp' => 0; build_requires 'Test::More' => 0; build_requires 'Test::Exception' => 0; no_index; repository 'https://github.com/mrallen1/net-amazon-ec2'; auto_install; WriteAll; Net-Amazon-EC2-0.24/MANIFEST000644 000765 000024 00000004241 12011363607 015523 0ustar00mallenstaff000000 000000 Changelog inc/Module/AutoInstall.pm inc/Module/Install.pm inc/Module/Install/AutoInstall.pm inc/Module/Install/Base.pm inc/Module/Install/Can.pm inc/Module/Install/Fetch.pm inc/Module/Install/Include.pm inc/Module/Install/Makefile.pm inc/Module/Install/Metadata.pm inc/Module/Install/Win32.pm inc/Module/Install/WriteAll.pm lib/Net/Amazon/EC2.pm lib/Net/Amazon/EC2/Attachment.pm lib/Net/Amazon/EC2/AvailabilityZone.pm lib/Net/Amazon/EC2/AvailabilityZoneMessage.pm lib/Net/Amazon/EC2/BlockDeviceMapping.pm lib/Net/Amazon/EC2/BundleInstanceResponse.pm lib/Net/Amazon/EC2/ConfirmProductInstanceResponse.pm lib/Net/Amazon/EC2/ConsoleOutput.pm lib/Net/Amazon/EC2/CreateVolumePermission.pm lib/Net/Amazon/EC2/DescribeAddress.pm lib/Net/Amazon/EC2/DescribeImageAttribute.pm lib/Net/Amazon/EC2/DescribeImagesResponse.pm lib/Net/Amazon/EC2/DescribeInstanceAttributeResponse.pm lib/Net/Amazon/EC2/DescribeKeyPairsResponse.pm lib/Net/Amazon/EC2/DescribeTags.pm lib/Net/Amazon/EC2/EbsBlockDevice.pm lib/Net/Amazon/EC2/EbsInstanceBlockDeviceMapping.pm lib/Net/Amazon/EC2/Error.pm lib/Net/Amazon/EC2/Errors.pm lib/Net/Amazon/EC2/GroupSet.pm lib/Net/Amazon/EC2/InstanceBlockDeviceMapping.pm lib/Net/Amazon/EC2/InstancePassword.pm lib/Net/Amazon/EC2/InstanceState.pm lib/Net/Amazon/EC2/InstanceStateChange.pm lib/Net/Amazon/EC2/IpPermission.pm lib/Net/Amazon/EC2/IpRange.pm lib/Net/Amazon/EC2/KeyPair.pm lib/Net/Amazon/EC2/LaunchPermission.pm lib/Net/Amazon/EC2/LaunchPermissionOperation.pm lib/Net/Amazon/EC2/MonitoredInstance.pm lib/Net/Amazon/EC2/PlacementResponse.pm lib/Net/Amazon/EC2/ProductCode.pm lib/Net/Amazon/EC2/ProductInstanceResponse.pm lib/Net/Amazon/EC2/Region.pm lib/Net/Amazon/EC2/ReservationInfo.pm lib/Net/Amazon/EC2/ReservedInstance.pm lib/Net/Amazon/EC2/ReservedInstanceOffering.pm lib/Net/Amazon/EC2/RunningInstances.pm lib/Net/Amazon/EC2/SecurityGroup.pm lib/Net/Amazon/EC2/Snapshot.pm lib/Net/Amazon/EC2/SnapshotAttribute.pm lib/Net/Amazon/EC2/StateReason.pm lib/Net/Amazon/EC2/TagSet.pm lib/Net/Amazon/EC2/UserData.pm lib/Net/Amazon/EC2/UserIdGroupPair.pm lib/Net/Amazon/EC2/Volume.pm Makefile.PL MANIFEST This list of files META.yml README t/00_use.t t/01_init.t t/02_live.t t/03_failing_calls.t Net-Amazon-EC2-0.24/META.yml000644 000765 000024 00000001456 12251245726 015657 0ustar00mallenstaff000000 000000 --- abstract: 'Perl interface to the Amazon Elastic Compute Cloud (EC2)' author: - 'Jeff Kim ' build_requires: ExtUtils::MakeMaker: 6.36 Test::Exception: 0 Test::More: 0 configure_requires: ExtUtils::MakeMaker: 6.36 distribution_type: module dynamic_config: 1 generated_by: 'Module::Install version 1.06' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Net-Amazon-EC2 no_index: directory: - inc - t requires: Carp: 0 Digest::SHA: 0 LWP::Protocol::https: 0 LWP::UserAgent: 0 MIME::Base64: 0 Moose: 0.38 POSIX: 0 Params::Validate: 0 URI: 0 URI::Escape: 0 XML::Simple: 2.18 resources: license: http://dev.perl.org/licenses/ repository: https://github.com/mrallen1/net-amazon-ec2 version: 0.24 Net-Amazon-EC2-0.24/README000644 000765 000024 00000000572 12043032340 015245 0ustar00mallenstaff000000 000000 Net::Amazon::EC2 Perl interface to the Amazon Elastic Compute Cloud (EC2). INSTALLATION To install this module, run the following commands: perl Makefile.PL make make test make install COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. Copyright (c) 2012 Mark Allen This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Net-Amazon-EC2-0.24/t/000755 000765 000024 00000000000 12251246040 014631 5ustar00mallenstaff000000 000000 Net-Amazon-EC2-0.24/t/00_use.t000644 000765 000024 00000003401 12010634076 016112 0ustar00mallenstaff000000 000000 use strict; use blib; use Test::More; BEGIN { my @modules = qw( Net::Amazon::EC2::AvailabilityZone Net::Amazon::EC2::BlockDeviceMapping Net::Amazon::EC2::ConfirmProductInstanceResponse Net::Amazon::EC2::ConsoleOutput Net::Amazon::EC2::DescribeAddress Net::Amazon::EC2::DescribeImageAttribute Net::Amazon::EC2::DescribeImagesResponse Net::Amazon::EC2::DescribeKeyPairsResponse Net::Amazon::EC2::Error Net::Amazon::EC2::Errors Net::Amazon::EC2::GroupSet Net::Amazon::EC2::InstanceState Net::Amazon::EC2::IpPermission Net::Amazon::EC2::IpRange Net::Amazon::EC2::KeyPair Net::Amazon::EC2::LaunchPermission Net::Amazon::EC2::LaunchPermissionOperation Net::Amazon::EC2::PlacementResponse Net::Amazon::EC2::ProductCode Net::Amazon::EC2::ProductInstanceResponse Net::Amazon::EC2::ReservationInfo Net::Amazon::EC2::RunningInstances Net::Amazon::EC2::SecurityGroup Net::Amazon::EC2::UserData Net::Amazon::EC2::UserIdGroupPair Net::Amazon::EC2::Volume Net::Amazon::EC2::Attachment Net::Amazon::EC2::Snapshot Net::Amazon::EC2::BundleInstanceResponse Net::Amazon::EC2::Region Net::Amazon::EC2::ReservedInstance Net::Amazon::EC2::ReservedInstanceOffering Net::Amazon::EC2::MonitoredInstance Net::Amazon::EC2::InstancePassword Net::Amazon::EC2::SnapshotAttribute Net::Amazon::EC2::CreateVolumePermission Net::Amazon::EC2::AvailabilityZoneMessage Net::Amazon::EC2::StateReason Net::Amazon::EC2::InstanceBlockDeviceMapping Net::Amazon::EC2::InstanceStateChange Net::Amazon::EC2::DescribeInstanceAttributeResponse Net::Amazon::EC2::EbsInstanceBlockDeviceMapping Net::Amazon::EC2::EbsBlockDevice Net::Amazon::EC2::DescribeTags Net::Amazon::EC2::TagSet ); plan tests => scalar @modules; use_ok($_) for @modules; } Net-Amazon-EC2-0.24/t/01_init.t000644 000765 000024 00000000675 12010634076 016274 0ustar00mallenstaff000000 000000 use strict; use blib; use Test::More; BEGIN { if (! $ENV{AWS_ACCESS_KEY_ID} || ! $ENV{SECRET_ACCESS_KEY} ) { plan skip_all => "Set AWS_ACCESS_KEY_ID and SECRET_ACCESS_KEY environment variables to run these tests"; } else { plan tests => 1; use_ok( 'Net::Amazon::EC2' ); } }; my $ec2 = Net::Amazon::EC2->new( AWSAccessKeyId => $ENV{AWS_ACCESS_KEY_ID}, SecretAccessKey => $ENV{SECRET_ACCESS_KEY}, ); Net-Amazon-EC2-0.24/t/02_live.t000644 000765 000024 00000021555 12064502555 016276 0ustar00mallenstaff000000 000000 use strict; use blib; use Test::More; use MIME::Base64 qw(encode_base64); BEGIN { if (! $ENV{AWS_ACCESS_KEY_ID} || ! $ENV{SECRET_ACCESS_KEY} ) { plan skip_all => "Set AWS_ACCESS_KEY_ID and SECRET_ACCESS_KEY environment variables to run these _LIVE_ tests (NOTE: they will incur one instance hour of costs from EC2)"; } else { plan tests => 25; use_ok( 'Net::Amazon::EC2' ); } }; #try ssl first my $ec2 = eval { Net::Amazon::EC2->new( AWSAccessKeyId => $ENV{AWS_ACCESS_KEY_ID}, SecretAccessKey => $ENV{SECRET_ACCESS_KEY}, ssl => 1, debug => 0, return_errors => 1, ); }; $ec2 = Net::Amazon::EC2->new( AWSAccessKeyId => $ENV{AWS_ACCESS_KEY_ID}, SecretAccessKey => $ENV{SECRET_ACCESS_KEY}, debug => 0, return_errors => 1, ) if $@; isa_ok($ec2, 'Net::Amazon::EC2'); my $delete_key_result = $ec2->delete_key_pair(KeyName => "test_keys"); my $delete_group_result = $ec2->delete_security_group(GroupName => "test_group"); # create_key_pair my $key_pair = $ec2->create_key_pair(KeyName => "test_keys"); isa_ok($key_pair, 'Net::Amazon::EC2::KeyPair'); is($key_pair->key_name, "test_keys", "Does new key pair come back?"); # describe_key_pairs my $key_pairs = $ec2->describe_key_pairs; my $seen_test_key = 0; foreach my $key_pair (@{$key_pairs}) { if ($key_pair->key_name eq "test_keys") { $seen_test_key = 1; } } ok($seen_test_key == 1, "Checking for created key pair in describe keys"); # For cleanup purposes $ec2->delete_security_group(GroupName => "test_group"); # create_security_group my $create_result = $ec2->create_security_group(GroupName => "test_group", GroupDescription => "test description"); ok($create_result == 1, "Checking for created security group"); # authorize_security_group_ingress my $authorize_result = $ec2->authorize_security_group_ingress(GroupName => "test_group", IpProtocol => 'tcp', FromPort => '7003', ToPort => '7003', CidrIp => '10.253.253.253/32'); ok($authorize_result == 1, "Checking for authorization of rule for security group"); # Add this for RT Bug: #33883 my $authorize_result_bad = $ec2->authorize_security_group_ingress(GroupName => "test_group_non_existant", IpProtocol => 'tcp', FromPort => '7003', ToPort => '7003', CidrIp => '10.253.253.253/32'); isa_ok($authorize_result_bad, 'Net::Amazon::EC2::Errors'); # describe_security_groups my $security_groups = $ec2->describe_security_groups(); my $seen_test_group = 0; my $seen_test_rule = 0; foreach my $security_group (@{$security_groups}) { if ($security_group->group_name eq "test_group") { $seen_test_group = 1; if ($security_group->ip_permissions->[0]->ip_ranges->[0]->cidr_ip eq '10.253.253.253/32') { $seen_test_rule = 1; } } } ok($seen_test_group == 1, "Checking for created security group in describe results"); ok($seen_test_rule == 1, "Checking for created authorized security group rule in describe results"); # revoke_security_group_ingress my $revoke_result = $ec2->revoke_security_group_ingress(GroupName => "test_group", IpProtocol => 'tcp', FromPort => '7003', ToPort => '7003', CidrIp => '10.253.253.253/32'); ok($revoke_result == 1, "Checking for revocation of rule for security group"); my $user_data =<<_EOF; I am the very model of a modern Major-General, I've information vegetable, animal, and mineral, I know the kings of England, and I quote the fights historical From Marathon to Waterloo, in order categorical; I'm very well acquainted, too, with matters mathematical, I understand equations, both the simple and quadratical, About binomial theorem I'm teeming with a lot o' news, With many cheerful facts about the square of the hypotenuse. I'm very good at integral and differential calculus; I know the scientific names of beings animalculous: In short, in matters vegetable, animal, and mineral, I am the very model of a modern Major-General. I know our mythic history, King Arthur's and Sir Caradoc's; I answer hard acrostics, I've a pretty taste for paradox, I quote in elegiacs all the crimes of Heliogabalus, In conics I can floor peculiarities parabolous; I can tell undoubted Raphaels from Gerard Dows and Zoffanies, I know the croaking chorus from The Frogs of Aristophanes! Then I can hum a fugue of which I've heard the music's din afore, And whistle all the airs from that infernal nonsense Pinafore. Then I can write a washing bill in Babylonic cuneiform, And tell you ev'ry detail of Caractacus's uniform: In short, in matters vegetable, animal, and mineral, I am the very model of a modern Major-General. In fact, when I know what is meant by "mamelon" and "ravelin", When I can tell at sight a Mauser rifle from a Javelin, When such affairs as sorties and surprises I'm more wary at, And when I know precisely what is meant by "commissariat", When I have learnt what progress has been made in modern gunnery, When I know more of tactics than a novice in a nunnery— In short, when I've a smattering of elemental strategy— You'll say a better Major-General has never sat a gee. For my military knowledge, though I'm plucky and adventury, Has only been brought down to the beginning of the century; But still, in matters vegetable, animal, and mineral, I am the very model of a modern Major-General. _EOF # run_instances my $run_result = $ec2->run_instances( MinCount => 1, MaxCount => 1, ImageId => "ami-26b6534f", # ec2-public-images/developer-image.manifest.xml KeyName => "test_keys", SecurityGroup => "test_group", InstanceType => 'm1.small', UserData => encode_base64($user_data, ""), EbsOptimized => 0, ); isa_ok($run_result, 'Net::Amazon::EC2::ReservationInfo'); ok($run_result->group_set->[0]->group_name eq "test_group", "Checking for running instance"); my $instance_id = $run_result->instances_set->[0]->instance_id; # describe_instances my $running_instances = $ec2->describe_instances(); my $seen_test_instance = 0; foreach my $instance (@{$running_instances}) { my $instance_set = $instance->instances_set->[0]; my $key_name = $instance_set->key_name || ''; my $image_id = $instance_set->image_id || ''; if ($key_name eq 'test_keys' and $image_id eq 'ami-26b6534f') { $seen_test_instance = 1; } } ok($seen_test_instance == 1, "Checking for newly run instance"); # create tags my $create_tags_result = $ec2->create_tags( ResourceId => $instance_id, Tags => { Name => 'hoge', test_tag_key => 'test_tag_value', }, ); ok($create_tags_result == 1, "Checking for created tags"); # describe_instances $running_instances = $ec2->describe_instances(); my $test_instance; foreach my $instance (@{$running_instances}) { my $instance_set = $instance->instances_set->[0]; if ($instance_set->instance_id eq $instance_id) { $test_instance = $instance_set; last; } } # instance name is($test_instance->name, 'hoge', 'Checking for instance name'); # instance tags foreach my $tag (@{$test_instance->tag_set}) { if($tag->key eq 'Name' && $tag->value eq 'hoge') { ok(1, 'Checking for tag (Name=hoge)'); }elsif($tag->key eq 'test_tag_key' && $tag->value eq 'test_tag_value') { ok(1, 'Checking for tag (test_tag_key=test_tag_value)'); } } # delete tags my $delete_tags_result = $ec2->delete_tags( ResourceId => $instance_id, 'Tag.Key' => ["Name","test_tag_key"], ); ok($delete_tags_result == 1, "Checking for delete tags"); # terminate_instances my $terminate_result = $ec2->terminate_instances(InstanceId => $instance_id); is($terminate_result->[0]->instance_id, $instance_id, "Checking to see if instance was terminated successfully"); # delete_key_pair $delete_key_result = $ec2->delete_key_pair(KeyName => "test_keys"); ok($delete_key_result == 1, "Deleting key pair"); # delete_security_group $delete_group_result = $ec2->delete_security_group(GroupName => "test_group"); ok($delete_group_result == 1, "Deleting security group"); my $availability_zones = $ec2->describe_availability_zones(); my $seen_availability_zone = 0; foreach my $availability_zone (@{$availability_zones}) { if ($availability_zone->zone_name eq 'us-east-1a') { $seen_availability_zone = 1; } } ok($seen_availability_zone == 1, "Describing availability zones"); my $regions = $ec2->describe_regions(); my $seen_region = 0; foreach my $region (@{$regions}) { if ($region->region_name eq 'us-east-1') { $seen_region = 1; } } ok($seen_region == 1, "Describing regions"); my $reserved_instance_offerings = $ec2->describe_reserved_instances_offerings(); my $seen_offering = 0; foreach my $offering (@{$reserved_instance_offerings}) { if ($offering->product_description eq 'Linux/UNIX') { $seen_offering = 1; } } ok($seen_offering == 1, "Describing Reserved Instances Offerings"); # THE REST OF THE METHODS ARE SKIPPED FOR NOW SINCE IT WOULD REQUIRE A DECENT AMOUNT OF TIME IN BETWEEN OPERATIONS TO COMPLETE Net-Amazon-EC2-0.24/t/03_failing_calls.t000644 000765 000024 00000002222 12011363042 020101 0ustar00mallenstaff000000 000000 use strict; use blib; use Test::More; use Test::Exception; BEGIN { plan tests => 5; use_ok( 'Net::Amazon::EC2' ); }; # Since you don't have an Amazon EC2 api endpoint running locally # (you don't, right?) all api calls should fail, and thus allow us to # test it properly. my $access_id = 'xxx'; my $secret_key = 'yyy'; my $base_url = 'http://localhost:22718'; my $die_ec2 = Net::Amazon::EC2->new( AWSAccessKeyId => $access_id, SecretAccessKey => $secret_key, base_url => $base_url, ); my $old_ec2 = Net::Amazon::EC2->new( AWSAccessKeyId => $access_id, SecretAccessKey => $secret_key, base_url => $base_url, return_errors => 1, ); my $errors; lives_ok { $errors = $old_ec2->describe_instances } "return_errors on , api call lives"; dies_ok { $die_ec2->describe_instances } "return_errors off, api call dies"; is_deeply ($@, $errors, "Same error thrown and returned"); my $dbg_ec2 = Net::Amazon::EC2->new( AWSAccessKeyId => $access_id, SecretAccessKey => $secret_key, base_url => $base_url, debug => 1, ); dies_ok { $dbg_ec2->describe_instances } "with debug on also dies"; Net-Amazon-EC2-0.24/lib/Net/000755 000765 000024 00000000000 12251246040 015662 5ustar00mallenstaff000000 000000 Net-Amazon-EC2-0.24/lib/Net/Amazon/000755 000765 000024 00000000000 12251246040 017107 5ustar00mallenstaff000000 000000 Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/000755 000765 000024 00000000000 12251246040 017460 5ustar00mallenstaff000000 000000 Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2.pm000644 000765 000024 00000343021 12251245234 020025 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2; use Moose; use strict; use vars qw($VERSION); use XML::Simple; use LWP::UserAgent; use LWP::Protocol::https; use Digest::SHA qw(hmac_sha256); use URI; use MIME::Base64 qw(encode_base64 decode_base64); use POSIX qw(strftime); use Params::Validate qw(validate SCALAR ARRAYREF HASHREF); use Data::Dumper qw(Dumper); use URI::Escape qw(uri_escape_utf8); use Carp; use Net::Amazon::EC2::DescribeImagesResponse; use Net::Amazon::EC2::DescribeKeyPairsResponse; use Net::Amazon::EC2::GroupSet; use Net::Amazon::EC2::InstanceState; use Net::Amazon::EC2::IpPermission; use Net::Amazon::EC2::LaunchPermission; use Net::Amazon::EC2::LaunchPermissionOperation; use Net::Amazon::EC2::ProductCode; use Net::Amazon::EC2::ProductInstanceResponse; use Net::Amazon::EC2::ReservationInfo; use Net::Amazon::EC2::RunningInstances; use Net::Amazon::EC2::SecurityGroup; use Net::Amazon::EC2::UserData; use Net::Amazon::EC2::UserIdGroupPair; use Net::Amazon::EC2::IpRange; use Net::Amazon::EC2::KeyPair; use Net::Amazon::EC2::DescribeImageAttribute; use Net::Amazon::EC2::ConsoleOutput; use Net::Amazon::EC2::Errors; use Net::Amazon::EC2::Error; use Net::Amazon::EC2::ConfirmProductInstanceResponse; use Net::Amazon::EC2::DescribeAddress; use Net::Amazon::EC2::AvailabilityZone; use Net::Amazon::EC2::BlockDeviceMapping; use Net::Amazon::EC2::PlacementResponse; use Net::Amazon::EC2::Volume; use Net::Amazon::EC2::Attachment; use Net::Amazon::EC2::Snapshot; use Net::Amazon::EC2::BundleInstanceResponse; use Net::Amazon::EC2::Region; use Net::Amazon::EC2::ReservedInstance; use Net::Amazon::EC2::ReservedInstanceOffering; use Net::Amazon::EC2::MonitoredInstance; use Net::Amazon::EC2::InstancePassword; use Net::Amazon::EC2::SnapshotAttribute; use Net::Amazon::EC2::CreateVolumePermission; use Net::Amazon::EC2::AvailabilityZoneMessage; use Net::Amazon::EC2::StateReason; use Net::Amazon::EC2::InstanceBlockDeviceMapping; use Net::Amazon::EC2::InstanceStateChange; use Net::Amazon::EC2::DescribeInstanceAttributeResponse; use Net::Amazon::EC2::EbsInstanceBlockDeviceMapping; use Net::Amazon::EC2::EbsBlockDevice; use Net::Amazon::EC2::TagSet; use Net::Amazon::EC2::DescribeTags; $VERSION = '0.24'; =head1 NAME Net::Amazon::EC2 - Perl interface to the Amazon Elastic Compute Cloud (EC2) environment. =head1 VERSION This is Net::Amazon::EC2 version 0.24 EC2 Query API version: '2012-07-20' =head1 SYNOPSIS use Net::Amazon::EC2; my $ec2 = Net::Amazon::EC2->new( AWSAccessKeyId => 'PUBLIC_KEY_HERE', SecretAccessKey => 'SECRET_KEY_HERE' ); # Start 1 new instance from AMI: ami-XXXXXXXX my $instance = $ec2->run_instances(ImageId => 'ami-XXXXXXXX', MinCount => 1, MaxCount => 1); my $running_instances = $ec2->describe_instances; foreach my $reservation (@$running_instances) { foreach my $instance ($reservation->instances_set) { print $instance->instance_id . "\n"; } } my $instance_id = $instance->instances_set->[0]->instance_id; print "$instance_id\n"; # Terminate instance my $result = $ec2->terminate_instances(InstanceId => $instance_id); If an error occurs while communicating with EC2, these methods will throw a L exception. =head1 DESCRIPTION This module is a Perl interface to Amazon's Elastic Compute Cloud. It uses the Query API to communicate with Amazon's Web Services framework. =head1 CLASS METHODS =head2 new(%params) This is the constructor, it will return you a Net::Amazon::EC2 object to work with. It takes these parameters: =over =item AWSAccessKeyId (required, unless an IAM role is present) Your AWS access key. For information on IAM roles, see L =item SecretAccessKey (required, unless an IAM role is present) Your secret key, B don't give this out or someone will be able to use your account and incur charges on your behalf. =item region (optional) The region to run the API requests through. Defaults to us-east-1. =item ssl (optional) If set to a true value, the base_url will use https:// instead of http://. Setting base_url explicitly will override this. Defaults to true as of 0.22. =item debug (optional) A flag to turn on debugging. Among other useful things, it will make the failing api calls print a stack trace. It is turned off by default. =item return_errors (optional) Previously, Net::Amazon::EC2 would return a L object when it encountered an error condition. As of 0.19, this object is thrown as an exception using croak or confess depending on if the debug flag is set. If you want/need the old behavior, set this attribute to a true value. =back =cut has 'AWSAccessKeyId' => ( is => 'ro', isa => 'Str', required => 1, lazy => 1, default => sub { if (defined($_[0]->temp_creds)) { return $_[0]->temp_creds->{'AccessKeyId'}; } else { return undef; } } ); has 'SecretAccessKey' => ( is => 'ro', isa => 'Str', required => 1, lazy => 1, default => sub { if (defined($_[0]->temp_creds)) { return $_[0]->temp_creds->{'SecretAccessKey'}; } else { return undef; } } ); has 'debug' => ( is => 'ro', isa => 'Str', required => 0, default => 0 ); has 'signature_version' => ( is => 'ro', isa => 'Int', required => 1, default => 2 ); has 'version' => ( is => 'ro', isa => 'Str', required => 1, default => '2012-07-20' ); has 'region' => ( is => 'ro', isa => 'Str', required => 1, default => 'us-east-1' ); has 'ssl' => ( is => 'ro', isa => 'Bool', required => 1, default => 1 ); has 'return_errors' => ( is => 'ro', isa => 'Bool', default => 0 ); has 'base_url' => ( is => 'ro', isa => 'Str', required => 1, lazy => 1, default => sub { return 'http' . ($_[0]->ssl ? 's' : '') . '://' . $_[0]->region . '.ec2.amazonaws.com'; } ); has 'temp_creds' => ( is => 'ro', lazy => 1, default => sub { my $ret; $ret = $_[0]->_fetch_iam_security_credentials(); }, predicate => 'has_temp_creds' ); sub timestamp { return strftime("%Y-%m-%dT%H:%M:%SZ",gmtime); } sub _fetch_iam_security_credentials { my $self = shift; my $retval = {}; my $ua = LWP::UserAgent->new(); # Fail quickly if this is not running on an EC2 instance $ua->timeout(2); my $url = 'http://169.254.169.254/latest/meta-data/iam/security-credentials/'; $self->_debug("Attempting to fetch instance credentials"); my $res = $ua->get($url); if ($res->code == 200) { # Assumes the first profile is the only profile my $profile = (split /\n/, $res->content())[0]; $res = $ua->get($url . $profile); if ($res->code == 200) { $retval->{'Profile'} = $profile; foreach (split /\n/, $res->content()) { return undef if /Code/ && !/Success/; if (m/.*"([^"]+)"\s+:\s+"([^"]+)",/) { $retval->{$1} = $2; } } return $retval if (keys %{$retval}); } } return undef; } sub _sign { my $self = shift; my %args = @_; my $action = delete $args{Action}; my %sign_hash = %args; my $timestamp = $self->timestamp; $sign_hash{AWSAccessKeyId} = $self->AWSAccessKeyId; $sign_hash{Action} = $action; $sign_hash{Timestamp} = $timestamp; $sign_hash{Version} = $self->version; $sign_hash{SignatureVersion} = $self->signature_version; $sign_hash{SignatureMethod} = "HmacSHA256"; if ($self->has_temp_creds) { $sign_hash{SecurityToken} = $self->temp_creds->{'Token'}; } my $sign_this = "POST\n"; my $uri = URI->new($self->base_url); $sign_this .= lc($uri->host) . "\n"; $sign_this .= "/\n"; my @signing_elements; foreach my $key (sort keys %sign_hash) { push @signing_elements, uri_escape_utf8($key)."=".uri_escape_utf8($sign_hash{$key}); } $sign_this .= join "&", @signing_elements; $self->_debug("QUERY TO SIGN: $sign_this"); my $encoded = $self->_hashit($self->SecretAccessKey, $sign_this); my $content = join "&", @signing_elements, 'Signature=' . uri_escape_utf8($encoded); my $ur = $uri->as_string(); $self->_debug("GENERATED QUERY URL: $ur"); my $ua = LWP::UserAgent->new(); $ua->env_proxy; my $res = $ua->post($ur, Content => $content); # We should force elements to be in an array my $xs = XML::Simple->new( ForceArray => qr/(?:item|Errors)/i, # Always want item elements unpacked to arrays KeyAttr => '', # Turn off folding for 'id', 'name', 'key' elements SuppressEmpty => undef, # Turn empty values into explicit undefs ); my $xml; # Check the result for connectivity problems, if so throw an error if ($res->code >= 500) { my $message = $res->status_line; $xml = < N/A HTTP POST FAILURE $message EOXML } else { $xml = $res->content(); } my $ref = $xs->XMLin($xml); warn Dumper($ref) . "\n\n" if $self->debug == 1; return $ref; } sub _parse_errors { my $self = shift; my $errors_xml = shift; my $es; my $request_id = $errors_xml->{RequestID}; foreach my $e (@{$errors_xml->{Errors}}) { my $error = Net::Amazon::EC2::Error->new( code => $e->{Error}{Code}, message => $e->{Error}{Message}, ); push @$es, $error; } my $errors = Net::Amazon::EC2::Errors->new( request_id => $request_id, errors => $es, ); foreach my $error (@{$errors->errors}) { $self->_debug("ERROR CODE: " . $error->code . " MESSAGE: " . $error->message . " FOR REQUEST: " . $errors->request_id); } # User wants old behaviour if ($self->return_errors) { return $errors; } # Print a stack trace if debugging is enabled if ($self->debug) { confess 'Last error was: ' . $es->[-1]->message; } else { croak $errors; } } sub _debug { my $self = shift; my $message = shift; if ((grep { defined && length} $self->debug) && $self->debug == 1) { print "$message\n\n\n\n"; } } # HMAC sign the query with the aws secret access key and base64 encodes the result. sub _hashit { my $self = shift; my ($secret_access_key, $query_string) = @_; return encode_base64(hmac_sha256($query_string, $secret_access_key), ''); } sub _build_filters { my ($self, $args) = @_; my $filters = delete $args->{Filter}; return unless $filters && ref($filters) eq 'ARRAY'; $filters = [ $filters ] unless ref($filters->[0]) eq 'ARRAY'; my $count = 1; foreach my $filter (@{$filters}) { my ($name, @args) = @$filter; $args->{"Filter." . $count.".Name"} = $name; $args->{"Filter." . $count.".Value.".$_} = $args[$_-1] for 1..scalar @args; $count++; } } =head1 OBJECT METHODS =head2 allocate_address() Acquires an elastic IP address which can be associated with an instance to create a movable static IP. Takes no arguments Returns the IP address obtained. =cut sub allocate_address { my $self = shift; my $xml = $self->_sign(Action => 'AllocateAddress'); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { return $xml->{publicIp}; } } =head2 associate_address(%params) Associates an elastic IP address with an instance. It takes the following arguments: =over =item InstanceId (required) The instance id you wish to associate the IP address with =item PublicIp (optional) The IP address to associate with =item AllocationId (optional) The allocation id if IP will be assigned in a virtual private cloud. =back Returns true if the association succeeded. =cut sub associate_address { my $self = shift; my %args = validate( @_, { InstanceId => { type => SCALAR }, PublicIp => { type => SCALAR, optional => 1 }, AllocationId => { type => SCALAR, optional => 1 }, }); my $xml = $self->_sign(Action => 'AssociateAddress', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{return} eq 'true') { return 1; } else { return undef; } } } =head2 attach_volume(%params) Attach a volume to an instance. =over =item VolumeId (required) The volume id you wish to attach. =item InstanceId (required) The instance id you wish to attach the volume to. =item Device (required) The device id you want the volume attached as. =back Returns a Net::Amazon::EC2::Attachment object containing the resulting volume status. =cut sub attach_volume { my $self = shift; my %args = validate( @_, { VolumeId => { type => SCALAR }, InstanceId => { type => SCALAR }, Device => { type => SCALAR }, }); my $xml = $self->_sign(Action => 'AttachVolume', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $attachment = Net::Amazon::EC2::Attachment->new( volume_id => $xml->{volumeId}, status => $xml->{status}, instance_id => $xml->{instanceId}, attach_time => $xml->{attachTime}, device => $xml->{device}, ); return $attachment; } } =head2 authorize_security_group_ingress(%params) This method adds permissions to a security group. It takes the following parameters: =over =item GroupName (required) The name of the group to add security rules to. =item SourceSecurityGroupName (required when authorizing a user and group together) Name of the group to add access for. =item SourceSecurityGroupOwnerId (required when authorizing a user and group together) Owner of the group to add access for. =item IpProtocol (required when adding access for a CIDR) IP Protocol of the rule you are adding access for (TCP, UDP, or ICMP) =item FromPort (required when adding access for a CIDR) Beginning of port range to add access for. =item ToPort (required when adding access for a CIDR) End of port range to add access for. =item CidrIp (required when adding access for a CIDR) The CIDR IP space we are adding access for. =back Adding a rule can be done in two ways: adding a source group name + source group owner id, or, CIDR IP range. Both methods allow IP protocol, from port and to port specifications. Returns 1 if rule is added successfully. =cut sub authorize_security_group_ingress { my $self = shift; my %args = validate( @_, { GroupName => { type => SCALAR }, SourceSecurityGroupName => { type => SCALAR, depends => ['SourceSecurityGroupOwnerId'], optional => 1 , }, SourceSecurityGroupOwnerId => { type => SCALAR, optional => 1 }, IpProtocol => { type => SCALAR, depends => ['FromPort', 'ToPort'], optional => 1 }, FromPort => { type => SCALAR, optional => 1 }, ToPort => { type => SCALAR, optional => 1 }, CidrIp => { type => SCALAR, optional => 1 }, }); my $xml = $self->_sign(Action => 'AuthorizeSecurityGroupIngress', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{return} eq 'true') { return 1; } else { return undef; } } } =head2 bundle_instance(%params) Bundles the Windows instance. This procedure is not applicable for Linux and UNIX instances. NOTE NOTE NOTE This is not well tested as I don't run windows instances =over =item InstanceId (required) The ID of the instance to bundle. =item Storage.S3.Bucket (required) The bucket in which to store the AMI. You can specify a bucket that you already own or a new bucket that Amazon EC2 creates on your behalf. If you specify a bucket that belongs to someone else, Amazon EC2 returns an error. =item Storage.S3.Prefix (required) Specifies the beginning of the file name of the AMI. =item Storage.S3.AWSAccessKeyId (required) The Access Key ID of the owner of the Amazon S3 bucket. =item Storage.S3.UploadPolicy (required) An Amazon S3 upload policy that gives Amazon EC2 permission to upload items into Amazon S3 on the user's behalf. =item Storage.S3.UploadPolicySignature (required) The signature of the Base64 encoded JSON document. JSON Parameters: (all are required) expiration - The expiration of the policy. Amazon recommends 12 hours or longer. conditions - A list of restrictions on what can be uploaded to Amazon S3. Must contain the bucket and ACL conditions in this table. bucket - The bucket to store the AMI. acl - This must be set to ec2-bundle-read. =back Returns a Net::Amazon::EC2::BundleInstanceResponse object =cut sub bundle_instance { my $self = shift; my %args = validate( @_, { 'InstanceId' => { type => SCALAR }, 'Storage.S3.Bucket' => { type => SCALAR }, 'Storage.S3.Prefix' => { type => SCALAR }, 'Storage.S3.AWSAccessKeyId' => { type => SCALAR }, 'Storage.S3.UploadPolicy' => { type => SCALAR }, 'Storage.S3.UploadPolicySignature' => { type => SCALAR }, }); my $xml = $self->_sign(Action => 'BundleInstance', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $bundle = Net::Amazon::EC2::BundleInstanceResponse->new( instance_id => $xml->{bundleInstanceTask}{instanceId}, bundle_id => $xml->{bundleInstanceTask}{bundleId}, state => $xml->{bundleInstanceTask}{state}, start_time => $xml->{bundleInstanceTask}{startTime}, update_time => $xml->{bundleInstanceTask}{updateTime}, progress => $xml->{bundleInstanceTask}{progress}, s3_bucket => $xml->{bundleInstanceTask}{storage}{S3}{bucket}, s3_prefix => $xml->{bundleInstanceTask}{storage}{S3}{bucket}, s3_aws_access_key_id => $xml->{bundleInstanceTask}{storage}{S3}{bucket}, s3_upload_policy => $xml->{bundleInstanceTask}{storage}{S3}{bucket}, s3_policy_upload_signature => $xml->{bundleInstanceTask}{storage}{S3}{bucket}, bundle_error_code => $xml->{bundleInstanceTask}{error}{code}, bundle_error_message => $xml->{bundleInstanceTask}{error}{message}, ); return $bundle; } } =head2 cancel_bundle_task(%params) Cancels the bundle task. This procedure is not applicable for Linux and UNIX instances. =over =item BundleId (required) The ID of the bundle task to cancel. =back Returns a Net::Amazon::EC2::BundleInstanceResponse object =cut sub cancel_bundle_task { my $self = shift; my %args = validate( @_, { 'BundleId' => { type => SCALAR }, }); my $xml = $self->_sign(Action => 'CancelBundleTask', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $bundle = Net::Amazon::EC2::BundleInstanceResponse->new( instance_id => $xml->{bundleInstanceTask}{instanceId}, bundle_id => $xml->{bundleInstanceTask}{bundleId}, state => $xml->{bundleInstanceTask}{state}, start_time => $xml->{bundleInstanceTask}{startTime}, update_time => $xml->{bundleInstanceTask}{updateTime}, progress => $xml->{bundleInstanceTask}{progress}, s3_bucket => $xml->{bundleInstanceTask}{storage}{S3}{bucket}, s3_prefix => $xml->{bundleInstanceTask}{storage}{S3}{bucket}, s3_aws_access_key_id => $xml->{bundleInstanceTask}{storage}{S3}{bucket}, s3_upload_policy => $xml->{bundleInstanceTask}{storage}{S3}{bucket}, s3_policy_upload_signature => $xml->{bundleInstanceTask}{storage}{S3}{bucket}, bundle_error_code => $xml->{bundleInstanceTask}{error}{code}, bundle_error_message => $xml->{bundleInstanceTask}{error}{message}, ); return $bundle; } } =head2 confirm_product_instance(%params) Checks to see if the product code passed in is attached to the instance id, taking the following parameter: =over =item ProductCode (required) The Product Code to check =item InstanceId (required) The Instance Id to check =back Returns a Net::Amazon::EC2::ConfirmProductInstanceResponse object =cut sub confirm_product_instance { my $self = shift; my %args = validate( @_, { ProductCode => { type => SCALAR }, InstanceId => { type => SCALAR }, }); my $xml = $self->_sign(Action => 'ConfirmProductInstance', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $confirm_response = Net::Amazon::EC2::ConfirmProductInstanceResponse->new( 'return' => $xml->{'return'}, owner_id => $xml->{ownerId}, ); return $confirm_response; } } =head2 create_image(%params) Creates an AMI that uses an Amazon EBS root device from a "running" or "stopped" instance. AMIs that use an Amazon EBS root device boot faster than AMIs that use instance stores. They can be up to 1 TiB in size, use storage that persists on instance failure, and can be stopped and started. =over =item InstanceId (required) The ID of the instance. =item Name (required) The name of the AMI that was provided during image creation. Note that the image name has the following constraints: 3-128 alphanumeric characters, parenthesis, commas, slashes, dashes, or underscores. =item Description (optional) The description of the AMI that was provided during image creation. =item NoReboot (optional) By default this property is set to false, which means Amazon EC2 attempts to cleanly shut down the instance before image creation and reboots the instance afterwards. When set to true, Amazon EC2 does not shut down the instance before creating the image. When this option is used, file system integrity on the created image cannot be guaranteed. =item BlockDeviceMapping (optional) Array ref of the device names exposed to the instance. You can specify device names as '=' similar to ec2-create-image command. (L) BlockDeviceMapping => [ '/dev/sda=:256:true:standard', '/dev/sdb=none', '/dev/sdc=ephemeral0', '/dev/sdd=ephemeral1', ], =back Returns the ID of the AMI created. =cut sub create_image { my $self = shift; my %args = validate( @_, { InstanceId => { type => SCALAR }, Name => { type => SCALAR }, Description => { type => SCALAR, optional => 1 }, NoReboot => { type => SCALAR, optional => 1 }, BlockDeviceMapping => { type => ARRAYREF, optional => 1 }, }); if (my $bdm = delete $args{BlockDeviceMapping}) { my $n = 0; for my $bdme (@$bdm) { my($device, $block_device) = split /=/, $bdme, 2; $args{"BlockDeviceMapping.${n}.DeviceName"} = $device; if ($block_device =~ /^ephemeral[0-9]+$/) { $args{"BlockDeviceMapping.${n}.VirtualName"} = $block_device; } elsif ($block_device eq 'none') { $args{"BlockDeviceMapping.${n}.NoDevice"} = ''; } else { my @keys = qw( Ebs.SnapshotId Ebs.VolumeSize Ebs.DeleteOnTermination Ebs.VolumeType Ebs.Iops ); for my $bde (split /:/, $block_device) { my $key = shift @keys; next unless $bde; $args{"BlockDeviceMapping.${n}.${key}"} = $bde; } } $n++; } } my $xml = $self->_sign(Action => 'CreateImage', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { return $xml->{imageId}; } } =head2 create_key_pair(%params) Creates a new 2048 bit key pair, taking the following parameter: =over =item KeyName (required) A name for this key. Should be unique. =back Returns a Net::Amazon::EC2::KeyPair object =cut sub create_key_pair { my $self = shift; my %args = validate( @_, { KeyName => { type => SCALAR }, }); my $xml = $self->_sign(Action => 'CreateKeyPair', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $key_pair = Net::Amazon::EC2::KeyPair->new( key_name => $xml->{keyName}, key_fingerprint => $xml->{keyFingerprint}, key_material => $xml->{keyMaterial}, ); return $key_pair; } } =head2 create_security_group(%params) This method creates a new security group. It takes the following parameters: =over =item GroupName (required) The name of the new group to create. =item GroupDescription (required) A short description of the new group. =back Returns 1 if the group creation succeeds. =cut sub create_security_group { my $self = shift; my %args = validate( @_, { GroupName => { type => SCALAR }, GroupDescription => { type => SCALAR }, }); my $xml = $self->_sign(Action => 'CreateSecurityGroup', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{return} eq 'true') { return 1; } else { return undef; } } } =head2 create_snapshot(%params) Create a snapshot of a volume. It takes the following arguments: =over =item VolumeId (required) The volume id of the volume you want to take a snapshot of. =item Description (optional) Description of the Amazon EBS snapshot. =back Returns a Net::Amazon::EC2::Snapshot object of the newly created snapshot. =cut sub create_snapshot { my $self = shift; my %args = validate( @_, { VolumeId => { type => SCALAR }, Description => { type => SCALAR, optional => 1 }, }); my $xml = $self->_sign(Action => 'CreateSnapshot', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { unless ( grep { defined && length } $xml->{progress} and ref $xml->{progress} ne 'HASH') { $xml->{progress} = undef; } my $snapshot = Net::Amazon::EC2::Snapshot->new( snapshot_id => $xml->{snapshotId}, status => $xml->{status}, volume_id => $xml->{volumeId}, start_time => $xml->{startTime}, progress => $xml->{progress}, owner_id => $xml->{ownerId}, volume_size => $xml->{volumeSize}, description => $xml->{description}, ); return $snapshot; } } =head2 create_tags(%params) Creates tags. =over =item ResourceId (required) The ID of the resource to create tags. Can be a scalar or arrayref =item Tags (required) Hashref where keys and values will be set on all resources given in the first element. =back Returns true if the tag creation succeeded. =cut sub create_tags { my $self = shift; my %args = validate( @_, { ResourceId => { type => ARRAYREF | SCALAR }, Tags => { type => HASHREF }, }); if (ref ($args{'ResourceId'}) eq 'ARRAY') { my $keys = delete $args{'ResourceId'}; my $count = 1; foreach my $key (@{$keys}) { $args{"ResourceId." . $count} = $key; $count++; } } else { $args{"ResourceId.1"} = delete $args{'ResourceId'}; } if (ref ($args{'Tags'}) eq 'HASH') { my $count = 1; my $tags = delete $args{'Tags'}; foreach my $key ( keys %{$tags} ) { last if $count > 10; $args{"Tag." . $count . ".Key"} = $key; $args{"Tag." . $count . ".Value"} = $tags->{$key}; $count++; } } my $xml = $self->_sign(Action => 'CreateTags', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{return} eq 'true') { return 1; } else { return undef; } } } =head2 create_volume(%params) Creates a volume. =over =item Size (required) The size in GiB of the volume you want to create. =item SnapshotId (optional) The optional snapshot id to create the volume from. =item AvailabilityZone (required) The availability zone to create the volume in. =item VolumeType (optional) The volume type: 'standard' or 'io1'. Defaults to 'standard'. =item Iops (optional) The number of I/O operations per second (IOPS) that the volume supports. Required when the volume type is io1; not used with standard volumes. =back Returns a Net::Amazon::EC2::Volume object containing the resulting volume status =cut sub create_volume { my $self = shift; my %args = validate( @_, { Size => { type => SCALAR }, SnapshotId => { type => SCALAR, optional => 1 }, AvailabilityZone => { type => SCALAR }, VolumeType => { type => SCALAR, optional => 1 }, Iops => { type => SCALAR, optional => 1 }, }); my $xml = $self->_sign(Action => 'CreateVolume', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { unless ( grep { defined && length } $xml->{snapshotId} and ref $xml->{snapshotId} ne 'HASH') { $xml->{snapshotId} = undef; } my $volume = Net::Amazon::EC2::Volume->new( volume_id => $xml->{volumeId}, status => $xml->{status}, zone => $xml->{availabilityZone}, create_time => $xml->{createTime}, snapshot_id => $xml->{snapshotId}, size => $xml->{size}, volume_type => $xml->{volumeType}, iops => $xml->{iops}, ); return $volume; } } =head2 delete_key_pair(%params) This method deletes a keypair. Takes the following parameter: =over =item KeyName (required) The name of the key to delete. =back Returns 1 if the key was successfully deleted. =cut sub delete_key_pair { my $self = shift; my %args = validate( @_, { KeyName => { type => SCALAR }, }); my $xml = $self->_sign(Action => 'DeleteKeyPair', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{return} eq 'true') { return 1; } else { return undef; } } } =head2 delete_security_group(%params) This method deletes a security group. It takes the following parameter: =over =item GroupName (required) The name of the security group to delete. =back Returns 1 if the delete succeeded. =cut sub delete_security_group { my $self = shift; my %args = validate( @_, { GroupName => { type => SCALAR }, }); my $xml = $self->_sign(Action => 'DeleteSecurityGroup', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{return} eq 'true') { return 1; } else { return undef; } } } =head2 delete_snapshot(%params) Deletes the snapshots passed in. It takes the following arguments: =over =item SnapshotId (required) A snapshot id can be passed in. Will delete the corresponding snapshot. =back Returns true if the deleting succeeded. =cut sub delete_snapshot { my $self = shift; my %args = validate( @_, { SnapshotId => { type => SCALAR }, }); my $xml = $self->_sign(Action => 'DeleteSnapshot', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{return} eq 'true') { return 1; } else { return undef; } } } =head2 delete_volume(%params) Delete a volume. =over =item VolumeId (required) The volume id you wish to delete. =back Returns true if the deleting succeeded. =cut sub delete_volume { my $self = shift; my %args = validate( @_, { VolumeId => { type => SCALAR, optional => 1 }, }); my $xml = $self->_sign(Action => 'DeleteVolume', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{return} eq 'true') { return 1; } else { return undef; } } } =head2 delete_tags(%params) Delete tags. =over =item ResourceId (required) The ID of the resource to delete tags =item Tag.Key (required) Key for a tag, may pass in a scalar or arrayref. =item Tag.Value (required) Value for a tag, may pass in a scalar or arrayref. =back Returns true if the releasing succeeded. =cut sub delete_tags { my $self = shift; my %args = validate( @_, { ResourceId => { type => ARRAYREF | SCALAR }, 'Tag.Key' => { type => ARRAYREF | SCALAR }, 'Tag.Value' => { type => ARRAYREF | SCALAR, optional => 1 }, }); # If we have a array ref of keys lets split them out into their Tag.n.Key format if (ref ($args{'Tag.Key'}) eq 'ARRAY') { my $keys = delete $args{'Tag.Key'}; my $count = 1; foreach my $key (@{$keys}) { $args{"Tag." . $count . ".Key"} = $key; $count++; } } # If we have a array ref of values lets split them out into their Tag.n.Value format if (ref ($args{'Tag.Value'}) eq 'ARRAY') { my $values = delete $args{'Tag.Value'}; my $count = 1; foreach my $value (@{$values}) { $args{"Tag." . $count . ".Value"} = $value; $count++; } } my $xml = $self->_sign(Action => 'DeleteTags', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{return} eq 'true') { return 1; } else { return undef; } } } =head2 deregister_image(%params) This method will deregister an AMI. It takes the following parameter: =over =item ImageId (required) The image id of the AMI you want to deregister. =back Returns 1 if the deregistering succeeded =cut sub deregister_image { my $self = shift; my %args = validate( @_, { ImageId => { type => SCALAR }, }); my $xml = $self->_sign(Action => 'DeregisterImage', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{return} eq 'true') { return 1; } else { return undef; } } } =head2 describe_addresses(%params) This method describes the elastic addresses currently allocated and any instances associated with them. It takes the following arguments: =over =item PublicIp (optional) The IP address to describe. Can be either a scalar or an array ref. =back Returns an array ref of Net::Amazon::EC2::DescribeAddress objects =cut sub describe_addresses { my $self = shift; my %args = validate( @_, { PublicIp => { type => SCALAR, optional => 1 }, }); # If we have a array ref of ip addresses lets split them out into their PublicIp.n format if (ref ($args{PublicIp}) eq 'ARRAY') { my $ip_addresses = delete $args{PublicIp}; my $count = 1; foreach my $ip_address (@{$ip_addresses}) { $args{"PublicIp." . $count} = $ip_address; $count++; } } my $addresses; my $xml = $self->_sign(Action => 'DescribeAddresses', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { foreach my $addy (@{$xml->{addressesSet}{item}}) { if (ref($addy->{instanceId}) eq 'HASH') { undef $addy->{instanceId}; } my $address = Net::Amazon::EC2::DescribeAddress->new( public_ip => $addy->{publicIp}, instance_id => $addy->{instanceId}, ); push @$addresses, $address; } return $addresses; } } =head2 describe_availability_zones(%params) This method describes the availability zones currently available to choose from. It takes the following arguments: =over =item ZoneName (optional) The zone name to describe. Can be either a scalar or an array ref. =back Returns an array ref of Net::Amazon::EC2::AvailabilityZone objects =cut sub describe_availability_zones { my $self = shift; my %args = validate( @_, { ZoneName => { type => SCALAR, optional => 1 }, }); # If we have a array ref of zone names lets split them out into their ZoneName.n format if (ref ($args{ZoneName}) eq 'ARRAY') { my $zone_names = delete $args{ZoneName}; my $count = 1; foreach my $zone_name (@{$zone_names}) { $args{"ZoneName." . $count} = $zone_name; $count++; } } my $xml = $self->_sign(Action => 'DescribeAvailabilityZones', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $availability_zones; foreach my $az (@{$xml->{availabilityZoneInfo}{item}}) { my $availability_zone_messages; # Create the messages for this zone foreach my $azm (@{$az->{messageSet}{item}}) { my $availability_zone_message = Net::Amazon::EC2::AvailabilityZoneMessage->new( message => $azm->{message}, ); push @$availability_zone_messages, $availability_zone_message; } my $availability_zone = Net::Amazon::EC2::AvailabilityZone->new( zone_name => $az->{zoneName}, zone_state => $az->{zoneState}, region_name => $az->{regionName}, messages => $availability_zone_messages, ); push @$availability_zones, $availability_zone; } return $availability_zones; } } =head2 describe_bundle_tasks(%params) Describes current bundling tasks. This procedure is not applicable for Linux and UNIX instances. =over =item BundleId (optional) The optional ID of the bundle task to describe. =back Returns a array ref of Net::Amazon::EC2::BundleInstanceResponse objects =cut sub describe_bundle_tasks { my $self = shift; my %args = validate( @_, { 'BundleId' => { type => SCALAR, optional => 1 }, }); my $xml = $self->_sign(Action => 'DescribeBundleTasks', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $bundle_tasks; foreach my $item (@{$xml->{bundleInstanceTasksSet}{item}}) { my $bundle = Net::Amazon::EC2::BundleInstanceResponse->new( instance_id => $item->{instanceId}, bundle_id => $item->{bundleId}, state => $item->{state}, start_time => $item->{startTime}, update_time => $item->{updateTime}, progress => $item->{progress}, s3_bucket => $item->{storage}{S3}{bucket}, s3_prefix => $item->{storage}{S3}{bucket}, s3_aws_access_key_id => $item->{storage}{S3}{bucket}, s3_upload_policy => $item->{storage}{S3}{bucket}, s3_policy_upload_signature => $item->{storage}{S3}{bucket}, bundle_error_code => $item->{error}{code}, bundle_error_message => $item->{error}{message}, ); push @$bundle_tasks, $bundle; } return $bundle_tasks; } } =head2 describe_image_attributes(%params) This method pulls a list of attributes for the image id specified =over =item ImageId (required) A scalar containing the image you want to get the list of attributes for. =item Attribute (required) A scalar containing the attribute to describe. Valid attributes are: =over =item launchPermission - The AMIs launch permissions. =item ImageId - ID of the AMI for which an attribute will be described. =item productCodes - The product code attached to the AMI. =item kernel - Describes the ID of the kernel associated with the AMI. =item ramdisk - Describes the ID of RAM disk associated with the AMI. =item blockDeviceMapping - Defines native device names to use when exposing virtual devices. =item platform - Describes the operating system platform. =back =back Returns a Net::Amazon::EC2::DescribeImageAttribute object * NOTE: There is currently a bug in Amazon's SOAP and Query API for when you try and describe the attributes: kernel, ramdisk, blockDeviceMapping, or platform AWS returns an invalid response. No response yet from Amazon on an ETA for getting that bug fixed. =cut sub describe_image_attribute { my $self = shift; my %args = validate( @_, { ImageId => { type => SCALAR }, Attribute => { type => SCALAR } }); my $xml = $self->_sign(Action => 'DescribeImageAttribute', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $launch_permissions; my $product_codes; my $block_device_mappings; if ( grep { defined && length } $xml->{launchPermission}{item} ) { foreach my $lp (@{$xml->{launchPermission}{item}}) { my $launch_permission = Net::Amazon::EC2::LaunchPermission->new( group => $lp->{group}, user_id => $lp->{userId}, ); push @$launch_permissions, $launch_permission; } } if ( grep { defined && length } $xml->{productCodes}{item} ) { foreach my $pc (@{$xml->{productCodes}{item}}) { my $product_code = Net::Amazon::EC2::ProductCode->new( product_code => $pc->{productCode}, ); push @$product_codes, $product_code; } } if ( grep { defined && length } $xml->{blockDeviceMapping}{item} ) { foreach my $bd (@{$xml->{blockDeviceMapping}{item}}) { my $block_device_mapping = Net::Amazon::EC2::BlockDeviceMapping->new( virtual_name => $bd->{virtualName}, device_name => $bd->{deviceName}, ); push @$block_device_mappings, $block_device_mapping; } } my $describe_image_attribute = Net::Amazon::EC2::DescribeImageAttribute->new( image_id => $xml->{imageId}, launch_permissions => $launch_permissions, product_codes => $product_codes, kernel => $xml->{kernel}, ramdisk => $xml->{ramdisk}, blockDeviceMapping => $block_device_mappings, platform => $xml->{platform}, ); return $describe_image_attribute; } } =head2 describe_images(%params) This method pulls a list of the AMIs which can be run. The list can be modified by passing in some of the following parameters: =over =item ImageId (optional) Either a scalar or an array ref can be passed in, will cause just these AMIs to be 'described' =item Owner (optional) Either a scalar or an array ref can be passed in, will cause AMIs owned by the Owner's provided will be 'described'. Pass either account ids, or 'amazon' for all amazon-owned AMIs, or 'self' for your own AMIs. =item ExecutableBy (optional) Either a scalar or an array ref can be passed in, will cause AMIs executable by the account id's specified. Or 'self' for your own AMIs. =back Returns an array ref of Net::Amazon::EC2::DescribeImagesResponse objects =cut sub describe_images { my $self = shift; my %args = validate( @_, { ImageId => { type => SCALAR | ARRAYREF, optional => 1 }, Owner => { type => SCALAR | ARRAYREF, optional => 1 }, ExecutableBy => { type => SCALAR | ARRAYREF, optional => 1 }, }); # If we have a array ref of instances lets split them out into their ImageId.n format if (ref ($args{ImageId}) eq 'ARRAY') { my $image_ids = delete $args{ImageId}; my $count = 1; foreach my $image_id (@{$image_ids}) { $args{"ImageId." . $count} = $image_id; $count++; } } # If we have a array ref of instances lets split them out into their Owner.n format if (ref ($args{Owner}) eq 'ARRAY') { my $owners = delete $args{Owner}; my $count = 1; foreach my $owner (@{$owners}) { $args{"Owner." . $count} = $owner; $count++; } } # If we have a array ref of instances lets split them out into their ExecutableBy.n format if (ref ($args{ExecutableBy}) eq 'ARRAY') { my $executors = delete $args{ExecutableBy}; my $count = 1; foreach my $executor (@{$executors}) { $args{"ExecutableBy." . $count} = $executor; $count++; } } my $xml = $self->_sign(Action => 'DescribeImages', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $images; foreach my $item (@{$xml->{imagesSet}{item}}) { my $product_codes; my $state_reason; my $block_device_mappings; if ( grep { defined && length } $item->{stateReason} ) { $state_reason = Net::Amazon::EC2::StateReason->new( code => $item->{stateReason}{code}, message => $item->{stateReason}{message}, ); } if ( grep { defined && length } $item->{blockDeviceMapping} ) { foreach my $bdm ( @{$item->{blockDeviceMapping}{item}} ) { my $virtual_name; my $no_device; my $ebs_block_device_mapping; if ( grep { defined && length } $bdm->{ebs} ) { $ebs_block_device_mapping = Net::Amazon::EC2::EbsBlockDevice->new( snapshot_id => $bdm->{ebs}{snapshotId}, volume_size => $bdm->{ebs}{volumeSize}, delete_on_termination => $bdm->{ebs}{deleteOnTermination}, ); } my $block_device_mapping = Net::Amazon::EC2::BlockDeviceMapping->new( device_name => $bdm->{deviceName}, virtual_name => $virtual_name, ebs => $ebs_block_device_mapping, no_device => $no_device, ); push @$block_device_mappings, $block_device_mapping; } } $item->{description} = undef if ref ($item->{description}); my $image = Net::Amazon::EC2::DescribeImagesResponse->new( image_id => $item->{imageId}, image_owner_id => $item->{imageOwnerId}, image_state => $item->{imageState}, is_public => $item->{isPublic}, image_location => $item->{imageLocation}, architecture => $item->{architecture}, image_type => $item->{imageType}, kernel_id => $item->{kernelId}, ramdisk_id => $item->{ramdiskId}, platform => $item->{platform}, state_reason => $state_reason, image_owner_alias => $item->{imageOwnerAlias}, name => $item->{name}, description => $item->{description}, root_device_type => $item->{rootDeviceType}, root_device_name => $item->{rootDeviceName}, block_device_mapping => $block_device_mappings, ); if (grep { defined && length } $item->{productCodes} ) { foreach my $pc (@{$item->{productCodes}{item}}) { my $product_code = Net::Amazon::EC2::ProductCode->new( product_code => $pc->{productCode} ); push @$product_codes, $product_code; } $image->product_codes($product_codes); } push @$images, $image; } return $images; } } =head2 describe_instances(%params) This method pulls a list of the instances which are running or were just running. The list can be modified by passing in some of the following parameters: =over =item InstanceId (optional) Either a scalar or an array ref can be passed in, will cause just these instances to be 'described' =item Filter (optional) The filters for only the matching instances to be 'described'. A filter tuple is an arrayref constsing one key and one or more values. The option takes one filter tuple, or an arrayref of multiple filter tuples. =back Returns an array ref of Net::Amazon::EC2::ReservationInfo objects =cut sub describe_instances { my $self = shift; my %args = validate( @_, { InstanceId => { type => SCALAR | ARRAYREF, optional => 1 }, Filter => { type => ARRAYREF, optional => 1 }, }); # If we have a array ref of instances lets split them out into their InstanceId.n format if (ref ($args{InstanceId}) eq 'ARRAY') { my $instance_ids = delete $args{InstanceId}; my $count = 1; foreach my $instance_id (@{$instance_ids}) { $args{"InstanceId." . $count} = $instance_id; $count++; } } $self->_build_filters(\%args); my $xml = $self->_sign(Action => 'DescribeInstances', %args); my $reservations; if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { foreach my $reservation_set (@{$xml->{reservationSet}{item}}) { my $group_sets=[]; foreach my $group_arr (@{$reservation_set->{groupSet}{item}}) { my $group = Net::Amazon::EC2::GroupSet->new( group_id => $group_arr->{groupId}, group_name => $group_arr->{groupName}, ); push @$group_sets, $group; } my $running_instances; foreach my $instance_elem (@{$reservation_set->{instancesSet}{item}}) { my $instance_state_type = Net::Amazon::EC2::InstanceState->new( code => $instance_elem->{instanceState}{code}, name => $instance_elem->{instanceState}{name}, ); my $product_codes; my $block_device_mappings; my $state_reason; if (grep { defined && length } $instance_elem->{productCodes} ) { foreach my $pc (@{$instance_elem->{productCodes}{item}}) { my $product_code = Net::Amazon::EC2::ProductCode->new( product_code => $pc->{productCode} ); push @$product_codes, $product_code; } } if ( grep { defined && length } $instance_elem->{blockDeviceMapping} ) { foreach my $bdm ( @{$instance_elem->{blockDeviceMapping}{item}} ) { my $ebs_block_device_mapping = Net::Amazon::EC2::EbsInstanceBlockDeviceMapping->new( volume_id => $bdm->{ebs}{volumeId}, status => $bdm->{ebs}{status}, attach_time => $bdm->{ebs}{attachTime}, delete_on_termination => $bdm->{ebs}{deleteOnTermination}, ); my $block_device_mapping = Net::Amazon::EC2::BlockDeviceMapping->new( ebs => $ebs_block_device_mapping, device_name => $bdm->{deviceName}, ); push @$block_device_mappings, $block_device_mapping; } } if ( grep { defined && length } $instance_elem->{stateReason} ) { $state_reason = Net::Amazon::EC2::StateReason->new( code => $instance_elem->{stateReason}{code}, message => $instance_elem->{stateReason}{message}, ); } unless ( grep { defined && length } $instance_elem->{reason} and ref $instance_elem->{reason} ne 'HASH' ) { $instance_elem->{reason} = undef; } unless ( grep { defined && length } $instance_elem->{privateDnsName} and ref $instance_elem->{privateDnsName} ne 'HASH' ) { $instance_elem->{privateDnsName} = undef; } unless ( grep { defined && length } $instance_elem->{dnsName} and ref $instance_elem->{dnsName} ne 'HASH' ) { $instance_elem->{dnsName} = undef; } unless ( grep { defined && length } $instance_elem->{placement}{availabilityZone} and ref $instance_elem->{placement}{availabilityZone} ne 'HASH' ) { $instance_elem->{placement}{availabilityZone} = undef; } my $placement_response = Net::Amazon::EC2::PlacementResponse->new( availability_zone => $instance_elem->{placement}{availabilityZone} ); my $tag_sets; foreach my $tag_arr (@{$instance_elem->{tagSet}{item}}) { if ( ref $tag_arr->{value} eq "HASH" ) { $tag_arr->{value} = ""; } my $tag = Net::Amazon::EC2::TagSet->new( key => $tag_arr->{key}, value => $tag_arr->{value}, ); push @$tag_sets, $tag; } my $running_instance = Net::Amazon::EC2::RunningInstances->new( ami_launch_index => $instance_elem->{amiLaunchIndex}, dns_name => $instance_elem->{dnsName}, image_id => $instance_elem->{imageId}, kernel_id => $instance_elem->{kernelId}, ramdisk_id => $instance_elem->{ramdiskId}, instance_id => $instance_elem->{instanceId}, instance_state => $instance_state_type, instance_type => $instance_elem->{instanceType}, key_name => $instance_elem->{keyName}, launch_time => $instance_elem->{launchTime}, placement => $placement_response, private_dns_name => $instance_elem->{privateDnsName}, reason => $instance_elem->{reason}, platform => $instance_elem->{platform}, monitoring => $instance_elem->{monitoring}{state}, subnet_id => $instance_elem->{subnetId}, vpc_id => $instance_elem->{vpcId}, private_ip_address => $instance_elem->{privateIpAddress}, ip_address => $instance_elem->{ipAddress}, architecture => $instance_elem->{architecture}, root_device_name => $instance_elem->{rootDeviceName}, root_device_type => $instance_elem->{rootDeviceType}, block_device_mapping => $block_device_mappings, state_reason => $state_reason, tag_set => $tag_sets, ); if ($product_codes) { $running_instance->product_codes($product_codes); } push @$running_instances, $running_instance; } my $reservation = Net::Amazon::EC2::ReservationInfo->new( reservation_id => $reservation_set->{reservationId}, owner_id => $reservation_set->{ownerId}, group_set => $group_sets, instances_set => $running_instances, requester_id => $reservation_set->{requesterId}, ); push @$reservations, $reservation; } } return $reservations; } =head2 describe_instance_attribute(%params) Returns information about an attribute of an instance. Only one attribute can be specified per call. =over =item InstanceId (required) The instance id we want to describe the attributes of. =item Attribute (required) The attribute we want to describe. Valid values are: =over =item * instanceType =item * kernel =item * ramdisk =item * userData =item * disableApiTermination =item * instanceInitiatedShutdownBehavior =item * rootDeviceName =item * blockDeviceMapping =back =back Returns a Net::Amazon::EC2::DescribeInstanceAttributeResponse object =cut sub describe_instance_attribute { my $self = shift; my %args = validate( @_, { InstanceId => { type => SCALAR }, Attribute => { type => SCALAR }, }); my $xml = $self->_sign(Action => 'DescribeInstanceAttribute', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $attribute_response; # Test to see which type of attribute we are looking for, to dictacte # how to create the Net::Amazon::EC2::DescribeInstanceAttributeResponse object. if ( $args{Attribute} eq 'instanceType' ) { $attribute_response = Net::Amazon::EC2::DescribeInstanceAttributeResponse->new( instance_id => $xml->{instanceId}, instance_type => $xml->{instanceType}{value}, ); } elsif ( $args{Attribute} eq 'kernel' ) { $attribute_response = Net::Amazon::EC2::DescribeInstanceAttributeResponse->new( instance_id => $xml->{instanceId}, kernel => $xml->{kernel}{value}, ); } elsif ( $args{Attribute} eq 'ramdisk' ) { $attribute_response = Net::Amazon::EC2::DescribeInstanceAttributeResponse->new( instance_id => $xml->{instanceId}, ramdisk => $xml->{ramdisk}{value}, ); } elsif ( $args{Attribute} eq 'userData' ) { $attribute_response = Net::Amazon::EC2::DescribeInstanceAttributeResponse->new( instance_id => $xml->{instanceId}, user_data => $xml->{userData}{value}, ); } elsif ( $args{Attribute} eq 'disableApiTermination' ) { $attribute_response = Net::Amazon::EC2::DescribeInstanceAttributeResponse->new( instance_id => $xml->{instanceId}, disable_api_termination => $xml->{disableApiTermination}{value}, ); } elsif ( $args{Attribute} eq 'instanceInitiatedShutdownBehavior' ) { $attribute_response = Net::Amazon::EC2::DescribeInstanceAttributeResponse->new( instance_id => $xml->{instanceId}, instance_initiated_shutdown_behavior => $xml->{instanceInitiatedShutdownBehavior}{value}, ); } elsif ( $args{Attribute} eq 'rootDeviceName' ) { $attribute_response = Net::Amazon::EC2::DescribeInstanceAttributeResponse->new( instance_id => $xml->{instanceId}, root_device_name => $xml->{rootDeviceName}{value}, ); } elsif ( $args{Attribute} eq 'blockDeviceMapping' ) { my $block_mappings; foreach my $block_item (@{$xml->{blockDeviceMapping}{item}}) { my $ebs_mapping = Net::Amazon::EC2::EbsInstanceBlockDeviceMapping->new( attach_time => $block_item->{ebs}{attachTime}, delete_on_termination => $block_item->{ebs}{deleteOnTermination}, status => $block_item->{ebs}{status}, volume_id => $block_item->{ebs}{volumeId}, ); my $block_device_mapping = Net::Amazon::EC2::BlockDeviceMapping->new( device_name => $block_item->{deviceName}, ebs => $ebs_mapping, ); push @$block_mappings, $block_device_mapping; } $attribute_response = Net::Amazon::EC2::DescribeInstanceAttributeResponse->new( instance_id => $xml->{instanceId}, block_device_mapping => $block_mappings, ); } return $attribute_response; } } =head2 describe_key_pairs(%params) This method describes the keypairs available on this account. It takes the following parameter: =over =item KeyName (optional) The name of the key to be described. Can be either a scalar or an array ref. =back Returns an array ref of Net::Amazon::EC2::DescribeKeyPairsResponse objects =cut sub describe_key_pairs { my $self = shift; my %args = validate( @_, { KeyName => { type => SCALAR | ARRAYREF, optional => 1 }, }); # If we have a array ref of instances lets split them out into their InstanceId.n format if (ref ($args{KeyName}) eq 'ARRAY') { my $keynames = delete $args{KeyName}; my $count = 1; foreach my $keyname (@{$keynames}) { $args{"KeyName." . $count} = $keyname; $count++; } } my $xml = $self->_sign(Action => 'DescribeKeyPairs', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $key_pairs; foreach my $pair (@{$xml->{keySet}{item}}) { my $key_pair = Net::Amazon::EC2::DescribeKeyPairsResponse->new( key_name => $pair->{keyName}, key_fingerprint => $pair->{keyFingerprint}, ); push @$key_pairs, $key_pair; } return $key_pairs; } } =head2 describe_regions(%params) Describes EC2 regions that are currently available to launch instances in for this account. =over =item RegionName (optional) The name of the region(s) to be described. Can be either a scalar or an array ref. =back Returns an array ref of Net::Amazon::EC2::Region objects =cut sub describe_regions { my $self = shift; my %args = validate( @_, { RegionName => { type => ARRAYREF | SCALAR, optional => 1 }, }); # If we have a array ref of regions lets split them out into their RegionName.n format if (ref ($args{RegionName}) eq 'ARRAY') { my $regions = delete $args{RegionName}; my $count = 1; foreach my $region (@{$regions}) { $args{"RegionName." . $count} = $region; $count++; } } my $xml = $self->_sign(Action => 'DescribeRegions', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $regions; foreach my $region_item (@{$xml->{regionInfo}{item}}) { my $region = Net::Amazon::EC2::Region->new( region_name => $region_item->{regionName}, region_endpoint => $region_item->{regionEndpoint}, ); push @$regions, $region; } return $regions; } } =head2 describe_reserved_instances(%params) Describes Reserved Instances that you purchased. =over =item ReservedInstancesId (optional) The reserved instance id(s) to be described. Can be either a scalar or an array ref. =back Returns an array ref of Net::Amazon::EC2::ReservedInstance objects =cut sub describe_reserved_instances { my $self = shift; my %args = validate( @_, { ReservedInstancesId => { type => ARRAYREF | SCALAR, optional => 1 }, }); # If we have a array ref of reserved instances lets split them out into their ReservedInstancesId.n format if (ref ($args{ReservedInstancesId}) eq 'ARRAY') { my $reserved_instance_ids = delete $args{ReservedInstancesId}; my $count = 1; foreach my $reserved_instance_id (@{$reserved_instance_ids}) { $args{"ReservedInstancesId." . $count} = $reserved_instance_id; $count++; } } my $xml = $self->_sign(Action => 'DescribeReservedInstances', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $reserved_instances; foreach my $reserved_instance_item (@{$xml->{reservedInstancesSet}{item}}) { my $reserved_instance = Net::Amazon::EC2::ReservedInstance->new( reserved_instances_id => $reserved_instance_item->{reservedInstancesId}, instance_type => $reserved_instance_item->{instanceType}, availability_zone => $reserved_instance_item->{availabilityZone}, duration => $reserved_instance_item->{duration}, start => $reserved_instance_item->{start}, usage_price => $reserved_instance_item->{usagePrice}, fixed_price => $reserved_instance_item->{fixedPrice}, instance_count => $reserved_instance_item->{instanceCount}, product_description => $reserved_instance_item->{productDescription}, state => $reserved_instance_item->{state}, ); push @$reserved_instances, $reserved_instance; } return $reserved_instances; } } =head2 describe_reserved_instances_offerings(%params) Describes Reserved Instance offerings that are available for purchase. With Amazon EC2 Reserved Instances, you purchase the right to launch Amazon EC2 instances for a period of time (without getting insufficient capacity errors) and pay a lower usage rate for the actual time used. =over =item ReservedInstancesOfferingId (optional) ID of the Reserved Instances to describe. =item InstanceType (optional) The instance type on which the Reserved Instance can be used. =item AvailabilityZone (optional) The Availability Zone in which the Reserved Instance can be used. =item ProductDescription (optional) The Reserved Instance description. =back Returns an array ref of Net::Amazon::EC2::ReservedInstanceOffering objects =cut sub describe_reserved_instances_offerings { my $self = shift; my %args = validate( @_, { ReservedInstancesOfferingId => { type => SCALAR, optional => 1 }, InstanceType => { type => SCALAR, optional => 1 }, AvailabilityZone => { type => SCALAR, optional => 1 }, ProductDescription => { type => SCALAR, optional => 1 }, }); my $xml = $self->_sign(Action => 'DescribeReservedInstancesOfferings', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $reserved_instance_offerings; foreach my $reserved_instance_offering_item (@{$xml->{reservedInstancesOfferingsSet}{item}}) { my $reserved_instance_offering = Net::Amazon::EC2::ReservedInstanceOffering->new( reserved_instances_offering_id => $reserved_instance_offering_item->{reservedInstancesOfferingId}, instance_type => $reserved_instance_offering_item->{instanceType}, availability_zone => $reserved_instance_offering_item->{availabilityZone}, duration => $reserved_instance_offering_item->{duration}, start => $reserved_instance_offering_item->{start}, usage_price => $reserved_instance_offering_item->{usagePrice}, fixed_price => $reserved_instance_offering_item->{fixedPrice}, instance_count => $reserved_instance_offering_item->{instanceCount}, product_description => $reserved_instance_offering_item->{productDescription}, state => $reserved_instance_offering_item->{state}, ); push @$reserved_instance_offerings, $reserved_instance_offering; } return $reserved_instance_offerings; } } =head2 describe_security_groups(%params) This method describes the security groups available to this account. It takes the following parameter: =over =item GroupName (optional) The name of the security group(s) to be described. Can be either a scalar or an array ref. =back Returns an array ref of Net::Amazon::EC2::SecurityGroup objects =cut sub describe_security_groups { my $self = shift; my %args = validate( @_, { GroupName => { type => SCALAR | ARRAYREF, optional => 1 }, }); # If we have a array ref of instances lets split them out into their InstanceId.n format if (ref ($args{GroupName}) eq 'ARRAY') { my $groups = delete $args{GroupName}; my $count = 1; foreach my $group (@{$groups}) { $args{"GroupName." . $count} = $group; $count++; } } my $xml = $self->_sign(Action => 'DescribeSecurityGroups', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $security_groups; foreach my $sec_grp (@{$xml->{securityGroupInfo}{item}}) { my $owner_id = $sec_grp->{ownerId}; my $group_name = $sec_grp->{groupName}; my $group_description = $sec_grp->{groupDescription}; my $ip_permissions; foreach my $ip_perm (@{$sec_grp->{ipPermissions}{item}}) { my $ip_protocol = $ip_perm->{ipProtocol}; my $from_port = $ip_perm->{fromPort}; my $to_port = $ip_perm->{toPort}; my $icmp_port = $ip_perm->{icmpPort}; my $groups; my $ip_ranges; if (grep { defined && length } $ip_perm->{groups}{item}) { foreach my $grp (@{$ip_perm->{groups}{item}}) { my $group = Net::Amazon::EC2::UserIdGroupPair->new( user_id => $grp->{userId}, group_name => $grp->{groupName}, ); push @$groups, $group; } } if (grep { defined && length } $ip_perm->{ipRanges}{item}) { foreach my $rng (@{$ip_perm->{ipRanges}{item}}) { my $ip_range = Net::Amazon::EC2::IpRange->new( cidr_ip => $rng->{cidrIp}, ); push @$ip_ranges, $ip_range; } } my $ip_permission = Net::Amazon::EC2::IpPermission->new( ip_protocol => $ip_protocol, group_name => $group_name, group_description => $group_description, from_port => $from_port, to_port => $to_port, icmp_port => $icmp_port, ); if ($ip_ranges) { $ip_permission->ip_ranges($ip_ranges); } if ($groups) { $ip_permission->groups($groups); } push @$ip_permissions, $ip_permission; } my $security_group = Net::Amazon::EC2::SecurityGroup->new( owner_id => $owner_id, group_name => $group_name, group_description => $group_description, ip_permissions => $ip_permissions, ); push @$security_groups, $security_group; } return $security_groups; } } =head2 describe_snapshot_attribute(%params) Describes the snapshots attributes related to the snapshot in question. It takes the following arguments: =over =item SnapshotId (optional) Either a scalar or array ref of snapshot id's can be passed in. If this isn't passed in it will describe the attributes of all the current snapshots. =item Attribute (required) The attribute to describe, currently, the only valid attribute is createVolumePermission. =back Returns a Net::Amazon::EC2::SnapshotAttribute object. =cut sub describe_snapshot_attribute { my $self = shift; my %args = validate( @_, { SnapshotId => { type => ARRAYREF | SCALAR, optional => 1 }, Attribute => { type => SCALAR }, }); # If we have a array ref of volumes lets split them out into their SnapshotId.n format if (ref ($args{SnapshotId}) eq 'ARRAY') { my $snapshots = delete $args{SnapshotId}; my $count = 1; foreach my $snapshot (@{$snapshots}) { $args{"SnapshotId." . $count} = $snapshot; $count++; } } my $xml = $self->_sign(Action => 'DescribeSnapshotAttribute', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $perms; unless ( grep { defined && length } $xml->{createVolumePermission} and ref $xml->{createVolumePermission} ne 'HASH') { $perms = undef; } foreach my $perm_item (@{$xml->{createVolumePermission}{item}}) { my $perm = Net::Amazon::EC2::CreateVolumePermission->new( user_id => $perm_item->{userId}, group => $perm_item->{group}, ); push @$perms, $perm; } my $snapshot_attribute = Net::Amazon::EC2::SnapshotAttribute->new( snapshot_id => $xml->{snapshotId}, permissions => $perms, ); return $snapshot_attribute; } } =head2 describe_snapshots(%params) Describes the snapshots available to the user. It takes the following arguments: =over =item SnapshotId (optional) Either a scalar or array ref of snapshot id's can be passed in. If this isn't passed in it will describe all the current snapshots. =item Owner (optional) The owner of the snapshot. =item RestorableBy (optional) A user who can create volumes from the snapshot. =item Filter (optional) The filters for only the matching snapshots to be 'described'. A filter tuple is an arrayref constsing one key and one or more values. The option takes one filter tuple, or an arrayref of multiple filter tuples. =back Returns an array ref of Net::Amazon::EC2::Snapshot objects. =cut sub describe_snapshots { my $self = shift; my %args = validate( @_, { SnapshotId => { type => ARRAYREF | SCALAR, optional => 1 }, Owner => { type => SCALAR, optional => 1 }, RestorableBy => { type => SCALAR, optional => 1 }, Filter => { type => ARRAYREF, optional => 1 }, }); $self->_build_filters(\%args); # If we have a array ref of volumes lets split them out into their SnapshotId.n format if (ref ($args{SnapshotId}) eq 'ARRAY') { my $snapshots = delete $args{SnapshotId}; my $count = 1; foreach my $snapshot (@{$snapshots}) { $args{"SnapshotId." . $count} = $snapshot; $count++; } } my $xml = $self->_sign(Action => 'DescribeSnapshots', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $snapshots; foreach my $snap (@{$xml->{snapshotSet}{item}}) { unless ( grep { defined && length } $snap->{description} and ref $snap->{description} ne 'HASH') { $snap->{description} = undef; } unless ( grep { defined && length } $snap->{progress} and ref $snap->{progress} ne 'HASH') { $snap->{progress} = undef; } my $snapshot = Net::Amazon::EC2::Snapshot->new( snapshot_id => $snap->{snapshotId}, status => $snap->{status}, volume_id => $snap->{volumeId}, start_time => $snap->{startTime}, progress => $snap->{progress}, owner_id => $snap->{ownerId}, volume_size => $snap->{volumeSize}, description => $snap->{description}, owner_alias => $snap->{ownerAlias}, ); push @$snapshots, $snapshot; } return $snapshots; } } =head2 describe_volumes(%params) Describes the volumes currently created. It takes the following arguments: =over =item VolumeId (optional) Either a scalar or array ref of volume id's can be passed in. If this isn't passed in it will describe all the current volumes. =back Returns an array ref of Net::Amazon::EC2::Volume objects. =cut sub describe_volumes { my $self = shift; my %args = validate( @_, { VolumeId => { type => ARRAYREF | SCALAR, optional => 1 }, }); # If we have a array ref of volumes lets split them out into their Volume.n format if (ref ($args{VolumeId}) eq 'ARRAY') { my $volumes = delete $args{VolumeId}; my $count = 1; foreach my $volume (@{$volumes}) { $args{"VolumeId." . $count} = $volume; $count++; } } my $xml = $self->_sign(Action => 'DescribeVolumes', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $volumes; foreach my $volume_set (@{$xml->{volumeSet}{item}}) { my $attachments; unless ( grep { defined && length } $volume_set->{snapshotId} and ref $volume_set->{snapshotId} ne 'HASH') { $volume_set->{snapshotId} = undef; } foreach my $attachment_set (@{$volume_set->{attachmentSet}{item}}) { my $attachment = Net::Amazon::EC2::Attachment->new( volume_id => $attachment_set->{volumeId}, status => $attachment_set->{status}, instance_id => $attachment_set->{instanceId}, attach_time => $attachment_set->{attachTime}, device => $attachment_set->{device}, delete_on_termination => $attachment_set->{deleteOnTermination}, ); push @$attachments, $attachment; } my $tags; foreach my $tag_arr (@{$volume_set->{tagSet}{item}}) { if ( ref $tag_arr->{value} eq "HASH" ) { $tag_arr->{value} = ""; } my $tag = Net::Amazon::EC2::TagSet->new( key => $tag_arr->{key}, value => $tag_arr->{value}, ); push @$tags, $tag; } my $volume = Net::Amazon::EC2::Volume->new( volume_id => $volume_set->{volumeId}, status => $volume_set->{status}, zone => $volume_set->{availabilityZone}, create_time => $volume_set->{createTime}, snapshot_id => $volume_set->{snapshotId}, size => $volume_set->{size}, volume_type => $volume_set->{volumeType}, iops => $volume_set->{iops}, tag_set => $tags, attachments => $attachments, ); push @$volumes, $volume; } return $volumes; } } =head2 describe_tags(%params) This method describes the tags available on this account. It takes the following parameter: =over =item Filter.Name (optional) The name of the Filter.Name to be described. Can be either a scalar or an array ref. =item Filter.Value (optional) The name of the Filter.Value to be described. Can be either a scalar or an array ref. =back Returns an array ref of Net::Amazon::EC2::DescribeTags objects =cut sub describe_tags { my $self = shift; my %args = validate( @_, { 'Filter.Name' => { type => ARRAYREF | SCALAR, optional => 1 }, 'Filter.Value' => { type => ARRAYREF | SCALAR, optional => 1 }, }); if (ref ($args{'Filter.Name'}) eq 'ARRAY') { my $keys = delete $args{'Filter.Name'}; my $count = 1; foreach my $key (@{$keys}) { $args{"Filter." . $count . ".Name"} = $key; $count++; } } if (ref ($args{'Filter.Value'}) eq 'ARRAY') { my $keys = delete $args{'Filter.Value'}; my $count = 1; foreach my $key (@{$keys}) { $args{"Filter." . $count . ".Value"} = $key; $count++; } } my $xml = $self->_sign(Action => 'DescribeTags', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $tags; foreach my $pair (@{$xml->{tagSet}{item}}) { my $tag = Net::Amazon::EC2::DescribeTags->new( resource_id => $pair->{resourceId}, resource_type => $pair->{resourceType}, key => $pair->{key}, value => $pair->{value}, ); push @$tags, $tag; } return $tags; } } =head2 detach_volume(%params) Detach a volume from an instance. =over =item VolumeId (required) The volume id you wish to detach. =item InstanceId (optional) The instance id you wish to detach from. =item Device (optional) The device the volume was attached as. =item Force (optional) A boolean for if to forcibly detach the volume from the instance. WARNING: This can lead to data loss or a corrupted file system. Use this option only as a last resort to detach a volume from a failed instance. The instance will not have an opportunity to flush file system caches nor file system meta data. =back Returns a Net::Amazon::EC2::Attachment object containing the resulting volume status. =cut sub detach_volume { my $self = shift; my %args = validate( @_, { VolumeId => { type => SCALAR }, InstanceId => { type => SCALAR, optional => 1 }, Device => { type => SCALAR, optional => 1 }, Force => { type => SCALAR, optional => 1 }, }); my $xml = $self->_sign(Action => 'DetachVolume', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $attachment = Net::Amazon::EC2::Attachment->new( volume_id => $xml->{volumeId}, status => $xml->{status}, instance_id => $xml->{instanceId}, attach_time => $xml->{attachTime}, device => $xml->{device}, ); return $attachment; } } =head2 disassociate_address(%params) Disassociates an elastic IP address with an instance. It takes the following arguments: =over =item PublicIp (required) The IP address to disassociate =back Returns true if the disassociation succeeded. =cut sub disassociate_address { my $self = shift; my %args = validate( @_, { PublicIp => { type => SCALAR }, }); my $xml = $self->_sign(Action => 'DisassociateAddress', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{return} eq 'true') { return 1; } else { return undef; } } } =head2 get_console_output(%params) This method gets the output from the virtual console for an instance. It takes the following parameters: =over =item InstanceId (required) A scalar containing a instance id. =back Returns a Net::Amazon::EC2::ConsoleOutput object. =cut sub get_console_output { my $self = shift; my %args = validate( @_, { InstanceId => { type => SCALAR }, }); my $xml = $self->_sign(Action => 'GetConsoleOutput', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $console_output = Net::Amazon::EC2::ConsoleOutput->new( instance_id => $xml->{instanceId}, timestamp => $xml->{timestamp}, output => decode_base64($xml->{output}), ); return $console_output; } } =head2 get_password_data(%params) Retrieves the encrypted administrator password for the instances running Windows. This procedure is not applicable for Linux and UNIX instances. =over =item InstanceId (required) The Instance Id for which to retrieve the password. =back Returns a Net::Amazon::EC2::InstancePassword object =cut sub get_password_data { my $self = shift; my %args = validate( @_, { instanceId => { type => SCALAR }, }); my $xml = $self->_sign(Action => 'GetPasswordData', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $instance_password = Net::Amazon::EC2::InstancePassword->new( instance_id => $xml->{instanceId}, timestamp => $xml->{timestamp}, password_data => $xml->{passwordData}, ); return $instance_password; } } =head2 modify_image_attribute(%params) This method modifies attributes of an machine image. =over =item ImageId (required) The AMI to modify the attributes of. =item Attribute (required) The attribute you wish to modify, right now the attributes you can modify are launchPermission and productCodes =item OperationType (required for launchPermission) The operation you wish to perform on the attribute. Right now just 'add' and 'remove' are supported. =item UserId (required for launchPermission) User Id's you wish to add/remove from the attribute. =item UserGroup (required for launchPermission) Groups you wish to add/remove from the attribute. Currently there is only one User Group available 'all' for all Amazon EC2 customers. =item ProductCode (required for productCodes) Attaches a product code to the AMI. Currently only one product code can be assigned to the AMI. Once this is set it cannot be changed or reset. =back Returns 1 if the modification succeeds. =cut sub modify_image_attribute { my $self = shift; my %args = validate( @_, { ImageId => { type => SCALAR }, Attribute => { type => SCALAR }, OperationType => { type => SCALAR, optional => 1 }, UserId => { type => SCALAR | ARRAYREF, optional => 1 }, UserGroup => { type => SCALAR | ARRAYREF, optional => 1 }, ProductCode => { type => SCALAR, optional => 1 }, }); my $xml = $self->_sign(Action => 'ModifyImageAttribute', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{return} eq 'true') { return 1; } else { return undef; } } } =head2 modify_instance_attribute(%params) Modify an attribute of an instance. =over =item InstanceId (required) The instance id we want to modify the attributes of. =item Attribute (required) The attribute we want to modify. Valid values are: =over =item * instanceType =item * kernel =item * ramdisk =item * userData =item * disableApiTermination =item * instanceInitiatedShutdownBehavior =item * rootDeviceName =item * blockDeviceMapping =back =item Value (required) The value to set the attribute to. You may also pass a hashref with one or more keys and values. This hashref will be flattened and passed to AWS. For example: $ec2->modify_instance_attribute( 'InstanceId' => $id, 'Attribute' => 'blockDeviceMapping', 'Value' => { 'BlockDeviceMapping.1.DeviceName' => '/dev/sdf1', 'BlockDeviceMapping.1.Ebs.DeleteOnTermination' => 'true', } ); =back Returns 1 if the modification succeeds. =cut sub modify_instance_attribute { my $self = shift; my %args = validate( @_, { InstanceId => { type => SCALAR }, Attribute => { type => SCALAR }, Value => { type => SCALAR | HASHREF }, }); if ( ref($args{'Value'}) eq "HASH" ) { # remove the 'Value' key and flatten the hashref my $href = delete $args{'Value'}; map { $args{$_} = $href->{$_} } keys %{$href}; } my $xml = $self->_sign(Action => 'ModifyInstanceAttribute', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{return} eq 'true') { return 1; } else { return undef; } } } =head2 modify_snapshot_attribute(%params) This method modifies attributes of a snapshot. =over =item SnapshotId (required) The snapshot id to modify the attributes of. =item UserId (optional) User Id you wish to add/remove create volume permissions for. =item UserGroup (optional) User Id you wish to add/remove create volume permissions for. To make the snapshot createable by all set the UserGroup to "all". =item Attribute (required) The attribute you wish to modify, right now the only attribute you can modify is "CreateVolumePermission" =item OperationType (required) The operation you wish to perform on the attribute. Right now just 'add' and 'remove' are supported. =back Returns 1 if the modification succeeds. =cut sub modify_snapshot_attribute { my $self = shift; my %args = validate( @_, { SnapshotId => { type => SCALAR }, UserId => { type => SCALAR, optional => 1 }, UserGroup => { type => SCALAR, optional => 1 }, Attribute => { type => SCALAR }, OperationType => { type => SCALAR }, }); my $xml = $self->_sign(Action => 'ModifySnapshotAttribute', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{return} eq 'true') { return 1; } else { return undef; } } } =head2 monitor_instances(%params) Enables monitoring for a running instance. For more information, refer to the Amazon CloudWatch Developer Guide. =over =item InstanceId (required) The instance id(s) to monitor. Can be a scalar or an array ref =back Returns an array ref of Net::Amazon::EC2::MonitoredInstance objects =cut sub monitor_instances { my $self = shift; my %args = validate( @_, { InstanceId => { type => ARRAYREF | SCALAR, optional => 1 }, }); # If we have a array ref of instances lets split them out into their InstanceId.n format if (ref ($args{InstanceId}) eq 'ARRAY') { my $instance_ids = delete $args{InstanceId}; my $count = 1; foreach my $instance_id (@{$instance_ids}) { $args{"InstanceId." . $count} = $instance_id; $count++; } } my $xml = $self->_sign(Action => 'MonitorInstances', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $monitored_instances; foreach my $monitored_instance_item (@{$xml->{instancesSet}{item}}) { my $monitored_instance = Net::Amazon::EC2::ReservedInstance->new( instance_id => $monitored_instance_item->{instanceId}, state => $monitored_instance_item->{monitoring}{state}, ); push @$monitored_instances, $monitored_instance; } return $monitored_instances; } } =head2 purchase_reserved_instances_offering(%params) Purchases a Reserved Instance for use with your account. With Amazon EC2 Reserved Instances, you purchase the right to launch Amazon EC2 instances for a period of time (without getting insufficient capacity errors) and pay a lower usage rate for the actual time used. =over =item ReservedInstancesOfferingId (required) ID of the Reserved Instances to describe. Can be either a scalar or an array ref. =item InstanceCount (optional) The number of Reserved Instances to purchase (default is 1). Can be either a scalar or an array ref. NOTE NOTE NOTE, the array ref needs to line up with the InstanceCount if you want to pass that in, so that the right number of instances are started of the right instance offering =back Returns 1 if the reservations succeeded. =cut sub purchase_reserved_instances_offering { my $self = shift; my %args = validate( @_, { ReservedInstancesOfferingId => { type => ARRAYREF | SCALAR }, InstanceCount => { type => ARRAYREF | SCALAR, optional => 1 }, }); # If we have a array ref of reserved instance offerings lets split them out into their ReservedInstancesOfferingId.n format if (ref ($args{ReservedInstancesOfferingId}) eq 'ARRAY') { my $reserved_instance_offering_ids = delete $args{ReservedInstancesOfferingId}; my $count = 1; foreach my $reserved_instance_offering_id (@{$reserved_instance_offering_ids}) { $args{"ReservedInstancesOfferingId." . $count} = $reserved_instance_offering_id; $count++; } } # If we have a array ref of instance counts lets split them out into their InstanceCount.n format if (ref ($args{InstanceCount}) eq 'ARRAY') { my $instance_counts = delete $args{InstanceCount}; my $count = 1; foreach my $instance_count (@{$instance_counts}) { $args{"InstanceCount." . $count} = $instance_count; $count++; } } my $xml = $self->_sign(Action => 'PurchaseReservedInstancesOffering', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{reservedInstancesId} ) { return 1; } else { return undef; } } } =head2 reboot_instances(%params) This method reboots an instance. It takes the following parameters: =over =item InstanceId (required) Instance Id of the instance you wish to reboot. Can be either a scalar or array ref of instances to reboot. =back Returns 1 if the reboot succeeded. =cut sub reboot_instances { my $self = shift; my %args = validate( @_, { InstanceId => { type => SCALAR }, }); # If we have a array ref of instances lets split them out into their InstanceId.n format if (ref ($args{InstanceId}) eq 'ARRAY') { my $instance_ids = delete $args{InstanceId}; my $count = 1; foreach my $instance_id (@{$instance_ids}) { $args{"InstanceId." . $count} = $instance_id; $count++; } } my $xml = $self->_sign(Action => 'RebootInstances', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{return} eq 'true') { return 1; } else { return undef; } } } =head2 register_image(%params) This method registers an AMI on the EC2. It takes the following parameter: =over =item imageLocation (optional) The location of the AMI manifest on S3 =item name (required) The name of the AMI that was provided during image creation. =item description (optional) The description of the AMI. =item architecture (optional) The architecture of the image. Either i386 or x86_64 =item kernelId (optional) The ID of the kernel to select. =item ramdiskId (optional) The ID of the RAM disk to select. Some kernels require additional drivers at launch. =item rootDeviceName (optional) The root device name (e.g., /dev/sda1). =item blockDeviceMapping (optional) This needs to be a data structure like this: [ { deviceName => "/dev/sdh", (optional) virtualName => "ephermel0", (optional) noDevice => "/dev/sdl", (optional), ebs => { snapshotId => "snap-0000", (optional) volumeSize => "20", (optional) deleteOnTermination => "false", (optional) }, }, ... ] =back Returns the image id of the new image on EC2. =cut sub register_image { my $self = shift; my %args = validate( @_, { ImageLocation => { type => SCALAR, optional => 1 }, Name => { type => SCALAR }, Description => { type => SCALAR, optional => 1 }, Architecture => { type => SCALAR, optional => 1 }, KernelId => { type => SCALAR, optional => 1 }, RamdiskId => { type => SCALAR, optional => 1 }, RootDeviceName => { type => SCALAR, optional => 1 }, BlockDeviceMapping => { type => ARRAYREF, optional => 1 }, }); # If we have a array ref of block devices, we need to split them up if (ref ($args{BlockDeviceMapping}) eq 'ARRAY') { my $block_devices = delete $args{BlockDeviceMapping}; my $count = 1; foreach my $block_device (@{$block_devices}) { $args{"BlockDeviceMapping." . $count . ".DeviceName"} = $block_device->{deviceName} if $block_device->{deviceName}; $args{"BlockDeviceMapping." . $count . ".VirtualName"} = $block_device->{virtualName} if $block_device->{virtualName}; $args{"BlockDeviceMapping." . $count . ".NoDevice"} = $block_device->{noDevice} if $block_device->{noDevice}; $args{"BlockDeviceMapping." . $count . ".Ebs.SnapshotId"} = $block_device->{ebs}{snapshotId} if $block_device->{ebs}{snapshotId}; $args{"BlockDeviceMapping." . $count . ".Ebs.VolumeSize"} = $block_device->{ebs}{volumeSize} if $block_device->{ebs}{volumeSize}; $args{"BlockDeviceMapping." . $count . ".Ebs.DeleteOnTermination"} = $block_device->{ebs}{deleteOnTermination} if $block_device->{ebs}{deleteOnTermination}; $count++; } } my $xml = $self->_sign(Action => 'RegisterImage', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { return $xml->{imageId}; } } =head2 release_address(%params) Releases an allocated IP address. It takes the following arguments: =over =item PublicIp (required) The IP address to release =back Returns true if the releasing succeeded. =cut sub release_address { my $self = shift; my %args = validate( @_, { PublicIp => { type => SCALAR }, }); my $xml = $self->_sign(Action => 'ReleaseAddress', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{return} eq 'true') { return 1; } else { return undef; } } } =head2 reset_image_attribute(%params) This method resets an attribute for an AMI to its default state (NOTE: product codes cannot be reset). It takes the following parameters: =over =item ImageId (required) The image id of the AMI you wish to reset the attributes on. =item Attribute (required) The attribute you want to reset. =back Returns 1 if the attribute reset succeeds. =cut sub reset_image_attribute { my $self = shift; my %args = validate( @_, { ImageId => { type => SCALAR }, Attribute => { type => SCALAR }, }); my $xml = $self->_sign(Action => 'ResetImageAttribute', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{return} eq 'true') { return 1; } else { return undef; } } } =head2 reset_instance_attribute(%params) Reset an attribute of an instance. Only one attribute can be specified per call. =over =item InstanceId (required) The instance id we want to reset the attributes of. =item Attribute (required) The attribute we want to reset. Valid values are: =over =item * kernel =item * ramdisk =back =back Returns 1 if the reset succeeds. =cut sub reset_instance_attribute { my $self = shift; my %args = validate( @_, { InstanceId => { type => SCALAR }, Attribute => { type => SCALAR }, }); my $xml = $self->_sign(Action => 'ResetInstanceAttribute', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{return} eq 'true') { return 1; } else { return undef; } } } =head2 reset_snapshot_attribute(%params) This method resets an attribute for an snapshot to its default state. It takes the following parameters: =over =item SnapshotId (required) The snapshot id of the snapshot you wish to reset the attributes on. =item Attribute (required) The attribute you want to reset (currently "CreateVolumePermission" is the only valid attribute). =back Returns 1 if the attribute reset succeeds. =cut sub reset_snapshot_attribute { my $self = shift; my %args = validate( @_, { SnapshotId => { type => SCALAR }, Attribute => { type => SCALAR }, }); my $xml = $self->_sign(Action => 'ResetSnapshotAttribute', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{return} eq 'true') { return 1; } else { return undef; } } } =head2 revoke_security_group_ingress(%params) This method revoke permissions to a security group. It takes the following parameters: =over =item GroupName (required) The name of the group to revoke security rules from. =item SourceSecurityGroupName (required when revoking a user and group together) Name of the group to revoke access from. =item SourceSecurityGroupOwnerId (required when revoking a user and group together) Owner of the group to revoke access from. =item IpProtocol (required when revoking access from a CIDR) IP Protocol of the rule you are revoking access from (TCP, UDP, or ICMP) =item FromPort (required when revoking access from a CIDR) Beginning of port range to revoke access from. =item ToPort (required when revoking access from a CIDR) End of port range to revoke access from. =item CidrIp (required when revoking access from a CIDR) The CIDR IP space we are revoking access from. =back Revoking a rule can be done in two ways: revoking a source group name + source group owner id, or, by Protocol + start port + end port + CIDR IP. The two are mutally exclusive. Returns 1 if rule is revoked successfully. =cut sub revoke_security_group_ingress { my $self = shift; my %args = validate( @_, { GroupName => { type => SCALAR }, SourceSecurityGroupName => { type => SCALAR, depends => ['SourceSecurityGroupOwnerId'], optional => 1 , }, SourceSecurityGroupOwnerId => { type => SCALAR, optional => 1 }, IpProtocol => { type => SCALAR, depends => ['FromPort', 'ToPort', 'CidrIp'], optional => 1 }, FromPort => { type => SCALAR, optional => 1 }, ToPort => { type => SCALAR, optional => 1 }, CidrIp => { type => SCALAR, optional => 1 }, }); my $xml = $self->_sign(Action => 'RevokeSecurityGroupIngress', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { if ($xml->{return} eq 'true') { return 1; } else { return undef; } } } =head2 run_instances(%params) This method will start instance(s) of AMIs on EC2. The parameters indicate which AMI to instantiate and how many / what properties they have: =over =item ImageId (required) The image id you want to start an instance of. =item MinCount (required) The minimum number of instances to start. =item MaxCount (required) The maximum number of instances to start. =item KeyName (optional) The keypair name to associate this instance with. If omitted, will use your default keypair. =item SecurityGroup (optional) An scalar or array ref. Will associate this instance with the group names passed in. If omitted, will be associated with the default security group. =item SecurityGroupId (optional) An scalar or array ref. Will associate this instance with the group ids passed in. If omitted, will be associated with the default security group. =item AdditionalInfo (optional) Specifies additional information to make available to the instance(s). =item UserData (optional) Optional data to pass into the instance being started. Needs to be base64 encoded. =item InstanceType (optional) Specifies the type of instance to start. See http://aws.amazon.com/ec2/instance-types The options are: =over =item m1.small (default) 1 EC2 Compute Unit (1 virtual core with 1 EC2 Compute Unit). 32-bit or 64-bit, 1.7GB RAM, 160GB disk =item m1.medium Medium Instance 2 EC2 Compute Units (1 virtual core with 2 EC2 Compute Unit), 32-bit or 64-bit, 3.75GB RAM, 410GB disk =item m1.large: Standard Large Instance 4 EC2 Compute Units (2 virtual cores with 2 EC2 Compute Units each). 64-bit, 7.5GB RAM, 850GB disk =item m1.xlarge: Standard Extra Large Instance 8 EC2 Compute Units (4 virtual cores with 2 EC2 Compute Units each). 64-bit, 15GB RAM, 1690GB disk =item t1.micro Micro Instance Up to 2 EC2 Compute Units (for short periodic bursts), 32-bit or 64-bit, 613MB RAM, EBS storage only =item c1.medium: High-CPU Medium Instance 5 EC2 Compute Units (2 virutal cores with 2.5 EC2 Compute Units each). 32-bit or 64-bit, 1.7GB RAM, 350GB disk =item c1.xlarge: High-CPU Extra Large Instance 20 EC2 Compute Units (8 virtual cores with 2.5 EC2 Compute Units each). 64-bit, 7GB RAM, 1690GB disk =item m2.2xlarge High-Memory Double Extra Large Instance 13 EC2 Compute Units (4 virtual cores with 3.25 EC2 Compute Units each). 64-bit, 34.2GB RAM, 850GB disk =item m2.4xlarge High-Memory Quadruple Extra Large Instance 26 EC2 Compute Units (8 virtual cores with 3.25 EC2 Compute Units each). 64-bit, 68.4GB RAM, 1690GB disk =item cc1.4xlarge Cluster Compute Quadruple Extra Large Instance 33.5 EC2 Compute Units (2 x Intel Xeon X5570, quad-core "Nehalem" architecture), 64-bit, 23GB RAM, 1690GB disk, 10Gbit Ethernet =item cc1.8xlarge Cluster Compute Eight Extra Large Instance 88 EC2 Compute Units (2 x Intel Xeon E5-2670, eight-core "Sandy Bridge" architecture), 64-bit, 60.5GB RAM, 3370GB disk, 10Gbit Ethernet =item cg1.4xlarge Cluster GPU Quadruple Extra Large Instance 33.5 EC2 Compute Units (2 x Intel Xeon X5570, quad-core "Nehalem" architecture), 64-bit, 22GB RAM 1690GB disk, 10Gbit Ethernet, 2 x NVIDIA Tesla "Fermi" M2050 GPUs =item hi1.4xlarge High I/O Quadruple Extra Large Instance 35 EC2 Compute Units (16 virtual cores), 60.5GB RAM, 64-bit, 2 x 1024GB SSD disk, 10Gbit Ethernet =back =item Placement.AvailabilityZone (optional) The availability zone you want to run the instance in =item KernelId (optional) The id of the kernel you want to launch the instance with =item RamdiskId (optional) The id of the ramdisk you want to launch the instance with =item BlockDeviceMapping.VirtualName (optional) This is the virtual name for a blocked device to be attached, may pass in a scalar or arrayref =item BlockDeviceMapping.DeviceName (optional) This is the device name for a block device to be attached, may pass in a scalar or arrayref =item Encoding (optional) The encoding. =item Version (optional) The version. =item Monitoring.Enabled (optional) Enables monitoring for this instance. =item SubnetId (optional) Specifies the subnet ID within which to launch the instance(s) for Amazon Virtual Private Cloud. =item ClientToken (optional) Specifies the idempotent instance id. =item EbsOptimized (optional) Whether the instance is optimized for EBS I/O. =item PrivateIpAddress (optional) Specifies the private IP address to use when launching an Amazon VPC instance. =item IamInstanceProfile.Name (optional) Specifies the IAM profile to associate with the launched instance(s). This is the name of the role. =item IamInstanceProfile.Arn (optional) Specifies the IAM profile to associate with the launched instance(s). This is the ARN of the profile. =back Returns a Net::Amazon::EC2::ReservationInfo object =cut sub run_instances { my $self = shift; my %args = validate( @_, { ImageId => { type => SCALAR }, MinCount => { type => SCALAR }, MaxCount => { type => SCALAR }, KeyName => { type => SCALAR, optional => 1 }, SecurityGroup => { type => SCALAR | ARRAYREF, optional => 1 }, SecurityGroupId => { type => SCALAR | ARRAYREF, optional => 1 }, AddressingType => { type => SCALAR, optional => 1 }, AdditionalInfo => { type => SCALAR, optional => 1 }, UserData => { type => SCALAR, optional => 1 }, InstanceType => { type => SCALAR, optional => 1 }, 'Placement.AvailabilityZone' => { type => SCALAR, optional => 1 }, KernelId => { type => SCALAR, optional => 1 }, RamdiskId => { type => SCALAR, optional => 1 }, 'BlockDeviceMapping.VirtualName' => { type => SCALAR | ARRAYREF, optional => 1 }, 'BlockDeviceMapping.DeviceName' => { type => SCALAR | ARRAYREF, optional => 1 }, 'BlockDeviceMapping.Ebs.SnapshotId' => { type => SCALAR | ARRAYREF, optional => 1 }, 'BlockDeviceMapping.Ebs.VolumeSize' => { type => SCALAR | ARRAYREF, optional => 1 }, 'BlockDeviceMapping.Ebs.DeleteOnTermination' => { type => SCALAR | ARRAYREF, optional => 1 }, Encoding => { type => SCALAR, optional => 1 }, Version => { type => SCALAR, optional => 1 }, 'Monitoring.Enabled' => { type => SCALAR, optional => 1 }, SubnetId => { type => SCALAR, optional => 1 }, DisableApiTermination => { type => SCALAR, optional => 1 }, InstanceInitiatedShutdownBehavior => { type => SCALAR, optional => 1 }, ClientToken => { type => SCALAR, optional => 1 }, EbsOptimized => { type => SCALAR, optional => 1 }, PrivateIpAddress => { type => SCALAR, optional => 1 }, 'IamInstanceProfile.Name' => { type => SCALAR, optional => 1 }, 'IamInstanceProfile.Arn' => { type => SCALAR, optional => 1 }, }); # If we have a array ref of instances lets split them out into their SecurityGroup.n format if (ref ($args{SecurityGroup}) eq 'ARRAY') { my $security_groups = delete $args{SecurityGroup}; my $count = 1; foreach my $security_group (@{$security_groups}) { $args{"SecurityGroup." . $count} = $security_group; $count++; } } # If we have a array ref of instances lets split them out into their SecurityGroupId.n format if (ref ($args{SecurityGroupId}) eq 'ARRAY') { my $security_groups = delete $args{SecurityGroupId}; my $count = 1; foreach my $security_group (@{$security_groups}) { $args{"SecurityGroupId." . $count} = $security_group; $count++; } } # If we have a array ref of block device virtual names lets split them out into their BlockDeviceMapping.n.VirtualName format if (ref ($args{'BlockDeviceMapping.VirtualName'}) eq 'ARRAY') { my $virtual_names = delete $args{'BlockDeviceMapping.VirtualName'}; my $count = 1; foreach my $virtual_name (@{$virtual_names}) { $args{"BlockDeviceMapping." . $count . ".VirtualName"} = $virtual_name; $count++; } } # If we have a array ref of block device virtual names lets split them out into their BlockDeviceMapping.n.DeviceName format if (ref ($args{'BlockDeviceMapping.DeviceName'}) eq 'ARRAY') { my $device_names = delete $args{'BlockDeviceMapping.DeviceName'}; my $count = 1; foreach my $device_name (@{$device_names}) { $args{"BlockDeviceMapping." . $count . ".DeviceName"} = $device_name; $count++; } } # If we have a array ref of block device EBS Snapshots lets split them out into their BlockDeviceMapping.n.Ebs.SnapshotId format if (ref ($args{'BlockDeviceMapping.Ebs.SnapshotId'}) eq 'ARRAY') { my $snapshot_ids = delete $args{'BlockDeviceMapping.Ebs.SnapshotId'}; my $count = 1; foreach my $snapshot_id (@{$snapshot_ids}) { $args{"BlockDeviceMapping." . $count . ".Ebs.SnapshotId"} = $snapshot_id; $count++; } } # If we have a array ref of block device EBS VolumeSizes lets split them out into their BlockDeviceMapping.n.Ebs.VolumeSize format if (ref ($args{'BlockDeviceMapping.Ebs.VolumeSize'}) eq 'ARRAY') { my $volume_sizes = delete $args{'BlockDeviceMapping.Ebs.VolumeSize'}; my $count = 1; foreach my $volume_size (@{$volume_sizes}) { $args{"BlockDeviceMapping." . $count . ".Ebs.VolumeSize"} = $volume_size; $count++; } } # If we have a array ref of block device EBS DeleteOnTerminations lets split them out into their BlockDeviceMapping.n.Ebs.DeleteOnTermination format if (ref ($args{'BlockDeviceMapping.Ebs.DeleteOnTermination'}) eq 'ARRAY') { my $terminations = delete $args{'BlockDeviceMapping.Ebs.DeleteOnTermination'}; my $count = 1; foreach my $termination (@{$terminations}) { $args{"BlockDeviceMapping." . $count . ".Ebs.DeleteOnTermination"} = $termination; $count++; } } my $xml = $self->_sign(Action => 'RunInstances', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $group_sets=[]; foreach my $group_arr (@{$xml->{groupSet}{item}}) { my $group = Net::Amazon::EC2::GroupSet->new( group_id => $group_arr->{groupId}, group_name => $group_arr->{groupName}, ); push @$group_sets, $group; } my $running_instances; foreach my $instance_elem (@{$xml->{instancesSet}{item}}) { my $instance_state_type = Net::Amazon::EC2::InstanceState->new( code => $instance_elem->{instanceState}{code}, name => $instance_elem->{instanceState}{name}, ); my $product_codes; my $state_reason; my $block_device_mappings; if (grep { defined && length } $instance_elem->{productCodes} ) { foreach my $pc (@{$instance_elem->{productCodes}{item}}) { my $product_code = Net::Amazon::EC2::ProductCode->new( product_code => $pc->{productCode} ); push @$product_codes, $product_code; } } unless ( grep { defined && length } $instance_elem->{reason} and ref $instance_elem->{reason} ne 'HASH' ) { $instance_elem->{reason} = undef; } unless ( grep { defined && length } $instance_elem->{privateDnsName} and ref $instance_elem->{privateDnsName} ne 'HASH') { $instance_elem->{privateDnsName} = undef; } unless ( grep { defined && length } $instance_elem->{dnsName} and ref $instance_elem->{dnsName} ne 'HASH') { $instance_elem->{dnsName} = undef; } if ( grep { defined && length } $instance_elem->{stateReason} ) { $state_reason = Net::Amazon::EC2::StateReason->new( code => $instance_elem->{stateReason}{code}, message => $instance_elem->{stateReason}{message}, ); } if ( grep { defined && length } $instance_elem->{blockDeviceMapping} ) { foreach my $bdm ( @{$instance_elem->{blockDeviceMapping}{item}} ) { my $ebs_block_device_mapping = Net::Amazon::EC2::EbsInstanceBlockDeviceMapping->new( volume_id => $bdm->{ebs}{volumeId}, status => $bdm->{ebs}{status}, attach_time => $bdm->{ebs}{attachTime}, delete_on_termination => $bdm->{ebs}{deleteOnTermination}, ); my $block_device_mapping = Net::Amazon::EC2::BlockDeviceMapping->new( ebs => $ebs_block_device_mapping, device_name => $bdm->{deviceName}, ); push @$block_device_mappings, $block_device_mapping; } } my $placement_response = Net::Amazon::EC2::PlacementResponse->new( availability_zone => $instance_elem->{placement}{availabilityZone} ); my $running_instance = Net::Amazon::EC2::RunningInstances->new( ami_launch_index => $instance_elem->{amiLaunchIndex}, dns_name => $instance_elem->{dnsName}, image_id => $instance_elem->{imageId}, kernel_id => $instance_elem->{kernelId}, ramdisk_id => $instance_elem->{ramdiskId}, instance_id => $instance_elem->{instanceId}, instance_state => $instance_state_type, instance_type => $instance_elem->{instanceType}, key_name => $instance_elem->{keyName}, launch_time => $instance_elem->{launchTime}, placement => $placement_response, private_dns_name => $instance_elem->{privateDnsName}, reason => $instance_elem->{reason}, platform => $instance_elem->{platform}, monitoring => $instance_elem->{monitoring}{state}, subnet_id => $instance_elem->{subnetId}, vpc_id => $instance_elem->{vpcId}, private_ip_address => $instance_elem->{privateIpAddress}, ip_address => $instance_elem->{ipAddress}, architecture => $instance_elem->{architecture}, root_device_name => $instance_elem->{rootDeviceName}, root_device_type => $instance_elem->{rootDeviceType}, block_device_mapping => $block_device_mappings, state_reason => $state_reason, ); if ($product_codes) { $running_instance->product_codes($product_codes); } push @$running_instances, $running_instance; } my $reservation = Net::Amazon::EC2::ReservationInfo->new( reservation_id => $xml->{reservationId}, owner_id => $xml->{ownerId}, group_set => $group_sets, instances_set => $running_instances, ); return $reservation; } } =head2 start_instances(%params) Starts an instance that uses an Amazon EBS volume as its root device. =over =item InstanceId (required) Either a scalar or an array ref can be passed in (containing instance ids to be started). =back Returns an array ref of Net::Amazon::EC2::InstanceStateChange objects. =cut sub start_instances { my $self = shift; my %args = validate( @_, { InstanceId => { type => SCALAR | ARRAYREF }, }); # If we have a array ref of instances lets split them out into their InstanceId.n format if (ref ($args{InstanceId}) eq 'ARRAY') { my $instance_ids = delete $args{InstanceId}; my $count = 1; foreach my $instance_id (@{$instance_ids}) { $args{"InstanceId." . $count} = $instance_id; $count++; } } my $xml = $self->_sign(Action => 'StartInstances', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $started_instances; foreach my $inst (@{$xml->{instancesSet}{item}}) { my $previous_state = Net::Amazon::EC2::InstanceState->new( code => $inst->{previousState}{code}, name => $inst->{previousState}{name}, ); my $current_state = Net::Amazon::EC2::InstanceState->new( code => $inst->{currentState}{code}, name => $inst->{currentState}{name}, ); my $started_instance = Net::Amazon::EC2::InstanceStateChange->new( instance_id => $inst->{instanceId}, previous_state => $previous_state, current_state => $current_state, ); push @$started_instances, $started_instance; } return $started_instances; } } =head2 stop_instances(%params) Stops an instance that uses an Amazon EBS volume as its root device. =over =item InstanceId (required) Either a scalar or an array ref can be passed in (containing instance ids to be stopped). =item Force (optional) If set to true, forces the instance to stop. The instance will not have an opportunity to flush file system caches nor file system meta data. If you use this option, you must perform file system check and repair procedures. This option is not recommended for Windows instances. The default is false. =back Returns an array ref of Net::Amazon::EC2::InstanceStateChange objects. =cut sub stop_instances { my $self = shift; my %args = validate( @_, { InstanceId => { type => SCALAR | ARRAYREF }, Force => { type => SCALAR, optional => 1 }, }); # If we have a array ref of instances lets split them out into their InstanceId.n format if (ref ($args{InstanceId}) eq 'ARRAY') { my $instance_ids = delete $args{InstanceId}; my $count = 1; foreach my $instance_id (@{$instance_ids}) { $args{"InstanceId." . $count} = $instance_id; $count++; } } my $xml = $self->_sign(Action => 'StopInstances', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $stopped_instances; foreach my $inst (@{$xml->{instancesSet}{item}}) { my $previous_state = Net::Amazon::EC2::InstanceState->new( code => $inst->{previousState}{code}, name => $inst->{previousState}{name}, ); my $current_state = Net::Amazon::EC2::InstanceState->new( code => $inst->{currentState}{code}, name => $inst->{currentState}{name}, ); my $stopped_instance = Net::Amazon::EC2::InstanceStateChange->new( instance_id => $inst->{instanceId}, previous_state => $previous_state, current_state => $current_state, ); push @$stopped_instances, $stopped_instance; } return $stopped_instances; } } =head2 terminate_instances(%params) This method shuts down instance(s) passed into it. It takes the following parameter: =over =item InstanceId (required) Either a scalar or an array ref can be passed in (containing instance ids) =back Returns an array ref of Net::Amazon::EC2::InstanceStateChange objects. =cut sub terminate_instances { my $self = shift; my %args = validate( @_, { InstanceId => { type => SCALAR | ARRAYREF }, }); # If we have a array ref of instances lets split them out into their InstanceId.n format if (ref ($args{InstanceId}) eq 'ARRAY') { my $instance_ids = delete $args{InstanceId}; my $count = 1; foreach my $instance_id (@{$instance_ids}) { $args{"InstanceId." . $count} = $instance_id; $count++; } } my $xml = $self->_sign(Action => 'TerminateInstances', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $terminated_instances; foreach my $inst (@{$xml->{instancesSet}{item}}) { my $previous_state = Net::Amazon::EC2::InstanceState->new( code => $inst->{previousState}{code}, name => $inst->{previousState}{name}, ); my $current_state = Net::Amazon::EC2::InstanceState->new( code => $inst->{currentState}{code}, name => $inst->{currentState}{name}, ); # Note, this is a bit of a backwards incompatible change in so much as I am changing # return class for this. I hate to do it but I need to be consistent with this # now being a instance stage change object. This used to be a # Net::Amazon::EC2::TerminateInstancesResponse object. my $terminated_instance = Net::Amazon::EC2::InstanceStateChange->new( instance_id => $inst->{instanceId}, previous_state => $previous_state, current_state => $current_state, ); push @$terminated_instances, $terminated_instance; } return $terminated_instances; } } =head2 unmonitor_instances(%params) Disables monitoring for a running instance. For more information, refer to the Amazon CloudWatch Developer Guide. =over =item InstanceId (required) The instance id(s) to monitor. Can be a scalar or an array ref =back Returns an array ref of Net::Amazon::EC2::MonitoredInstance objects =cut sub unmonitor_instances { my $self = shift; my %args = validate( @_, { InstanceId => { type => ARRAYREF | SCALAR, optional => 1 }, }); # If we have a array ref of instances lets split them out into their InstanceId.n format if (ref ($args{InstanceId}) eq 'ARRAY') { my $instance_ids = delete $args{InstanceId}; my $count = 1; foreach my $instance_id (@{$instance_ids}) { $args{"InstanceId." . $count} = $instance_id; $count++; } } my $xml = $self->_sign(Action => 'UnmonitorInstances', %args); if ( grep { defined && length } $xml->{Errors} ) { return $self->_parse_errors($xml); } else { my $monitored_instances; foreach my $monitored_instance_item (@{$xml->{instancesSet}{item}}) { my $monitored_instance = Net::Amazon::EC2::ReservedInstance->new( instance_id => $monitored_instance_item->{instanceId}, state => $monitored_instance_item->{monitoring}{state}, ); push @$monitored_instances, $monitored_instance; } return $monitored_instances; } } no Moose; 1; __END__ =head1 TESTING Set AWS_ACCESS_KEY_ID and SECRET_ACCESS_KEY environment variables to run the live tests. Note: because the live tests start an instance (and kill it) in both the tests and backwards compat tests there will be 2 hours of machine instance usage charges (since there are 2 instances started) which as of February 1st, 2010 costs a total of $0.17 USD Important note about the windows-only methods. These have not been well tested as I do not run windows-based instances, so exercise caution in using these. =head1 BUGS Please report any bugs or feature requests to C, or through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 AUTHOR Jeff Kim =head1 CONTRIBUTORS John McCullough and others as listed in the Changelog =head1 MAINTAINER The current maintainer is Mark Allen C<< >> =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. Copyright (c) 2012 Mark Allen. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO Amazon EC2 API: L =cut Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/Attachment.pm000644 000765 000024 00000002515 12064473057 022125 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::Attachment; use Moose; =head1 NAME Net::Amazon::EC2::Attachment =head1 DESCRIPTION A class representing a volume attachment to an instance =head1 ATTRIBUTES =over =item volume_id (required) The ID of the volume. =item instance_id (optional) The ID of the instance which this volume was attached to. =item device (required) The device path on the instance that the volume was attached as. =item status (required) The attachment's status. =item attach_time (required) The time the volume was attached. =item delete_on_termination (required) This boolean indicates if an volume is terminated upon instance termination. =back =cut has 'volume_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'instance_id' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'device' => ( is => 'ro', isa => 'Str', required => 1 ); has 'status' => ( is => 'ro', isa => 'Str', required => 1 ); has 'attach_time' => ( is => 'ro', isa => 'Str', required => 1 ); has 'delete_on_termination' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/AvailabilityZone.pm000644 000765 000024 00000002120 12064473057 023273 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::AvailabilityZone; use Moose; =head1 NAME Net::Amazon::EC2::AvailabilityZone =head1 DESCRIPTION A class representing an availability zone =head1 ATTRIBUTES =over =item zone_name (required) Name of the Availability Zone. =item zone_state (required) State of the Availability Zone. =item region_name (required) Name of the region. =item messages (optional) An array ref of Net::Amazon::EC2::AvailabilityZoneMessage objects representing messages for this zone (if any) =back =cut has 'zone_name' => ( is => 'ro', isa => 'Str', required => 1 ); has 'zone_state' => ( is => 'ro', isa => 'Str', required => 1 ); has 'region_name' => ( is => 'ro', isa => 'Maybe[Str]', required => 1 ); has 'messages' => ( is => 'ro', isa => 'ArrayRef[Net::Amazon::EC2::AvailabilityZoneMessage]|Undef', required => 0 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1; Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/AvailabilityZoneMessage.pm000644 000765 000024 00000001152 12064473057 024604 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::AvailabilityZoneMessage; use Moose; =head1 NAME Net::Amazon::EC2::AvailabilityZoneMessage =head1 DESCRIPTION A class containing messaging associated with an availability zone. =head1 ATTRIBUTES =over =item message (required) The message itself. =cut has 'message' => ( is => 'ro', isa => 'Str', required => 1 ); __PACKAGE__->meta->make_immutable(); =back =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/BlockDeviceMapping.pm000644 000765 000024 00000002227 12064473057 023523 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::BlockDeviceMapping; use strict; use Moose; =head1 NAME Net::Amazon::EC2::BlockDeviceMapping =head1 DESCRIPTION A class representing a block device mapping =head1 ATTRIBUTES =over =item device_name (required) Name of the device within Amazon EC2. =item ebs (optional) A Net::Amazon::EC2::EbsInstanceBlockDeviceMapping object representing the EBS mapping =item virtual_name (optional) A virtual device name. =item no_device (optional) Specifies the device name to suppress during instance launch. =back =cut has 'device_name' => ( is => 'ro', isa => 'Str', required => 1 ); has 'ebs' => ( is => 'ro', isa => 'Maybe[Net::Amazon::EC2::EbsBlockDevice]|Maybe[Net::Amazon::EC2::EbsInstanceBlockDeviceMapping]', required => 0 ); has 'virtual_name' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'no_device' => ( is => 'ro', isa => 'Maybe[Int]', required => 0 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/BundleInstanceResponse.pm000644 000765 000024 00000005174 12064473057 024456 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::BundleInstanceResponse; use Moose; =head1 NAME Net::Amazon::EC2::BundleInstanceResponse =head1 DESCRIPTION A class representing a bundled instance =head1 ATTRIBUTES =over =item instance_id (required) Instance associated with this bundle task. =item bundle_id (required) Identifier for this task. =item state (required) The state of this bundling task. =item start_time (required) The time the bundle task started =item update_time (required) The time of the most recent update for the bundle. =item progress (required) A percentage description of the progress of the task, such as 94%. =item s3_bucket (required) The bucket in which to store the AMI. You can specify a bucket that you already own or a new bucket that Amazon EC2 creates on your behalf. If you specify a bucket that belongs to someone else, Amazon EC2 returns an error. =item s3_prefix (required) Specifies the beginning of the file name of the AMI. =item s3_aws_access_key_id (required) The Access Key ID of the owner of the Amazon S3 bucket. =item s3_upload_policy (required) An Amazon S3 upload policy that gives Amazon EC2 permission to upload items into Amazon S3 on the user's behalf. =item s3_policy_upload_signature (required) The signature of the Base64 encoded JSON document. =item bundle_error_code (optional) Error code for bundle failure. =item bundle_error_message (optional) Error message associated with bundle failure. =back =cut has 'instance_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'bundle_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'state' => ( is => 'ro', isa => 'Str', required => 1 ); has 'start_time' => ( is => 'ro', isa => 'Str', required => 1 ); has 'update_time' => ( is => 'ro', isa => 'Str', required => 1 ); has 'progress' => ( is => 'ro', isa => 'Str', required => 1 ); has 's3_bucket' => ( is => 'ro', isa => 'Str', required => 1 ); has 's3_prefix' => ( is => 'ro', isa => 'Str', required => 1 ); has 's3_aws_access_key_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 's3_upload_policy' => ( is => 'ro', isa => 'Str', required => 1 ); has 's3_policy_upload_signature' => ( is => 'ro', isa => 'Str', required => 1 ); has 'bundle_error_code' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'bundle_error_message' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/ConfirmProductInstanceResponse.pm000644 000765 000024 00000001636 12064473057 026202 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::ConfirmProductInstanceResponse; use strict; use Moose; =head1 NAME Net::Amazon::EC2::ConfirmProductInstanceResponse =head1 DESCRIPTION A class representing the response from a request to attach a product code to a running instance =head1 ATTRIBUTES =over =item return (required) true if the product code is attached to the instance, false if it is not. =item owner_id (optional) The instance owner's account ID. Only present if the product code is sucessfully attached to the instance. =back =cut has 'return' => ( is => 'ro', isa => 'Str', required => 1 ); has 'owner_id' => ( is => 'ro', isa => 'Str', required => 0 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/ConsoleOutput.pm000644 000765 000024 00000001600 12064473057 022652 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::ConsoleOutput; use Moose; =head1 NAME Net::Amazon::EC2::ConsoleOutput =head1 DESCRIPTION A class containing the output from an instance's console =head1 ATTRIBUTES =over =item instance_id (required) The instance id of the output returned. =item timestamp (required) The timestamp of when the console output was last updated. =item output (required) The console output itself. =back =cut has 'instance_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'timestamp' => ( is => 'ro', isa => 'Str', required => 1 ); has 'output' => ( is => 'ro', isa => 'Str', required => 1 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/CreateVolumePermission.pm000644 000765 000024 00000001560 12064473057 024500 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::CreateVolumePermission; use Moose; =head1 NAME Net::Amazon::EC2::CreateVolumePermission =head1 DESCRIPTION A class representing the users or groups allowed to create a volume from the associated snapshot. =head1 ATTRIBUTES =over =item user_id (optional) User ID of a user that can create volumes from the snapshot. =item group (optional) Group that is allowed to create volumes from the snapshot (currently supports "all"). =cut has 'user_id' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'group' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); __PACKAGE__->meta->make_immutable(); =back =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/DescribeAddress.pm000644 000765 000024 00000001465 12064473057 023066 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::DescribeAddress; use Moose; =head1 NAME Net::Amazon::EC2::DescribeAddress =head1 DESCRIPTION A class containing information about allocated elastic addresses and the instances they are bound to =head1 ATTRIBUTES =over =item public_ip (required) The public ip address allocated. =item instance_id (optional) The instance id (if any) associated with the public ip. =back =cut has 'public_ip' => ( is => 'ro', isa => 'Maybe[Str]', required => 1 ); has 'instance_id' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/DescribeImageAttribute.pm000644 000765 000024 00000003711 12064473057 024403 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::DescribeImageAttribute; use Moose; =head1 NAME Net::Amazon::EC2::DescribeImageAttribute =head1 DESCRIPTION A class representing the attributes associated with a machine image. =head1 ATTRIBUTES =over =item image_id (required) Image ID you are describing the image attributes of. =item launch_permissions (optional) An array ref of Net::Amazon::EC2::LaunchPermission objects. =item product_codes (optional) An array ref of Net::Amazon::EC2::ProductCode objects. =item kernel (optional) ID of the kernel associated with the AMI. Returned if kernel is specified. =item ramdisk (optional) ID of the RAM disk associated with the AMI. Returned if ramdisk is specified. =item block_device_mapping (optional) An array ref of Net::Amazon::EC2::BlockDeviceMapping objects. =item platform (optional) Describes the operating system platform. =back =cut has 'image_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'launch_permissions' => ( is => 'ro', isa => 'Maybe[ArrayRef[Net::Amazon::EC2::LaunchPermission]]', predicate => 'has_launch_permissions', required => 0, ); has 'product_codes' => ( is => 'ro', isa => 'Maybe[ArrayRef[Net::Amazon::EC2::ProductCode]]', predicate => 'has_product_codes', required => 0, ); has 'kernel' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'ramdisk' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'blockDeviceMapping' => ( is => 'ro', isa => 'Maybe[ArrayRef[Net::Amazon::EC2::BlockDeviceMapping]]', required => 0, ); has 'platform' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/DescribeImagesResponse.pm000644 000765 000024 00000007707 12064473057 024432 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::DescribeImagesResponse; use Moose; =head1 NAME Net::Amazon::EC2::DescribeImagesResponse =head1 DESCRIPTION A class representing a machine image. =head1 ATTRIBUTES =over =item image_id (required) The image_id you you are describing the image attributes of. =item image_location (required) Path to the AMI itself =item image_state (required) Current state of the AMI. If the operation returns available, the image is successfully registered and available for launching If the operation returns deregistered, the image is deregistered and no longer available for launching. =item image_owner_id (required) AWS access key id of the owner of the image. =item is_public (required) This is true if the AMI can be launched by anyone (has public launch permissions) or false if its only able to be run by the owner of the AMI. =item product_codes (optional) An array ref of Net::Amazon::EC2::ProductCode objects (if any) associated with this AMI. =item architecture (optional) The AMI architecture (i386 or x86_64). =item image_type (optional) The type of AMI this is. Valid values are: =over =item machine =item kernel =item ramdisk =back =item kernel_id (optional) The kernel id associated with this AMI (if any). This is only defined for machine type AMIs. =item ramdisk_id (optional) The ramdisk id associated with this AMI (if any). This is only defined for machine type AMIs. =item platform (optional) The operating system of the instance. =item state_reason (optional) A Net::Amazon::EC2::StateReason object representing the stage change. =item image_owner_alias (optional) The AWS account alias (e.g., "amazon", "redhat", "self", etc.) or AWS account ID that owns the AMI. =item name (optional) The name of the AMI that was provided during image creation. =item description (optional) The description of the AMI that was provided during image creation. =item root_device_type (optional) The root device type used by the AMI. The AMI can use an Amazon EBS or instance store root device. =item root_device_name (optional) The root device name (e.g., /dev/sda1). =item block_device_mapping (optional) An array ref of Net::Amazon::EC2::BlockDeviceMapping objects. =back =cut has 'image_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'image_location' => ( is => 'ro', isa => 'Str', required => 1 ); has 'image_state' => ( is => 'ro', isa => 'Str', required => 1 ); has 'image_owner_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'is_public' => ( is => 'ro', isa => 'Str', required => 1 ); has 'product_codes' => ( is => 'rw', isa => 'Maybe[ArrayRef[Net::Amazon::EC2::ProductCode]]', predicate => 'has_product_codes', required => 0, ); has 'architecture' => ( is => 'ro', isa => 'Str', required => 0 ); has 'image_type' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'kernel_id' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'ramdisk_id' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'platform' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'state_reason' => ( is => 'ro', isa => 'Maybe[Net::Amazon::EC2::StateReason]', required => 0 ); has 'image_owner_alias' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'name' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'description' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'root_device_type' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'root_device_name' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'block_device_mapping' => ( is => 'ro', isa => 'Maybe[ArrayRef[Net::Amazon::EC2::BlockDeviceMapping]]', required => 0 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/DescribeInstanceAttributeResponse.pm000644 000765 000024 00000004351 12064473057 026645 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::DescribeInstanceAttributeResponse; use Moose; =head1 NAME Net::Amazon::EC2::DescribeInstanceAttributeResponse =head1 DESCRIPTION A class representing an instance attribute. =head1 ATTRIBUTES =over =item instance_id (required) The instance id you you are describing the attributes of. =item block_device_mapping (optional) Specifies how block devices are exposed to the instance. Each mapping is made up of a virtual_name and a device_name. This should be a Net::Amazon::EC2::BlockDeviceMapping object. =item disable_api_termination (optional) Specifies whether the instance can be terminated. You must modify this attribute before you can terminate any "locked" instances. =item instance_initiated_shutdown_behavior (optional) Specifies whether the instance's Amazon EBS volumes are deleted when the instance is shut down. =item instance_type (optional) The instance type (e.g., m1.small, c1.medium, m2.2xlarge, and so on). =item kernel (optional) The kernel ID. =item ramdisk (optional) The RAM disk ID. =item root_device_name (optional) The root device name (e.g., /dev/sda1). =item user_data (optional) MIME, Base64-encoded user data. =back =cut has 'instance_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'disable_api_termination' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'instance_initiated_shutdown_behavior' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'instance_type' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'kernel' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'ramdisk' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'root_device_name' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'user_data' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'block_device_mapping' => ( is => 'ro', isa => 'Maybe[ArrayRef[Net::Amazon::EC2::BlockDeviceMapping]]', required => 0, ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/DescribeKeyPairsResponse.pm000644 000765 000024 00000001513 12064473057 024741 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::DescribeKeyPairsResponse; use strict; use Moose; =head1 NAME Net::Amazon::EC2::DescribeKeyPairsResponse =head1 DESCRIPTION A class representing a key pair. =head1 ATTRIBUTES =over =item key_name (required) The name of the key pair. =item key_fingerprint (required) A fingerprint for the private key of the key pair. This is calculated as the SHA-1 of the DER version of the private key. =cut has 'key_name' => ( is => 'ro', isa => 'Str', required => 1 ); has 'key_fingerprint' => ( is => 'ro', isa => 'Str', required => 1 ); __PACKAGE__->meta->make_immutable(); =back =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/DescribeTags.pm000644 000765 000024 00000002260 12064473057 022371 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::DescribeTags; use Moose; =head1 NAME Net::Amazon::EC2::DescribeTags =head1 DESCRIPTION A class containing information about tags =head1 ATTRIBUTES =over =item resource_id (required) The resource_id of the tag. =item resource_type (required) The resource_type of the tag. Values: customer-gateway | dhcp-options | image | instance | internet-gateway | network-acl | reserved-instances | route-table | security-group | snapshot | spot-instances-request | subnet | volume | vpc | vpn-connection | vpn-gateway =item key (required) The key of the tag. =item value (required) The value of the tag. =back =cut has 'resource_id' => ( is => 'ro', isa => 'Maybe[Str]', required => 1 ); has 'resource_type' => ( is => 'ro', isa => 'Maybe[Str]', required => 1 ); has 'key' => ( is => 'ro', isa => 'Maybe[Str]', required => 1 ); has 'value' => ( is => 'ro', isa => 'Maybe[Str]', required => 1 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1; Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/EbsBlockDevice.pm000644 000765 000024 00000001705 12064473057 022641 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::EbsBlockDevice; use strict; use Moose; =head1 NAME Net::Amazon::EC2::Net::Amazon::EC2::EbsBlockDevice =head1 DESCRIPTION A class representing a EBS block device =head1 ATTRIBUTES =over =item snapshot_id (optional) The EBS snapshot id. =item volume_size (optional) The size, in GiB (1GiB = 2^30 octects) =item delete_on_termination (optional) Specifies whether the Amazon EBS volume is deleted on instance termination. =back =cut has 'snapshot_id' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'volume_size' => ( is => 'ro', isa => 'Maybe[Int]', required => 0 ); has 'delete_on_termination' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/EbsInstanceBlockDeviceMapping.pm000644 000765 000024 00000002056 12064473057 025642 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::EbsInstanceBlockDeviceMapping; use strict; use Moose; =head1 NAME Net::Amazon::EC2::EbsInstanceBlockDeviceMapping =head1 DESCRIPTION A class representing a EBS block device mapping =head1 ATTRIBUTES =over =item attach_time (required) Time stamp when the attachment initiated. =item delete_on_termination (required) Specifies whether the Amazon EBS volume is deleted on instance termination. =item status (required) Attachment state. =item volume_id (required) The EBS volume id. =back =cut has 'attach_time' => ( is => 'ro', isa => 'Str', required => 1 ); has 'delete_on_termination' => ( is => 'ro', isa => 'Str', required => 1 ); has 'status' => ( is => 'ro', isa => 'Str', required => 1 ); has 'volume_id' => ( is => 'ro', isa => 'Str', required => 1 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/Error.pm000644 000765 000024 00000001475 12251244167 021126 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::Error; use Moose; =head1 NAME Net::Amazon::EC2::Error =head1 DESCRIPTION A class representing an EC2 API error. =head1 ATTRIBUTES =over =item code (required) The error code returned from the API request. =item message (required) The long form message about the error. =cut use overload '""' => 'as_string'; has 'code' => ( is => 'ro', isa => 'Str', required => 1 ); has 'message' => ( is => 'ro', isa => 'Str', required => 1 ); sub as_string { my $self = shift; return '['.$self->code.'] '.$self->message; } __PACKAGE__->meta->make_immutable(); =back =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1; Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/Errors.pm000644 000765 000024 00000002135 12251244167 021303 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::Errors; use Moose; =head1 NAME Net::Amazon::EC2::Errors =head1 DESCRIPTION A class representing one or more errors from an API request. =head1 ATTRIBUTES =over =item request_id (required) The ID of the request associated with this error. =item errors (required) An array ref of Net::Amazon::EC2::Error objects associated with this request. =cut use overload '""' => 'as_string'; has 'request_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'errors' => ( is => 'rw', isa => 'ArrayRef[Net::Amazon::EC2::Error]', predicate => 'has_errors', required => 1, ); sub as_string { my $self = shift; my $errors = join '', map { '['.$_->code.'] '.$_->message."\n" } @{$self->errors}; return "Amazon EC2 Errors [Request ".$self->request_id."]:\n$errors" } __PACKAGE__->meta->make_immutable(); =back =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1; Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/GroupSet.pm000644 000765 000024 00000001203 12064473057 021576 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::GroupSet; use Moose; =head1 NAME Net::Amazon::EC2::GroupSet =head1 DESCRIPTION A class containing information about a group. =head1 ATTRIBUTES =over =item group_id (required) The ID of the group. =cut has 'group_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'group_name' => ( is => 'ro', isa => 'Maybe[Str]', required => 1 ); __PACKAGE__->meta->make_immutable(); =back =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1; Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/InstanceBlockDeviceMapping.pm000644 000765 000024 00000002065 12064473057 025210 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::InstanceBlockDeviceMapping; use strict; use Moose; =head1 NAME Net::Amazon::EC2::InstanceBlockDeviceMapping =head1 DESCRIPTION A class representing a instance block device mapping =head1 ATTRIBUTES =over =item volume_id (required) The volume id of the EBS Volume. =item status (required) The status of the attachment. =item attach_time (required) The time of attachment. =item delete_on_termination (required) A boolean indicating if the volume will be deleted on instance termination. =back =cut has 'volume_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'status' => ( is => 'ro', isa => 'Str', required => 1 ); has 'attach_time' => ( is => 'ro', isa => 'Str', required => 1 ); has 'delete_on_termination' => ( is => 'ro', isa => 'Str', required => 1 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/InstancePassword.pm000644 000765 000024 00000001562 12064473057 023325 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::InstancePassword; use Moose; =head1 NAME Net::Amazon::EC2::InstancePassword =head1 DESCRIPTION A class representing a instance password for a Windows-based instance. =head1 ATTRIBUTES =over =item instance_id (required) The ID of the instance. =item timestamp (required) The time the data was last updated. =item password_data (required) The password of the instance. =back =cut has 'instance_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'timestamp' => ( is => 'ro', isa => 'Str', required => 1 ); has 'password_data' => ( is => 'ro', isa => 'Str', required => 1 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/InstanceState.pm000644 000765 000024 00000002351 12064473057 022600 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::InstanceState; use Moose; =head1 NAME Net::Amazon::EC2::InstanceState =head1 DESCRIPTION A class representing the state of an instance. =head1 ATTRIBUTES =over =item code (required) An interger representing the instance state. Valid values are: =over =item * 0: pending =item * 16: running =item * 32: shutting-down =item * 48: terminated =item * 64: stopping =item * 80: stopped =back =item name (required) The current named state of the instance. Valid values are: =over =item * pending: the instance is in the process of being launched =item * running: the instance launched (though booting may not be completed) =item * shutting-down: the instance started shutting down =item * terminated: the instance terminated =item * stopping: the instance is in the process of stopping =item * stopped: the instance has been stopped =back =cut has 'code' => ( is => 'ro', isa => 'Int' ); has 'name' => ( is => 'ro', isa => 'Str' ); __PACKAGE__->meta->make_immutable(); =back =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/InstanceStateChange.pm000644 000765 000024 00000002043 12064473057 023704 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::InstanceStateChange; use Moose; =head1 NAME Net::Amazon::EC2::InstanceStateChange =head1 DESCRIPTION A class representing the change of a state of an instance. =head1 ATTRIBUTES =over =item instance_id (required) The instance id in question. =item current_state (required) A Net::Amazon::EC2::InstanceState object representing the current state of the instance. =item previous_state (required) A Net::Amazon::EC2::InstanceState object representing the previous state of the instance. =back =cut has 'instance_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'current_state' => ( is => 'ro', isa => 'Net::Amazon::EC2::InstanceState', required => 1 ); has 'previous_state' => ( is => 'ro', isa => 'Net::Amazon::EC2::InstanceState', required => 1 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/IpPermission.pm000644 000765 000024 00000003673 12064473057 022464 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::IpPermission; use Moose; =head1 NAME Net::Amazon::EC2::IpPermission =head1 DESCRIPTION A class representing a rule within the security group. =head1 ATTRIBUTES =over =item ip_protocol (required) Protocol for the rule. e.g. tcp =item from_port (required) Start of port range for the TCP and UDP protocols, or an ICMP type number. An ICMP type number of -1 indicates a wildcard (i.e., any ICMP type number). =item to_port (required) End of port range for the TCP and UDP protocols, or an ICMP code. An ICMP code of -1 indicates a wildcard (i.e., any ICMP code). =item ip_ranges (optional) An array ref of Net::Amazon::EC2::IpRange objects to be associated with this rule. =item groups (optional) An array ref of Net::Amazon::EC2::UserIdGroupPair objects to be associated with this rule. =item icmp_port (optional) For the ICMP protocol, the ICMP type and code must be specified. This must be specified in the format type:code where both are integers. Type, code, or both can be specified as -1, which is a wildcard. =back =cut has 'ip_protocol' => ( is => 'ro', isa => 'Str', required => 1 ); has 'from_port' => ( is => 'ro', isa => 'Maybe[Int]', required => 1 ); has 'to_port' => ( is => 'ro', isa => 'Maybe[Int]', required => 1 ); has 'ip_ranges' => ( is => 'rw', isa => 'ArrayRef[Net::Amazon::EC2::IpRange]', predicate => 'has_ip_ranges', required => 0, ); has 'groups' => ( is => 'rw', isa => 'ArrayRef[Net::Amazon::EC2::UserIdGroupPair]', predicate => 'has_groups', required => 0, ); has 'icmp_port' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1; Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/IpRange.pm000644 000765 000024 00000001034 12064473057 021355 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::IpRange; use Moose; =head1 NAME Net::Amazon::EC2::IpRange =head1 DESCRIPTION A class representing an IP range (CIDR). =head1 ATTRIBUTES =over =item cidr_ip (required) CIDR IP Range. =back =cut has 'cidr_ip' => ( is => 'ro', isa => 'Str' ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/KeyPair.pm000644 000765 000024 00000001237 12064473057 021401 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::KeyPair; use Moose; =head1 NAME Net::Amazon::EC2::KeyPair =head1 DESCRIPTION A class representing a key pair upon creation of a new pair. =head1 ATTRIBUTES =over =item key_material (required) The unencrypted PEM encoded RSA private key. =back =cut extends 'Net::Amazon::EC2::DescribeKeyPairsResponse'; has 'key_material' => ( is => 'ro', isa => 'Str', required => 1 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/LaunchPermission.pm000644 000765 000024 00000001666 12064473057 023326 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::LaunchPermission; use Moose; =head1 NAME Net::Amazon::EC2::LaunchPermission =head1 DESCRIPTION A class containing information about the group or user_id associated with this launch permission attribute. =head1 ATTRIBUTES =over =item group (required if user_id not defined) A launch permission for a group. Currently only 'all' is supported, which gives public launch permissions. Either choose a group or a user_id but not both. =item user_id (required if group not defined) The AWS account id of the user with launch permissions. =back =cut has 'group' => ( is => 'ro', isa => 'Str' ); has 'user_id' => ( is => 'ro', isa => 'Str' ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/LaunchPermissionOperation.pm000644 000765 000024 00000001677 12064473057 025211 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::LaunchPermissionOperation; use strict; use Moose; =head1 NAME Net::Amazon::EC2::LaunchPermissionOperation =head1 DESCRIPTION A class representing the operation type of the launch permission (adding or removing). =head1 ATTRIBUTES =over =item add (required if remove not defined) An Net::Amazon::EC2::LaunchPermission object to add permissions for. =item remove (required if add not defined) An Net::Amazon::EC2::LaunchPermission object to remove permissions for. =back =cut has 'add' => ( is => 'ro', isa => 'Net::Amazon::EC2::LaunchPermission', required => 0 ); has 'remove' => ( is => 'ro', isa => 'Net::Amazon::EC2::LaunchPermission', required => 0 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/MonitoredInstance.pm000644 000765 000024 00000001342 12064473057 023457 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::MonitoredInstance; use Moose; =head1 NAME Net::Amazon::EC2::MonitoredInstance =head1 DESCRIPTION A class representing a monitored instance. =head1 ATTRIBUTES =over =item instance_id (required) The ID of the instance being monitored. =item state (required) The state of monitoring of this instance. =back =cut has 'instance_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'state' => ( is => 'ro', isa => 'Str', required => 1 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/PlacementResponse.pm000644 000765 000024 00000001260 12064473057 023460 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::PlacementResponse; use strict; use Moose; =head1 NAME Net::Amazon::EC2::PlacementResponse =head1 DESCRIPTION A class containing information about the placement of an instance in an availability zone. =head1 ATTRIBUTES =over =item availability_zone (required) The availability zone for the instance. =back =cut has 'availability_zone' => ( is => 'ro', isa => 'Maybe[Str]', required => 1 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/ProductCode.pm000644 000765 000024 00000001075 12064473057 022250 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::ProductCode; use Moose; =head1 NAME Net::Amazon::EC2::ProductCode =head1 DESCRIPTION A class representing a product code. =head1 ATTRIBUTES =over =item product_code (required) The product code. =back =cut has 'product_code' => ( is => 'ro', isa => 'Str', required => 1 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/ProductInstanceResponse.pm000644 000765 000024 00000001613 12064473057 024657 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::ProductInstanceResponse; use strict; use Moose; =head1 NAME Net::Amazon::EC2::ProductInstanceResponse =head1 DESCRIPTION A class representing the response from a confirm_product_instance call. =head1 ATTRIBUTES =over =item product_code (required) The product code attached to the instance. =item instance_id (required) Instance ID. =item owner_id (required) AWS Account id of the instance owner. =cut has 'product_code' => ( is => 'ro', isa => 'Str', required => 1 ); has 'instance_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'owner_id' => ( is => 'ro', isa => 'Str', required => 1 ); __PACKAGE__->meta->make_immutable(); =back =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/Region.pm000644 000765 000024 00000001271 12064473057 021256 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::Region; use Moose; =head1 NAME Net::Amazon::EC2::Region =head1 DESCRIPTION A class representing a EC2 region =head1 ATTRIBUTES =over =item region_name (required) The name of the region. =item region_endpoint (required) The region service endpoint. =back =cut has 'region_name' => ( is => 'ro', isa => 'Str', required => 1 ); has 'region_endpoint' => ( is => 'ro', isa => 'Str', required => 1 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/ReservationInfo.pm000644 000765 000024 00000002475 12064473057 023157 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::ReservationInfo; use Moose; =head1 NAME Net::Amazon::EC2::ReservationInfo =head1 DESCRIPTION A class representing a run instance reservation. =head1 ATTRIBUTES =over =item reservation_id (required) Unique ID attached to the reservation. =item owner_id (required) AWS Account id of the person making the reservation. =item group_set An array ref of Net::Amazon::EC2::GroupSet objects. =item instances_set (required) An array ref of Net::Amazon::EC2::RunningInstances objects. =item requesterId (optional) ID of the requester. =cut has 'reservation_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'owner_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'group_set' => ( is => 'ro', isa => 'ArrayRef[Net::Amazon::EC2::GroupSet]', required => 1, auto_deref => 1, ); has 'instances_set' => ( is => 'ro', isa => 'ArrayRef[Net::Amazon::EC2::RunningInstances]', required => 1, auto_deref => 1, ); has 'requester_id' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); __PACKAGE__->meta->make_immutable(); =back =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1; Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/ReservedInstance.pm000644 000765 000024 00000003660 12064473057 023303 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::ReservedInstance; use Moose; =head1 NAME Net::Amazon::EC2::ReservedInstance =head1 DESCRIPTION A class representing a reserved instance. =head1 ATTRIBUTES =over =item reserved_instances_id (required) The ID of the Reserved Instance. =item instance_type (required) The instance type on which the Reserved Instance can be used. =item availability_zone (required) The Availability Zone in which the Reserved Instance can be used. =item duration (required) The duration of the Reserved Instance, in seconds. =item start (required) The date and time the Reserved Instance started. =item usage_price (required) The usage price of the Reserved Instance, per hour. =item fixed_price (required) The purchase price of the Reserved Instance. =item instance_count (required) The number of Reserved Instances purchased. =item product_description (required) The Reserved Instance description. =item state (required) The state of the Reserved Instance purchase. =back =cut has 'reserved_instances_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'instance_type' => ( is => 'ro', isa => 'Str', required => 1 ); has 'availability_zone' => ( is => 'ro', isa => 'Str', required => 1 ); has 'duration' => ( is => 'ro', isa => 'Str', required => 1 ); has 'start' => ( is => 'ro', isa => 'Str', required => 1 ); has 'usage_price' => ( is => 'ro', isa => 'Str', required => 1 ); has 'fixed_price' => ( is => 'ro', isa => 'Str', required => 1 ); has 'instance_count' => ( is => 'ro', isa => 'Str', required => 1 ); has 'product_description' => ( is => 'ro', isa => 'Str', required => 1 ); has 'state' => ( is => 'ro', isa => 'Str', required => 1 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/ReservedInstanceOffering.pm000644 000765 000024 00000003122 12064473057 024754 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::ReservedInstanceOffering; use Moose; =head1 NAME Net::Amazon::EC2::ReservedInstanceOffering =head1 DESCRIPTION A class representing a reserved instance offering. =head1 ATTRIBUTES =over =item reserved_instances_offering_id (required) The ID of the Reserved Instance offering. =item instance_type (required) The instance type on which the Reserved Instance can be used. =item availability_zone (required) The Availability Zone in which the Reserved Instance can be used. =item duration (required) The duration of the Reserved Instance, in seconds. =item usage_price (required) The usage price of the Reserved Instance, per hour. =item fixed_price (required) The purchase price of the Reserved Instance. =item product_description (required) The Reserved Instance description. =back =cut has 'reserved_instances_offering_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'instance_type' => ( is => 'ro', isa => 'Str', required => 1 ); has 'availability_zone' => ( is => 'ro', isa => 'Str', required => 1 ); has 'duration' => ( is => 'ro', isa => 'Str', required => 1 ); has 'usage_price' => ( is => 'ro', isa => 'Str', required => 1 ); has 'fixed_price' => ( is => 'ro', isa => 'Str', required => 1 ); has 'product_description' => ( is => 'ro', isa => 'Str', required => 1 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/RunningInstances.pm000644 000765 000024 00000012633 12064473057 023327 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::RunningInstances; use Moose; =head1 NAME Net::Amazon::EC2::RunningInstances =head1 DESCRIPTION A class representing a running instance. =head1 ATTRIBUTES =over =item ami_launch_index (optional) The AMI launch index, which can be used to find this instance within the launch group. =item dns_name (optional) The public DNS name assigned to the instance. This DNS name is contactable from outside the Amazon EC2 network. This element remains empty until the instance enters a running state. =item image_id (required) The image id of the AMI currently running in this instance. =item kernel_id (required) The kernel id of the AKI currently running in this instance. =item ramdisk_id (required) The ramdisk id of the ARI loaded in this instance. =item instance_id (required) The instance id of the launched instance. =item instance_state (required) An Net::Amazon::EC2::InstanceState object. =item instance_type (required) The type of instance launched. =item key_name (optional) The key pair name the instance was launched with. =item launch_time (required) The time the instance was started. =item placement (required) A Net::Amazon::EC2::PlacementResponse object. =item private_dns_name (optional) The private DNS name assigned to the instance. This DNS name can only be used inside the Amazon EC2 network. This element remains empty until the instance enters a running state. =item product_codes (optional) An array ref of Net::Amazon::EC2::ProductCode objects. =item reason (optional) The reason for the most recent state transition. =item platform (optional) The operating system for this instance. =item monitoring (optional) The state of monitoring on this instance. =item subnet_id (optional) Specifies the subnet ID in which the instance is running (Amazon Virtual Private Cloud). =item vpc_id (optional) Specifies the VPC in which the instance is running (Amazon Virtual Private Cloud). =item private_ip_address (optional) Specifies the private IP address that is assigned to the instance (Amazon VPC). =item ip_address (optional) Specifies the IP address of the instance. =item state_reason (optional) The reason for the state change. A Net::Amazon::EC2::StateReason object. =item architecture (optional) The architecture of the image. =item root_device_name (optional) The root device name (e.g., /dev/sda1). =item root_device_type (optional) The root device type used by the AMI. The AMI can use an Amazon EBS or instance store root device. =item block_device_mapping (optional) An array ref of Net::Amazon::EC2::BlockDeviceMapping objects. =item tag_set (optional) An array ref of Net::Amazon::EC2::TagSet objects. =item name (optional) The instance name from tags. =cut has 'ami_launch_index' => ( is => 'ro', isa => 'Str', required => 0 ); has 'dns_name' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'image_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'kernel_id' => ( is => 'ro', isa => 'Maybe[Str]', required => 1 ); has 'ramdisk_id' => ( is => 'ro', isa => 'Maybe[Str]', required => 1 ); has 'instance_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'instance_state' => ( is => 'ro', isa => 'Net::Amazon::EC2::InstanceState', required => 1 ); has 'instance_type' => ( is => 'ro', isa => 'Str', required => 1 ); has 'key_name' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'launch_time' => ( is => 'ro', isa => 'Str', required => 1 ); has 'placement' => ( is => 'ro', isa => 'Net::Amazon::EC2::PlacementResponse', required => 1 ); has 'private_dns_name' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'product_codes' => ( is => 'rw', isa => 'ArrayRef[Net::Amazon::EC2::ProductCode]', auto_deref => 1, required => 0, ); has 'reason' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'platform' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'monitoring' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'subnet_id' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'vpc_id' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'private_ip_address' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'ip_address' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'state_reason' => ( is => 'ro', isa => 'Maybe[Net::Amazon::EC2::StateReason]', required => 0 ); has 'architecture' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'root_device_name' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'root_device_type' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'block_device_mapping' => ( is => 'ro', isa => 'Maybe[ArrayRef[Net::Amazon::EC2::BlockDeviceMapping]]', required => 0 ); has 'tag_set' => ( is => 'ro', isa => 'Maybe[ArrayRef[Net::Amazon::EC2::TagSet]]', required => 0 ); has 'name' => ( is => 'ro', lazy => 1, default => sub { my $self = shift; return '' if !$self->tag_set || scalar @{$self->tag_set} == 0; my $name = (grep {$_->{key} eq 'Name'} @{$self->tag_set})[0]; return $name->{value} || ''; }, ); __PACKAGE__->meta->make_immutable(); =back =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1; Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/SecurityGroup.pm000644 000765 000024 00000002245 12064473057 022661 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::SecurityGroup; use Moose; =head1 NAME Net::Amazon::EC2::SecurityGroup =head1 DESCRIPTION A class representing a security group. =head1 ATTRIBUTES =over =item owner_id (required) The AWS Access Key ID of the owner of the security group. =item group_name (required) The name of the security group. =item group_description (required) The description of the security group. =item ip_permissions (optional) An array ref of Net::Amazon::EC2::IpPermission objects. =cut has 'owner_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'group_name' => ( is => 'ro', isa => 'Str', required => 1 ); has 'group_description' => ( is => 'ro', isa => 'Str', required => 1 ); has 'ip_permissions' => ( is => 'ro', isa => 'Maybe[ArrayRef[Net::Amazon::EC2::IpPermission]]', predicate => 'has_ip_permissions', default => sub { [ ] }, ); __PACKAGE__->meta->make_immutable(); =back =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/Snapshot.pm000644 000765 000024 00000003272 12064473057 021635 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::Snapshot; use Moose; =head1 NAME Net::Amazon::EC2::Snapshot =head1 DESCRIPTION A class representing a snapshot of a volume. =head1 ATTRIBUTES =over =item snapshot_id (required) The ID of the snapshot. =item status (required) The snapshot's status. =item volume_id (required) The ID of the volume the snapshot was taken from. =item start_time (required) The time the snapshot was started. =item progress (required) The current progress of the snapshop, in percent. =item owner_id (required) AWS Access Key ID of the user who owns the snapshot. =item volume_size (required) The size of the volume, in GiB. =item description (optional) Description of the snapshot. =item owner_alias (optional) The AWS account alias (e.g., "amazon", "redhat", "self", etc.) or AWS account ID that owns the AMI. =back =cut has 'snapshot_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'status' => ( is => 'ro', isa => 'Str', required => 1 ); has 'volume_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'start_time' => ( is => 'ro', isa => 'Str', required => 1 ); has 'progress' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'owner_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'volume_size' => ( is => 'ro', isa => 'Str', required => 1 ); has 'description' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'owner_alias' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/SnapshotAttribute.pm000644 000765 000024 00000001467 12064473057 023525 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::SnapshotAttribute; use Moose; =head1 NAME Net::Amazon::EC2::SnapshotAttribute =head1 DESCRIPTION A class representing the snapshot attributes of a volume. =head1 ATTRIBUTES =over =item snapshot_id (required) The ID of the snapshot. =item permissions (required) An arrayref of Net::Amazon::EC2::CreateVolumePermission objects =back =cut has 'snapshot_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'permissions' => ( is => 'ro', isa => 'Maybe[ArrayRef[Net::Amazon::EC2::CreateVolumePermission]]', required => 0 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/StateReason.pm000644 000765 000024 00000001366 12064473057 022270 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::StateReason; use Moose; =head1 NAME Net::Amazon::EC2::StateReason =head1 DESCRIPTION A class representing additional information on the reason for the current state of the instance. =head1 ATTRIBUTES =over =item code (required) A code for the state change reason. =item message (required) A message providing additional information about the state. =back =cut has 'code' => ( is => 'ro', isa => 'Int|Str' ); has 'message' => ( is => 'ro', isa => 'Str' ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/TagSet.pm000644 000765 000024 00000001315 12064473057 021221 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::TagSet; use Moose; =head1 NAME Net::Amazon::EC2::TagSet =head1 DESCRIPTION A class containing information about a tag. =head1 ATTRIBUTES =over =item key (required) The key of the tag. =item value The value of the tag. (May be undefined if there is no value for a given key.) =cut has 'key' => ( is => 'ro', isa => 'Str', required => 1 ); has 'value' => ( is => 'ro', isa => 'Maybe[Str]', required => 1 ); __PACKAGE__->meta->make_immutable(); =back =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1; Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/UserData.pm000644 000765 000024 00000001150 12064473057 021537 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::UserData; use strict; use Moose; =head1 NAME Net::Amazon::EC2::UserData =head1 DESCRIPTION A class representing EC2 User Data attached to an instance. =head1 ATTRIBUTES =over =item data (required) User data itself which is passed to the instance. =cut has 'data' => ( is => 'ro', isa => 'Str', required => 1 ); __PACKAGE__->meta->make_immutable(); =back =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1;Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/UserIdGroupPair.pm000644 000765 000024 00000001402 12064473057 023053 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::UserIdGroupPair; use Moose; =head1 NAME Net::Amazon::EC2::UserIdGroupPair =head1 DESCRIPTION A class representing the User ID and Group pair used with security group operations. =head1 ATTRIBUTES =over =item user_id (required) AWS Access Key ID of the user. =item group_name (required) Name of the security group. =cut has 'user_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'group_name' => ( is => 'ro', isa => 'Maybe[Str]', required => 1 ); __PACKAGE__->meta->make_immutable(); =back =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1; Net-Amazon-EC2-0.24/lib/Net/Amazon/EC2/Volume.pm000644 000765 000024 00000003513 12064473057 021303 0ustar00mallenstaff000000 000000 package Net::Amazon::EC2::Volume; use Moose; =head1 NAME Net::Amazon::EC2::Volume =head1 DESCRIPTION A class representing a volume =head1 ATTRIBUTES =over =item volume_id (required) The ID of the volume. =item size (required) The size, in GiB (1GiB = 2^30 octects) =item snapshot_id (optional) The ID of the snapshot which this volume was created from (if any). =item zone (required) The availability zone the volume was creared in. =item status (required) The volume's status. =item create_time (required) The time the volume was created. =item volume_type (optional) The volume type. =item iops (optional) The number of I/O operations per second (IOPS) that the volume supports (only applies to volumes with a volume_type of io1). =item attachments (optional) An array ref of Net:Amazon::EC2::Attachment objects. =back =cut has 'volume_id' => ( is => 'ro', isa => 'Str', required => 1 ); has 'size' => ( is => 'ro', isa => 'Str', required => 1 ); has 'snapshot_id' => ( is => 'ro', isa => 'Maybe[Str]', required => 0 ); has 'zone' => ( is => 'ro', isa => 'Str', required => 1 ); has 'status' => ( is => 'ro', isa => 'Str', required => 1 ); has 'create_time' => ( is => 'ro', isa => 'Str', required => 1 ); has 'volume_type' => ( is => 'ro', isa => 'Str', default => 'standard'); has 'iops' => ( is => 'ro', isa => 'Maybe[Int]'); has 'attachments' => ( is => 'ro', isa => 'Maybe[ArrayRef[Net::Amazon::EC2::Attachment]]', required => 0 ); has 'tag_set' => ( is => 'ro', isa => 'Maybe[ArrayRef[Net::Amazon::EC2::TagSet]]', required => 0 ); __PACKAGE__->meta->make_immutable(); =head1 AUTHOR Jeff Kim =head1 COPYRIGHT Copyright (c) 2006-2010 Jeff Kim. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut no Moose; 1; Net-Amazon-EC2-0.24/inc/Module/000755 000765 000024 00000000000 12251246040 016364 5ustar00mallenstaff000000 000000 Net-Amazon-EC2-0.24/inc/Module/AutoInstall.pm000644 000765 000024 00000062162 12251245726 021202 0ustar00mallenstaff000000 000000 #line 1 package Module::AutoInstall; use strict; use Cwd (); use File::Spec (); use ExtUtils::MakeMaker (); use vars qw{$VERSION}; BEGIN { $VERSION = '1.06'; } # special map on pre-defined feature sets my %FeatureMap = ( '' => 'Core Features', # XXX: deprecated '-core' => 'Core Features', ); # various lexical flags my ( @Missing, @Existing, %DisabledTests, $UnderCPAN, $InstallDepsTarget, $HasCPANPLUS ); my ( $Config, $CheckOnly, $SkipInstall, $AcceptDefault, $TestOnly, $AllDeps, $UpgradeDeps ); my ( $PostambleActions, $PostambleActionsNoTest, $PostambleActionsUpgradeDeps, $PostambleActionsUpgradeDepsNoTest, $PostambleActionsListDeps, $PostambleActionsListAllDeps, $PostambleUsed, $NoTest); # See if it's a testing or non-interactive session _accept_default( $ENV{AUTOMATED_TESTING} or ! -t STDIN ); _init(); sub _accept_default { $AcceptDefault = shift; } sub _installdeps_target { $InstallDepsTarget = shift; } sub missing_modules { return @Missing; } sub do_install { __PACKAGE__->install( [ $Config ? ( UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) : () ], @Missing, ); } # initialize various flags, and/or perform install sub _init { foreach my $arg ( @ARGV, split( /[\s\t]+/, $ENV{PERL_AUTOINSTALL} || $ENV{PERL_EXTUTILS_AUTOINSTALL} || '' ) ) { if ( $arg =~ /^--config=(.*)$/ ) { $Config = [ split( ',', $1 ) ]; } elsif ( $arg =~ /^--installdeps=(.*)$/ ) { __PACKAGE__->install( $Config, @Missing = split( /,/, $1 ) ); exit 0; } elsif ( $arg =~ /^--upgradedeps=(.*)$/ ) { $UpgradeDeps = 1; __PACKAGE__->install( $Config, @Missing = split( /,/, $1 ) ); exit 0; } elsif ( $arg =~ /^--default(?:deps)?$/ ) { $AcceptDefault = 1; } elsif ( $arg =~ /^--check(?:deps)?$/ ) { $CheckOnly = 1; } elsif ( $arg =~ /^--skip(?:deps)?$/ ) { $SkipInstall = 1; } elsif ( $arg =~ /^--test(?:only)?$/ ) { $TestOnly = 1; } elsif ( $arg =~ /^--all(?:deps)?$/ ) { $AllDeps = 1; } } } # overrides MakeMaker's prompt() to automatically accept the default choice sub _prompt { goto &ExtUtils::MakeMaker::prompt unless $AcceptDefault; my ( $prompt, $default ) = @_; my $y = ( $default =~ /^[Yy]/ ); print $prompt, ' [', ( $y ? 'Y' : 'y' ), '/', ( $y ? 'n' : 'N' ), '] '; print "$default\n"; return $default; } # the workhorse sub import { my $class = shift; my @args = @_ or return; my $core_all; print "*** $class version " . $class->VERSION . "\n"; print "*** Checking for Perl dependencies...\n"; my $cwd = Cwd::cwd(); $Config = []; my $maxlen = length( ( sort { length($b) <=> length($a) } grep { /^[^\-]/ } map { ref($_) ? ( ( ref($_) eq 'HASH' ) ? keys(%$_) : @{$_} ) : '' } map { +{@args}->{$_} } grep { /^[^\-]/ or /^-core$/i } keys %{ +{@args} } )[0] ); # We want to know if we're under CPAN early to avoid prompting, but # if we aren't going to try and install anything anyway then skip the # check entirely since we don't want to have to load (and configure) # an old CPAN just for a cosmetic message $UnderCPAN = _check_lock(1) unless $SkipInstall || $InstallDepsTarget; while ( my ( $feature, $modules ) = splice( @args, 0, 2 ) ) { my ( @required, @tests, @skiptests ); my $default = 1; my $conflict = 0; if ( $feature =~ m/^-(\w+)$/ ) { my $option = lc($1); # check for a newer version of myself _update_to( $modules, @_ ) and return if $option eq 'version'; # sets CPAN configuration options $Config = $modules if $option eq 'config'; # promote every features to core status $core_all = ( $modules =~ /^all$/i ) and next if $option eq 'core'; next unless $option eq 'core'; } print "[" . ( $FeatureMap{ lc($feature) } || $feature ) . "]\n"; $modules = [ %{$modules} ] if UNIVERSAL::isa( $modules, 'HASH' ); unshift @$modules, -default => &{ shift(@$modules) } if ( ref( $modules->[0] ) eq 'CODE' ); # XXX: bugward combatability while ( my ( $mod, $arg ) = splice( @$modules, 0, 2 ) ) { if ( $mod =~ m/^-(\w+)$/ ) { my $option = lc($1); $default = $arg if ( $option eq 'default' ); $conflict = $arg if ( $option eq 'conflict' ); @tests = @{$arg} if ( $option eq 'tests' ); @skiptests = @{$arg} if ( $option eq 'skiptests' ); next; } printf( "- %-${maxlen}s ...", $mod ); if ( $arg and $arg =~ /^\D/ ) { unshift @$modules, $arg; $arg = 0; } # XXX: check for conflicts and uninstalls(!) them. my $cur = _version_of($mod); if (_version_cmp ($cur, $arg) >= 0) { print "loaded. ($cur" . ( $arg ? " >= $arg" : '' ) . ")\n"; push @Existing, $mod => $arg; $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } else { if (not defined $cur) # indeed missing { print "missing." . ( $arg ? " (would need $arg)" : '' ) . "\n"; } else { # no need to check $arg as _version_cmp ($cur, undef) would satisfy >= above print "too old. ($cur < $arg)\n"; } push @required, $mod => $arg; } } next unless @required; my $mandatory = ( $feature eq '-core' or $core_all ); if ( !$SkipInstall and ( $CheckOnly or ($mandatory and $UnderCPAN) or $AllDeps or $InstallDepsTarget or _prompt( qq{==> Auto-install the } . ( @required / 2 ) . ( $mandatory ? ' mandatory' : ' optional' ) . qq{ module(s) from CPAN?}, $default ? 'y' : 'n', ) =~ /^[Yy]/ ) ) { push( @Missing, @required ); $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } elsif ( !$SkipInstall and $default and $mandatory and _prompt( qq{==> The module(s) are mandatory! Really skip?}, 'n', ) =~ /^[Nn]/ ) { push( @Missing, @required ); $DisabledTests{$_} = 1 for map { glob($_) } @skiptests; } else { $DisabledTests{$_} = 1 for map { glob($_) } @tests; } } if ( @Missing and not( $CheckOnly or $UnderCPAN) ) { require Config; my $make = $Config::Config{make}; if ($InstallDepsTarget) { print "*** To install dependencies type '$make installdeps' or '$make installdeps_notest'.\n"; } else { print "*** Dependencies will be installed the next time you type '$make'.\n"; } # make an educated guess of whether we'll need root permission. print " (You may need to do that as the 'root' user.)\n" if eval '$>'; } print "*** $class configuration finished.\n"; chdir $cwd; # import to main:: no strict 'refs'; *{'main::WriteMakefile'} = \&Write if caller(0) eq 'main'; return (@Existing, @Missing); } sub _running_under { my $thing = shift; print <<"END_MESSAGE"; *** Since we're running under ${thing}, I'll just let it take care of the dependency's installation later. END_MESSAGE return 1; } # Check to see if we are currently running under CPAN.pm and/or CPANPLUS; # if we are, then we simply let it taking care of our dependencies sub _check_lock { return unless @Missing or @_; if ($ENV{PERL5_CPANM_IS_RUNNING}) { return _running_under('cpanminus'); } my $cpan_env = $ENV{PERL5_CPAN_IS_RUNNING}; if ($ENV{PERL5_CPANPLUS_IS_RUNNING}) { return _running_under($cpan_env ? 'CPAN' : 'CPANPLUS'); } require CPAN; if ($CPAN::VERSION > '1.89') { if ($cpan_env) { return _running_under('CPAN'); } return; # CPAN.pm new enough, don't need to check further } # last ditch attempt, this -will- configure CPAN, very sorry _load_cpan(1); # force initialize even though it's already loaded # Find the CPAN lock-file my $lock = MM->catfile( $CPAN::Config->{cpan_home}, ".lock" ); return unless -f $lock; # Check the lock local *LOCK; return unless open(LOCK, $lock); if ( ( $^O eq 'MSWin32' ? _under_cpan() : == getppid() ) and ( $CPAN::Config->{prerequisites_policy} || '' ) ne 'ignore' ) { print <<'END_MESSAGE'; *** Since we're running under CPAN, I'll just let it take care of the dependency's installation later. END_MESSAGE return 1; } close LOCK; return; } sub install { my $class = shift; my $i; # used below to strip leading '-' from config keys my @config = ( map { s/^-// if ++$i; $_ } @{ +shift } ); my ( @modules, @installed ); while ( my ( $pkg, $ver ) = splice( @_, 0, 2 ) ) { # grep out those already installed if ( _version_cmp( _version_of($pkg), $ver ) >= 0 ) { push @installed, $pkg; } else { push @modules, $pkg, $ver; } } if ($UpgradeDeps) { push @modules, @installed; @installed = (); } return @installed unless @modules; # nothing to do return @installed if _check_lock(); # defer to the CPAN shell print "*** Installing dependencies...\n"; return unless _connected_to('cpan.org'); my %args = @config; my %failed; local *FAILED; if ( $args{do_once} and open( FAILED, '.#autoinstall.failed' ) ) { while () { chomp; $failed{$_}++ } close FAILED; my @newmod; while ( my ( $k, $v ) = splice( @modules, 0, 2 ) ) { push @newmod, ( $k => $v ) unless $failed{$k}; } @modules = @newmod; } if ( _has_cpanplus() and not $ENV{PERL_AUTOINSTALL_PREFER_CPAN} ) { _install_cpanplus( \@modules, \@config ); } else { _install_cpan( \@modules, \@config ); } print "*** $class installation finished.\n"; # see if we have successfully installed them while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { if ( _version_cmp( _version_of($pkg), $ver ) >= 0 ) { push @installed, $pkg; } elsif ( $args{do_once} and open( FAILED, '>> .#autoinstall.failed' ) ) { print FAILED "$pkg\n"; } } close FAILED if $args{do_once}; return @installed; } sub _install_cpanplus { my @modules = @{ +shift }; my @config = _cpanplus_config( @{ +shift } ); my $installed = 0; require CPANPLUS::Backend; my $cp = CPANPLUS::Backend->new; my $conf = $cp->configure_object; return unless $conf->can('conf') # 0.05x+ with "sudo" support or _can_write($conf->_get_build('base')); # 0.04x # if we're root, set UNINST=1 to avoid trouble unless user asked for it. my $makeflags = $conf->get_conf('makeflags') || ''; if ( UNIVERSAL::isa( $makeflags, 'HASH' ) ) { # 0.03+ uses a hashref here $makeflags->{UNINST} = 1 unless exists $makeflags->{UNINST}; } else { # 0.02 and below uses a scalar $makeflags = join( ' ', split( ' ', $makeflags ), 'UNINST=1' ) if ( $makeflags !~ /\bUNINST\b/ and eval qq{ $> eq '0' } ); } $conf->set_conf( makeflags => $makeflags ); $conf->set_conf( prereqs => 1 ); while ( my ( $key, $val ) = splice( @config, 0, 2 ) ) { $conf->set_conf( $key, $val ); } my $modtree = $cp->module_tree; while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { print "*** Installing $pkg...\n"; MY::preinstall( $pkg, $ver ) or next if defined &MY::preinstall; my $success; my $obj = $modtree->{$pkg}; if ( $obj and _version_cmp( $obj->{version}, $ver ) >= 0 ) { my $pathname = $pkg; $pathname =~ s/::/\\W/; foreach my $inc ( grep { m/$pathname.pm/i } keys(%INC) ) { delete $INC{$inc}; } my $rv = $cp->install( modules => [ $obj->{module} ] ); if ( $rv and ( $rv->{ $obj->{module} } or $rv->{ok} ) ) { print "*** $pkg successfully installed.\n"; $success = 1; } else { print "*** $pkg installation cancelled.\n"; $success = 0; } $installed += $success; } else { print << "."; *** Could not find a version $ver or above for $pkg; skipping. . } MY::postinstall( $pkg, $ver, $success ) if defined &MY::postinstall; } return $installed; } sub _cpanplus_config { my @config = (); while ( @_ ) { my ($key, $value) = (shift(), shift()); if ( $key eq 'prerequisites_policy' ) { if ( $value eq 'follow' ) { $value = CPANPLUS::Internals::Constants::PREREQ_INSTALL(); } elsif ( $value eq 'ask' ) { $value = CPANPLUS::Internals::Constants::PREREQ_ASK(); } elsif ( $value eq 'ignore' ) { $value = CPANPLUS::Internals::Constants::PREREQ_IGNORE(); } else { die "*** Cannot convert option $key = '$value' to CPANPLUS version.\n"; } push @config, 'prereqs', $value; } elsif ( $key eq 'force' ) { push @config, $key, $value; } elsif ( $key eq 'notest' ) { push @config, 'skiptest', $value; } else { die "*** Cannot convert option $key to CPANPLUS version.\n"; } } return @config; } sub _install_cpan { my @modules = @{ +shift }; my @config = @{ +shift }; my $installed = 0; my %args; _load_cpan(); require Config; if (CPAN->VERSION < 1.80) { # no "sudo" support, probe for writableness return unless _can_write( MM->catfile( $CPAN::Config->{cpan_home}, 'sources' ) ) and _can_write( $Config::Config{sitelib} ); } # if we're root, set UNINST=1 to avoid trouble unless user asked for it. my $makeflags = $CPAN::Config->{make_install_arg} || ''; $CPAN::Config->{make_install_arg} = join( ' ', split( ' ', $makeflags ), 'UNINST=1' ) if ( $makeflags !~ /\bUNINST\b/ and eval qq{ $> eq '0' } ); # don't show start-up info $CPAN::Config->{inhibit_startup_message} = 1; # set additional options while ( my ( $opt, $arg ) = splice( @config, 0, 2 ) ) { ( $args{$opt} = $arg, next ) if $opt =~ /^(?:force|notest)$/; # pseudo-option $CPAN::Config->{$opt} = $arg; } if ($args{notest} && (not CPAN::Shell->can('notest'))) { die "Your version of CPAN is too old to support the 'notest' pragma"; } local $CPAN::Config->{prerequisites_policy} = 'follow'; while ( my ( $pkg, $ver ) = splice( @modules, 0, 2 ) ) { MY::preinstall( $pkg, $ver ) or next if defined &MY::preinstall; print "*** Installing $pkg...\n"; my $obj = CPAN::Shell->expand( Module => $pkg ); my $success = 0; if ( $obj and _version_cmp( $obj->cpan_version, $ver ) >= 0 ) { my $pathname = $pkg; $pathname =~ s/::/\\W/; foreach my $inc ( grep { m/$pathname.pm/i } keys(%INC) ) { delete $INC{$inc}; } my $rv = do { if ($args{force}) { CPAN::Shell->force( install => $pkg ) } elsif ($args{notest}) { CPAN::Shell->notest( install => $pkg ) } else { CPAN::Shell->install($pkg) } }; $rv ||= eval { $CPAN::META->instance( 'CPAN::Distribution', $obj->cpan_file, ) ->{install} if $CPAN::META; }; if ( $rv eq 'YES' ) { print "*** $pkg successfully installed.\n"; $success = 1; } else { print "*** $pkg installation failed.\n"; $success = 0; } $installed += $success; } else { print << "."; *** Could not find a version $ver or above for $pkg; skipping. . } MY::postinstall( $pkg, $ver, $success ) if defined &MY::postinstall; } return $installed; } sub _has_cpanplus { return ( $HasCPANPLUS = ( $INC{'CPANPLUS/Config.pm'} or _load('CPANPLUS::Shell::Default') ) ); } # make guesses on whether we're under the CPAN installation directory sub _under_cpan { require Cwd; require File::Spec; my $cwd = File::Spec->canonpath( Cwd::cwd() ); my $cpan = File::Spec->canonpath( $CPAN::Config->{cpan_home} ); return ( index( $cwd, $cpan ) > -1 ); } sub _update_to { my $class = __PACKAGE__; my $ver = shift; return if _version_cmp( _version_of($class), $ver ) >= 0; # no need to upgrade if ( _prompt( "==> A newer version of $class ($ver) is required. Install?", 'y' ) =~ /^[Nn]/ ) { die "*** Please install $class $ver manually.\n"; } print << "."; *** Trying to fetch it from CPAN... . # install ourselves _load($class) and return $class->import(@_) if $class->install( [], $class, $ver ); print << '.'; exit 1; *** Cannot bootstrap myself. :-( Installation terminated. . } # check if we're connected to some host, using inet_aton sub _connected_to { my $site = shift; return ( ( _load('Socket') and Socket::inet_aton($site) ) or _prompt( qq( *** Your host cannot resolve the domain name '$site', which probably means the Internet connections are unavailable. ==> Should we try to install the required module(s) anyway?), 'n' ) =~ /^[Yy]/ ); } # check if a directory is writable; may create it on demand sub _can_write { my $path = shift; mkdir( $path, 0755 ) unless -e $path; return 1 if -w $path; print << "."; *** You are not allowed to write to the directory '$path'; the installation may fail due to insufficient permissions. . if ( eval '$>' and lc(`sudo -V`) =~ /version/ and _prompt( qq( ==> Should we try to re-execute the autoinstall process with 'sudo'?), ((-t STDIN) ? 'y' : 'n') ) =~ /^[Yy]/ ) { # try to bootstrap ourselves from sudo print << "."; *** Trying to re-execute the autoinstall process with 'sudo'... . my $missing = join( ',', @Missing ); my $config = join( ',', UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) if $Config; return unless system( 'sudo', $^X, $0, "--config=$config", "--installdeps=$missing" ); print << "."; *** The 'sudo' command exited with error! Resuming... . } return _prompt( qq( ==> Should we try to install the required module(s) anyway?), 'n' ) =~ /^[Yy]/; } # load a module and return the version it reports sub _load { my $mod = pop; # method/function doesn't matter my $file = $mod; $file =~ s|::|/|g; $file .= '.pm'; local $@; return eval { require $file; $mod->VERSION } || ( $@ ? undef: 0 ); } # report version without loading a module sub _version_of { my $mod = pop; # method/function doesn't matter my $file = $mod; $file =~ s|::|/|g; $file .= '.pm'; foreach my $dir ( @INC ) { next if ref $dir; my $path = File::Spec->catfile($dir, $file); next unless -e $path; require ExtUtils::MM_Unix; return ExtUtils::MM_Unix->parse_version($path); } return undef; } # Load CPAN.pm and it's configuration sub _load_cpan { return if $CPAN::VERSION and $CPAN::Config and not @_; require CPAN; # CPAN-1.82+ adds CPAN::Config::AUTOLOAD to redirect to # CPAN::HandleConfig->load. CPAN reports that the redirection # is deprecated in a warning printed at the user. # CPAN-1.81 expects CPAN::HandleConfig->load, does not have # $CPAN::HandleConfig::VERSION but cannot handle # CPAN::Config->load # Which "versions expect CPAN::Config->load? if ( $CPAN::HandleConfig::VERSION || CPAN::HandleConfig->can('load') ) { # Newer versions of CPAN have a HandleConfig module CPAN::HandleConfig->load; } else { # Older versions had the load method in Config directly CPAN::Config->load; } } # compare two versions, either use Sort::Versions or plain comparison # return values same as <=> sub _version_cmp { my ( $cur, $min ) = @_; return -1 unless defined $cur; # if 0 keep comparing return 1 unless $min; $cur =~ s/\s+$//; # check for version numbers that are not in decimal format if ( ref($cur) or ref($min) or $cur =~ /v|\..*\./ or $min =~ /v|\..*\./ ) { if ( ( $version::VERSION or defined( _load('version') )) and version->can('new') ) { # use version.pm if it is installed. return version->new($cur) <=> version->new($min); } elsif ( $Sort::Versions::VERSION or defined( _load('Sort::Versions') ) ) { # use Sort::Versions as the sorting algorithm for a.b.c versions return Sort::Versions::versioncmp( $cur, $min ); } warn "Cannot reliably compare non-decimal formatted versions.\n" . "Please install version.pm or Sort::Versions.\n"; } # plain comparison local $^W = 0; # shuts off 'not numeric' bugs return $cur <=> $min; } # nothing; this usage is deprecated. sub main::PREREQ_PM { return {}; } sub _make_args { my %args = @_; $args{PREREQ_PM} = { %{ $args{PREREQ_PM} || {} }, @Existing, @Missing } if $UnderCPAN or $TestOnly; if ( $args{EXE_FILES} and -e 'MANIFEST' ) { require ExtUtils::Manifest; my $manifest = ExtUtils::Manifest::maniread('MANIFEST'); $args{EXE_FILES} = [ grep { exists $manifest->{$_} } @{ $args{EXE_FILES} } ]; } $args{test}{TESTS} ||= 't/*.t'; $args{test}{TESTS} = join( ' ', grep { !exists( $DisabledTests{$_} ) } map { glob($_) } split( /\s+/, $args{test}{TESTS} ) ); my $missing = join( ',', @Missing ); my $config = join( ',', UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config} ) if $Config; $PostambleActions = ( ($missing and not $UnderCPAN) ? "\$(PERL) $0 --config=$config --installdeps=$missing" : "\$(NOECHO) \$(NOOP)" ); my $deps_list = join( ',', @Missing, @Existing ); $PostambleActionsUpgradeDeps = "\$(PERL) $0 --config=$config --upgradedeps=$deps_list"; my $config_notest = join( ',', (UNIVERSAL::isa( $Config, 'HASH' ) ? %{$Config} : @{$Config}), 'notest', 1 ) if $Config; $PostambleActionsNoTest = ( ($missing and not $UnderCPAN) ? "\$(PERL) $0 --config=$config_notest --installdeps=$missing" : "\$(NOECHO) \$(NOOP)" ); $PostambleActionsUpgradeDepsNoTest = "\$(PERL) $0 --config=$config_notest --upgradedeps=$deps_list"; $PostambleActionsListDeps = '@$(PERL) -le "print for @ARGV" ' . join(' ', map $Missing[$_], grep $_ % 2 == 0, 0..$#Missing); my @all = (@Missing, @Existing); $PostambleActionsListAllDeps = '@$(PERL) -le "print for @ARGV" ' . join(' ', map $all[$_], grep $_ % 2 == 0, 0..$#all); return %args; } # a wrapper to ExtUtils::MakeMaker::WriteMakefile sub Write { require Carp; Carp::croak "WriteMakefile: Need even number of args" if @_ % 2; if ($CheckOnly) { print << "."; *** Makefile not written in check-only mode. . return; } my %args = _make_args(@_); no strict 'refs'; $PostambleUsed = 0; local *MY::postamble = \&postamble unless defined &MY::postamble; ExtUtils::MakeMaker::WriteMakefile(%args); print << "." unless $PostambleUsed; *** WARNING: Makefile written with customized MY::postamble() without including contents from Module::AutoInstall::postamble() -- auto installation features disabled. Please contact the author. . return 1; } sub postamble { $PostambleUsed = 1; my $fragment; $fragment .= <<"AUTO_INSTALL" if !$InstallDepsTarget; config :: installdeps \t\$(NOECHO) \$(NOOP) AUTO_INSTALL $fragment .= <<"END_MAKE"; checkdeps :: \t\$(PERL) $0 --checkdeps installdeps :: \t$PostambleActions installdeps_notest :: \t$PostambleActionsNoTest upgradedeps :: \t$PostambleActionsUpgradeDeps upgradedeps_notest :: \t$PostambleActionsUpgradeDepsNoTest listdeps :: \t$PostambleActionsListDeps listalldeps :: \t$PostambleActionsListAllDeps END_MAKE return $fragment; } 1; __END__ #line 1193 Net-Amazon-EC2-0.24/inc/Module/Install/000755 000765 000024 00000000000 12251246040 017772 5ustar00mallenstaff000000 000000 Net-Amazon-EC2-0.24/inc/Module/Install.pm000644 000765 000024 00000030135 12251245726 020344 0ustar00mallenstaff000000 000000 #line 1 package Module::Install; # For any maintainers: # The load order for Module::Install is a bit magic. # It goes something like this... # # IF ( host has Module::Install installed, creating author mode ) { # 1. Makefile.PL calls "use inc::Module::Install" # 2. $INC{inc/Module/Install.pm} set to installed version of inc::Module::Install # 3. The installed version of inc::Module::Install loads # 4. inc::Module::Install calls "require Module::Install" # 5. The ./inc/ version of Module::Install loads # } ELSE { # 1. Makefile.PL calls "use inc::Module::Install" # 2. $INC{inc/Module/Install.pm} set to ./inc/ version of Module::Install # 3. The ./inc/ version of Module::Install loads # } use 5.005; use strict 'vars'; use Cwd (); use File::Find (); use File::Path (); use vars qw{$VERSION $MAIN}; BEGIN { # All Module::Install core packages now require synchronised versions. # This will be used to ensure we don't accidentally load old or # different versions of modules. # This is not enforced yet, but will be some time in the next few # releases once we can make sure it won't clash with custom # Module::Install extensions. $VERSION = '1.06'; # Storage for the pseudo-singleton $MAIN = undef; *inc::Module::Install::VERSION = *VERSION; @inc::Module::Install::ISA = __PACKAGE__; } sub import { my $class = shift; my $self = $class->new(@_); my $who = $self->_caller; #------------------------------------------------------------- # all of the following checks should be included in import(), # to allow "eval 'require Module::Install; 1' to test # installation of Module::Install. (RT #51267) #------------------------------------------------------------- # Whether or not inc::Module::Install is actually loaded, the # $INC{inc/Module/Install.pm} is what will still get set as long as # the caller loaded module this in the documented manner. # If not set, the caller may NOT have loaded the bundled version, and thus # they may not have a MI version that works with the Makefile.PL. This would # result in false errors or unexpected behaviour. And we don't want that. my $file = join( '/', 'inc', split /::/, __PACKAGE__ ) . '.pm'; unless ( $INC{$file} ) { die <<"END_DIE" } Please invoke ${\__PACKAGE__} with: use inc::${\__PACKAGE__}; not: use ${\__PACKAGE__}; END_DIE # This reportedly fixes a rare Win32 UTC file time issue, but # as this is a non-cross-platform XS module not in the core, # we shouldn't really depend on it. See RT #24194 for detail. # (Also, this module only supports Perl 5.6 and above). eval "use Win32::UTCFileTime" if $^O eq 'MSWin32' && $] >= 5.006; # If the script that is loading Module::Install is from the future, # then make will detect this and cause it to re-run over and over # again. This is bad. Rather than taking action to touch it (which # is unreliable on some platforms and requires write permissions) # for now we should catch this and refuse to run. if ( -f $0 ) { my $s = (stat($0))[9]; # If the modification time is only slightly in the future, # sleep briefly to remove the problem. my $a = $s - time; if ( $a > 0 and $a < 5 ) { sleep 5 } # Too far in the future, throw an error. my $t = time; if ( $s > $t ) { die <<"END_DIE" } Your installer $0 has a modification time in the future ($s > $t). This is known to create infinite loops in make. Please correct this, then run $0 again. END_DIE } # Build.PL was formerly supported, but no longer is due to excessive # difficulty in implementing every single feature twice. if ( $0 =~ /Build.PL$/i ) { die <<"END_DIE" } Module::Install no longer supports Build.PL. It was impossible to maintain duel backends, and has been deprecated. Please remove all Build.PL files and only use the Makefile.PL installer. END_DIE #------------------------------------------------------------- # To save some more typing in Module::Install installers, every... # use inc::Module::Install # ...also acts as an implicit use strict. $^H |= strict::bits(qw(refs subs vars)); #------------------------------------------------------------- unless ( -f $self->{file} ) { foreach my $key (keys %INC) { delete $INC{$key} if $key =~ /Module\/Install/; } local $^W; require "$self->{path}/$self->{dispatch}.pm"; File::Path::mkpath("$self->{prefix}/$self->{author}"); $self->{admin} = "$self->{name}::$self->{dispatch}"->new( _top => $self ); $self->{admin}->init; @_ = ($class, _self => $self); goto &{"$self->{name}::import"}; } local $^W; *{"${who}::AUTOLOAD"} = $self->autoload; $self->preload; # Unregister loader and worker packages so subdirs can use them again delete $INC{'inc/Module/Install.pm'}; delete $INC{'Module/Install.pm'}; # Save to the singleton $MAIN = $self; return 1; } sub autoload { my $self = shift; my $who = $self->_caller; my $cwd = Cwd::cwd(); my $sym = "${who}::AUTOLOAD"; $sym->{$cwd} = sub { my $pwd = Cwd::cwd(); if ( my $code = $sym->{$pwd} ) { # Delegate back to parent dirs goto &$code unless $cwd eq $pwd; } unless ($$sym =~ s/([^:]+)$//) { # XXX: it looks like we can't retrieve the missing function # via $$sym (usually $main::AUTOLOAD) in this case. # I'm still wondering if we should slurp Makefile.PL to # get some context or not ... my ($package, $file, $line) = caller; die <<"EOT"; Unknown function is found at $file line $line. Execution of $file aborted due to runtime errors. If you're a contributor to a project, you may need to install some Module::Install extensions from CPAN (or other repository). If you're a user of a module, please contact the author. EOT } my $method = $1; if ( uc($method) eq $method ) { # Do nothing return; } elsif ( $method =~ /^_/ and $self->can($method) ) { # Dispatch to the root M:I class return $self->$method(@_); } # Dispatch to the appropriate plugin unshift @_, ( $self, $1 ); goto &{$self->can('call')}; }; } sub preload { my $self = shift; unless ( $self->{extensions} ) { $self->load_extensions( "$self->{prefix}/$self->{path}", $self ); } my @exts = @{$self->{extensions}}; unless ( @exts ) { @exts = $self->{admin}->load_all_extensions; } my %seen; foreach my $obj ( @exts ) { while (my ($method, $glob) = each %{ref($obj) . '::'}) { next unless $obj->can($method); next if $method =~ /^_/; next if $method eq uc($method); $seen{$method}++; } } my $who = $self->_caller; foreach my $name ( sort keys %seen ) { local $^W; *{"${who}::$name"} = sub { ${"${who}::AUTOLOAD"} = "${who}::$name"; goto &{"${who}::AUTOLOAD"}; }; } } sub new { my ($class, %args) = @_; delete $INC{'FindBin.pm'}; { # to suppress the redefine warning local $SIG{__WARN__} = sub {}; require FindBin; } # ignore the prefix on extension modules built from top level. my $base_path = Cwd::abs_path($FindBin::Bin); unless ( Cwd::abs_path(Cwd::cwd()) eq $base_path ) { delete $args{prefix}; } return $args{_self} if $args{_self}; $args{dispatch} ||= 'Admin'; $args{prefix} ||= 'inc'; $args{author} ||= ($^O eq 'VMS' ? '_author' : '.author'); $args{bundle} ||= 'inc/BUNDLES'; $args{base} ||= $base_path; $class =~ s/^\Q$args{prefix}\E:://; $args{name} ||= $class; $args{version} ||= $class->VERSION; unless ( $args{path} ) { $args{path} = $args{name}; $args{path} =~ s!::!/!g; } $args{file} ||= "$args{base}/$args{prefix}/$args{path}.pm"; $args{wrote} = 0; bless( \%args, $class ); } sub call { my ($self, $method) = @_; my $obj = $self->load($method) or return; splice(@_, 0, 2, $obj); goto &{$obj->can($method)}; } sub load { my ($self, $method) = @_; $self->load_extensions( "$self->{prefix}/$self->{path}", $self ) unless $self->{extensions}; foreach my $obj (@{$self->{extensions}}) { return $obj if $obj->can($method); } my $admin = $self->{admin} or die <<"END_DIE"; The '$method' method does not exist in the '$self->{prefix}' path! Please remove the '$self->{prefix}' directory and run $0 again to load it. END_DIE my $obj = $admin->load($method, 1); push @{$self->{extensions}}, $obj; $obj; } sub load_extensions { my ($self, $path, $top) = @_; my $should_reload = 0; unless ( grep { ! ref $_ and lc $_ eq lc $self->{prefix} } @INC ) { unshift @INC, $self->{prefix}; $should_reload = 1; } foreach my $rv ( $self->find_extensions($path) ) { my ($file, $pkg) = @{$rv}; next if $self->{pathnames}{$pkg}; local $@; my $new = eval { local $^W; require $file; $pkg->can('new') }; unless ( $new ) { warn $@ if $@; next; } $self->{pathnames}{$pkg} = $should_reload ? delete $INC{$file} : $INC{$file}; push @{$self->{extensions}}, &{$new}($pkg, _top => $top ); } $self->{extensions} ||= []; } sub find_extensions { my ($self, $path) = @_; my @found; File::Find::find( sub { my $file = $File::Find::name; return unless $file =~ m!^\Q$path\E/(.+)\.pm\Z!is; my $subpath = $1; return if lc($subpath) eq lc($self->{dispatch}); $file = "$self->{path}/$subpath.pm"; my $pkg = "$self->{name}::$subpath"; $pkg =~ s!/!::!g; # If we have a mixed-case package name, assume case has been preserved # correctly. Otherwise, root through the file to locate the case-preserved # version of the package name. if ( $subpath eq lc($subpath) || $subpath eq uc($subpath) ) { my $content = Module::Install::_read($subpath . '.pm'); my $in_pod = 0; foreach ( split //, $content ) { $in_pod = 1 if /^=\w/; $in_pod = 0 if /^=cut/; next if ($in_pod || /^=cut/); # skip pod text next if /^\s*#/; # and comments if ( m/^\s*package\s+($pkg)\s*;/i ) { $pkg = $1; last; } } } push @found, [ $file, $pkg ]; }, $path ) if -d $path; @found; } ##################################################################### # Common Utility Functions sub _caller { my $depth = 0; my $call = caller($depth); while ( $call eq __PACKAGE__ ) { $depth++; $call = caller($depth); } return $call; } # Done in evals to avoid confusing Perl::MinimumVersion eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@; sub _read { local *FH; open( FH, '<', $_[0] ) or die "open($_[0]): $!"; my $string = do { local $/; }; close FH or die "close($_[0]): $!"; return $string; } END_NEW sub _read { local *FH; open( FH, "< $_[0]" ) or die "open($_[0]): $!"; my $string = do { local $/; }; close FH or die "close($_[0]): $!"; return $string; } END_OLD sub _readperl { my $string = Module::Install::_read($_[0]); $string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg; $string =~ s/(\n)\n*__(?:DATA|END)__\b.*\z/$1/s; $string =~ s/\n\n=\w+.+?\n\n=cut\b.+?\n+/\n\n/sg; return $string; } sub _readpod { my $string = Module::Install::_read($_[0]); $string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg; return $string if $_[0] =~ /\.pod\z/; $string =~ s/(^|\n=cut\b.+?\n+)[^=\s].+?\n(\n=\w+|\z)/$1$2/sg; $string =~ s/\n*=pod\b[^\n]*\n+/\n\n/sg; $string =~ s/\n*=cut\b[^\n]*\n+/\n\n/sg; $string =~ s/^\n+//s; return $string; } # Done in evals to avoid confusing Perl::MinimumVersion eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@; sub _write { local *FH; open( FH, '>', $_[0] ) or die "open($_[0]): $!"; foreach ( 1 .. $#_ ) { print FH $_[$_] or die "print($_[0]): $!"; } close FH or die "close($_[0]): $!"; } END_NEW sub _write { local *FH; open( FH, "> $_[0]" ) or die "open($_[0]): $!"; foreach ( 1 .. $#_ ) { print FH $_[$_] or die "print($_[0]): $!"; } close FH or die "close($_[0]): $!"; } END_OLD # _version is for processing module versions (eg, 1.03_05) not # Perl versions (eg, 5.8.1). sub _version ($) { my $s = shift || 0; my $d =()= $s =~ /(\.)/g; if ( $d >= 2 ) { # Normalise multipart versions $s =~ s/(\.)(\d{1,3})/sprintf("$1%03d",$2)/eg; } $s =~ s/^(\d+)\.?//; my $l = $1 || 0; my @v = map { $_ . '0' x (3 - length $_) } $s =~ /(\d{1,3})\D?/g; $l = $l . '.' . join '', @v if @v; return $l + 0; } sub _cmp ($$) { _version($_[1]) <=> _version($_[2]); } # Cloned from Params::Util::_CLASS sub _CLASS ($) { ( defined $_[0] and ! ref $_[0] and $_[0] =~ m/^[^\W\d]\w*(?:::\w+)*\z/s ) ? $_[0] : undef; } 1; # Copyright 2008 - 2012 Adam Kennedy. Net-Amazon-EC2-0.24/inc/Module/Install/AutoInstall.pm000644 000765 000024 00000004162 12251245726 022604 0ustar00mallenstaff000000 000000 #line 1 package Module::Install::AutoInstall; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.06'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub AutoInstall { $_[0] } sub run { my $self = shift; $self->auto_install_now(@_); } sub write { my $self = shift; $self->auto_install(@_); } sub auto_install { my $self = shift; return if $self->{done}++; # Flatten array of arrays into a single array my @core = map @$_, map @$_, grep ref, $self->build_requires, $self->requires; my @config = @_; # We'll need Module::AutoInstall $self->include('Module::AutoInstall'); require Module::AutoInstall; my @features_require = Module::AutoInstall->import( (@config ? (-config => \@config) : ()), (@core ? (-core => \@core) : ()), $self->features, ); my %seen; my @requires = map @$_, map @$_, grep ref, $self->requires; while (my ($mod, $ver) = splice(@requires, 0, 2)) { $seen{$mod}{$ver}++; } my @build_requires = map @$_, map @$_, grep ref, $self->build_requires; while (my ($mod, $ver) = splice(@build_requires, 0, 2)) { $seen{$mod}{$ver}++; } my @configure_requires = map @$_, map @$_, grep ref, $self->configure_requires; while (my ($mod, $ver) = splice(@configure_requires, 0, 2)) { $seen{$mod}{$ver}++; } my @deduped; while (my ($mod, $ver) = splice(@features_require, 0, 2)) { push @deduped, $mod => $ver unless $seen{$mod}{$ver}++; } $self->requires(@deduped); $self->makemaker_args( Module::AutoInstall::_make_args() ); my $class = ref($self); $self->postamble( "# --- $class section:\n" . Module::AutoInstall::postamble() ); } sub installdeps_target { my ($self, @args) = @_; $self->include('Module::AutoInstall'); require Module::AutoInstall; Module::AutoInstall::_installdeps_target(1); $self->auto_install(@args); } sub auto_install_now { my $self = shift; $self->auto_install(@_); Module::AutoInstall::do_install(); } 1; Net-Amazon-EC2-0.24/inc/Module/Install/Base.pm000644 000765 000024 00000002147 12251245726 021220 0ustar00mallenstaff000000 000000 #line 1 package Module::Install::Base; use strict 'vars'; use vars qw{$VERSION}; BEGIN { $VERSION = '1.06'; } # Suspend handler for "redefined" warnings BEGIN { my $w = $SIG{__WARN__}; $SIG{__WARN__} = sub { $w }; } #line 42 sub new { my $class = shift; unless ( defined &{"${class}::call"} ) { *{"${class}::call"} = sub { shift->_top->call(@_) }; } unless ( defined &{"${class}::load"} ) { *{"${class}::load"} = sub { shift->_top->load(@_) }; } bless { @_ }, $class; } #line 61 sub AUTOLOAD { local $@; my $func = eval { shift->_top->autoload } or return; goto &$func; } #line 75 sub _top { $_[0]->{_top}; } #line 90 sub admin { $_[0]->_top->{admin} or Module::Install::Base::FakeAdmin->new; } #line 106 sub is_admin { ! $_[0]->admin->isa('Module::Install::Base::FakeAdmin'); } sub DESTROY {} package Module::Install::Base::FakeAdmin; use vars qw{$VERSION}; BEGIN { $VERSION = $Module::Install::Base::VERSION; } my $fake; sub new { $fake ||= bless(\@_, $_[0]); } sub AUTOLOAD {} sub DESTROY {} # Restore warning handler BEGIN { $SIG{__WARN__} = $SIG{__WARN__}->(); } 1; #line 159 Net-Amazon-EC2-0.24/inc/Module/Install/Can.pm000644 000765 000024 00000006157 12251245726 021054 0ustar00mallenstaff000000 000000 #line 1 package Module::Install::Can; use strict; use Config (); use ExtUtils::MakeMaker (); use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.06'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } # check if we can load some module ### Upgrade this to not have to load the module if possible sub can_use { my ($self, $mod, $ver) = @_; $mod =~ s{::|\\}{/}g; $mod .= '.pm' unless $mod =~ /\.pm$/i; my $pkg = $mod; $pkg =~ s{/}{::}g; $pkg =~ s{\.pm$}{}i; local $@; eval { require $mod; $pkg->VERSION($ver || 0); 1 }; } # Check if we can run some command sub can_run { my ($self, $cmd) = @_; my $_cmd = $cmd; return $_cmd if (-x $_cmd or $_cmd = MM->maybe_command($_cmd)); for my $dir ((split /$Config::Config{path_sep}/, $ENV{PATH}), '.') { next if $dir eq ''; require File::Spec; my $abs = File::Spec->catfile($dir, $cmd); return $abs if (-x $abs or $abs = MM->maybe_command($abs)); } return; } # Can our C compiler environment build XS files sub can_xs { my $self = shift; # Ensure we have the CBuilder module $self->configure_requires( 'ExtUtils::CBuilder' => 0.27 ); # Do we have the configure_requires checker? local $@; eval "require ExtUtils::CBuilder;"; if ( $@ ) { # They don't obey configure_requires, so it is # someone old and delicate. Try to avoid hurting # them by falling back to an older simpler test. return $self->can_cc(); } # Do we have a working C compiler my $builder = ExtUtils::CBuilder->new( quiet => 1, ); unless ( $builder->have_compiler ) { # No working C compiler return 0; } # Write a C file representative of what XS becomes require File::Temp; my ( $FH, $tmpfile ) = File::Temp::tempfile( "compilexs-XXXXX", SUFFIX => '.c', ); binmode $FH; print $FH <<'END_C'; #include "EXTERN.h" #include "perl.h" #include "XSUB.h" int main(int argc, char **argv) { return 0; } int boot_sanexs() { return 1; } END_C close $FH; # Can the C compiler access the same headers XS does my @libs = (); my $object = undef; eval { local $^W = 0; $object = $builder->compile( source => $tmpfile, ); @libs = $builder->link( objects => $object, module_name => 'sanexs', ); }; my $result = $@ ? 0 : 1; # Clean up all the build files foreach ( $tmpfile, $object, @libs ) { next unless defined $_; 1 while unlink; } return $result; } # Can we locate a (the) C compiler sub can_cc { my $self = shift; my @chunks = split(/ /, $Config::Config{cc}) or return; # $Config{cc} may contain args; try to find out the program part while (@chunks) { return $self->can_run("@chunks") || (pop(@chunks), next); } return; } # Fix Cygwin bug on maybe_command(); if ( $^O eq 'cygwin' ) { require ExtUtils::MM_Cygwin; require ExtUtils::MM_Win32; if ( ! defined(&ExtUtils::MM_Cygwin::maybe_command) ) { *ExtUtils::MM_Cygwin::maybe_command = sub { my ($self, $file) = @_; if ($file =~ m{^/cygdrive/}i and ExtUtils::MM_Win32->can('maybe_command')) { ExtUtils::MM_Win32->maybe_command($file); } else { ExtUtils::MM_Unix->maybe_command($file); } } } } 1; __END__ #line 236 Net-Amazon-EC2-0.24/inc/Module/Install/Fetch.pm000644 000765 000024 00000004627 12251245726 021404 0ustar00mallenstaff000000 000000 #line 1 package Module::Install::Fetch; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.06'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub get_file { my ($self, %args) = @_; my ($scheme, $host, $path, $file) = $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; if ( $scheme eq 'http' and ! eval { require LWP::Simple; 1 } ) { $args{url} = $args{ftp_url} or (warn("LWP support unavailable!\n"), return); ($scheme, $host, $path, $file) = $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; } $|++; print "Fetching '$file' from $host... "; unless (eval { require Socket; Socket::inet_aton($host) }) { warn "'$host' resolve failed!\n"; return; } return unless $scheme eq 'ftp' or $scheme eq 'http'; require Cwd; my $dir = Cwd::getcwd(); chdir $args{local_dir} or return if exists $args{local_dir}; if (eval { require LWP::Simple; 1 }) { LWP::Simple::mirror($args{url}, $file); } elsif (eval { require Net::FTP; 1 }) { eval { # use Net::FTP to get past firewall my $ftp = Net::FTP->new($host, Passive => 1, Timeout => 600); $ftp->login("anonymous", 'anonymous@example.com'); $ftp->cwd($path); $ftp->binary; $ftp->get($file) or (warn("$!\n"), return); $ftp->quit; } } elsif (my $ftp = $self->can_run('ftp')) { eval { # no Net::FTP, fallback to ftp.exe require FileHandle; my $fh = FileHandle->new; local $SIG{CHLD} = 'IGNORE'; unless ($fh->open("|$ftp -n")) { warn "Couldn't open ftp: $!\n"; chdir $dir; return; } my @dialog = split(/\n/, <<"END_FTP"); open $host user anonymous anonymous\@example.com cd $path binary get $file $file quit END_FTP foreach (@dialog) { $fh->print("$_\n") } $fh->close; } } else { warn "No working 'ftp' program available!\n"; chdir $dir; return; } unless (-f $file) { warn "Fetching failed: $@\n"; chdir $dir; return; } return if exists $args{size} and -s $file != $args{size}; system($args{run}) if exists $args{run}; unlink($file) if $args{remove}; print(((!exists $args{check_for} or -e $args{check_for}) ? "done!" : "failed! ($!)"), "\n"); chdir $dir; return !$?; } 1; Net-Amazon-EC2-0.24/inc/Module/Install/Include.pm000644 000765 000024 00000001015 12251245726 021722 0ustar00mallenstaff000000 000000 #line 1 package Module::Install::Include; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.06'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub include { shift()->admin->include(@_); } sub include_deps { shift()->admin->include_deps(@_); } sub auto_include { shift()->admin->auto_include(@_); } sub auto_include_deps { shift()->admin->auto_include_deps(@_); } sub auto_include_dependent_dists { shift()->admin->auto_include_dependent_dists(@_); } 1; Net-Amazon-EC2-0.24/inc/Module/Install/Makefile.pm000644 000765 000024 00000027437 12251245726 022074 0ustar00mallenstaff000000 000000 #line 1 package Module::Install::Makefile; use strict 'vars'; use ExtUtils::MakeMaker (); use Module::Install::Base (); use Fcntl qw/:flock :seek/; use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.06'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub Makefile { $_[0] } my %seen = (); sub prompt { shift; # Infinite loop protection my @c = caller(); if ( ++$seen{"$c[1]|$c[2]|$_[0]"} > 3 ) { die "Caught an potential prompt infinite loop ($c[1]|$c[2]|$_[0])"; } # In automated testing or non-interactive session, always use defaults if ( ($ENV{AUTOMATED_TESTING} or -! -t STDIN) and ! $ENV{PERL_MM_USE_DEFAULT} ) { local $ENV{PERL_MM_USE_DEFAULT} = 1; goto &ExtUtils::MakeMaker::prompt; } else { goto &ExtUtils::MakeMaker::prompt; } } # Store a cleaned up version of the MakeMaker version, # since we need to behave differently in a variety of # ways based on the MM version. my $makemaker = eval $ExtUtils::MakeMaker::VERSION; # If we are passed a param, do a "newer than" comparison. # Otherwise, just return the MakeMaker version. sub makemaker { ( @_ < 2 or $makemaker >= eval($_[1]) ) ? $makemaker : 0 } # Ripped from ExtUtils::MakeMaker 6.56, and slightly modified # as we only need to know here whether the attribute is an array # or a hash or something else (which may or may not be appendable). my %makemaker_argtype = ( C => 'ARRAY', CONFIG => 'ARRAY', # CONFIGURE => 'CODE', # ignore DIR => 'ARRAY', DL_FUNCS => 'HASH', DL_VARS => 'ARRAY', EXCLUDE_EXT => 'ARRAY', EXE_FILES => 'ARRAY', FUNCLIST => 'ARRAY', H => 'ARRAY', IMPORTS => 'HASH', INCLUDE_EXT => 'ARRAY', LIBS => 'ARRAY', # ignore '' MAN1PODS => 'HASH', MAN3PODS => 'HASH', META_ADD => 'HASH', META_MERGE => 'HASH', PL_FILES => 'HASH', PM => 'HASH', PMLIBDIRS => 'ARRAY', PMLIBPARENTDIRS => 'ARRAY', PREREQ_PM => 'HASH', CONFIGURE_REQUIRES => 'HASH', SKIP => 'ARRAY', TYPEMAPS => 'ARRAY', XS => 'HASH', # VERSION => ['version',''], # ignore # _KEEP_AFTER_FLUSH => '', clean => 'HASH', depend => 'HASH', dist => 'HASH', dynamic_lib=> 'HASH', linkext => 'HASH', macro => 'HASH', postamble => 'HASH', realclean => 'HASH', test => 'HASH', tool_autosplit => 'HASH', # special cases where you can use makemaker_append CCFLAGS => 'APPENDABLE', DEFINE => 'APPENDABLE', INC => 'APPENDABLE', LDDLFLAGS => 'APPENDABLE', LDFROM => 'APPENDABLE', ); sub makemaker_args { my ($self, %new_args) = @_; my $args = ( $self->{makemaker_args} ||= {} ); foreach my $key (keys %new_args) { if ($makemaker_argtype{$key}) { if ($makemaker_argtype{$key} eq 'ARRAY') { $args->{$key} = [] unless defined $args->{$key}; unless (ref $args->{$key} eq 'ARRAY') { $args->{$key} = [$args->{$key}] } push @{$args->{$key}}, ref $new_args{$key} eq 'ARRAY' ? @{$new_args{$key}} : $new_args{$key}; } elsif ($makemaker_argtype{$key} eq 'HASH') { $args->{$key} = {} unless defined $args->{$key}; foreach my $skey (keys %{ $new_args{$key} }) { $args->{$key}{$skey} = $new_args{$key}{$skey}; } } elsif ($makemaker_argtype{$key} eq 'APPENDABLE') { $self->makemaker_append($key => $new_args{$key}); } } else { if (defined $args->{$key}) { warn qq{MakeMaker attribute "$key" is overriden; use "makemaker_append" to append values\n}; } $args->{$key} = $new_args{$key}; } } return $args; } # For mm args that take multiple space-seperated args, # append an argument to the current list. sub makemaker_append { my $self = shift; my $name = shift; my $args = $self->makemaker_args; $args->{$name} = defined $args->{$name} ? join( ' ', $args->{$name}, @_ ) : join( ' ', @_ ); } sub build_subdirs { my $self = shift; my $subdirs = $self->makemaker_args->{DIR} ||= []; for my $subdir (@_) { push @$subdirs, $subdir; } } sub clean_files { my $self = shift; my $clean = $self->makemaker_args->{clean} ||= {}; %$clean = ( %$clean, FILES => join ' ', grep { length $_ } ($clean->{FILES} || (), @_), ); } sub realclean_files { my $self = shift; my $realclean = $self->makemaker_args->{realclean} ||= {}; %$realclean = ( %$realclean, FILES => join ' ', grep { length $_ } ($realclean->{FILES} || (), @_), ); } sub libs { my $self = shift; my $libs = ref $_[0] ? shift : [ shift ]; $self->makemaker_args( LIBS => $libs ); } sub inc { my $self = shift; $self->makemaker_args( INC => shift ); } sub _wanted_t { } sub tests_recursive { my $self = shift; my $dir = shift || 't'; unless ( -d $dir ) { die "tests_recursive dir '$dir' does not exist"; } my %tests = map { $_ => 1 } split / /, ($self->tests || ''); require File::Find; File::Find::find( sub { /\.t$/ and -f $_ and $tests{"$File::Find::dir/*.t"} = 1 }, $dir ); $self->tests( join ' ', sort keys %tests ); } sub write { my $self = shift; die "&Makefile->write() takes no arguments\n" if @_; # Check the current Perl version my $perl_version = $self->perl_version; if ( $perl_version ) { eval "use $perl_version; 1" or die "ERROR: perl: Version $] is installed, " . "but we need version >= $perl_version"; } # Make sure we have a new enough MakeMaker require ExtUtils::MakeMaker; if ( $perl_version and $self->_cmp($perl_version, '5.006') >= 0 ) { # This previous attempted to inherit the version of # ExtUtils::MakeMaker in use by the module author, but this # was found to be untenable as some authors build releases # using future dev versions of EU:MM that nobody else has. # Instead, #toolchain suggests we use 6.59 which is the most # stable version on CPAN at time of writing and is, to quote # ribasushi, "not terminally fucked, > and tested enough". # TODO: We will now need to maintain this over time to push # the version up as new versions are released. $self->build_requires( 'ExtUtils::MakeMaker' => 6.59 ); $self->configure_requires( 'ExtUtils::MakeMaker' => 6.59 ); } else { # Allow legacy-compatibility with 5.005 by depending on the # most recent EU:MM that supported 5.005. $self->build_requires( 'ExtUtils::MakeMaker' => 6.36 ); $self->configure_requires( 'ExtUtils::MakeMaker' => 6.36 ); } # Generate the MakeMaker params my $args = $self->makemaker_args; $args->{DISTNAME} = $self->name; $args->{NAME} = $self->module_name || $self->name; $args->{NAME} =~ s/-/::/g; $args->{VERSION} = $self->version or die <<'EOT'; ERROR: Can't determine distribution version. Please specify it explicitly via 'version' in Makefile.PL, or set a valid $VERSION in a module, and provide its file path via 'version_from' (or 'all_from' if you prefer) in Makefile.PL. EOT if ( $self->tests ) { my @tests = split ' ', $self->tests; my %seen; $args->{test} = { TESTS => (join ' ', grep {!$seen{$_}++} @tests), }; } elsif ( $Module::Install::ExtraTests::use_extratests ) { # Module::Install::ExtraTests doesn't set $self->tests and does its own tests via harness. # So, just ignore our xt tests here. } elsif ( -d 'xt' and ($Module::Install::AUTHOR or $ENV{RELEASE_TESTING}) ) { $args->{test} = { TESTS => join( ' ', map { "$_/*.t" } grep { -d $_ } qw{ t xt } ), }; } if ( $] >= 5.005 ) { $args->{ABSTRACT} = $self->abstract; $args->{AUTHOR} = join ', ', @{$self->author || []}; } if ( $self->makemaker(6.10) ) { $args->{NO_META} = 1; #$args->{NO_MYMETA} = 1; } if ( $self->makemaker(6.17) and $self->sign ) { $args->{SIGN} = 1; } unless ( $self->is_admin ) { delete $args->{SIGN}; } if ( $self->makemaker(6.31) and $self->license ) { $args->{LICENSE} = $self->license; } my $prereq = ($args->{PREREQ_PM} ||= {}); %$prereq = ( %$prereq, map { @$_ } # flatten [module => version] map { @$_ } grep $_, ($self->requires) ); # Remove any reference to perl, PREREQ_PM doesn't support it delete $args->{PREREQ_PM}->{perl}; # Merge both kinds of requires into BUILD_REQUIRES my $build_prereq = ($args->{BUILD_REQUIRES} ||= {}); %$build_prereq = ( %$build_prereq, map { @$_ } # flatten [module => version] map { @$_ } grep $_, ($self->configure_requires, $self->build_requires) ); # Remove any reference to perl, BUILD_REQUIRES doesn't support it delete $args->{BUILD_REQUIRES}->{perl}; # Delete bundled dists from prereq_pm, add it to Makefile DIR my $subdirs = ($args->{DIR} || []); if ($self->bundles) { my %processed; foreach my $bundle (@{ $self->bundles }) { my ($mod_name, $dist_dir) = @$bundle; delete $prereq->{$mod_name}; $dist_dir = File::Basename::basename($dist_dir); # dir for building this module if (not exists $processed{$dist_dir}) { if (-d $dist_dir) { # List as sub-directory to be processed by make push @$subdirs, $dist_dir; } # Else do nothing: the module is already present on the system $processed{$dist_dir} = undef; } } } unless ( $self->makemaker('6.55_03') ) { %$prereq = (%$prereq,%$build_prereq); delete $args->{BUILD_REQUIRES}; } if ( my $perl_version = $self->perl_version ) { eval "use $perl_version; 1" or die "ERROR: perl: Version $] is installed, " . "but we need version >= $perl_version"; if ( $self->makemaker(6.48) ) { $args->{MIN_PERL_VERSION} = $perl_version; } } if ($self->installdirs) { warn qq{old INSTALLDIRS (probably set by makemaker_args) is overriden by installdirs\n} if $args->{INSTALLDIRS}; $args->{INSTALLDIRS} = $self->installdirs; } my %args = map { ( $_ => $args->{$_} ) } grep {defined($args->{$_} ) } keys %$args; my $user_preop = delete $args{dist}->{PREOP}; if ( my $preop = $self->admin->preop($user_preop) ) { foreach my $key ( keys %$preop ) { $args{dist}->{$key} = $preop->{$key}; } } my $mm = ExtUtils::MakeMaker::WriteMakefile(%args); $self->fix_up_makefile($mm->{FIRST_MAKEFILE} || 'Makefile'); } sub fix_up_makefile { my $self = shift; my $makefile_name = shift; my $top_class = ref($self->_top) || ''; my $top_version = $self->_top->VERSION || ''; my $preamble = $self->preamble ? "# Preamble by $top_class $top_version\n" . $self->preamble : ''; my $postamble = "# Postamble by $top_class $top_version\n" . ($self->postamble || ''); local *MAKEFILE; open MAKEFILE, "+< $makefile_name" or die "fix_up_makefile: Couldn't open $makefile_name: $!"; eval { flock MAKEFILE, LOCK_EX }; my $makefile = do { local $/; }; $makefile =~ s/\b(test_harness\(\$\(TEST_VERBOSE\), )/$1'inc', /; $makefile =~ s/( -I\$\(INST_ARCHLIB\))/ -Iinc$1/g; $makefile =~ s/( "-I\$\(INST_LIB\)")/ "-Iinc"$1/g; $makefile =~ s/^(FULLPERL = .*)/$1 "-Iinc"/m; $makefile =~ s/^(PERL = .*)/$1 "-Iinc"/m; # Module::Install will never be used to build the Core Perl # Sometimes PERL_LIB and PERL_ARCHLIB get written anyway, which breaks # PREFIX/PERL5LIB, and thus, install_share. Blank them if they exist $makefile =~ s/^PERL_LIB = .+/PERL_LIB =/m; #$makefile =~ s/^PERL_ARCHLIB = .+/PERL_ARCHLIB =/m; # Perl 5.005 mentions PERL_LIB explicitly, so we have to remove that as well. $makefile =~ s/(\"?)-I\$\(PERL_LIB\)\1//g; # XXX - This is currently unused; not sure if it breaks other MM-users # $makefile =~ s/^pm_to_blib\s+:\s+/pm_to_blib :: /mg; seek MAKEFILE, 0, SEEK_SET; truncate MAKEFILE, 0; print MAKEFILE "$preamble$makefile$postamble" or die $!; close MAKEFILE or die $!; 1; } sub preamble { my ($self, $text) = @_; $self->{preamble} = $text . $self->{preamble} if defined $text; $self->{preamble}; } sub postamble { my ($self, $text) = @_; $self->{postamble} ||= $self->admin->postamble; $self->{postamble} .= $text if defined $text; $self->{postamble} } 1; __END__ #line 544 Net-Amazon-EC2-0.24/inc/Module/Install/Metadata.pm000644 000765 000024 00000043277 12251245726 022077 0ustar00mallenstaff000000 000000 #line 1 package Module::Install::Metadata; use strict 'vars'; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.06'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } my @boolean_keys = qw{ sign }; my @scalar_keys = qw{ name module_name abstract version distribution_type tests installdirs }; my @tuple_keys = qw{ configure_requires build_requires requires recommends bundles resources }; my @resource_keys = qw{ homepage bugtracker repository }; my @array_keys = qw{ keywords author }; *authors = \&author; sub Meta { shift } sub Meta_BooleanKeys { @boolean_keys } sub Meta_ScalarKeys { @scalar_keys } sub Meta_TupleKeys { @tuple_keys } sub Meta_ResourceKeys { @resource_keys } sub Meta_ArrayKeys { @array_keys } foreach my $key ( @boolean_keys ) { *$key = sub { my $self = shift; if ( defined wantarray and not @_ ) { return $self->{values}->{$key}; } $self->{values}->{$key} = ( @_ ? $_[0] : 1 ); return $self; }; } foreach my $key ( @scalar_keys ) { *$key = sub { my $self = shift; return $self->{values}->{$key} if defined wantarray and !@_; $self->{values}->{$key} = shift; return $self; }; } foreach my $key ( @array_keys ) { *$key = sub { my $self = shift; return $self->{values}->{$key} if defined wantarray and !@_; $self->{values}->{$key} ||= []; push @{$self->{values}->{$key}}, @_; return $self; }; } foreach my $key ( @resource_keys ) { *$key = sub { my $self = shift; unless ( @_ ) { return () unless $self->{values}->{resources}; return map { $_->[1] } grep { $_->[0] eq $key } @{ $self->{values}->{resources} }; } return $self->{values}->{resources}->{$key} unless @_; my $uri = shift or die( "Did not provide a value to $key()" ); $self->resources( $key => $uri ); return 1; }; } foreach my $key ( grep { $_ ne "resources" } @tuple_keys) { *$key = sub { my $self = shift; return $self->{values}->{$key} unless @_; my @added; while ( @_ ) { my $module = shift or last; my $version = shift || 0; push @added, [ $module, $version ]; } push @{ $self->{values}->{$key} }, @added; return map {@$_} @added; }; } # Resource handling my %lc_resource = map { $_ => 1 } qw{ homepage license bugtracker repository }; sub resources { my $self = shift; while ( @_ ) { my $name = shift or last; my $value = shift or next; if ( $name eq lc $name and ! $lc_resource{$name} ) { die("Unsupported reserved lowercase resource '$name'"); } $self->{values}->{resources} ||= []; push @{ $self->{values}->{resources} }, [ $name, $value ]; } $self->{values}->{resources}; } # Aliases for build_requires that will have alternative # meanings in some future version of META.yml. sub test_requires { shift->build_requires(@_) } sub install_requires { shift->build_requires(@_) } # Aliases for installdirs options sub install_as_core { $_[0]->installdirs('perl') } sub install_as_cpan { $_[0]->installdirs('site') } sub install_as_site { $_[0]->installdirs('site') } sub install_as_vendor { $_[0]->installdirs('vendor') } sub dynamic_config { my $self = shift; my $value = @_ ? shift : 1; if ( $self->{values}->{dynamic_config} ) { # Once dynamic we never change to static, for safety return 0; } $self->{values}->{dynamic_config} = $value ? 1 : 0; return 1; } # Convenience command sub static_config { shift->dynamic_config(0); } sub perl_version { my $self = shift; return $self->{values}->{perl_version} unless @_; my $version = shift or die( "Did not provide a value to perl_version()" ); # Normalize the version $version = $self->_perl_version($version); # We don't support the really old versions unless ( $version >= 5.005 ) { die "Module::Install only supports 5.005 or newer (use ExtUtils::MakeMaker)\n"; } $self->{values}->{perl_version} = $version; } sub all_from { my ( $self, $file ) = @_; unless ( defined($file) ) { my $name = $self->name or die( "all_from called with no args without setting name() first" ); $file = join('/', 'lib', split(/-/, $name)) . '.pm'; $file =~ s{.*/}{} unless -e $file; unless ( -e $file ) { die("all_from cannot find $file from $name"); } } unless ( -f $file ) { die("The path '$file' does not exist, or is not a file"); } $self->{values}{all_from} = $file; # Some methods pull from POD instead of code. # If there is a matching .pod, use that instead my $pod = $file; $pod =~ s/\.pm$/.pod/i; $pod = $file unless -e $pod; # Pull the different values $self->name_from($file) unless $self->name; $self->version_from($file) unless $self->version; $self->perl_version_from($file) unless $self->perl_version; $self->author_from($pod) unless @{$self->author || []}; $self->license_from($pod) unless $self->license; $self->abstract_from($pod) unless $self->abstract; return 1; } sub provides { my $self = shift; my $provides = ( $self->{values}->{provides} ||= {} ); %$provides = (%$provides, @_) if @_; return $provides; } sub auto_provides { my $self = shift; return $self unless $self->is_admin; unless (-e 'MANIFEST') { warn "Cannot deduce auto_provides without a MANIFEST, skipping\n"; return $self; } # Avoid spurious warnings as we are not checking manifest here. local $SIG{__WARN__} = sub {1}; require ExtUtils::Manifest; local *ExtUtils::Manifest::manicheck = sub { return }; require Module::Build; my $build = Module::Build->new( dist_name => $self->name, dist_version => $self->version, license => $self->license, ); $self->provides( %{ $build->find_dist_packages || {} } ); } sub feature { my $self = shift; my $name = shift; my $features = ( $self->{values}->{features} ||= [] ); my $mods; if ( @_ == 1 and ref( $_[0] ) ) { # The user used ->feature like ->features by passing in the second # argument as a reference. Accomodate for that. $mods = $_[0]; } else { $mods = \@_; } my $count = 0; push @$features, ( $name => [ map { ref($_) ? ( ref($_) eq 'HASH' ) ? %$_ : @$_ : $_ } @$mods ] ); return @$features; } sub features { my $self = shift; while ( my ( $name, $mods ) = splice( @_, 0, 2 ) ) { $self->feature( $name, @$mods ); } return $self->{values}->{features} ? @{ $self->{values}->{features} } : (); } sub no_index { my $self = shift; my $type = shift; push @{ $self->{values}->{no_index}->{$type} }, @_ if $type; return $self->{values}->{no_index}; } sub read { my $self = shift; $self->include_deps( 'YAML::Tiny', 0 ); require YAML::Tiny; my $data = YAML::Tiny::LoadFile('META.yml'); # Call methods explicitly in case user has already set some values. while ( my ( $key, $value ) = each %$data ) { next unless $self->can($key); if ( ref $value eq 'HASH' ) { while ( my ( $module, $version ) = each %$value ) { $self->can($key)->($self, $module => $version ); } } else { $self->can($key)->($self, $value); } } return $self; } sub write { my $self = shift; return $self unless $self->is_admin; $self->admin->write_meta; return $self; } sub version_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->version( ExtUtils::MM_Unix->parse_version($file) ); # for version integrity check $self->makemaker_args( VERSION_FROM => $file ); } sub abstract_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->abstract( bless( { DISTNAME => $self->name }, 'ExtUtils::MM_Unix' )->parse_abstract($file) ); } # Add both distribution and module name sub name_from { my ($self, $file) = @_; if ( Module::Install::_read($file) =~ m/ ^ \s* package \s* ([\w:]+) \s* ; /ixms ) { my ($name, $module_name) = ($1, $1); $name =~ s{::}{-}g; $self->name($name); unless ( $self->module_name ) { $self->module_name($module_name); } } else { die("Cannot determine name from $file\n"); } } sub _extract_perl_version { if ( $_[0] =~ m/ ^\s* (?:use|require) \s* v? ([\d_\.]+) \s* ; /ixms ) { my $perl_version = $1; $perl_version =~ s{_}{}g; return $perl_version; } else { return; } } sub perl_version_from { my $self = shift; my $perl_version=_extract_perl_version(Module::Install::_read($_[0])); if ($perl_version) { $self->perl_version($perl_version); } else { warn "Cannot determine perl version info from $_[0]\n"; return; } } sub author_from { my $self = shift; my $content = Module::Install::_read($_[0]); if ($content =~ m/ =head \d \s+ (?:authors?)\b \s* ([^\n]*) | =head \d \s+ (?:licen[cs]e|licensing|copyright|legal)\b \s* .*? copyright .*? \d\d\d[\d.]+ \s* (?:\bby\b)? \s* ([^\n]*) /ixms) { my $author = $1 || $2; # XXX: ugly but should work anyway... if (eval "require Pod::Escapes; 1") { # Pod::Escapes has a mapping table. # It's in core of perl >= 5.9.3, and should be installed # as one of the Pod::Simple's prereqs, which is a prereq # of Pod::Text 3.x (see also below). $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } { defined $2 ? chr($2) : defined $Pod::Escapes::Name2character_number{$1} ? chr($Pod::Escapes::Name2character_number{$1}) : do { warn "Unknown escape: E<$1>"; "E<$1>"; }; }gex; } elsif (eval "require Pod::Text; 1" && $Pod::Text::VERSION < 3) { # Pod::Text < 3.0 has yet another mapping table, # though the table name of 2.x and 1.x are different. # (1.x is in core of Perl < 5.6, 2.x is in core of # Perl < 5.9.3) my $mapping = ($Pod::Text::VERSION < 2) ? \%Pod::Text::HTML_Escapes : \%Pod::Text::ESCAPES; $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } { defined $2 ? chr($2) : defined $mapping->{$1} ? $mapping->{$1} : do { warn "Unknown escape: E<$1>"; "E<$1>"; }; }gex; } else { $author =~ s{E}{<}g; $author =~ s{E}{>}g; } $self->author($author); } else { warn "Cannot determine author info from $_[0]\n"; } } #Stolen from M::B my %license_urls = ( perl => 'http://dev.perl.org/licenses/', apache => 'http://apache.org/licenses/LICENSE-2.0', apache_1_1 => 'http://apache.org/licenses/LICENSE-1.1', artistic => 'http://opensource.org/licenses/artistic-license.php', artistic_2 => 'http://opensource.org/licenses/artistic-license-2.0.php', lgpl => 'http://opensource.org/licenses/lgpl-license.php', lgpl2 => 'http://opensource.org/licenses/lgpl-2.1.php', lgpl3 => 'http://opensource.org/licenses/lgpl-3.0.html', bsd => 'http://opensource.org/licenses/bsd-license.php', gpl => 'http://opensource.org/licenses/gpl-license.php', gpl2 => 'http://opensource.org/licenses/gpl-2.0.php', gpl3 => 'http://opensource.org/licenses/gpl-3.0.html', mit => 'http://opensource.org/licenses/mit-license.php', mozilla => 'http://opensource.org/licenses/mozilla1.1.php', open_source => undef, unrestricted => undef, restrictive => undef, unknown => undef, ); sub license { my $self = shift; return $self->{values}->{license} unless @_; my $license = shift or die( 'Did not provide a value to license()' ); $license = __extract_license($license) || lc $license; $self->{values}->{license} = $license; # Automatically fill in license URLs if ( $license_urls{$license} ) { $self->resources( license => $license_urls{$license} ); } return 1; } sub _extract_license { my $pod = shift; my $matched; return __extract_license( ($matched) = $pod =~ m/ (=head \d \s+ L(?i:ICEN[CS]E|ICENSING)\b.*?) (=head \d.*|=cut.*|)\z /xms ) || __extract_license( ($matched) = $pod =~ m/ (=head \d \s+ (?:C(?i:OPYRIGHTS?)|L(?i:EGAL))\b.*?) (=head \d.*|=cut.*|)\z /xms ); } sub __extract_license { my $license_text = shift or return; my @phrases = ( '(?:under )?the same (?:terms|license) as (?:perl|the perl (?:\d )?programming language)' => 'perl', 1, '(?:under )?the terms of (?:perl|the perl programming language) itself' => 'perl', 1, 'Artistic and GPL' => 'perl', 1, 'GNU general public license' => 'gpl', 1, 'GNU public license' => 'gpl', 1, 'GNU lesser general public license' => 'lgpl', 1, 'GNU lesser public license' => 'lgpl', 1, 'GNU library general public license' => 'lgpl', 1, 'GNU library public license' => 'lgpl', 1, 'GNU Free Documentation license' => 'unrestricted', 1, 'GNU Affero General Public License' => 'open_source', 1, '(?:Free)?BSD license' => 'bsd', 1, 'Artistic license 2\.0' => 'artistic_2', 1, 'Artistic license' => 'artistic', 1, 'Apache (?:Software )?license' => 'apache', 1, 'GPL' => 'gpl', 1, 'LGPL' => 'lgpl', 1, 'BSD' => 'bsd', 1, 'Artistic' => 'artistic', 1, 'MIT' => 'mit', 1, 'Mozilla Public License' => 'mozilla', 1, 'Q Public License' => 'open_source', 1, 'OpenSSL License' => 'unrestricted', 1, 'SSLeay License' => 'unrestricted', 1, 'zlib License' => 'open_source', 1, 'proprietary' => 'proprietary', 0, ); while ( my ($pattern, $license, $osi) = splice(@phrases, 0, 3) ) { $pattern =~ s#\s+#\\s+#gs; if ( $license_text =~ /\b$pattern\b/i ) { return $license; } } return ''; } sub license_from { my $self = shift; if (my $license=_extract_license(Module::Install::_read($_[0]))) { $self->license($license); } else { warn "Cannot determine license info from $_[0]\n"; return 'unknown'; } } sub _extract_bugtracker { my @links = $_[0] =~ m#L<( https?\Q://rt.cpan.org/\E[^>]+| https?\Q://github.com/\E[\w_]+/[\w_]+/issues| https?\Q://code.google.com/p/\E[\w_\-]+/issues/list )>#gx; my %links; @links{@links}=(); @links=keys %links; return @links; } sub bugtracker_from { my $self = shift; my $content = Module::Install::_read($_[0]); my @links = _extract_bugtracker($content); unless ( @links ) { warn "Cannot determine bugtracker info from $_[0]\n"; return 0; } if ( @links > 1 ) { warn "Found more than one bugtracker link in $_[0]\n"; return 0; } # Set the bugtracker bugtracker( $links[0] ); return 1; } sub requires_from { my $self = shift; my $content = Module::Install::_readperl($_[0]); my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+(v?[\d\.]+)/mg; while ( @requires ) { my $module = shift @requires; my $version = shift @requires; $self->requires( $module => $version ); } } sub test_requires_from { my $self = shift; my $content = Module::Install::_readperl($_[0]); my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+([\d\.]+)/mg; while ( @requires ) { my $module = shift @requires; my $version = shift @requires; $self->test_requires( $module => $version ); } } # Convert triple-part versions (eg, 5.6.1 or 5.8.9) to # numbers (eg, 5.006001 or 5.008009). # Also, convert double-part versions (eg, 5.8) sub _perl_version { my $v = $_[-1]; $v =~ s/^([1-9])\.([1-9]\d?\d?)$/sprintf("%d.%03d",$1,$2)/e; $v =~ s/^([1-9])\.([1-9]\d?\d?)\.(0|[1-9]\d?\d?)$/sprintf("%d.%03d%03d",$1,$2,$3 || 0)/e; $v =~ s/(\.\d\d\d)000$/$1/; $v =~ s/_.+$//; if ( ref($v) ) { # Numify $v = $v + 0; } return $v; } sub add_metadata { my $self = shift; my %hash = @_; for my $key (keys %hash) { warn "add_metadata: $key is not prefixed with 'x_'.\n" . "Use appopriate function to add non-private metadata.\n" unless $key =~ /^x_/; $self->{values}->{$key} = $hash{$key}; } } ###################################################################### # MYMETA Support sub WriteMyMeta { die "WriteMyMeta has been deprecated"; } sub write_mymeta_yaml { my $self = shift; # We need YAML::Tiny to write the MYMETA.yml file unless ( eval { require YAML::Tiny; 1; } ) { return 1; } # Generate the data my $meta = $self->_write_mymeta_data or return 1; # Save as the MYMETA.yml file print "Writing MYMETA.yml\n"; YAML::Tiny::DumpFile('MYMETA.yml', $meta); } sub write_mymeta_json { my $self = shift; # We need JSON to write the MYMETA.json file unless ( eval { require JSON; 1; } ) { return 1; } # Generate the data my $meta = $self->_write_mymeta_data or return 1; # Save as the MYMETA.yml file print "Writing MYMETA.json\n"; Module::Install::_write( 'MYMETA.json', JSON->new->pretty(1)->canonical->encode($meta), ); } sub _write_mymeta_data { my $self = shift; # If there's no existing META.yml there is nothing we can do return undef unless -f 'META.yml'; # We need Parse::CPAN::Meta to load the file unless ( eval { require Parse::CPAN::Meta; 1; } ) { return undef; } # Merge the perl version into the dependencies my $val = $self->Meta->{values}; my $perl = delete $val->{perl_version}; if ( $perl ) { $val->{requires} ||= []; my $requires = $val->{requires}; # Canonize to three-dot version after Perl 5.6 if ( $perl >= 5.006 ) { $perl =~ s{^(\d+)\.(\d\d\d)(\d*)}{join('.', $1, int($2||0), int($3||0))}e } unshift @$requires, [ perl => $perl ]; } # Load the advisory META.yml file my @yaml = Parse::CPAN::Meta::LoadFile('META.yml'); my $meta = $yaml[0]; # Overwrite the non-configure dependency hashs delete $meta->{requires}; delete $meta->{build_requires}; delete $meta->{recommends}; if ( exists $val->{requires} ) { $meta->{requires} = { map { @$_ } @{ $val->{requires} } }; } if ( exists $val->{build_requires} ) { $meta->{build_requires} = { map { @$_ } @{ $val->{build_requires} } }; } return $meta; } 1; Net-Amazon-EC2-0.24/inc/Module/Install/Win32.pm000644 000765 000024 00000003403 12251245726 021244 0ustar00mallenstaff000000 000000 #line 1 package Module::Install::Win32; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.06'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } # determine if the user needs nmake, and download it if needed sub check_nmake { my $self = shift; $self->load('can_run'); $self->load('get_file'); require Config; return unless ( $^O eq 'MSWin32' and $Config::Config{make} and $Config::Config{make} =~ /^nmake\b/i and ! $self->can_run('nmake') ); print "The required 'nmake' executable not found, fetching it...\n"; require File::Basename; my $rv = $self->get_file( url => 'http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe', ftp_url => 'ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe', local_dir => File::Basename::dirname($^X), size => 51928, run => 'Nmake15.exe /o > nul', check_for => 'Nmake.exe', remove => 1, ); die <<'END_MESSAGE' unless $rv; ------------------------------------------------------------------------------- Since you are using Microsoft Windows, you will need the 'nmake' utility before installation. It's available at: http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe or ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe Please download the file manually, save it to a directory in %PATH% (e.g. C:\WINDOWS\COMMAND\), then launch the MS-DOS command line shell, "cd" to that directory, and run "Nmake15.exe" from there; that will create the 'nmake.exe' file needed by this module. You may then resume the installation process described in README. ------------------------------------------------------------------------------- END_MESSAGE } 1; Net-Amazon-EC2-0.24/inc/Module/Install/WriteAll.pm000644 000765 000024 00000002376 12251245726 022075 0ustar00mallenstaff000000 000000 #line 1 package Module::Install::WriteAll; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.06'; @ISA = qw{Module::Install::Base}; $ISCORE = 1; } sub WriteAll { my $self = shift; my %args = ( meta => 1, sign => 0, inline => 0, check_nmake => 1, @_, ); $self->sign(1) if $args{sign}; $self->admin->WriteAll(%args) if $self->is_admin; $self->check_nmake if $args{check_nmake}; unless ( $self->makemaker_args->{PL_FILES} ) { # XXX: This still may be a bit over-defensive... unless ($self->makemaker(6.25)) { $self->makemaker_args( PL_FILES => {} ) if -f 'Build.PL'; } } # Until ExtUtils::MakeMaker support MYMETA.yml, make sure # we clean it up properly ourself. $self->realclean_files('MYMETA.yml'); if ( $args{inline} ) { $self->Inline->write; } else { $self->Makefile->write; } # The Makefile write process adds a couple of dependencies, # so write the META.yml files after the Makefile. if ( $args{meta} ) { $self->Meta->write; } # Experimental support for MYMETA if ( $ENV{X_MYMETA} ) { if ( $ENV{X_MYMETA} eq 'JSON' ) { $self->Meta->write_mymeta_json; } else { $self->Meta->write_mymeta_yaml; } } return 1; } 1;