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