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