status.ajax 24.1 KB
Newer Older
1 2
<?php
#
3
# Copyright (c) 2000-2015 University of Utah and the Flux Group.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
# 
# {{{EMULAB-LICENSE
# 
# This file is part of the Emulab network testbed software.
# 
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
# 
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
# License for more details.
# 
# You should have received a copy of the GNU Affero General Public License
# along with this file.  If not, see <http://www.gnu.org/licenses/>.
# 
# }}}
#
chdir("..");
25
include_once("webtask.php");
26 27 28 29 30 31 32 33 34 35 36 37
include_once("geni_defs.php");
chdir("apt");
include_once("profile_defs.php");
include_once("instance_defs.php");

# Set these globals below.
$instance = null;
$creator  = null;

#
# Locate the objects and check permission.
#
38
function StatusSetupAjax($needmodify)
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
{
    global $this_user, $ajax_args;
    global $instance, $creator;

    if (!isset($ajax_args["uuid"])) {
	SPITAJAX_ERROR(1, "Missing instance uuid");
	return 1;
    }
    $uuid = $ajax_args["uuid"];
    $instance = Instance::Lookup($uuid);
    if (!$instance) {
	SPITAJAX_ERROR(1, "no such instance uuid: $uuid");
	return 1;
    }
    $creator = GeniUser::Lookup("sa", $instance->creator_uuid());
    if (! $creator) {
	$creator = User::LookupByUUID($instance->creator_uuid());
    }
    if (!$creator) {
	SPITAJAX_ERROR(1, "no such instance creator");
	return 1;
    }
61
    # Admin users do whatever they like.
62 63 64
    if (isset($this_user) && ISADMIN()) {
	return 0;
    }
65 66 67 68 69 70 71 72 73 74 75 76 77 78
    # For a guest user; must be the same guest that created experiment.
    if (get_class($creator) == "GeniUser") {
        if (isset($_COOKIE['quickvm_user']) &&
            $_COOKIE['quickvm_user'] == $creator->uuid()) {
            return 0;
        }
	SPITAJAX_ERROR(1, "You do not have permission!");
	return 1;
    }
    # An experiment created by a real user, can be accessed by other
    # members of the project, subject to modify restrictions.
    if (! (isset($this_user) && get_class($creator) == "User" &&
           $instance->CanView($this_user) &&
           (!$needmodify || $instance->CanModify($this_user)))) {
79 80 81 82 83 84 85 86 87 88 89 90 91
	SPITAJAX_ERROR(1, "You do not have permission!");
	return 1;
    }
    return 0;
}

#
# Status/
#
function Do_GetInstanceStatus()
{
    global $instance, $creator;

92
    if (StatusSetupAjax(0)) {
93 94
	return;
    }
95 96
    $blob = array();
    $blob["status"] = $instance->status();
97 98
    $blob["sliverstatus"] = array();
    $blob["sliverurls"]   = array();
99
    
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
    #
    # 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;
                }
118 119
            }
        }
120 121 122
        if ($sliver->public_url()) {
            $blob["sliverurls"][$sliver->aggregate_urn()] =
                $sliver->public_url();
123
        }
124
    }
125
    $blob["havemanifests"] = $havemanifests;
126
    SPITAJAX_RESPONSE($blob);
127 128 129 130 131 132 133
}

