#!/usr/bin/perl -w # Copyright (C) 2000 by Sam Hartman # This file may be copied either under the terms of the GNU GPL or the IBM # Public License either version 2 or later of the GPL or version 1.0 or later # of the IPL. use Term::ReadLine; use strict; use Debian::OpenAFS::ConfigUtils; use Getopt::Long; use Socket qw(inet_ntoa); use vars qw($admin $server $requirements_met $shutdown_needed); my $rl = new Term::ReadLine('afs-newcell'); # The default file server options are poor. Until they've been updated, use # the following from Harald Barth; it should be an improvement for most # people. my $fs_options = '-p 23 -busyat 600 -rxpck 400 -s 1200 -l 1200 -cb 65535' . ' -b 240 -vc 1200'; =head1 NAME afs-newcell - Set up initial database server for AFS cell =head1 SYNOPSIS B [B<--requirements-met>] [B<--admin> admin_user] =head1 DESCRIPTION This script sets up the initial AFS database and configures the first database/file server. The B<--requirements-met> option specifies that the initial requirements have been met and that the script can proceed without displaying the initial banner or asking for confirmation. The B<--admin> option specifies the name of the administrative user. This user will be given system:administrators and susers permission in the cell. =head1 AUTHOR Sam Hartman =cut # Flush all output immediately. $| = 1; GetOptions ("requirements-met" => \$requirements_met, "admin=s" => \$admin); unless ($requirements_met) { print <readline("Do you meet these requirements? [y/n] "); unless (/^y/i ) { print "Run this script again when you meet the requirements\n"; exit(1); } if ($> != 0) { die "This script should almost always be run as root. Use the\n" . "--requirements-met option to run as non-root.\n"; } } # Make sure the AFS client is not already running. open(MOUNT, "mount |") or die "Failed to run mount: $!\n"; while() { if (m:^AFS:) { print "The AFS client is currently running on this workstation.\n"; print "Please restart this script after running" . " service openafs-client stop\n"; exit(1); } } close MOUNT; # Make sure there is a keyfile. unless ( -f "/etc/openafs/server/KeyFile") { print "You do not have an AFS keyfile. Please create this using\n"; print "asetkey from openafs-krb5 or the bos addkey command\n"; exit(1); } # Stop the file server. print "If the fileserver is not running, this may hang for 30 seconds.\n"; run("service openafs-fileserver stop"); # Get the local hostname. Use the fully-qualified hostname to be safer. $server = `hostname -f`; chomp $server; my $ip = gethostbyname $server; if (inet_ntoa($ip) eq '127.0.0.1') { print "\n"; print "Your hostname $server resolves to 127.0.0.1, which AFS cannot\n"; print "cope with. Make sure your hostname resolves to a non-loopback\n"; print "IP address. (Check /etc/hosts and make sure that your hostname\n"; print "isn't listed on the 127.0.0.1 line. If it is, removing it from\n"; print "that line will probably solve this problem.)\n"; exit(1); } # Determine the admin principal. $admin = $rl->readline("What administrative principal should be used? ") unless $admin; print "\n"; die "Please specify an administrative user\n" unless $admin; my $afs_admin = $admin; $afs_admin =~ s:/:.:g; if ($afs_admin =~ /@/) { die "The administrative user must be in the same realm as the cell and\n" . "no realm may be specified.\n"; } # Determine the local cell. This should be configured via debconf, from the # openafs-client configuration, when openafs-fileserver is installed. open(CELL, "/etc/openafs/server/ThisCell") or die "Cannot open /etc/openafs/server/ThisCell: $!\n"; my $cell = ; chomp $cell; # Make sure the new cell is configured in the client CellServDB. open(CELLSERVDB, "/etc/openafs/CellServDB") or die "Cannot open /etc/openafs/CellServDB: $!\n"; my $found = 0; while () { next unless /^>\Q$cell\E\s/; while () { last if /^>/; my ($dbserver) = split ' '; if ($dbserver eq inet_ntoa($ip)) { $found = 1; last; } } last; } unless ($found) { print "\n"; print "The new cell $cell is not configured in /etc/openafs/CellServDB\n"; print "Add configuration like:\n\n"; print ">$cell\n"; print inet_ntoa($ip), "\t\t\t#$server\n\n"; print "to that file before continuing.\n"; exit(1); } # Write out a new CellServDB for the local cell containing only this server. if (-f "/etc/openafs/server/CellServDB") { print "/etc/openafs/server/CellServDB already exists, renaming to .old\n"; rename("/etc/openafs/server/CellServDB", "/etc/openafs/server/CellServDB.old") or die "Cannot rename /etc/openafs/server/CellServDB: $!\n"; } open(CELLSERVDB, "> /etc/openafs/server/CellServDB") or die "Cannot create /etc/openafs/server/CellServDB: $!\n"; print CELLSERVDB ">$cell\n"; print CELLSERVDB inet_ntoa($ip), "\t\t\t#$server\n"; close CELLSERVDB or die "Cannot write to /etc/openafs/server/CellServDB: $!\n"; # Now, we should be able to start bos and add the admin user. run("service openafs-fileserver start"); $shutdown_needed = 1; run("bos adduser $server $afs_admin -localauth"); unwind("bos removeuser $server $afs_admin -localauth"); # Create the initial protection database using pt_util. This is safer than # the standard mechanism of starting the cell in noauth mode until the first # user has been created. if (-f "/var/lib/openafs/db/prdb.DB0") { warn "ERROR: Protection database already exists; cell already partially\n"; warn "ERROR: created. If you do not want the current database, remove\n"; warn "ERROR: all files in /var/lib/openafs/db and then run this program\n"; warn "ERROR: again.\n"; exit(1); } print "\nCreating initial protection database. This will print some errors\n"; print "about an id already existing and a bad ubik magic. These errors can\n"; print "be safely ignored.\n\n"; open(PRDB, "| pt_util -p /var/lib/openafs/db/prdb.DB0 -w") or die "Unable to start pt_util: $!\n"; print PRDB "$afs_admin 128/20 1 -204 -204\n"; print PRDB "system:administrators 130/20 -204 -204 -204\n"; print PRDB " $afs_admin 1\n"; close PRDB; unwind("rm /var/lib/openafs/db/prdb*"); print "\n"; # We should now be able to start ptserver and vlserver. run("bos create $server ptserver simple /usr/lib/openafs/ptserver -localauth"); unwind("bos delete $server ptserver -localauth"); run("bos create $server vlserver simple /usr/lib/openafs/vlserver -localauth"); unwind("bos delete $server vlserver -localauth"); # Create a file server as well. run("bos create $server dafs dafs" . " -cmd '/usr/lib/openafs/dafileserver $fs_options'" . " -cmd /usr/lib/openafs/davolserver" . " -cmd /usr/lib/openafs/salvageserver" . " -cmd /usr/lib/openafs/dasalvager -localauth"); unwind("bos delete $server dafs -localauth"); # Make sure that there is no scheduled general restart time; it's not needed. run("bos setrestart $server -time never -general -localauth"); # Pause for a while for ubik to catch up. print "Waiting for database elections: "; sleep(30); print "done.\n"; # Past this point we want to control when bos shutdown happens. $shutdown_needed = 0; unwind("bos shutdown $server -localauth -wait"); run("vos create $server a root.afs -localauth"); unwind("vos remove $server a root.afs -localauth"); # We should now be able to bring up the client (it may need root.afs to exist # if not using dynroot). We override whatever default cell was configured for # the client, just in case it was pointing to some other cell. open(THIS, "> /etc/openafs/ThisCell") or die "ERROR: Cannot create /etc/openafs/ThisCell: $!\n"; print THIS "$cell\n"; close THIS or die "ERROR: Cannot write to /etc/openafs/ThisCell: $!\n"; run("service openafs-client force-start"); # Verify that AFS has managed to start. my $afs_running = 0; open(MOUNT, "mount |") or die "ERROR: Failed to run mount: $!\n"; while() { if (m:^AFS:) { $afs_running = 1; } } unless ($afs_running) { print "ERROR: The AFS client failed to start.\n"; print "ERROR: Please fix whatever problem kept it from running.\n"; exit(1); } print "\n"; print "Now, get tokens as $admin in the $cell cell.\n"; print "Then, run afs-rootvol.\n"; # Success, so clear the unwind commands. @unwinds = (); # If we fail before all the instances are created, we need to back out of # everything we did as much as possible. END { if ($shutdown_needed || @unwinds) { print "\nCell setup failed, ABORTING\n"; } system("bos shutdown $server -localauth -wait") if $shutdown_needed; run(pop @unwinds) while @unwinds; }