Commit 146d7329 authored by Leigh B Stoller's avatar Leigh B Stoller

Initial commit at putting XEN vhosts into the manifest (issue #181) so

that they can be displayed and accounted.
parent 5fc4edb0
......@@ -739,7 +739,10 @@ sub ComputeNodeCounts($)
my $vcount = 0;
foreach my $ref (GeniXML::FindNodes("n:node",
$manifest)->get_nodelist()) {
$manifest)->get_nodelist(),
GeniXML::FindNodesNS("n:vhost",
$manifest,
$GeniXML::EMULAB_NS)->get_nodelist()) {
my $virtualization_type = GeniXML::GetVirtualizationSubtype($ref);
my $manager_urn = GetManagerId($ref);
......
......@@ -970,7 +970,9 @@ sub DoConsole()
if (! defined($manifest)) {
fatal("Could not parse manifest for $obj");
}
my @nodes = GeniXML::FindNodes("n:node", $manifest)->get_nodelist();
my @nodes = (GeniXML::FindNodes("n:node", $manifest)->get_nodelist(),
GeniXML::FindNodesNS("n:vhost", $manifest,
$GeniXML::EMULAB_NS)->get_nodelist());
foreach my $node (@nodes) {
my $client_id = GeniXML::GetVirtualId($node);
my $urn = GeniXML::GetSliverId($node);
......@@ -2350,7 +2352,9 @@ sub DoRebootOrReload($)
if (! defined($manifest)) {
fatal("Could not parse manifest");
}
my @nodes = GeniXML::FindNodes("n:node", $manifest)->get_nodelist();
my @nodes = (GeniXML::FindNodes("n:node", $manifest)->get_nodelist(),
GeniXML::FindNodesNS("n:vhost", $manifest,
$GeniXML::EMULAB_NS)->get_nodelist());
foreach my $node (@nodes) {
my $client_id = GeniXML::GetVirtualId($node);
if (grep {$_ eq $client_id} @ARGV) {
......
......@@ -916,6 +916,8 @@ sub GetTicketAuxAux($$$$$$$$$$$)
my @nodeids = ();
my %lannodes = ();
my %allnodes = ();
# Extra nodes (like XEN vhosts).
my %internal_nodemap = ();
# For stitching, keep track of external nodes and links.
my %external_nodemap = ();
my %external_linkmap = ();
......@@ -3039,9 +3041,18 @@ sub GetTicketAuxAux($$$$$$$$$$$)
#
my $exclusive = (defined($node->sharing_mode()) ? "0" : "1");
#
# Watch for dedicated XEN vhost nodes. We add those to the manifest
# later, and as real sliver objects when the ticket is redeemed.
#
if ($node->isvirtnode() && $exclusive && !defined($instantiate_on)) {
# Marker for below.
$internal_nodemap{$node->phys_nodeid()} = undef;
}
# Set sliver urns in ticket
my $sliver_idx = TBGetUniqueIndex('next_sliver', 1);
my $sliver_urn = GeniHRN::Generate( "@OURDOMAIN@", "sliver", $sliver_idx );
my $sliver_urn = GeniHRN::Generate($OURDOMAIN, "sliver", $sliver_idx);
if (GeniXML::IsVersion0($rspec)) {
GeniXML::SetText("component_urn", $rspec,
......@@ -3125,6 +3136,23 @@ sub GetTicketAuxAux($$$$$$$$$$$)
}
}
#
# Add the internal nodes to the manifest.
#
foreach my $nodeid (keys(%internal_nodemap)) {
my $pnode = Node->Lookup($nodeid);
if (!defined($pnode)) {
$response = GeniResponse->Create(GENIRESPONSE_ERROR, undef);
goto bad;
}
my $vhost = AddInternalNodeToRspec($rspec, $pnode);
if (!defined($vhost)) {
$response = GeniResponse->Create(GENIRESPONSE_ERROR, undef);
goto bad;
}
$internal_nodemap{$nodeid} = $vhost;
}
# Store the virt topo again since we changed it above.
$virtexperiment->Dump();
if ($virtexperiment->Store()) {
......@@ -3714,6 +3742,9 @@ sub SliverWorkAux($$$$$$$$)
my @freelinks= ();
my %iface2node = ();
my $needplabslice = 0;
# Extra nodes (like XEN vhosts).
my %internal_nodemap = ();
my @freevhosts = ();
# For stitching, keep track of external nodes and links.
my %external_nodemap = ();
my %external_linkmap = ();
......@@ -3759,6 +3790,9 @@ sub SliverWorkAux($$$$$$$$)
if (ref($s) eq "GeniSliver::Node") {
$nodemap{$s->nickname()} = $s;
}
if (ref($s) eq "GeniSliver::Vhost") {
$internal_nodemap{$s->nickname()} = $s;
}
elsif (ref($s) eq "GeniAggregate::Link" ||
ref($s) eq "GeniAggregate::Tunnel") {
# XXX See the constructor in GeniAggregate.
......@@ -3919,6 +3953,26 @@ sub SliverWorkAux($$$$$$$$)
}
}
#
# What vhost slivers need to be deleted.
#
foreach my $nickname (keys(%internal_nodemap)) {
my $sliver = $internal_nodemap{$nickname};
my $needfree = 1;
foreach my $ref (GeniXML::FindNodesNS("n:vhost", $rspec,
$GeniXML::EMULAB_NS)->get_nodelist()) {
my $virtual_id = GeniXML::GetVirtualId($ref);
if (defined($virtual_id) && $nickname eq $virtual_id) {
$needfree = 0;
last;
}
}
if ($needfree) {
push(@freevhosts, $sliver);
}
}
#
# We are actually an Aggregate, so return an aggregate of slivers,
# even if there is just one node. This makes sliceupdate easier.
......@@ -4188,6 +4242,59 @@ sub SliverWorkAux($$$$$$$$)
}
}
}
#
# Create slivers for internal nodes.
#
foreach my $ref (GeniXML::FindNodesNS("n:vhost", $rspec,
$GeniXML::EMULAB_NS)->get_nodelist()) {
my $resource_id = GeniXML::GetNodeId($ref);
my $vnode_id = GeniXML::GetVnodeId($ref);
my $virtual_id = GeniXML::GetVirtualId($ref);
my $manager_id = GeniXML::GetManagerId($ref);
my $inaggregate = 0;
my $sliver;
my $node = GeniUtil::LookupNode($vnode_id);
if (!defined($node)) {
$message = "Unknown vnode_id in ticket: $vnode_id";
goto bad;
}
# Must do this after mapper has run
$node->Refresh();
if (grep {$_ eq $virtual_id} keys(%internal_nodemap)) {
#
# Already in the aggregate, so reuse sliver.
#
$inaggregate = 1;
$sliver = $internal_nodemap{$virtual_id};
}
else {
$sliver = GeniSliver::Vhost->Create($slice, $owner, $node, $ref);
if (!defined($sliver)) {
$message = "Could not create GeniSliver object for $virtual_id";
goto bad;
}
$slivers{$sliver->uuid()} = $sliver;
$internal_nodemap{$virtual_id} = $sliver;
# Add to the aggregate.
if ($sliver->SetAggregate($aggregate) != 0) {
$message = "Could not set aggregate for $sliver to $aggregate";
goto bad;
}
}
my $node_manifest = $sliver->AnnotateManifest();
if (! defined($node_manifest)) {
$message = "Could not annotate sliver for $virtual_id";
goto bad;
}
# And store into the new manifest.
my $oldnode = GeniXML::GetVhostByVirtualId($virtual_id, $manifest);
my $newnode = GeniXML::ReplaceNode($oldnode, $node_manifest);
}
#
# Now do the links. For each link, we have to add a sliver for the
......@@ -4802,6 +4909,10 @@ sub SliverWorkAux($$$$$$$$)
$snode->UnProvision();
$snode->Delete(0);
}
foreach my $svhost (@freevhosts) {
$svhost->UnProvision();
$svhost->Delete(0);
}
$ticket->Redeem()
if (defined($ticket));
$aggregate->SetRegistered(0);
......@@ -6686,6 +6797,7 @@ sub CleanupDeadSlice($;$)
return -1;
}
if ($ticket->Release(TICKET_PURGED)) {
# Leave it locked.
print STDERR "CleanupDeadSlice: Could not release $ticket\n";
return -1;
}
......@@ -7976,5 +8088,38 @@ sub AddProgramAgent($$$)
return 0;
}
#
# Add a node to an rspec at top level. The rspec is the document and
# the node is an emulab Node object. The rspec is modified, we return
# the new node element.
#
sub AddInternalNodeToRspec($$)
{
my ($rspec, $node) = @_;
my $newnode = GeniXML::AddElement("vhost", $rspec, $GeniXML::EMULAB_NS);
return undef
if (!defined($newnode));
GeniXML::SetText('client_id', $newnode, $node->vname());
# I am assuming that we would never do this for a shared node.
GeniXML::SetText('exclusive', $newnode, "1");
GeniXML::SetText('component_manager_id', $newnode, $ENV{'MYURN'});
GeniXML::SetText("component_id", $newnode,
GeniHRN::Generate($OURDOMAIN, "node",
$node->phys_nodeid()));
# Extra stuff in Emulab namespace.
my $vnoderef = GeniXML::AddElement("vnode", $newnode, $GeniXML::EMULAB_NS);
GeniXML::SetText("name", $vnoderef, $node->node_id());
GeniXML::SetText("hardware_type", $vnoderef, $node->type());
# Set sliver urns in ticket
my $sliver_idx = TBGetUniqueIndex('next_sliver', 1);
my $sliver_urn = GeniHRN::Generate("@OURDOMAIN@", "sliver", $sliver_idx);
GeniXML::SetText("sliver_id", $newnode, $sliver_urn);
return $newnode;
}
# _Always_ make sure that this 1 is at the end of the file...
1;
......@@ -747,10 +747,13 @@ sub resource_urn($)
return GeniHRN::Generate("@OURDOMAIN@", "node", $self->resource_id())
}
sub Create($$$$$$)
sub Create($$$$$;$)
{
# $rspec is a LibXML element representing a single node.
my ($class, $slice, $user, $node, $rspec) = @_;
my ($class, $slice, $user, $node, $rspec, $resource_type) = @_;
$resource_type = "Node"
if (!defined($resource_type));
my $virtualization_type = GeniXML::GetVirtualizationType($rspec);
if (!defined($virtualization_type)) {
print STDERR "Node does not contain a virtualization_type\n";
......@@ -789,7 +792,8 @@ sub Create($$$$$$)
my $resource_id = $node->node_id();
my $hrn = "${PGENIDOMAIN}." . $node->node_id();
my $sliver = GeniSliver->Create($slice, $user, $resource_uuid, "Node",
my $sliver = GeniSliver->Create($slice, $user, $resource_uuid,
$resource_type,
$resource_id, $hrn, $nickname, $rspec);
return undef
if (!defined($sliver));
......@@ -1633,6 +1637,36 @@ sub GenerateStatusBlob($)
return $blob;
}
##########################################################################
#
package GeniSliver::Vhost;
use vars qw(@ISA);
@ISA = "GeniSliver::Node";
use GeniDB;
use GeniComponent;
use GeniSlice;
use GeniCredential;
use GeniCertificate;
use GeniUtil;
#
# This is a wrapper so that we can represent internally added hosts
# but not treat them like normal nodes when doing rspec/manifest things.
#
sub Create($$$$$)
{
my ($class, $slice, $user, $node, $rspec) = @_;
return GeniSliver::Node->Create($slice, $user, $node, $rspec, "Vhost");
}
# Nothing to do right now.
sub UnProvision($$)
{
return 0;
}
##########################################################################
#
package GeniSliver::Interface;
......
......@@ -856,6 +856,10 @@ sub Release($$)
#
$experiment->ClearUnusedReservedVlanTags();
# Make sure we have nothing in the Node cache, since we probably
# released the slivers before we called this.
Node->FlushAll();
#
# Release nodes.
#
......
......@@ -154,11 +154,24 @@ sub GetXmlVersion($)
sub IsVersion0($)
{
my ($node) = @_;
#
# Yuck, we call this all over the place, but if the thing we call
# it on (say, an emulab:vhost) is in its own namespace, then the
# test above in GetXmlVersion makes no sense and fails.
#
my $ns = $node->namespaceURI();
return 0
if (defined($ns) &&
$ns !~ /protogeni.net\/resources\/rspec\/[\d\.]+$/);
my $version = GetXmlVersion($_[0]);
return defined($version)
&& ($version eq $RSPEC_0_1 || $version eq $RSPEC_0_2);
}
# Returns a NodeList for a given XPath using a given node as
# context. 'n' is defined to be the prefix for the namespace of the
# node.
......@@ -282,6 +295,14 @@ sub GetNodeByVirtualId($$)
return GetElementByVirtualId($name, 'node', $node);
}
sub GetVhostByVirtualId($$)
{
my ($name, $node) = @_;
return FindNodesNS('n:vhost[@client_id = "'.$name.'"]',
$node, $EMULAB_NS)->pop();
}
sub GetLinkByVirtualId($$)
{
my ($name, $node) = @_;
......
......@@ -1484,22 +1484,28 @@ $(function ()
var ProcessNodes = function(aggregate_urn, xml) {
// Find all of the nodes, and put them into the list tab.
// Clear current table.
$(xml).find("node").each(function() {
$(xml).find("node, emulab\\:vhost").each(function() {
// Only nodes that match the aggregate being processed,
// since we send the same rspec to every aggregate.
var manager_urn = $(this).attr("component_manager_id");
if (!manager_urn.length || manager_urn != aggregate_urn) {
return;
}
var tag = $(this).prop("tagName");
var isvhost= (tag == "emulab:vhost" ? 1 : 0);
var node = $(this).attr("client_id");
var login = $(this).find("login");
var stype = $(this).find("sliver_type");
var login = $(this).find("login");
var coninfo= this.getElementsByTagNameNS(EMULAB_NS, 'console');
var vnode = this.getElementsByTagNameNS(EMULAB_NS, 'vnode');
var href = "n/a";
var ssh = "n/a";
var cons = "n/a";
var clone = $(listview_row);
// Cause of nodes in the emulab namespace (vhost).
if (!login.length) {
login = this.getElementsByTagNameNS(EMULAB_NS, 'login');
}
// Change the ID of the clone so its unique.
clone.attr('id', 'listview-row-' + node);
......@@ -1525,8 +1531,8 @@ $(function ()
if (login.length && dossh) {
var user = window.APT_OPTIONS.thisUid;
var host = login.attr("hostname");
var port = login.attr("port");
var host = $(login).attr("hostname");
var port = $(login).attr("port");
var url = "ssh://" + user + "@" + host + ":" + port +"/";
var sshcmd = "ssh -p " + port + " " + user + "@" + host;
href = "<a href='" + url + "'><kbd>" + sshcmd +
......@@ -1579,20 +1585,29 @@ $(function ()
$('#listview-row-' + node + ' [name=console]')
.parent().addClass('disabled');
}
//
// And a handler for the snapshot action.
//
$('#listview-row-' + node + ' [name=snapshot]')
.click(function (e) {
ActionHandler("snapshot", [node]);
});
//
// Ditto the delete button,
//
$('#listview-row-' + node + ' [name=delete]')
.click(function (e) {
ActionHandler("delete", [node]);
});
if (!isvhost) {
//
// And a handler for the snapshot action.
//
$('#listview-row-' + node + ' [name=snapshot]')
.click(function (e) {
ActionHandler("snapshot", [node]);
});
//
// Ditto the delete button,
//
$('#listview-row-' + node + ' [name=delete]')
.click(function (e) {
ActionHandler("delete", [node]);
});
}
else {
// Need to do this on the context menu too, but painful.
$('#listview-row-' + node + ' [name=snapshot]')
.parent().addClass('disabled');
$('#listview-row-' + node + ' [name=delete]')
.parent().addClass('disabled');
}
/*
* Make a copy of the master context menu and init.
......
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