#!/usr/bin/perl -w # # Copyright (c) 2003-2012 University of Utah and the Flux Group. # # {{{EMULAB-LICENSE # # This file is part of the Emulab network testbed software. # # This file is free software: you can redistribute it and/or modify it # under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or (at # your option) any later version. # # This file is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public # License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this file. If not, see . # # }}} # 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: addspecialdevice -t [-s count] \n"; print STDERR "Options:\n"; print STDERR " -d - Turn on debugging\n"; print STDERR " -n - Dry run mode\n"; print STDERR " -s count - Node is to be shared, provide capacity\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 = $options{'s'}; } 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. # my $nodetype = NodeType->Lookup($type); if (!defined($nodetype)) { CreateType($type, 0); if ($isshared) { CreateType("${type}-vm", 1); } $nodetype = NodeType->Lookup($type); } CreateNode(); exit(0); # # Add a new node type. # sub CreateType($$) { my ($type, $isvirt) = @_; my $osid = ($isvirt ? $osinfo_vm->osid() : $osinfo->osid()); # # 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'"); if (0 && $isshared && $isvirt) { DBQueryFatal("replace into node_auxtypes values ". "('$node_id', '$type', '$isshared')"); } } # # Device nodes are neither rebootable nor imageable. # if ($debug || $impotent) { print "Adding false attributes rebootable/imageable\n"; print "Adding true attribute fakenode\n"; print "Setting default osid: " . ($isvirt ? $osinfo_vm->osname() : $osinfo->osname()) . "\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')"); DBQueryFatal("replace into node_type_attributes values ". " ('$type','default_osid','$osid','integer')"); if ($isshared && !$isvirt) { DBQueryFatal("replace into node_type_attributes values ". " ('$type','virtnode_capacity', ". " '$isshared','integer')"); } } return 0; } # # Create the node. # sub CreateNode() { my $blob = { "type" => $type, "role" => ($nodetype->isswitch() ? "testswitch" : "testnode"), "initial_eventstate" => 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"); }