newnode.in 6.33 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
#!/usr/bin/perl -w

#
# EMULAB-COPYRIGHT
# Copyright (c) 2003 University of Utah and the Flux Group.
# All rights reserved.
#

#
# newnode - a script for moving nodes from the new_ tables into production.
#

13
use lib '@prefix@/lib';
14 15 16 17 18

use libdb;

use strict;

19
my $TB = "@prefix@";
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

my $switchmac = "$TB/sbin/switchmac";
my $sched_reload = "$TB/sbin/sched_reload";
my $nalloc = "$TB/bin/nalloc";
my $nfree = "$TB/bin/nfree";
my $dhcpd_makeconf = "$TB/sbin/dhcpd_makeconf";

my $dhcpd_conf = "/usr/local/etc/dhpcd.conf";
my $dhcpd_template = "/usr/local/etc/dhcpd.conf.template";
my $dhcpd_rc = "/usr/local/etc/rc.d/2.dhcpd.sh";

if (!TBAdmin()) {
    die "Sorry, only testbed administrators can run this script!\n";
}

if (@ARGV < 1) {
    die "Usage: $0 <node_id> ...\n";
}

my @node_ids = @ARGV;

#
# Start this party by getting MAC addresses from the switches
#
print "Getting MAC addresses from the switches (this could take a while!)\n";
open(MAC,"$switchmac |") or die "Unable to fork: $!\n";
my %wires;
47 48
my @lines = ('000000000000,intel1/1.17,1,unknown');
while (my $line = <MAC>) {
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
    chomp $line;
    my ($MAC,$switchport,$vlan,$iface) = split /,/, $line;
    if ($switchport !~ /^([\w-]+)\/(\d+)\.(\d+)$/) {
	die "Bad line from $switchmac: $line\n";
    }
    my ($switch, $card, $port) = ($1,$2,$3);
    $wires{$MAC} = [$switch, $card, $port];
}

