File Coverage

blib/lib/Net/OpenStack/Compute.pm
Criterion Covered Total %
statement 29 125 23.2
branch 5 62 8.0
condition 2 47 4.2
subroutine 9 29 31.0
pod 14 19 73.6
total 59 282 20.9


line stmt bran cond sub pod time code
1             package Net::OpenStack::Compute;
2 2     2   63784 use Moose;
  2         739907  
  2         18  
3              
4             our $VERSION = '1.1200'; # VERSION
5              
6 2     2   11262 use Carp;
  2         4  
  2         140  
7 2     2   1370 use HTTP::Request;
  2         43100  
  2         84  
8 2     2   625 use JSON qw(from_json to_json);
  2         9421  
  2         13  
9 2     2   9832 use LWP;
  2         50102  
  2         3430  
10              
11             has auth_url => (is => 'rw', required => 1);
12             has user => (is => 'ro', required => 1);
13             has password => (is => 'ro', required => 1);
14             has project_id => (is => 'ro');
15             has region => (is => 'ro');
16             has service_name => (is => 'ro');
17             has is_rax_auth => (is => 'ro');
18             has verify_ssl => (is => 'ro', default => sub {! $ENV{OSCOMPUTE_INSECURE}});
19              
20             has base_url => (
21             is => 'ro',
22             lazy => 1,
23             default => sub { shift->_auth_info->{base_url} },
24             );
25             has token => (
26             is => 'ro',
27             lazy => 1,
28             default => sub { shift->_auth_info->{token} },
29             );
30             has _auth_info => (is => 'ro', lazy => 1, builder => '_build_auth_info');
31              
32             has _agent => (
33             is => 'ro',
34             lazy => 1,
35             default => sub {
36             my $self = shift;
37             my $agent = LWP::UserAgent->new(
38             ssl_opts => { verify_hostname => $self->verify_ssl });
39             return $agent;
40             },
41             );
42              
43             with 'Net::OpenStack::Compute::AuthRole';
44              
45             sub new_from_env {
46 0     0 0 0 my ($self, %params) = @_;
47 0         0 my $msg = "%s env var is required. Did you forget to source novarc?\n";
48 0 0 0     0 die sprintf($msg, 'NOVA_URL or OS_AUTH_URL')
49             unless $ENV{NOVA_URL} || $ENV{OS_AUTH_URL};
50 0 0 0     0 die sprintf($msg, 'NOVA_USERNAME or OS_USERNAME')
51             unless $ENV{NOVA_USERNAME} || $ENV{OS_USERNAME};
52 0 0 0     0 die sprintf($msg, 'NOVA_PASSWORD or NOVA_API_KEY or OS_PASSWORD')
      0        
53             unless $ENV{NOVA_PASSWORD} || $ENV{NOVA_API_KEY} || $ENV{OS_PASSWORD};
54 0   0     0 my %env = (
      0        
      0        
      0        
      0        
55             auth_url => $ENV{NOVA_URL} || $ENV{OS_AUTH_URL},
56             user => $ENV{NOVA_USERNAME} || $ENV{OS_USERNAME},
57             password => $ENV{NOVA_PASSWORD} || $ENV{NOVA_API_KEY}
58             || $ENV{OS_PASSWORD},
59             project_id => $ENV{NOVA_PROJECT_ID} || $ENV{OS_TENANT_NAME},
60             region => $ENV{NOVA_REGION_NAME} || $ENV{OS_AUTH_REGION},
61             service_name => $ENV{NOVA_SERVICE_NAME},
62             is_rax_auth => $ENV{NOVA_RAX_AUTH},
63             );
64 0         0 return Net::OpenStack::Compute->new(%env, %params);
65             }
66              
67             sub BUILD {
68 2     2 0 2099 my ($self) = @_;
69             # Make sure trailing slashes are removed from auth_url
70 2         71 my $auth_url = $self->auth_url;
71 2         7 $auth_url =~ s|/+$||;
72 2         54 $self->auth_url($auth_url);
73             }
74              
75             sub _build_auth_info {
76 2     2   3 my ($self) = @_;
77 2         8 my $auth_info = $self->get_auth_info();
78 0         0 $self->_agent->default_header(x_auth_token => $auth_info->{token});
79 0         0 return $auth_info;
80             }
81              
82             sub _get_query {
83 0     0   0 my %params = @_;
84 0 0       0 my $q = $params{query} or return '';
85 0 0       0 for ($q) { s/^/?/ unless /^\?/ }
  0         0  
86 0         0 return $q;
87             };
88              
89             sub get_servers {
90 0     0 1 0 my ($self, %params) = @_;
91 0         0 my $q = _get_query(%params);
92 0         0 my $res = $self->_get($self->_url("/servers", $params{detail}, $q));
93 0         0 return from_json($res->content)->{servers};
94             }
95              
96             sub get_server {
97 0     0 1 0 my ($self, $id) = @_;
98 0 0       0 croak "Invalid server id" unless $id;
99 0         0 my $res = $self->_get($self->_url("/servers/$id"));
100 0 0       0 return undef unless $res->is_success;
101 0         0 return from_json($res->content)->{server};
102             }
103              
104             sub get_servers_by_name {
105 0     0 1 0 my ($self, $name) = @_;
106 0         0 my $servers = $self->get_servers(detail => 1);
107 0         0 return [ grep { $_->{name} eq $name } @$servers ];
  0         0  
108             }
109              
110             sub create_server {
111 3     3 1 975 my ($self, $data) = @_;
112 3 100 66     42 croak "invalid data" unless $data and 'HASH' eq ref $data;
113 2 50       6 croak "name is required" unless defined $data->{name};
114 2 50       5 croak "flavorRef is required" unless defined $data->{flavorRef};
115 2 50       5 croak "imageRef is required" unless defined $data->{imageRef};
116 2         9 my $res = $self->_post("/servers", { server => $data });
117 0         0 return from_json($res->content)->{server};
118             }
119              
120             sub delete_server {
121 0     0 1 0 my ($self, $id) = @_;
122 0         0 $self->_delete($self->_url("/servers/$id"));
123 0         0 return 1;
124             }
125              
126             sub rebuild_server {
127 0     0 1 0 my ($self, $server, $data) = @_;
128 0 0       0 croak "server id is required" unless $server;
129 0 0 0     0 croak "invalid data" unless $data and 'HASH' eq ref $data;
130 0 0       0 croak "imageRef is required" unless $data->{imageRef};
131 0         0 my $res = $self->_action($server, rebuild => $data);
132 0         0 return from_json($res->content)->{server};
133             }
134              
135             sub resize_server {
136 0     0 0 0 my ($self, $server, $data) = @_;
137 0 0       0 croak "server id is required" unless $server;
138 0 0 0     0 croak "invalid data" unless $data and 'HASH' eq ref $data;
139 0 0       0 croak "flavorRef is required" unless $data->{flavorRef};
140 0         0 my $res = $self->_action($server, resize => $data);
141 0         0 return 1;
142             }
143              
144             sub reboot_server {
145 0     0 0 0 my ($self, $server, $data) = @_;
146 0 0       0 croak "server id is required" unless $server;
147 0 0 0     0 croak "invalid data" unless $data and 'HASH' eq ref $data;
148 0 0       0 croak "reboot type is required" unless $data->{type};
149 0         0 my $res = $self->_action($server, reboot => $data);
150 0         0 return 1;
151             }
152              
153             sub set_password {
154 0     0 1 0 my ($self, $server, $password) = @_;
155 0 0       0 croak "server id is required" unless $server;
156 0 0       0 croak "password id is required" unless defined $password;
157 0         0 my $res = $self->_action($server,
158             changePassword => { adminPass => $password });
159 0         0 return 1;
160             }
161              
162             sub get_vnc_console {
163 0     0 1 0 my ($self, $server, $type) = @_;
164 0   0     0 $type ||= "novnc";
165 0 0       0 croak "server id is required" unless $server;
166 0         0 my $res = $self->_action($server,
167             "os-getVNCConsole" => { type => $type });
168 0         0 return from_json($res->content)->{console};
169             }
170              
171             sub get_networks {
172 0     0 1 0 my ($self, %params) = @_;
173 0         0 my $q = _get_query(%params);
174 0         0 my $res = $self->_get(
175             $self->_url("/os-tenant-networks", $params{detail}, $q));
176 0         0 return from_json($res->content)->{networks};
177             }
178              
179             sub get_images {
180 0     0 1 0 my ($self, %params) = @_;
181 0         0 my $q = _get_query(%params);
182 0         0 my $res = $self->_get($self->_url("/images", $params{detail}, $q));
183 0         0 return from_json($res->content)->{images};
184             }
185              
186             sub get_image {
187 0     0 0 0 my ($self, $id) = @_;
188 0         0 my $res = $self->_get($self->_url("/images/$id"));
189 0 0       0 return undef unless $res->is_success;
190 0         0 return from_json($res->content)->{image};
191             }
192              
193             sub create_image {
194 0     0 1 0 my ($self, $server, $data) = @_;
195 0 0       0 croak "server id is required" unless defined $server;
196 0 0 0     0 croak "invalid data" unless $data and 'HASH' eq ref $data;
197 0 0       0 croak "name is required" unless defined $data->{name};
198 0         0 my $res = $self->_action($server, createImage => $data);
199 0         0 return 1;
200             }
201              
202             sub delete_image {
203 0     0 1 0 my ($self, $id) = @_;
204 0         0 $self->_delete($self->_url("/images/$id"));
205 0         0 return 1;
206             }
207              
208             sub get_flavors {
209 0     0 1 0 my ($self, %params) = @_;
210 0         0 my $q = _get_query(%params);
211 0         0 my $res = $self->_get($self->_url('/flavors', $params{detail}, $q));
212 0         0 return from_json($res->content)->{flavors};
213             }
214              
215             sub get_flavor {
216 0     0 1 0 my ($self, $id) = @_;
217 0         0 my $res = $self->_get($self->_url("/flavors/$id"));
218 0 0       0 return undef unless $res->is_success;
219 0         0 return from_json($res->content)->{flavor};
220             }
221              
222             sub _url {
223 2     2   3 my ($self, $path, $is_detail, $query) = @_;
224 2         57 my $url = $self->base_url . $path;
225 0 0         $url .= '/detail' if $is_detail;
226 0 0         $url .= $query if $query;
227 0           return $url;
228             }
229              
230             sub _get {
231             my ($self, $url) = @_;
232             return $self->_agent->get($url);
233             }
234              
235             sub _post {
236             my ($self, $url, $data) = @_;
237             return $self->_agent->post(
238             $self->_url($url),
239             content_type => 'application/json',
240             content => to_json($data),
241             );
242             }
243              
244             sub _delete {
245             my ($self, $url) = @_;
246             my $req = HTTP::Request->new(DELETE => $url);
247             return $self->_agent->request($req);
248             }
249              
250             sub _action {
251 0     0     my ($self, $server, $action, $data) = @_;
252 0           return $self->_post("/servers/$server/action", { $action => $data });
253             }
254              
255             sub _check_res {
256 0     0     my ($res) = @_;
257 0 0 0       die $res->status_line . "\n" . $res->content
258             if ! $res->is_success and $res->code != 404;
259 0           return 1;
260             }
261              
262             around qw( _get _post _delete ) => sub {
263             my $orig = shift;
264             my $self = shift;
265             my $res = $self->$orig(@_);
266             _check_res($res);
267             return $res;
268             };
269              
270              
271             # ABSTRACT: Bindings for the OpenStack Compute API.
272              
273              
274             1;
275              
276             __END__
277              
278             =pod
279              
280             =encoding UTF-8
281              
282             =head1 NAME
283              
284             Net::OpenStack::Compute - Bindings for the OpenStack Compute API.
285              
286             =head1 VERSION
287              
288             version 1.1200
289              
290             =head1 SYNOPSIS
291              
292             use Net::OpenStack::Compute;
293             my $compute = Net::OpenStack::Compute->new(
294             auth_url => 'https://identity.api.rackspacecloud.com/v2.0',
295             user => 'alejandro',
296             password => 'password',
297             region => 'ORD',
298             );
299             $compute->create_server({
300             name => 'server1',
301             flavorRef => $flav_id,
302             imageRef => $img_id,
303             });
304              
305             =head1 DESCRIPTION
306              
307             This class is an interface to the OpenStack Compute API.
308             Also see the L<oscompute> command line tool.
309              
310             =head1 METHODS
311              
312             Methods that take a hashref data param generally expect the corresponding
313             data format as defined by the OpenStack API JSON request objects.
314             See the
315             L<OpenStack Docs|http://docs.openstack.org/api/openstack-compute/1.1/content>
316             for more information.
317             Methods that return a single resource will return false if the resource is not
318             found.
319             Methods that return an arrayref of resources will return an empty arrayref if
320             the list is empty.
321             Methods that create, modify, or delete resources will throw an exception on
322             failure.
323              
324             =head2 new
325              
326             Creates a client.
327              
328             params:
329              
330             =over
331              
332             =item auth_url
333              
334             Required. The url of the authentication endpoint. For example:
335             C<'https://identity.api.rackspacecloud.com/v2.0'>
336              
337             =item user
338              
339             Required.
340              
341             =item password
342              
343             Required.
344              
345             =item region
346              
347             Optional.
348              
349             =item project_id
350              
351             Optional.
352              
353             =item service_name
354              
355             Optional.
356              
357             =item verify_ssl
358              
359             Optional. Defaults to 1.
360              
361             =item is_rax_auth
362              
363             Optional. Defaults to 0.
364              
365             =back
366              
367             =head2 get_server
368              
369             get_server($id)
370              
371             Returns the server with the given id or false if it doesn't exist.
372              
373             =head2 get_servers
374              
375             get_servers(%params)
376              
377             params:
378              
379             =over
380              
381             =item detail
382              
383             Optional. Defaults to 0.
384              
385             =item query
386              
387             Optional query string to be appended to requests.
388              
389             =back
390              
391             Returns an arrayref of all the servers.
392              
393             =head2 get_servers_by_name
394              
395             get_servers_by_name($name)
396              
397             Returns an arrayref of servers with the given name.
398             Returns an empty arrayref if there are no such servers.
399              
400             =head2 create_server
401              
402             create_server({ name => $name, flavorRef => $flavor, imageRef => $img_id })
403              
404             Returns a server hashref.
405              
406             =head2 delete_server
407              
408             delete_server($id)
409              
410             Returns true on success.
411              
412             =head2 rebuild_server
413              
414             rebuild_server($server_id, { imageRef => $img_id })
415              
416             Returns a server hashref.
417              
418             =head2 set_password
419              
420             set_password($server_id, $new_password)
421              
422             Returns true on success.
423              
424             =head2 get_vnc_console
425              
426             get_vnc_console($server_id[, $type=novnc])
427              
428             Returns a url to the server's VNC console
429              
430             =head2 get_networks
431              
432             get_networks($id)
433              
434             Returns a network list
435             .
436             =head2 get_image
437              
438             get_image($id)
439              
440             Returns an image hashref.
441              
442             =head2 get_images
443              
444             get_images(%params)
445              
446             params:
447              
448             =over
449              
450             =item detail
451              
452             Optional. Defaults to 0.
453              
454             =item query
455              
456             Optional query string to be appended to requests.
457              
458             =back
459              
460             Returns an arrayref of all the images.
461              
462             =head2 create_image
463              
464             create_image($server_id, { name => 'bob' })
465              
466             Returns an image hashref.
467              
468             =head2 delete_image
469              
470             delete_image($id)
471              
472             Returns true on success.
473              
474             =head2 get_flavor
475              
476             get_flavor($id)
477              
478             Returns a flavor hashref.
479              
480             =head2 get_flavors
481              
482             get_flavors(%params)
483              
484             params:
485              
486             =over
487              
488             =item detail
489              
490             Optional. Defaults to 0.
491              
492             =item query
493              
494             Optional query string to be appended to requests.
495              
496             =back
497              
498             Returns an arrayref of all the flavors.
499              
500             =head2 token
501              
502             token()
503              
504             Returns the OpenStack Compute API auth token.
505              
506             =head2 base_url
507              
508             base_url()
509              
510             Returns the base url for the OpenStack Compute API, which is returned by the
511             server after authenticating.
512              
513             =head1 SEE ALSO
514              
515             =over
516              
517             =item L<oscompute>
518              
519             =item L<OpenStack Docs|http://docs.openstack.org/api/openstack-compute/1.1/content>
520              
521             =back
522              
523             =head1 AUTHOR
524              
525             Naveed Massjouni <naveedm9@gmail.com>
526              
527             =head1 COPYRIGHT AND LICENSE
528              
529             This software is copyright (c) 2011 by Naveed Massjouni.
530              
531             This is free software; you can redistribute it and/or modify it under
532             the same terms as the Perl 5 programming language system itself.
533              
534             =cut