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