Commit 86cd9965 authored by Leigh B. Stoller's avatar Leigh B. Stoller

Checkpoint working swapin of experiments using multiple federated nodes with...

Checkpoint working swapin of experiments using multiple federated nodes with vlans between them. Now I need to figure out how to swap the experiment out
parent ab9ad2ba
......@@ -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";
......
......@@ -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);
}
......@@ -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;
......@@ -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($$)
" <type>capability</type>\n".
" <serial>$idx</serial>\n".
" <owner_uuid>$owner_cert</owner_uuid>\n".
" <target_uuid>$target_cert</target_uuid>\n".
" <this_uuid>$target_cert</this_uuid>\n".
" <hrn>$hrn</hrn>\n".
" <expires>2008-05-10T09:00:00</expires>\n".
" $cap_xml\n".
"</credential>\n";
......
This diff is collapsed.
......@@ -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) = @_;