better error on bad pkgpart
[freeside.git] / FS / FS / part_export / amazon_ec2.pm
1 package FS::part_export::amazon_ec2;
2
3 use base qw( FS::part_export );
4
5 use vars qw(@ISA %info $replace_ok_kludge);
6 use Tie::IxHash;
7 use FS::Record qw( qsearchs );
8 use FS::svc_external;
9
10 tie my %options, 'Tie::IxHash',
11   'access_key' => { label => 'AWS access key', },
12   'secret_key' => { label => 'AWS secret key', },
13   'ami'        => { label => 'AMI', 'default' => 'ami-ff46a796', },
14   'keyname'    => { label => 'Keypair name', },
15   #option to turn off (or on) ip address allocation
16 ;
17
18 %info = (
19   'svc'      => 'svc_external',
20   'desc'     =>
21     'Export to Amazon EC2',
22   'options'  => \%options,
23   'notes'    => <<'END'
24 Create instances in the Amazon EC2 (Elastic compute cloud).  Install
25 Net::Amazon::EC2 perl module.  Advisable to set svc_external-skip_manual config
26 option.
27 END
28 );
29
30 $replace_ok_kludge = 0;
31
32 sub rebless { shift; }
33
34 sub _export_insert {
35   my($self, $svc_external) = (shift, shift);
36   $err_or_queue = $self->amazon_ec2_queue( $svc_external->svcnum, 'insert',
37     $svc_external->svcnum,
38     $self->option('ami'),
39     $self->option('keyname'),
40   );
41   ref($err_or_queue) ? '' : $err_or_queue;
42 }
43
44 sub _export_replace {
45   my( $self, $new, $old ) = (shift, shift, shift);
46   return '' if $replace_ok_kludge;
47   return "can't change instance id or IP address";
48   #$err_or_queue = $self->amazon_ec2_queue( $new->svcnum,
49   #  'replace', $new->username, $new->_password );
50   #ref($err_or_queue) ? '' : $err_or_queue;
51 }
52
53 sub _export_delete {
54   my( $self, $svc_external ) = (shift, shift);
55   my( $instance_id, $ip ) = split(/:/, $svc_external->title );
56   $err_or_queue = $self->amazon_ec2_queue( $svc_external->svcnum, 'delete',
57     $instance_id,
58     $ip,
59   );
60   ref($err_or_queue) ? '' : $err_or_queue;
61 }
62
63 #these three are optional
64 # fallback for svc_acct will change and restore password
65 #sub _export_suspend {
66 #  my( $self, $svc_something ) = (shift, shift);
67 #  $err_or_queue = $self->amazon_ec2_queue( $svc_something->svcnum,
68 #    'suspend', $svc_something->username );
69 #  ref($err_or_queue) ? '' : $err_or_queue;
70 #}
71 #
72 #sub _export_unsuspend {
73 #  my( $self, $svc_something ) = (shift, shift);
74 #  $err_or_queue = $self->amazon_ec2_queue( $svc_something->svcnum,
75 #    'unsuspend', $svc_something->username );
76 #  ref($err_or_queue) ? '' : $err_or_queue;
77 #}
78
79 sub export_links {
80   my($self, $svc_external, $arrayref) = (shift, shift, shift);
81   my( $instance_id, $ip ) = split(/:/, $svc_external->title );
82    
83   push @$arrayref, qq!<A HREF="http://$ip/">http://$ip/</A>!;
84   '';
85 }
86
87 ###
88
89 #a good idea to queue anything that could fail or take any time
90 sub amazon_ec2_queue {
91   my( $self, $svcnum, $method ) = (shift, shift, shift);
92   my $queue = new FS::queue {
93     'svcnum' => $svcnum,
94     'job'    => "FS::part_export::amazon_ec2::amazon_ec2_$method",
95   };
96   $queue->insert( $self->option('access_key'),
97                   $self->option('secret_key'),
98                   @_
99                 )
100     or $queue;
101 }
102
103 sub amazon_ec2_new {
104   my( $access_key, $secret_key, @rest ) = @_;
105
106   eval 'use Net::Amazon::EC2;';
107   die $@ if $@;
108
109   my $ec2 = new Net::Amazon::EC2 'AWSAccessKeyId'  => $access_key,
110                                  'SecretAccessKey' => $secret_key;
111
112   ( $ec2, @rest );
113 }
114
115 sub amazon_ec2_insert { #subroutine, not method
116   my( $ec2, $svcnum, $ami, $keyname ) = amazon_ec2_new(@_);
117
118   my $reservation_info = $ec2->run_instances( 'ImageId'  => $ami,
119                                               'KeyName'  => $keyname,
120                                               'MinCount' => 1,
121                                               'MaxCount' => 1,
122                                             );
123
124   my $instance_id = $reservation_info->instances_set->[0]->instance_id;
125
126   my $ip = $ec2->allocate_address
127     or die "can't allocate address";
128   $ec2->associate_address('InstanceId' => $instance_id,
129                           'PublicIp'   => $ip,
130                          )
131     or die "can't assocate IP address $ip with instance $instance_id";
132
133   my $svc_external = qsearchs('svc_external', { 'svcnum' => $svcnum } )
134     or die "can't find svc_external.svcnum $svcnum\n";
135
136   $svc_external->title("$instance_id:$ip");
137
138   local($replace_ok_kludge) = 1;
139   my $error = $svc_external->replace;
140   die $error if $error;
141
142 }
143
144 #sub amazon_ec2_replace { #subroutine, not method
145 #}
146
147 sub amazon_ec2_delete { #subroutine, not method
148   my( $ec2, $id, $ip ) = amazon_ec2_new(@_);
149
150   my $instance_id = sprintf('i-%x', $id);
151   $ec2->disassociate_address('PublicIp'=>$ip)
152     or die "can't dissassocate $ip";
153
154   $ec2->release_address('PublicIp'=>$ip)
155     or die "can't release $ip";
156
157   my $result = $ec2->terminate_instances('InstanceId'=>$instance_id);
158   #check for instance_id match or something?
159
160 }
161
162 #sub amazon_ec2_suspend { #subroutine, not method
163 #}
164
165 #sub amazon_ec2_unsuspend { #subroutine, not method
166 #}
167
168 1;
169