diff --git a/protogeni/lib/GeniAggregate.pm.in b/protogeni/lib/GeniAggregate.pm.in
index 122498edc190d9b2e4b84006e33506b3c20dd46e..e59ddd169a868832f85760a3d3101b803e6f379f 100644
--- a/protogeni/lib/GeniAggregate.pm.in
+++ b/protogeni/lib/GeniAggregate.pm.in
@@ -220,6 +220,16 @@ sub Delete($)
return 0;
}
+#
+# Cons up an hrn.
+#
+sub hrn($)
+{
+ my ($self) = @_;
+
+ return $OURDOMAIN . ".aggregates." . $self->idx();
+}
+
#
# Look up a list of aggregates for a locally instantiated slice.
# Used by the CM.
@@ -258,9 +268,11 @@ sub SliverList($$)
return -1
if (! (ref($self) && ref($pref)));
- my $idx = $self->idx();
+ my $idx = $self->idx();
+ my $uuid = $self->uuid();
my $query_result =
- DBQueryWarn("select idx from geni_slivers where aggregate_idx='$idx'");
+ DBQueryWarn("select idx from geni_slivers ".
+ "where aggregate_uuid='$uuid'");
return -1
if (!$query_result);
@@ -530,31 +542,23 @@ sub Provision($;$)
print STDERR "Could not map $self to its experiment\n";
return -1;
}
- my $sliver0 = $slivers[0];
- my $sliver1 = $slivers[1];
- my $interface0 = Interface->LookupByUUID($sliver0->resource_uuid());
- my $interface1 = Interface->LookupByUUID($sliver1->resource_uuid());
- if (! defined($interface0)) {
- print STDERR "Could not map $sliver0 to its object\n";
- return -1;
- }
- if (! defined($interface1)) {
- print STDERR "Could not map $sliver1 to its object\n";
- return -1;
- }
my $vlan = VLan->Create($experiment, $self->uuid());
if (!defined($vlan)) {
print STDERR "Could not create vlan for $self\n";
- return -1;
- }
- if (! $vlan->AddMember($interface0->node_id(), $interface0->iface())) {
- print STDERR "$self: Could not add $interface0 to $vlan\n";
goto bad;
}
- if (! $vlan->AddMember($interface1->node_id(), $interface1->iface())) {
- print STDERR "$self: Could not add $interface1 to $vlan\n";
- goto bad;
+
+ foreach my $sliver (@slivers) {
+ my $interface = Interface->LookupByUUID($sliver->resource_uuid());
+ if (! defined($interface)) {
+ print STDERR "Could not map $sliver to its interface object\n";
+ goto bad;
+ }
+ if (! $vlan->AddMember($interface->node_id(), $interface->iface())) {
+ print STDERR "$self: Could not add $interface to $vlan\n";
+ goto bad;
+ }
}
if ($vlan->Instantiate() != 0) {
print STDERR "$self: Could not instantiate $vlan on switches\n";
@@ -591,18 +595,7 @@ sub UnProvision($)
print STDERR "Could not map $self to its experiment\n";
return -1;
}
- my $sliver0 = $slivers[0];
- my $sliver1 = $slivers[1];
- my $interface0 = Interface->LookupByUUID($sliver0->resource_uuid());
- my $interface1 = Interface->LookupByUUID($sliver1->resource_uuid());
- if (! defined($interface0)) {
- print STDERR "Could not map $sliver0 to its object\n";
- return -1;
- }
- if (! defined($interface1)) {
- print STDERR "Could not map $sliver1 to its object\n";
- return -1;
- }
+
my $vlan = VLan->Lookup($experiment, $self->uuid());
if (! defined($vlan)) {
print STDERR "Could not map self to its vlan object\n";
diff --git a/protogeni/lib/GeniCM.pm.in b/protogeni/lib/GeniCM.pm.in
index 691977e5aec04902fde3266180fc8179f60d52a2..e2ed65d0a739d55988682ed2828c7e6e12969ab8 100644
--- a/protogeni/lib/GeniCM.pm.in
+++ b/protogeni/lib/GeniCM.pm.in
@@ -121,6 +121,7 @@ sub Resolve($)
# Return a blob.
my $blob = { "hrn" => "${OURDOMAIN}." . $node->node_id(),
"uuid" => $node->uuid(),
+ "role" => $node->role(),
};
#
@@ -134,15 +135,23 @@ sub Resolve($)
my @iblobs = ();
foreach my $interface (@interfaces) {
+ next
+ if (!defined($interface->switch_id()));
+
my $iblob = { "uuid" => $interface->uuid(),
"iface" => $interface->iface(),
"type" => $interface->type(),
"card" => $interface->card(),
"port" => $interface->port(),
"role" => $interface->role(),
- "IP" => $interface->IP(),
- "mask" => $interface->mask(),
+ "IP" => $interface->IP() || "",
+ "mask" => $interface->mask() || "",
"MAC" => $interface->mac(),
+ "switch_id" => "${OURDOMAIN}." .
+ $interface->switch_id(),
+ "switch_card" => $interface->switch_card(),
+ "switch_port" => $interface->switch_port(),
+ "wire_type" => $interface->wire_type(),
};
push(@iblobs, $iblob);
@@ -505,6 +514,8 @@ sub RedeemTicket($)
}
}
+ print Dumper($ticket->rspec());
+
#
# Now for each resource (okay, node) in the ticket create a sliver and
# add it to the aggregate.
@@ -550,14 +561,11 @@ sub RedeemTicket($)
my $linkendpoints =
$ticket->rspec()->{'link'}->{$linkname}->{'LinkEndPoints'};
- my $src_interface_spec = $linkendpoints->{'source_interface'};
- my $dst_interface_spec = $linkendpoints->{'destination_interface'};
-
- my @interfaces = ($src_interface_spec, $dst_interface_spec);
- foreach my $iface (@interfaces) {
- my $node_uuid = $iface->{'node_uuid'};
- my $iface = $iface->{'iface_name'};
- my $nodesliver= $slivers{$node_uuid};
+ foreach my $ifacename (keys(%{ $linkendpoints })) {
+ my $iface = $linkendpoints->{$ifacename};
+ my $node_uuid = $iface->{'node_uuid'};
+ my $iface_name = $iface->{'iface_name'};
+ my $nodesliver = $slivers{$node_uuid};
if (!defined($nodesliver)) {
$message = "Link $linkname specifies a non-existent node";
goto bad;
@@ -567,9 +575,9 @@ sub RedeemTicket($)
$message = "Could not find node object for $node_uuid";
goto bad;
}
- my $interface = Interface->LookupByIface($nodeobject, $iface);
+ my $interface = Interface->LookupByIface($nodeobject, $iface_name);
if (!defined($interface)) {
- $message = "No such interface $iface on node $nodeobject";
+ $message = "No such interface $iface_name on node $nodeobject";
goto bad;
}
my $sliver = GeniSliver::Interface->Create($slice,
@@ -589,8 +597,9 @@ sub RedeemTicket($)
}
#
- # Now do the provisioning (note that we actually allocated the node
- # above when the ticket was granted). The add the sliver to the aggregate.
+ # Now do the provisioning (note that we actually allocated the
+ # node above when the ticket was granted). Then add the sliver to
+ # the aggregate.
#
foreach my $sliver (values(%slivers)) {
if (!$impotent && $sliver->Provision($extraargs) != 0) {
@@ -1060,3 +1069,66 @@ sub DeleteSlice($)
}
return GeniResponse->Create(GENIRESPONSE_SUCCESS);
}
+
+#
+# Split an aggregated sliver into its separate parts and return a list.
+#
+sub SplitSliver($)
+{
+ my ($argref) = @_;
+ my $cred = $argref->{'credential'};
+ my $impotent = $argref->{'impotent'};
+
+ $impotent = 0
+ if (!defined($impotent));
+
+ if (!defined($cred)) {
+ return GeniResponse->Create(GENIRESPONSE_BADARGS);
+ }
+ my $credential = GeniCredential->CreateFromSigned($cred);
+ if (!defined($credential)) {
+ return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
+ "Could not create GeniCredential object");
+ }
+ my $sliver_uuid = $credential->this_uuid();
+ my $user_uuid = $credential->owner_uuid();
+
+ #
+ # Make sure the credential was issued to the caller.
+ #
+ if ($credential->owner_uuid() ne $ENV{'GENIUUID'}) {
+ return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
+ "This is not your credential!");
+ }
+ my $user = GeniUser->Lookup($user_uuid);
+ if (!defined($user)) {
+ $user = CreateUserFromRegistry($user_uuid);
+ if (!defined($user)) {
+ print STDERR "No user $user_uuid in the ClearingHouse\n";
+ return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
+ "No user record for $user_uuid");
+ }
+ }
+
+ my $aggregate = GeniAggregate->Lookup($sliver_uuid);
+ if (!defined($aggregate)) {
+ return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
+ "No such aggregate $sliver_uuid");
+ }
+ my @sliver_list = ();
+ if ($aggregate->SliverList(\@sliver_list) != 0) {
+ return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
+ "Could not get slivers for $aggregate");
+ }
+ my @credentials = ();
+
+ foreach my $sliver (@sliver_list) {
+ my $credential = $sliver->NewCredential($user);
+ if (!defined($credential)) {
+ return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
+ "Could not create credential for $sliver");
+ }
+ push(@credentials, $credential->asString());
+ }
+ return GeniResponse->Create(GENIRESPONSE_SUCCESS, \@credentials);
+}
diff --git a/protogeni/lib/GeniComponent.pm.in b/protogeni/lib/GeniComponent.pm.in
index ba4305d8f79c97d8b50f3fdb1b6d97399f2b5dae..195cd289a8fc4245554c56ceff1764ff1987a73d 100644
--- a/protogeni/lib/GeniComponent.pm.in
+++ b/protogeni/lib/GeniComponent.pm.in
@@ -202,6 +202,19 @@ sub NewResource($$)
return 0;
}
+#
+# Compare two component refs.
+#
+sub SameComponent($$)
+{
+ my ($self, $other) = @_;
+
+ return 0
+ if (! (ref($self) && ref($other)));
+
+ return $self->idx() == $other->idx();
+}
+
#
# Refresh a class instance by reloading from the DB.
#
@@ -398,16 +411,6 @@ sub CreateSliver($$$$;$)
return undef;
}
- #
- # We need to store this credential (not the default) so we can
- # operate on the sliver later.
- #
- if ($credential->Store() != 0) {
- print STDER "Could not store $credential for new sliver\n";
- $credential->Delete();
- return undef;
- }
-
my $sliver = GeniSliver::Client->Create($slice, $ticket->owner_uuid(),
$ticket->rspec(),
$credential, $self);
@@ -475,6 +478,65 @@ sub StartSliver($$$)
return 0;
}
+#
+# Split a sliver.
+#
+sub SplitSliver($$$$)
+{
+ my ($self, $sliver, $context, $pref) = @_;
+
+ # Must be a real reference.
+ return -1
+ if (! ref($self));
+
+ my $credential = $sliver->GetCredential($context->user());
+ return -1
+ if (!defined($credential));
+
+ my $slice = $sliver->GetSlice();
+ return -1
+ if (!defined($slice));
+
+ my $response =
+ Genixmlrpc::CallMethod($self->url(), $context,
+ "SplitSliver",
+ { "credential" => $credential->asString() });
+
+ if ($response->code() != GENIRESPONSE_SUCCESS) {
+ print STDERR "Could not split sliver $sliver\n";
+ return -1;
+ }
+
+ #
+ # We get back signed credentials, which has the sliver uuid inside.
+ #
+ my @slivers = ();
+
+ foreach my $credential (@{ $response->value() }) {
+ my $credential = GeniCredential->CreateFromSigned($credential, 1);
+ if (!defined($credential)) {
+ print STDERR "Could not create local credential object.\n";
+ return -1;
+ }
+
+ my $s = GeniSliver::Client->Create($slice,
+ $credential->owner_uuid(),
+ undef,
+ $credential, $self);
+
+ if (!defined($s)) {
+ print STDERR "Could not create local sliver object.\n";
+ return -1;
+ }
+ $s->SetAggregate($sliver);
+ # XXX Kludge for Emulab aggregates
+ $s->Sethrn($credential->hrn());
+ push(@slivers, $s);
+ }
+ @$pref = @slivers;
+ return 0;
+}
+
# _Always_ make sure that this 1 is at the end of the file...
1;
diff --git a/protogeni/lib/GeniCredential.pm.in b/protogeni/lib/GeniCredential.pm.in
index 40685ff7c4f36607a8b05bd4a62aaa0eeb6e1762..a2c7a5b0fbc0f493dea65aee64c1e75ac5b83cf4 100644
--- a/protogeni/lib/GeniCredential.pm.in
+++ b/protogeni/lib/GeniCredential.pm.in
@@ -115,6 +115,7 @@ sub Create($$$$)
$self->{'target_uuid'} = $target->uuid();
$self->{'target_cert'} = $target->cert();
$self->{'owner_uuid'} = $owner->uuid();
+ $self->{'hrn'} = $target->hrn();
$self->{'string'} = undef;
$self->{'capabilities'} = undef;
$self->{'idx'} = undef; # Only set when stored to DB.
@@ -125,6 +126,7 @@ sub Create($$$$)
# accessors
sub field($$) { return ($_[0]->{$_[1]}); }
sub idx($) { return field($_[0], "idx"); }
+sub hrn($) { return field($_[0], "hrn"); }
sub target($) { return field($_[0], "target"); }
sub owner($) { return field($_[0], "owner"); }
sub this_uuid($) { return field($_[0], "target_uuid"); }
@@ -196,7 +198,14 @@ sub CreateFromSigned($$;$)
# Use XML::Simple to convert to something we can mess with.
my $parser = XML::LibXML->new;
- my $doc = $parser->parse_string($string);
+ my $doc;
+ eval {
+ $doc = $parser->parse_string($string);
+ };
+ if ($@) {
+ print STDERR "Failed to parse credential string: $@\n";
+ return undef;
+ }
# Dig out the capabilities
my ($cap_node) = $doc->getElementsByTagName("capabilities");
@@ -219,6 +228,12 @@ sub CreateFromSigned($$;$)
return undef;
}
+ # Dig out the hrn.
+ my ($hrn_node) = $doc->getElementsByTagName("hrn");
+ return undef
+ if (!defined($hrn_node));
+ my $hrn = $hrn_node->to_literal();
+
# Dig out the owner uuid. Locally, I am not sure if we bother to
# keep users in the DB (they are in the DB at geni central).
($uuid_node) = $doc->getElementsByTagName("owner_uuid");
@@ -239,6 +254,7 @@ sub CreateFromSigned($$;$)
$self->{'target_uuid'} = $this_uuid;
$self->{'target_cert'} = $this_cert;
$self->{'owner_uuid'} = $owner_uuid;
+ $self->{'hrn'} = $hrn;
$self->{'string'} = $string;
$self->{'target'} = undef;
$self->{'owner'} = undef;
@@ -288,6 +304,7 @@ sub Sign($$)
# Every one gets a new unique index, which is used in the xml:id below.
my $idx = TBGetUniqueIndex('next_ticket', 1);
+ my $hrn = $self->hrn();
#
# Need the certificates for target and owner of the credential.
@@ -313,7 +330,10 @@ sub Sign($$)
" capability\n".
" $idx\n".
" $owner_cert\n".
+ " $target_cert\n".
" $target_cert\n".
+ " $hrn\n".
+ " 2008-05-10T09:00:00\n".
" $cap_xml\n".
"\n";
diff --git a/protogeni/lib/GeniEmulab.pm.in b/protogeni/lib/GeniEmulab.pm.in
index ca968445b5f13aff1362ca88622d3dca1bdcb827..db54052c5412ca1eeda4a616d449b7b30519a9fe 100644
--- a/protogeni/lib/GeniEmulab.pm.in
+++ b/protogeni/lib/GeniEmulab.pm.in
@@ -31,6 +31,7 @@ use libtestbed;
use User;
use Node;
use Interface;
+use Lan;
use English;
use Data::Dumper;
use Experiment;
@@ -180,36 +181,25 @@ sub AllocateSlivers($$$)
}
#
- # Loop through each node and grab a ticket for it. The nodes table
- # stores the uuid of the node as told to us in resource discovery.
- # Use this to create a simple rspec. This will need to get fancier
- # later.
- #
- # XXX We are still not using rspecs anywhere.
+ # Loop through nodes, combining nodes at the same component into a
+ # list for that component.
#
+ # Bookkeeping for the rest of this function.
+ my %components = ();
+ my %component_nodes = ();
+ my %node_component = ();
+ my %pnode_component = ();
+
foreach my $node (@{ $nodelist }) {
- my $sliver_idx;
- return -1
- if ($node->GetGeniSliverInfo(\$sliver_idx) != 0);
- next
- if ($sliver_idx);
-
#
# The node is a virtnode, but we want a ticket for the physnode.
#
- my $physnode = Node->Lookup($node->phys_nodeid());
+ my $pnode = Node->Lookup($node->phys_nodeid());
return -1
- if (!defined($physnode));
-
- my $node_uuid = $physnode->uuid();
-
- my $rspec =
- " " .
- " " .
- " " .
- "";
+ if (!defined($pnode));
+ my $node_uuid = $pnode->uuid();
+
#
# XXX The component is stored in the geni_resources table. Not sure
# how that will work out.
@@ -219,17 +209,161 @@ sub AllocateSlivers($$$)
print STDERR "Could not find CM for $node\n";
return -1;
}
+ $component_nodes{$component->uuid()} = []
+ if (!exists($component_nodes{$component->uuid()}));
+ push(@{ $component_nodes{$component->uuid()} }, $node);
+ $node_component{$node->node_id()} = $component;
+ $pnode_component{$pnode->node_id()} = $component;
+ $components{$component->uuid()} = $component;
+ }
+
+ #
+ # Now find links and lans between nodes, which of course must be at
+ # the same components since we talking about real vlans, not tunnels.
+ #
+ my %component_lans = ();
+ my @lans;
+
+ if (Lan->ExperimentLans($experiment, \@lans) != 0) {
+ print STDERR "Could not get lans for $experiment\n";
+ return -1;
+ }
+ foreach my $lan (@lans) {
+ next
+ if ($lan->type() ne "geni-vlan");
+
+ my @members;
+
+ if ($lan->MemberList(\@members) != 0) {
+ print STDERR "Could not get members for $lan\n";
+ return -1;
+ }
+
+ #
+ # Sanity check; all the nodes in the list must reside on the same
+ # component.
+ #
+ my $component;
+ foreach my $member (@members) {
+ my $node;
+ my $iface;
+
+ if ($member->GetNodeIface(\$node, \$iface) != 0) {
+ print STDERR "Could not get node/iface for $member\n";
+ return -1;
+ }
+ #
+ #
+ #
+ my $tmp = $pnode_component{$node->node_id()};
+
+ $component = $tmp
+ if (!defined($component));
+
+ if (!$component->SameComponent($tmp)) {
+ print STDERR "Component mismatch in members of $lan\n";
+ return -1;
+ }
+ }
+ $component_lans{$component->uuid()} = []
+ if (!exists($component_lans{$component->uuid()}));
+ push(@{ $component_lans{$component->uuid()} }, $lan);
+ }
+
+ #
+ # Now build up rspecs for each component.
+ #
+ my %component_rspecs = ();
+
+ foreach my $component_uuid (keys(%component_nodes)) {
+ my @nodelist = @{ $component_nodes{$component_uuid} };
+ my $component = $components{$component_uuid};
+ my $rspec =
+ " ";
+
+ foreach my $node (@nodelist) {
+ #
+ # The node is a virtnode, but we want a ticket for the physnode.
+ #
+ my $physnode = Node->Lookup($node->phys_nodeid());
+ return -1
+ if (!defined($physnode));
+ my $node_uuid = $physnode->uuid();
+ my $node_id = $node->node_id();
+
+ #
+ # We need to pass in some extra stuff for Emulab federation
+ # (tmcd redirection).
+ #
+ $rspec .= " " .
+ " ";
+ }
+ if (exists($component_lans{$component_uuid})) {
+ my @lans = @{ $component_lans{$component_uuid} };
+
+ foreach my $lan (@lans) {
+ my $name = $lan->vname();
+ my @members;
+
+ if ($lan->MemberList(\@members) != 0) {
+ print STDERR "Could not get members for $lan\n";
+ return -1;
+ }
+ $rspec .= " ";
+
+ foreach my $member (@members) {
+ my $node;
+ my $iface;
+
+ if ($member->GetNodeIface(\$node, \$iface) != 0) {
+ print STDERR "Could not get node/iface for $member\n";
+ return -1;
+ }
+ #
+ # The node is a virtnode, but we want the physnode.
+ #
+ my $physnode = Node->Lookup($node->phys_nodeid());
+ return -1
+ if (!defined($physnode));
+ my $pnode_uuid = $physnode->uuid();
+ my $name = $node->node_id() . ":" . $iface;
+
+ $rspec .= " ";
+ }
+ $rspec .= "";
+ }
+ }
+ $rspec .= "";
+ print "$rspec\n";
+ $component_rspecs{$component_uuid} = $rspec;
+ }
+
+ #
+ # Now submit each rspec to its component.
+ #
+ my %component_tickets = ();
+
+ foreach my $component_uuid (keys(%component_nodes)) {
+ my @nodelist = @{ $component_nodes{$component_uuid} };
+ my $component = $components{$component_uuid};
+ my $rspec = $component_rspecs{$component_uuid};
#
# Get ticket from component.
#
- print STDERR "Asking for ticket for $node from $component.\n";
+ print STDERR "Asking for ticket from $component.\n";
my $ticket = $component->GetTicket($slice, $rspec,
$context, $credential);
if (!defined($ticket)) {
- print STDERR "Could not get ticket from CM for $node\n";
+ print STDERR "Could not get ticket from $component\n";
return -1;
}
@@ -239,7 +373,7 @@ sub AllocateSlivers($$$)
#
if ($ticket->Store() != 0) {
$ticket->Delete();
- print STDERR "Could not store $ticket on $component for $node\n";
+ print STDERR "Could not store $ticket for $component\n";
return -1;
}
@@ -250,12 +384,14 @@ sub AllocateSlivers($$$)
# since an rspec can have multiple resources (nodes, links),
# and I have not figured out what to do for that yet.
#
- if ($node->SetGeniSliverInfo($ticket->idx()) != 0) {
- print STDERR "Could not set sliver (ticket) idx for $node\n";
- if ($ticket->Delete() != 0) {
- print STDERR "Could not destroy $ticket\n";
+ foreach my $node (@nodelist) {
+ if ($node->SetGeniSliverInfo($ticket->idx()) != 0) {
+ print STDERR "Could not set sliver/ticket idx for $node\n";
+ if ($ticket->Delete() != 0) {
+ print STDERR "Could not destroy $ticket\n";
+ }
+ return -1;
}
- return -1;
}
}
@@ -287,67 +423,130 @@ sub InstantiateSlivers($$$)
}
#
- # Loop through each node and grab a ticket for it. The nodes table
- # stores the uuid of the node as told to us in resource discovery.
- # Use this to create a simple rspec. This will need to get fancier
- # later.
- #
- # XXX We are still not using rspecs anywhere.
+ # Loop through nodes, combining nodes at the same component into a
+ # list for that component.
#
+ # Bookkeeping for the rest of this function.
+ my %components = ();
+ my %component_nodes = ();
+ my %component_tickets = ();
+ my %node_component = ();
+ my %node_slivers = ();
+ my %pnodes = ();
+
foreach my $node (@{ $nodelist }) {
- my $sliver_idx;
+ my $ticket_idx;
return -1
- if ($node->GetGeniSliverInfo(\$sliver_idx) != 0);
- next
- if (! $sliver_idx);
-
- my $sliver = GeniSliver->Lookup($sliver_idx);
+ if ($node->GetGeniSliverInfo(\$ticket_idx) != 0);
next
- if (defined($sliver));
+ if (! $ticket_idx);
- # See if its still a ticket.
- my $ticket = GeniTicket->Lookup($sliver_idx);
+ my $physnode = Node->Lookup($node->phys_nodeid());
+ if (!defined($physnode)) {
+ print STDERR "Could not get pnode object for $node\n";
+ return -1;
+ }
+ $pnodes{$node->uuid()} = $physnode;
+
+ my $ticket = GeniTicket->Lookup($ticket_idx);
if (!defined($ticket)) {
print STDERR "Could not find ticket for $node in $experiment\n";
return -1;
}
my $component = $ticket->component();
- #
- # We need to pass in some extra stuff for Emulab federation.
- #
- my $args = {'tmcd_server' => $BOSSNODE,
- 'tmcd_nodeid' => $node->node_id() };
+ $component_nodes{$component->uuid()} = []
+ if (!exists($component_nodes{$component->uuid()}));
+ push(@{ $component_nodes{$component->uuid()} }, $node);
+ $node_component{$node->node_id()} = $component;
+ $components{$component->uuid()} = $component;
+
+ # Sanity check.
+ if (!exists($component_tickets{$component->uuid()})) {
+ $component_tickets{$component->uuid()} = $ticket;
+ }
+ elsif (!$ticket->SameTicket($component_tickets{$component->uuid()})) {
+ print STDERR "Ticket mismatch for $component\n";
+ return -1;
+ }
+ }
+
+ #
+ # For each component, submit the ticket associated with the list of
+ # nodes on that component.
+ #
+ foreach my $component_uuid (keys(%component_tickets)) {
+ my @nodelist = @{ $component_nodes{$component_uuid} };
+ my $component = $components{$component_uuid};
+ my $ticket = $component_tickets{$component_uuid};
#
# Create sliver on component using the ticket.
#
- print STDERR "Redeeming ticket for $node on $component.\n";
+ print STDERR "Redeeming ticket on $component.\n";
- $sliver = $component->CreateSliver($slice, $ticket, $context, $args);
+ my $sliver =
+ $component->CreateSliver($slice, $ticket, $context);
+
+ # No longer need the ticket.
+ if ($ticket->Delete() != 0) {
+ print STDERR "Could not delete $ticket\n";
+ }
if (!defined($sliver)) {
- print STDERR "Could not create sliver on $component for $node\n";
- if ($ticket->Delete() != 0) {
- print STDERR "Could not delete $ticket\n";
- }
- if ($node->SetGeniSliverInfo(0) != 0) {
- print STDERR "Could not clear sliver idx for $node\n";
- }
+ print STDERR "Could not create sliver on $component\n";
return -1;
}
- if ($node->SetGeniSliverInfo($sliver->idx()) != 0) {
- print STDERR "Could not set sliver idx for $node\n";
- if ($ticket->Delete() != 0) {
- print STDERR "Could not delete $ticket\n";
+
+ #
+ # If the sliver corresponds to multiple nodes, then we want to
+ # split it apart so that we have a credential for each node.
+ #
+ if (@nodelist > 1) {
+ my @slivers;
+
+ if ($component->SplitSliver($sliver, $context, \@slivers) != 0) {
+ print STDERR "Could not split $sliver on $component\n";
+ if ($sliver->Destroy($context) != 0) {
+ print STDERR "Could not destroy $sliver\n";
+ }
+ return -1;
}
- if ($sliver->Destroy() != 0) {
- print STDERR "Could not destroy $sliver\n";
+ foreach my $node (@nodelist) {
+ my $physnode = $pnodes{$node->uuid()};
+ my $node_sliver;
+ foreach my $s (@slivers) {
+ #
+ # XXX Bogus use of hrn, but I am assuming the only
+ # time this happens is when speaking to another Emulab
+ # which will be doing the same thing.
+ #
+ if ($s->hrn() eq $node->node_id()) {
+ $node_sliver = $s;
+ last;
+ }
+ }
+ if (!defined($node_sliver)) {
+ print STDERR "Could not get sliver for $node in $sliver\n";
+ if ($sliver->Destroy($context) != 0) {
+ print STDERR "Could not destroy $sliver\n";
+ }
+ return -1;
+ }
+ $node_slivers{$node->uuid()} = $node_sliver;
}
- return -1;
}
- # No longer need the ticket.
- if ($ticket->Delete() != 0) {
- print STDERR "Could not delete $ticket\n";
+ else {
+ # For loop below.
+ $node_slivers{$nodelist[0]->uuid()} = $sliver;
+ }
+
+ foreach my $node (@nodelist) {
+ my $s = $node_slivers{$node->uuid()};
+
+ if ($node->SetGeniSliverInfo($s->idx()) != 0) {
+ print STDERR "Could not set sliver idx for $node\n";
+ return -1;
+ }
}
}
return 0;
@@ -432,8 +631,6 @@ sub DestroySlivers($$$)
#
# Loop through each node and do the sliver thing.
#
- # XXX We are still not using rspecs anywhere.
- #
foreach my $node (@{ $nodelist }) {
my $sliver_idx;
return -1
diff --git a/protogeni/lib/GeniSliver.pm.in b/protogeni/lib/GeniSliver.pm.in
index 933f12460bf81316fd270dac5b67c0b36f9de243..9aa6173f5d74500736900f0d4720e02c1491688d 100644
--- a/protogeni/lib/GeniSliver.pm.in
+++ b/protogeni/lib/GeniSliver.pm.in
@@ -93,6 +93,7 @@ sub Lookup($$)
$self->{'CREDENTIAL'} = undef; # client
$self->{'AGGREGATE'} = undef; # server
$self->{'RSPEC'} = undef; # client/server
+ $self->{'HRN'} = undef; # Bogus kludge for aggregates.
my $rspec_string = $self->{'SLIVER'}->{'rspec_string'};
if (defined($rspec_string) && $rspec_string ne "") {
@@ -139,16 +140,46 @@ sub Stringify($)
return "[GeniSliver: $uuid, IDX: $idx]";
}
+#
+# Cons up an hrn.
+#
+sub hrn($)
+{
+ my ($self) = @_;
+
+ if (defined($self->{'HRN'})) {
+ # XXX Kludge for Emulab aggregates
+ return $self->{'HRN'};
+ }
+ elsif (defined($self->rspec()->{'tmcd_nodeid'})) {
+ return $self->rspec()->{'tmcd_nodeid'};
+ }
+ elsif (defined($self->rspec()->{'hrn'})) {
+ return $self->rspec()->{'hrn'};
+ }
+ else {
+ return $OURDOMAIN . "." . $self->resource_type() . "." .
+ $self->idx();
+ }
+}
+# XXX Kludge for Emulab aggregates
+sub Sethrn($$)
+{
+ my ($self, $hrn) = @_;
+
+ $self->{'HRN'} = $hrn;
+ return 0;
+}
+
#
# Create a sliver record in the DB. On the client side we save the credential
# that allows control of it, for later operations.
#
-sub Create($$$$$;$$$)
+sub Create($$$$$$;$$$)
{
- my ($class, $slice, $owner_uuid, $resource_uuid, $resource_type,
+ my ($class, $slice, $owner_uuid, $uuid, $resource_uuid, $resource_type,
$rspec, $credential, $component) = @_;
my @insert_data = ();
- my $uuid;
my $certificate;
# Every sliver gets a new unique index.
@@ -161,20 +192,19 @@ sub Create($$$$$;$$$)
print STDERR "Could not store certificate\n";
return undef;
}
- $uuid = $credential->this_uuid();
+ $resource_uuid = $uuid = $credential->this_uuid();
# Store the credential
return undef
if ($credential->Store() != 0);
}
else {
- # Create a cert pair, which gives us a new uuid.
- $certificate = GeniCertificate->Create("sliver");
+ # Create a cert pair, for this resource uuid.
+ $certificate = GeniCertificate->Create("sliver", $uuid);
if (!defined($certificate)) {
print STDERR "Could not generate new certificate and UUID!\n";
return undef;
}
- $uuid = $certificate->uuid();
}
my $slice_uuid = $slice->uuid();
@@ -182,10 +212,8 @@ sub Create($$$$$;$$$)
push(@insert_data, "created=now()");
push(@insert_data, "idx='$idx'");
push(@insert_data, "uuid='$uuid'");
- push(@insert_data, "resource_uuid='$resource_uuid'")
- if (defined($resource_uuid));
- push(@insert_data, "resource_type='$resource_type'")
- if (defined($resource_type));
+ push(@insert_data, "resource_uuid='$resource_uuid'");
+ push(@insert_data, "resource_type='$resource_type'");
push(@insert_data, "creator_uuid='$owner_uuid'");
push(@insert_data, "slice_uuid='$slice_uuid'");
@@ -487,8 +515,8 @@ sub Create()
{
my ($class, $slice, $user_uuid, $rspec, $credential, $component) = @_;
- return GeniSliver->Create($slice, $user_uuid,
- $credential->target_uuid(), "Client", $rspec,
+ return GeniSliver->Create($slice, $user_uuid, undef, undef,
+ "Client", $rspec,
$credential, $component);
}
@@ -536,6 +564,45 @@ sub Destroy($$)
return 0;
}
+#
+# On the client side, the aggregate points to the parent sliver when it
+# contains multiple resources.
+#
+sub SetAggregate($$)
+{
+ my ($self, $parent) = @_;
+
+ return -1
+ if (! (ref($self) && ref($parent)));
+
+ my $idx = $self->idx();
+ my $parent_uuid = $parent->uuid();
+
+ return -1
+ if (!DBQueryWarn("update geni_slivers set ".
+ " aggregate_uuid='$parent_uuid' ".
+ "where idx='$idx'"));
+
+ return 0;
+}
+sub GetAggregate($)
+{
+ my ($self) = @_;
+
+ return undef
+ if (! ref($self));
+
+ return undef
+ if (!defined($self->aggregate_uuid()));
+
+ my $parent = GeniSliver->Lookup($self->aggregate_uuid());
+ if (!defined($parent)) {
+ print STDERR "Could not get parent object associated with $self\n";
+ return undef;
+ }
+ return $parent;
+}
+
############################################################################
#
# The server side methods are in packages which inherit from above.
@@ -558,6 +625,7 @@ sub Create($$$$$)
{
my ($class, $slice, $user_uuid, $resource_uuid, $rspec) = @_;
my $virtualization_type = $rspec->{'virtualization_type'};
+ my $uuid = $resource_uuid;
my $experiment = $slice->GetExperiment();
if (!defined($experiment)) {
@@ -606,9 +674,9 @@ sub Create($$$$$)
return -1;
}
my $vnode = Node->Lookup($vnodes[0]);
- $resource_uuid = $vnode->uuid();
+ $uuid = $vnode->uuid();
}
- return GeniSliver->Create($slice, $user_uuid, $resource_uuid,
+ return GeniSliver->Create($slice, $user_uuid, $uuid, $resource_uuid,
"Node", $rspec);
}
@@ -633,12 +701,12 @@ sub Provision($;$)
print STDERR "Could not map $self to its experiment\n";
return -1;
}
- my $resource_uuid = $self->resource_uuid();
+ my $uuid = $self->uuid();
return 0
- if (!defined($resource_uuid));
- my $node = Node->Lookup($resource_uuid);
+ if (!defined($uuid));
+ my $node = Node->Lookup($uuid);
if (!defined($node)) {
- print STDERR "Could not map node $resource_uuid to its object\n";
+ print STDERR "Could not map node $uuid to its object\n";
return -1;
}
my $reservation = $node->Reservation();
@@ -655,16 +723,14 @@ sub Provision($;$)
return -1;
}
- if (defined($extraargs)) {
- if (exists($extraargs->{'tmcd_server'}) &&
- exists($extraargs->{'tmcd_nodeid'})) {
- my $tmcd_redirect = $extraargs->{'tmcd_server'} . ":" .
- $extraargs->{'tmcd_nodeid'};
+ if (exists($self->rspec()->{'tmcd_server'}) &&
+ exists($self->rspec()->{'tmcd_nodeid'})) {
+ my $tmcd_redirect =
+ $self->rspec()->{'tmcd_server'} . ":" .
+ $self->rspec()->{'tmcd_nodeid'};
- if ($node->ModifyReservation({"tmcd_redirect" =>
- $tmcd_redirect})) {
- return -1;
- }
+ if ($node->ModifyReservation({"tmcd_redirect" => $tmcd_redirect})){
+ return -1;
}
}
@@ -674,7 +740,8 @@ sub Provision($;$)
# the vnode since it is going to redirect to tmcd on the remote Emulab
# controlling the experiment.
#
- if ($self->rspec()->{'virtualization_type'} eq "emulab-vnode") {
+ if (exists($self->rspec()->{'virtualization_type'}) &&
+ $self->rspec()->{'virtualization_type'} eq "emulab-vnode") {
my $pnode = Node->Lookup($node->phys_nodeid());
if (!defined($pnode)) {
print STDERR "Could not get pnode object for $node\n";
@@ -738,12 +805,12 @@ sub UnProvision($)
print STDERR "Could not map $self to its experiment\n";
return -1;
}
- my $resource_uuid = $self->resource_uuid();
+ my $uuid = $self->uuid();
return 0
- if (!defined($resource_uuid));
- my $node = Node->Lookup($resource_uuid);
+ if (!defined($uuid));
+ my $node = Node->Lookup($uuid);
if (!defined($node)) {
- print STDERR "Could not map node $resource_uuid to its object\n";
+ print STDERR "Could not map node $uuid to its object\n";
return -1;
}
my $reservation = $node->Reservation();
@@ -808,12 +875,12 @@ sub Start($)
print STDERR "Could not map $self to its experiment\n";
return -1;
}
- my $resource_uuid = $self->resource_uuid();
+ my $uuid = $self->uuid();
return 0
- if (!defined($resource_uuid));
- my $node = Node->Lookup($resource_uuid);
+ if (!defined($uuid));
+ my $node = Node->Lookup($uuid);
if (!defined($node)) {
- print STDERR "Could not map node $resource_uuid to its object\n";
+ print STDERR "Could not map node $uuid to its object\n";
return -1;
}
my $reservation = $node->Reservation();
@@ -869,7 +936,7 @@ sub Create()
my ($class, $slice, $user_uuid, $resource_uuid, $rspec) = @_;
return GeniSliver->Create($slice, $user_uuid, $resource_uuid,
- "Interface", $rspec);
+ $resource_uuid, "Interface", $rspec);
}
sub Provision($)
diff --git a/protogeni/lib/GeniTicket.pm.in b/protogeni/lib/GeniTicket.pm.in
index f6ffc98982655b2eedef39f197947ff23876a28f..c27db9c005fd754905f6e0cc9791b22e8c61dff7 100644
--- a/protogeni/lib/GeniTicket.pm.in
+++ b/protogeni/lib/GeniTicket.pm.in
@@ -67,8 +67,8 @@ sub Lookup($$)
# Map the component
my $component;
- if ($row->{'component_idx'}) {
- $component = GeniComponent->Lookup($row->{'component_idx'});
+ if ($row->{'component_uuid'}) {
+ $component = GeniComponent->Lookup($row->{'component_uuid'});
return undef
if (!defined($component));
}
@@ -132,6 +132,7 @@ sub owner_cert($) { return field($_[0], "owner_cert"); }
sub ticket($) { return field($_[0], "ticket"); }
sub asString($) { return field($_[0], "ticket_string"); }
sub ticket_string($) { return field($_[0], "ticket_string"); }
+sub component_uuid($) { return field($_[0], "component_uuid"); }
sub component($) { return field($_[0], "component"); }
sub stored($) { return field($_[0], "stored"); }
@@ -183,7 +184,14 @@ sub CreateFromSignedTicket($$;$$)
# Use XML::Simple to convert to something we can mess with.
my $parser = XML::LibXML->new;
- my $doc = $parser->parse_string($ticket_string);
+ my $doc;
+ eval {
+ $doc = $parser->parse_string($ticket_string);
+ };
+ if ($@) {
+ print STDERR "Failed to parse ticket string: $@\n";
+ return undef;
+ }
# Dig out the rspec.
my ($rspec_node) = $doc->getElementsByTagName("rspec");
@@ -326,7 +334,7 @@ sub Store($)
$self->{'idx'} = $idx;
}
# A locally generated ticket will not have a component. Might change that.
- push(@insert_data, "component_idx=" . $self->component()->idx())
+ push(@insert_data, "component_uuid='" . $self->component()->uuid() . "'")
if (defined($self->component()));
# Now tack on other stuff we need.
@@ -362,6 +370,7 @@ sub Sign($)
my $idx = $self->seqno();
my $slice_cert = $self->slice_cert();
my $owner_cert = $self->owner_cert();
+ my $hrn = "$OURDOMAIN.tickets.$idx";
my $rspec_xml = XMLout($self->rspec(), "NoAttr" => 1);
$rspec_xml =~ s/opt\>/rspec\>/g;
@@ -374,7 +383,10 @@ sub Sign($)
" ticket\n".
" $idx\n".
" $owner_cert\n".
+ " $slice_cert\n".
" $slice_cert\n".
+ " $hrn\n".
+ " 2008-05-10T09:00:00\n".
" \n".
" 1\n".
" $rspec_xml\n".
@@ -495,5 +507,19 @@ sub Release($)
return 0;
}
+#
+# Equality test for two tickets.
+#
+sub SameTicket($$)
+{
+ my ($self, $other) = @_;
+
+ # Must be a real reference.
+ return 0
+ if (! (ref($self) && ref($other)));
+
+ return $self->idx() == $other->idx();
+}
+
# _Always_ make sure that this 1 is at the end of the file...
1;
diff --git a/protogeni/xmlrpc/GNUmakefile.in b/protogeni/xmlrpc/GNUmakefile.in
index ec920143c401b68ce33aa4e16ea0c527aeb9f175..a16d182c4a9049a5afa2e0e204ff5c0699dbc91a 100644
--- a/protogeni/xmlrpc/GNUmakefile.in
+++ b/protogeni/xmlrpc/GNUmakefile.in
@@ -40,7 +40,7 @@ install-scripts: $(INSTALL_DIR)/protogeni/xmlrpc/protogeni-sa.pl \
$(SUDO) chown root $(INSTALL_DIR)/protogeni/xmlrpc/protogeni-cm.pl
$(SUDO) chmod u+s $(INSTALL_DIR)/protogeni/xmlrpc/protogeni-cm.pl
-install: install-libs
+install: install-libs install-scripts
control-install:
diff --git a/protogeni/xmlrpc/client.py b/protogeni/xmlrpc/client.py
index 873d9b2634afdcbc01104788e93d15595a71c0df..fb9cb31fb3ac7af6d496fb7cbc208ea4e3dcc78a 100755
--- a/protogeni/xmlrpc/client.py
+++ b/protogeni/xmlrpc/client.py
@@ -122,6 +122,8 @@ if rval:
pass
mycredential = response["value"]
print "Got my SA credential"
+#print str(mycredential);
+#sys.exit(0);
#
# Look me up just for the hell of it. I can see why the hrn is "useful"
@@ -230,6 +232,7 @@ print "Bogus DiscoverResources returned"
#
rspec = " " +\
" " +\
" " +\
" new( "methods" => {
"StartSliver" => \&GeniCM::StartSliver,
"DeleteSliver" => \&GeniCM::DeleteSliver,
"DeleteSlice" => \&GeniCM::DeleteSlice,
+ "SplitSliver" => \&GeniCM::SplitSliver,
},
);