All new accounts created on Gitlab now require administrator approval. If you invite any collaborators, please let Flux staff know so they can approve the accounts.

Commit 5326988f authored by Kirk Webb's avatar Kirk Webb

New node_attributes facility and table.

Auxiliary node attributes, such as service tag #, BIOS version, etc., are
should now be placed into the node_attributes table.  This can be accomplished
by either using the node_attributes command line tool, or by using the
modnodeattributes_form.php3 form (not linked in anywhere yet, but will be
in a moment).  Attribute names and values are checked for sanity using
table_regex entries.  Also note that I started with the nodecontrol stuff
as a template.

The command line tool and web form (which simply calls the command line tool
to actually do the modifications) can add, delete, and/or remove attributes.

Finally, note that the bios_version column has been moved from the nodes
table to the node_attributes table.  The Node Information page will show
the list of current attributes at the bottom of the info table.
parent 98d9d9d3
......@@ -2263,7 +2263,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
tbsetup/savelogs tbsetup/setgroups tbsetup/websetgroups \
tbsetup/savelogs.proxy \
tbsetup/rmgroup tbsetup/webrmuser tbsetup/webrmgroup tbsetup/mkexpdir \
tbsetup/webnodecontrol tbsetup/node_control \
tbsetup/webnodecontrol tbsetup/node_control tbsetup/node_attributes \
tbsetup/webmkgroup tbsetup/mkgroup tbsetup/eventsys_start \
tbsetup/eventsys_control tbsetup/webeventsys_control \
tbsetup/webmkproj tbsetup/mkproj tbsetup/libtestbed.pm \
......@@ -2273,7 +2273,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
tbsetup/libreboot.pm tbsetup/libosload.pm \
tbsetup/sfskey_update tbsetup/sfskey_update.proxy \
tbsetup/idleswap tbsetup/webidleswap tbsetup/switchmac \
tbsetup/newnode_reboot \
tbsetup/newnode_reboot tbsetup/webnodeattributes \
tbsetup/libtestbed.py \
tbsetup/tarfiles_setup tbsetup/webtarfiles_setup \
tbsetup/fetchtar.proxy tbsetup/webfrisbeekiller \
......
......@@ -701,7 +701,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
tbsetup/savelogs tbsetup/setgroups tbsetup/websetgroups \
tbsetup/savelogs.proxy \
tbsetup/rmgroup tbsetup/webrmuser tbsetup/webrmgroup tbsetup/mkexpdir \
tbsetup/webnodecontrol tbsetup/node_control \
tbsetup/webnodecontrol tbsetup/node_control tbsetup/node_attributes \
tbsetup/webmkgroup tbsetup/mkgroup tbsetup/eventsys_start \
tbsetup/eventsys_control tbsetup/webeventsys_control \
tbsetup/webmkproj tbsetup/mkproj tbsetup/libtestbed.pm \
......@@ -711,7 +711,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
tbsetup/libreboot.pm tbsetup/libosload.pm \
tbsetup/sfskey_update tbsetup/sfskey_update.proxy \
tbsetup/idleswap tbsetup/webidleswap tbsetup/switchmac \
tbsetup/newnode_reboot \
tbsetup/newnode_reboot tbsetup/webnodeattributes \
tbsetup/libtestbed.py \
tbsetup/tarfiles_setup tbsetup/webtarfiles_setup \
tbsetup/fetchtar.proxy tbsetup/webfrisbeekiller \
......
......@@ -10,4 +10,6 @@ TBAUDITEMAIL=kwebb@flux.utah.edu
TBSTATEDEMAIL=kwebb@flux.utah.edu
TBTESTSUITEEMAIL=kwebb@flux.utah.edu
WWW=www.emulab.net/dev/kwebb
FS_WITH_QUOTAS="/q /groups /users"
PLABSUPPORT=1
PLAB_ROOTBALL="plabroot-kwebb.tar.bz2"
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2004 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
use lib "/usr/testbed/lib";
use libdb;
#
# Turn off line buffering on output
#
$| = 1;
#
# Untaint the path
#
$ENV{'PATH'} = '/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
my $query_result =
DBQueryFatal("select node_id,bios_version from nodes ".
"order by node_id");
while (my @row = $query_result->fetchrow_array()) {
if ($row[1]) {
print "REPLACE INTO node_attributes VALUES ".
"('$row[0]', 'bios_version', '$row[1]');\n";
}
}
......@@ -977,6 +977,18 @@ CREATE TABLE node_activity (
PRIMARY KEY (node_id)
) TYPE=MyISAM;
--
-- Table structure for table `node_attributes`
--
CREATE TABLE node_attributes (
node_id varchar(32) NOT NULL default '',
attrkey varchar(32) NOT NULL default '',
attrvalue tinytext NOT NULL,
PRIMARY KEY (node_id,attrkey),
KEY node_id (node_id)
) TYPE=MyISAM;
--
-- Table structure for table `node_auxtypes`
--
......@@ -1211,7 +1223,6 @@ CREATE TABLE nodes (
failureaction enum('fatal','nonfatal','ignore') NOT NULL default 'fatal',
routertype enum('none','ospf','static','manual','static-ddijk','static-old') NOT NULL default 'none',
next_pxe_boot_path text,
bios_version varchar(64) default NULL,
eventstate varchar(20) default NULL,
state_timestamp int(10) unsigned default NULL,
op_mode varchar(20) default NULL,
......@@ -1240,8 +1251,6 @@ CREATE TABLE nodes (
destination_x float default NULL,
destination_y float default NULL,
destination_orientation float default NULL,
serial varchar(32) default NULL,
service_tag varchar(32) default NULL,
PRIMARY KEY (node_id),
KEY phys_nodeid (phys_nodeid),
KEY node_id (node_id,phys_nodeid),
......
......@@ -654,7 +654,6 @@ REPLACE INTO table_regex VALUES ('experiments','jail_osname','text','redirect','
REPLACE INTO table_regex VALUES ('experiments','delay_osname','text','redirect','os_info:osname',0,0,NULL);
REPLACE INTO table_regex VALUES ('experiments','use_ipassign','int','redirect','default:boolean',0,0,NULL);
REPLACE INTO table_regex VALUES ('experiments','ipassign_args','text','regex','^[\\w\\s-]*$',0,255,NULL);
REPLACE INTO table_regex VALUES ('nodes','bios_version','text','regex','^[-\\w\\.+]+$',0,64,NULL);
REPLACE INTO table_regex VALUES ('os_info','osid','text','regex','^[-\\w\\.+]+$',2,35,NULL);
REPLACE INTO table_regex VALUES ('experiments','expt_name','text','redirect','default:tinytext',1,255,NULL);
REPLACE INTO table_regex VALUES ('experiments','noswap_reason','text','redirect','default:tinytext',1,255,NULL);
......@@ -740,8 +739,8 @@ REPLACE INTO table_regex VALUES ('virt_firewalls','type','text','regex','^(ipfw|
REPLACE INTO table_regex VALUES ('virt_firewalls','style','text','regex','^(open|closed|basic|emulab)$',0,0,NULL);
REPLACE INTO table_regex VALUES ('mailman_listnames','listname','text','regex','^[-\\w\\.\\+]+$',3,64,NULL);
REPLACE INTO table_regex VALUES ('default','fulltext','text','regex','^[\\040-\\176\\012\\015\\011]*$',0,20000,NULL);
REPLACE INTO table_regex VALUES ('nodes','serial','text','regex','^[-\\w\\.+]+$',0,32,NULL);
REPLACE INTO table_regex VALUES ('nodes','service_tag','text','regex','^[-\\w\\.+]+$',0,32,NULL);
REPLACE INTO table_regex VALUES ('node_attributes','attrkey','text','regex','^[-\\w]+$',1,32,NULL);
REPLACE INTO table_regex VALUES ('node_attributes','attrvalue','text','regex','^[-\\w\\.+,\\s]+$',0,255,NULL);
--
-- Dumping data for table `testsuite_preentables`
......
......@@ -2830,12 +2830,7 @@ last_net_act,last_cpu_act,last_ext_act);
alter table global_policies change auxdata \
auxdata varchar(128) NOT NULL default '';
4.13: Add serial and service_tag columns to nodes table.
alter table nodes add serial varchar(32) \
default NULL after destination_orientation;
alter table nodes add service_tag varchar(32) \
default NULL after serial;
4.13: Skip to 4.14
4.14: Add disk loader and admin MFS fields to node_types.
......@@ -2843,3 +2838,23 @@ last_net_act,last_cpu_act,last_ext_act);
default 'FREEBSD-MFS' after bios_waittime;
alter table node_types add diskloadmfs_osid varchar(35) \
default 'FRISBEE-MFS' after adminmfs_osid;
4.15 Create node_attributes table; migrate a column from the nodes table.
CREATE TABLE node_attributes (
node_id varchar(32) NOT NULL default '',
attrkey varchar(32) NOT NULL default '',
attrvalue tinytext NOT NULL,
PRIMARY KEY (node_id,attrkey),
KEY node_id (node_id)
) TYPE=MyISAM;
Migrate bios_version info:
Run:
./bios_move.pl | mysql tbdb
Check the node_attributes table to be sure it contains your bios
version entries. Then remove the column from the nodes table:
alter table nodes drop column bios_version;
......@@ -19,7 +19,8 @@ BIN_STUFF = power snmpit tbend tbprerun tbreport \
os_load endexp batchexp swapexp \
node_reboot nscheck node_update savelogs node_control \
portstats checkports eventsys_control os_select tbrestart \
tbswap nseswap tarfiles_setup node_history tbrsync
tbswap nseswap tarfiles_setup node_history tbrsync \
node_attributes
SBIN_STUFF = resetvlans console_setup.proxy sched_reload named_setup \
batch_daemon exports_setup reload_daemon sched_reserve \
......@@ -28,7 +29,7 @@ SBIN_STUFF = resetvlans console_setup.proxy sched_reload named_setup \
exports_setup.proxy vnode_setup eventsys_start \
sfskey_update sfskey_update.proxy rmuser idleswap \
newnode_reboot savelogs.proxy eventsys.proxy \
elabinelab snmpit.proxy panic repos_daemon
elabinelab snmpit.proxy panic repos_daemon node_attributes
CTRLBIN_STUFF = console_setup.proxy sfskey_update.proxy \
savelogs.proxy eventsys.proxy
......@@ -44,7 +45,8 @@ LIBEXEC_STUFF = rmproj wanlinksolve wanlinkinfo \
webmkgroup websetgroups webmkproj webmodgroups \
spewlogfile staticroutes routecalc wanassign \
webnodereboot webrmuser webidleswap switchmac \
spewrpmtar webtarfiles_setup webfrisbeekiller gentopofile
spewrpmtar webtarfiles_setup webfrisbeekiller gentopofile \
webnodeattributes
LIB_STUFF = libtbsetup.pm exitonwarn.pm libtestbed.pm snmpit_intel.pm \
snmpit_cisco.pm snmpit_lib.pm snmpit_apc.pm power_rpc27.pm \
......
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2002, 2004 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
use Getopt::Std;
#
# This script is invoked from ops and from the web interface. Must check
# all the args.
#
sub usage()
{
print("Usage: node_attributes {-m|a} name=value [name=value ...] node [node ...]\n".
" node_attributes -r attr [attr ... ] node\n".
" node_attributes -r attr [attr ... ] nodelist: node [node ...]\n".
" node_attributes -l node [node ...]\n".
"\n".
"Must specify one of: ".
" -m modify attributes\n".
" -a add attributes\n".
" -r remove attributes\n".
" -l list attributes\n".
"\n".
"For multi-node attribute removal, use the \"nodelist:\" syntax");
exit(-1);
}
my $optlist = "mardl";
#
# Define a few constants
#
my $NODEATTRS_TABLE = "node_attributes";
my $NODEATTRS_KEY = "attrkey";
my $NODEATTRS_VAL = "attrvalue";
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $TBLOGS = "@TBLOGSEMAIL@";
my @nodes = ();
my %attrs = ();
my $debug = 0;
my $errors = 0;
my $modify_attrs = 0;
my $add_attrs = 0;
my $remove_attrs = 0;
my $list_attrs = 0;
#
# Load the Testbed support stuff.
#
use lib "@prefix@/lib";
use libdb;
use libtestbed;
if (!TBAdmin($UID)) {
print "Error: You must be an admin to use this command!\n";
exit(-1);
}
# un-taint path
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
# Turn off line buffering on output
$| = 1;
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
my %options = ();
my $operation = 0;
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"m"})) {
$modify_attrs = 1;
$operation++;
}
if (defined($options{"a"})) {
$add_attrs = 1;
$operation++;
}
if (defined($options{"r"})) {
$remove_attrs = 1;
$operation++;
}
if (defined($options{"l"})) {
$list_attrs = 1;
$operation++;
}
#
# Sanity checks.
#
if ($operation > 1) {
print "Error: Only one of -m, -a, -r, or -l may be specified!\n";
usage();
}
elsif ($operation == 0) {
print "Error: One of -m, -a, -r, or -l MUST be specified!\n";
usage();
}
if (! @ARGV) {
usage();
}
#
# Shift off the set strings (name=value). Verify that each one is in the
# proper format.
#
while (@ARGV) {
my $string = $ARGV[0];
#
# Attributes are bare when in removal mode.
# If the 'nodelist:' token is given, then the remainder
# of the command line contains nodes. Otherwise, the last
# argument must be the node to operate on.
#
if ($remove_attrs) {
if ($string =~ /nodelist:/) {
shift @ARGV;
last;
}
elsif (@ARGV == 1) {
last;
}
else {
$attrs{$string} = "remove";
}
}
else {
if (! ($string =~ /([-\w]*)=[\']?([^\']*)[\']?/)) {
last;
}
$attrs{$1} = "$2";
}
shift @ARGV;
}
if ($debug) {
foreach my $option (keys(%attrs)) {
print "Will set $option to '$attrs{$option}'\n";
}
}
# Be sure at least one node was specified.
if (! @ARGV) {
print "You must specify one or more nodes!\n";
usage();
}
# Untaint the nodes.
foreach my $node ( @ARGV ) {
if ($node =~ /^([-\w]+)$/) {
$node = $1;
}
else {
die("Bad node name: $node.");
}
if (!TBValidNodeName($node)) {
die("Node is not a valid node: $node\n");
}
push(@nodes, $node);
}
if ($debug) {
print "node list: @nodes\n";
}
# If this is a attribute listing command, then let's list 'em!
# XXX: this is done in a very lame way right now.
if ($list_attrs) {
my $nodelist = join("','", @nodes);
my $query_result =
DBQueryFatal("select * from node_attributes where ".
"node_id in ('$nodelist') order by node_id");
print "node_id \t attribute \t value\n";
while (my $row = join("\t",$query_result->fetchrow_array())) {
print "$row\n";
}
exit(0);
}
#
# Process the attributes to add, mod, or remove
#
foreach my $attr (keys(%attrs)) {
my $value = $attrs{$attr};
#
# Do a checkslot on the key and value to make sure they are
# valid.
#
if ($attr ne "" &&
!TBcheck_dbslot($attr, $NODEATTRS_TABLE, $NODEATTRS_KEY,
TBDB_CHECKDBSLOT_WARN|TBDB_CHECKDBSLOT_ERROR)) {
die("*** $0:\n".
" Illegal attribute name: '$attr'\n");
}
if ($value ne "" &&
!TBcheck_dbslot($value, $NODEATTRS_TABLE, $NODEATTRS_VAL,
TBDB_CHECKDBSLOT_WARN|TBDB_CHECKDBSLOT_ERROR)) {
die("*** $0:\n".
" Illegal value contents: '$value'\n");
}
#
# If this is a modify operation, then just build up a single clause to
# execute later. Otherwise perform the insert/delete operation
# for each node now.
#
if ($modify_attrs) {
foreach my $node (@nodes) {
DBQueryFatal("replace into $NODEATTRS_TABLE values ".
"('$node','$attr','$value')");
}
}
# XXX: maybe just merge this with modify operation.
elsif ($add_attrs) {
foreach my $node (@nodes) {
DBQueryFatal("insert into $NODEATTRS_TABLE values ".
"('$node','$attr','$value')");
}
}
elsif ($remove_attrs) {
foreach my $node (@nodes) {
DBQueryFatal("delete from $NODEATTRS_TABLE where ".
"node_id='$node' and $NODEATTRS_KEY='$attr'");
}
}
}
exit(0);
......@@ -56,12 +56,6 @@ my %controlset =
[1, 0, "next_boot_cmd_line", undef, 0, "", "virt_nodes:cmd_line"],
temp_boot_osid =>
[1, 0, "temp_boot_osid", undef, 1, "-t", "os_info:osid"],
bios_version =>
[1, 0, "bios_version", undef, 0, "", "nodes:bios_version"],
serial =>
[1, 0, "serial", undef, 0, "", "nodes:serial"],
service_tag =>
[1, 0, "service_tag", undef, 0, "", "nodes:service_tag"],
);
#
......
<?php
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2002, 2004 University of Utah and the Flux Group.
# All rights reserved.
#
include("defs.php3");
include("showstuff.php3");
#
# Standard Testbed Header
#
PAGEHEADER("Modify Node Attributes Form");
#
# Only known and logged in users can do this.
#
$uid = GETLOGIN();
LOGGEDINORDIE($uid);
#
# Check to make sure that this is a valid nodeid
#
$query_result =
DBQueryFatal("SELECT * FROM nodes WHERE node_id='$node_id'");
if (mysql_num_rows($query_result) == 0) {
USERERROR("The node $node_id is not a valid nodeid!", 1);
}
$noderow = mysql_fetch_array($query_result);
#
# Get current set of attributes for node - used in comparison below
#
$node_attrs = array();
$attr_result =
DBQueryFatal("select attrkey,attrvalue from node_attributes ".
"where node_id='$node_id'");
while($row = mysql_fetch_array($attr_result)) {
$cur_node_attrs[$row[attrkey]] = $row[attrvalue];
}
#
# Only admin users may modify node attributes.
#
$isadmin = ISADMIN($uid);
if (! $isadmin) {
USERERROR("You do not have permission to modify node $node_id!", 1);
}
#
# Command strings are empty initially
#
$mod_command_string = "";
$add_command_string = "";
$del_command_string = "";
#
# Figure out which attributes are to be modified, added, or deleted
#
# Find attributes needing modification - make sure they are actually
# different than the current value before adding them to the command string.
if ($_modattrs) {
foreach ($_modattrs as $attrkey => $attrval) {
if ($cur_node_attrs[$attrkey] != $attrval) {
$mod_command_string .= "$attrkey='$attrval' ";
}
}
}
# Check for new attributes - make sure they are unique.
if ($_newattrs) {
for ($i = 0; $i < count($_newattrs); $i++) {
if ($cur_node_attrs &&
array_key_exists($_newattrs[$i], $cur_node_attrs)) {
USERERROR("You cannot add a key that already exists!",1);
}
if ($_newattrs[$i]) {
$add_command_string .= "$_newattrs[$i]='$_newvals[$i]' ";
}
}
}
# Finally, see if any attributes need to be deleted.
if ($_delattrs) {
foreach ($_delattrs as $attrkey => $attrval) {
$del_command_string .= "$attrkey ";
}
}
#
# Pass commands off to the script. It will check the arguments.
# NB: This is how nodcontrol.php3 does it, but it may not be safe;
# Shell command injection may be possible. This is an admin-only
# command though.
#
# Fire off the modify operation first
if ($mod_command_string) {
SUEXEC($uid, "nobody", "webnodeattributes -m ".
"$mod_command_string $node_id",
SUEXEC_ACTION_DIE);
}
# Next, add attributes
if ($add_command_string) {
SUEXEC($uid, "nobody", "webnodeattributes -a ".
"$add_command_string $node_id",
SUEXEC_ACTION_DIE);
}
# Finally, delete attributes.
if ($del_command_string) {
SUEXEC($uid, "nobody", "webnodeattributes -r ".
"$del_command_string $node_id",
SUEXEC_ACTION_DIE);
}
echo "<center>
<br>
<h3>Node attributes successfully modified!</h3><p>
</center>\n";
SHOWNODE($node_id, SHOWNODE_NOFLAGS);
#
# Edit option.
#
echo "<br><center>
<A href='modnodeattributes_form.php3?node_id=$node_id'>
Edit this node's attributes again?</a>
</center>\n";
#
# Standard Testbed Footer
#
PAGEFOOTER();
?>
<?php
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2002, 2004 University of Utah and the Flux Group.
# All rights reserved.
#
include("defs.php3");
#
# Standard Testbed Header
#
PAGEHEADER("Modify Node Attributes Form");
#
# Only known and logged in users can do this.
#
$uid = GETLOGIN();
LOGGEDINORDIE($uid);
#
# Verify form arguments.
#
if (!isset($node_id) ||
strcmp($node_id, "") == 0) {
USERERROR("You must provide a node ID.", 1);
}
#
# Check to make sure that this is a valid nodeid
#
$query_result =
DBQueryFatal("select * from nodes where node_id='$node_id'");
if (mysql_num_rows($query_result) == 0) {
USERERROR("The node $node_id is not a valid nodeid!", 1);
}
$noderow = mysql_fetch_array($query_result);
#
# Only admin users can modify node attributes.
#
$isadmin = ISADMIN($uid);
if (! $isadmin) {
USERERROR("You do not have permission to modify node $node_id!", 1);
}