#
# Terminate.
#
function Do_TerminateInstance()
{
134
    global $instance, $creator, $this_user, $ajax_args;
135

136
    if (StatusSetupAjax(1)) {
137 138 139
	return;
    }
    $uuid = $instance->uuid();
140 141 142 143 144 145 146 147 148 149
    $webtask_id = WebTask::GenerateID();

    if ($instance->admin_lockdown() || $instance->user_lockdown()) {
        if (! (isset($this_user) &&
               ($instance->creator() == $this_user->uid() || ISADMIN()))) {
            SPITAJAX_ERROR(1, "Not enough permission to terminate; ".
                           "experiment is locked down");
            return;
        }
        $override = substr($uuid, 2, 5);
150

151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
        if (! (isset($ajax_args["lockdown_override"]) &&
               $ajax_args["lockdown_override"] == $override)) {
            SPITAJAX_ERROR(1, "Lockdown override is incorrect");
            return;
        }
        $retval = SUEXEC($this_user->uid(), "nobody",
                         "webmanage_instance -t $webtask_id -- ".
                         "  lockdown $uuid clear all",
                         SUEXEC_ACTION_CONTINUE);
        if ($retval) {
            $webtask = WebTask::Lookup($webtask_id);

            if ($webtask && $webtask->exited()) {
                SPITAJAX_ERROR(1, $webtask->TaskValue("output"));
                $webtask->Delete();
            }
            else {
                SPITAJAX_ERROR(-1, "Internal Error. Please try again later");
            }
            return;
        }
    }
173
    # This needs work.
174
    $retval = SUEXEC("nobody", "nobody",
175
                     "webmanage_instance terminate $uuid",
176
                     SUEXEC_ACTION_CONTINUE);
177 178 179 180 181

    if ($retval == 0) {
	SPITAJAX_RESPONSE("");
	return;
    }
182
    SPITAJAX_ERROR(-1, "Unable to Terminate; please try again later");
183 184 185 186 187 188 189 190 191
}

#
# Manifest.
#
function Do_GetInstanceManifest()
{
    global $instance, $creator;

192
    if (StatusSetupAjax(0)) {
193 194 195
	return;
    }

196 197 198 199 200 201 202 203
    $blob = array();

    foreach ($instance->slivers() as $sliver) {
        if ($sliver->manifest()) {
            $blob[$sliver->aggregate_urn()] = $sliver->manifest();
        }
    }
    SPITAJAX_RESPONSE($blob);
204 205 206 207 208 209 210
}

#
# SSH Auth Object
#
function Do_GetSSHAuthObject()
{
211
    global $instance, $creator, $this_user;
212 213 214 215 216 217 218 219
    global $ajax_args;

    if (!isset($ajax_args["hostport"])) {
	SPITAJAX_ERROR(1, "Missing hostport");
	return 1;
    }
    $hostport = $ajax_args["hostport"];
    
220
    if (StatusSetupAjax(1)) {
221 222
	return;
    }
223 224 225
    #
    # XXX Need to deal with multiple members of an experiment.
    #
Leigh B Stoller's avatar
Leigh B Stoller committed
226 227 228
    if (! ((isset($this_user) && $this_user->SameUser($creator)) ||
	   (isset($_COOKIE['quickvm_user']) &&
	    $_COOKIE['quickvm_user'] == $creator->uuid()))) {
229 230 231 232
	SPITAJAX_ERROR(1, "Not allowed to ssh; only the creator");
	return;
    }
    
233 234 235 236 237 238 239 240 241 242 243 244
    $nodeid = $ajax_args["nodeid"];
    $auth   = SSHAuthObject($creator->uid(), $hostport);
    if (!$auth) {
	SPITAJAX_ERROR(1, "Could not create authentication object");
	return;
    }
    SPITAJAX_RESPONSE($auth);
}

