File Coverage

blib/lib/MMM/Host.pm
Criterion Covered Total %
statement 47 93 50.5
branch 7 38 18.4
condition 2 15 13.3
subroutine 14 21 66.6
pod 13 13 100.0
total 83 180 46.1


line stmt bran cond sub pod time code
1             package MMM::Host;
2              
3 5     5   9355 use strict;
  5         13  
  5         373  
4 5     5   29 use warnings;
  5         11  
  5         135  
5 5     5   4404 use URI;
  5         41380  
  5         191  
6 5     5   5895 use POSIX qw(strftime);
  5         42909  
  5         40  
7 5     5   15883 use Math::Trig;
  5         165099  
  5         1441  
8 5     5   7400 use Net::DNS;
  5         731961  
  5         3074  
9              
10             =head1 NAME
11              
12             MMM::Host
13              
14             =head1 DESCRIPTION
15              
16             An object to retain host information
17              
18             =head1 METHODS
19              
20             =head2 new
21              
22             Create a MMM::Host object from information found in hash passed
23             as arguments.
24              
25             my $mirror MMM::Mirror->new( host => 'host.domain' );
26              
27             =cut
28              
29             sub _rev {
30 12     12   836 strftime( '%Y%m%d%H%M%S', gmtime(time) );
31             }
32              
33             sub new {
34 13     13 1 2709 my ( $class, %infos ) = @_;
35 13 100       48 $infos{hostname} or return;
36 12         48 $infos{hostname} = lc( $infos{hostname} );
37 12   33     67 $infos{revision} ||= _rev();
38 12 100       49 if ( $infos{geolocation} ) {
39 5         40 ( $infos{longitude}, $infos{latitude} ) =
40             $infos{geolocation} =~ /([\d\.]+),([\d\.]+)/;
41             }
42 12         146 bless( {%infos}, $class );
43             }
44              
45             =head2 hostname
46              
47             Return the hostname of the host
48              
49             =cut
50              
51             sub hostname {
52 1     1 1 325 my ($self) = @_;
53 1         10 $self->{hostname};
54             }
55              
56             =head2 revision
57              
58             Return the revision of the entry. The revision is an id to identify if an
59             entry is newer than another for same mirror.
60              
61             =cut
62              
63             sub revision {
64 2     2 1 7 my ($self) = @_;
65 2         10 $self->{revision};
66             }
67              
68             =head2 refresh_revision
69              
70             Reset revision to current timestamp
71              
72             =cut
73              
74             sub refresh_revision {
75 0     0 1 0 my ($self) = @_;
76 0         0 $self->{revision} = _rev();
77             }
78              
79             =head2 geo
80              
81             Return the latitude and the longitude for this host
82              
83             =cut
84              
85             sub geo {
86 14     14 1 64 return ( $_[0]->{latitude}, $_[0]->{longitude} );
87             }
88              
89             =head2 get_geo
90              
91             Try to use various method to find latitude and longitude
92             and return them
93              
94             =cut
95              
96             sub get_geo {
97 0 0   0 1 0 if ( !$_[0]->{get_geo_done} ) {
98 0 0 0     0 if (
99             !( defined( $_[0]->{latitude} ) && defined( $_[0]->{longitude} ) ) )
100             {
101 0 0       0 $_[0]->get_dnsloc || $_[0]->get_hostiploc;
102             }
103 0         0 $_[0]->{get_geo_done} = 1;
104             }
105 0         0 return $_[0]->geo;
106             }
107              
108             =head2 get_hostiploc
109              
110             Get and set information from hostip.info website
111              
112             =cut
113              
114             sub get_hostiploc {
115 0     0 1 0 my ($self) = @_;
116              
117 0 0       0 my ( $name, $aliases, $addrtype, $length, $paddr, @addrs ) =
118             gethostbyname( $self->hostname )
119             or return;
120 0         0 my $addr = join( '.', unpack( 'C4', $paddr ) );
121 5     5   5398 use WWW::HostipInfo;
  5         402912  
  5         5420  
122 0         0 my $hostip = new WWW::HostipInfo;
123 0 0       0 my $info = $hostip->get_info($addr) or return;
124 0 0       0 $self->{latitude} = $info->latitude
125             if ( defined( $info->latitude ) );
126 0 0       0 $self->{longitude} = $info->longitude
127             if ( defined( $info->longitude ) );
128 0 0       0 $self->{country} = $info->country_name
129             if ( defined( $info->country_name ) );
130 0 0       0 $self->{city} = $info->city if ( defined( $info->city ) );
131 0         0 $self->refresh_revision;
132              
133 0         0 1;
134             }
135              
136             =head2 get_dnsloc
137              
138             Try to find geolocalisation from DNS LOC record
139              
140             =cut
141              
142             sub get_dnsloc {
143 0     0 1 0 my ($self) = @_;
144 0         0 return;
145 0         0 my @partname = split( /\./, $self->hostname );
146 0         0 my $dnsq = Net::DNS::Resolver->new();
147 0         0 do {
148 0 0       0 my $answer = $dnsq->query( join( '.', @partname ), 'LOC' ) or return;
149 0         0 foreach my $ans ( $answer->answer ) {
150 0 0       0 if ( $ans->type eq 'LOC' ) {
151 0         0 ( $self->{latitude}, $self->{longitude} ) = $ans->latlon();
152 0         0 $self->refresh_revision;
153 0         0 return 1;
154             }
155             }
156             } while ( shift(@partname) );
157              
158 0         0 return;
159             }
160              
161             =head2 set_geo($latitude, $longitude)
162              
163             Set the geolocalisation for this host
164              
165             =cut
166              
167             sub set_geo {
168 0     0 1 0 my ( $self, $lat, $lon ) = @_;
169 0         0 ( $self->{latitude}, $self->{longitude} ) = ( $lat, $lon );
170             }
171              
172             =head2 distance( $host )
173              
174             Calcule the distance (angle in degrees) to another host
175              
176             =cut
177              
178             sub distance {
179 3     3 1 5 my ( $self, $host ) = @_;
180 3 50       10 grep { !defined($_) } ($self->geo, $host->geo) and return;
  12         32  
181 3         8 my ( $lat1, $lon1 ) = map { deg2rad($_) } $self->geo;
  6         57  
182 3         32 my ( $lat2, $lon2 ) = map { deg2rad($_) } $host->geo;
  6         34  
183 3         166 rad2deg(
184             acos(
185             sin($lat1) * sin($lat2) + cos($lat1) * cos($lat2) *
186             cos( $lon1 - $lon2 )
187             )
188             );
189             }
190              
191             =head2 same_host($host)
192              
193             Compare two host entry and return true if they identify the same
194             computer
195              
196             =cut
197              
198             sub same_host {
199 0     0 1 0 my ( $self, $host ) = @_;
200 0 0       0 if ( $self->hostname eq $host->hostname ) {
201 0         0 return 1;
202             }
203 0         0 return;
204             }
205              
206             =head2 sync_host($host)
207              
208             Get unknown values from $host if defined.
209              
210             =cut
211              
212             sub sync_host {
213 1     1 1 3 my ( $self, $host ) = @_;
214 1         3 foreach (qw(city continent country latitude longiture)) {
215 5 50 0     18 if (
      33        
216             ( !defined( $self->{$_} ) )
217             || ( defined( $host->{$_} )
218             && $host->revision > $self->revision )
219             )
220             {
221 5         13 $self->{$_} = $host->{$_};
222             }
223             }
224              
225 1 50       6 if ( $host->revision > $self->revision ) {
226 0           $self->{revision} = $host->{revision};
227             }
228             }
229              
230             =head2 xml_output
231              
232             Return a xml string describing this mirror.
233              
234             See also
235              
236             =cut
237              
238             sub xml_output {
239 0     0 1   my ($self) = @_;
240 0           my $xml = "\t\t\n";
241              
242 0           foreach (qw(hostname continent country city revision)) {
243 0 0         if ( $self->{$_} ) {
244 0           $xml .= sprintf( "\t\t\t<%s>%s\n", $_, $self->{$_}, $_ );
245             }
246             }
247              
248 0 0 0       if ( defined( $self->{latitude} ) && defined( $self->{longitude} ) ) {
249 0           $xml .=
250             "\t\t\t$self->{longitude},$self->{latitude}\n";
251             }
252              
253 0           $xml .= "\t\t\n";
254              
255 0           $xml;
256             }
257              
258             1;
259              
260             =head1 AUTHOR
261              
262             Olivier Thauvin
263              
264             =head1 COPYRIGHT AND LICENSE
265              
266             Copyright (C) 2006 Olivier Thauvin
267              
268             This program is free software; you can redistribute it and/or
269             modify it under the terms of the GNU General Public License
270             as published by the Free Software Foundation; either version 2
271             of the License, or (at your option) any later version.
272              
273             This program is distributed in the hope that it will be useful,
274             but WITHOUT ANY WARRANTY; without even the implied warranty of
275             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
276             GNU General Public License for more details.
277              
278             You should have received a copy of the GNU General Public License
279             along with this program; if not, write to the Free Software
280             Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
281              
282             =cut
283