#!/usr/bin/perl -w use strict; use LWP::UserAgent; use Net::Ping; use URI; use Time::HiRes qw(usleep ualarm gettimeofday tv_interval); $| = 1; # list of URLs to find the mirror list my @svr_list = ('http://envy/moo', 'file:server_list'); # file to download to test speed my $test_file = '3/os/i386/GPL'; # file to get time/date from to gauge the mirror's freshness my $age_file = '3/updates/i386/headers/header.info'; # seconds to wait for a mirror to respond to our request my $timeout = 5; # HTTP useragent for this beast my $user_agent_txt = 'CentOS thingie for z00dax/0.1'; # how many tier 1 urls do we include in the return list my $t1_max = 2; # phone home and report dead/slow mirrors my $report_dead_mirrors = 1; # phone home and report mirror stats (age, rtt, whatever) my $report_mirror_stats = 1; ### my $DEBUG = 1; my $top_n = 5; my %mirror_list; my %dead_mirror_list; my $got_list = 0; my $arch = `/bin/uname -i`; my $releasever = `/bin/rpm -q centos-release --qf %{version}`; # force FTP into passive mode $ENV{'FTP_PASSIVE'} = 1; unless($arch && $releasever) { die "ERROR: Can't get arch or dist release info.\n"; } # let's get the list of mirror servers to check foreach my $url (@svr_list) { my $res = get_url($url); if($res->is_success) { my @m_list = split(/\n/, $res->content); foreach my $m (@m_list) { next if($m =~ /^#/); chomp($m); my ($_tier, $_url) = split(/\|/, $m); my $test_url = $_url . $test_file; my $duration = clock_url($test_url); if($duration) { $mirror_list{$_url} = { tier => $_tier, uri => URI->new($_url), rtt => $duration, url => $_url }; # print "-- Saving $_url : $_tier\n"; } else { # print "** dead $_url : $_tier\n"; $dead_mirror_list{$_url} = { url => $_url, tier => $_tier, error => $res->status_line }; # do something about dead/slow mirrors here } } $got_list = 1; last; } else { print "Error getting mirror list from $url : " . $res->status_line . "\n" if($DEBUG); print "Trying next server in the list...\n" if($DEBUG); } } die "ERROR: Can't get a valid list of mirrors to check.\n" unless($got_list); my @sorted = sort { $mirror_list{$a}->{rtt} <=> $mirror_list{$b}->{rtt} } keys(%mirror_list); my $t1_count = 0; my $total_count = 0; my @top_n_list; foreach my $_url (@sorted) { # stop if we have $top_n number of mirrors last if($total_count == $top_n); # next if we have enough tier 1 mirrors next if($t1_count == $t1_max && $mirror_list{$_url}->{tier} == 1); $total_count++; $t1_count++ if($mirror_list{$_url}->{tier} == 1); push(@top_n_list, $_url); } # take the $top_n fastest mirrors #my @top_n_list = splice(@sorted, 0, $top_n); foreach my $_url (@top_n_list) { my $age_url = $_url . $age_file; my $res = get_url($age_url); if($res->is_success) { $mirror_list{$_url}->{age} = time() - $res->last_modified } print "$_url : $mirror_list{$_url}->{rtt} : $mirror_list{$_url}->{age} : $mirror_list{$_url}->{tier}\n"; if($report_mirror_stats) { report_mirror_stats($mirror_list{$_url}); } } if($report_dead_mirrors) { foreach $_url (keys(%dead_mirror_list)) { report_dead_mirror($dead_mirror_list{$_url}); } } sub clock_url { my $url = shift; my $start = [gettimeofday]; my $res = get_url($url, $timeout); my $duration = tv_interval($start); return $res->is_success ? $duration : undef; } sub report_mirror_stats { my $mirror_hr = shift; return 1; } sub report_dead_mirror { my $mirror_hr = shift; return 1; } sub get_url { my $url = shift; my $timeout = shift || 5; my $ua = LWP::UserAgent->new; $ua->agent($user_agent_txt); my $req = HTTP::Request->new(GET => $url); # $req->header('Accept' => 'text/html'); # send request #my $res = $ua->request($req); #check the outcome $ua->timeout($timeout); return $ua->request($req); }