#
# Request automatic extension.
#
Leigh B Stoller's avatar
Leigh B Stoller committed
245
function Do_RequestExtension()
246
{
247
    global $instance, $creator, $this_user, $suexec_output;
248
    global $ajax_args;
249
    global $TBMAIL_OPS, $APTMAIL, $EXTENSIONS, $APTBASE;
250 251
    $autoextend_maximum = TBGetSiteVar("aptui/autoextend_maximum");
    $autoextend_maxage  = TBGetSiteVar("aptui/autoextend_maxage");
252
    $reason  = "";
253
    $message = "";
254
    $needapproval = 0;
255
    $granted = 0;
256

257
    if (StatusSetupAjax(1)) {
258
	goto bad;
259 260 261 262 263
    }
    $uuid = $instance->uuid();
    $slice = GeniSlice::Lookup("sa", $instance->slice_uuid());
    if (!slice) {
	SPITAJAX_ERROR(1, "no slice for instance");
264
	goto bad;
265 266
    }
    $expires_time = strtotime($slice->expires());
267
    $created_time = strtotime($instance->created());
268

269 270 271
    if ($autoextend_maximum == 0 && !ISADMIN()) {
	SPITAJAX_ERROR(1, "Extensions are currenly disabled; please ".
                       "contact us if you need to make special arrangements.");
272 273 274
	goto bad;
    }

275 276 277 278
    if (!isset($ajax_args["howlong"]) || $ajax_args["howlong"] == "") {
	SPITAJAX_ERROR(1, "Missing number of days");
	goto bad;
    }
279 280
    $granted = $wanted = $ajax_args["howlong"];
    if (! preg_match("/^\d+$/", $wanted)) {
281 282 283 284
	SPITAJAX_ERROR(1, "Invalid characters in days");
	goto bad;
    }

285
    if (ISADMIN()) {
286
	if ($wanted < 1 || $wanted > 365) {
287
	    SPITAJAX_ERROR(1, "Must be an integer 1 <= days <= 365");
288
	    goto bad;
289 290 291 292 293 294
	}
	$reason  = "Extended by site administrator";
    }
    else {
	if (!isset($ajax_args["reason"]) || $ajax_args["reason"] == "") {
	    SPITAJAX_ERROR(1, "Missing reason");
295
	    goto bad;
296 297 298
	}
	$reason  = $ajax_args["reason"];

299 300 301 302 303
        if (!TBvalid_fulltext($reason)) {
	    SPITAJAX_ERROR(1, "Illegal characters in reason");
	    goto bad;
        }

304 305 306 307 308
	#
	# Guest users are treated differently.
	#
	if (!isset($this_user)) {
            # Only extend for 24 hours. More later.
309
            $granted = 1;
310

311
	    if ($expires_time > time() + (3600 * 24 * $granted)) {
312
		SPITAJAX_ERROR(1, "You still have a day left. ".
313 314
			       "Try again tomorrow");
		goto delay;
315 316 317
	    }
	}
	else {
318
            $diff  = $expires_time - time();
Leigh B Stoller's avatar
Leigh B Stoller committed
319
            $cdiff = time() - $created_time;
Leigh B Stoller's avatar
Leigh B Stoller committed
320 321 322 323 324 325 326 327 328 329

            #
            # If admin lockout, we are refusing any more free time.
            #
            if ($instance->extension_lockout()) {
                $needapproval = 1;
                $granted = 0;
                $message = "because you are not allowed any more ".
                    "free extensions";
            }
330
            #
331
            # After maxage, all extension requests require admin approval.
332
            #
Leigh B Stoller's avatar
Leigh B Stoller committed
333
            elseif ($cdiff > (3600 * 24 * $autoextend_maxage)) {
334 335 336 337
                #
                # Well, unless they asked for less then the free grant,
                # which is a nice loophole people will probably notice.
                #
338
                $granted = 2;
339 340 341 342 343 344
                
                if ($wanted > $granted) {
                    $needapproval = 1;
                    $message = "because it was started more then ".
                        "$autoextend_maxage days ago";
                }
345
            }
346
	    #
347 348 349 350 351
	    # Registered users are granted up to the autoextend_maximum
            # automatically. Beyond that, requires approval, but we still
            # give them whatever the free extension is, since we want
            # to give them extra time until the next meeting of the
            # "resource management committee."
352
	    #
353 354 355 356 357 358 359 360 361 362 363 364 365 366
	    elseif ($wanted > $autoextend_maxage) {
                #
                # We have plenty of time left, no extension just a message.
                #
                if ($diff > (3600 * 24 * 7)) {
                    needAdminApproval($wanted, 0, $reason,
                                      "because it was for longer then ".
                                      "$autoextend_maximum days");
                    goto delay;
                }
                $needapproval = 1;
                $granted = $autoextend_maximum;
                $message = "because it was for longer then ".
                    "$autoextend_maximum days";
367
	    }
368 369 370 371 372 373
            else {
                if ($diff > (3600 * 24 * 7)) {
                    SPITAJAX_ERROR(1, "You still have a week left!");
                    goto bad;
                }
            }
374
	    #
375 376 377 378
	    # The most we allow is the autoextend_maximum out, no
	    # matter what they asked for. So, if the autoextend_maximum
	    # is a week and there are five days left and they asked
	    # for seven, we give them two.
379
	    #
380 381 382
            if ($expires_time + ($granted * 3600 * 24) >
                time() + (3600 * 24 * $autoextend_maximum)) {
		$seconds = (3600 * 24 * $autoextend_maximum) - $diff;
383
                $granted = intval($seconds / (3600 * 24));
384
	    }
385
        }
386
    }
387 388
    if ($granted > 0) {
        $seconds = 3600 * 24 * $granted;
389 390 391 392
        $retval = SUEXEC("nobody", "nobody",
                         "webmanage_instance extend $uuid $seconds",
                         SUEXEC_ACTION_CONTINUE);
    }
393 394

    if ($retval == 0) {
395
	# Refresh. 
396
	$slice = GeniSlice::Lookup("sa", $instance->slice_uuid());
Leigh B Stoller's avatar
Leigh B Stoller committed
397 398
	$new_expires = date("Y-m-d H:i:s T", strtotime($slice->expires()));
        $created = date("Y-m-d H:i:s T", strtotime($instance->created()));
399 400
        $before = date("Y-m-d H:i:s T", strtotime($expires_time));
        $now = date("Y-m-d H:i:s T", strtotime(time()));
Leigh B Stoller's avatar
Leigh B Stoller committed
401
        list($cluster) = Instance::ParseURN($instance->aggregate_urn());
402

403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
        #
        # We store each extension request in an ongoing text field.
        #
        $text =
            "Date: $now\n".
            "Wanted: $wanted, Granted: $granted\n".
            "Before: $before\n".
            "After $new_expires\n".
            "Reason:\n".
            $reason . "\n\n".
            "-----------------------------------------------\n";
        $instance->AddExtensionHistory($text);

        if ($needapproval) {
            needAdminApproval($wanted, $granted, $reason, $message);
            if (!$granted)
                goto delay;
            return;
        }
422 423
	SPITAJAX_RESPONSE($new_expires);

424 425 426
	$instance->SendEmail($creator->email(),
	       "Experiment Extension: $uuid",
	       "A request to extend your experiment was made and ".
427 428
	       "granted.\n".
	       "Your reason was:\n\n". $reason . "\n\n".
Leigh B Stoller's avatar
Leigh B Stoller committed
429 430 431
               "Your experiment was started on $created\n".
 	       "Your experiment will now expire at $new_expires\n".
               "It is running on $cluster\n\n\n".
432
               "$APTBASE/status.php?uuid=$uuid\n",
433 434
	       "From: $EXTENSIONS\n" .
	       "BCC: $EXTENSIONS");
435 436 437 438 439 440 441 442
        #
        # We do not want to overwrite the reason in the DB if this
        # was an admin extension, we want to keep whatever the user
        # has written previously.
        #
        if (! ISADMIN()) {
            $instance->SetExtensionReason($reason);
        }
443
        $instance->BumpExtensionCount($granted);
444 445 446
    }
    elseif ($retval > 0) {
	SPITAJAX_ERROR(1, $suexec_output);
447
	goto bad;
448 449 450
    }
    else {
	SPITAJAX_ERROR(-1, "Internal Error. Please try again later");
451
	goto bad;
452
    }
453 454
    return;
bad:
455 456 457 458 459 460 461 462 463 464
delay:
    sleep(1);
}

