Commit 36d218a5 authored by Mike Hibler's avatar Mike Hibler

Merge remote branch 'central/master' into rebaseit

parents 6feda7d3 fd9b70d8
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2009 University of Utah and the Flux Group.
# Copyright (c) 2000-2010 University of Utah and the Flux Group.
# All rights reserved.
#
# Testbed Makefile
......@@ -67,12 +67,15 @@ boss-install: install-schemacheck install-sitevarscheck install-dbfillcheck \
install-setbuildinfo
@echo "Boss node installed!"
#
# Same target, with the install-schemacheck dependency omitted
#
# Same target, with the checks omitted
boss-install-force: install-subdirs install-mkdirs install-setbuildinfo
@echo "Boss node installed!"
# Skip only the schema checks, but do the other checks.
boss-install-noschemacheck: install-sitevarscheck install-dbfillcheck \
install-genischemacheck install-subdirs install-mkdirs \
install-setbuildinfo
clrhouse-install: install-subdirs install-mkdirs
@echo "CleaingHouse code installed!"
......
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2008 University of Utah and the Flux Group.
# Copyright (c) 2000-2010 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
......@@ -149,6 +149,7 @@ my %xmlfields =
"issimnode" => ["issimnode", $SLOT_OPTIONAL],
"isgeninode" => ["isgeninode", $SLOT_OPTIONAL],
"isfednode" => ["isfednode", $SLOT_OPTIONAL],
"isswitch" => ["isswitch", $SLOT_OPTIONAL],
# Dynamic attributes with wildcards.
"attr_boolean_*" => ["attr_boolean", $SLOT_OPTIONAL],
......
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2008 University of Utah and the Flux Group.
# Copyright (c) 2000-2008, 2010 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
......@@ -18,8 +18,9 @@ sub usage()
print("Usage: newimageid [-v] <xmlfile>\n");
exit(-1);
}
my $optlist = "dv";
my $optlist = "dvf";
my $debug = 0;
my $force = 0;
my $verify = 0; # Check data and return status only.
#
......@@ -68,6 +69,9 @@ if (! getopts($optlist, \%options)) {
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"f"})) {
$force = 1;
}
if (defined($options{"v"})) {
$verify = 1;
}
......@@ -266,11 +270,32 @@ foreach $key (keys(%{ $xmlparse->{'attribute'} })) {
if (! $this_user->IsAdmin());
}
# Now check that the value is legal.
if (! TBcheck_dbslot($value, "images",
$dbslot, TBDB_CHECKDBSLOT_ERROR)) {
$errors{$key} = TBFieldErrorString();
next;
#
# Special case osids so they can be in pid,osname format.
#
if (($dbslot eq "default_osid" || $dbslot =~ /^part\d/) &&
$value =~ /^.+,.+$/) {
my ($pid,$osname) = ($value =~ /^(.*),(.*)$/);
# Now check that the value is legal.
if (! TBcheck_dbslot($pid, "projects",
"pid", TBDB_CHECKDBSLOT_ERROR)) {
$errors{$key} = TBFieldErrorString();
next;
}
if (! TBcheck_dbslot($osname, "os_info",
"osname", TBDB_CHECKDBSLOT_ERROR)) {
$errors{$key} = TBFieldErrorString();
next;
}
}
else {
# Now check that the value is legal.
if (! TBcheck_dbslot($value, "images",
$dbslot, TBDB_CHECKDBSLOT_ERROR)) {
$errors{$key} = TBFieldErrorString();
next;
}
}
$newimageid_args{$key} = $value;
......@@ -460,7 +485,7 @@ foreach $key (@mtype_keys) {
}
}
UserError("Node Types: Must select at least one node type")
if ($node_types_selected == 0);
if ($node_types_selected == 0 && !$force);
#
# Check sanity of node name and that user can create an image from it.
......
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2008 University of Utah and the Flux Group.
# Copyright (c) 2000-2010 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
......@@ -18,8 +18,9 @@ sub usage()
print("Usage: newimageid [-v] <xmlfile>\n");
exit(-1);
}
my $optlist = "dv";
my $optlist = "dvf";
my $debug = 0;
my $force = 0;
my $verify = 0; # Check data and return status only.
#
......@@ -68,6 +69,9 @@ if (! getopts($optlist, \%options)) {
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"f"})) {
$force = 1;
}
if (defined($options{"v"})) {
$verify = 1;
}
......@@ -487,7 +491,7 @@ foreach $key (@mtype_keys) {
}
}
UserError("Node Types: Must select at least one node type")
if ($node_types_selected == 0);
if ($node_types_selected == 0 && !$force);
#
# We perform a further check for non-admins. When a node to snapshot
......
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2007 University of Utah and the Flux Group.
# Copyright (c) 2000-2010 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
......@@ -132,13 +132,14 @@ my %xmlfields =
# XML Field Name DB slot name Flags Default
("description" => ["description", $SLOT_REQUIRED],
"osname" => ["osname" , $SLOT_REQUIRED],
"project" => ["pid_idx", $SLOT_REQUIRED],
"pid" => ["pid", $SLOT_REQUIRED],
"OS" => ["OS", $SLOT_REQUIRED],
"version" => ["version", $SLOT_OPTIONAL, ""],
"path" => ["path", $SLOT_OPTIONAL, "NULL"],
"magic", => ["magic", $SLOT_OPTIONAL, ""],
"op_mode", => ["op_mode", $SLOT_REQUIRED],
"features", => ["osfeatures", $SLOT_OPTIONAL, ""],
"mfs", => ["mfs", $SLOT_ADMINONLY, 0],
"shared", => ["shared", $SLOT_ADMINONLY, 0],
"mustclean", => ["mustclean", $SLOT_ADMINONLY, 1],
"nextosid", => ["nextosid", $SLOT_ADMINONLY],
......@@ -257,12 +258,32 @@ foreach $key (keys(%{ $xmlparse->{'attribute'} })) {
$errors{$key} = "Administrators only"
if (! $this_user->IsAdmin());
}
#
# Special case nextosid so it can be in pid,osname format.
#
if ($dbslot eq "nextosid" && $value =~ /^.+,.+$/) {
my ($pid,$osname) = ($value =~ /^(.*),(.*)$/);
# Now check that the value is legal.
if (! TBcheck_dbslot($value, "os_info",
$dbslot, TBDB_CHECKDBSLOT_ERROR)) {
$errors{$key} = TBFieldErrorString();
next;
# Now check that the value is legal.
if (! TBcheck_dbslot($pid, "projects",
"pid", TBDB_CHECKDBSLOT_ERROR)) {
$errors{$key} = TBFieldErrorString();
next;
}
if (! TBcheck_dbslot($osname, "os_info",
"osname", TBDB_CHECKDBSLOT_ERROR)) {
$errors{$key} = TBFieldErrorString();
next;
}
}
else {
# Now check that the value is legal.
if (! TBcheck_dbslot($value, "os_info",
$dbslot, TBDB_CHECKDBSLOT_ERROR)) {
$errors{$key} = TBFieldErrorString();
next;
}
}
$newosid_args{$key} = $value;
......@@ -273,9 +294,9 @@ UserError()
#
# Now do special checks.
#
my $project = Project->Lookup($newosid_args{"project"});
my $project = Project->Lookup($newosid_args{"pid"});
if (!defined($project)) {
UserError("Project: No such project ($project)");
UserError("Project: No such project");
}
if (!$project->AccessCheck($this_user, TB_PROJECT_MAKEOSID())) {
UserError("Project: Not enough permission");
......@@ -297,6 +318,8 @@ if (exists($newosid_args{"nextosid"})) {
if (!defined($nextos)) {
UserError("Nextosid: Does not exist");
}
# Might be in pid,osname format.
$newosid_args{"nextosid"} = $nextos->osid();
}
# Mere users have to supply a version, but admin people do not.
......
......@@ -8,7 +8,7 @@ package Experiment;
use strict;
use Exporter;
use vars qw(@ISA @EXPORT);
use vars qw(@ISA @EXPORT $AUTOLOAD);
@ISA = "Exporter";
@EXPORT = qw ( );
......@@ -275,78 +275,38 @@ sub Lookup($$;$)
return $self;
}
# accessors
sub field($$) { return ((! ref($_[0])) ? -1 : $_[0]->{'EXPT'}->{$_[1]}); }
sub stats($$) { return ((! ref($_[0])) ? -1 : $_[0]->{'STATS'}->{$_[1]});}
sub resources($$) { return ((! ref($_[0])) ? -1 : $_[0]->{'RSRC'}->{$_[1]}); }
# To avoid writting out all the methods.
sub AUTOLOAD {
my $self = shift;
my $type = ref($self) or die("$self is not an object\n");
my $name = $AUTOLOAD;
$name =~ s/.*://; # strip fully-qualified portion
if (exists($self->{'EXPT'}->{$name})) {
return $self->{'EXPT'}->{$name};
}
elsif (exists($self->{'STATS'}->{$name})) {
return $self->{'STATS'}->{$name};
}
elsif (exists($self->{'RSRC'}->{$name})) {
return $self->{'RSRC'}->{$name};
}
print STDERR "$self: tried to access unknown slot $name\n";
return undef;
}
sub dbrow($$) { return $_[0]->{'EXPT'}; }
sub pid($) { return field($_[0], 'pid'); }
sub gid($) { return field($_[0], 'gid'); }
sub pid_idx($) { return field($_[0], 'pid_idx'); }
sub gid_idx($) { return field($_[0], 'gid_idx'); }
sub eid($) { return field($_[0], 'eid'); }
sub idx($) { return field($_[0], 'idx'); }
sub uuid($) { return field($_[0], 'eid_uuid'); }
sub eid_uuid($) { return field($_[0], 'eid_uuid'); }
sub description($) { return field($_[0], 'expt_name'); }
sub path($) { return field($_[0], 'path'); }
sub state($) { return field($_[0], 'state'); }
sub batchstate($) { return field($_[0], 'batchstate'); }
sub batchmode($) { return field($_[0], 'batchmode'); }
sub rsrcidx($) { return stats($_[0], 'rsrcidx'); }
sub lastrsrc($) { return stats($_[0], 'lastrsrc'); }
sub creator($) { return field($_[0], 'expt_head_uid');}
sub locked($) { return field($_[0], 'expt_locked'); }
sub elabinelab($) { return field($_[0], 'elab_in_elab');}
sub elabinelab_eid($) { return field($_[0], 'elabinelab_eid');}
sub elabinelab_exptidx($){return field($_[0], 'elabinelab_exptidx');}
sub elabinelab_nosetup($){return field($_[0], 'elabinelab_nosetup');}
sub elabinelab_singlenet($){return field($_[0], 'elabinelab_singlenet');}
sub elabinelab_cvstag($){return field($_[0], 'elabinelab_cvstag');}
sub lockdown($) { return field($_[0], 'lockdown'); }
sub geniflags($) { return field($_[0], 'geniflags'); }
sub created($) { return field($_[0], 'expt_created'); }
sub swapper($) { return field($_[0], 'expt_swap_uid');}
sub swappable($) { return field($_[0], 'swappable');}
sub idleswap($) { return field($_[0], 'idleswap');}
sub autoswap($) { return field($_[0], 'autoswap');}
sub noswap_reason($) { return field($_[0], 'noswap_reason');}
sub noidleswap_reason($){ return field($_[0], 'noidleswap_reason');}
sub idleswap_timeout($) { return field($_[0], 'idleswap_timeout');}
sub autoswap_timeout($) { return field($_[0], 'autoswap_timeout');}
sub prerender_pid($) { return field($_[0], 'prerender_pid');}
sub dpdb($) { return field($_[0], 'dpdb');}
sub dpdbname($) { return field($_[0], 'dpdbname');}
sub dpdbpassword($) { return field($_[0], 'dpdbpassword');}
sub instance_idx($) { return field($_[0], 'instance_idx'); }
sub creator_idx($) { return field($_[0], 'creator_idx');}
sub swapper_idx($) { return field($_[0], 'swapper_idx');}
sub use_ipassign($) { return field($_[0], 'use_ipassign');}
sub ipassign_args($) { return field($_[0], 'ipassign_args');}
sub security_level($) { return field($_[0], 'security_level');}
sub linktest_pid($) { return field($_[0], 'linktest_pid');}
sub linktest_level($) { return field($_[0], 'linktest_level');}
sub logfile($) { return field($_[0], 'logfile');}
sub eventkey($) { return field($_[0], 'eventkey');}
sub keyhash($) { return field($_[0], 'keyhash');}
sub paniced($) { return field($_[0], 'paniced');}
sub cpu_usage($) { return field($_[0], 'cpu_usage');}
sub encap_style($) { return field($_[0], 'encap_style');}
sub minimum_nodes($) { return field($_[0], 'minimum_nodes');}
sub maximum_nodes($) { return field($_[0], 'maximum_nodes');}
sub multiplex_factor($) { return field($_[0], 'multiplex_factor');}
sub delay_capacity($) { return field($_[0], 'delay_capacity');}
sub virtnode_count($) { return field($_[0], 'virtnode_count');}
sub archive_idx($) { return stats($_[0], 'archive_idx'); }
sub swapin_count($) { return stats($_[0], 'swapin_count'); }
sub destroyed($) { return stats($_[0], 'destroyed'); }
sub archive_tag($) { return resources($_[0], 'archive_tag'); }
sub thumbnail($) { return resources($_[0], 'thumbnail'); }
sub swapin_time($) { return resources($_[0], 'swapin_time'); }
sub swapout_time($) { return resources($_[0], 'swapout_time'); }
sub lastidx($) { return resources($_[0], 'lastidx'); }
sub input_data_idx($) { return resources($_[0], 'input_data_idx'); }
# Break circular reference someplace to avoid exit errors.
sub DESTROY {
my $self = shift;
$self->{"EXPT"} = undef;
$self->{"STATS"} = undef;
$self->{"RSRC"} = undef;
$self->{'VIRTEXPT'} = undef;
}
#
# For canceled, goto to the DB.
......
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2007, 2008 University of Utah and the Flux Group.
# Copyright (c) 2007-2010 University of Utah and the Flux Group.
# All rights reserved.
#
package Image;
......@@ -139,6 +139,7 @@ sub ezid($) { return field($_[0], "ezid"); }
sub shared($) { return field($_[0], "shared"); }
sub global($) { return field($_[0], "global"); }
sub updated($) { return field($_[0], "updated"); }
sub mbr_version($) { return field($_[0], "mbr_version"); }
sub access_key($) { return field($_[0], "access_key"); }
#
......
......@@ -1191,6 +1191,7 @@ sub issimnode($) { return NodeTypeInfo($_[0])->issimnode(); }
sub isgeninode($) { return NodeTypeInfo($_[0])->isgeninode(); }
sub isfednode($) { return NodeTypeInfo($_[0])->isfednode(); }
sub isdedicatedremote($) { return NodeTypeInfo($_[0])->isdedicatedremote(); }
sub isswitch($) { return NodeTypeInfo($_[0])->isswitch(); }
#
# And these are the less common attributes, but still common enough to
......
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2005-2009 University of Utah and the Flux Group.
# Copyright (c) 2005-2010 University of Utah and the Flux Group.
# All rights reserved.
#
package NodeType;
......@@ -82,6 +82,7 @@ sub isplabphysnode($) { return field($_[0], 'isplabphysnode'); }
sub issimnode($) { return field($_[0], 'issimnode'); }
sub isgeninode($) { return field($_[0], 'isgeninode'); }
sub isfednode($) { return field($_[0], 'isfednode'); }
sub isswitch($) { return field($_[0], 'isswitch'); }
#
# Force a reload of the data.
......
......@@ -71,6 +71,10 @@ my %WAITTIMES = ("Linux" => 120,
# OP modes. Mirrored in the web interface. The value is a user-okay flag.
my %OPMODES = ("NORMALv2" => 1,
"NORMALv1" => 0,
"PXEFBSD" => 0,
"RELOAD" => 0,
"OPSNODEBSD" => 0,
"PCVM" => 0,
"MINIMAL" => 1,
"NORMAL" => 1,
"ALWAYSUP" => 1 );
......@@ -573,6 +577,16 @@ sub ResolveNextOSID($;$)
return OSinfo->Lookup($osid);
}
#
# Set the nextosid.
#
sub SetNextOS($$)
{
my ($self, $nextosinfo) = @_;
return $self->Update({"nextosid" => $nextosinfo->osid()});
}
#
# Check if a particular feature is supported.
#
......
......@@ -41,7 +41,7 @@ delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
# Turn off line buffering on output
$| = 1;
use lib "@prefix@/lib";
use lib "/usr/testbed/lib";
use libdb;
use libtestbed;
use NodeType;
......@@ -50,6 +50,9 @@ my $CRTLTAG = TBDB_IFACEROLE_CONTROL();
my $DHCPD_CONF = "/usr/local/etc/dhcpd.conf";
my $DHCPD_TEMPLATE = "/usr/local/etc/dhcpd.conf.template";
my %servernodes = ();
my %dhcp_subbosses = ();
my %tftp_subbosses = ();
my %bootinfo_subbosses = ();
my %singlectlnet = ();
my $template = $DHCPD_TEMPLATE;
my $outfile = "/tmp/dhcpd_makeconf.$$";
......@@ -155,6 +158,28 @@ while (my %row = $query_result->fetchhash()) {
}
}
# Slurp in all of the subboss data to know A) if we should serve the DHCP
# lease to a given node, or if the next-server field should be something
# other than the IP for boss.
$query_result =
DBQueryWarn("select s.node_id, s.service, s.subboss_id, i.IP ".
"from subbosses as s left join interfaces as i on ".
"s.subboss_id=i.node_id where i.role='$CRTLTAG'");
if (! $query_result) {
fatal("Could not dhcpd data from DB!");
}
while (my %row = $query_result->fetchhash()) {
my $node_id = $row{"node_id"};
if ($row{"service"} eq 'tftp') {
$tftp_subbosses{$node_id} = $row{"IP"};
} elsif ($row{"service"} eq 'dhcp') {
$dhcp_subbosses{$node_id} = $row{"IP"};
} elsif ($row{"service"} eq 'bootinfo') {
$bootinfo_subbosses{$node_id} = $row{"IP"};
}
}
open(IF,"<$template") or
fatal("Unable to open $template for reading");
while (<IF>) {
......@@ -239,47 +264,25 @@ while (<IF>) {
}
}
}
elsif (defined $dhcp_subbosses{$node_id}) {
$hostname =
"${spaces}\toption host-name \"$node_id\";\n";
$booting = "${spaces}\tignore booting;\n";
}
else {
$hostname =
"${spaces}\toption host-name \"$node_id\";\n";
my $query_result =
DBQueryWarn( "(select attrvalue from " .
"node_attributes where node_id = '$node_id' " .
" and attrkey = 'tftp_server' ) union " .
"(select attrvalue from " .
"node_type_attributes where type = " .
"'$nodetype' " .
" and attrkey = 'tftp_server') limit 1" );
if (! $query_result) {
fatal("Could not get tftp_server data from DB!");
}
if (my %row = $query_result->fetchhash()) {
my $tftp_server = $row{'attrvalue'};
$next_server = "${spaces}\tnext-server " .
$tftp_server . ";\n";
}
if (defined $tftp_subbosses{$node_id}) {
$next_server = "${spaces}\tnext-server " .
$tftp_subbosses{$node_id} . ";\n";
}
$query_result =
DBQueryWarn( "(select attrvalue from " .
"node_attributes where node_id = '$node_id' " .
" and attrkey = 'bootinfo_server' ) union " .
"(select attrvalue from " .
"node_type_attributes where type = " .
"'$nodetype' " .
" and attrkey = 'bootinfo_server') limit 1" );
if (! $query_result) {
fatal("Could not get bootinfo_server data from DB!");
}
if (defined $bootinfo_subbosses{$node_id}) {
$bootinfo_server = "${spaces}\toption PXE.emulab-bootinfo " .
$bootinfo_subbosses{$node_id} . ";\n";
}
if (my %row = $query_result->fetchhash()) {
$bootinfo_server = "${spaces}\toption " .
"PXE.emulab-bootinfo " .
$row{'attrvalue'} . ";\n";
}
}
#
......
......@@ -1307,26 +1307,6 @@ sub TBOSMaxConcurrent ($)
return $osinfo->max_concurrent();
}
#
# Returns the reboot waittime.
#
# usage: TBOSIDRebootWaittime(char *osid)
# returns >= 1 if there is a waittime
# returns undef if there is no waittime
# returns 0 if not valid.
#
sub TBOSIDRebootWaittime ($)
{
my ($osid) = @_;
require OSinfo;
my $osinfo = OSinfo->Lookup($osid);
return 0
if (!defined($osinfo));
return $osinfo->reboot_waittime();
}
#
# Returns the number of nodes that are supposedly booting an OS. A list of
# nodes that should be excluded from this count can be given.
......
<descriptors>
<osid>
<attribute name="mfs">
<value>1</value>
</attribute>
<attribute name="features">
<value>ping,ssh,ipod,isup</value>
</attribute>
<attribute name="version">
<value>6.2</value>
</attribute>
<attribute name="path">
<value>boss:/tftpboot/frisbee</value>
</attribute>
<attribute name="reboot_waittime">
<value>150</value>
</attribute>
<attribute name="description">
<value>Frisbee (FreeBSD) in an MFS</value>
</attribute>
<attribute name="mustclean">
<value>0</value>
</attribute>
<attribute name="shared">
<value>1</value>
</attribute>
<attribute name="op_mode">
<value>RELOAD</value>
</attribute>
<attribute name="pid">
<value>emulab-ops</value>
</attribute>
<attribute name="osname">
<value>FRISBEE-MFS</value>
</attribute>
<attribute name="OS">
<value>FreeBSD</value>
</attribute>
</osid>
<osid>
<attribute name="mfs">
<value>1</value>
</attribute>
<attribute name="features">
<value>ping,ssh,ipod,isup</value>
</attribute>
<attribute name="version">
<value>4.X</value>
</attribute>
<attribute name="reboot_waittime">
<value>150</value>
</attribute>
<attribute name="description">
<value>FreeBSD on the Operations Node</value>
</attribute>
<attribute name="mustclean">
<value>0</value>
</attribute>
<attribute name="op_mode">
<value>OPSNODEBSD</value>
</attribute>
<attribute name="shared">
<value>1</value>
</attribute>
<attribute name="pid">
<value>emulab-ops</value>
</attribute>
<attribute name="osname">
<value>OPSNODE-BSD</value>
</attribute>
<attribute name="OS">
<value>FreeBSD</value>
</attribute>
</osid>
<osid>
<attribute name="mfs">
<value>1</value>
</attribute>
<attribute name="features">
<value>ping,ssh,ipod,isup</value>
</attribute>
<attribute name="version">
<value>6.2</value>
</attribute>
<attribute name="path">
<value>boss:/tftpboot/freebsd.newnode</value>
</attribute>
<attribute name="reboot_waittime">
<value>150</value>
</attribute>
<attribute name="description">
<value>NewNode (FreeBSD) in an MFS</value>
</attribute>
<attribute name="mustclean">
<value>0</value>
</attribute>
<attribute name="shared">
<value>1</value>
</attribute>
<attribute name="op_mode">
<value>PXEFBSD</value>
</attribute>
<attribute name="pid">
<value>emulab-ops</value>
</attribute>
<attribute name="osname">
<value>NEWNODE-MFS</value>
</attribute>
<attribute name="OS">
<value>FreeBSD</value>
</attribute>
</osid>
<osid>
<attribute name="mfs">
<value>1</value>
</attribute>
<attribute name="features">
<value>ping,ssh,ipod,isup</value>
</attribute>
<attribute name="version">
<value>6.2</value>
</attribute>
<attribute name="path">
<value>boss:/tftpboot/freebsd</value>
</attribute>
<attribute name="reboot_waittime">
<value>150</value>
</attribute>
<attribute name="description">
<value>FreeBSD in an MFS</value>
</attribute>
<attribute name="mustclean">
<value>0</value>
</attribute>
<attribute name="shared">
<value>1</value>
</attribute>
<attribute name="op_mode">
<value>PXEFBSD</value>
</attribute>
<attribute name="pid">
<value>emulab-ops</value>
</attribute>
<attribute name="osname">
<value>FREEBSD-MFS</value>
</attribute>
<attribute name="OS">
<value>FreeBSD</value>
</attribute>
</osid>
</descriptors>