Ejemplo n.º 1
0
function build_agg_table_on_slicepg()
{
    global $am_list;
    global $slice;
    global $slice_id;
    global $renew_slice_privilege;
    global $slice_expiration;
    global $slice_date_expiration;
    global $delete_slivers_disabled;
    global $slice_name;
    global $disable_buttons_str;
    global $get_slice_credential_disable_buttons;
    global $add_slivers_disabled;
    $sliver_expiration = "NOT IMPLEMENTED YET";
    $slice_status = "";
    $add_url = 'slice-add-resources-jacks.php?slice_id=' . $slice_id;
    $listres_url = 'listresources.php?slice_id=' . $slice_id;
    $updating_text = "Updating status...";
    $initial_text = "Status not retrieved";
    $output = "";
    $output .= "<table id='actions_table' class='card'>";
    $output .= "<tr id='manage'><th colspan='3'>Manage Resources</th></tr>";
    $output .= "<tr class='statusButtons'><td><button onClick=\"selectAll()\">Select All</button>";
    $output .= "<button onClick=\"deselectAll()\">Deselect All</button></td>";
    $output .= "<td colspan='2'>";
    $output .= "<button title='Get summary status for resources at selected aggregates.' onClick=\"getCheckedStatus();\"><b>Ready?</b></button>";
    $output .= "<button title='Login info, etc. for resources at selected aggregates.' onClick=\"doOnChecked('{$listres_url}');\"><b>Resource Details</b></button>";
    $output .= "<button title='Delete resources at selected aggregates.' onClick=\"doOnChecked('confirm-sliverdelete.php?slice_id=" . $slice_id . "', true)\"><b>Delete Resources</b></button>";
    $output .= "</td></tr>\n";
    $output .= "<tr><td><span style='margin: 0 5px;'>Select Only: </span><select id='checkGroups'>";
    $output .= "<option style='display:none;'> </option>";
    $output .= "<option value='op_my_slice' class='op_my_slice'>This Slice</option>";
    $output .= "<option class='op_" . SERVICE_ATTRIBUTE_COMPUTE_CAT . "'>Compute</option>";
    $output .= "<option class='op_" . SERVICE_ATTRIBUTE_NETWORK_CAT . "'>Network</option>";
    $output .= "<option class='op_" . SERVICE_ATTRIBUTE_STITCHABLE_CAT . "'>Stitchable</option>";
    $output .= "<option class='op_" . SERVICE_ATTRIBUTE_PROD_CAT . "'>Production</option>";
    $output .= "<option class='op_" . SERVICE_ATTRIBUTE_DEV_CAT . "'>Development</option>";
    $output .= "<option class='op_" . SERVICE_ATTRIBUTE_EXPERIMENTAL_CAT . "'>Experimental</option>";
    $output .= "<option class='op_" . SERVICE_ATTRIBUTE_FEDERATED_CAT . "'>Federated</option>";
    $output .= "</select>";
    $output .= "</td>";
    $output .= "<td colspan='2'>";
    if ($renew_slice_privilege) {
        $output .= "<input id='renew_field_check' class='date' type='text' name='sliver_expiration' placeholder='Select Date...' ";
        $size = strlen($slice_date_expiration) + 3;
        $output .= "size=\"{$size}\"/>\n";
        $output .= "<button id='renew_button_check' title='Renew resource reservation at selected aggregates until the specified date' ";
        $output .= "onClick=\"confirmQuerySelected('" . $slice_id . "');\"";
        $output .= "{$disable_buttons_str}><b>Renew Resources</b></button>\n";
    }
    $output .= "</td></tr>\n";
    $output .= "<tr><td id='am_name_list'><ul id='am_names'>";
    $output .= "<li id='g_exogeni' class='am_group'><div class='collapsable'></div><input type='checkbox' id='exogenibox' class='outer' checked='checked'><span class='checkSib'>ExoGENI<span class='countSelected'> (0)</span></span><ul style='display:none;'></ul></li>";
    $output .= "<li id='g_foam' class='am_group'><div class='collapsable'></div><input type='checkbox' id='foambox' class='outer' checked='checked'><span class='checkSib'>FOAM<span class='countSelected'> (0)</span></span><ul style='display:none;'></ul></li>";
    $output .= "<li id='g_instageni' class='am_group'><div class='collapsable'></div><input type='checkbox' id='instagenibox' class='outer' checked='checked'><span class='checkSib'>InstaGENI<span class='countSelected'> (0)</span></span><ul style='display:none;'></ul></li>";
    $output .= "<li id='g_other' class='am_group'><div class='collapsable'></div><input type='checkbox' id='otherbox' class='outer' checked='checked'><span class='checkSib'>Other<span class='countSelected'> (0)</span></span><ul style='display:none;'></ul></li>";
    $output .= "</ul>";
    $output .= "</td>";
    // (2) create an HTML table with one row for each aggregate
    $output .= "<td colspan='2'><div id='status_table_cont'>";
    $output .= "<div id='none-selected'>You do not have any aggregates selected.<br /> Please select aggregates on the left.</div>";
    $output .= "<table id='status_table' cols='3'>";
    foreach ($am_list as $am) {
        $name = $am[SR_TABLE_FIELDNAME::SERVICE_NAME];
        $am_id = $am[SR_TABLE_FIELDNAME::SERVICE_ID];
        $am_type = lookup_attribute($am[SR_TABLE_FIELDNAME::SERVICE_URL], SERVICE_ATTRIBUTE_AM_TYPE);
        if ($am_type) {
            $output .= "<tbody id='t_" . $am_id . "' class='" . $am_type;
        } else {
            $output .= "<tbody id='t_" . $am_id . "' class='ui_other_am";
        }
        $am_cat = lookup_attribute($am[SR_TABLE_FIELDNAME::SERVICE_URL], SERVICE_ATTRIBUTE_AM_CAT);
        if ($am_cat) {
            $output .= " " . $am_cat;
        }
        $output .= "' tabindex='-1'>";
        $output .= "<tr id='" . $am_id . "'>";
        $output .= "<td colspan='1' class='am_name_field'><b>";
        $output .= $name;
        $output .= "</b></td>";
        // sliver expiration
        $output .= "<td colspan='2' class='hide status_buttons'><div>";
        $output .= "<button  id='add_button_" . $am_id . "' title='Add resources at this aggregate.' onClick=\"window.location='" . $add_url . "&am_id=" . $am_id . "'\" {$add_slivers_disabled} {$disable_buttons_str}><b>Add</b></button>\n";
        $output .= "<button  id='details_button_" . $am_id . "' title='Login info, etc. for resources at this aggregate.' onClick=\"window.location='" . $listres_url . "&am_id=" . $am_id . "'\" {$get_slice_credential_disable_buttons}><b>Details</b></button>\n";
        $output .= "<button  id='delete_button_" . $am_id . "' title='Delete resources at this aggregate.' onClick=\"window.location='confirm-sliverdelete.php?slice_id=" . $slice_id . "&am_id=" . $am_id . "'\" " . $delete_slivers_disabled . " {$disable_buttons_str}><b>Delete</b></button>\n";
        $output .= "</div></td></tr>";
        $output .= "<tr class='notqueried'><td colspan='1' id='status_" . $am_id . "' class='notqueried'>";
        $output .= $initial_text;
        $output .= "</td>";
        $output .= "<td class='hide' colspan='2'><div>";
        $output .= "<button id='reload_button_" . $am_id . "' title='Get summary status for resources at this aggregate.' type='button' onclick='refresh_agg_row(" . $am_id . ")' class='getButton' {$get_slice_credential_disable_buttons}>Ready?</button>";
        $output .= "<div class='renewForm'><div class='expireText'>Expires on <b><span class='renew_date' id='renew_sliver_" . $am_id . "'>" . $initial_text . "</span></b></div>";
        if ($renew_slice_privilege) {
            $output .= "<form  method='GET' action=\"do-renew.php\">";
            $output .= "<input type=\"hidden\" name=\"slice_id\" value=\"" . $slice_id . "\"/>\n";
            $output .= "<input type=\"hidden\" name=\"am_id\" value=\"" . $am_id . "\"/>\n";
            $output .= "<input type=\"hidden\" name=\"renew\" value=\"sliver\"/>\n";
            $output .= "<input id='renew_field_" . $am_id . "' class='date' type='text' placeholder='Select Date...' name='sliver_expiration' ";
            $size = strlen($slice_date_expiration) + 3;
            $output .= "size=\"{$size}\"/>\n";
            $output .= "<button id='renew_button_" . $am_id . "' onclick='confirmQueryTable(" . $am_id . ")' type='button' {$disable_buttons_str} title='Renew resource reservation at this aggregate until the specified date'>Renew</button>\n";
            $output .= "</form></div>";
        }
        $output .= "</div></td></tr>";
        // (3) Get the status for this slice at this aggregate
        //	    update_agg_row( am_id );
    }
    $output .= "</table></div></td>";
    $output .= "</tr></table>";
    return $output;
}
Ejemplo n.º 2
0
function invoke_omni_function($am_urls, $user, $args, $slice_users = array(), $bound_rspec = 0, $stitch_rspec = 0, $fork = false, $omni_invocation_dir = NULL, $api_version = "2")
{
    global $portal_gcf_dir;
    /* $file_manager only holds on to non-critical files (i.e., those
       that can be deleted regardless of whether the call was successful
       or not). */
    $file_manager = new FileManager();
    //  error_log("INVOKE : " . print_r($am_urls, true));
    // If we get a single URL, make it an array (handle the general case)
    if ($am_urls && !is_array($am_urls)) {
        $am_urls = array($am_urls);
    }
    /* Does each given URL handle speaks-for?
            If one or more AM URLs are given, check the SR for whether SF is enabled.
            If no AM URL is given but it's for stitching, just assume for now
                that all AMs handle SpeaksFor and see what happens.
      */
    if ($am_urls) {
        $handles_speaks_for = True;
        foreach ($am_urls as $am_url) {
            $am_handles_speaks_for = lookup_attribute($am_url, SERVICE_ATTRIBUTE_SPEAKS_FOR) == 't';
            if (!$am_handles_speaks_for) {
                $handles_speaks_for = False;
                break;
            }
        }
    } else {
        $handles_speaks_for = True;
    }
    /*
     If an aggregate doesn't handle speaks-for, 
     we use the inside cert and key of the user
     If an aggregate DOES handle speaks-for and the
     user has a speaks-for credential, 
     portal's cert and key and pass along the geni_speaking_for option
    */
    $speaks_for_invocation = false;
    $cert = $user->insideCertificate();
    $private_key = $user->insidePrivateKey();
    $speaks_for_cred = $user->speaksForCred();
    if ($handles_speaks_for and $speaks_for_cred) {
        $speaks_for_invocation = true;
        $cert = $user->certificate();
        $private_key = $user->privateKey();
    }
    $username = $user->username;
    $urn = $user->urn();
    // Get the authority from the user's URN
    parse_urn($urn, $authority, $type, $name);
    $aggregates = "aggregates=";
    $first = True;
    // get AMs if non-stitchable
    if (!$stitch_rspec) {
        if (is_array($am_urls)) {
            if (count($am_urls) == 0) {
                error_log("am_client Got non stitching RSpec and 0 AM URLs");
                // Careful: Are all RSpecs that stitcher can handle marked as stitch_rspecs properly?
                // return("Invalid AM URL");
            }
            foreach ($am_urls as $single) {
                if (!isset($single) || is_null($single) || $single == '') {
                    error_log("am_client cannot invoke Omni with invalid AM URL");
                    return "Invalid AM URL";
                }
                if ($first) {
                    $first = False;
                } else {
                    $aggregates = $aggregates . ", ";
                }
                $aggregates = $aggregates . $single;
            }
            $aggregates = $aggregates . "\n";
        } elseif (!isset($am_url) || is_null($am_url) || $am_url == '') {
            error_log("am_client cannot invoke Omni without an AM URL");
            return "Missing AM URL";
        }
    }
    /* Create a directory to store all temp files, including logs and error
          messages *if one doesn't exist already*. Let the prefix be the username.
          An "omni invocation ID" is created.
       
          Returns something like: /tmp/omni-invoke-myuser-RKvQ1Z
       */
    if (is_null($omni_invocation_dir)) {
        $omni_invocation_dir = createTempDir($username);
    }
    /* Write key and credential files */
    $tmp_version_cache = "{$omni_invocation_dir}/omniVersionCache";
    $tmp_agg_cache = "{$omni_invocation_dir}/omniAggCache";
    $file_manager->add($tmp_version_cache);
    $file_manager->add($tmp_agg_cache);
    $cert_file = writeDataToTempDir($omni_invocation_dir, $cert, OMNI_INVOCATION_FILE::CERTIFICATE_FILE);
    $file_manager->add($cert_file);
    $key_file = writeDataToTempDir($omni_invocation_dir, $private_key, OMNI_INVOCATION_FILE::PRIVATE_KEY_FILE);
    $file_manager->add($key_file);
    $slice_users = $slice_users + array($user);
    $username_array = array();
    $all_ssh_key_files = array();
    $ssh_key_files_by_user = array();
    foreach ($slice_users as $slice_user) {
        $slice_urn = $slice_user->urn();
        $ssh_key_files = write_ssh_keys($slice_user, $user, $omni_invocation_dir);
        // Skip from omni_config any user with no public SSH keys
        if (count($ssh_key_files) == 0) {
            continue;
        }
        $all_ssh_key_files = array_merge($all_ssh_key_files, $ssh_key_files);
        $ssh_key_files_by_user[$slice_urn] = $ssh_key_files;
        $username_array[] = $slice_user->username;
    }
    /* Create OMNI config file */
    if (!isset($sa_url)) {
        $sa_url = get_first_service_of_type(SR_SERVICE_TYPE::SLICE_AUTHORITY);
    }
    if (!isset($ma_url)) {
        $ma_url = get_first_service_of_type(SR_SERVICE_TYPE::MEMBER_AUTHORITY);
    }
    $omni_config = "[omni]\n" . "default_cf = my_chapi\n" . "users = " . implode(", ", $username_array) . "\n";
    // As of omni 2.7, by default omni queries the CH to get slice members
    // We pass those in explicitly and don't want the extra query
    $omni_config .= "useslicemembers = False\n";
    // specify AM for non-stitchable RSpecs
    if (!$stitch_rspec) {
        if (is_array($am_urls)) {
            $omni_config = $omni_config . $aggregates . "\n";
        }
    }
    # Create the aggregate nickname cache file
    if (!write_agg_nick_cache($tmp_agg_cache)) {
        error_log("Failed to write the aggregate nickname cache.");
        // Now what? Continue?
    }
    // FIXME: Get the /CH URL from a portal/www/portal/settings.php entry?
    $omni_config = $omni_config . "[my_chapi]\n" . "type=chapi\n" . "authority={$authority}\n" . "ch=https://{$authority}:8444/CH\n" . "sa={$sa_url}\n" . "ma={$ma_url}\n" . "cert={$cert_file}\n" . "key={$key_file}\n";
    foreach ($slice_users as $slice_user) {
        $slice_username = $slice_user->username;
        $slice_urn = $slice_user->urn();
        if (!array_key_exists($slice_urn, $ssh_key_files_by_user)) {
            // This user had no SSH keys
            continue;
        }
        $all_key_files = implode(',', $ssh_key_files_by_user[$slice_urn]);
        $omni_config = $omni_config . "[{$slice_username}]\n" . "urn={$slice_urn}\n" . "keys={$all_key_files}\n";
    }
    foreach ($all_ssh_key_files as $ssh_key_file) {
        $file_manager->add($ssh_key_file);
    }
    $omni_file = writeDataToTempDir($omni_invocation_dir, $omni_config, OMNI_INVOCATION_FILE::OMNI_CONFIGURATION_FILE);
    $file_manager->add($omni_file);
    /* Call OMNI */
    $omni_log_file = "{$omni_invocation_dir}/" . OMNI_INVOCATION_FILE::DEBUG_LOG_FILE;
    $omni_stderr_file = "{$omni_invocation_dir}/" . OMNI_INVOCATION_FILE::ERROR_LOG_FILE;
    $omni_stdout_file = "{$omni_invocation_dir}/" . OMNI_INVOCATION_FILE::CALL_RESULTS_FILE;
    $omni_command_file = "{$omni_invocation_dir}/" . OMNI_INVOCATION_FILE::COMMAND_FILE;
    $omni_pid_file = "{$omni_invocation_dir}/" . OMNI_INVOCATION_FILE::PID_FILE;
    /*    $cmd_array = array($portal_gcf_dir . '/src/omni.py', */
    $cmd_array = array($portal_gcf_dir . '/src/stitcher_php.py', '-c', $omni_file, '-l', write_logger_configuration_file($omni_invocation_dir), '--logoutput', $omni_log_file, '--timeout', '45', '--api-version', $api_version, "--GetVersionCacheName", $tmp_version_cache, "--ForceUseAggNickCache", "--AggNickCacheName", $tmp_agg_cache);
    $descriptor_spec = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("file", $omni_stderr_file, "a"));
    /* stitcher.py: specify fileDir */
    $cmd_array[] = '--fileDir';
    $cmd_array[] = $omni_invocation_dir;
    // specify AM for non-stitchable RSpecs
    if (!$stitch_rspec) {
        foreach ($am_urls as $am_url) {
            $cmd_array[] = '-a';
            $cmd_array[] = $am_url;
        }
    }
    if ($speaks_for_invocation) {
        $cmd_array[] = "--speaksfor=" . $user->urn;
        $speaks_for_cred_filename = writeDataToTempDir($omni_invocation_dir, $speaks_for_cred->credential(), OMNI_INVOCATION_FILE::SPEAKSFOR_CREDENTIAL_FILE);
        $file_manager->add($speaks_for_cred_filename);
        $cmd_array[] = "--cred=" . $speaks_for_cred_filename;
    }
    for ($i = 0; $i < count($args); $i++) {
        $cmd_array[] = $args[$i];
    }
    $command = implode(" ", $cmd_array);
    // save command that was run
    $cmd_file = fopen($omni_command_file, "a");
    fwrite($cmd_file, $command);
    fclose($cmd_file);
    /* forked omni call */
    if ($fork) {
        // define how to handle streams
        $stdout_redirect = " > " . $omni_stdout_file;
        $stderr_redirect = " 2> " . $omni_stderr_file;
        $stdin_redirect = " < /dev/null";
        // set up call via nohup and grab its PID
        $fork_call = 'nohup ' . $command . $stdout_redirect . $stderr_redirect . $stdin_redirect . ' & echo $!';
        error_log("am_client invoke_omni_function COMMAND = " . $fork_call);
        exec($fork_call, $op);
        // assuming success, $op will be a non-empty array
        if ($op) {
            // nohup should return an array with one line containing the PID
            $pid = $op[0];
            // write PID to a file
            $pid_file = fopen($omni_pid_file, "a");
            fwrite($pid_file, $pid);
            fclose($pid_file);
            // FIXME: Should we wait around to do 'ps -p <pid>' to make sure
            // process didn't quickly die?
            return $pid;
        } else {
            return NULL;
        }
    } else {
        error_log("am_client invoke_omni_function COMMAND = " . $command);
        $handle = proc_open($command, $descriptor_spec, $pipes);
        stream_set_blocking($pipes[1], 0);
        // 1 MB
        $bufsiz = 1024 * 1024;
        $output = '';
        $outchunk = null;
        //time to terminate omni process
        $now = time();
        $kill_time = $now + AM_CLIENT_OMNI_KILL_TIME;
        while ($outchunk !== FALSE && !feof($pipes[1]) && $now < $kill_time) {
            $outchunk = fread($pipes[1], $bufsiz);
            if ($outchunk != null && $outchunk !== FALSE) {
                $output = $output . $outchunk;
                $usleep = 0;
            } else {
                // 0.25 seconds
                $usleep = 250000;
            }
            // If we got data, don't sleep, see if there's more ($usleep = 0)
            // If no data, sleep for a little while then check again.
            usleep($usleep);
            $now = time();
        }
        // Catch any final output after timeout
        $outchunk = fread($pipes[1], $bufsiz);
        if ($outchunk != null && $outchunk !== FALSE) {
            $output = $output . $outchunk;
        }
        //fclose($pipes[0]);
        //fclose($pipes[1]);
        //proc_close($handle);
        $status = proc_get_status($handle);
        if (!$status['running']) {
            fclose($pipes[0]);
            fclose($pipes[1]);
            $return_value = $status['exitcode'];
            proc_close($handle);
        } else {
            // Still running, terminate it.
            // See https://bugs.php.net/bug.php?id=39992, for problems
            // terminating child processes and a workaround involving posix_setpgid()
            fclose($pipes[0]);
            fclose($pipes[1]);
            $term_result = proc_terminate($handle);
            // Omni is taking too long to respond so
            // assign Timeout error message to output and this message may show up in UI
            //msg constant defined above
            $output = AM_CLIENT_TIMED_OUT_MSG;
        }
        /*
        unlink($cert_file);
        unlink($key_file);
        unlink($omni_file);
        unlink($tmp_version_cache);
        unlink($tmp_agg_cache);
        foreach ($all_ssh_key_files as $tmpfile) {
          unlink($tmpfile);
        }
        if ($speaks_for_invocation) {
          unlink($speaks_for_cred_filename);
        }
        */
        // Good for debugging but verbose
        //     error_log("am_client output " .  print_r($output, True));
        // FIXME: Write stdout's contents to omni_stdout_file for now to capture
        //  stitcher output. This will be changed when assigning descriptor_spec
        //  to send to a file rather than a pipe.
        $stdout_file = fopen($omni_stdout_file, "a");
        fwrite($stdout_file, $output);
        fclose($stdout_file);
        $output2 = json_decode($output, True);
        if (is_null($output2)) {
            // this is probably a traceback from python
            // return it as a string
            // but see if omni-stderr exists, and pass back its information
            // in addition to output to get a better traceback
            $error_file = fopen($omni_stderr_file, "r");
            // only try to read if fopen was successful and if the error file
            // contains something (i.e. more than 0 bytes)
            if ($error_file && filesize($omni_stderr_file)) {
                $error_file_contents = fread($error_file, filesize($omni_stderr_file));
                if ($error_file_contents) {
                    $substr = $error_file_contents;
                    if (strlen($substr) > 120) {
                        // Pull out just the interesting bits: match on either OmniError or StitchingError
                        $substr = trim(preg_replace("/Traceback(.*)OmniError\\:/s", "", $substr, -1));
                        $substr = trim(preg_replace("/Traceback(.*)StitchingError\\:/s", "", $substr, -1));
                        $substr = "..." . $substr;
                    }
                    error_log("am_client invoke_omni_function: " . "stderr file non-empty: '" . $substr . "'. Check " . $omni_stderr_file . " for more information");
                    // uncomment the next line to append stderr contents to what
                    // users will see. But this has been fixed elsewhere under ticket 1086.
                    //$output .= $error_file_contents;
                }
                fclose($error_file);
            }
            error_log("am_client invoke_omni_function:" . "JSON result is not parseable: \"{$output}\"");
            return $output;
        }
        /* Clean out $file_manager's directory 
              This does NOT include log/error files or any additional files that
              stitching requests may make.
           */
        $file_manager->destruct();
        /* Delete the remaining temp files only if the decoded output is an array
             and its length is 2 and the second value (index 1) is boolean true
             (not null or empty string).
           */
        if (is_array($output2) && count($output2) == 2 && $output2[1]) {
            clean_directory($omni_invocation_dir);
            rmdir($omni_invocation_dir);
            //unlink($omni_log_file);
            //unlink($omni_stderr_file);
        }
        //error_log("Returning output2 : " . print_r($output2, True));
        return $output2;
    }
}