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