#
# Helper for above.
#
function needAdminApproval($wanted, $granted, $reason, $message)
{
    global $instance, $creator, $this_user, $suexec_output;
465
    global $EXTENSIONS, $APTBASE;
466 467 468 469 470 471 472 473

    $uuid = $instance->uuid();
    # Subtract out the extra time we added above.
    $howlong = $wanted - $granted;
    $url = "$APTBASE/status.php?uuid=$uuid&extend=$howlong";

    # Refresh. 
    $slice = GeniSlice::Lookup("sa", $instance->slice_uuid());
Leigh B Stoller's avatar
Leigh B Stoller committed
474
    $new_expires = date("Y-m-d H:i:s T",
475
                        strtotime($slice->expires()) + ($howlong * 3600 * 24));
Leigh B Stoller's avatar
Leigh B Stoller committed
476 477
    $created = date("Y-m-d H:i:s T", strtotime($instance->created()));
    list($cluster) = Instance::ParseURN($instance->aggregate_urn());
478
		    
479
    $instance->SendEmail($EXTENSIONS,
480 481 482 483 484 485 486
        "Experiment Extension Request: $uuid",
        "A request to extend this experiment was made but requires\n".
        "administrator approval" .
        ($message ? " because $message" : "") . ".\n\n" .
        "The request was for $wanted days, we granted $granted days, ".
        "the reason given is:\n\n".
        $reason . "\n\n".
487
        "This experiment was started on $created\n".
488
        "Granting the request would set the expiration to $new_expires\n".
Leigh B Stoller's avatar
Leigh B Stoller committed
489
        "It is running on $cluster\n".
490
        "\n\n". $url . "\n\n",
491 492 493
        "From: " . $creator->email());

    $instance->SetExtensionReason($reason);
494
    $instance->BumpExtensionCount($granted);
495 496 497 498
            
    # XXX 
    SPITAJAX_ERROR(2, "Your request requires admininstrator approval".
                   ($message ? " because $message" : "") . ". " .
Leigh B Stoller's avatar
Leigh B Stoller committed
499 500
                   "You will receive email if/when your ".
                   "request is granted (or denied). Thanks!");
501
    return;
502
}
503

