File Coverage

lib/Webservice/OVH/Cloud/Project.pm
Criterion Covered Total %
statement 24 228 10.5
branch 0 76 0.0
condition 0 15 0.0
subroutine 8 35 22.8
pod 26 26 100.0
total 58 380 15.2


line stmt bran cond sub pod time code
1             package Webservice::OVH::Cloud::Project;
2              
3             =encoding utf-8
4              
5             =head1 NAME
6              
7             Webservice::OVH::Cloud::Project
8              
9             =head1 SYNOPSIS
10              
11             use Webservice::OVH;
12            
13             my $ovh = Webservice::OVH->new_from_json("credentials.json");
14            
15             my $projects = $ovh->cloud->projects;
16             my $example_project = $projects->[0];
17            
18             my $images = $project->images;
19             my $instances = $project->instances;
20             my $regions = $project->regions;
21             my $flavors = $project->flavors;
22             my $ssh_keys = $project->ssh_keys;
23             my $networks = $project->network->privates;
24              
25             =head1 DESCRIPTION
26              
27             Provides access to all sub objects of a specific projects.
28              
29             =head1 METHODS
30              
31             =cut
32              
33 36     36   258 use strict;
  36         109  
  36         1056  
34 36     36   200 use warnings;
  36         88  
  36         963  
35 36     36   204 use Carp qw{ carp croak };
  36         99  
  36         2706  
36              
37             our $VERSION = 0.48;
38              
39 36     36   16814 use Webservice::OVH::Cloud::Project::IP;
  36         111  
  36         1145  
40 36     36   17947 use Webservice::OVH::Cloud::Project::Instance;
  36         113  
  36         1243  
41 36     36   16265 use Webservice::OVH::Cloud::Project::Network;
  36         133  
  36         1319  
42 36     36   16543 use Webservice::OVH::Cloud::Project::Image;
  36         119  
  36         1199  
43 36     36   15994 use Webservice::OVH::Cloud::Project::SSH;
  36         111  
  36         104822  
