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 88e0ecb5 authored by Leigh B Stoller's avatar Leigh B 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