504 505 506 507 508 509 510 511 512
#
# Request a console URL and pass back to the status page.
#
function Do_ConsoleURL()
{
    global $instance, $creator;
    global $ajax_args;

    if (!isset($ajax_args["node"])) {
513
	SPITAJAX_ERROR(1, "Missing node argument");
514 515 516 517
	return 1;
    }
    $node = $ajax_args["node"];

518
    if (StatusSetupAjax(1)) {
519 520 521 522 523 524 525 526
	return;
    }
    $uuid = $instance->uuid();
    $slice = GeniSlice::Lookup("sa", $instance->slice_uuid());
    if (!slice) {
	SPITAJAX_ERROR(1, "no slice for instance");
	return 1;
    }
527
    $webtask_id = WebTask::GenerateID();
528
    $retval = SUEXEC("nobody", "nobody",
529 530
		     "webmanage_instance -t $webtask_id -- consoleurl $uuid " .
		     escapeshellarg($node),
531
		     SUEXEC_ACTION_CONTINUE);
532
    $webtask = WebTask::Lookup($webtask_id);
533 534

    if ($retval == 0) {
Leigh B Stoller's avatar
Leigh B Stoller committed
535 536 537 538 539 540 541
        $taskdata = $webtask->TaskData();
        $blob = array();
        $blob["url"] = $taskdata["url"];
        if (isset($taskdata["password"])) {
            $blob["password"] = $taskdata["password"];
        }
	SPITAJAX_RESPONSE($blob);
542 543
	$webtask->Delete();
	return;
544
    }
545
    if ($webtask) {
Leigh B Stoller's avatar
Leigh B Stoller committed
546
	SPITAJAX_ERROR(1, $webtask->TaskValue("output"));
547
	$webtask->Delete();
548 549 550 551 552 553
    }
    else {
	SPITAJAX_ERROR(-1, "Internal Error. Please try again later");
    }
}

