Commit 4ae8610e authored by Leigh B. Stoller's avatar Leigh B. Stoller
Browse files

Lots of work. Taint check errors fixed. Add DB checks to make sure caller

has permission to mess with the nodes specified. Some general cleanup.
Redo the freebsd approach completely. Instead of copying over the current
rc.conf.local and munging it, I build them up locally and just overwrite
what is on the node. This cuts down on the number of ssh/scp commands that
get invoked (which appear to cause all kinds of problems). Its also more
rebust than trying to devine whats in that file. In fact, we should change
/etc/rc.conf to load, say, /etc/rc.conf.tbifc so avoid any clashes with
local stuff that might/will exist in that file.
parent 63eabd05
#!/usr/bin/perl -w
#!/usr/bin/perl -wT
use English;
my $rsh = "ssh";
my $rcp = "scp";
my $rsh = "sshtb -q";
my $rcp = "scptb -q";
my $ping = "/sbin/ping";
my $SAVEUID = $UID;
my $dbg = 1;
my %seen = ();
#
# Untaint path
#
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
$| = 1; #Turn off line buffering on output
if ( $#ARGV < 0) {
die("Usage: ifc_setup <ifc_file>\n".
#
# Set up for querying the database.
#
use Mysql;
my $DB = Mysql->connect("localhost", "tbdb", "script", "none");
#
# Check arguments.
#
if ( $#ARGV != 2) {
die("Usage: ifc_setup <pid> <eid> <ifc_file>\n".
"Sets network interface configurations, both with ifconfig, and\n".
"in the boot configuration files.\n");
}
open(WHO,"/usr/bin/whoami 2>&1 |");
$_ = <WHO>;
chop;
if ($_ ne "root") { die("This won't work unless you're root.\n"); }
close(WHO);
if (-e "$ARGV[0]" ) {
open(IN,$ARGV[0]) || die("Couldn't open $ARGV[0]\n");
} elsif (-e "/usr/testbed/etc/$ARGV[0]") {
open(IN,"/usr/testbed/etc/$ARGV[0]") ||
die("Couldn't open /usr/testbed/etc/$ARGV[0]\n");
} else {
die ("Couldn't locate $ARGV[0]\n");
my $pid = $ARGV[0];
my $eid = $ARGV[1];
my $ifc = $ARGV[2];
#
# Figure out who called us. Only root, people with admin status
# in the DB, or the owner of the experiment can run this script.
#
if ($UID != 0) {
my ($me) = getpwuid($UID)
or die "$UID not in passwd file";
$db_result = $DB->query("select expt_head_uid from experiments ".
"where eid='$eid' and pid='$pid'");
if ($db_result->numrows < 1) {
die("There is no experiment '$eid' in project '$pid'.\n");
}
my @row = $db_result->fetchrow_array();
if ($row[0] ne "$me") {
print STDOUT "Checking for admin status ...\n" if $dbg;
$db_result = $DB->query("select admin from users where uid='$me'");
my @row = $db_result->fetchrow_array();
if ($row[0] != 1) {
die("mkprojdir: You must be root or a TB administrator\n");
}
}
}
#
# Need to be real root, not effective root.
#
$UID = 0;
#
# Open up the ifc file. Should we allow it to come on on stdin?
#
if (-e "$ifc") {
open(IN, $ifc) || die("Couldn't open $ifc\n");
}
else {
die("Couldn't open $ifc\n");
}
my $last = "";
my $OS = "Unknown";
my $IP = "";
my $IF = 0;
my $ifstr = "";
my $newIP = "";
my $node = "";
print "Reading input file...\n";
while (<IN>) {
chop;
......@@ -39,123 +89,146 @@ while (<IN>) {
if ($_ eq "") {next;}
#print "Got $_\n";
($IP,$IF,$newIP)= split(" ",$_);
#
# Untaint. Sheer idiocy.
#
if ($IP =~ /^([-\@\w.]+)$/) {
$IP = $1;
}
if ($IF =~ /^([-\@\w.]+)$/) {
$IF = $1;
}
if ($newIP =~ /^([-\@\w.]+)$/) {
$newIP = $1;
}
#print "Config $IP, interface $IF, to IP $newIP\n";
#if its not the same as the last one, get the OS
# if its not the same as the last one, do a few things.
if ( $IP ne $last ) {
$last = $IP;
print "Pinging $IP...";
if (-e "/bin/ping") {
open(PING,"/bin/ping -c 1 $IP 2>&1 |");
} else {
open(PING,"/sbin/ping -c 1 $IP 2>&1 |");
}
do { } until ( <PING> =~ /transmitted, (\d*) packets received/ );
print "Got $1 ping packet(s) back from $IP.\n";
if ( $1 > 0 ) {
open(UNAME,"$rsh $IP uname -a 2>&1 |");
$last = $IP;
$OS = "Unknown";
#
# Verify that the node is actually in the experiment. This requires
# knowing what node it is. Perhaps the file format should be changed.
# For now must ask the DB.
#
$db_result = $DB->query("select node_id from interfaces where IP='$IP'");
if ($db_result->numrows < 1) {
die("There is no node with IP='$IP'");
}
my @row = $db_result->fetchrow_array();
$node = $row[0];
$db_result = $DB->query("select node_id from reserved where ".
"node_id='$node' and pid='$pid' and eid='$eid'");
if ($db_result->numrows < 1) {
die("Node $node is not in project/experiment $pid/$eid");
}
#
# Make sure the node is alive before doing anything else.
#
# Untaint the argument. Sheer idiocy.
#
if ($node =~ /^([-\@\w.]+)$/) {
$node = $1;
}
print STDERR "Pinging $node ... \n" if $dbg;
if (-e $ping) {
open(PING, "$ping -c 4 $node 2>&1 |");
}
else {
die("PING command $ping not found!\n");
}
do {
} until ( <PING> =~ /transmitted, (\d*) packets received/ );
close(PING);
print STDERR "Got back $1 ping packets from $node.\n" if $dbg;
if ( $1 == 0 ) {
print STDERR "$node appears to be unresponsive. Skipping ...\n";
next;
}
#
# We rsh over to get the OS type. Should we ask the DB instead?
#
open(UNAME, "$rsh $node uname -a 2>&1 |");
$_ = <UNAME>;
#print $_;
if ($_ ) { @temp = split(" ",$_); $OS = $temp[0]; }
} else {
print STDERR "Can't reach $IP with ping. Skipping interface $IF.\n";
$OS = "_NO_PING_";
next;
}
print "OS for $IP is $OS \t";
if ($OS eq "Linux") { $ifstr="eth"; }
elsif ($OS eq "FreeBSD") { $ifstr="fxp"; }
else { $ifstr = ""; }
if ($ifstr) { print "Using interface string '$ifstr'\n"; }
} else {
if ($OS eq "_NO_PING_") {
print STDERR "Can't reach $IP with ping. Skipping interface $IF.\n";
close(UNAME);
if ( $_ ) {
@temp = split(" ",$_);
$OS = $temp[0];
}
sleep(2);
print STDERR "$node appears to be running $OS.\n" if $dbg;
}
if ($OS eq "Unknown") {
print STDERR "Cannot configure $node because OS is Unknown. Skipping.\n";
next;
}
}
#Set up the interface
if ( $ifstr eq "" ) {
print STDERR "Can't configure OS '$OS' on $IP. Skipping interface $IF.\n";
next;
} elsif ( $OS eq "Linux" ) {
@_ = split(/\./,$newIP);
my $network = join(".",@_[0..2]);
print "Setting $IP $ifstr$IF to $newIP in boot configurations...\n";
open(TEMP,">/tmp/ifc_boot_file");
print TEMP "DEVICE=$ifstr$IF\nIPADDR=$newIP\nNETMASK=255.255.255.0\n".
"NETWORK=$network.0\nBROADCAST=$network.255\nONBOOT=yes\n".
"BOOTPROTO=bootp\nUSERCTL=no\n";
close(TEMP);
open(IFC, "$rcp /tmp/ifc_boot_file ".
"$IP:/etc/sysconfig/network-scripts/ifcfg-$ifstr$IF 2>&1 |");
if ( $OS eq "Linux" ) {
@_ = split(/\./,$newIP);
my $network = join(".",@_[0..2]);
my $confname = "ifc-$node";
$ifstr = "eth";
print "Setting $IP $ifstr$IF to $newIP in boot configurations...\n";
open(TEMP,">$confname");
print TEMP "DEVICE=$ifstr$IF\nIPADDR=$newIP\nNETMASK=255.255.255.0\n".
"NETWORK=$network.0\nBROADCAST=$network.255\nONBOOT=yes\n".
"USERCTL=no\n";
close(TEMP);
if (system("$rcp $confname ".
"$node:/etc/sysconfig/network-scripts/ifcfg-$ifstr$IF")) {
print STDERR "Error copying network config for $ifstr$IF to $node\n";
}
} elsif ($OS eq "FreeBSD") {
my $exists = 0;
print "Setting $IP $ifstr$IF to $newIP in boot configurations...\n";
# Wait a second - Quick hack fix...
sleep(1);
#
open(EXISTS, "$rsh $IP ls /etc/rc.conf.local 2>&1 |");
while ( <EXISTS> ) { if ( ! /No such file/ ) { $exists = 1; } }
close(EXISTS);
open(TEMP,">/tmp/ifc_boot_file");
if ($exists) {
# Wait a second - Quick hack fix...
sleep(1);
my $confname = "ifc-$node";
my $exists = 0;
$ifstr = "fxp";
print "Setting $IP $ifstr$IF to $newIP in boot configurations...\n";
#
# I am not going to copy the existing file over from the node.
# Just build it up locally and overwrite whats on the node.
#
open(COPY, "$rcp $IP:/etc/rc.conf.local /etc/ifc_boot_input 2>&1 |");
while ( <COPY> ) { print "COPY>> $_"; }
close(COPY);
open(CONF,"/etc/ifc_boot_input");
while ( <CONF> ) {
# print "CONF>>$_";
if ( ! /ifconfig_fxp$IF=/ ) {
if ( /network_interfaces\s*=\s*\"([A-Za-z0-9_ ]*)\"/ ) {
$_ = $1;
s/\s+/ /g;
s/^\s+//g;
s/\s+$//g;
my @ifcs = split(" ",$_);
print TEMP "network_interfaces=\"";
foreach my $ifc (@ifcs) {
if ($ifc ne "fxp$IF") { print TEMP "$ifc "; }
}
print TEMP "fxp$IF\"\n";
} else {
print TEMP $_;
}
# print "KEPT\n";
}
if ($seen{$node}) {
open(CONF,">>$confname");
}
else {
$seen{$node} = 1;
open(CONF,">$confname");
}
print CONF "network_interfaces=\"\$network_interfaces fxp$IF\"\n";
print CONF "ifconfig_fxp$IF=\"inet $newIP netmask 255.255.255.0\"\n";
close(CONF);
} else { print TEMP "network_interfaces=\"fxp$IF lo0\"\n"; }
print TEMP "ifconfig_fxp$IF=\"inet $newIP netmask 255.255.255.0\"\n";
close(TEMP);
# Wait a second - Quick hack fix...
sleep(1);
#
open(IFC,"$rcp /tmp/ifc_boot_file $IP:/etc/rc.conf.local 2>&1 |");
# Wait a second - Quick hack fix...
sleep(2);
#
if (system("$rcp $confname $node:/etc/rc.conf.local")) {
print STDERR "Error copying network config for $ifstr$IF to $node\n";
}
} else {
print STDERR "Can't configure OS '$OS' on $IP. Skipping interface $IF.\n";
next;
}
while ( <IFC> ) {
print ">> $_";
print STDERR "Can't configure OS '$OS' on $IP. Skipping $IF.\n";
next;
}
close(IFC);
print "Setting $IP $ifstr$IF to $newIP with ifconfig...\n";
$ifcmd = "$rsh $node /sbin/ifconfig $ifstr$IF inet $newIP ".
"netmask 255.255.255.0";
print "Doing remote $ifcmd\n";
# Wait a second - Quick hack fix...
sleep(1);
sleep(2);
#
open(IFC,
"$rsh $IP /sbin/ifconfig $ifstr$IF inet $newIP ".
"netmask 255.255.255.0 2>&1 |"
);
while ( <IFC> ) {
print ">> $_";
if (system("$ifcmd")) {
print STDERR "Error running ifconfig on $IP for $IF\n";
}
close(IFC);
}
close(IN);
......
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