Commit 85b81867 authored by Leigh Stoller's avatar Leigh Stoller

Bunch of changes for "management" interfaces (ilo,drac,etc); make

management interfaces more of a first class citizen instead of a
hack. New script:

management_iface -t <type> -a [key|pswd] [-s <switchinfo>]
                        <node_id> mac IP arg1 arg2
management_iface -r <node_id>
  -h       This message
  -t type  Management type; ilo, ilo2, drac
  -s info  Optional switch info; switch,card,port
  -s -     Search output of switchmac to find switch info
  -a pswd  Password auth; provide login and password.
  -a key   SSH key auth; provide login and key path.
  -r       Remove management interface from DB.

which adds the management interface to the database (interfaces,
outlets and outlets_remoteauth. Optionally adds the wires table
entry if you add -s option. Uses switchmac to find the switch info or
you can specify it on the command line. So for example, here is what I
did to add the ilo2 interface for a node:

management_iface -t ilo2 -a pswd -s - pc1 e8:39:35:ae:c9:7c \
                 155.98.34.100 elabman mypasswd
or
management_iface -t ilo2 -a key -s - pc1 e8:39:35:ae:c9:7c \
                 155.98.34.100 elabman /root/.ssh/somekey

Of course someone had to have added the elabman user and key or
password to the ilo config via its interface. 

* dhcpd_makeconf will add local node management interfaces to the
  config file. We can set them to dhcp instead of hardwiring the IP in
  the management interface.

* The DB changes add a management type to the enums in the interfaces
  and wires table, and updates the existing interface entries.
parent 172abd53
......@@ -60,8 +60,10 @@ my $GPXELINUXPREFIX = "$PXEBOOTDIR/gpxelinux";
my $GPXELINUXBOOT = "gpxelinux.0";
my $CRTLTAG = TBDB_IFACEROLE_CONTROL();
my $MNGMNTTAG = TBDB_IFACEROLE_MANAGEMENT();
my $DHCPD_CONF = "/usr/local/etc/dhcpd.conf";
my $DHCPD_TEMPLATE = "/usr/local/etc/dhcpd.conf.template";
my $DHCPD_TAIL = "/usr/local/etc/dhcpd.conf.tail";
my %servernodes = ();
my %dhcp_subbosses = ();
my %tftp_subbosses = ();
......@@ -222,7 +224,7 @@ while (<IF>) {
" n.pxe_boot_path,n.next_pxe_boot_path,".
" i.IP,i.MAC,r.pid,r.eid,r.vname, ".
" r.inner_elab_role,r.inner_elab_boot, ".
" r.plab_role,r.plab_boot ".
" r.plab_role,r.plab_boot,i.role ".
"from nodes as n ".
"left join interfaces as i on ".
" n.node_id=i.node_id ".
......@@ -231,7 +233,9 @@ while (<IF>) {
" n.node_id=r.node_id ".
"where (n.type='$nodetype' or ".
" t.class='$nodetype') and ".
" i.role='$CRTLTAG' ".
" (i.role='$CRTLTAG' or ".
" (i.role='$MNGMNTTAG' and ".
" t.isremotenode=0)) ".
"order BY n.priority");
if (! $query_result) {
fatal("Could not dhcpd data from DB!");
......@@ -240,6 +244,7 @@ while (<IF>) {
while (my %row = $query_result->fetchhash()) {
my $ip = $row{"IP"};
my $mac = $row{"MAC"};
my $role = $row{"role"};
my $node_id;
my $next_server = "";
my $bootinfo_server = "";
......@@ -248,6 +253,10 @@ while (<IF>) {
my $booting = "";
my $filename = "";
# Management ports, nothing special to do.
goto spit
if ($role eq TBDB_IFACEROLE_MANAGEMENT());
if ($vnames && defined($row{"vname"})) {
$node_id = $row{"vname"};
}
......@@ -339,7 +348,7 @@ while (<IF>) {
if ($filename) {
$filename = "${spaces}\tfilename \"$filename\";\n";
}
spit:
# Need to make MAC look right..
$mac =~ s/(..)\B/$1:/g;
......@@ -366,6 +375,11 @@ if ($install) {
close(OF) or
fatal("Could not close $outfile");
if (-e $DHCPD_TAIL) {
system("cat $DHCPD_TAIL >> $outfile") == 0 or
fatal("Could not add tail to $outfile");
}
if (-e $DHCPD_CONF) {
system("cp -fp $DHCPD_CONF ${DHCPD_CONF}.old") == 0 or
fatal("Could not backup copy of ${DHCPD_CONF}");
......
......@@ -1827,7 +1827,7 @@ CREATE TABLE `interfaces` (
`mask` varchar(15) default NULL,
`interface_type` varchar(30) default NULL,
`iface` text NOT NULL,
`role` enum('ctrl','expt','jail','fake','other','gw','outer_ctrl') default NULL,
`role` enum('ctrl','expt','jail','fake','other','gw','outer_ctrl','mngmnt') default NULL,
`current_speed` enum('0','10','100','1000','4000','10000','40000','100000') NOT NULL default '0',
`duplex` enum('full','half') NOT NULL default 'full',
`rtabid` smallint(5) unsigned NOT NULL default '0',
......
#
# Stuff for ilo (management interface) support.
#
use strict;
use libdb;
sub DoUpdate($$$)
{
my ($dbhandle, $dbname, $version) = @_;
my $type = DBSlotType("interfaces", "role");
if (!$type) {
Fatal("No 'role' slot in 'interfaces' table");
}
if (! ($type =~ /mngmnt/)) {
DBQueryFatal("alter table interfaces change `role` `role` ".
" enum('ctrl','expt','jail','fake','other','gw',".
" 'outer_ctrl','mngmnt') default NULL");
}
$type = DBSlotType("wires", "type");
if (!$type) {
Fatal("No 'type' slot in 'wires' table");
}
if (! ($type =~ /Management/)) {
DBQueryFatal("alter table wires change `type` `type` ".
" enum('Node','Serial','Power','Dnard','Control',".
" 'Trunk','OuterControl','Unused','Management') ".
"NOT NULL default 'Node'");
}
#
# Update all of the interfaces. Assume no wires to worry about.
#
DBQueryFatal("update interfaces set role='mngmnt' ".
"where role='other' and ".
" (interface_type='drac' or interface_type='ilo' or ".
" interface_type='ilo2')");
return 0;
}
1;
# Local Variables:
# mode:perl
# End:
......@@ -2,14 +2,14 @@
#
# EMULAB-COPYRIGHT
# Copyright (c) 2008-2010 University of Utah and the Flux Group.
# Copyright (c) 2008-2010, 2012 University of Utah and the Flux Group.
# All rights reserved.
#
#
# Handle iLO or iLO 2 remote power control.
# Also handle DRAC since its so similar.
# Node must have an interface such that role='other' and
# Node must have an interface such that role='mngmnt' and
# interface_type='ilo2' or 'ilo'.
#
# Supports either pubkey or passwd auth, depending on what's in db.
......@@ -66,7 +66,8 @@ sub iloctrl($$@) {
# grab ilo IP and auth info
foreach my $n (@nodes) {
my $res = DBQueryFatal("select IP from interfaces" .
" where node_id='$n' and role='other'" .
" where node_id='$n' and ".
" role='" . TBDB_IFACEROLE_MANAGEMENT() . "'" .
" and interface_type='$type'");
if (!defined($res) || !$res || $res->num_rows() == 0) {
warn "No $type interface for $n; cannot find $type IP!\n";
......
......@@ -27,7 +27,8 @@ SBIN_SCRIPTS = vlandiff vlansync withadminprivs export_tables cvsupd.pl \
anonsendmail epmodeset fixexpinfo node_traffic \
dumpdescriptor subboss_tftpboot_sync testbed-control \
archive-expinfo grantfeature emulabfeature addblob readblob \
prereserve grantimage getimages localize_mfs
prereserve grantimage getimages localize_mfs \
management_iface
WEB_SBIN_SCRIPTS= webnewnode webdeletenode webspewconlog webarchive_list \
webwanodecheckin webspewimage
......
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2003-2012 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
use English;
use Getopt::Std;
use Date::Parse;
use Time::Local;
use Data::Dumper;
use File::Temp qw(tempfile);
#
# Add a management interface for a node. ilo, ilo2, drac.
# When adding for a local node, try to insert switch info if -s is given.
# Also restart DHCPD since we now add entries for local management interfaces.
#
sub usage()
{
print STDERR "Usage: management_iface -t <type> -a [key|pswd] ";
print STDERR " [-s <switchinfo>] <node_id> mac IP arg1 arg2\n";
print STDERR " management_iface -r <node_id>\n";
print STDERR " -h This message\n";
print STDERR " -t type Management type; ilo, ilo2, drac\n";
print STDERR " -s info Optional switch info; switch,card,port\n";
print STDERR " -s - Search output of switchmac to find switch info\n";
print STDERR " -a pswd Password auth; provide login and password.\n";
print STDERR " -a key SSH key auth; provide login and key path.\n";
print STDERR " -r Remove management interface from DB.\n";
exit(-1);
}
my $optlist = "ht:a:rs:";
my $debug = 0;
my $remove = 0;
my $authtype;
my $type;
my $switchinfo;
# Protos
sub fatal($);
sub RemoveManagementInterface($);
#
# Configure variables
#
my $TB = "@prefix@";
my $SWITCHMAC = "$TB/libexec/switchmac";
my $DHCPD_MAKECONF = "$TB/sbin/dhcpd_makeconf";
#
# Testbed Support libraries
#
use lib "@prefix@/lib";
use emdb;
use EmulabConstants;
use emutil;
use User;
use Node;
use Interface;
#
# Turn off line buffering on output
#
$| = 1;
#
# Untaint the path
#
$ENV{'PATH'} = "/bin:/sbin:/usr/bin:";
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{'h'})) {
usage();
}
if (defined($options{'d'})) {
$debug = 1;
}
if (defined($options{'r'})) {
$remove = 1;
usage()
if (@ARGV != 1);
}
if (defined($options{'s'})) {
$switchinfo = $options{'s'};
}
if (defined($options{'t'})) {
$type = $options{'t'};
usage()
if (! ($type eq "ilo" || $type eq "ilo2" || $type eq "drac"));
}
if (defined($options{'a'})) {
$authtype = $options{'a'};
usage()
if (! ($authtype eq "key" || $authtype eq "pswd"));
}
# Need at least one argument.
usage()
if (@ARGV < 1);
#
# Verify user, must be admin.
#
my $this_user = User->ThisUser();
if (! defined($this_user)) {
fatal("You ($UID) do not exist!");
}
if (!$this_user->IsAdmin()) {
fatal("You are not a testbed administrator!");
}
my $node_id = shift();
my $node = Node->Lookup($node_id);
if (!defined($node)) {
fatal("No such node!");
}
#
# Remove existing interface.
#
if ($remove) {
exit(RemoveManagementInterface($node));
}
#
# Else adding new one.
#
usage()
if (@ARGV != 4);
my $mac = shift();
my $IP = shift();
# Convert mac to DB representation.
if ($mac =~ /(\w\w):(\w\w):(\w\w):(\w\w):(\w\w):(\w\w)/) {
$mac = "$1$2$3$4$5$6";
}
# Verify optional switch info
my $switchid;
my $switchcard;
my $switchport;
if (defined($switchinfo)) {
if ($switchinfo eq "-") {
#
# Search using switchmac
#
my $output = emutil::ExecQuiet($SWITCHMAC);
if ($?) {
fatal("Error running $SWITCHMAC:\n$output");
}
foreach my $line (split("\n", $output)) {
my ($smac,$sinfo,undef,undef,$role) = split(',', $line);
if ($smac eq $mac) {
print "Found mac on switch: $line\n";
if ($sinfo =~ /([-\w]*)\/(\d*)\.(\d*)/) {
$switchid = $1;
$switchcard = $2;
$switchport = $3;
}
else {
fatal("Could not parse switchmac data");
}
last;
}
}
if (!defined($switchid)) {
print STDERR "Could not find the switch info with switchmac.\n";
print STDERR "Ping the current IP address and then try again\n";
exit(1);
}
}
elsif ($switchinfo =~ /^([-\w]+),(\d+),(\d+)$/) {
$switchid = $1;
$switchcard = $2;
$switchport = $3;
}
else {
fatal("Invalid switch info");
}
}
#
# Add the outlet and authinfo.
#
$node->AddOutlet($type, 0,
{"key_type" => $type,
"key_role" => ($authtype eq "key" ? "ssh-key" : "ssh-passwd"),
"key_uid" => $ARGV[0],
"key" => $ARGV[1]}) == 0
or fatal("Could not add outlet records");
#
# Add the interface.
#
my $ifaceargs = {
"card" => 99, # XXX Bogus.
"iface" => $type,
"role" => TBDB_IFACEROLE_MANAGEMENT(),
"MAC" => $mac,
"IP" => $IP,
"type" => $type,
};
if (defined($switchinfo)) {
$ifaceargs->{'switch_id'} = $switchid;
$ifaceargs->{'switch_port'} = $switchcard;
$ifaceargs->{'switch_card'} = $switchport;
}
Interface->Create($node, $ifaceargs)
or fatal("Could not create interface entry");
#
# Restart DHCPD.
#
if (!$node->isremotenode()) {
print "Re-generating dhcpd.conf and restarting dhcpd\n";
if (system("$DHCPD_MAKECONF -i -r")) {
fatal("Unable to restart dhcpd");
}
}
exit(0);
#
# Remove a management interface.
#
sub RemoveManagementInterface($)
{
my ($node) = @_;
my $interface = Interface->LookupManagement($node);
fatal("No management interface")
if (!defined($interface));
$node->DeleteOutlet() == 0
or fatal("Could not delete outlets");
$interface->DeleteWire() == 0
or fatal("Could not delete wire for $interface");
# Flag indicates it is okay to delete real interface.
$interface->Delete(1) == 0
or fatal("Could not delete $interface");
#
# Restart DHCPD.
#
if (!$node->isremotenode()) {
print "Re-generating dhcpd.conf and restarting dhcpd\n";
if (system("$DHCPD_MAKECONF -i -r")) {
fatal("Unable to restart dhcpd");
}
return 0;
}
}
sub fatal($)
{
my ($mesg) = $_[0];
die("*** $0:\n".
" $mesg\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