554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
#
# Fire off a snapshot.
#
function Do_Snapshot()
{
    global $this_user;
    global $ajax_args;

    $this_idx = $this_user->uid_idx();

    if (!isset($ajax_args["uuid"])) {
	SPITAJAX_ERROR(1, "Missing profile uuid");
	return;
    }
    $uuid = $ajax_args["uuid"];
    $instance = Instance::Lookup($uuid);
    if (!$instance) {
	SPITAJAX_ERROR(1, "Unknown instance uuid");
	return;
    }
    if ($this_idx != $instance->creator_idx() && !ISADMIN()) {
	SPITAJAX_ERROR(1, "Not enough permission. Maybe Clone instead?");
	return;
    }
    if ($instance->status() != "ready") {
	SPITAJAX_ERROR(1, "Experiment is currently busy");
	return;
    }
    #
    # The profile also has to belong to the user, since it is
    # going to be modified to use the new image.
    #
586 587
    $profile = Profile::Lookup($instance->profile_id(),
			       $instance->profile_version());
588 589 590 591 592 593 594 595
    if (!$profile) {
	SPITAJAX_ERROR(1, "Cannot lookup profile for instance");
	return;
    }
    if ($this_idx != $profile->creator_idx() && !ISADMIN()) {
	SPITAJAX_ERROR(1, "Not your profile to change. Clone first!");
	return;
    }
Leigh B Stoller's avatar
Leigh B Stoller committed
596
    $optargs = "";
Leigh B Stoller's avatar
Leigh B Stoller committed
597
    if (isset($ajax_args["node_id"]) && $ajax_args["node_id"] != "") {
Leigh B Stoller's avatar
Leigh B Stoller committed
598 599 600 601 602
        $node_id = $ajax_args["node_id"];
        if (!TBvalid_vnode_id($node_id)) {
            SPITAJAX_ERROR(1, "Bad node id");
            return;
        }
603
        $optargs .= " -n $node_id ";
Leigh B Stoller's avatar
Leigh B Stoller committed
604 605 606 607 608 609

        if (isset($ajax_args["update_profile"]) &&
            $ajax_args["update_profile"]) {
            $optargs .= " -u all ";
        }
    }
610 611 612 613
    if (isset($ajax_args["update_prepare"]) &&
        $ajax_args["update_prepare"]) {
        $optargs .= " -U ";
    }
614 615 616 617
    
    #
    # Call out to the backend.
    #
618
    $webtask_id = WebTask::GenerateID();
619
    $retval = SUEXEC($this_user->uid(), "nobody",
Leigh B Stoller's avatar
Leigh B Stoller committed
620
		     "webmanage_instance -t $webtask_id -- ".
621
                     "  snapshot $uuid $optargs",
622
		     SUEXEC_ACTION_IGNORE);
623
    $webtask = WebTask::Lookup($webtask_id);
624 625 626

    if ($retval != 0) {
	if ($retval < 0) {
627
	    SPITAJAX_ERROR(-11, "Internal error, cannot proceed.");
628 629 630
	    # Notify tbops.
	    SUEXECERROR(SUEXEC_ACTION_CONTINUE);
	}
631
	elseif ($webtask) {
Leigh B Stoller's avatar
Leigh B Stoller committed
632
	    SPITAJAX_ERROR(1, $webtask->TaskValue("output"));
633
	}
634
	else {
635
	    SPITAJAX_ERROR(-1, "Internal Error. Please try again later");
636
	}
637 638 639
	if ($webtask) {
	    $webtask->Delete();
	}
640
	return;
641
    }
Leigh B Stoller's avatar
Leigh B Stoller committed
642
    if ($webtask && $webtask->exited()) {
643 644
	$webtask->Delete();
    }
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
    SPITAJAX_RESPONSE("Success");
}

