newnode.in 6.16 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

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";

31 32 33 34 35 36 37 38
my $sudo = "/usr/local/bin/sudo";

#
# Initial event system state to put the nodes into
#
my $INITIAL_STATE = "SHUTDOWN";
my $INITIAL_OPMODE = "MINIMAL";

39 40 41 42 43 44 45 46
if (!TBAdmin()) {
    die "Sorry, only testbed administrators can run this script!\n";
}

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

47 48 49 50 51 52 53
#
# The user has to be able to run sudo, so they can restart dhcpd.
#
if (system "$sudo -s /bin/pwd < /dev/null") {
    die "You must be able to sudo to root to use this script\n";
}

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
my @node_ids = @ARGV;

#
# 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
    #
76 77
    $query_result = DBQueryFatal("SELECT new_node_id, type, IP " .
	"FROM new_nodes WHERE node_id='$node_id'");
78 79 80 81
    if (!$query_result->num_rows()) {
	warn "Node $node_id failed: No pending node with that name exists!\n";
	next NODE;
    }
82
    my ($new_node_id, $type, $IP) = $query_result->fetchrow();
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98

    #
    # 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
    #
99
    $query_result = DBQueryFatal("SELECT card, MAC, interface_type, " .
100
	"switch_id, switch_card, switch_port " .
101
	"FROM new_interfaces WHERE new_node_id='$new_node_id'");
102 103 104 105 106 107
    if (!$query_result->num_rows()) {
	warn "Node $node_id failed: Must have at least one interface!\n";
	next NODE;
    }

    my %interfaces;
108
    while (my ($card, $MAC, $iface_type, $switch_id, $switch_card,
109
	    $switch_port) = $query_result->fetchrow()) {
110 111 112 113 114 115
	#
	# 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()) {
116
	    warn "Node $node_id failed: Interface $card is of unknown type " .
117 118 119 120 121 122 123 124 125
	    	"$iface_type";
	    next NODE;
	}

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

	#
	# Stash it away...
	#
126
	$interfaces{$card} = [$MAC, $iface_type, $max_speed, $full_duplex,
127
		$switch_id, $switch_card, $switch_port];
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146

    }

    #
    # 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', " .
147 148
	"phys_nodeid='$node_id', role='testnode', priority=$priority" .
    	"eventstate='$INITIAL_STATE', op_mode='$INITIAL_OPMODE'");
149

150
    while (my ($card, $aref) = each %interfaces) {
151 152
	my ($MAC, $iface_type, $speed, $duplex, $switch_id, $switch_card,
	    $switch_port) = @$aref;
153
	my $iface = "eth$card";
154 155 156 157 158 159 160 161 162 163 164
	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");

165 166 167 168
	DBQueryFatal("INSERT INTO wires SET type='$wire_type', " .
	    "node_id1='$node_id', card1=$card, port1=1, " .
	    "node_id2='$switch_id', card2='$switch_card', " .
	    "port2='$switch_port'");
169 170 171 172 173 174 175
    }

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

    #
176
    # Schedule a reload for it
177 178 179 180 181 182 183
    #
    system "$nalloc emulab-ops hwdown $node_id";
    system "$sched_reload $node_id";

    #
    # Remove the node from the new_ tables
    #
184
    DBQueryFatal("DELETE FROM new_nodes WHERE new_node_id=$new_node_id");
185
    DBQueryFatal("DELETE FROM new_interfaces WHERE new_node_id=$new_node_id");
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203

    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";
204 205
    warn "You'll need to re-run dhcpd_makeconf manually, free the new\n";
    warn "nodes from emulab-ops/hwdown, then reboot them.\n";
206 207 208 209 210 211 212 213 214 215
} 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;

216 217 218 219 220
    if ($> == 0) {
	print "Restarting dhcpd\n";
	system "$sudo $dhcpd_rc stop";
	sleep 2;
	system "$sudo $dhcpd_rc start";
221

222 223 224 225 226 227 228 229
	#
	# Now, free all the nodes we just made from hwdown, so that they can reload
	#
	system "$nfree emulab-ops hwdown " . join(" ",@succeeded_nodes);
    } else {
	warn "Warning: You will need to restart dhcpd, free the nodes\n";
	warn "from emulab-ops/hwdown, then reboot them.\n";
    }
230 231 232 233

}

#
234 235 236 237
# TODO -
#    add nodes to named?
#    disable interfaces
#    console setup
238
#