Commit bc5b1968 authored by Leigh Stoller's avatar Leigh Stoller

Checkpoint multisite topology code. Work in progress.

parent 9f49096b
This diff is collapsed.
......@@ -781,85 +781,12 @@ sub UpdateDiskImage($$@)
return 0;
}
#
# We need to convert from using URNs to using URLs for disk images,
# since we want to support choosing the backend. This list is the
# list as of the conversion, at the APT. Before we instantiate, look
# at the rspec and update the URNs to URLs based on this list.
#
my %APTImages = (
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:demo-profile' => 'https://www.apt.emulab.net/image_metadata.php?uuid=39383c39-7b2f-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:docker' => 'https://www.apt.emulab.net/image_metadata.php?uuid=5ae53ff8-7b2f-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:docker-running-env' => 'https://www.apt.emulab.net/image_metadata.php?uuid=a1317423-7b2f-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:docker-running-env-02' => 'https://www.apt.emulab.net/image_metadata.php?uuid=f30e8657-7b2f-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:Docker1' => 'https://www.apt.emulab.net/image_metadata.php?uuid=31d9f5c1-7b30-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:ESA' => 'https://www.apt.emulab.net/image_metadata.php?uuid=72d94622-7b35-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:firstclone' => 'https://www.apt.emulab.net/image_metadata.php?uuid=d49e30a8-7b31-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:FPTaylorVM' => 'https://www.apt.emulab.net/image_metadata.php?uuid=f2e99dbe-7b31-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:FrequentDirection' => 'https://www.apt.emulab.net/image_metadata.php?uuid=1c6b4e98-7b32-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:geni-lib' => 'https://www.apt.emulab.net/image_metadata.php?uuid=441fc279-7b32-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:gimiovsomf6' => 'https://www.apt.emulab.net/image_metadata.php?uuid=626184be-7b32-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:hadoop' => 'https://www.apt.emulab.net/image_metadata.php?uuid=ffa8f859-3524-11e4-8944-81966d62745f',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:hg' => 'https://www.apt.emulab.net/image_metadata.php?uuid=91dcd7d5-7b32-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:imageusage' => 'https://www.apt.emulab.net/image_metadata.php?uuid=adc61bad-7b32-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:Iperf' => 'https://www.apt.emulab.net/image_metadata.php?uuid=d0c8aba4-7b32-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:labwikiXORP' => 'https://www.apt.emulab.net/image_metadata.php?uuid=eee5f68d-7b32-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:myapt' => 'https://www.apt.emulab.net/image_metadata.php?uuid=13baa069-7b33-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:myclone' => 'https://www.apt.emulab.net/image_metadata.php?uuid=301d4978-7b33-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:myimage' => 'https://www.apt.emulab.net/image_metadata.php?uuid=03a342be-7b2c-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:myvm' => 'https://www.apt.emulab.net/image_metadata.php?uuid=6334cf1c-7a59-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:myvm2' => 'https://www.apt.emulab.net/image_metadata.php?uuid=aa8b3638-7a79-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:ricci-cav-2014' => 'https://www.apt.emulab.net/image_metadata.php?uuid=b3d6f6f7-7b35-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:rob-profile' => 'https://www.apt.emulab.net/image_metadata.php?uuid=31278fc7-7b34-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:robtestimage' => 'https://www.apt.emulab.net/image_metadata.php?uuid=4d43d6bb-7b34-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:singlenodelime' => 'https://www.apt.emulab.net/image_metadata.php?uuid=60905cf9-7b34-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:singlenodelime-2' => 'https://www.apt.emulab.net/image_metadata.php?uuid=8db24268-7b34-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:singlevmlime' => 'https://www.apt.emulab.net/image_metadata.php?uuid=b192a572-7b34-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:smack-cav2014-test' => 'https://www.apt.emulab.net/image_metadata.php?uuid=a4594b69-7b36-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:ubuntu1204maas' => 'https://www.apt.emulab.net/image_metadata.php?uuid=e532f26d-7b36-11e4-9439-db9edc46fe2c',
'urn:publicid:IDN+utahddc.geniracks.net+image+emulab-net:Ubuntu1404' => 'https://www.apt.emulab.net/image_metadata.php?uuid=0838c611-7b37-11e4-9439-db9edc46fe2c'
);
sub ConvertDiskImages($)
{
my ($self) = @_;
my $modified = 0;
my $rspec = GeniXML::Parse($self->rspec());
if (! defined($rspec)) {
print STDERR "Could not parse rspec\n";
return -1;
}
foreach my $ref (GeniXML::FindNodes("n:node", $rspec)->get_nodelist()) {
my $diskref = GeniXML::GetDiskImage($ref);
next
if (!defined($diskref));
my $imageurn = GeniXML::GetText("name", $diskref);
next
if (!defined($imageurn));
if (exists($APTImages{$imageurn})) {
GeniXML::SetDiskImage($ref, $APTImages{$imageurn});
$modified = 1;
}
}
if ($modified) {
$self->{'DBROW'}->{'rspec'} = GeniXML::Serialize($rspec);
my $profileid = $self->profileid();
my $version = $self->version();
my $safe_rspec = DBQuoteSpecial($self->rspec());
DBQueryWarn("update apt_profile_versions set rspec=$safe_rspec ".
"where profileid='$profileid' and version='$version'")
if (1);
}
return 0;
}
# Total nonsense, to be thrown away.
sub CheckNodeConstraints($$$)
{
my ($self, $iscloudlab, $pmsg) = @_;
my ($self, $default_aggregate_urn, $pmsg) = @_;
my $cloudwww = "www.utah.cloudlab.us";
my $cloudurn = "urn:publicid:IDN+utah.cloudlab.us+authority+cm";
require URI;
my $rspec = GeniXML::Parse($self->rspec());
......@@ -870,6 +797,11 @@ sub CheckNodeConstraints($$$)
foreach my $ref (GeniXML::FindNodes("n:node", $rspec)->get_nodelist()) {
my $client_id = GetVirtualId($ref);
my $virtualization_type = GeniXML::GetVirtualizationSubtype($ref);
my $manager_urn = GetManagerId($ref);
if (! defined($manager_urn)) {
$manager_urn = $default_aggregate_urn;
}
my $iscloudlab = ($manager_urn eq $cloudurn ? 1 : 0);
if (defined($virtualization_type) && $iscloudlab &&
$virtualization_type eq "emulab-xen") {
......@@ -1012,6 +944,38 @@ sub CheckDatasets($$$)
return 0;
}
#
# Set the component_manager_urn for the sites.
#
sub SetSites($$$)
{
my ($prspecstr, $sitemap, $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()) {
my $client_id = GetVirtualId($ref);
my $site_id = GeniXML::GetJacksSiteId($ref);
if (!defined($site_id)) {
$$perrmsg = "No site ID for $client_id";
return -1;
}
my $site_mid = "site:" . $site_id;
if (!exists($sitemap->{$site_mid})) {
$$perrmsg = "No site mapping for $client_id ($site_id)";
return -1;
}
GeniXML::SetManagerId($ref, $sitemap->{$site_mid});
GeniXML::SetJacksSiteManagerId($ref, $sitemap->{$site_mid});
}
$$prspecstr = GeniXML::Serialize($rspec);
return 0;
}
sub IsHead($)
{
my ($self) = @_;
......
This diff is collapsed.
......@@ -167,7 +167,7 @@ sub DoCreate()
my $read_access;
my $write_access;
# imdataset snapshot info.
my ($instance,$nodeid,$bsname);
my ($instance,$aggregate,$nodeid,$bsname);
my $optlist = "ds:t:e:f:w:p:R:W:I:i:";
my %options = ();
......@@ -196,13 +196,15 @@ sub DoCreate()
if (!defined($instance)) {
fatal("Instance does not exist!");
}
$aggregate_urn = $instance->aggregate_urn();
($nodeid,$bsname) = split(",", $options{"I"});
if (! (defined($nodeid) && defined($bsname))) {
print STDERR "Improper -I opton for imdatasets\n";
&$usage();
}
$aggregate = $instance->FindAggregateByNodeId($nodeid);
if (!defined($aggregate)) {
fatal("Could not find aggregate for $nodeid");
}
}
if (defined($options{"f"})) {
$fstype = $options{"f"};
......@@ -696,7 +698,7 @@ sub DoSnapShotInternal($$$$$)
goto failed;
}
my $response = $instance->CreateImage($sliver_urn,
$dataset->dataset_id(), $bsname);
$dataset->dataset_id(), 0, $bsname);
if ($response->code() != GENIRESPONSE_SUCCESS) {
$errmsg = "SnapshotDataset failed: ". $response->output() . "\n";
goto failed;
......
This diff is collapsed.
......@@ -68,9 +68,15 @@ class Instance
$this->instance = null;
return;
}
$this->instance = mysql_fetch_array($query_result);
$this->instance = mysql_fetch_array($query_result);
$this->slivers = InstanceSliver::LookupForInstance($this);
if (!count($this->slivers) && $this->aggregate_urn()) {
$this->slivers =
array(InstanceSliver::Lookup($this, $this->aggregate_urn()));
}
}
# accessors
function slivers() { return $this->slivers; }
function field($name) {
return (is_null($this->instance) ? -1 : $this->instance[$name]);
}
......@@ -431,4 +437,85 @@ class Instance
}
}
}
class InstanceSliver
{
var $sliver;
#
# Constructor by lookup on unique index.
#
function InstanceSliver($instance, $urn) {
$uuid = $instance->uuid();
$query_result =
DBQueryWarn("select * from apt_instance_aggregates ".
"where uuid='$uuid' and aggregate_urn='$urn'");
if (!$query_result || !mysql_num_rows($query_result)) {
$this->sliver = null;
return;
}
$this->sliver = mysql_fetch_array($query_result);
}
# accessors
function field($name) {
return (is_null($this->sliver) ? -1 : $this->sliver[$name]);
}
function uuid() { return $this->field('uuid'); }
function name() { return $this->field('name'); }
function aggregate_urn(){ return $this->field('aggregate_urn'); }
function status() { return $this->field('status'); }
function public_url() { return $this->field('public_url'); }
function webtask_id() { return $this->field('webtask_id'); }
function manifest() { return $this->field('manifest'); }
# Hmm, how does one cause an error in a php constructor?
function IsValid() {
return !is_null($this->sliver);
}
function Lookup($instance, $urn) {
$foo = new InstanceSliver($instance, $urn);
if ($foo->IsValid()) {
return $foo;
}
#
# Backwards compat for a while, create a fake one.
#
$webtask = WebTask::LookupByObject($instance->uuid());
$foo->sliver = array(
"uuid" => $instance->uuid(),
"name" => $instance->name(),
"aggregate_urn" => $instance->aggregate_urn(),
"status" => $instance->status(),
"public_url" => $instance->public_url(),
"manifest" => $instance->manifest(),
"webtask_id" => $webtask->task_id(),
);
return $foo;
}
#
# Lookup all slivers for an instance
#
function LookupForInstance($instance) {
$result = array();
$uuid = $instance->uuid();
$query_result =
DBQueryFatal("select aggregate_urn from apt_instance_aggregates ".
"where uuid='$uuid'");
while ($row = mysql_fetch_array($query_result)) {
$sliver = InstanceSliver::Lookup($instance, $row['aggregate_urn']);
if ($sliver) {
$result[] = $sliver;
}
}
return $result;
}
}
?>
......@@ -561,8 +561,8 @@ function SPITFORM($formfields, $newuser, $errors)
$am_options .=
"<option $selected value='$am'>$am</option>\n";
}
$html =
"<div class='form-horizontal' id='aggregate_selector'>
$html = "<div id='aggregate_selector'>
<div class='form-horizontal' id='nosite_selector'>
<div class='form-group'>
<label class='col-sm-4 control-label'
style='text-align: right;'>
......@@ -572,8 +572,9 @@ function SPITFORM($formfields, $newuser, $errors)
id='profile_where' class='form-control'>
$am_options</select><br>
<div class='alert alert-warning' id='where-warning' style='display: none'>This profile only works on some clusters. Incompatible clusters are unselectable.</div>
</div></div><div>\n";
echo $html;
</div></div></div>";
$html = $html . "<div id='site_selector' class='hidden'></div></div>";
echo $html;
}
echo "</fieldset>
<div class='form-group row'>
......@@ -819,18 +820,29 @@ if ($profile && $profile->isParameterized() &&
# Allow admin users to select the Aggregate. Experimental.
#
$aggregate_urn = "";
$sitemap = array();
if ($this_user && ($ISCLOUD || ISADMIN() || STUDLY())) {
if (isset($formfields["where"]) && $formfields["where"] != "") {
if (array_key_exists($formfields["where"], $am_array)) {
if (isset($formfields["sites"]) && is_array($formfields["sites"])) {
while (list($siteid, $am) = each($formfields["sites"])) {
if (array_key_exists($am, $am_array)) {
$sitemap[$siteid] = $am_array[$am];
}
else {
$errors["sites"] = "Invalid Aggregate";
break;
}
}
}
elseif (isset($formfields["where"]) &&
$formfields["where"] != "" &&
array_key_exists($formfields["where"], $am_array)) {
$aggregate_urn = $am_array[$formfields["where"]];
}
else {
$errors["where"] = "Invalid Aggregate";
}
}
else {
$errors["where"] = "Invalid Aggregate";
}
}
if (count($errors)) {
SPITFORM($formfields, false, $errors);
SPITFOOTER();
......@@ -929,7 +941,16 @@ if (!$this_user &&
}
# Admins can change aggregate.
$options = ($aggregate_urn != "" ? " -a '$aggregate_urn'" : "");
$options = "";
if ($aggregate_urn != "") {
$options = " -a '$aggregate_urn'";
}
elseif (count($sitemap)) {
while (list($siteid, $urn) = each($sitemap)) {
$options .= "--site 'site:${siteid}=${urn}' ";
}
}
#
# Invoke the backend.
......
......@@ -101,6 +101,7 @@ function (_, editModalString)
mode: this.mode,
source: 'rspec',
root: '#edit_nopicker',
multiSite: true,
nodeSelect: true,
readyCallback: _.bind(this.jacksReady, this),
show: {
......
......@@ -17,6 +17,7 @@ function (_, Constraints, sup, ppstart, aboutaptString, aboutcloudString, waitwa
var webonly = 0;
var portal = null;
var registered = false;
var JACKS_NS = "http://www.protogeni.net/resources/rspec/ext/jacks/1";
var jacks = {
instance: null,
input: null,
......@@ -217,6 +218,8 @@ function (_, Constraints, sup, ppstart, aboutaptString, aboutcloudString, waitwa
$('#instantiate_submit').attr('disabled', false);
}
CreateAggregateSelectors(rspec);
// Hide the aggregate picker for a parameterized profile.
// Shown later.
if (ispprofile) {
......@@ -305,6 +308,73 @@ function (_, Constraints, sup, ppstart, aboutaptString, aboutcloudString, waitwa
}
}
/*
* Build up a list of Aggregate selectors. Normally just one, but for
* a multisite aggregate, need more then one.
*/
function CreateAggregateSelectors(rspec)
{
var xmlDoc = $.parseXML(rspec);
var xml = $(xmlDoc);
var sites = {};
var html = "";
/*
* Find the sites. Might not be any if not a multisite topology
*/
$(xml).find("node").each(function() {
var node_id = $(this).attr("client_id");
var site = this.getElementsByTagNameNS(JACKS_NS, 'site');
if (! site.length) {
return;
}
var siteid = $(site).attr("id");
if (siteid === undefined) {
console.log("No site ID in " + site);
return;
}
sites[siteid] = siteid;
});
if (Object.keys(sites) == 0) {
$("#site_selector").addClass("hidden");
$("#nosite_selector").removeClass("hidden");
// Clear the form data.
$("#site_selector").html("");
return;
}
// Create the dropdown selection list. First the options which
// are duplicated in each dropdown.
var options = "";
_.each(amlist, function(name) {
options = options +
"<option value='" + name + "'>" + name + "</option>";
});
for (var siteid in sites) {
html = html +
"<div class='form-horizontal'>" +
" <div class='form-group'>" +
" <label class='col-sm-4 control-label' " +
" style='text-align: right;'>"+
" <a href=cluster-status.php " +
" target=_blank>Site " + siteid + " Cluster:</a>" +
" </label> " +
" <div class='col-sm-6'>" +
" <select name=\"formfields[sites][" + siteid + "]\"" +
" class='form-control'>" + options +
" </select>" +
"</div></div><div>";
}
html = html + "<br>";
console.info(html);
$("#nosite_selector").addClass("hidden");
$("#site_selector").removeClass("hidden");
$("#site_selector").html(html);
}
var constraints;
function contextReady(data)
......
......@@ -55,6 +55,7 @@ function maketopmap(divname, xml, sshcallback, writeable)
jacksInstance = new window.Jacks({
mode: 'viewer',
source: 'rspec',
multiSite: true,
root: divname,
nodeSelect: writeable,
readyCallback: function (input, output) {
......
This diff is collapsed.
......@@ -94,30 +94,35 @@ function Do_GetInstanceStatus()
}
$blob = array();
$blob["status"] = $instance->status();
# Indicate that we have a manifest and so we can view it.
$blob["havemanifest"] = ($instance->manifest() ? 1 : 0);
# Provide PublicURL so that we can show the sliver info button
if ($instance->public_url()) {
$blob["publicURL"] = $instance->public_url();
}
$blob["sliverstatus"] = array();
$blob["sliverurls"] = array();
$webtask = WebTask::LookupByObject($instance->uuid());
if ($webtask) {
if ($webtask->exited()) {
# Reflect errors back to the user.
if ($webtask->exitcode() == 26) {
$blob["reason"] = "Not enough free nodes, ".
"please try again later.";
}
else {
$blob["reason"] = htmlentities($webtask->TaskValue("output"));
#
# If we have all of our manifests, the client can request them
# and show the topology.
#
$havemanifests = 1;
foreach ($instance->slivers() as $sliver) {
if (!$sliver->manifest()) {
$havemanifests = 0;
}
else {
$webtask = WebTask::Lookup($sliver->webtask_id());
if ($webtask) {
$sliverstatus = $webtask->TaskValue("sliverstatus");
if ($sliverstatus) {
$blob["sliverstatus"][$sliver->aggregate_urn()] =
$sliverstatus;
}
}
}
$sliverstatus = $webtask->TaskValue("sliverstatus");
if ($sliverstatus) {
$blob["sliverstatus"] = $sliverstatus;
if ($sliver->public_url()) {
$blob["sliverurls"][$sliver->aggregate_urn()] =
$sliver->public_url();
}
}
$blob["havemanifests"] = $havemanifests;
SPITAJAX_RESPONSE($blob);
}
......@@ -167,24 +172,14 @@ function Do_TerminateInstance()
}
# This needs work.
$retval = SUEXEC("nobody", "nobody",
"webmanage_instance -t $webtask_id -- terminate $uuid",
"webmanage_instance terminate $uuid",
SUEXEC_ACTION_CONTINUE);
$webtask = WebTask::Lookup($webtask_id);
if ($retval == 0) {
SPITAJAX_RESPONSE("");
if ($webtask) {
$webtask->Delete();
}
return;
}
if ($webtask && $webtask->exited()) {
SPITAJAX_ERROR(1, $webtask->TaskValue("output"));
$webtask->Delete();
}
else {
SPITAJAX_ERROR(-1, "Internal Error. Please try again later");
}
SPITAJAX_ERROR(-1, "Unable to Terminate; please try again later");
}
#
......@@ -198,7 +193,14 @@ function Do_GetInstanceManifest()
return;
}
SPITAJAX_RESPONSE($instance->manifest());
$blob = array();
foreach ($instance->slivers() as $sliver) {
if ($sliver->manifest()) {
$blob[$sliver->aggregate_urn()] = $sliver->manifest();
}
}
SPITAJAX_RESPONSE($blob);
}
#
......@@ -747,12 +749,7 @@ function Do_Refresh()
}
return;
}
$blob = array();
if ($webtask) {
$blob = $webtask->TaskValue("sliverstatus");
$webtask->Delete();
}
SPITAJAX_RESPONSE($blob);
SPITAJAX_RESPONSE("Success");
}
#
......
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