Commit b57f385e authored by Weibin Sun's avatar Weibin Sun
Browse files

Merge remote branch 'central/master'

parents 15244732 e8a7fa5b
......@@ -138,7 +138,11 @@ $EXPT_RESOURCESHOSED = 0;
"firewall_rules",
"elabinelab_attributes",
"virt_tiptunnels",
"ipsubnets");
"ipsubnets",
"virt_blobs",
"virt_client_service_ctl",
"virt_client_service_hooks",
"virt_client_service_opts");
%physicalTables = ("delays" => ["node_id", "vname", "vnode0", "vnode1"],
"ipport_ranges" => undef,
......@@ -3507,6 +3511,135 @@ sub SetupProgramAgents($)
return 0;
}
#
# Convert virt_blobs into real blobs. We go to some pain to keep the same
# filenames associated with the same uuid to make sure caching doesn't get
# needlessly broken on the client (on a modify).
#
sub UploadBlobs($$)
{
my ($self,$update) = @_;
# Must be a real reference.
return -1
if (! ref($self));
my $pid = $self->pid();
my $eid = $self->eid();
my $idx = $self->idx();
my $virtexp = $self->GetVirtExperiment();
return -1
if (!defined($virtexp));
my %blobs = ();
my %virt_blobs = ();
#
# Grab the existing blobs tied to our experiment
#
my $qres = DBQueryFatal("select uuid,filename,vblob_id" .
" from blobs where exptidx=$idx");
if (defined($qres) && $qres->numrows()) {
while (my ($uuid,$filename,$vblob_id) = $qres->fetchrow_array()) {
$blobs{$vblob_id} = [ 0,$uuid,$filename ];
}
}
#
# Now grab our experiment virt blobs
#
my $virt_blobs_table = $virtexp->Table("virt_blobs");
foreach my $row ($virt_blobs_table->Rows()) {
my $vblob_id = $row->vblob_id();
my $filename = $row->filename();
$virt_blobs{$vblob_id} = $filename;
}
#
# Make sure each virt_blob is in the blobs table!
#
foreach my $vblob_id (keys(%virt_blobs)) {
my $vfilename = $virt_blobs{$vblob_id};
if (exists($blobs{$vblob_id})
&& $blobs{$vblob_id}->[2] eq $vfilename) {
# this one is a keeper, so mark it!
$blobs{$vblob_id}->[0] = 1;
}
else {
my $found = 0;
foreach my $rvblob_id (keys(%blobs)) {
# if this one's a keeper, skip it!
next
if ($blobs{$rvblob_id}->[0]);
# if the filenames match, we adjust the vblob_id field
# in the blobs table to match what we have -- this leaves
# the uuid<->filename mapping intact
if ($blobs{$rvblob_id}->[2] eq $vfilename) {
my $uuid = $blobs{$rvblob_id}->[1];
$blobs{$vblob_id} = [ 1,$blobs{$rvblob_id}->[1],
$blobs{$rvblob_id}->[2] ];
DBQueryFatal("replace into blobs (uuid,vblob_id)" .
" values ('$uuid','$vblob_id')");
$found = 1;
last;
}
}
if (!$found) {
# need to add this blob fresh!
my $swapperuid = $self->swapper();
DBQueryFatal("insert into blobs" .
" (uuid,filename,owner_uid,vblob_id,exptidx)" .
" values (UUID(),'$vfilename','$swapperuid'," .
" '$vblob_id',$idx)");
}
}
}
#
# Only remove real blobs if we're done using them (i.e., on a modify)
#
if ($update) {
foreach my $vblob_id (keys(%blobs)) {
my ($keep,$uuid,$filename) = @{$blobs{$vblob_id}};
if (!$keep) {
DBQueryFatal("delete from blobs" .
" where exptidx=$idx and vblob_id='${vblob_id}'");
}
}
}
return 0;
}
#
# Remove any real blobs that were a result of a virt blob (i.e., those
# blobs that have our exptidx and a valid vblob_id).
#
sub RemoveBlobs($$)
{
my ($self) = @_;
# Must be a real reference.
return -1
if (! ref($self));
my $idx = $self->idx();
my $qres = DBQueryFatal("delete from blobs using blobs" .
" left join virt_blobs as vblobs" .
" on blobs.vblob_id=vblobs.vblob_id" .
" where blobs.exptidx=$idx" .
" and vblobs.vblob_id is not NULL");
# XXX: probably should clean out blob_files stuff too!
return 0;
}
#
# Seed the virt_agents table. Each lan/link needs an agent to handle
# changes to delays or other link parameters, and that agent (might be
......
......@@ -3095,6 +3095,7 @@ sub RecordVLanDeletion($$)
sub RecordVLanModification($$$$)
{
my ($class, $lanid, $added, $removed) = @_;
my %current = ();
my $query_result =
DBQueryWarn("select members from vlans where id='$lanid'");
......@@ -3102,7 +3103,9 @@ sub RecordVLanModification($$$$)
return -1
if (!$query_result);
my ($current) = $query_result->fetchrow_array();
my %current = map { $_ => $_ } split(/\s+/, $current);
if (defined($current) && $current ne "") {
%current = map { $_ => $_ } split(/\s+/, $current);
}
if ($added) {
foreach my $port (@$added) {
......
......@@ -55,13 +55,14 @@ sub checknodeid($$)
my ($nid,$msg) = @_;
if ($nid =~ /^(.*)\x0/) {
my $onid = $nid;
$nid = $1;
if (!exists($carped{$nid}) && open(MAIL, "| /usr/sbin/sendmail -t")) {
$carped{$nid} = 1;
require Carp;
my $TBOPS = "@TBOPSEMAIL@";
print MAIL "To: $TBOPS\n";
print MAIL "Subject: NUL in node_id '$nid'\n";
print MAIL "Subject: NUL in node_id '$nid' ('$onid')\n";
print MAIL "$msg\n";
print MAIL "\n";
print MAIL Carp::longmess();
......@@ -167,8 +168,18 @@ sub Lookup($$)
return undef
if (!$query_result || !$query_result->numrows);
#
# Make a copy of the array. Still fighting memory corruption error.
#
my $hash_orig = $query_result->fetchrow_hashref();
my $hash_copy = {};
foreach my $key (keys(%{ $hash_orig })) {
my $val = $hash_orig->{$key};
$hash_copy->{$key} = $val;
}
my $self = {};
$self->{"DBROW"} = $query_result->fetchrow_hashref();
$self->{"DBROW"} = $hash_copy;
$self->{"RSRV"} = undef;
$self->{"TYPEINFO"} = undef;
$self->{"ATTRS"} = undef;
......
......@@ -73,6 +73,11 @@ my $debug = 0;
"virt_parameters" => [ "name", "value" ],
"virt_paths" => [ "pathname", "segmentname"],
"experiment_blobs" => [ "path", "action" ],
"virt_blobs" => [ "vblob_id", "filename" ],
"virt_client_service_ctl" => [ "vnode", "service_idx", "env", "whence" ],
"virt_client_service_hooks"=> [ "vnode", "service_idx", "env", "whence",
"hook_vblob_id" ],
"virt_client_service_opts" => [ "vnode", "opt_name", "opt_value" ],
);
#
......@@ -1198,6 +1203,27 @@ package VirtExperiment::VirtTableRow::experiment_blobs;
use vars qw(@ISA);
@ISA = "VirtExperiment::VirtTableRow";
use VirtExperiment;
use VirtExperiment;
package VirtExperiment::VirtTableRow::virt_blobs;
use vars qw(@ISA);
@ISA = "VirtExperiment::VirtTableRow";
use VirtExperiment;
package VirtExperiment::VirtTableRow::virt_client_service_ctl;
use vars qw(@ISA);
@ISA = "VirtExperiment::VirtTableRow";
use VirtExperiment;
package VirtExperiment::VirtTableRow::virt_client_service_hooks;
use vars qw(@ISA);
@ISA = "VirtExperiment::VirtTableRow";
use VirtExperiment;
package VirtExperiment::VirtTableRow::virt_client_service_opts;
use vars qw(@ISA);
@ISA = "VirtExperiment::VirtTableRow";
use VirtExperiment;
# _Always_ make sure that this 1 is at the end of the file...
1;
......@@ -125,6 +125,18 @@ my %virtual_tables =
"experiment_blobs" => { rows => undef,
tag => "blobs",
row => "blob"},
"virt_blobs" => { rows => undef,
tag => "virt_blobs",
row => "virt_blob"},
"virt_client_service_ctl" => { rows => undef,
tag => "virt_client_service_ctl",
row => "virt_client_service_ctlrow"},
"virt_client_service_hooks"=> { rows => undef,
tag => "virt_client_service_hooks",
row => "virt_client_service_hook"},
"virt_client_service_opts" => { rows => undef,
tag => "virt_client_service_opts",
row => "virt_client_service_opt"},
# This is a fake table. See below. If we add more, lets generalize.
"external_sourcefiles" => { rows => undef,
tag => "nsfiles",
......
......@@ -42,6 +42,7 @@ sub InstallUpdate($$)
PhaseSucceed();
};
}
return 0;
}
1;
......@@ -105,8 +105,13 @@ set_get_options(struct config_host_authinfo *ai, int ix)
/*
* We use a small server inactive timeout since we no longer have
* to start up a frisbeed well in advance of the client(s).
*
* XXX we cranked this from 60 to 180 seconds to account for clients
* with lots of write buffer memory but slow disks, giving them time
* to flush all their buffers and report their stats before we give
* up on them.
*/
strcat(str, " -T 60");
strcat(str, " -T 180");
ai->imageinfo[ix].get_options = mystrdup(str);
}
......
......@@ -218,7 +218,7 @@ CREATE TABLE `geni_rspecs` (
`idx` int(10) unsigned NOT NULL auto_increment,
`created` datetime default NULL,
`rspec` text,
PRIMARY KEY (`idx`),
PRIMARY KEY (`idx`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
DROP TABLE IF EXISTS `geni_bindings`;
......
......@@ -106,6 +106,7 @@ sub ListResources()
my $available = $options->{'geni_available'};
my $compress = $options->{'geni_compressed'};
my $slice_urn = $options->{'geni_slice_urn'};
my $version = $options->{'rspec_version'} || undef;
my $xml = undef;
if ($slice_urn) {
......@@ -138,7 +139,8 @@ sub ListResources()
# No slice was specified, so get the advertisement RSpec.
my $discover_args = {
'credentials' => $credentials,
'available' => $available
'available' => $available,
'rspec_version' => $version,
};
my $response = GeniCMV2::DiscoverResources($discover_args);
if (GeniResponse::IsError($response)) {
......
......@@ -144,7 +144,14 @@ sub GetCredential($)
"Malformed URN in the certificate")
if (!GeniHRN::IsValid($urn));
my ($auth, $type, $id) = GeniHRN::Parse($urn);
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Not an authority certificate")
if ($type ne "authority");
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Not an am/cm/sa/ses certificate")
if (! ($id =~ /^(am|cm|ses|sa)$/i));
#
# Check for an existing authority.
#
......@@ -179,15 +186,22 @@ sub GetCredential($)
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Who are you?");
}
my $credential =
GeniCredential->CreateSigned($authority,
$caller_authority,
$GeniCredential::LOCALMA_FLAG);
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
my $credential = GeniCredential->Create($authority, $caller_authority);
if (!defined($credential)) {
print STDERR "Could not create credential for $caller_authority\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
#
# We want this credential to be valid for a long time;
#
$credential->SetExpiration(time() + 24 * 60 * 60 * 120);
if ($credential->Sign($GeniCredential::LOCALMA_FLAG) != 0) {
$credential->Delete();
print STDERR "Could not sign credential for $caller_authority\n";
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not create signed credential")
if (!defined($credential));
}
return GeniResponse->Create(GENIRESPONSE_SUCCESS,
$credential->asString());
}
......
......@@ -192,18 +192,19 @@ sub DiscoverResources($)
return $credential
if (GeniResponse::IsResponse($credential));
return DiscoverResourcesAux($available, $compress, [$credential]);
return DiscoverResourcesAux($available,
$compress, $version, [$credential]);
}
# Helper function for V2.
sub DiscoverResourcesAux($$$;$)
sub DiscoverResourcesAux($$$$)
{
my ($available, $compress, $credentials, $version) = @_;
my ($available, $compress, $version, $credentials) = @_;
my $user_urn = $ENV{'GENIRN'};
$version = "0.2"
if (!defined($version));
# Sanity check since this can come from client.
if (! ($version eq "0.1" || $version eq "0.2" ||$version eq "2.0")) {
if (! ($version eq "0.1" || $version eq "0.2" ||$version eq "2")) {
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Improper version request");
}
......@@ -904,10 +905,17 @@ sub GetTicketAuxAux($$$$$$$$$)
}
# If the node still isn't bound and doesn't have a pctype,
# use the user-specified one.
if (! defined($node) && ! defined($pctype)) {
my $usertype = GeniXML::FindFirst("n:node_type", $ref);
if (GeniXML::IsVersion0($ref)) {
if (! defined($node) && ! defined($pctype)) {
my $usertype = GeniXML::FindFirst("n:node_type", $ref);
if (defined($usertype)) {
$pctype = GeniXML::GetText("type_name", $usertype);
}
}
} else {
my $usertype = GeniXML::FindFirst("n:hardware_type", $ref);
if (defined($usertype)) {
$pctype = GeniXML::GetText("type_name", $usertype);
$pctype = GeniXML::GetText("name", $usertype);
}
}
}
......@@ -966,7 +974,7 @@ sub GetTicketAuxAux($$$$$$$$$)
};
# Tarball and startup command.
my $startupcmd = GeniXML::GetText("startup_command", $ref);
my $startupcmd = GeniXML::GetStartupCommand($ref);
if (defined($startupcmd)) {
if (! TBcheck_dbslot($startupcmd, "virt_nodes", "startupcmd",
TBDB_CHECKDBSLOT_WARN|TBDB_CHECKDBSLOT_ERROR)) {
......@@ -977,7 +985,7 @@ sub GetTicketAuxAux($$$$$$$$$)
}
$nodeblob->{'startupcmd'} = $startupcmd;
}
my $tarfiles = GeniXML::GetText("tarfiles", $ref);
my $tarfiles = GeniXML::GetTarball($ref);
if (defined($tarfiles)) {
if (! TBcheck_dbslot($tarfiles, "virt_nodes", "tarfiles",
TBDB_CHECKDBSLOT_WARN|TBDB_CHECKDBSLOT_ERROR)) {
......@@ -2322,6 +2330,7 @@ sub SliverWorkAux($$$$$$$)
my %slivers = ();
my @plabnodes = ();
my %ifacemap = ();
my %ifacexml = ();
my %rspecmap = ();
foreach my $ref (GeniXML::FindNodes("n:node", $rspec)->get_nodelist()) {
my $resource_id = GeniXML::GetNodeId($ref);
......@@ -2417,7 +2426,17 @@ sub SliverWorkAux($$$$$$$)
# And store into the new manifest.
my $oldnode = GeniXML::GetNodeByVirtualId($virtual_id, $manifest);
GeniXML::ReplaceNode($oldnode, $ref);
my $newnode = GeniXML::ReplaceNode($oldnode, $ref);
# If using rspec v2, save the interface xml node for later
# annotation when iterating through links.
if (! GeniXML::IsVersion0($newnode)) {
foreach my $linkref (GeniXML::FindNodes("n:interface",
$newnode)->get_nodelist()) {
my $virtual_iface_id = GeniXML::GetInterfaceId($linkref);
$ifacexml{$virtual_iface_id} = $linkref;
}
}
}
#
......@@ -2675,29 +2694,45 @@ sub SliverWorkAux($$$$$$$)
"$iface_name in $linkname";
goto bad;
}
my $outref;
my $sliverName = "sliver_urn";
my $macName = "MAC";
my $ipAddress;
if (defined($vinterface)) {
$ipAddress = $vinterface->IP();
} else {
$ipAddress = $interface->IP();
}
# Manifest goes back to the user.
if (GeniXML::IsVersion0($ifaceref)) {
GeniXML::SetText("sliver_urn", $ifaceref,
$sliver->sliver_urn());
GeniXML::SetText("MAC", $ifaceref, $interface->mac())
if (defined($interface));
$outref = $ifaceref;
GeniXML::SetText("VMAC", $ifaceref, $vinterface->mac())
if (defined($vinterface));
if (defined($vinterface)) {
GeniXML::SetText("IP", $ifaceref, $vinterface->IP())
if (defined($vinterface->IP())
&& $vinterface->IP() ne "");
if (defined($ipAddress) && $ipAddress ne "") {
GeniXML::SetText("IP", $outref, $ipAddress);
}
else {
GeniXML::SetText("IP", $ifaceref, $interface->IP())
if (defined($interface) &&
defined($interface->IP())
&& $interface->IP() ne "");
} elsif (exists($ifacexml{$iface_id})) {
$outref = $ifacexml{$iface_id};
$sliverName = "sliver_id";
$macName = "mac_address";
if (defined($ipAddress) && $ipAddress ne "") {
my $child = GeniXML::FindFirst("n:ip", $outref);
if (! defined($child)) {
$child = GeniXML::AddElement("ip", $outref);
}
GeniXML::SetText("address", $child, $ipAddress);
GeniXML::SetText("type", $child, "ipv4");
}
} else {
GeniXML::SetText("sliver_id", $ifaceref,
GeniXML::SetText($sliverName, $ifaceref,
$sliver->sliver_urn());
}
if (defined($outref)) {
GeniXML::SetText($sliverName, $outref,
$sliver->sliver_urn());
GeniXML::SetText($macName, $outref, $interface->mac())
if (defined($interface));
}
if ($sliver->SetAggregate($linkaggregate) != 0) {
$message = "Could not add link sliver $sliver to $aggregate";
......
......@@ -299,7 +299,7 @@ sub DiscoverResources($)
if(!GeniResponse::IsResponse($cred));
}
return GeniCM::DiscoverResourcesAux($available, $compress,
$credential_objects);
$version, $credential_objects);
}
#
......
......@@ -512,7 +512,7 @@ sub PipeTo($$$)
{
my ($self, $withkey, $string) = @_;
print STDERR "PipeTo: $self, '$string'\n";
# print STDERR "PipeTo: $self, '$string'\n";
require Socket;
import Socket qw(:DEFAULT);
......
#!/usr/bin/perl -wT
#
# GENIPUBLIC-COPYRIGHT
# Copyright (c) 2008-2010 University of Utah and the Flux Group.
# Copyright (c) 2008-2011 University of Utah and the Flux Group.
# All rights reserved.
#
package GeniCredential;
......@@ -135,6 +135,7 @@ sub Create($$$)
$self->{'string'} = undef;
$self->{'capabilities'} = undef;
$self->{'extensions'} = undef;
$self->{'parent_cred'} = undef;
$self->{'idx'} = undef; # Only set when stored to DB.
bless($self, $class);
......@@ -157,6 +158,7 @@ sub hrn($) { return $_[0]->{"target_cert"}->hrn(); }
sub target_urn($) { return $_[0]->{"target_cert"}->urn(); }
sub owner_urn($) { return $_[0]->{"owner_cert"}->urn(); }
sub signer_certs($) { return $_[0]->{"signer_certs"}; }
sub parent_cred($) { return $_[0]->{"parent_cred"}; }
#
# Stringify for output.
......@@ -190,6 +192,20 @@ sub IsExpired($)
return (time() >= $expires);
}
#
# Set the expiration time for a credential. Only changes the
# in memory copy, not the DB.
#
sub SetExpiration($$)
{
my ($self, $expires) = @_;
$self->{'valid_until'} =
POSIX::strftime("20%y-%m-%dT%H:%M:%S", localtime($expires));
return 0;
}
#
# Compare the certs inside a credential to make sure that the
# certs for the target/owner have not changed. Say, if the user
......@@ -323,6 +339,18 @@ sub GetSelfCredential($$)
return GeniCredential->CreateSigned($me, $me, $signer);
}
# Find an element (which must exist exactly once) within a node.
my $find = sub
{
my( $node, $name ) = @_;
my @cnodes = grep( $_->nodeName eq $name, $node->childNodes );
return undef unless scalar( @cnodes ) == 1;
return $cnodes[ 0 ];
};
#
# Create a credential object from a signed credential string.
#
......@@ -364,6 +392,14 @@ sub CreateFromSigned($$;$)
return undef;
}
my $root = $doc->documentElement();
my $credential_el = &$find( $root, "credential" );
return undef unless defined( $credential_el );
# Dig out the entire credential structure to save it.
my ($credential) = $doc->getElementsByTagName("credential");
# Ditto the signatures.
my @signatures = $doc->getElementsByTagName("signatures");
# Dig out the extensions
# now extensions is an xml element.
......@@ -371,7 +407,7 @@ sub CreateFromSigned($$;$)
$root)->get_nodelist;
# UUID of the credential.
my ($uuid_node) = $doc->getElementsByTagName("uuid");
my $uuid_node = &$find( $credential_el, "uuid" );
return undef
if (!defined($uuid_node));
my $this_uuid = $uuid_node->to_literal();
......@@ -382,7 +418,7 @@ sub CreateFromSigned($$;$)
}