#
# Now, loop through the nodes given, and add each one
#
my @succeeded_nodes;
NODE: foreach my $node_id (@node_ids) {
    my $query_result;

    #
    # Check to make sure said node does not already exist!
    #
    $query_result = DBQueryFatal("SELECT node_id FROM nodes WHERE " .
	"node_id='$node_id'");
    if ($query_result->num_rows()) {
	warn "Node $node_id failed: a node with that name already exists!\n";
	next NODE;
    }

    #
    # Grab information about the node from the new_nodes table
    #
78 79
    $query_result = DBQueryFatal("SELECT new_node_id, type, IP " .
	"FROM new_nodes WHERE node_id='$node_id'");
80 81 82 83
    if (!$query_result->num_rows()) {
	warn "Node $node_id failed: No pending node with that name exists!\n";
	next NODE;
    }
84
    my ($new_node_id, $type, $IP) = $query_result->fetchrow();
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101

    #
    # Make sure that the new node is of a valid type, and grab a few other
    # things to fill in as initial values
    #
    $query_result = DBQueryFatal("SELECT control_net FROM node_types " .
	"WHERE type='$type'");
    if (!$query_result->num_rows()) {
	warn "Node $node_id failed: Type $type does not exist!\n";
	next NODE;
    }
    my ($control_net) = $query_result->fetchrow();

    #
    # Grab the node's MACs from the new_interfaces table
    #
    $query_result = DBQueryFatal("SELECT iface, MAC, interface_type " .
102
	"FROM new_interfaces WHERE new_node_id='$new_node_id'");
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
    if (!$query_result->num_rows()) {
	warn "Node $node_id failed: Must have at least one interface!\n";
	next NODE;
    }

    my %interfaces;
    while (my ($iface, $MAC, $iface_type) = $query_result->fetchrow()) {
	#
	# Get some more information about this interface type
	#
	my $iface_query = DBQueryFatal("SELECT max_speed, full_duplex " .
	    "FROM interface_types WHERE type='$iface_type'");
	if (!$iface_query->num_rows()) {
	    warn "Node $node_id failed: Interface $iface is of unknown type " .
	    	"$iface_type";
	    next NODE;
	}

	my ($max_speed, $full_duplex) = $iface_query->fetchrow();

	#
	# Stash it away...
	#
	$interfaces{$iface} = [$MAC, $iface_type, $max_speed, $full_duplex];

	#
	# Check to see if we have wires for all of the interfaces - we can ignore
	# the control net, it's OK if we don't have that one.
	#
	if ($iface eq "eth$control_net") {
	    next NODE;
	}

	if (!$wires{$MAC}) {
	    print "Node $node_id failed: Could not find switch port for ".
		"$MAC ($iface)\n";
	    next NODE;
	}
    }

    #
    # Make up a priority (just used for sorting)
    #
    $node_id =~ /(\d+)$/;
    my $priority;
    if ($1) {
	$priority = $1;
    } else {
	$priority = 1;
    }

    #
    # Okay, time to actually add the node!
    #
    
    DBQueryFatal("INSERT INTO nodes SET node_id='$node_id', type='$type', " .
	"phys_nodeid='$node_id', role='testnode', priority=$priority");

    while (my ($iface, $aref) = each %interfaces) {
	my ($MAC, $iface_type, $speed, $duplex) = @$aref;
	$iface =~ /(\d+)$/;
	my $card = $1;
	my $iface_IP = "";
	my $wire_type = "Node";
	if ($card == $control_net) {
	    $iface_IP = $IP;
	    $wire_type = "Control";
	}
	DBQueryFatal("INSERT INTO interfaces SET node_id='$node_id', " .
	    "card=$card, port=1, mac='$MAC', IP='$iface_IP', " .
	    "interface_type='$iface_type', iface='$iface', " .
	    "current_speed='$speed', duplex=$duplex");

	if ($card != $control_net) {
	    my ($switch, $card2, $port2) = @{$wires{$MAC}};
	    DBQueryFatal("INSERT INTO wires SET type='$wire_type', " .
		"node_id1='$node_id', card1=$card, port1=1, node_id2='$switch', " .
		"card2=$card2, port2=$port2");
	}
    }

    #
    # TODO - Do we need to get the nodes into a good state for the event system?
    #

    #
    # Put the node into hwdown and schedule a reload for it
    #
    system "$nalloc emulab-ops hwdown $node_id";
    system "$sched_reload $node_id";

    #
    # Remove the node from the new_ tables
    #
197 198
    DBQueryFatal("DELETE FROM new_nodes WHERE new_node_id=$new_node_id");
    DBQueryFatal("DELETE FROM new_interfaces WHERE node_id=$new_node_id");
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242

    print "$node_id succesfully added!";

    push @succeeded_nodes, $node_id;
}

#
# No point in restarting dhcpd, etc. if there are no nodes that succeeded
#
if (!@succeeded_nodes) {
    die "No nodes succeeded, exiting early\n";
}

#
# Re-generate dhcpd.conf
#
if (! -f $dhcpd_template) {
    warn "Warning: $dhcpd_template does not exist\n";
    warn "You'll need to re-run dhcpd_makeconf manually, then free the new\n";
    warn "nodes from emulab-ops/hwdown\n";
} else {
    print "Re-generating dhcpd.conf\n";
    open(CONF,"$dhcpd_makeconf $dhcpd_template|") or die "Unable to fork: $!\n";
    my @conf = <CONF>;
    close CONF or die "Error reading from dhcpd_makeconf: $!\n";

    open(CONF,">$dhcpd_conf") or die "Unable to open $dhcpd_conf for writing\n";
    print CONF @conf;
    close CONF;

    print "Restarting dhcpd\n";
    system "$dhcpd_rc stop";
    system "$dhcpd_rc start";

    #
    # Now, free all the nodes we just made from hwdown, so that they can reload
    #
    system "$nfree emulab-ops hwdown " . join(" ",@succeeded_nodes);

}

#
# TODO - add nodes to named?
#