#
# Return snapshot status.
#
function Do_SnapshotStatus()
{
    global $this_user;
    global $ajax_args;

    $this_idx = $this_user->uid_idx();

    if (!isset($ajax_args["uuid"])) {
	SPITAJAX_ERROR(1, "Missing profile uuid");
	return;
    }
    $instance = Instance::Lookup($ajax_args["uuid"]);
    if (!$instance) {
	SPITAJAX_ERROR(1, "Unknown instance uuid");
	return;
    }
    if ($this_idx != $instance->creator_idx() && !ISADMIN()) {
	SPITAJAX_ERROR(1, "Not enough permission");
	return;
    }
    $webtask = WebTask::LookupByObject($instance->uuid());
    if (!$webtask) {
	SPITAJAX_ERROR(1, "No status descriptor found");
	return;
    }
    $taskdata = $webtask->TaskData();
    $blob = array();

    #
    # Size is in KB to avoid bigint problems. But kill the KB.
    # 
    if (isset($taskdata["image_size"])) {
	if (preg_match("/^(\d+)KB$/", $taskdata["image_size"], $matches)) {
	    $taskdata["image_size"] = $matches[1]; 
	}
	$blob["image_size"] = $taskdata["image_size"];
    }
    else {
	$blob["image_size"] = 0;
    }
    $blob["node_status"]  = $taskdata["rawstate"];
    $blob["image_status"] = $taskdata["image_status"];
693 694 695 696 697 698
    if ($webtask->exited()) {
	# Success, but not sure what to report. Come back to this later.
	$blob["exited"]   = $webtask->exited();
	$blob["exitcode"] = $webtask->exitcode();
	$webtask->Delete();
    }
699 700 701
    SPITAJAX_RESPONSE($blob);
}

702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751
#
# Ask the backend to refresh sliverstatus
#
function Do_Refresh()
{
    global $this_user;
    global $ajax_args;

    $this_idx = $this_user->uid_idx();

    if (!isset($ajax_args["uuid"])) {
	SPITAJAX_ERROR(1, "Missing profile uuid");
	return;
    }
    $uuid = $ajax_args["uuid"];
    $instance = Instance::Lookup($uuid);
    if (!$instance) {
	SPITAJAX_ERROR(1, "Unknown instance uuid");
	return;
    }
    if ($this_idx != $instance->creator_idx() && !ISADMIN()) {
	SPITAJAX_ERROR(1, "Not enough permission. Maybe Clone instead?");
	return;
    }
    #
    # Call out to the backend.
    #
    $webtask_id = WebTask::GenerateID();
    $retval = SUEXEC($this_user->uid(), "nobody",
		     "webmanage_instance -t $webtask_id -- refresh $uuid",
		     SUEXEC_ACTION_IGNORE);
    $webtask = WebTask::Lookup($webtask_id);

    if ($retval != 0) {
	if ($retval < 0) {
	    SPITAJAX_ERROR(-11, "Internal error, cannot proceed.");
	    # Notify tbops.
	    SUEXECERROR(SUEXEC_ACTION_CONTINUE);
	}
	elseif ($webtask) {
	    SPITAJAX_ERROR(1, $webtask->TaskValue("output"));
	}
	else {
	    SPITAJAX_ERROR(-1, "Internal Error. Please try again later");
	}
	if ($webtask) {
	    $webtask->Delete();
	}
	return;
    }
752
    SPITAJAX_RESPONSE("Success");
753 754 755
}

