fdfb7ab1df93fc40b44f4512589e6a26d9d9e760
[p5sagit/Oyster.git] / lib / Oyster / Provision / Rackspace.pm
1 package Oyster::Provision::Rackspace;
2 use Moose::Role;
3 use Net::RackSpace::CloudServers;
4 use Net::RackSpace::CloudServers::Server;
5 use MIME::Base64;
6
7 # TODO http://failverse.com/manually-creating-a-cloud-server-from-a-cloud-files-image/
8 # in order to use an already created image to build the server, a la EC2 way
9
10 requires 'config';
11
12 has 'api_username' => ( is => 'ro', isa => 'Str', required => 1, lazy_build => 1);
13 sub _build_api_username {
14     my $self = shift;
15     return $ENV{CLOUDSERVERS_USER} if exists $ENV{CLOUDSERVERS_USER};
16     return $self->config->{api_username}
17         or die "Need api_username or CLOUDSERVERS_USER in environment";
18 }
19
20 has 'api_password' => ( is => 'ro', isa => 'Str', required => 1, lazy_build => 1);
21 sub _build_api_password {
22     my $self = shift;
23     return $ENV{CLOUDSERVERS_KEY} if exists $ENV{CLOUDSERVERS_KEY};
24     return $self->config->{api_password}
25         or die "Need api_password or CLOUDSERVERS_KEY in environment";
26 }
27
28 has '_rs' => ( is => 'rw', isa => 'Net::RackSpace::CloudServers', default => sub {
29     my $self = shift;
30     my $rs = Net::RackSpace::CloudServers->new(
31         user => $self->api_username,
32         key  => $self->api_password,
33     );
34     $rs;
35 });
36
37 sub create {
38    my $self = shift;
39
40    # Do nothing if the server named $self->name already exists
41    return if scalar grep { $_->name eq $self->name } $self->_rs->get_server();
42
43    # Check the ssh pub key exists and is <10K
44    die "SSH pubkey needs to exist" if !-f $self->pub_ssh;
45    my $pub_ssh = do {
46        local $/=undef;
47        open my $fh, '<', $self->pub_ssh or die "Cannot open ", $self->pub_ssh, ": $!";
48        my $_data = <$fh>;
49        close $fh or die "Cannot close ", $self->pub_ssh, ": $!";
50        $_data;
51    };
52    die "SSH pubkey needs to be < 10KiB" if length $pub_ssh > 10*1024;
53
54    # Build the server
55    my $server = Net::RackSpace::CloudServers::Server->new(
56       cloudservers => $self->_rs,
57       name         => $self->name,
58       flavorid     => $self->size,
59       imageid      => $self->image,
60       personality => [
61            {
62                path     => '/root/.ssh/authorized_keys',
63                contents => encode_base64($pub_ssh),
64            },
65       ],
66    );
67    my $newserver = $server->create_server;
68    warn "Server root password: ", $newserver->adminpass, "\n";
69
70    do {
71       $|=1;
72       my @tmpservers = $self->_rs->get_server_detail();
73       $server = ( grep { $_->name eq $self->name } @tmpservers )[0];
74       print "\rServer status: ", ($server->status || '?'), " progress: ", ($server->progress || '?');
75       if ( ( $server->status // '' ) ne 'ACTIVE' ) {
76         print " sleeping..";
77         sleep 2;
78       }
79    } while ( ( $server->status // '' ) ne 'ACTIVE' );
80
81    warn "Server public IP is: @{$server->public_address}\n";
82
83    # Connect to server and execute installation routines?
84    # Use Net::SSH?
85 }
86
87 sub delete {
88    my $self = shift;
89
90    # Die if the server named $self->name already exists
91    my ($server) = grep { $_->name eq $self->name } $self->_rs->get_server();
92    die "No such server: ", $self->name if !$server;
93
94    # Goodbye cruel user!
95    $server->delete_server();
96 }
97
98 sub resize {
99    my $self = shift;
100
101    $self->config();
102 }
103
104 1;
105
106 __END__
107
108 =head1 NAME
109
110 Oyster::Provision::Rackspace -- Provision your Oyster on Rackspace
111
112 =head1 SYNOPSIS
113
114 Use the Rackspace backend on your Oyster configuration file
115
116 =head1 REQUIRED PARAMETERS
117
118 The following are required to instantiate a backend:
119
120 =over
121
122 =item api_username
123
124 The rackspace API username, or C<$ENV{RACKSPACE_USER}> will be used if that is
125 not given
126
127 =item password
128
129 This is your rackspace API Key
130
131 The rackspace API key, or C<$ENV{RACKSPACE_KEY}> will be used if that is not
132 given
133
134 =item name
135
136 The name of your new/existing rackspace server.
137
138 =item size
139
140 The size ID of the rackspace server you want to create.
141 Use the following incantation to see them:
142
143     perl -MNet::RackSpace::CloudServers -e'
144         $r=Net::RackSpace::CloudServers->new(
145             user=>$ENV{CLOUDSERVERS_USER},
146             key=>$ENV{CLOUDSERVERS_KEY},
147         );
148         print map
149             { "id $_->{id} ram $_->{ram} disk $_->{disk}\n" }
150             $r->get_flavor_detail
151     '
152     id 1 ram 256 disk 10
153     id 2 ram 512 disk 20
154     id 3 ram 1024 disk 40
155     id 4 ram 2048 disk 80
156     id 5 ram 4096 disk 160
157     id 6 ram 8192 disk 320
158     id 7 ram 15872 disk 620
159
160 =item image
161
162 The image ID of the rackspace server you want to create.
163 Use the following incantation to see them:
164
165     perl -MNet::RackSpace::CloudServers -e'
166         $r=Net::RackSpace::CloudServers->new(
167             user=>$ENV{CLOUDSERVERS_USER},
168             key=>$ENV{CLOUDSERVERS_KEY},
169         );
170         print map
171             { "id $_->{id} name $_->{name}\n" }
172             $r->get_image_detail
173     '
174     id 29 name Windows Server 2003 R2 SP2 x86
175     id 69 name Ubuntu 10.10 (maverick)
176     id 41 name Oracle EL JeOS Release 5 Update 3
177     id 40 name Oracle EL Server Release 5 Update 4
178     id 187811 name CentOS 5.4
179     id 4 name Debian 5.0 (lenny)
180     id 10 name Ubuntu 8.04.2 LTS (hardy)
181     id 23 name Windows Server 2003 R2 SP2 x64
182     id 24 name Windows Server 2008 SP2 x64
183     id 49 name Ubuntu 10.04 LTS (lucid)
184     id 14362 name Ubuntu 9.10 (karmic)
185     id 62 name Red Hat Enterprise Linux 5.5
186     id 53 name Fedora 13
187     id 17 name Fedora 12
188     id 71 name Fedora 14
189     id 31 name Windows Server 2008 SP2 x86
190     id 51 name CentOS 5.5
191     id 14 name Red Hat Enterprise Linux 5.4
192     id 19 name Gentoo 10.1
193     id 28 name Windows Server 2008 R2 x64
194     id 55 name Arch 2010.05
195
196 Oyster only supports Linux images, specifically
197 Ubuntu 10.10 (maverick).
198
199 =item pub_ssh
200
201 The public ssh key you would like copied to the
202 new server's C</root/.ssh/authorized_keys> file
203 to allow you to ssh in the box without providing
204 a root password.
205
206 =back
207
208 =cut