十二月 242007
 

這是今年1月寫的 script… 用來監控各大 FreeBSD CVSUP mirror 網站的檔案更新程度,
提供服務的網址是 http://ftp.giga.net.tw/cvsup.php

內容其實很簡單,下面把程式放出來,有興趣的人歡迎免費拿去修改使用

==
原理說明:

CVS 不像 Subversion 一樣可以很容易知道目前 repository 中的最新版本為何,
必須要把每個檔案檢查一遍才有辦法知道最新的版本是什麼…

不過在 FreeBSD Source CVS 下面,每次 commit 都會有 commit log 可經由 CVSUP 取得,
因此我們可以利用 CVSROOT-*/commitlogs/* 這幾個檔案來判斷目前 source tree 的狀態..
只要把這幾個檔案經由 CVSUP 取出來就可以大致知道該伺服器的目前保存的最新版本是哪一個了
==

第一個是一個 Perl script,主要是連結到各大 FreeBSD CVSUP 網站取得相關資訊存下來
後面則附上一個 PHP script,可以把這些資訊用 HTML 表格方式呈現出來

check-cvsup.pl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#!/usr/bin/perl
 
# Check the update status for CVSUP servers
# BSD license
# Shen Cheng-Da (cdsheen AT gmail.com)
 
use POSIX qw(strftime);
use Net::DNS;
use Time::HiRes qw( gettimeofday tv_interval );
 
@servers = qw( cvsup.tw.freebsd.org cvsup1.tw.freebsd.org cvsup2.tw.freebsd.org
                cvsup3.tw.freebsd.org cvsup4.tw.freebsd.org cvsup5.tw.freebsd.org
                cvsup6.tw.freebsd.org cvsup7.tw.freebsd.org cvsup8.tw.freebsd.org
                cvsup9.tw.freebsd.org cvsup10.tw.freebsd.org cvsup11.tw.freebsd.org
                cvsup12.tw.freebsd.org cvsup13.tw.freebsd.org cvsup14.tw.freebsd.org );
 
$dir    = '/home/cvsup-monitor';
 
$cvsup  = '/usr/local/bin/cvsup';
$base   = $dir . '/base';
$log    = $dir . '/check.log';
 
chdir( $dir ) || die "ERROR: Can not change to directory [$dir]\n";
 
mkdir( $base, 0755 ) unless -d $base;
 
@files_src = qw( CVSROOT-src/commitlogs/CVSROOT CVSROOT-src/commitlogs/bin
                CVSROOT-src/commitlogs/etc CVSROOT-src/commitlogs/contrib
                CVSROOT-src/commitlogs/gnu CVSROOT-src/commitlogs/games
                CVSROOT-src/commitlogs/include CVSROOT-src/commitlogs/lib
                CVSROOT-src/commitlogs/release CVSROOT-src/commitlogs/sys
                CVSROOT-src/commitlogs/sbin CVSROOT-src/commitlogs/share
                CVSROOT-src/commitlogs/tools CVSROOT-src/commitlogs/user
                CVSROOT-src/commitlogs/usrbin CVSROOT-src/commitlogs/usrsbin );
 
@files_ports = qw( CVSROOT-ports/commitlogs/CVSROOT
                        CVSROOT-ports/commitlogs/ports );
 
$includes = '';
foreach $f ( @files_src ) {
        $includes .= " -i $f";
}
foreach $f ( @files_ports ) {
        $includes .= " -i $f";
}
 
open( LOG, ">$log");
 
my $resolver = Net::DNS::Resolver->new;
 
$resolver->usevc(1);
$resolver->udp_timeout(5);
$resolver->tcp_timeout(5);
$resolver->retrans(3);
$resolver->retry(2);
$resolver->persistent_tcp(1);
 
foreach $server ( @servers ) {
        my $query = $resolver->query($server, 'A');
        @ipaddr = @cname = ();
        if( $query ) {
                foreach $rr ($query->answer) {
                        if( $rr->type eq 'A' ) {
                                print LOG "$server => [A] ".$rr->address."\n";
                                push( @ipaddr, $rr->address );
                        }
                        elsif( $rr->type eq 'CNAME' ) {
                                print LOG "$server => [CNAME] ".$rr->cname."\n";
                                push( @cname, $rr->cname );
                        }
                }
        }
        $ip = $ipaddr[0];
        $ipaddr = join( '|', @ipaddr );
        $cname  = join( '|', @cname  );
 
        $ibase   = "$base/$server";
        mkdir( $ibase, 0755 ) unless -d $ibase;
        mkdir( "$ibase/SRC", 0755 ) unless -d "$ibase/SRC";
 
        $cmd = "$cvsup -h $ip -L 0 -b $ibase -r 0 $includes supfile";
 
        $time_start = [gettimeofday];
        system($cmd);
        $elapsed = tv_interval( $time_start );
 
        printf LOG ("$server => cvsup on $ip elapsed %.2fs\n", $time_elapsed);
 
        unless( $? ) {
                $mt_src = $mt_ports = 0;
                foreach $f ( @files_src ) {
                        $t = (stat( "$ibase/SRC/$f" ))[9];
                        $mt_src = $t if $t > $mt_src;
                }
                foreach $f ( @files_ports ) {
                        $t = (stat( "$ibase/SRC/$f" ))[9];
                        $mt_ports = $t if $t > $mt_ports;
                }
                open( REC, ">$ibase/last-commit.txt" );
                printf REC("$mt_src,$mt_ports,%.2f,$ipaddr,$cname",$elapsed);
                close(REC);
 
                printf LOG ("$server => SRC: %s\n",
                        strftime("%Y/%m/%d %H:%M:%S", localtime($mt_src)) );
                printf LOG ("$server => PORTS: %s\n",
                        strftime("%Y/%m/%d %H:%M:%S", localtime($mt_ports)) );
        }
}
 
close(LOG);

supfile:

*default prefix=SRC
*default release=cvs delete use-rel-suffix
*default compress
 
cvsroot-src
cvsroot-ports

cvsup.php

<style type="text/css">
  td       { font-size: 12px; vertical-align: top }
  td.head  { background: #FFFFC0 }
  td.c     { background: #E0E0FF }
  td.red   { background: #FFE0E0 }
  td.green { background: #E0FFE0 }
</style>
<table border=1 cellspacing=0 cellpadding=2>
<tr><td class=head>Server Name</td><td class=head>IP</td>
<td class=head>CNAME</td><td class=head>latest commit of src</td>
<td class=head>latest commit of ports</td>
</tr>
<?
        $dir = '/home/cvsup-monitor';
        $servers = array(
              'cvsup.tw.freebsd.org',  'cvsup1.tw.freebsd.org',  'cvsup2.tw.freebsd.org',
              'cvsup3.tw.freebsd.org', 'cvsup4.tw.freebsd.org', 'cvsup5.tw.freebsd.org',
              'cvsup6.tw.freebsd.org', 'cvsup7.tw.freebsd.org', 'cvsup8.tw.freebsd.org',
              'cvsup9.tw.freebsd.org', 'cvsup10.tw.freebsd.org', 'cvsup11.tw.freebsd.org',
              'cvsup12.tw.freebsd.org', 'cvsup13.tw.freebsd.org', 'cvsup14.tw.freebsd.org' );
        $check = time() - 86400;
        $time_format = '%Y/%m/%d %H:%M:%S';
        $latest_src = $latest_ports = 0;
        foreach( $servers as $server ) {
                $data = file_get_contents("$dir/base/$server/last-commit.txt");
                $data = trim($data);
                if( $data != '' ) {
                        $SERVER[$server] = explode(',', $data);
                        if( $SERVER[$server][0] > $latest_src )
                                $latest_src = $SERVER[$server][0];
                        if( $SERVER[$server][1] > $latest_ports )
                                $latest_ports = $SERVER[$server][1];
                }
        }
        foreach( $servers as $server ) {
                if( is_array($SERVER[$server]) ) {
                        list( $src, $ports, $elapsed, $ipaddr, $aliases ) = $SERVER[$server];
                        $ipaddr = str_replace( '|', '<br />', $ipaddr );
                        $aliases = str_replace( '|', '<br />', $aliases );
                        if( $aliases == '' )
                                $aliases = '&nbsp;';
                        print "<tr>\n";
                        print "  <td class=c>$server</td>\n";
                        print "  <td class=c>$ipaddr</td>\n";
                        print "  <td class=c>$aliases</td>\n";
                        if( $src == $latest_src )
                                print "  <td class=green>";
                        elseif( $src < $check )
                                print "  <td class=red>";
                        else
                                print "  <td class=c>";
                        print strftime( $time_format, $src ) . "</td>\n";
                        if( $ports == $latest_ports )
                                print "  <td class=green>";
                        elseif( $ports < $check )
                                print "  <td class=red>";
                        else
                                print "  <td class=c>";
                        print strftime( $time_format, $ports ) . "</td>\n";
#                       print "  <td align=right>$elapsed s</td>\n";
                        print "</tr>\n";
                }
        }
?>
</table>
 Posted by at 23:52

  3 Responses to “Script: 取得 FreeBSD CVSUP 的更新狀態”

  1. […] CVSUP Server 更新狀態,以及更新的時間,也有程式碼的釋出,參考這篇:Script: 取得 FreeBSD CVSUP 的更新狀態,這篇寫的蠻清楚的,只需要 perl 跟 php […]

  2. Hi, nice script but I can’t make it work – It looks like cvslogs are empty or nonexistent. You didn’t provide supfile you use in your script. I guess you specified cvs-all collection inside but maybe it’s not enough?

  3. Hi Marcin, I add a “supfile” in the blog.

歡迎留下您的意見