Commit cf517af6 authored by Leigh Stoller's avatar Leigh Stoller

Another protogeni checkbox; scriptify and simplify adding "special"

devices with network interfaces. Emulab's spp and bbg nodes are
examples, but I did all that by hand inserting sql. An spp node is a
shared node with some interfaces. Users can allocate one or more of
those interfaces and establish vlans to the interfaces. The node is a
"fakenode" in "shared" mode, and everything else falls out. The mapper
assigns virtual nodes until all of the interfaces are allocated,
snmpit does its work on the interfaces, and the user then does the
rest.

Anyway, to added a special device:

  boss> wap addspecialdevice -s -t goober goober1

The -t argument is the name of the node type, created if it does not
exists. The last argument is the name of the fakenode to create in the
DB. The -s option says the special device is shared. Without -s, the
device is allocated exclusively.

Then to add interfaces to the device:

  boss> wap addspecialiface -b 1Gb -s cisco4,100,100 goober1 eth0

The -b option is the speed (either 100Mb or 1Gb). The -s option is the
switch side of the interface (switchname,card,port). The last two
arguments are the nodename and iface name for the interfaces table.

After the interface and wires table entry are added to the DB, snmpit
is called to put the switch port into tagged mode (if the node is
shared). To skip the snmpit step, add the -t option.
parent 11c3cf4d
......@@ -175,13 +175,17 @@ sub IsManagement($)
#
# Lookup by card,port
#
sub Lookup($$$$)
sub Lookup($$$;$)
{
my ($class, $nodeid, $card, $port) = @_;
$nodeid = $nodeid->node_id()
if (ref($nodeid));
# XXX: the node side always uses port 1.
$port = 1
if (!defined($port));
# Look in cache first
return $all_interfaces{"$nodeid:$card:$port"}
if (exists($all_interfaces{"$nodeid:$card:$port"}));
......@@ -322,9 +326,15 @@ sub Create($$$)
my $length = $argref->{'length'};
my $iface = $argref->{'iface'};
my $logical = $argref->{'logical'};
my $trunk = $argref->{'trunk'};
if ($ifrole eq TBDB_IFACEROLE_MANAGEMENT()) {
$wire_type = "Management";
if (!defined($wire_type)) {
if ($ifrole eq TBDB_IFACEROLE_MANAGEMENT()) {
$wire_type = "Management";
}
if ($ifrole eq TBDB_IFACEROLE_EXPERIMENT()) {
$wire_type = "Node";
}
}
$iface = "eth$card"
if (!defined($iface));
......@@ -340,6 +350,8 @@ sub Create($$$)
if (!defined($max_speed));
$logical = 0
if (!defined($logical));
$trunk = 0
if (!defined($trunk));
if (!defined($uuid)) {
$uuid = NewUUID();
if (!defined($uuid)) {
......@@ -355,7 +367,7 @@ sub Create($$$)
print STDERR Dumper($argref);
return undef;
}
#
# Lock the tables to prevent concurrent creation
#
......@@ -382,6 +394,7 @@ sub Create($$$)
" card=$card, port=$port, role='$ifrole', ".
" mac='$MAC', IP='$IP', " .
(defined($mask) ? "mask='$mask', " : "") .
($trunk ? "trunk='1', " : "") .
" interface_type='$iftype', iface='$iface', " .
" current_speed='$max_speed', duplex='$duplex', ".
" uuid='$uuid'")) {
......@@ -391,6 +404,7 @@ sub Create($$$)
if (!DBQueryWarn("insert into interface_state set ".
" node_id='$node_id', " .
($trunk ? "remaining_bandwidth='$max_speed', " : "") .
" card=$card, port=$port, iface='$iface'")) {
DBQueryWarn("delete from interfaces ".
"where node_id='$node_id' and card='$card' ".
......
......@@ -407,7 +407,7 @@ sub Create($$$$)
$osid = "NULL";
$opmode = "ALWAYSUP";
}
elsif ($isremote) {
elsif ($isremote || $typeinfo->isfakenode()) {
$osid = "NULL";
$opmode = "";
......@@ -449,7 +449,12 @@ sub Create($$$$)
$osid = "NULL";
$opmode = "";
}
$state = $STATE_INITIAL;
if (exists($argref->{'eventstate'})) {
$state = $argref->{'eventstate'};
}
else {
$state = $STATE_INITIAL;
}
#
# Lock the tables to prevent concurrent creation
......
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2005-2010 University of Utah and the Flux Group.
# Copyright (c) 2005-2012 University of Utah and the Flux Group.
# All rights reserved.
#
package NodeType;
......@@ -342,6 +342,9 @@ sub trivlink_maxspeed($;$) {
sub isdedicatedremote($;$) {
return GetAttribute($_[0], "dedicated_widearea", $_[1]);
}
sub isfakenode($;$) {
return GetAttribute($_[0], "fakenode", $_[1]);
}
sub control_interface($;$) { return control_iface($_[0], $_[1]); }
#
......
......@@ -1594,11 +1594,15 @@ sub LoadVirtLans($)
# Temporary, for generating rspecs.
push(@{ $vlanmember->virt_node()->_virtifaces() }, $vlanmember);
# Terrible.
#
# Currently a virtual fakenode implies that the physical node is
# shared, and that different experiments can allocate portions of
# interfaces.
#
$vlanmember->_reservebw(0);
$vlanmember->_needtrunk(0);
if ($vlanmember->virt_node()->type() eq "sppvm" ||
$vlanmember->virt_node()->type() eq "bbgenivm") {
if ($vlanmember->virt_node()->_typeinfo()->isfakenode() &&
$vlanmember->virt_node()->_typeinfo()->isvirtnode()) {
$vlanmember->_reservebw($bandwidth);
$vlanmember->_needtrunk(1);
$vlanmember->_nobwshaping(1);
......
......@@ -1590,11 +1590,15 @@ sub LoadVirtLans($)
# Temporary, for generating rspecs.
push(@{ $vlanmember->virt_node()->_virtifaces() }, $vlanmember);
# Terrible.
#
# Currently a virtual fakenode implies that the physical node is
# shared, and that different experiments can allocate portions of
# interfaces.
#
$vlanmember->_reservebw(0);
$vlanmember->_needtrunk(0);
if ($vlanmember->virt_node()->type() eq "sppvm" ||
$vlanmember->virt_node()->type() eq "bbgenivm") {
if ($vlanmember->virt_node()->_typeinfo()->isfakenode() &&
$vlanmember->virt_node()->_typeinfo()->isvirtnode()) {
$vlanmember->_reservebw($bandwidth);
$vlanmember->_needtrunk(1);
$vlanmember->_nobwshaping(1);
......@@ -5290,7 +5294,7 @@ sub InterpLinks($)
push(@sharedpnodes, $pnode);
}
}
if (@sharedpnodes > 1) {
if (@sharedpnodes > 0) {
my $protovlan = ProtoLan->Create($experiment, "sharedlan",
$self->impotent() ||
$self->alloconly());
......
......@@ -28,7 +28,8 @@ SBIN_SCRIPTS = vlandiff vlansync withadminprivs export_tables cvsupd.pl \
dumpdescriptor subboss_tftpboot_sync testbed-control \
archive-expinfo grantfeature emulabfeature addblob readblob \
prereserve grantimage getimages localize_mfs \
management_iface sharevlan check-shared-bw
management_iface sharevlan check-shared-bw \
addspecialdevice addspecialiface
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 generic device to the DB.
#
sub usage()
{
print STDERR "Usage: addgenericdev -t <type> [-s] <node_id>\n";
print STDERR "Options:\n";
print STDERR " -d - Turn on debugging\n";
print STDERR " -n - Dry run mode\n";
print STDERR " -s - Node is to be shared by multiple experiments\n";
print STDERR " -t type - Type name (eg: bbg, spp, goober, whatever)\n";
exit(-1);
}
my $optlist = "t:dns";
my $debug = 0;
my $impotent = 0;
my $type;
my $isshared = 0;
my $experiment;
# Protos
sub fatal($);
sub CreateType($$);
sub CreateNode();
#
# Configure variables
#
my $TB = "@prefix@";
#
# Testbed Support libraries
#
use lib "@prefix@/lib";
use emdb;
use EmulabConstants;
use emutil;
use User;
use Node;
use NodeType;
use OSinfo;
use Experiment;
use Interface;
#
# Turn off line buffering on output
#
$| = 1;
#
# Untaint the path
#
$ENV{'PATH'} = "/bin:/sbin:/usr/bin:";
#
# Parse command arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{'h'})) {
usage();
}
if (defined($options{'d'})) {
$debug = 1;
}
if (defined($options{'n'})) {
$impotent = 1;
}
if (defined($options{'t'})) {
$type = $options{'t'};
}
if (defined($options{'s'})) {
$isshared = 1;
}
usage()
if (@ARGV != 1 || !(defined($type)));
my $node_id = $ARGV[0];
#
# 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!");
}
#
# The node may not already exist.
#
if (Node->Lookup($node_id)) {
fatal("Node already exists in the DB");
}
#
# These two OSIDs must exist.
#
my $osinfo = OSinfo->LookupByName("GENERICDEV");
if (!defined($osinfo)) {
fatal("Cannot lookup OSID 'GENERICDEV' for physical device");
}
my $osinfo_vm = OSinfo->LookupByName("GENERICDEV-VM");
if (!defined($osinfo_vm)) {
fatal("Cannot lookup OSID 'GENERICDEV-VM' for virtual device");
}
#
# If the fakenode is shared, it has to be allocated to a holding
# experiment.
#
if ($isshared) {
$experiment = Experiment->Lookup(TBOPSPID(), "holding");
fatal("Holding experiment does not exist!")
if (!defined($experiment));
}
#
# Create the type if it does not exist.
#
if (!defined(NodeType->Lookup($type))) {
CreateType($type, 0);
if ($isshared) {
CreateType("${type}-vm", 1);
}
}
CreateNode();
exit(0);
#
# Add a new node type.
#
sub CreateType($$)
{
my ($type, $isvirt) = @_;
#
# Defaults work for almost everything.
#
if ($debug || $impotent) {
print "Creating type: $type - isvirt is $isvirt\n";
}
if (!$impotent) {
DBQueryFatal("replace into node_types set ".
" class='$type', type='$type', ".
" isvirtnode='$isvirt', isdynamic='$isvirt'");
}
#
# Device nodes are neither rebootable nor imageable.
#
if ($debug || $impotent) {
print "Adding false attributes rebootable/imageable\n";
print "Adding true attribute fakenode\n";
}
if (!$impotent) {
DBQueryFatal("replace into node_type_attributes values ".
" ('$type','rebootable','0','boolean')");
DBQueryFatal("replace into node_type_attributes values ".
" ('$type','imageable','0','boolean')");
DBQueryFatal("replace into node_type_attributes values ".
" ('$type','fakenode','1','boolean')");
}
return 0;
}
#
# Create the node.
#
sub CreateNode()
{
my $blob = {
"type" => $type,
"role" => "testnode",
"initial_state" =>TBDB_NODESTATE_ISUP(),
};
my $node;
print "Creating new node $node_id\n";
if (!$impotent) {
$node = Node->Create($node_id, $experiment, $blob);
if (!defined($node)) {
fatal("Could not create new node");
}
}
#
# When the node is shared, need to update the sharing state.
#
if ($isshared) {
print "Updating reservation to reflect sharing.\n";
if (!$impotent) {
$node->ModifyReservation({"erole" => "sharedhost",
"sharing_mode" => "shared_local"})
== 0 or fatal("Could not update reservation entry");
}
}
return 0;
}
sub fatal($)
{
my ($mesg) = $_[0];
die("*** $0:\n".
" $mesg\n");
}
#!/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 generic device to the DB.
#
sub usage()
{
print STDERR "Usage: addgenericiface -b <speed> [-s <switchinfo>] ".
"<node_id> <iface_id>\n";
print STDERR "Usage: addgenericiface -r <node_id> <iface_id>\n";
print STDERR "Options:\n";
print STDERR " -d - Turn on debugging\n";
print STDERR " -n - Dry run mode\n";
print STDERR " -t - Do not call snmpit to set trunk mode\n";
print STDERR " -r - Delete interface\n";
print STDERR " -b speed - Interface speed; 100Mb or 1Gb \n";
print STDERR " -s info - switchname,switchcard,switchport\n";
print STDERR " iface_id - eth0, eth1, etc (must end in an integer)\n";
exit(-1);
}
my $optlist = "b:dns:rt";
my $debug = 0;
my $impotent = 0;
my $removing = 0;
my $notrunk = 0;
my $speed;
my $switchinfo;
# Protos
sub fatal($);
#
# Configure variables
#
my $TB = "@prefix@";
my $SNMPIT = "$TB/bin/snmpit_test";
#
# Testbed Support libraries
#
use lib "@prefix@/lib";
use emdb;
use EmulabConstants;
use emutil;
use User;
use Node;
use NodeType;
use OSinfo;
use Interface;
#
# Turn off line buffering on output
#
$| = 1;
#
# Untaint the path
#
$ENV{'PATH'} = "/bin:/sbin:/usr/bin:";
#
# Parse command arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{'h'})) {
usage();
}
if (defined($options{'d'})) {
$debug = 1;
}
if (defined($options{'n'})) {
$impotent = 1;
}
if (defined($options{'r'})) {
$removing = 1;
}
if (defined($options{'t'})) {
$notrunk = 1;
}
if (defined($options{'b'})) {
$speed = $options{'b'};
usage()
if ($speed ne "1Gb" && $speed ne "100Mb");
}
if (defined($options{'s'})) {
$switchinfo = $options{"s"};
}
usage()
if (@ARGV != 2);
my $node_id = $ARGV[0];
my $iface_id = $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 = Node->Lookup($node_id);
if (!defined($node)) {
fatal("Node does not exist in the DB")
}
my $interface = Interface->LookupByIface($node, $iface_id);
if ($removing) {
fatal("Node does not have an interface named $iface_id")
if (!defined($interface));
}
else {
fatal("Node already has an interface named $iface_id")
if (defined($interface));
}
if ($removing) {
if ($node->erole() eq "sharedhost" && !$notrunk) {
print "Turning off trunk mode for $node_id:$iface_id\n";
system("$SNMPIT -T $node_id:$iface_id") == 0
or fatal("Could not put port into trunking mode");
}
$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");
exit(0);
}
# Verify switch info
my $nodecard;
my $switchid;
my $switchcard;
my $switchport;
#
# Derive a card number form the iface number.
#
if ($iface_id =~ /^[^\d]*(\d*)$/) {
$nodecard = $1;
}
else {
fatal("iface_id is not in the proper format");
}
if (Interface->Lookup($node, $nodecard)) {
fatal("Node already has an interface with card=$nodecard");
}
if ($switchinfo =~ /^([-\w]+),(\d+),(\d+)$/) {
$switchid = $1;
$switchcard = $2;
$switchport = $3;
}
else {
fatal("Invalid switch info");
}
my $switch = Node->Lookup($switchid);
if (!defined($switch)) {
fatal("Switch $switchid does not exist");
}
if (Interface->Lookup($node, $switchcard, $switchport)) {
fatal("Switch $switchid already has an interface with ".
"card=$switchcard,port=$switchport");
}
#
# Add the interface.
#
my $ifaceargs = {
"card" => $nodecard,
"iface" => $iface_id,
"role" => TBDB_IFACEROLE_EXPERIMENT(),
"type" => ($speed eq "100Mb" ? "generic" : "generic_1G"),
"max_speed" => ($speed eq "100Mb" ? "100000" : "1000000"),
"switch_id" => $switchid,
"switch_port" => $switchport,
"switch_card" => $switchcard,
"trunk" => ($node->erole() eq "sharedhost" ? 1 : 0),
"mac" => "000000000000",
};
print "Creating interface with arguments:\n";
print Dumper($ifaceargs);
if (!$impotent) {
Interface->Create($node, $ifaceargs)
or fatal("Could not create interface entry");
if ($node->erole() eq "sharedhost" && !$notrunk) {
print "Setting $node_id:$iface_id to trunking mode\n";
system("$SNMPIT -T $node_id:$iface_id") == 0
or fatal("Could not put port into trunking mode");
}
}
exit(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