44              
45             =head2 _new_existing
46              
47             Internal Method to create the project object.
48             This method is not ment to be called directly.
49              
50             =over
51              
52             =item * Parameter: $api_wrapper - ovh api wrapper object, $module - root object, $id - api id
53              
54             =item * Return: L<Webservice::OVH::Cloud::Project>
55              
56             =item * Synopsis: Webservice::OVH::Cloud::Project->_new($ovh_api_wrapper, $project_name, $module);
57              
58             =back
59              
60             =cut
61              
62             sub _new_existing {
63              
64 0     0     my ( $class, %params ) = @_;
65              
66 0 0         die "Missing module" unless $params{module};
67 0 0         die "Missing wrapper" unless $params{wrapper};
68 0 0         die "Missing id" unless $params{id};
69              
70 0           my $project_id = $params{id};
71 0           my $api_wrapper = $params{wrapper};
72 0           my $module = $params{module};
73              
74 0           my $self = bless { _module => $module, _api_wrapper => $api_wrapper, _properties => undef, _id => $project_id, _instances => {}, _available_instances => [], _images => {}, _available_images => [], _ssh_keys => {}, _available_ssh_keys => [] }, $class;
75              
76 0           my $instance = Webservice::OVH::Cloud::Project::Instance->_new_empty( wrapper => $api_wrapper, project => $self, module => $module );
77 0           my $network = Webservice::OVH::Cloud::Project::Network->_new( wrapper => $api_wrapper, project => $self, module => $module );
78 0           my $ip = Webservice::OVH::Cloud::Project::IP->_new( wrapper => $api_wrapper, project => $self, module => $module );
79              
80 0           $self->{_instance} = $instance;
81 0           $self->{_network} = $network;
82 0           $self->{_ip} = $ip;
83              
84 0           $self->properties;
85              
86 0           return $self;
87             }
88              
89             =head2 id
90              
91             Returns the api id
92              
93             =over
94              
95             =item * Return: VALUE
96              
97             =item * Synopsis: my $id = $project->id;
98              
99             =back
100              
101             =cut
102              
103             sub id {
104              
105 0     0 1   my ($self) = @_;
106 0           return $self->{_id};
107             }
108              
109             =head2 properties
110              
111             Returns the raw properties as a hash.
112             This is the original return value of the web-api.
113              
114             =over
115              
116             =item * Return: HASH
117              
118             =item * Synopsis: my $properties = $project->properties;
119              
120             =back
121              
122             =cut
123              
124             sub properties {
125              
126 0     0 1   my ($self) = @_;
127              
128 0           my $api = $self->{_api_wrapper};
129 0           my $id = $self->id;
130 0           my $response = $api->rawCall( method => 'get', path => "/cloud/project/$id", noSignature => 0 );
131 0 0         croak $response->error if $response->error;
132 0           $self->{_properties} = $response->content;
133 0           return $self->{_properties};
134             }
135              
136             =head2 description
137              
138             Exposed property value.
139              
140             =over
141              
142             =item * Return: VALUE
143              
144             =item * Synopsis: my $description = $project->description;
145              
146             =back
147              
148             =cut
149              
150             sub description {
151              
152 0     0 1   my ($self) = @_;
153              
154 0           return $self->{_properties}->{description};
155             }
156              
157             =head2 unleash
158              
159             Exposed property value.
160              
161             =over
162              
163             =item * Return: VALUE
164              
165             =item * Synopsis: my $sub_domain = $project->unleash;
166              
167             =back
168              
169             =cut
170              
171             sub unleash {
172              
173 0     0 1   my ($self) = @_;
174              
175 0 0         return $self->{_properties}->{unleash} eq 'true' ? 1 : 0;
176             }
177              
178             =head2 order
179              
180             Exposed property value.
181              
182             =over
183              
184             =item * Return: <Webservice::OVH::Me::Order>
185              
186             =item * Synopsis: my $order = $project->order;
187              
188             =back
189              
190             =cut
191              
192             sub order {
193              
194 0     0 1   my ($self) = @_;
195              
196 0           my $order_id = $self->{_properties}->{orderId};
197              
198 0 0         return $self->{_module}->me->order($order_id) if $order_id;
199              
200 0           return undef;
201             }
202              
203             =head2 status
204              
205             Exposed property value.
206              
207             =over
208              
209             =item * Return: VALUE
210              
211             =item * Synopsis: my $status = $project->status;
212              
213             =back
214              
215             =cut
216              
217             sub status {
218              
219 0     0 1   my ($self) = @_;
220              
221 0           return $self->{_properties}->{status};
222             }
223              
224             =head2 access
225              
226             Exposed property value.
227              
228             =over
229              
230             =item * Return: VALUE
231              
232             =item * Synopsis: my $access = $project->access;
233              
234             =back
235              
236             =cut
237              
238             sub access {
239              
240 0     0 1   my ($self) = @_;
241              
242 0           return $self->{_properties}->{access};
243             }
244              
245             =head2 change
246              
247             Changes the project.
248              
249             =over
250              
251             =item * Parameter: %params - key => value description
252              
253             =item * Synopsis: $project->change(description => 'Beschreibung');
254              
255             =back
256              
257             =cut
258              
259             sub change {
260              
261 0     0 1   my ( $self, $description ) = @_;
262              
263 0           my $api = $self->{_api_wrapper};
264 0           my $project_id = $self->id;
265              
266 0           my $response = $api->rawCall( method => 'put', path => "/cloud/project/$project_id", body => { description => $description }, noSignature => 0 );
267 0 0         croak $response->error if $response->error;
268              
269 0           $self->properties;
270             }
271              
272             =head2 vrack
273              
274             Get associated vrack.
275              
276             =over
277              
278             =item * Return: HASH
279              
280             =item * Synopsis: $project->vrack;
281              
282             =back
283              
284             =cut
285              
286             sub vrack {
287              
288 0     0 1   my ($self) = @_;
289              
290 0           my $api = $self->{_api_wrapper};
291 0           my $project_id = $self->id;
292              
293 0           my $response = $api->rawCall( method => 'get', path => "/cloud/project/$project_id/vrack", noSignature => 0 );
294 0 0         croak $response->error if $response->error;
295              
296 0           return $response->content;
297             }
298              
299             =head2 instance_exists
300              
301             Returns 1 if object is available for the connected account, 0 if not.
302              
303             =over
304              
305             =item * Parameter: $instance_id - api id, $no_recheck - (optional)only for internal usage
306              
307             =item * Return: VALUE
308              
309             =item * Synopsis: print "instance exists" if $project->instance_exists($id);
310              
311             =back
312              
313             =cut
314              
315             sub instance_exists {
316              
317 0     0 1   my ( $self, $instance_id, $no_recheck ) = @_;
318              
319 0 0         if ( !$no_recheck ) {
320              
321 0           my $api = $self->{_api_wrapper};
322 0           my $project_id = $self->id;
323 0           my $response = $api->rawCall( method => 'get', path => "/cloud/project/$project_id/instance", noSignature => 0 );
324 0 0         croak $response->error if $response->error;
325              
326 0           my $list = $response->content;
327 0           my @instance_ids = grep { $_ = $_->{id} } @$list;
  0            
328              
329 0 0         return ( grep { $_ eq $instance_id } @instance_ids ) ? 1 : 0;
  0            
330              
331             } else {
332              
333 0           my $list = $self->{_available_instances};
334              
335 0 0         return ( grep { $_ eq $instance_id } @$list ) ? 1 : 0;
  0            
336             }
337             }
338              
339             =head2 instances
340              
341             Produces an array of all available instances that are connected to the project.
342              
343             =over
344              
345             =item * Return: ARRAY
346              
347             =item * Synopsis: my $instances = $project->instances;
348              
349             =back
350              
351             =cut
352              
353             sub instances {
354              
355 0     0 1   my ( $self, $region ) = @_;
356              
357 0 0         my $filter = $region ? Webservice::OVH::Helper->construct_filter( "region" => $region ) : "";
358 0           my $api = $self->{_api_wrapper};
359 0           my $project_id = $self->id;
360 0           my $response = $api->rawCall( method => 'get', path => sprintf( "/cloud/project/$project_id/instance%s", $filter ), noSignature => 0 );
361 0 0         croak $response->error if $response->error;
362              
363 0           my $instance_array = $response->content;
364 0           my $instances = [];
365 0           my $instance_ids = [map { $_->{id} } @$instance_array];
  0            
366 0           $self->{_available_instances} = $instance_ids;
367              
368 0           foreach my $instance_id (@$instance_ids) {
369              
370 0           my $instance = Webservice::OVH::Cloud::Project::Instance->_new_existing( wrapper => $api, project => $self, id => $instance_id, module => $self->{_module} );
371 0           push @$instances, $instance;
372             }
373              
374 0           return $instances;
375             }
376              
377             =head2 instance
378              
379             Returns a single instance by id
380              
381             =over
382              
383             =item * Parameter: $instance_id - api id
384              
385             =item * Return: L<Webservice::OVH::Cloud::Project::Instance>
386              
387             =item * Synopsis: my $instance = $project->instance($id);
388              
389             =back
390              
391             =cut
392              
393             sub instance {
394              
395 0     0 1   my ( $self, $instance_id ) = @_;
396              
397 0 0         if ( !$instance_id ) {
398              
399 0           return $self->{_instance};
400              
401             } else {
402              
403 0 0         if ( $self->instance_exists($instance_id) ) {
404              
405 0           my $api = $self->{_api_wrapper};
406 0   0       my $instance = $self->{_instances}{$instance_id} = $self->{_instances}{$instance_id} || Webservice::OVH::Cloud::Project::Instance->_new_existing( wrapper => $api, project => $self, id => $instance_id, module => $self->{_module} );
407              
408 0           return $instance;
409             } else {
410              
411 0           carp "Instance $instance_id doesn't exists";
412 0           return undef;
413             }
414             }
415             }
416              
417             =head2 create_instance
418              
419             Creates a new instance. Flavor image and ssh key need to be fetched first.
420             There is an example in examples/cloud.pl
421              
422             =over
423              
424             =item * Parameter: %params - key => value (required) flavor_id image_id name region (optional) group_id monthly_billing ssh_key_id user_data networks
425              
426             =item * Return: <Webservice::OVH::Cloud::Project::Instance>
427              
428             =item * Synopsis: my $instance = $project->create_instance(flavor_id => $flavor->id, image_id => $image->id, name => 'test', region => 'GRA1', ssh_key => $key->id networks => [ {ip => '0.0.0.0', network_id => 1 }, {ip => '0.0.0.0', network_id => 2 } ] );
429              
430             =back
431              
432             =cut
433              
434             sub create_instance {
435              
436 0     0 1   my ( $self, %params ) = @_;
437              
438 0           my $api = $self->{_api_wrapper};
439 0           my $instance = Webservice::OVH::Cloud::Project::Instance->_new( wrapper => $api, module => $self->{_module}, project => $self, %params, );
440 0           return $instance;
441             }
442              
443             =head2 regions
444              
445             Simple list of all available regions
446              
447             =over
448              
449             =item * Return: ARRAY
450              
451             =item * Synopsis: my $regions = $project->regions;
452              
453             =back
454              
455             =cut
456              
457             sub regions {
458              
459 0     0 1   my ($self) = @_;
460              
461 0           my $api = $self->{_api_wrapper};
462 0           my $project_id = $self->id;
463 0           my $response = $api->rawCall( method => 'get', path => "/cloud/project/$project_id/region", noSignature => 0 );
464 0 0         croak $response->error if $response->error;
465              
466 0           return $response->content;
467             }
468              
469             =head2 regions
470              
471             Get additional info about a specific region
472              
473             =over
474              
475             =item * Return: HASH
476              
477             =item * Synopsis: my $region_info = $project->region('GRA1');
478              
479             =back
480              
481             =cut
482              
483             sub region {
484              
485 0     0 1   my ( $self, $region_name ) = @_;
486              
487 0           my $api = $self->{_api_wrapper};
488 0           my $project_id = $self->id;
489 0           my $response = $api->rawCall( method => 'get', path => "/cloud/project/$project_id/region/$region_name", noSignature => 0 );
490 0 0         croak $response->error if $response->error;
491              
492 0           return $response->content;
493             }
494              
495             =head2 flavors
496              
497             Returns a hash of all available flavors.
498              
499             =over
500              
501             =item * Return: ARRAY
502              
503             =item * Synopsis: my $flavors = $project->flavors;
504              
505             =back
506              
507             =cut
508              
509             sub flavors {
510              
511 0     0 1   my ($self) = @_;
512              
513 0           my $api = $self->{_api_wrapper};
514 0           my $project_id = $self->id;
515 0           my $response = $api->rawCall( method => 'get', path => "/cloud/project/$project_id/flavor", noSignature => 0 );
516 0 0         croak $response->error if $response->error;
517              
518 0           my @flavor_ids = grep { $_->{id} } @{ $response->content };
  0            
  0            
519              
520 0           return \@flavor_ids;
521             }
522              
523             =head2 flavor
524              
525             Returns info about a specific flavor by id.
526              
527             =over
528              
529             =item * Return: HASH
530              
531             =item * Synopsis: my $flavors = $project->flavors;
532              
533             =back
534              
535             =cut
536              
537             sub flavor {
538              
539 0     0 1   my ( $self, $flavor_id ) = @_;
540              
541 0           my $api = $self->{_api_wrapper};
542 0           my $project_id = $self->id;
543 0           my $response = $api->rawCall( method => 'get', path => "/cloud/project/$project_id/flavor/$flavor_id", noSignature => 0 );
544 0 0         croak $response->error if $response->error;
545              
546 0           return $response->content;
547             }
548              
549             =head2 image_exists
550              
551             Returns 1 if image is available for the project, 0 if not.
552              
553             =over
554              
555             =item * Parameter: $image_id - api id, $no_recheck - (optional)only for internal usage
556              
557             =item * Return: VALUE
558              
559             =item * Synopsis: print "image exists" if $project->image_exists(1234);
560              
561             =back
562              
563             =cut
564              
565             sub image_exists {
566              
567 0     0 1   my ( $self, $image_id, $no_recheck ) = @_;
568              
569 0 0         if ( !$no_recheck ) {
570              
571 0           my $api = $self->{_api_wrapper};
572 0           my $project_id = $self->id;
573 0           my $response = $api->rawCall( method => 'get', path => "/cloud/project/$project_id/image", noSignature => 0 );
574 0 0         croak $response->error if $response->error;
575              
576 0           my $list = $response->content;
577              
578 0           my @image_ids = grep { $_ = $_->{id} } @$list;
  0            
579              
580 0 0         return ( grep { $_ eq $image_id } @image_ids ) ? 1 : 0;
  0            
581              
582             } else {
583              
584 0           my $list = $self->{_available_images};
585              
586 0 0         return ( grep { $_ eq $image_id } @$list ) ? 1 : 0;
  0            
587             }
588             }
589              
590             =head2 images
591              
592             Produces an array of all available images that are connected to the project.
593              
594             =over
595              
596             =item * Parameter: %filter - key => value flavor_type os_type region
597              
598             =item * Return: ARRAY
599              
600             =item * Synopsis: my $images = $project->images( flavor_type => 'ovh.ssd.eg', os_type => 'linux', region => 'GRA1' );
601              
602             =back
603              
604             =cut
605              
606             sub images {
607              
608 0     0 1   my ( $self, %filter ) = @_;
609              
610 0           my %filter_values;
611 0 0         $filter_values{flavorType} = $filter{flavor_type} unless exists $filter{flavor_type};
612 0 0         $filter_values{osType} = $filter{os_type} unless exists $filter{os_type};
613 0 0         $filter_values{region} = $filter{region} unless exists $filter{region};
614 0           my $filter = Webservice::OVH::Helper->construct_filter(%filter);
615              
616 0           my $api = $self->{_api_wrapper};
617 0           my $project_id = $self->id;
618 0           my $response = $api->rawCall( method => 'get', path => sprintf( "/cloud/project/$project_id/image%s", $filter ), noSignature => 0 );
619 0 0         croak $response->error if $response->error;
620              
621 0           my $image_array = $response->content;
622 0           my $images = [];
623 0           my @image_ids = grep { $_ = $_->{id} } @$image_array;
  0            
624 0           $self->{_available_images} = \@image_ids;
625              
626 0           foreach my $image_id (@image_ids) {
627              
628 0 0         if ( $self->image_exists( $image_id, 1 ) ) {
629              
630 0   0       my $image = $self->{_images}{$image_id} = $self->{_images}{$image_id} || Webservice::OVH::Cloud::Project::Image->_new_existing( wrapper => $api, module => $self->{_module}, project => $self, id => $image_id );
631 0           push @$images, $image;
632             }
633             }
634              
635 0           return $images;
636             }
637              
638             =head2 image
639              
640             Returns a single image by id
641              
642             =over
643              
644             =item * Parameter: $image_id - api id
645              
646             =item * Return: L<Webservice::OVH::Cloud::Project::Image>
647              
648             =item * Synopsis: my $image = $project->image($id);
649              
650             =back
651              
652             =cut
653              
654             sub image {
655              
656 0     0 1   my ( $self, $image_id ) = @_;
657              
658 0 0         if ( $self->image_exists($image_id) ) {
659              
660 0           my $api = $self->{_api_wrapper};
661 0   0       my $instance = $self->{_image}{$image_id} = $self->{_image}{$image_id} || Webservice::OVH::Cloud::Project::Image->_new_existing( wrapper => $api, module => $self->{_module}, project => $self, id => $image_id );
662              
663 0           return $instance;
664             } else {
665              
666 0           carp "Instance $image_id doesn't exists";
667 0           return undef;
668             }
669             }
670              
671             =head2 ssh_key_exists
672              
673             Returns 1 if key is available for the project, 0 if not.
674              
675             =over
676              
677             =item * Parameter: $key_id - api id, $no_recheck - (optional)only for internal usage
678              
679             =item * Return: VALUE
680              
681             =item * Synopsis: print "image exists" if $project->image_exists(1234);
682              
683             =back
684              
685             =cut
686              
687             sub ssh_key_exists {
688              
689 0     0 1   my ( $self, $key_id, $no_recheck ) = @_;
690              
691 0 0         if ( !$no_recheck ) {
692              
693 0           my $api = $self->{_api_wrapper};
694 0           my $project_id = $self->id;
695 0           my $response = $api->rawCall( method => 'get', path => "/cloud/project/$project_id/sshkey", noSignature => 0 );
696 0 0         croak $response->error if $response->error;
697              
698 0           my $list = $response->content;
699 0           my @key_ids = grep { $_ = $_->{id} } @$list;
  0            
700              
701 0 0         return ( grep { $_ eq $key_id } @key_ids ) ? 1 : 0;
  0            
702              
703             } else {
704              
705 0           my $list = $self->{_available_ssh_keys};
706              
707 0 0         return ( grep { $_ eq $key_id } @$list ) ? 1 : 0;
  0            
708             }
709             }
710              
711             =head2 ssh_keys
712              
713             Produces an array of all available ssh_keys that are connected to the project.
714              
715             =over
716              
717             =item * Parameter: $region - filters for specific region
718              
719             =item * Return: ARRAY
720              
721             =item * Synopsis: my $keys = $project->images( region => 'GRA1' );
722              
723             =back
724              
725             =cut
726              
727             sub ssh_keys {
728              
729 0     0 1   my ( $self, $region ) = @_;
730              
731 0 0         my $filter = $region ? Webservice::OVH::Helper->construct_filter( region => $region ) : "";
732              
733 0           my $api = $self->{_api_wrapper};
734 0           my $project_id = $self->id;
735 0           my $response = $api->rawCall( method => 'get', path => sprintf( "/cloud/project/$project_id/sshkey%s", $filter ), noSignature => 0 );
736 0 0         croak $response->error if $response->error;
737              
738 0           my $key_array = $response->content;
739 0           my $keys = [];
740 0           my @key_ids = grep { $_ = $_->{id} } @$key_array;
  0            
741 0           $self->{_available_ssh_keys} = \@key_ids;
742              
743 0           foreach my $key_id (@key_ids) {
744              
745 0 0         if ( $self->ssh_key_exists( $key_id, 1 ) ) {
746              
747 0   0       my $ssh_key = $self->{_ssh_keys}{$key_id} = $self->{_ssh_keys}{$key_id} || Webservice::OVH::Cloud::Project::SSH->_new_existing( wrapper => $api, module => $self->{_module}, project => $self, id => $key_id );
748 0           push @$keys, $ssh_key;
749             }
750             }
751              
752 0           return $keys;
753             }
754              
755             =head2 ssh_key
756              
757             Returns a single ssh_key by id
758              
759             =over
760              
761             =item * Parameter: $key_id - api id
762              
763             =item * Return: L<Webservice::OVH::Cloud::Project::SSH>
764              
765             =item * Synopsis: my $ssh_key = $project->ssh_key($id);
766              
767             =back
768              
769             =cut
770              
771             sub ssh_key {
772              
773 0     0 1   my ( $self, $key_id ) = @_;
774              
775 0 0         if ( $self->ssh_key_exists($key_id) ) {
776              
777 0           my $api = $self->{_api_wrapper};
778 0   0       my $instance = $self->{_ssh_keys}{$key_id} = $self->{_ssh_keys}{$key_id} || Webservice::OVH::Cloud::Project::SSH->_new_existing( wrapper => $api, module => $self->{_module}, project => $self, id => $key_id );
779              
780 0           return $instance;
781             } else {
782              
783 0           carp "SSH-Key $key_id doesn't exists";
784 0           return undef;
785             }
786             }
787              
788             =head2 create_ssh_key
789              
790             Creates a new ssh key.
791              
792             =over
793              
794             =item * Parameter: %params - key => value (required) name public_key (optional) region
795              
796             =item * Return: <Webservice::OVH::Cloud::Project::SSH>
797              
798             =item * Synopsis: my $ssh_key = $project->create_ssh_key( name => 'Test key', public_key => $key );
799              
800             =back
801              
802             =cut
803              
804             sub create_ssh_key {
805              
806 0     0 1   my ( $self, %params ) = @_;
807              
808 0           my $api = $self->{_api_wrapper};
809 0           my $ssh_key = Webservice::OVH::Cloud::Project::SSH->_new( wrapper => $api, module => $self->{_module}, project => $self, %params, );
810 0           return $ssh_key;
811             }
812              
813             =head2 network
814              
815             Access to /cloud/project/network api methods
816              
817             =over
818              
819             =item * Return: L<Webservice::OVH::Cloud::Project::Network>
820              
821             =item * Synopsis: $project->network;
822              
823             =back
824              
825             =cut
826              
827             sub network {
828              
829 0     0 1   my ($self) = @_;
830              
831 0           return $self->{_network};
832             }
833              
834             =head2 ip
835              
836             Access to /cloud/project/ip api methods
837              
838             =over
839              
840             =item * Return: L<Webservice::OVH::Cloud::Project::IP>
841              
842             =item * Synopsis: $project->ip;
843              
844             =back
845              
846             =cut
847              
848             sub ip {
849              
850 0     0 1   my ($self) = @_;
851              
852 0           return $self->{_ip};
853             }
854              
855             1;