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 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