#
756
# Ask the backend to reboot or reload a node.
757
#
758
function Do_RebootOrReload($which)
759 760 761 762
{
    global $this_user;
    global $ajax_args;

Leigh B Stoller's avatar
Leigh B Stoller committed
763 764 765 766
    if (!isset($this_user)) {
	SPITAJAX_ERROR(1, "Only registered users can reboot/reload nodes");
	return;
    }
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
    $this_idx = $this_user->uid_idx();

    if (!isset($ajax_args["node_id"])) {
	SPITAJAX_ERROR(1, "Missing node_id");
	return;
    }
    $node_id = $ajax_args["node_id"];
    if (!preg_match("/^[-\w]+$/", $node_id)) {
        SPITAJAX_ERROR(1, "Illegal characters in node_id");
    }

    if (!isset($ajax_args["uuid"])) {
	SPITAJAX_ERROR(1, "Missing profile uuid");
	return;
    }
    $uuid = $ajax_args["uuid"];
    $instance = Instance::Lookup($uuid);
    if (!$instance) {
	SPITAJAX_ERROR(1, "Unknown instance uuid");
	return;
    }
    if ($this_idx != $instance->creator_idx() && !ISADMIN()) {
	SPITAJAX_ERROR(1, "Not enough permission. Maybe Clone instead?");
	return;
    }
    if ($instance->status() != "ready" && $instance->status() != "failed") {
	SPITAJAX_ERROR(1, "Experiment is currently busy");
	return;
    }

    #
    # Call out to the backend.
    #
    $webtask_id = WebTask::GenerateID();
    $retval = SUEXEC($this_user->uid(), "nobody",
		     "webmanage_instance -t $webtask_id -- ".
803
                     "  $which $uuid " . escapeshellarg($node_id), 
804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828
		     SUEXEC_ACTION_IGNORE);
    $webtask = WebTask::Lookup($webtask_id);

    if ($retval != 0) {
	if ($retval < 0) {
	    SPITAJAX_ERROR(-11, "Internal error, cannot proceed.");
	    # Notify tbops.
	    SUEXECERROR(SUEXEC_ACTION_CONTINUE);
	}
	elseif ($webtask) {
	    SPITAJAX_ERROR(1, $webtask->TaskValue("output"));
	}
	else {
	    SPITAJAX_ERROR(-1, "Internal Error. Please try again later");
	}
	if ($webtask) {
	    $webtask->Delete();
	}
	return;
    }
    if ($webtask) {
	$webtask->Delete();
    }
    SPITAJAX_RESPONSE("Success");
}
829 830 831 832 833 834 835 836
function Do_Reboot()
{
    Do_RebootOrReload("reboot");
}
function Do_Reload()
{
    Do_RebootOrReload("reload");
}
837

Leigh B Stoller's avatar
Leigh B Stoller committed
838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
#
# Set or clear the lockout flag
#
function Do_Lockout()
{
    global $this_user;
    global $ajax_args;

    $this_idx = $this_user->uid_idx();

    if (!isset($ajax_args["uuid"])) {
	SPITAJAX_ERROR(1, "Missing profile uuid");
	return;
    }
    if (!isset($ajax_args["lockout"])) {
	SPITAJAX_ERROR(1, "Missing lockout value");
	return;
    }
    $uuid = $ajax_args["uuid"];
    $instance = Instance::Lookup($uuid);
    if (!$instance) {
	SPITAJAX_ERROR(1, "Unknown instance uuid");
	return;
    }
    if (!ISADMIN()) {
	SPITAJAX_ERROR(1, "Not enough permission.");
	return;
    }
    $lockout = ($ajax_args["lockout"] ? 1 : 0);
    if (!DBQueryWarn("update apt_instances set extension_adminonly='$lockout' ".
                     "where uuid='$uuid'")) {
	SPITAJAX_ERROR(1, "Database failure.");
	return;
    }
    SPITAJAX_RESPONSE("Success");
}

875 876 877
# Local Variables:
# mode:php
# End:
878
?>