Commit 88e0ecb5 authored by Leigh Stoller's avatar Leigh Stoller

Checkpoint multisite support.

parent e11d79be
......@@ -46,6 +46,10 @@ my $MAINSITE = @TBMAINSITE@;
my $TBOPS = "@TBOPSEMAIL@";
my $SACERT = "$TB/etc/genisa.pem";
# Cache credentials so we do not keep regenerating down inside the
# libraries that make the XMLRPC calls.
my %credcache = ();
#
# Generate the credentials we need.
#
......@@ -66,6 +70,15 @@ sub GenCredentials($$;$)
$speaker_signer = "/usr/testbed/etc/utah-apt.sa";
}
#
# Check cache.
#
my $cachetag = $target->urn() . "::" . $geniuser->urn();
if (exists($credcache{$cachetag})) {
($credential,$speaksfor) = @{ $credcache{$cachetag} };
goto cached;
}
#
# If a local user account, but a nonlocal id, then we should
# have a speaksfor credential stored, as well as a certificate
......@@ -139,6 +152,10 @@ sub GenCredentials($$;$)
print STDERR "Could not sign $target credential\n";
goto bad;
}
if ($wantspeaksfor) {
$credcache{$cachetag} = [$credential, $speaksfor];
}
cached:
if (wantarray) {
return ($credential, $speaksfor);
}
......
This diff is collapsed.
......@@ -947,9 +947,9 @@ sub CheckDatasets($$$)
#
# Set the component_manager_urn for the sites.
#
sub SetSites($$$)
sub SetSites($$$$)
{
my ($prspecstr, $sitemap, $perrmsg) = @_;
my ($prspecstr, $sitemap, $pneedstitcher, $perrmsg) = @_;
my $rspec = GeniXML::Parse($$prspecstr);
if (! defined($rspec)) {
......@@ -961,17 +961,60 @@ sub SetSites($$$)
my $site_id = GeniXML::GetJacksSiteId($ref);
if (!defined($site_id)) {
$$perrmsg = "No site ID for $client_id";
$$perrmsg = "No site ID for node $client_id";
return -1;
}
my $site_mid = "site:" . $site_id;
if (!exists($sitemap->{$site_mid})) {
$$perrmsg = "No site mapping for $client_id ($site_id)";
$$perrmsg = "No site mapping for node $client_id ($site_id)";
return -1;
}
GeniXML::SetManagerId($ref, $sitemap->{$site_mid});
GeniXML::SetJacksSiteManagerId($ref, $sitemap->{$site_mid});
}
foreach my $ref (GeniXML::FindNodes("n:link", $rspec)->get_nodelist()) {
my %linksites = ();
my $client_id = GetVirtualId($ref);
foreach my $siteref (GeniXML::FindNodesNS("n:site", $ref,
$GeniXML::JACKS_NS)->get_nodelist()) {
my $site_id = GeniXML::GetText("id", $siteref);
if (!defined($site_id)) {
$$perrmsg = "No site ID for link $client_id";
return -1;
}
my $site_mid = "site:" . $site_id;
if (!exists($sitemap->{$site_mid})) {
$$perrmsg = "No site mapping for link $client_id ($site_id)";
return -1;
}
GeniXML::AddManagerToLink($ref, $sitemap->{$site_mid});
$linksites{$sitemap->{$site_mid}} = 1;
}
# if more then one site for a link, must use the stitcher.
$$pneedstitcher = 1
if (keys(%linksites) > 1);
}
$$prspecstr = GeniXML::Serialize($rspec);
return 0;
}
#
# Set the component_manager_urn for the rspec
#
sub BindRspec($$$)
{
my ($prspecstr, $aggregate_urn, $perrmsg) = @_;
my $rspec = GeniXML::Parse($$prspecstr);
if (! defined($rspec)) {
$$perrmsg = "Could not parse rspec\n";
return -1;
}
foreach my $ref (GeniXML::FindNodes("n:node", $rspec)->get_nodelist()) {
GeniXML::SetManagerId($ref, $aggregate_urn);
}
$$prspecstr = GeniXML::Serialize($rspec);
return 0;
}
......
This diff is collapsed.
......@@ -205,6 +205,7 @@ sub DoCreate()
if (!defined($aggregate)) {
fatal("Could not find aggregate for $nodeid");
}
$aggregate_urn = $aggregate->aggregate_urn();
}
if (defined($options{"f"})) {
$fstype = $options{"f"};
......@@ -345,7 +346,7 @@ sub DoCreate()
# Handoff to snapshot if an imdataset.
#
if ($type eq "imdataset" &&
DoSnapShotInternal($dataset, $instance,
DoSnapShotInternal($dataset, $aggregate,
$bsname, $nodeid, \$errmsg)) {
$instance->Unlock();
goto failed;
......@@ -624,6 +625,10 @@ sub DoSnapshot()
if (!defined($instance)) {
fatal("No such instance");
}
my $aggregate = $instance->FindAggregateByNodeId($nodeid);
if (!defined($aggregate)) {
fatal("Could not find aggregate for $nodeid");
}
if ($dataset->Lock()) {
fatal("dataset is busy, cannot lock it");
}
......@@ -639,7 +644,7 @@ sub DoSnapshot()
# Convenient.
$webtask->AutoStore(1);
}
if (DoSnapShotInternal($dataset, $instance, $bsname, $nodeid, \$errmsg)) {
if (DoSnapShotInternal($dataset, $aggregate, $bsname, $nodeid, \$errmsg)) {
goto failed;
}
if (PollDatasetStatus($dataset, \$errmsg)) {
......@@ -659,10 +664,10 @@ sub DoSnapshot()
sub DoSnapShotInternal($$$$$)
{
my ($dataset, $instance, $bsname, $nodeid, $perrmsg) = @_;
my ($dataset, $aggregate, $bsname, $nodeid, $perrmsg) = @_;
my $errmsg;
my $manifest = GeniXML::Parse($instance->manifest());
my $manifest = GeniXML::Parse($aggregate->manifest());
if (! defined($manifest)) {
$errmsg = "Could not parse manifest";
goto failed;
......@@ -697,8 +702,8 @@ sub DoSnapShotInternal($$$$$)
$errmsg = "Could not find node '$nodeid' in manifest";
goto failed;
}
my $response = $instance->CreateImage($sliver_urn,
$dataset->dataset_id(), 0, $bsname);
my $response = $aggregate->CreateImage($sliver_urn,
$dataset->dataset_id(), 0, $bsname);
if ($response->code() != GENIRESPONSE_SUCCESS) {
$errmsg = "SnapshotDataset failed: ". $response->output() . "\n";
goto failed;
......
......@@ -45,6 +45,7 @@ sub usage()
print("Usage: manage_instance reload instance node_id [node_id ...]\n");
print("Usage: manage_instance monitor instance\n");
print("Usage: manage_instance lockdown instance set|clear user|admin\n");
print("Usage: manage_instance writecreds instance directory\n");
exit(-1);
}
my $optlist = "dt:";
......@@ -104,6 +105,7 @@ sub DoRefresh();
sub DoReboot();
sub DoReload();
sub DoLockdown();
sub WriteCredentials();
sub StartMonitor();
#
......@@ -160,6 +162,9 @@ elsif ($action eq "monitor") {
elsif ($action eq "lockdown") {
DoLockdown()
}
elsif ($action eq "writecreds") {
WriteCredentials()
}
else {
usage();
}
......@@ -248,7 +253,7 @@ sub DoSnapshot()
#
# Sanity checks.
#
my @aggs = @{ $instance->AggregateList() };
my @aggs = $instance->AggregateList();
if (! @aggs) {
fatal("No slivers for instance!");
}
......@@ -279,12 +284,15 @@ sub DoSnapshot()
}
foreach my $ref (GeniXML::FindNodes("n:node",
$manifest)->get_nodelist()) {
my $client_id = GeniXML::GetVirtualId($ref);
my $urn = GeniXML::GetSliverId($ref);
my $client_id = GeniXML::GetVirtualId($ref);
my $manager_urn = GetManagerId($ref);
my $urn = GeniXML::GetSliverId($ref);
# No sliver urn or a different aggregate.
next
if (! (defined($urn) && $urn eq $agg->aggregate_urn()));
if (! (defined($urn) &&
defined($manager_urn) &&
$manager_urn eq $agg->aggregate_urn()));
if ($node_id eq $client_id) {
$node = $ref;
......@@ -414,7 +422,7 @@ sub DoSnapshot()
sleep($interval);
$seconds -= $interval;
my $response = $aggregate->SliverStatus();
my $response = $aggregate->SliceStatus();
if ($response->code() != GENIRESPONSE_SUCCESS &&
$response->code() != GENIRESPONSE_BUSY) {
$errmsg = "Sliverstatus failed: ". $response->output() . "\n";
......@@ -579,7 +587,7 @@ sub DoConsole()
#
my $sliver_urn;
my $sliver;
foreach my $obj (@{ $instance->AggregateList() }) {
foreach my $obj ($instance->AggregateList()) {
my $manifest = GeniXML::Parse($obj->manifest());
if (! defined($manifest)) {
fatal("Could not parse manifest for $obj");
......@@ -725,7 +733,7 @@ sub DoTerminate()
return -1;
};
my @return_codes = ();
my @agglist = @{ $instance->AggregateList() };
my @agglist = $instance->AggregateList();
if (ParRun({"maxwaittime" => 99999,
"maxchildren" => scalar(@agglist)},
\@return_codes, $coderef, @agglist)) {
......@@ -851,7 +859,7 @@ sub DoExtend()
return -1;
};
my @return_codes = ();
my @agglist = @{ $instance->AggregateList() };
my @agglist = $instance->AggregateList();
if (ParRun({"maxwaittime" => 99999,
"maxchildren" => scalar(@agglist)},
\@return_codes, $coderef, @agglist)) {
......@@ -976,7 +984,7 @@ sub DoRefresh()
return 1;
};
my @return_codes = ();
my @agglist = @{ $instance->AggregateList() };
my @agglist = $instance->AggregateList();
if (ParRun({"maxwaittime" => 99999,
"maxchildren" => scalar(@agglist)},
\@return_codes, $coderef, @agglist)) {
......@@ -1031,7 +1039,7 @@ sub DoRebootOrReload($)
my %sliver_urns = ();
my @slivers = ();
foreach my $obj (@{ $instance->AggregateList() }) {
foreach my $obj ($instance->AggregateList()) {
my $manifest = GeniXML::Parse($obj->manifest());
if (! defined($manifest)) {
fatal("Could not parse manifest");
......@@ -1083,7 +1091,7 @@ sub DoRebootOrReload($)
# Clear this so that web interface will not update it.
$webtask->sliverstatus({});
my $response = $sliver->SliverAction($which, @urns);
my $response = $sliver->SliverAction(\$errmsg, $which, @urns);
if (!defined($response)) {
$errmsg = "RPC Error calling SliverAction";
goto bad;
......@@ -1267,7 +1275,7 @@ sub StartMonitor()
local $SIG{INT} = $handler;
}
my @return_codes = ();
my @agglist = @{ $instance->AggregateList() };
my @agglist = $instance->AggregateList();
if (ParRun({"maxwaittime" => 99999,
"maxchildren" => scalar(@agglist)},
\@return_codes, $coderef, @agglist)) {
......@@ -1351,7 +1359,7 @@ sub DoLockdownInternal($$)
return 0;
};
my @return_codes = ();
my @agglist = @{ $instance->AggregateList() };
my @agglist = $instance->AggregateList();
if (ParRun({"maxwaittime" => 99999,
"maxchildren" => scalar(@agglist)},
\@return_codes, $coderef, @agglist)) {
......@@ -1398,6 +1406,22 @@ sub DoLockdown()
exit(0);
}
#
# Write instance credentials to files.
#
sub WriteCredentials()
{
usage()
if (!@ARGV);
my $directory = shift(@ARGV);
fatal("$directory does not exist")
if (! -e $directory);
fatal("$directory is not a directory")
if (! -d $directory);
return $instance->WriteCredentials($directory);
}
sub fatal($)
{
my ($mesg) = @_;
......
......@@ -320,11 +320,11 @@ if ($snap) {
if (!defined($instance)) {
fatal("Could not look up instance $uuid");
}
if (@{ $instance->AggregateList() } != 1) {
if ($instance->AggregateList() != 1) {
$errors{"error"} = "Must be only one aggregate to snapshot";
UserError();
}
($aggregate) = @{ $instance->AggregateList() };
($aggregate) = $instance->AggregateList();
my $manifest = GeniXML::Parse($aggregate->manifest());
if (! defined($manifest)) {
fatal("Could not parse manifest");
......
......@@ -542,6 +542,18 @@ sub SetManagerId($$)
return $node;
}
sub AddManagerToLink($$)
{
my ($link, $urn) = @_;
my $ref = AddElement("component_manager", $link);
return undef
if (!defined($ref));
GeniXML::SetText("name", $ref, $urn);
return $link;
}
sub GetColocate($)
{
my ($node) = @_;
......
......@@ -180,7 +180,7 @@ function (_, Constraints, sup, ppstart, aboutaptString, aboutcloudString, waitwa
var continuation = function(rspec, description, name, amdefault, ispp) {
$('#showtopo_title').html("<h3>" + name + "</h3>");
$('#showtopo_description').html(description);
sup.maketopmap('#showtopo_div', rspec, null);
sup.maketopmap('#showtopo_div', rspec, false);
};
GetProfile($(selectedElement).attr('value'), continuation);
}
......
......@@ -834,17 +834,6 @@ function (_, sup, filesize, JacksEditor, ShowImagingModal, moment, ppstart,
}
}
//
// Show the rspec text in the modal.
//
function ShowRspecTopo(xml)
{
sup.ShowModal("#quickvm_topomodal");
$('#quickvm_topomodal').one('shown.bs.modal', function() {
sup.maketopmap("#showtopo_nopicker", xml, null);
});
}
//
// Instantiate a profile as a guest User.
//
......
......@@ -70,7 +70,7 @@ function (sup, moment)
}
sup.ShowModal("#quickvm_topomodal");
$("#quickvm_topomodal").one("shown.bs.modal", function () {
sup.maketopmap('#showtopo_nopicker', json.value.rspec, null);
sup.maketopmap('#showtopo_nopicker', json.value.rspec, false);
});
};
var $xmlthing = sup.CallServerMethod(ajaxurl,
......
......@@ -45,11 +45,8 @@ var jacksInstance;
var jacksInput;
var jacksOutput;
function maketopmap(divname, xml, sshcallback, writeable)
function maketopmap(divname, xml, showinfo)
{
if (writeable === undefined) {
writeable = false;
}
if (! jacksInstance)
{
jacksInstance = new window.Jacks({
......@@ -57,27 +54,18 @@ function maketopmap(divname, xml, sshcallback, writeable)
source: 'rspec',
multiSite: true,
root: divname,
nodeSelect: writeable,
nodeSelect: showinfo,
readyCallback: function (input, output) {
jacksInput = input;
jacksOutput = output;
jacksInput.trigger('change-topology',
[{ rspec: xml }]);
if (sshcallback)
{
jacksOutput.on('click-event', function (event) {
if (event.type === 'node')
{
sshcallback(event.ssh, event.client_id);
}
});
}
},
show: {
rspec: false,
tour: false,
version: false,
selectInfo: writeable,
selectInfo: showinfo,
menu: false
},
canvasOptions: {
......
......@@ -90,7 +90,7 @@ function (_, sup, moment, ppstart,
});
$('#quickvm_topomodal').on('shown.bs.modal', function() {
sup.maketopmap("#showtopo_nopicker",
$('#profile_rspec_textarea').val(), null, true);
$('#profile_rspec_textarea').val(), true);
});
// The Show Source button.
......
......@@ -1478,13 +1478,14 @@ function (_, sup, moment, marked, UriTemplate, ShowImagingModal,
var manifests = _.values(manifest_object);
var first_manifest = _.first(manifests);
var rest = _.rest(manifests);
var multisite = rest.length ? true : false;
if (! jacksInstance)
{
jacksInstance = new window.Jacks({
mode: 'viewer',
source: 'rspec',
multiSite: true,
multiSite: multisite,
root: divname,
nodeSelect: false,
readyCallback: function (input, output) {
......
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