Commit bf6f0f6d authored by Leigh B. Stoller's avatar Leigh B. Stoller

Checkpoint CVS repo support stuff. I have added pserver support stuff,

to generate the cvsd.conf file from a head+tail file, and restart the
server.

A few other steps need to be performed though since we NFS local mount
the project CVS repos into a jail that cvsd is running in. So, the
mount directory has to be changed, and the repo read-only mounted into
the jail. Also setup anoncvs (and anonymous) user entries (no
password), and munge the config file in CVSROOT so that the lockdir
points to someplace in the jail that can be written.
parent 24b8d2d2
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2005 University of Utah and the Flux Group.
# All rights reserved.
#
SRCDIR = @srcdir@
TESTBED_SRCDIR = @top_srcdir@
OBJDIR = ../..
SUBDIR = collab/cvs
include $(OBJDIR)/Makeconf
SBIN_SCRIPTS = cvsrepo_ctrl
LIBEXEC_SCRIPTS = webcvsrepo_ctrl
CTRL_LIBEXEC_SCRIPTS =
CTRL_LIB_FILES = cvsd.conf.head
CTRL_SBIN_SCRIPTS = cvsrepo_ctrl.proxy
#
# Force dependencies on the scripts so that they will be rerun through
# configure if the .in file is changed.
#
all: $(SBIN_SCRIPTS) $(CTRL_SBIN_SCRIPTS) $(CTRL_LIBEXEC_SCRIPTS) \
$(CTRL_LIB_FILES) $(LIBEXEC_SCRIPTS)
include $(TESTBED_SRCDIR)/GNUmakerules
install: $(addprefix $(INSTALL_SBINDIR)/, $(SBIN_SCRIPTS)) \
$(addprefix $(INSTALL_LIBEXECDIR)/, $(LIBEXEC_SCRIPTS)) \
$(addprefix $(INSTALL_DIR)/opsdir/lib/, $(CTRL_LIB_FILES)) \
$(addprefix $(INSTALL_DIR)/opsdir/sbin/, $(CTRL_SBIN_SCRIPTS))
boss-install: install
post-install:
chown root $(INSTALL_SBINDIR)/cvsrepo_ctrl
chmod u+s $(INSTALL_SBINDIR)/cvsrepo_ctrl
#
# Control node installation (okay, plastic)
#
control-install: \
$(addprefix $(INSTALL_SBINDIR)/, $(CTRL_SBIN_SCRIPTS)) \
$(addprefix $(INSTALL_LIBDIR)/, $(CTRL_LIB_FILES))
clean:
rm -f *.o core
$(INSTALL_DIR)/opsdir/sbin/%: %
@echo "Installing $<"
-mkdir -p $(INSTALL_DIR)/opsdir/sbin
$(INSTALL) $< $@
$(INSTALL_DIR)/opsdir/lib/%: %
@echo "Installing $<"
-mkdir -p $(INSTALL_DIR)/opsdir/lib
$(INSTALL_DATA) $< $@
......@@ -83,4 +83,6 @@ Log syslog info
# The path should be relative to the specified
# RootJail and should start with a `/'.
# This option can be supplied multiple times.
Repos /testbed
# Leave this here! cvsd barfs if there are no Repo statements. Ick.
Repos /dummy
......@@ -6,9 +6,12 @@
#
use English;
use Getopt::Std;
use Fcntl ':flock';
#
# Set the cvsrepo permission bits to make a CVS repo public.
# Set the cvsrepo permission bits to make a CVS repo public or private.
# Also regen the cvsd.conf file on ops.
# This script always does the right thing ...
#
sub usage()
{
......@@ -16,16 +19,22 @@ sub usage()
exit(-1);
}
my $optlist = "";
my $dbuid;
#
# Configure variables
#
my $TB = "@prefix@";
my $FSNODE = "@FSNODE@";
my $TBOPS = "@TBOPSEMAIL@";
my $TBAUDIT = "@TBAUDITEMAIL@";
my $PROJROOT = "/proj";
my $CVSREPOS = "$PROJROOT/cvsrepos";
my $TESTMODE = @TESTMODE@;
my $SSH = "$TB/bin/sshtb -l root -host $FSNODE";
my $PROG = "$TB/sbin/cvsrepo_ctrl.proxy";
my $tailfile = "/var/tmp/cvsd.conf.tail";
my $lockfile = "/var/tmp/testbed_cvsrepo_lockfile";
# un-taint path
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin:/usr/site/bin';
......@@ -51,7 +60,10 @@ if ($UID == 0) {
#
# Turn off line buffering on output. Very important for this script!
#
$| = 1;
$| = 1;
# Protos
sub fatal($);
# Load the Testbed support stuff.
use lib "@prefix@/lib";
......@@ -82,14 +94,6 @@ else {
die("*** Tainted project name: $pid\n");
}
#
# Verify user and get his DB uid.
#
if (! UNIX2DBUID($UID, \$dbuid)) {
die("*** $0:\n".
" You do not exist in the Emulab Database.\n");
}
#
# This script is always audited. Mail is sent automatically upon exit.
#
......@@ -101,14 +105,69 @@ if (AuditStart(0)) {
}
#
# Check permission.
#
if (!TBAdmin($UID) &&
!TBMinTrust(TBGrpTrust($dbuid, $pid, $pid), PROJMEMBERTRUST_GROUPROOT)) {
die("*** $0:\n".
" You do not have permission to set cvs permissions for $pid!\n");
# We need to serialize this script to avoid a trashed map file. Use
# a dummy file in /var/tmp, opened for writing and flock'ed.
#
if (!$TESTMODE) {
open(LOCK, ">>$lockfile") || fatal("Couldn't open $lockfile\n");
$count = 0;
if (flock(LOCK, LOCK_EX|LOCK_NB) == 0) {
#
# If we don't get it the first time, we wait for:
# 1) The lock to become free, in which case we do our thing
# 2) The time on the lock to change, in which case we wait for that process
# to finish
#
my $oldlocktime = (stat(LOCK))[9];
my $gotlock = 0;
while (1) {
print "Another cvsrepo update in progress, ".
"waiting for it to finish\n";
if (flock(LOCK, LOCK_EX|LOCK_NB) != 0) {
# OK, got the lock, we can do what we're supposed to
$gotlock = 1;
last;
}
$locktime = (stat(LOCK))[9];
if ($locktime != $oldlocktime) {
$oldlocktime = $locktime;
last;
}
if ($count++ > 20) {
fatal("Could not get the lock after a long time!\n");
}
sleep(1);
}
$count = 0;
#
# If we didn't get the lock, wait for the processes that did to finish
#
if (!$gotlock) {
while (1) {
if ((stat(LOCK))[9] != $oldlocktime) {
exit(0);
}
if (flock(LOCK, LOCK_EX|LOCK_NB) != 0) {
close(LOCK);
exit(0);
}
if ($count++ > 20) {
fatal("Process with the lock didn't finish after a long time!\n");
}
sleep(1);
}
}
}
}
#
# Perl-style touch(1)
#
my $now = time;
utime $now, $now, $lockfile;
#
# Grab DB data.
#
......@@ -127,4 +186,40 @@ if (! chmod($prot, "$CVSREPOS/$pid")) {
die("*** $0:\n".
" Could not chmod($prot) directory $CVSREPOS/$pid: $!");
}
#
# Okay, generate the public dir list and ship it over.
#
$query_result =
DBQueryFatal("select pid from projects where cvsrepo_public=1");
open(CONF, ">$tailfile") ||
fatal("Could not open $tailfile!");
while (my ($pid) = $query_result->fetchrow_array()) {
print CONF "$pid\n";
}
close(CONF);
#
# Fire the new tail file over to the fileserver to finish. We cat the file
# right into it.
#
if (!$TESTMODE) {
$UID = 0;
system("$SSH $PROG < $tailfile") == 0 or
fatal("Failed: $SSH $PROG < $tailfile: $?");
unlink("$tailfile");
close(LOCK);
}
exit(0);
sub fatal($) {
my ($msg) = @_;
SENDMAIL($TBOPS, "CVSD Setup Failed", $msg);
die($msg);
}
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2005 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
use Errno;
use Fcntl ':flock';
use Getopt::Std;
#
# Install new cvsd.conf file ...
#
sub usage()
{
print(STDOUT "Usage: cvsrepo_ctrl.proxy\n");
exit(-1);
}
my $optlist = "";
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $CVSDCONF = "/usr/local/etc/cvsd/cvsd.conf";
my $CVSDCONFNEW = "/usr/local/etc/cvsd/cvsd.conf.new";
my $CVSDCONFOLD = "/usr/local/etc/cvsd/cvsd.conf.backup";
my $HEADFILE = "$TB/lib/cvsd.conf.head";
my $STARTPROG = "/usr/local/etc/rc.d/cvsd.sh";
my $REPODIR = "cvsrepos";
my $PROJREPODIR = "/proj/$REPODIR";
my $JAILREPODIR = "/var/cvsjail/$REPODIR";
my $MOUNT = "/sbin/mount -o ro";
my $UNMOUNT = "/sbin/umount";
my %pubrepos = ();
#
# We don't want to run this script unless its the real version.
#
if ($UID != 0) {
die("Must be root!");
}
# un-taint path
$ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
# Turn off line buffering on output
$| = 1;
# Protos
sub fatal($);
#
# Testbed Support libraries
#
use lib "@prefix@/lib";
use libtestbed;
#
# Take our input and get the list of repos we need to make public.
#
while (<STDIN>) {
if ($_ =~ /^([^\s]*)$/) {
$pubrepos{$1} = $1;
}
}
#
# Generate a warning so that no one tries to edit the file by hand
#
open(CONF, ">$CVSDCONFNEW") ||
fatal("Could not open $CVSDCONFNEW!");
print CONF
"#\n".
"# ******************************************************************\n".
"# DO NOT EDIT THIS FILE. IT IS A CREATION, A FIGMENT, A CONTRIVANCE!\n".
"# ******************************************************************\n".
"#\n";
close(CONF);
chmod(0644, $CVSDCONFNEW);
#
# Now tack on the head part of the file.
#
system("cat $HEADFILE >> $CVSDCONFNEW") == 0 or
fatal("Failed to concat $HEADFILE to $CVSDCONFNEW\n");
#
# Now the tail of the file.
#
open(CONF, ">>$CVSDCONFNEW") ||
fatal("Could not open $CVSDCONFNEW for appending!");
print CONF "\n";
print CONF "#\n";
print CONF "# DO NOT EDIT below this point. Auto generated entries!\n";
print CONF "#\n";
foreach my $repo (keys(%pubrepos)) {
print CONF "Repos /$REPODIR/$repo\n";
}
close(CONF);
#
# Back up the existing config, and then mv in the new one.
#
system("cp $CVSDCONF $CVSDCONFOLD") == 0 or
fatal("Could not back up $CVSDCONF to $CVSDCONFOLD");
system("mv $CVSDCONFNEW $CVSDCONF") == 0 or
fatal("Could not mv $CVSDCONFNEW to $CVSDCONF");
# Avoid accidental editing.
chmod(0444, $CVSDCONF);
#
# Must stop cvsd before doing the next step.
#
system("$STARTPROG stop") == 0 or
fatal("Could not stop cvsd!");
#
# Okay, now do the mounts and unmounts into the jail tree. Each pub
# repo gets a mount and each repo that is no longer pub, gets an unmount.
#
# First see whats already there. The only record I keep is the list of
# subdirs that exist already.
#
opendir(DIR, $JAILREPODIR) or
fatal("Could not opdendir $JAILREPODIR: $!");
my @dirfiles = readdir(DIR);
closedir(DIR);
#
# Get rid of ones that are no longer supposed to be public.
#
foreach my $dir (@dirfiles) {
next
if ($dir eq "." || $dir eq "..");
#
# Any directory that is not in the list we got from boss, needs
# an unmount and rmdir; it is no longer public.
#
if (! exists($pubrepos{$dir})) {
system("$UNMOUNT $JAILREPODIR/$dir") == 0 or
fatal("Could not unmount $JAILREPODIR/$dir");
system("/bin/rmdir $JAILREPODIR/$dir") == 0 or
fatal("Could not rmdir $JAILREPODIR/$dir");
}
else {
#
# Already there, so delete from the list of ones we need to add.
#
delete($pubrepos{$dir});
}
}
#
# Now add any new ones.
#
foreach my $repo (keys(%pubrepos)) {
my $dir = $repo;
system("/bin/mkdir $JAILREPODIR/$dir") == 0 or
fatal("Could not mkdir $JAILREPODIR/$dir");
#
# Now mount it; if it fails then remove the directory too so as
# not to mess up the next time it runs.
#
system("$MOUNT localhost:${PROJREPODIR}/$dir $JAILREPODIR/$dir");
if ($?) {
system("/bin/rm -r $JAILREPODIR/$dir");
fatal("Could not NFS mount localhost:${PROJREPODIR}/$dir");
}
#
# Setup an anoncvs password entry for the directory.
#
system("/bin/echo 'anoncvs::nobody' > ".
"$PROJREPODIR/$dir/CVSROOT/passwd") == 0 or
fatal("Could not create $PROJREPODIR/$dir/CVSROOT/passwd!");
system("/bin/echo 'anonymous::nobody' >> ".
"$PROJREPODIR/$dir/CVSROOT/passwd") == 0 or
fatal("Could not create $PROJREPODIR/$dir/CVSROOT/passwd!");
#
# And now generate a config file that makes pserver happy. Just
# blow away the existing one; it should not matter.
#
system("/bin/rm -f $PROJREPODIR/$dir/CVSROOT/config ".
" $PROJREPODIR/$dir/CVSROOT/config,v") == 0 or
fatal("Could not rm $PROJREPODIR/$dir/CVSROOT/config!");
open(CONF, "> $PROJREPODIR/$dir/CVSROOT/config") or
fatal("Could not open $PROJREPODIR/$dir/CVSROOT/config!");
print CONF "SystemAuth=no\n";
print CONF "LockDir=/var/cvslock\n";
close(CONF);
}
#
# Okay, restart the cvsd process. Too bad there is no HUP handler to reload
# the config file, as this is going to kill anyone currently connected.
#
system("$STARTPROG start") == 0 or
fatal("Could not restart cvsd!");
exit(0);
sub fatal($) {
my ($msg) = @_;
die("*** $0:\n".
" $msg\n");
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment