Modified: vcl/trunk/web/.ht-inc/utils.php URL: http://svn.apache.org/viewvc/vcl/trunk/web/.ht-inc/utils.php?rev=1624325&r1=1624324&r2=1624325&view=diff ============================================================================== --- vcl/trunk/web/.ht-inc/utils.php (original) +++ vcl/trunk/web/.ht-inc/utils.php Thu Sep 11 16:01:48 2014 @@ -20,6 +20,7 @@ require_once(".ht-inc/secrets.php"); @include_once("itecsauth/itecsauth.php"); require_once(".ht-inc/authentication.php"); require_once(".ht-inc/phpseclib/Crypt/AES.php"); +require_once(".ht-inc/spyc-0.5/spyc.php"); if(file_exists(".ht-inc/vcldocs.php")) require_once(".ht-inc/vcldocs.php"); @@ -35,14 +36,10 @@ define("ARG_STRING", 1 << 1); define("ARG_MULTINUMERIC", 1 << 2); /// used for processInputVar, means the input variable should be an array of strings define("ARG_MULTISTRING", 1 << 3); -/// define semaphore key -define("SEMKEY", 192365819256598); /// global array used to hold request information between calling isAvailable /// and addRequest $requestInfo = array(); -#$requestInfo["freeComputerids"] = array(); -#$requestInfo["imageids"] = array(); /// global array to cache arrays of node parents for getNodeParents $nodeparents = array(); @@ -62,20 +59,25 @@ $printedHTMLheader = 0; //////////////////////////////////////////////////////////////////////////////// function initGlobals() { global $mode, $user, $remoteIP, $authed, $oldmode, $semid; - global $semislocked, $days, $phpVer, $keys, $pemkey, $AUTHERROR; + global $days, $phpVer, $keys, $pemkey, $AUTHERROR; global $passwdArray, $skin, $contdata, $lastmode, $inContinuation; - global $totalQueries, $ERRORS, $queryTimes, $actions; + global $ERRORS, $actions; global $affilValFunc, $addUserFunc, $updateUserFunc, $addUserFuncArgs; + global $uniqid; define("SECINDAY", 86400); define("SECINWEEK", 604800); define("SECINMONTH", 2678400); define("SECINYEAR", 31536000); + # TODO validate security of this + if(array_key_exists("PATH_INFO", $_SERVER)) { + $pathdata = explode("/", $_SERVER["PATH_INFO"]); + $tmp = explode('.', $pathdata[1]); + $_GET["mode"] = $tmp[0]; + } $mode = processInputVar("mode", ARG_STRING, 'main'); - $totalQueries = 0; $inContinuation = 0; $contdata = array(); - $queryTimes = array(); $contuserid = ''; $continuation = processInputVar('continuation', ARG_STRING); if(! empty($continuation)) { @@ -101,6 +103,7 @@ function initGlobals() { $days = array(_('Sunday'), _('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'), _('Friday'), _('Saturday')); $phpVerArr = explode('.', phpversion()); $phpVer = $phpVerArr[0]; + $uniqid = uniqid($_SERVER['HTTP_HOST'] . "-" . getmypid() . "-"); $passwdArray = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', @@ -185,10 +188,6 @@ function initGlobals() { $mode = "auth"; } if($mode == 'xmlrpccall' || $mode == 'xmlrpcaffiliations') { - // get the semaphore id - if(! ($semid = sem_get(SEMKEY, 1, 0666, 1))) - abort(2); - $semislocked = 0; require_once(".ht-inc/xmlrpcWrappers.php"); require_once(".ht-inc/requests.php"); require_once(".ht-inc/serverprofiles.php"); @@ -257,29 +256,11 @@ function initGlobals() { $updateUserFunc[$id] = create_function('', 'return NULL;'); } - // get the semaphore id - if(! ($semid = sem_get(SEMKEY, 1, 0666, 1))) - abort(2); - $semislocked = 0; - # include appropriate files switch($actions['pages'][$mode]) { case 'blockAllocations': require_once(".ht-inc/blockallocations.php"); break; - case 'manageComputers': - require_once(".ht-inc/computers.php"); - break; - case 'managementNodes': - require_once(".ht-inc/managementnodes.php"); - break; - case 'manageImages': - require_once(".ht-inc/images.php"); - require_once(".ht-inc/requests.php"); - break; - case 'manageSchedules': - require_once(".ht-inc/schedules.php"); - break; case 'help': require_once(".ht-inc/help.php"); break; @@ -305,6 +286,20 @@ function initGlobals() { case 'dashboard': require_once(".ht-inc/dashboard.php"); break; + case 'siteconfig': + require_once(".ht-inc/siteconfig.php"); + break; + case 'resource': + case 'config': + case 'image': + case 'computer': + case 'managementnode': + case 'schedule': + require_once(".ht-inc/resource.php"); + break; + case 'storebackend': + require_once(".ht-inc/storebackend.php"); + break; case 'serverProfiles': require_once(".ht-inc/serverprofiles.php"); require_once(".ht-inc/requests.php"); @@ -316,6 +311,21 @@ function initGlobals() { //////////////////////////////////////////////////////////////////////////////// /// +/// \fn __autoload($class) +/// +/// \param $class - name of a class +/// +/// \brief handles loading class implementation file for a specified class +/// +//////////////////////////////////////////////////////////////////////////////// +function __autoload($class) { + $class = strtolower($class); + require_once(".ht-inc/resource.php"); + require_once(".ht-inc/$class.php"); +} + +//////////////////////////////////////////////////////////////////////////////// +/// /// \fn checkAccess() /// /// \brief gets the user's access level to the locker from the ptsowner_admin @@ -346,6 +356,11 @@ function checkAccess() { exit; } } + if(! array_key_exists('HTTP_X_PASS', $_SERVER) || strlen($_SERVER['HTTP_X_PASS']) == 0) { + printXMLRPCerror(3); # access denied + dbDisconnect(); + exit; + } $xmlpass = $_SERVER['HTTP_X_PASS']; if(get_magic_quotes_gpc()) $xmlpass = stripslashes($xmlpass); @@ -439,16 +454,16 @@ function checkAccess() { exit; } } - elseif($authMechs[$authtype]['type'] == 'redirect'){ - $affilid = $authMechs[$authtype]['affiliationid']; - if(!(isset($apiValidateFunc) && is_array($apiValidateFunc) && - array_key_exists($affilid, $apiValidateFunc) && - $apiValidateFunc[$affilid]($xmluser, $xmlpass))){ - printXMLRPCerror(3); # access denied - dbDisconnect(); - exit; - } - } + elseif($authMechs[$authtype]['type'] == 'redirect') { + $affilid = $authMechs[$authtype]['affiliationid']; + if(!(isset($apiValidateFunc) && is_array($apiValidateFunc) && + array_key_exists($affilid, $apiValidateFunc) && + $apiValidateFunc[$affilid]($xmluser, $xmlpass))) { + printXMLRPCerror(3); # access denied + dbDisconnect(); + exit; + } + } else { printXMLRPCerror(6); # unable to auth passed in X-User dbDisconnect(); @@ -491,16 +506,6 @@ function checkAccess() { if(! $inContinuation) { # check that user has access to this area switch($mode) { - case 'viewRequests': - $requests = getUserRequests("all", $user["id"]); - if(! in_array("imageCheckOut", $user["privileges"]) && - ! in_array("imageAdmin", $user["privileges"]) && - ! count($requests)) { - $mode = ""; - $actionFunction = "main"; - return; - } - break; case 'viewGroups': if(! in_array("groupAdmin", $user["privileges"])) { $mode = ""; @@ -508,34 +513,6 @@ function checkAccess() { return; } break; - case 'selectImageOption': - if(! in_array("imageAdmin", $user["privileges"])) { - $mode = ""; - $actionFunction = "main"; - return; - } - break; - case 'viewSchedules': - if(! in_array("scheduleAdmin", $user["privileges"])) { - $mode = ""; - $actionFunction = "main"; - return; - } - break; - case 'selectComputers': - if(! in_array("computerAdmin", $user["privileges"])) { - $mode = ""; - $actionFunction = "main"; - return; - } - break; - case 'selectMgmtnodeOption': - if(! in_array("mgmtNodeAdmin", $user["privileges"])) { - $mode = ""; - $actionFunction = "main"; - return; - } - break; case 'serverProfiles': if(! in_array("serverProfileAdmin", $user["privileges"]) && ! in_array("serverCheckOut", $user["privileges"])) { @@ -756,6 +733,7 @@ function clearPrivCache() { $_SESSION['userhaspriv'] = array(); $_SESSION['compstateflow'] = array(); $_SESSION['usersessiondata'] = array(); + $_SESSION['variables'] = array(); unset($_SESSION['user']); unset($_SESSION['locales']); } @@ -808,6 +786,8 @@ function setupSession() { $_SESSION['compstateflow'] = array(); if(! array_key_exists('usersessiondata', $_SESSION)) $_SESSION['usersessiondata'] = array(); + if(! array_key_exists('variables', $_SESSION)) + $_SESSION['variables'] = array(); } //////////////////////////////////////////////////////////////////////////////// @@ -899,7 +879,8 @@ function abort($errcode, $query="") { $message = ""; if($errcode >= 100 && $errcode < 400) { $message .= mysql_error($mysql_link_vcl) . "\n"; - $message .= mysql_error($mysql_link_acct) . "\n"; + if($ENABLE_ITECSAUTH) + $message .= mysql_error($mysql_link_acct) . "\n"; $message .= $query . "\n"; } $message .= "ERROR($errcode): " . $ERRORS["$errcode"] . "\n"; @@ -926,10 +907,10 @@ function abort($errcode, $query="") { print HELPEMAIL . "</a> " . _("for further assistance. Please include the "); print _("steps you took that led up to this problem in your email message."); } + // release semaphore lock + cleanSemaphore(); dbDisconnect(); printHTMLFooter(); - // release semaphore lock - semUnlock(); exit; } @@ -1115,10 +1096,9 @@ function dbDisconnect() { //////////////////////////////////////////////////////////////////////////////// function doQuery($query, $errcode=101, $db="vcl", $nolog=0) { global $mysql_link_vcl, $mysql_link_acct, $user, $mode, $ENABLE_ITECSAUTH; - global $totalQueries, $queryTimes; - $totalQueries++; if($db == "vcl") { - if((! $nolog) && preg_match('/^(UPDATE|INSERT|DELETE)/', $query)) { + if((! $nolog) && preg_match('/^(UPDATE|INSERT|DELETE)/', $query) && + strpos($query, 'UPDATE continuations SET expiretime = ') === FALSE) { $logquery = str_replace("'", "\'", $query); $logquery = str_replace('"', '\"', $logquery); if(isset($user['id'])) @@ -1137,7 +1117,12 @@ function doQuery($query, $errcode=101, $ . "'$logquery')"; mysql_query($q, $mysql_link_vcl); } - $qh = mysql_query($query, $mysql_link_vcl) or abort($errcode, $query); + for($i = 0; ! ($qh = mysql_query($query, $mysql_link_vcl)) && $i < 3; $i++) { + if(mysql_errno() == '1213') # DEADLOCK, sleep and retry + usleep(50); + else + abort($errcode, $query); + } } elseif($db == "accounts") { if($ENABLE_ITECSAUTH) @@ -1172,7 +1157,8 @@ function dbLastInsertID() { /// //////////////////////////////////////////////////////////////////////////////// function getOSList() { - $qh = doQuery("SELECT id, name, prettyname, type FROM OS", "115"); + $query = "SELECT id, name, prettyname, type, installtype FROM OS ORDER BY prettyname"; + $qh = doQuery($query, "115"); $oslist = array(); while($row = mysql_fetch_assoc($qh)) $oslist[$row['id']] = $row; @@ -1197,6 +1183,8 @@ function getOSList() { /// \b osid - osid for the os on the image\n /// \b os - os the image contains\n /// \b installtype - method used to install image\n +/// \b ostypeid - id of the OS type in the image\n +/// \b ostype - name of the OS type in the image\n /// \b minram - minimum amount of RAM needed for image\n /// \b minprocnumber - minimum number of processors needed for image\n /// \b minprocspeed - minimum speed of processor(s) needed for image\n @@ -1255,14 +1243,17 @@ function getImages($includedeleted=0, $i . "CONCAT(u.unityid, '@', a.name) AS user, " . "i.datecreated, " . "DATE_FORMAT(i.datecreated, '%c/%d/%y %l:%i %p') AS prettydate, " + . "i.deleted, " + . "i.datedeleted, " . "i.production, " . "i.imagename " . "FROM imagerevision i, " . "affiliation a, " . "user u " - . "WHERE i.deleted = 0 AND " - . "i.userid = u.id AND " - . "u.affiliationid = a.id"; + . "WHERE i.userid = u.id AND "; + if(! $includedeleted) + $query .= "i.deleted = 0 AND "; + $query .= "u.affiliationid = a.id"; $qh = doQuery($query, 101); while($row = mysql_fetch_assoc($qh)) { $id = $row['imageid']; @@ -1281,6 +1272,8 @@ function getImages($includedeleted=0, $i . "i.OSid AS osid, " . "o.name AS os, " . "o.installtype, " + . "ot.id AS ostypeid, " + . "ot.name AS ostype, " . "i.minram AS minram, " . "i.minprocnumber AS minprocnumber, " . "i.minprocspeed AS minprocspeed, " @@ -1297,6 +1290,7 @@ function getImages($includedeleted=0, $i . "FROM image i, " . "platform p, " . "OS o, " + . "OStype ot, " . "resource r, " . "resourcetype t, " . "user u, " @@ -1306,6 +1300,7 @@ function getImages($includedeleted=0, $i . "t.name = 'image' AND " . "r.subid = i.id AND " . "i.OSid = o.id AND " + . "o.type = ot.name AND " . "i.ownerid = u.id AND " . "u.affiliationid = a.id "; if(! $includedeleted) @@ -1313,7 +1308,11 @@ function getImages($includedeleted=0, $i $query .= "ORDER BY i.prettyname"; $qh = doQuery($query, 120); while($row = mysql_fetch_assoc($qh)) { + if(is_null($row['maxconcurrent'])) + $row['maxconcurrent'] = 0; $imagelist[$includedeleted][$row["id"]] = $row; + $imagelist[$includedeleted][$row["id"]]['checkuser'] = 1; + $imagelist[$includedeleted][$row["id"]]['rootaccess'] = 1; if($row["imagemetaid"] != NULL) { if(array_key_exists($row['imagemetaid'], $allmetadata)) { $metaid = $row['imagemetaid']; @@ -1331,7 +1330,7 @@ function getImages($includedeleted=0, $i } } else - $row["imagemetaid"] = NULL; + $imagelist[$includedeleted][$row["id"]]["imagemetaid"] = NULL; } if(array_key_exists($row['id'], $allrevisiondata)) $imagelist[$includedeleted][$row['id']]['imagerevision'] = $allrevisiondata[$row['id']]; @@ -1344,6 +1343,131 @@ function getImages($includedeleted=0, $i //////////////////////////////////////////////////////////////////////////////// /// +/// \fn getServerProfiles($id) +/// +/// \param $id - (optional) if specified, only return data for specified profile +/// +/// \return an array where each key is a profile id whose value is an array with +/// these values:\n +/// \b name - profile name\n +/// \b description - profile description\n +/// \b imageid - id of image associated with profile\n +/// \b image - pretty name of image associated with profile\n +/// \b ownerid - user id of owner of profile\n +/// \b owner - unityid of owner of profile\n +/// \b fixedIP - IP address to be used with deployed profile\n +/// \b fixedMAC - MAC address to be used with deployed profile\n +/// \b admingroupid - id of admin user group associated with profile\n +/// \b admingroup - name of admin user group associated with profile\n +/// \b logingroupid - id of login user group associated with profile\n +/// \b logingroup - name of login user group associated with profile\n +/// \b monitored - whether or not deployed profile should be monitored\n +/// \b resourceid - resource id of profile +/// +/// \brief gets information about server profiles +/// +//////////////////////////////////////////////////////////////////////////////// +function getServerProfiles($id=0) { + $key = getKey(array('getServerProfiles', $id)); + if(array_key_exists($key, $_SESSION['usersessiondata'])) + return $_SESSION['usersessiondata'][$key]; + + $fixeddata = array(); + $query = "SELECT name, value FROM variable WHERE name LIKE 'fixedIPsp%'"; + $qh = doQuery($query); + while($row = mysql_fetch_assoc($qh)) { + $spid = str_replace('fixedIPsp', '', $row['name']); + $fixeddata[$spid] = Spyc::YAMLLoad($row['value']); + } + + $query = "SELECT s.id, " + . "s.name, " + . "s.description, " + . "s.imageid, " + . "i.prettyname AS image, " + . "s.ownerid, " + . "CONCAT(u.unityid, '@', a.name) AS owner, " + . "s.fixedIP, " + . "s.fixedMAC, " + . "s.admingroupid, " + . "CONCAT(ga.name, '@', aa.name) AS admingroup, " + . "s.logingroupid, " + . "CONCAT(gl.name, '@', al.name) AS logingroup, " + . "s.monitored, " + . "r.id AS resourceid " + . "FROM serverprofile s " + . "LEFT JOIN image i ON (i.id = s.imageid) " + . "LEFT JOIN user u ON (u.id = s.ownerid) " + . "LEFT JOIN affiliation a ON (a.id = u.affiliationid) " + . "LEFT JOIN usergroup ga ON (ga.id = s.admingroupid) " + . "LEFT JOIN affiliation aa ON (aa.id = ga.affiliationid) " + . "LEFT JOIN usergroup gl ON (gl.id = s.logingroupid) " + . "LEFT JOIN affiliation al ON (al.id = gl.affiliationid) " + . "LEFT JOIN resource r ON (r.subid = s.id) " + . "WHERE r.resourcetypeid = 17 "; + if($id != 0) + $query .= "AND s.id = $id"; + else + $query .= "ORDER BY name"; + $qh = doQuery($query, 101); + $profiles = array(); + while($row = mysql_fetch_assoc($qh)) { + $profiles[$row['id']] = $row; + if(array_key_exists($row['id'], $fixeddata)) { + $profiles[$row['id']]['netmask'] = $fixeddata[$row['id']]['netmask']; + $profiles[$row['id']]['router'] = $fixeddata[$row['id']]['router']; + $profiles[$row['id']]['dns'] = implode(',', $fixeddata[$row['id']]['dns']); + } + else { + $profiles[$row['id']]['netmask'] = ''; + $profiles[$row['id']]['router'] = ''; + $profiles[$row['id']]['dns'] = ''; + } + } + $_SESSION['usersessiondata'][$key] = $profiles; + return $profiles; +} + +//////////////////////////////////////////////////////////////////////////////// +/// +/// \fn getServerProfileImages($userid) +/// +/// \param $userid - id from user table +/// +/// \return array where the key is the id of the image and the value is the +/// prettyname of the image +/// +/// \brief builds an array of images that user has access to via server profiles +/// +//////////////////////////////////////////////////////////////////////////////// +function getServerProfileImages($userid) { + $key = getKey(array('getServerProfileImages', $userid)); + if(array_key_exists($key, $_SESSION['usersessiondata'])) + return $_SESSION['usersessiondata'][$key]; + $resources = getUserResources(array('serverCheckOut', 'serverProfileAdmin'), + array('available', 'administer')); + $ids = array_keys($resources['serverprofile']); + $inids = implode(',', $ids); + if(empty($inids)) { + $_SESSION['usersessiondata'][$key] = array(); + return array(); + } + $query = "SELECT i.id, " + . "i.prettyname AS image " + . "FROM serverprofile s, " + . "image i " + . "WHERE s.imageid = i.id AND " + . "s.id IN ($inids)"; + $qh = doQuery($query, 101); + $profiles = array(); + while($row = mysql_fetch_assoc($qh)) + $profiles[$row['id']] = $row['image']; + $_SESSION['usersessiondata'][$key] = $profiles; + return $profiles; +} + +//////////////////////////////////////////////////////////////////////////////// +/// /// \fn getImageRevisions($imageid, $incdeleted) /// /// \param $imageid - id of an image @@ -1420,10 +1544,12 @@ function getImageNotes($imageid) { //////////////////////////////////////////////////////////////////////////////// /// -/// \fn getImageConnectMethods($imageid, $revisionid) +/// \fn getImageConnectMethods($imageid, $revisionid, $nostatic=0) /// /// \param $imageid - id of an image /// \param $revisionid - (optional, default=0) revision id of image +/// \param $nostatic - (optional, default=0) pass 1 to keep from using the +/// static variable defined in the function /// /// \return an array of connect methods enabled for specified image where the /// key is the id of the connect method and the value is the description @@ -1431,18 +1557,20 @@ function getImageNotes($imageid) { /// \brief builds an array of connect methods enabled for the image /// //////////////////////////////////////////////////////////////////////////////// -function getImageConnectMethods($imageid, $revisionid=0) { - $key = getKey(array('getImageConnectMethods', $imageid, $revisionid)); +function getImageConnectMethods($imageid, $revisionid=0, $nostatic=0) { + $key = getKey(array('getImageConnectMethods', (int)$imageid, (int)$revisionid)); if(array_key_exists($key, $_SESSION['usersessiondata'])) return $_SESSION['usersessiondata'][$key]; if($revisionid == 0) - $revisionid = getProductionRevisionid($imageid); + $revisionid = getProductionRevisionid($imageid, $nostatic); if($revisionid == '') { $_SESSION['usersessiondata'][$key] = array(); return array(); } static $allmethods = array(); + if($nostatic) + $allmethods = array(); if(empty($allmethods)) { $query = "SELECT DISTINCT c.id, " . "c.description, " @@ -1622,9 +1750,11 @@ function checkClearImageMeta($imagemetai //////////////////////////////////////////////////////////////////////////////// /// -/// \fn getProductionRevisionid($imageid) +/// \fn getProductionRevisionid($imageid, $nostatic=0) /// /// \param $imageid +/// \param $nostatic - (optional, default=0) pass 1 to keep from using the +/// static variable defined in the function /// /// \return the production revision id for $imageid /// @@ -1632,8 +1762,10 @@ function checkClearImageMeta($imagemetai /// table /// //////////////////////////////////////////////////////////////////////////////// -function getProductionRevisionid($imageid) { +function getProductionRevisionid($imageid, $nostatic=0) { static $alldata = array(); + if($nostatic) + $alldata = array(); if(! empty($alldata)) if(array_key_exists($imageid, $alldata)) return $alldata[$imageid]; @@ -1709,6 +1841,8 @@ function removeNoCheckout($images) { function getUserResources($userprivs, $resourceprivs=array("available"), $onlygroups=0, $includedeleted=0, $userid=0) { global $user; + if(in_array('managementnodeAdmin', $userprivs)) + $userprivs[] = 'mgmtnodeAdmin'; $key = getKey(array($userprivs, $resourceprivs, $onlygroups, $includedeleted, $userid)); if(array_key_exists($key, $_SESSION['userresources'])) return $_SESSION['userresources'][$key]; @@ -1840,6 +1974,9 @@ function getUserResources($userprivs, $r getResourcesFromGroups($resourcegroups[$type], $type, $includedeleted); } addOwnedResources($resources, $includedeleted, $userid); + $noimageid = getImageId('noimage'); + if(array_key_exists($noimageid, $resources['image'])) + unset($resources['image'][$noimageid]); $_SESSION['userresources'][$key] = $resources; return $resources; } @@ -2082,23 +2219,25 @@ function addUserResources(&$nodeprivs, $ //////////////////////////////////////////////////////////////////////////////// function addOwnedResources(&$resources, $includedeleted, $userid) { foreach(array_keys($resources) as $type) { - if($type == "image") - $field = "prettyname"; - elseif($type == "computer") - $field = "hostname"; - elseif($type == "schedule") - $field = "name"; - elseif($type == "managementnode") - $field = "hostname"; - elseif($type == "serverprofile") - $field = "name"; - else - continue; + # TODO make this get name field from classes + switch($type) { + case "image": + $field = 'prettyname'; + break; + case "computer": + case "managementnode": + $field = 'hostname'; + break; + default: + $field = 'name'; + break; + } $query = "SELECT id, " . "$field " . "FROM $type " . "WHERE ownerid = $userid"; - if(! $includedeleted && ($type == "image" || $type == "computer")) + if(! $includedeleted && + ($type == "image" || $type == "computer" || $type == 'config')) $query .= " AND deleted = 0"; $qh = doQuery($query, 101); while($row = mysql_fetch_assoc($qh)) { @@ -2157,18 +2296,18 @@ function addOwnedResourceGroups(&$resour //////////////////////////////////////////////////////////////////////////////// function getResourcesFromGroups($groups, $type, $includedeleted) { $return = array(); - if($type == "image") - $field = "prettyname"; - elseif($type == "computer") - $field = "hostname"; - elseif($type == "schedule") - $field = "name"; - elseif($type == "managementnode") - $field = "hostname"; - elseif($type == "serverprofile") - $field = "name"; - else - return array(); + switch($type) { + case "image": + $field = 'prettyname'; + break; + case "computer": + case "managementnode": + $field = 'hostname'; + break; + default: + $field = 'name'; + break; + } $groups = implode("','", $groups); $inlist = "'$groups'"; @@ -2186,7 +2325,8 @@ function getResourcesFromGroups($groups, . "g.name IN ($inlist) AND " . "g.resourcetypeid = rt.id AND " . "rt.name = '$type'"; - if(! $includedeleted && ($type == "image" || $type == "computer")) { + if(! $includedeleted && + ($type == "image" || $type == "computer" || $type == 'config')) { $query .= "AND deleted = 0 "; } /*if($type == "image") @@ -2354,17 +2494,18 @@ function decryptData($data) { } //////////////////////////////////////////////////////////////////////////////// -// -// \fn encryptDataAsymmetric($data, $public_key) -// -// \param $data - a string -// -// \param $public_key - either a filename for a public key or the public key itself -// -// \return hex-encoded, encrypted form of $data -// -// \brief generate public key encrypted data -// +/// +/// \fn encryptDataAsymmetric($data, $public_key) +/// +/// \param $data - a string +/// +/// \param $public_key - either a filename for a public key or the public key +/// itself +/// +/// \return hex-encoded, encrypted form of $data +/// +/// \brief generate public key encrypted data +/// //////////////////////////////////////////////////////////////////////////////// function encryptDataAsymmetric($data, $public_key){ if(file_exists($public_key)){ @@ -3176,7 +3317,7 @@ function processInputVar($vartag, $type, if(! is_string($return)) { print "ERROR (code:3)<br>\n"; printHTMLFooter(); - semUnlock(); + cleanSemaphore(); exit(); } #print "before - $return<br>\n"; @@ -3198,7 +3339,7 @@ function processInputVar($vartag, $type, if(! is_string($value)) { print "ERROR (code:3)<br>\n"; printHTMLFooter(); - semUnlock(); + cleanSemaphore(); exit(); } } @@ -3406,6 +3547,8 @@ function getUserInfo($id, $noupdate=0, $ . "u.mapserial AS mapserial, " . "u.showallgroups, " . "u.lastupdated AS lastupdated, " + . "u.usepublickeys, " + . "u.sshpublickeys, " . "af.shibonly " . "FROM user u, " . "IMtype i, " @@ -3419,6 +3562,7 @@ function getUserInfo($id, $noupdate=0, $ $qh = doQuery($query, "105"); if($user = mysql_fetch_assoc($qh)) { + $user['sshpublickeys'] = htmlspecialchars($user['sshpublickeys']); if((datetimeToUnix($user["lastupdated"]) > time() - SECINDAY) || $user['unityid'] == 'vclreload' || $user['affiliation'] == 'Local' || @@ -3723,9 +3867,10 @@ function getOverallUserPrivs($userid) { . "WHERE ownerid = $userid))"; $qh = doQuery($query, 107); $privileges = array(); - while($row = mysql_fetch_row($qh)) { - array_push($privileges, $row[0]); - } + while($row = mysql_fetch_row($qh)) + $privileges[] = $row[0]; + if(in_array("mgmtNodeAdmin", $privileges)) + $privileges[] = 'managementnodeAdmin'; return $privileges; } @@ -3765,14 +3910,17 @@ function getBlockAllocationIDs($user) { //////////////////////////////////////////////////////////////////////////////// /// /// \fn isAvailable($images, $imageid, $imagerevisionid, $start, $end, -/// $requestid, $userid, $ignoreprivileges, $forimaging, $ip, -/// $mac, $skipconcurrentcheck) +/// $holdcomps, $requestid, $userid, $ignoreprivileges, +/// $forimaging, $ip, $mac, $skipconcurrentcheck) /// /// \param $images - array as returned from getImages /// \param $imageid - imageid from the image table /// \param $imagerevisionid - id of revision of image from imagerevision table /// \param $start - unix timestamp for start of reservation /// \param $end - unix timestamp for end of reservation +/// \param $holdcomps - bool - 1 to lock computers for later adding to +/// reservation, 0 not to; use 0 when just checking for estimated availability, +/// use 1 when finding computers to actually reserve /// \param $requestid - (optional) a requestid; if checking for an available /// timeslot to update a request, pass the request id that will be updated; /// otherwise, don't pass this argument @@ -3790,7 +3938,8 @@ function getBlockAllocationIDs($user) { /// \param $skipconcurrentcheck (optional, default=0) - set to 1 to skip check /// for concurrent use of image; useful for setting up reload reservations /// -/// \return -3 if unavailable due to an ip/mac conflict +/// \return -4 if unavailable due to an ip/mac conflict with another machine +/// -3 if unavailable due to an ip/mac conflict with another reservation /// -2 if specified time period is during a maintenance window /// -1 if $imageid is limited in the number of concurrent reservations /// available, and the limit has been reached @@ -3801,16 +3950,25 @@ function getBlockAllocationIDs($user) { /// //////////////////////////////////////////////////////////////////////////////// function isAvailable($images, $imageid, $imagerevisionid, $start, $end, - $requestid=0, $userid=0, $ignoreprivileges=0, + $holdcomps, $requestid=0, $userid=0, $ignoreprivileges=0, $forimaging=0, $ip='', $mac='', $skipconcurrentcheck=0) { - global $requestInfo; + global $requestInfo, $user; $requestInfo["start"] = $start; $requestInfo["end"] = $end; $requestInfo["imageid"] = $imageid; + $requestInfo["ipwarning"] = 0; $allocatedcompids = array(0); + if(! is_array($imagerevisionid)) + $imagerevisionid = array($imageid => array($imagerevisionid)); + elseif(empty($imagerevisionid)) + $imagerevisionid = array($imageid => array(getProductionRevisionid($imageid))); + if(schCheckMaintenance($start, $end)) - return -2; + return debugIsAvailable(-2, 1, $start, $end, $imagerevisionid); + + if(! array_key_exists($imageid, $images)) + return debugIsAvailable(0, 20, $start, $end, $imagerevisionid); if($requestInfo["start"] <= time()) { $now = 1; @@ -3826,26 +3984,29 @@ function isAvailable($images, $imageid, $requestInfo["computers"] = array(); $requestInfo["computers"][0] = 0; $requestInfo["images"][0] = $imageid; + $requestInfo["imagerevisions"][0] = $imagerevisionid[$imageid][0]; - # loop to check for available computers for all needed images + # build array of subimages + # TODO handle mininstance if(! $forimaging && $images[$imageid]["imagemetaid"] != NULL) { $count = 1; foreach($images[$imageid]["subimages"] as $imgid) { $requestInfo['computers'][$count] = 0; $requestInfo['images'][$count] = $imgid; + if(array_key_exists($imgid, $imagerevisionid) && + array_key_exists($count, $imagerevisionid[$imgid])) + $requestInfo['imagerevisions'][$count] = $imagerevisionid[$imgid][$count]; + else + $requestInfo['imagerevisions'][$count] = getProductionRevisionid($imgid); $count++; } } - // get semaphore lock - if(! semLock()) - abort(3); - $startstamp = unixToDatetime($start); $endstamp = unixToDatetime($end + 900); - # check for overlapping use of mac or ip if(! empty($mac) || ! empty($ip)) { + # check for overlapping use of mac or ip $query = "SELECT rq.id " . "FROM reservation rs, " . "request rq, " @@ -3862,8 +4023,17 @@ function isAvailable($images, $imageid, $query .= "LIMIT 1"; $qh = doQuery($query, 101); if(mysql_num_rows($qh)) { - semUnlock(); - return -3; + return debugIsAvailable(-3, 2, $start, $end, $imagerevisionid); + } + + # check for IP being used by a management node + $query = "SELECT id " + . "FROM managementnode " + . "WHERE IPaddress = '$ip' AND " + . "stateid != 1"; + $qh = doQuery($query, 101); + if(mysql_num_rows($qh)) { + return debugIsAvailable(-4, 16, $start, $end, $imagerevisionid); } } @@ -3874,10 +4044,19 @@ function isAvailable($images, $imageid, $ignorestates = "'maintenance','vmhostinuse','hpc','failed'"; if($now) $ignorestates .= ",'reloading','reload','timeout','inuse'"; + foreach($requestInfo["images"] as $key => $imageid) { # check for max concurrent usage of image if(! $skipconcurrentcheck && $images[$imageid]['maxconcurrent'] != NULL) { + if($userid == 0) + $usersgroups = $user['groups']; + else { + $testuser = getUserInfo($userid, 0, 1); + if(is_null($testuser)) + return debugIsAvailable(0, 17, $start, $end, $imagerevisionid); + $usersgroups = $testuser['groups']; + } $decforedit = 0; $compids = array(); $reloadid = getUserlistID('vclreload@Local'); @@ -3899,6 +4078,7 @@ function isAvailable($images, $imageid, } $usagecnt = count($compids); $allids = implode("','", $compids); + $ignoregroups = implode("','", array_keys($usersgroups)); $query = "SELECT COUNT(bc.imageid) AS currentusage " . "FROM blockComputers bc, " . "blockRequest br, " @@ -3907,34 +4087,55 @@ function isAvailable($images, $imageid, . "bt.blockRequestid = br.id AND " . "bc.imageid = $imageid AND " . "bc.computerid NOT IN ('$allids') AND " + . "br.groupid NOT IN ('$ignoregroups') AND " . "'$startstamp' < (bt.end + INTERVAL 900 SECOND) AND " . "'$endstamp' > bt.start AND " . "bt.skip != 1 AND " . "br.status != 'deleted'"; $qh = doQuery($query); if(! $row = mysql_fetch_assoc($qh)) { - semUnlock(); - return 0; + cleanSemaphore(); + return debugIsAvailable(0, 3, $start, $end, $imagerevisionid); } if(($usagecnt + $row['currentusage'] - $decforedit) >= $images[$imageid]['maxconcurrent']) { - semUnlock(); - return -1; + cleanSemaphore(); + return debugIsAvailable(-1, 4, $start, $end, $imagerevisionid); } } $platformid = getImagePlatform($imageid); if(is_null($platformid)) { - semUnlock(); - return 0; + cleanSemaphore(); + return debugIsAvailable(0, 5, $start, $end, $imagerevisionid); } # get computers $imageid maps to - $tmp = getMappedResources($imageid, "image", "computer"); - if(! count($tmp)) { - semUnlock(); - return 0; + $compids = getMappedResources($imageid, "image", "computer"); + if(! count($compids)) { + cleanSemaphore(); + return debugIsAvailable(0, 6, $start, $end, $imagerevisionid); + } + $mappedcomputers = implode(',', $compids); + + // if $ip specified, only look at computers under management nodes that can + # handle that network + if($ip != '') { + $mappedmns = getMnsFromImage($imageid); + $mnnets = checkAvailableNetworks($ip); + $intersect = array_intersect($mappedmns, $mnnets); + $tmpcompids = array(); + foreach($intersect as $mnid) { + $tmp2 = getMappedResources($mnid, 'managementnode', 'computer'); + $tmpcompids = array_merge($tmpcompids, $tmp2); + } + $tmpcompids = array_unique($tmpcompids); + $newcompids = array_intersect($compids, $tmpcompids); + if(! count($newcompids)) { + cleanSemaphore(); + return debugIsAvailable(0, 18, $start, $end, $imagerevisionid); + } + $mappedcomputers = implode(',', $newcompids); } - $mappedcomputers = implode(',', $tmp); #get computers for available schedules and platforms $computerids = array(); @@ -3960,8 +4161,8 @@ function isAvailable($images, $imageid, $qh = doQuery($query, 128); $row = mysql_fetch_row($qh); if(! in_array($row[0], $scheduleids)) { - semUnlock(); - return 0; + cleanSemaphore(); + return debugIsAvailable(0, 7, $start, $end, $imagerevisionid, $computerids, $currentids, $blockids); } // set $virtual to 0 so that it is defined later but skips the additional code $virtual = 0; @@ -3975,9 +4176,10 @@ function isAvailable($images, $imageid, . "WHERE i.id = $imageid"; $qh = doQuery($query, 101); if(! ($row = mysql_fetch_assoc($qh))) { - semUnlock(); - return 0; + cleanSemaphore(); + return debugIsAvailable(0, 8, $start, $end, $imagerevisionid, $computerids, $currentids, $blockids); } + # TODO might need to check for other strings for KVM, OpenStack, etc if(preg_match('/(vmware)/', $row['installtype'])) $virtual = 1; else @@ -4006,6 +4208,7 @@ function isAvailable($images, $imageid, . "LEFT JOIN OSinstalltype oi ON (oi.name = o.installtype) " . "LEFT JOIN provisioningOSinstalltype poi ON (poi.OSinstalltypeid = oi.id) " . "LEFT JOIN computer c ON (poi.provisioningid = c.provisioningid) " + . "LEFT JOIN semaphore se ON (c.id = se.computerid) " . "WHERE i.id = $imageid AND " . "c.scheduleid IN ($schedules) AND " . "c.platformid = $platformid AND " @@ -4020,16 +4223,17 @@ function isAvailable($images, $imageid, if(! $ignoreprivileges) $query .= "c.id IN ($usercomputers) AND "; $query .= "c.id IN ($mappedcomputers) AND " - . "c.id NOT IN ($alloccompids) " - . "ORDER BY (c.procspeed * c.procnumber) DESC, " - . "RAM DESC, " - . "network DESC"; + . "c.id NOT IN ($alloccompids) AND " + . "(se.expires IS NULL OR se.expires < NOW()) " + . "ORDER BY RAM, " + . "(c.procspeed * c.procnumber), " + . "network"; $qh = doQuery($query, 129); while($row = mysql_fetch_assoc($qh)) { array_push($computerids, $row['id']); if($row['currentimageid'] == $imageid && - $row['imagerevisionid'] == $imagerevisionid) { + $row['imagerevisionid'] == $requestInfo['imagerevisions'][$key]) { array_push($currentids, $row['id']); } } @@ -4039,6 +4243,10 @@ function isAvailable($images, $imageid, $blockids = $blockdata['compids']; } + # return 0 if no computers available + if(empty($computerids) && empty($blockids)) + return debugIsAvailable(0, 21, $start, $end, $imagerevisionid, $computerids, $currentids, $blockids, array(), $virtual); + #remove computers from list that are already scheduled $usedComputerids = array(); $query = "SELECT DISTINCT rs.computerid " @@ -4060,15 +4268,19 @@ function isAvailable($images, $imageid, // if modifying a reservation and $computerids is now empty, return 0 if($requestid && empty($computerids)) { - semUnlock(); - return 0; + cleanSemaphore(); + return debugIsAvailable(0, 9, $start, $end, $imagerevisionid, $computerids, $currentids, $blockids, array(), $virtual); } + # return 0 if no computers available + if(empty($computerids) && empty($currentids) && empty($blockids)) + return debugIsAvailable(0, 19, $start, $end, $imagerevisionid, $computerids, $currentids, $blockids, array(), $virtual); + # remove computers from list that are allocated to block allocations if($altRemoveBlockCheck) { if(editRequestBlockCheck($computerids[0], $imageid, $start, $end)) { - semUnlock(); - return 0; + cleanSemaphore(); + return debugIsAvailable(0, 10, $start, $end, $imagerevisionid, $computerids, $currentids, $blockids, array(), $virtual); } } elseif(! count($blockids)) { # && ! $altRemoveBlockCheck @@ -4104,7 +4316,7 @@ function isAvailable($images, $imageid, . "LEFT JOIN computer c2 ON (v.id = c2.vmhostid) " . "LEFT JOIN image i ON (c2.currentimageid = i.id) " . "WHERE c.stateid = 20 " - . "GROUP BY c.id"; + . "GROUP BY v.id"; doQuery($query, 101); } @@ -4116,9 +4328,9 @@ function isAvailable($images, $imageid, . "LEFT JOIN image i ON (c.currentimageid = i.id) " . "WHERE c.id IN ($inids) AND " . "(v.allocRAM - i.minram + {$images[$imageid]['minram']}) < v.RAM " - . "ORDER BY (c.procspeed * c.procnumber) DESC, " - . "c.RAM DESC, " - . "c.network DESC"; + . "ORDER BY c.RAM, " + . "(c.procspeed * c.procnumber), " + . "c.network"; $qh = doQuery($query, 101); $newcompids = array(); while($row = mysql_fetch_assoc($qh)) @@ -4126,6 +4338,48 @@ function isAvailable($images, $imageid, $computerids = $newcompids; } + # check for use of specified IP address, have to wait until here + # because there may be a computer already assigned the IP that + # can be used for this reservation + if(! empty($ip) && $now) { + $allcompids = array_merge($computerids, $blockids); + if(empty($allcompids)) + return debugIsAvailable(0, 13, $start, $end, $imagerevisionid, $computerids, $currentids, $blockids, array(), $virtual); + $inids = implode(',', $allcompids); + $query = "SELECT id " + . "FROM computer " + . "WHERE id NOT IN ($inids) AND " + . "deleted = 0 AND " + . "stateid != 1 AND " + . "IPaddress = '$ip' AND " + . "(type != 'virtualmachine' OR " + . "vmhostid IS NOT NULL)"; + $qh = doQuery($query); + if(mysql_num_rows($qh)) { + if($now) + return debugIsAvailable(-4, 18, $start, $end, $imagerevisionid, $computerids, $currentids, $blockids, array(), $virtual); + $requestInfo['ipwarning'] = 1; + } + $query = "SELECT id " + . "FROM computer " + . "WHERE id in ($inids) AND " + . "IPaddress = '$ip'"; + if($requestid) + $query .= " AND id != $compid"; # TODO test this + $qh = doQuery($query); + $cnt = mysql_num_rows($qh); + if($cnt > 1) { + if($now) + return debugIsAvailable(-4, 19, $start, $end, $imagerevisionid, $computerids, $currentids, $blockids, array(), $virtual); + $requestInfo['ipwarning'] = 1; + } + elseif($cnt == 1) { + $row = mysql_fetch_assoc($qh); + $computerids = array($row['id']); + $blockids = array(); + } + } + # remove any recently reserved computers that could have been an # undetected failure $failedids = getPossibleRecentFailures($userid, $imageid); @@ -4152,14 +4406,17 @@ function isAvailable($images, $imageid, } # allocate a computer + $_imgrevid = $requestInfo['imagerevisions'][$key]; $comparr = allocComputer($blockids, $currentids, $computerids, - $startstamp, $nowfuture); + $startstamp, $endstamp, $nowfuture, $imageid, $_imgrevid, + $holdcomps, $requestid); if(empty($comparr) && $shortened) $comparr = allocComputer($origblockids, $origcurrentids, - $origcomputerids, $startstamp, $nowfuture); + $origcomputerids, $startstamp, $endstamp, $nowfuture, + $imageid, $_imgrevid, $holdcomps, $requestid); if(empty($comparr)) { - semUnlock(); - return 0; + cleanSemaphore(); + return debugIsAvailable(0, 11, $start, $end, $imagerevisionid, $computerids, $currentids, $blockids, $failedids, $virtual); } $requestInfo["computers"][$key] = $comparr['compid']; @@ -4171,7 +4428,110 @@ function isAvailable($images, $imageid, array_push($allocatedcompids, $comparr['compid']); } - return 1; + return debugIsAvailable(1, 12, $start, $end, $imagerevisionid, $computerids, $currentids, $blockids, array(), $virtual); +} + +//////////////////////////////////////////////////////////////////////////////// +/// +/// \fn debugIsAvailable($rc, $loc, $start, $end, $imagerevisionid, +/// $compids=array(), $currentids=array(), +/// $blockids=array(), $failedids=array(), $virtual='') +/// +/// \param $rc - return code +/// \param $loc - location from isAvailable function +/// \param $start - as passed to isAvailable function +/// \param $end - as passed to isAvailable function +/// \param $imagerevisionid - as passed to isAvailable function +/// \param $compids - $computerids from isAvailable +/// \param $currentids - $currentids from isAvailable +/// \param $blockids - $blockids from isAvailable +/// \param $failedids - $failedids from isAvailable +/// \param $virtual - $virtual from isAvailable +/// +/// \return $rc as passed in +/// +/// \brief prints debug line about why isAvailable returned specified return +/// code in javascript console if user has 'View Debug Information' user group +/// permission and has set the debug flag; most data passed in is currently +/// unused, but allows for a single place to add code for debugging +/// +//////////////////////////////////////////////////////////////////////////////// +function debugIsAvailable($rc, $loc, $start, $end, $imagerevisionid, + $compids=array(), $currentids=array(), + $blockids=array(), $failedids=array(), $virtual='') { + global $user, $mode; + $debug = getContinuationVar('debug', 0); + if(! $debug || + $mode != 'AJupdateWaitTime' || + ! checkUserHasPerm('View Debug Information')) + return $rc; + switch($loc) { + case "1": + $msg = "site maintenance is scheduled for the requested time"; + break; + case "20": + $msg = "invalid image id submitted - not found in images available to the user"; + break; + case "2": + $msg = "an overlapping server reservation has the same fixed IP or MAC address"; + break; + case "16": + $msg = "the requested fixed IP address is currently in use by a management node"; + break; + case "17": + $msg = "failed to look up information about the specified user"; + break; + case "3": + $msg = "failed to get image usage count for block allocations"; + break; + case "4": + $msg = "max concurrent usage of image exceeded (includes those set aside for block allocations)"; + break; + case "5": + $msg = "failed to get platform of image"; + break; + case "6": + $msg = "image is not mapped to any computers"; + break; + case "18": + $msg = "no available computers under a management node that can handle the specified IP address"; + break; + case "7": + $msg = "the schedule of the currently reserved computer does not allow for the requested time"; + break; + case "8": + $msg = "failed to get OSinstalltype for image"; + break; + case "21": + $msg = "no computers with a matching schedule and platform, and in an available state, and available to the user, and mapped to the image, and matching image resource requirements"; + break; + case "9": + $msg = "not able to change existing reservation time for currently reserved computer"; + break; + case "19": + $msg = "no computers available (after removing scheduled computers/before performing virtual host resource checks)"; + break; + case "10": + $msg = "modification time overlaps with time computer is set aside for block allocation"; + break; + case "13": + $msg = "no computers available (after virtual host resource checks/before performing overlapping IP address check)"; + break; + case "18": + $msg = "requested IP address in use by another computer"; + break; + case "19": + $msg = "at least 2 computers have the requested IP address assigned to them"; + break; + case "11": + $msg = "unable to get either a management node or semaphore for available computer"; + break; + case "12": + $msg = "successfully found a computer"; + break; + } + print "console.log('$msg');"; + return $rc; } //////////////////////////////////////////////////////////////////////////////// @@ -4274,14 +4634,20 @@ function schCheckMaintenance($start, $en //////////////////////////////////////////////////////////////////////////////// /// -/// \fn allocComputer($blockids, $currentids, $computerids, $start, -/// $nowfuture) +/// \fn allocComputer($blockids, $currentids, $computerids, $start, $end, +/// $nowfuture, $imageid, $imagerevisionid, $holdcomps, +/// $requestid) /// /// \param $blockids - array of computer ids /// \param $currentids - array of computer ids /// \param $computerids - array of computer ids /// \param $start - start time in datetime format +/// \param $start - end time in datetime format /// \param $nowfuture - "now" or "future" +/// \param $holdcomps - bool - 1 to lock computers for later adding to +/// reservation, 0 not to; use 0 when just checking for estimated availability, +/// use 1 when finding computers to actually reserve +/// \param $requestid - id of request if called for editing an existing one /// /// \return empty array if failed to allocate a computer; array with these keys /// on success:\n @@ -4294,8 +4660,10 @@ function schCheckMaintenance($start, $en /// tries to allocate a management node for it /// //////////////////////////////////////////////////////////////////////////////// -function allocComputer($blockids, $currentids, $computerids, $start, - $nowfuture) { +function allocComputer($blockids, $currentids, $computerids, $start, $end, + $nowfuture, $imageid, $imagerevisionid, $holdcomps, + $requestid) { + global $requestInfo; $ret = array(); if(SCHEDULER_ALLOCATE_RANDOM_COMPUTER) { shuffle($blockids); @@ -4306,6 +4674,8 @@ function allocComputer($blockids, $curre $mgmtnodeid = findManagementNode($compid, $start, $nowfuture); if($mgmtnodeid == 0) continue; + if($holdcomps && ! getSemaphore($imageid, $imagerevisionid, $mgmtnodeid, $compid, $start, $end, $requestid)) + continue; $ret['compid'] = $compid; $ret['mgmtid'] = $mgmtnodeid; $ret['loaded'] = 1; @@ -4316,6 +4686,8 @@ function allocComputer($blockids, $curre $mgmtnodeid = findManagementNode($compid, $start, $nowfuture); if($mgmtnodeid == 0) continue; + if($holdcomps && ! getSemaphore($imageid, $imagerevisionid, $mgmtnodeid, $compid, $start, $end, $requestid)) + continue; $ret['compid'] = $compid; $ret['mgmtid'] = $mgmtnodeid; $ret['loaded'] = 1; @@ -4326,6 +4698,8 @@ function allocComputer($blockids, $curre $mgmtnodeid = findManagementNode($compid, $start, $nowfuture); if($mgmtnodeid == 0) continue; + if($holdcomps && ! getSemaphore($imageid, $imagerevisionid, $mgmtnodeid, $compid, $start, $end, $requestid)) + continue; $ret['compid'] = $compid; $ret['mgmtid'] = $mgmtnodeid; $ret['loaded'] = 0; @@ -4337,6 +4711,103 @@ function allocComputer($blockids, $curre //////////////////////////////////////////////////////////////////////////////// /// +/// \fn getSemaphore($imageid, $imagerevisionid, $mgmtnodeid, $compid, $start, +/// $end, $requestid=0) +/// +/// \param $imageid - id of image +/// \param $imagerevisionid - id of image revision +/// \param $mgmtnodeid - id of management node +/// \param $compid - id of computer +/// \param $start - start of reservation in datetime format +/// \param $end - end of reservation in datetime format +/// \param $requestid - (optional) if passed, ignores checking for conflict +/// in request table for matching id +/// +/// \return 0 on failure, 1 on success +/// +/// \brief tries to get a semaphore for the requested computer +/// +//////////////////////////////////////////////////////////////////////////////// +function getSemaphore($imageid, $imagerevisionid, $mgmtnodeid, $compid, $start, + $end, $requestid=0) { + global $mysql_link_vcl, $uniqid; + $query = "INSERT INTO semaphore " + . "SELECT c.id, " + . "$imageid, " + . "$imagerevisionid, " + . "$mgmtnodeid, " + . "NOW() + INTERVAL " . SEMTIMEOUT . " SECOND, " + . "'$uniqid' " + . "FROM computer c " + . "LEFT JOIN semaphore s ON (c.id = s.computerid) " + . "WHERE c.id = $compid AND " + . "(s.expires IS NULL OR s.expires < NOW()) " + . "LIMIT 1"; + doQuery($query); + $rc = mysql_affected_rows($mysql_link_vcl); + + # check to see if another process allocated this one + if($rc) { + $query = "SELECT rq.id " + . "FROM request rq, " + . "reservation rs " + . "WHERE rs.requestid = rq.id AND " + . "rs.computerid = $compid AND " + . "rq.start < '$end' AND " + . "rq.end > '$start' AND " + . "rq.stateid NOT IN (1, 5, 12)"; + if($requestid) + $query .= " AND rq.id != $requestid"; + $qh = doQuery($query); + $rc2 = mysql_num_rows($qh); + if($rc2) { + $query = "DELETE FROM semaphore " + . "WHERE computerid = $compid AND " + . "procid = '$uniqid'"; + doQuery($query); + return 0; + } + } + return $rc; +} + +//////////////////////////////////////////////////////////////////////////////// +/// +/// \fn retryGetSemaphore($imageid, $imagerevisionid, $mgmtnodeid, $compid, +/// $start, $end, $requestid=0, $tries=5, $delay=200000) +/// +/// \param $imageid - id of image +/// \param $imagerevisionid - id of image revision +/// \param $mgmtnodeid - id of management node +/// \param $compid - id of computer +/// \param $start - start of reservation in datetime format +/// \param $end - end of reservation in datetime format +/// \param $requestid - (optional) if passed, ignores checking for conflict +/// \param $tries - (optional, default=5) number of attempts to make for getting +/// a semaphore +/// \param $delay - (optional, default=200000) microseconds to wait between +/// tries +/// +/// \return 0 on failure, 1 on success +/// +/// \brief makes multiple attempts to get a semaphore for a computer; useful +/// when needing to do an operation on a specific computer +/// +//////////////////////////////////////////////////////////////////////////////// +function retryGetSemaphore($imageid, $imagerevisionid, $mgmtnodeid, $compid, + $start, $end, $requestid=0, $tries=5, $delay=200000) { + for($i = 0; $i < $tries; $i++) { + if(getSemaphore($imageid, $imagerevisionid, $mgmtnodeid, $compid, $start, $end, $requestid)) { + return 1; + } + else + usleep($delay); + } + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +/// /// \fn getPossibleRecentFailures($userid, $imageid) /// /// \param $userid - check log data for this user; if $userid = 0, check for @@ -4373,8 +4844,7 @@ function getPossibleRecentFailures($user //////////////////////////////////////////////////////////////////////////////// /// -/// \fn getMappedResources($resourcesubid, $resourcetype1, -/// $resourcetype2) +/// \fn getMappedResources($resourcesubid, $resourcetype1, $resourcetype2) /// /// \param $resourcesubid - id of a resource from its table (ie an imageid) /// \param $resourcetype1 - type of $resourcesubid (name or id) @@ -4606,7 +5076,7 @@ function getMaxOverlap($userid) { /// //////////////////////////////////////////////////////////////////////////////// function addRequest($forimaging=0, $revisionid=array()) { - global $requestInfo, $user; + global $requestInfo, $user, $uniqid, $mysql_link_vcl; $startstamp = unixToDatetime($requestInfo["start"]); $endstamp = unixToDatetime($requestInfo["end"]); $now = time(); @@ -4628,18 +5098,6 @@ function addRequest($forimaging=0, $revi } $logid = $row[0]; - $query = "INSERT INTO changelog " - . "(logid, " - . "start, " - . "end, " - . "timestamp) " - . "VALUES " - . "($logid, " - . "'$start', " - . "'$endstamp', " - . "NOW())"; - doQuery($query, 136); - # add single entry to request table $query = "INSERT INTO request " . "(stateid, " @@ -4690,24 +5148,51 @@ function addRequest($forimaging=0, $revi else $blockdata = array(); - $query = "INSERT INTO reservation " - . "(requestid, " - . "computerid, " - . "imageid, " - . "imagerevisionid, " - . "managementnodeid) " - . "VALUES " - . "($requestid, " - . "$computerid, " - . "$imageid, " - . "$imagerevisionid, " - . "$mgmtnodeid)"; - doQuery($query, 133); addSublogEntry($logid, $imageid, $imagerevisionid, $computerid, $mgmtnodeid, $fromblock, $blockdata); } + + $query = "INSERT INTO reservation " + . "(requestid, " + . "computerid, " + . "imageid, " + . "imagerevisionid, " + . "managementnodeid) " + . "SELECT $requestid, " + . "computerid, " + . "imageid, " + . "imagerevisionid, " + . "managementnodeid " + . "FROM semaphore " + . "WHERE expires > NOW() AND " + . "procid = '$uniqid'"; + doQuery($query); + $cnt = mysql_affected_rows($mysql_link_vcl); + if($cnt == 0) { + # reached this point SEMTIMEOUT seconds after getting semaphore, clean up and abort + $query = "DELETE FROM request WHERE id = $requestid"; + doQuery($query); + $query = "UPDATE log SET wasavailable = 0 WHERE id = $logid"; + doQuery($query); + $query = "DELETE FROM sublog WHERE logid = $logid"; + doQuery($query); + abort(400); + } + else { + $query = "INSERT INTO changelog " + . "(logid, " + . "start, " + . "end, " + . "timestamp) " + . "VALUES " + . "($logid, " + . "'$start', " + . "'$endstamp', " + . "NOW())"; + doQuery($query, 136); + } // release semaphore lock - semUnlock(); + cleanSemaphore(); return $requestid; } @@ -5033,7 +5518,11 @@ function updateRequest($requestid) { . "managementnodeid = $mgmtnodeid " . "WHERE requestid = $requestid AND " . "imageid = $imgid AND " - . "computerid = $oldCompid"; + . "computerid = $oldCompid " + . "LIMIT 1"; # without this, it can update one row to have the + # same computer as another row; then, the later row + # could be updated, which would end up setting both + # rows to the same computer doQuery($query, 147); addChangeLogEntry($logid, NULL, $endstamp, $startstamp, $computerid, NULL, 1); @@ -5120,12 +5609,17 @@ function deleteRequest($request) { } if($request['serverrequest']) { - $query = "DELETE FROM serverrequest WHERE requestid = {$request['id']}"; - $qh = doQuery($query, 152); + $query = "SELECT id FROM serverrequest WHERE requestid = {$request['id']}"; + $qh = doQuery($query); + if($row = mysql_fetch_assoc($qh)) { + $query = "DELETE FROM serverrequest WHERE requestid = {$request['id']}"; + doQuery($query, 152); + deleteVariable("fixedIPsr{$row['id']}"); + } } $query = "DELETE FROM request WHERE id = {$request['id']}"; - $qh = doQuery($query, 153); + doQuery($query, 153); $query = "DELETE FROM reservation WHERE requestid = {$request['id']}"; doQuery($query, 154); @@ -5145,7 +5639,8 @@ function deleteRequest($request) { /// reservations were found on $compid /// /// \brief attempts to move reservations off of a $compid - if $compid is not -/// given, removes all reservations from the computer with the least number +/// given, removes all reservations from the computer with the least number; +/// NOTE - cleanSemaphore should be called after this by the calling function /// //////////////////////////////////////////////////////////////////////////////// function moveReservationsOffComputer($compid=0, $count=0) { @@ -5198,10 +5693,14 @@ function moveReservationsOffComputer($co return -1; $images = getImages(); $allmovable = 1; + # TODO eventually, for clusters, there will probably be restrictions on how the computers + # relate to each other; at that point, this will need to be updated to make sure the computer + # a reservation is reassigned to meets the same restrictions foreach($resInfo as $res) { + // pass forimaging = 1 so that isAvailable only looks at one computer $rc = isAvailable($images, $res["imageid"], $res['imagerevisionid'], datetimeToUnix($res["start"]), datetimeToUnix($res["end"]), 0, - $res["userid"]); + 0, $res["userid"], 0, 1); if($rc < 1) { $allmovable = 0; break; @@ -5211,8 +5710,8 @@ function moveReservationsOffComputer($co return 0; foreach($resInfo as $res) { $rc = isAvailable($images, $res["imageid"], $res['imagerevisionid'], - datetimeToUnix($res["start"]), datetimeToUnix($res["end"]), 0, - $res["userid"]); + datetimeToUnix($res["start"]), datetimeToUnix($res["end"]), 1, + 0, $res["userid"], 0, 1); if($rc > 0) { $newcompid = array_shift($requestInfo["computers"]); # get mgmt node for computer @@ -5227,7 +5726,8 @@ function moveReservationsOffComputer($co addChangeLogEntry($res['logid'], NULL, NULL, NULL, $newcompid); # update sublog entry $query = "UPDATE sublog " - . "SET computerid = $newcompid " + . "SET computerid = $newcompid, " + . "managementnodeid = $mgmtnodeid " . "WHERE logid = {$res['logid']} AND " . "computerid = $compid"; doQuery($query, 101); @@ -5240,23 +5740,71 @@ function moveReservationsOffComputer($co //////////////////////////////////////////////////////////////////////////////// /// -/// \fn getCompFinalReservationTime($compid) +/// \fn moveReservationsOffVMs($compid, $sem) +/// +/// \param $compid - id of host computer from which to move +/// reservations +/// \param $sem - (optional) array of data to be used when getting a semaphore +/// for a VM after reservations have been moved off of it; must include these +/// keys: imageid, revid, mnid, start (datetime), end (datetime) +/// +/// \return 0 if failed to move reservations, 1 if succeeded, -1 if no +/// reservations were found on $compid +/// +/// \brief attempts to move reservations off of any VMs assigned to a $compid +/// NOTE - cleanSemaphore should be called after this by the calling function +/// +//////////////////////////////////////////////////////////////////////////////// +function moveReservationsOffVMs($compid, $sem=0) { + if(! is_array($sem)) { + $sem = array(); + $resources = getUserResources(array("imageAdmin", "imageCheckOut")); + $tmp = array_keys($resources['image']); + $sem['imageid'] = $tmp[0]; + $sem['revid'] = getProductionRevisionid($sem['imageid']); + $tmp = array_keys($resources['managementnode']); + $sem['mnid'] = $tmp[0]; + $sem['start'] = unixToDatetime(time()); + $sem['end'] = '2038-01-01 00:00:00'; + } + $query = "SELECT vm.id " + . "FROM computer vm, " + . "vmhost v " + . "WHERE v.computerid = $compid AND " + . "vm.vmhostid = v.id"; + $qh = doQuery($query); + while($row = mysql_fetch_assoc($qh)) { + $rc = moveReservationsOffComputer($row['id']); + if($rc != 0) + # lock computer so that reservations on other VMs on this host do not get moved to it + getSemaphore($sem['imageid'], $sem['revid'], $sem['mnid'], $row['id'], $sem['start'], $sem['end']); + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// +/// \fn getCompFinalReservationTime($compid, $extraskipstate=0) /// /// \param $compid - a computer id +/// \param $extraskipstate - (default=0) id of an additional request state to +/// ignore; if 0 passed, no additional states are ignored /// /// \return unix timestamp of last end time of any reservations for $compid /// /// \brief determines the final end time of all reservations on a computer /// //////////////////////////////////////////////////////////////////////////////// -function getCompFinalReservationTime($compid) { +function getCompFinalReservationTime($compid, $extraskipstate=0) { $end = 0; + $skipstates = "1,5,12"; + if($extraskipstate) + $skipstates .= ",$extraskipstate"; $query = "SELECT UNIX_TIMESTAMP(rq.end) as end " . "FROM request rq, " . "reservation rs " . "WHERE rs.requestid = rq.id AND " . "rs.computerid = $compid AND " - . "rq.stateid NOT IN (1,5,12) " + . "rq.stateid NOT IN ($skipstates) " . "ORDER BY rq.end DESC " . "LIMIT 1"; $qh = doQuery($query, 101); @@ -5279,6 +5827,153 @@ function getCompFinalReservationTime($co //////////////////////////////////////////////////////////////////////////////// /// +/// \fn getCompFinalVMReservationTime($hostid, $addsemaphores, $notomaintenance) +/// +/// \param $hostid - computer id of a vm host +/// \param $addsemaphores - (optional, default = 0) 1 to add semaphores for each +/// of the VMs +/// \param $notomaintenance - (optional, default = 0) 1 to ignore any +/// tomaintenance reservations +/// +/// \return unix timestamp of last end time of any reservations for VMs on +/// $hostid; 0 if no reservations; -1 if $addsemaphores = 1 and failed to get +/// semaphores +/// +/// \brief determines the final end time of all reservations of all VMs on a +/// VM host computer +/// +//////////////////////////////////////////////////////////////////////////////// +function getCompFinalVMReservationTime($hostid, $addsemaphores=0, + $notomaintenance=0) { + global $uniqid, $mysql_link_vcl; + if($addsemaphores) { + $query = "SELECT vm.id " + . "FROM computer vm, " + . "vmhost v " + . "WHERE v.computerid = $hostid AND " + . "vm.vmhostid = v.id"; + $qh = doQuery($query); + $compids = array(); + while($row = mysql_fetch_assoc($qh)) + $compids[] = $row['id']; + if(empty($compids)) + return 0; + $allcompids = implode(',', $compids); + $imageid = getImageId('noimage'); + $revid = getProductionRevisionid($imageid); + $tmp = getManagementNodes(); + $tmp = array_keys($tmp); + $mnid = $tmp[0]; + $query = "INSERT INTO semaphore " + . "SELECT c.id, " + . "$imageid, " + . "$revid, " + . "$mnid, " + . "NOW() + INTERVAL " . SEMTIMEOUT . " SECOND, " + . "'$uniqid' " + . "FROM computer c " + . "LEFT JOIN semaphore s ON (c.id = s.computerid) " + . "WHERE c.id IN ($allcompids) AND " + . "(s.expires IS NULL OR s.expires < NOW()) " + . "GROUP BY c.id"; + doQuery($query); + $cnt = mysql_affected_rows($mysql_link_vcl); + if($cnt != count($compids)) + return -1; + } + + $end = 0; + $skipstates = '1,5,12'; + if($notomaintenance) + $skipstates .= ',18'; + $query = "SELECT UNIX_TIMESTAMP(rq.end) as end " + . "FROM request rq, " + . "reservation rs " + . "WHERE rs.requestid = rq.id AND " + . "rq.stateid NOT IN ($skipstates) AND " + . "rs.computerid IN (SELECT vm.id " + . "FROM computer vm, " + . "vmhost v " + . "WHERE v.computerid = $hostid AND " + . "vm.vmhostid = v.id) " + . "ORDER BY rq.end DESC " + . "LIMIT 1"; + $qh = doQuery($query, 101); + if($row = mysql_fetch_assoc($qh)) + $end = $row['end']; + $query = "SELECT UNIX_TIMESTAMP(t.end) as end " + . "FROM blockComputers c, " + . "blockTimes t " + . "WHERE c.blockTimeid = t.id AND " + . "t.end > NOW() AND " + . "c.computerid IN (SELECT vm.id " + . "FROM computer vm, " + . "vmhost v " + . "WHERE v.computerid = $hostid AND " + . "vm.vmhostid = v.id) " + . "ORDER BY t.end DESC " + . "LIMIT 1"; + $qh = doQuery($query, 101); + if($row = mysql_fetch_assoc($qh)) + if($row['end'] > $end) + $end = $row['end']; + return $end; +} + +//////////////////////////////////////////////////////////////////////////////// +/// +/// \fn getExistingChangeStateStartTime($compid, $stateid) +/// +/// \param $compid - computer id +/// \param $stateid - id of state of reservation +/// +/// \return unix timestamp +/// +/// \brief gets the start time for the earliest existing reservation for $compid +/// that has a state of $stateid +/// +//////////////////////////////////////////////////////////////////////////////// +function getExistingChangeStateStartTime($compid, $stateid) { + $query = "SELECT rq.start " + . "FROM request rq, " + . "reservation rs " + . "WHERE rs.requestid = rq.id AND " + . "rs.computerid = $compid AND " + . "rq.stateid = $stateid AND " + . "rq.start > NOW() " + . "ORDER BY rq.start " + . "LIMIT 1"; + $qh = doQuery($query); + if($row = mysql_fetch_assoc($qh)) + return datetimeToUnix($row['start']); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +/// +/// \fn updateExistingToState($compid, $start, $stateid) +/// +/// \param $compid - computer id +/// \param $start - new start time in datetime format +/// \param $stateid - id of state for existing reservation +/// +/// \brief updates the start time of an existing reservation for $compid with a +/// state of $stateid +/// +//////////////////////////////////////////////////////////////////////////////// +function updateExistingToState($compid, $start, $stateid) { + $query = "UPDATE request rq, " + . "reservation rs " + . "SET rq.start = '$start' " + . "WHERE rs.requestid = rq.id AND " + . "rq.stateid = $stateid AND " + . "rq.start > '$start' AND " + . "rs.computerid = $compid"; + doQuery($query); +} + +//////////////////////////////////////////////////////////////////////////////// +/// /// \fn getUserRequests($type, $id) /// /// \param $type - "normal", "forimaging", or "all" @@ -5850,6 +6545,50 @@ function getProvisioning() { //////////////////////////////////////////////////////////////////////////////// /// +/// \fn getProvisioningTypes() +/// +/// \return array of provisioning types allowed for each computer type of this +/// form:\n +/// {[blade] => {[id] => type,\n +/// [id] => type},\n +/// [lab] => {[id] => type}\n +/// [virtualmachine] => {[id] => type,\n +/// [id] => type}\n +/// +/// \brief generates an array of provisioning types allowed for each computer +/// type +/// +//////////////////////////////////////////////////////////////////////////////// +function getProvisioningTypes() { + $query = "SELECT id, prettyname FROM provisioning WHERE name = 'none'"; + $qh = doQuery($query); + $none = mysql_fetch_assoc($qh); + $query = "SELECT p.id, " + . "p.prettyname, " + . "o.name AS `type` " + . "FROM provisioning p, " + . "OSinstalltype o, " + . "provisioningOSinstalltype po " + . "WHERE po.provisioningid = p.id AND " + . "po.OSinstalltypeid = o.id " + . "ORDER BY o.name"; + $qh = doQuery($query); + $types = array('blade' => array($none['id'] => $none['prettyname']), + 'lab' => array(), + 'virtualmachine' => array()); + while($row = mysql_fetch_assoc($qh)) { + if($row['type'] == 'kickstart' || $row['type'] == 'partimage') + $types['blade'][$row['id']] = $row['prettyname']; + if($row['type'] == 'none') + $types['lab'][$row['id']] = $row['prettyname']; + if($row['type'] == 'vbox' || $row['type'] == 'vmware') + $types['virtualmachine'][$row['id']] = $row['prettyname']; + } + return $types; +} + +//////////////////////////////////////////////////////////////////////////////// +/// /// \fn getSchedules() /// /// \return array of schedules where the index are the id from the schedule table, @@ -5857,6 +6596,7 @@ function getProvisioning() { /// \b name - name of schedule\n /// \b ownerid - user id of owner\n /// \b owner - unity id of owner\n +/// \b resourceid - id from resource table\n /// \b times - array of start and end times for the schedule /// /// \brief gets information for schedules in schedule table @@ -5943,11 +6683,15 @@ function formatMinOfWeek($min) { //////////////////////////////////////////////////////////////////////////////// /// -/// \fn getManagementNodes($alive) +/// \fn getManagementNodes($alive, $includedeleted, $id) /// /// \param $alive - (optional) if given, only return "alive" nodes, can be /// either "now" or "future" so we know how recently it must /// have checked in +/// \param $includedeleted - (optional, default=0) 1 to include management +/// nodes with a state of deleted, 0 to leave them out +/// \param $id - (optional, default is all nodes) specify an id of a management +/// node to only have data for that node returned /// /// \return an array of management nodes where eash index is the id from the /// managementnode table and each element is an array of data about the node @@ -5957,7 +6701,7 @@ function formatMinOfWeek($min) { /// if $alive = future, must have checked in within 1 hour /// //////////////////////////////////////////////////////////////////////////////// -function getManagementNodes($alive="neither") { +function getManagementNodes($alive="neither", $includedeleted=0, $id=0) { if($alive == "now") $lastcheckin = unixToDatetime(time() - 300); elseif($alive == "future") @@ -5988,7 +6732,9 @@ function getManagementNodes($alive="neit . "m.sharedMailBox AS sharedmailbox, " . "r.id as resourceid, " . "m.predictivemoduleid, " - . "mo.prettyname AS predictivemodule " + . "mo.prettyname AS predictivemodule, " + . "m.availablenetworks, " + . "m.NOT_STANDALONE AS federatedauth " . "FROM user u, " . "state s, " . "resource r, " @@ -6004,6 +6750,10 @@ function getManagementNodes($alive="neit . "rt.name = 'managementnode' AND " . "u.affiliationid = a.id AND " . "m.predictivemoduleid = mo.id"; + if($id != 0) + $query .= " AND m.id = $id"; + if($includedeleted == 0) + $query .= " AND s.name != 'deleted'"; if($alive == "now" || $alive == "future") { $query .= " AND m.lastcheckin > '$lastcheckin'" . " AND s.name != 'maintenance'"; @@ -6012,12 +6762,107 @@ function getManagementNodes($alive="neit $return = array(); while($row = mysql_fetch_assoc($qh)) { $return[$row["id"]] = $row; + $return[$row['id']]['availablenetworks'] = explode(',', $row['availablenetworks']); + if($row['state'] == 'deleted') + $return[$row['id']]['deleted'] = 1; + else + $return[$row['id']]['deleted'] = 0; } + + # Get items from variable table for specific management node id + foreach ($return as $mn_id => $value ) { + if(array_key_exists("hostname", $value)) { + $mn_hostname = $value['hostname']; + $timeservers = getVariable('timesource|'.$mn_hostname); + if($timeservers == NULL) { + $timeservers = getVariable('timesource|global'); + } + $return[$mn_id]['timeservers'] = $timeservers; + } + } + return $return; } //////////////////////////////////////////////////////////////////////////////// /// +/// \fn getMnsFromImage($imageid) +/// +/// \param $imageid - id of an image +/// +/// \return array of management node ids +/// +/// \brief determines which management nodes can handle an image based on +/// image group to computer group, then computer group to management node group +/// mapping +/// +//////////////////////////////////////////////////////////////////////////////// +function getMnsFromImage($imageid) { + $comps = getMappedResources($imageid, 'image', 'computer'); + if(empty($comps)) + return array(); + $inlist = implode(',', $comps); + $query = "SELECT DISTINCT rgm.resourcegroupid " + . "FROM resourcegroupmembers rgm, " + . "resource r, " + . "computer c " + . "WHERE c.id = r.subid AND " + . "r.resourcetypeid = 12 AND " + . "r.id = rgm.resourceid AND " + . "c.id in ($inlist)"; + $qh = doQuery($query); + $compgroups = array(); + while($row = mysql_fetch_assoc($qh)) + $compgroups[] = $row['resourcegroupid']; + $mngrps = array(); + foreach($compgroups as $grpid) { + $mngrpset = getResourceMapping('managementnode', 'computer', '', implode(',', $compgroups)); + foreach($mngrpset as $mngrpid => $compgrpset) + $mngrps[$mngrpid] = 1; + } + $mngrpnames = array(); + foreach(array_keys($mngrps) as $mnid) { + $mngrpnames[] = getResourceGroupName($mnid); + } + $mns = getResourcesFromGroups($mngrpnames, 'managementnode', 0); + $mnids = array(); + foreach($mns as $mnid => $name) + $mnids[$mnid] = 1; + return array_keys($mnids); +} + +//////////////////////////////////////////////////////////////////////////////// +/// +/// \fn checkAvailableNetworks($ip) +/// +/// \param $ip - public ip address for a reservation +/// +/// \return array of management node ids that can handle $ip +/// +/// \brief finds any management nodes that can manage networks containing $ip +/// +//////////////////////////////////////////////////////////////////////////////// +function checkAvailableNetworks($ip) { + $ip = ip2long($ip); + $mnids = array(); + $mns = getManagementNodes(); + foreach($mns as $mn) { + foreach($mn['availablenetworks'] as $net) { + if($net == '') + continue; + list($net, $netmask) = explode('/', $net); + $net = ip2long($net); + $mask = pow(2, (32 - $netmask)) - 1; + $mask = ~ $mask; + if(($ip & $mask) == ($net & $mask)) + $mnids[$mn['id']] = 1; + } + } + return array_keys($mnids); +} + +//////////////////////////////////////////////////////////////////////////////// +/// /// \fn getPredictiveModules() /// /// \return an array of predictive loading modules where the index is the module @@ -6043,8 +6888,9 @@ function getPredictiveModules() { //////////////////////////////////////////////////////////////////////////////// /// -/// \fn getTimeSlots($end, $start) +/// \fn getTimeSlots($compids, $end, $start) /// +/// \param $compids - array of computer ids /// \param $end - (optional) end time as unix timestamp /// \param $start - (optional) start time as unix timestamp /// @@ -6755,12 +7601,19 @@ function findAvailableTimes($start, $end $query = "SELECT c.id AS compid " . "FROM computer c, " . "image i, " - . "state s " + . "state s, " + . "provisioningOSinstalltype poi, " + . "OSinstalltype oi, " + . "OS o " . "WHERE c.stateid = s.id AND " . "i.id = $imageid AND " . "s.name NOT IN ($nowignorestates) AND " . "c.platformid = $platformid AND " . "c.scheduleid IN ($schedules) AND " + . "i.OSid = o.id AND " + . "o.installtype = oi.name AND " + . "oi.id = poi.OSinstalltypeid AND " + . "poi.provisioningid = c.provisioningid AND " . "c.RAM >= i.minram AND " . "c.procnumber >= i.minprocnumber AND " . "c.procspeed >= i.minprocspeed AND " @@ -6774,9 +7627,9 @@ function findAvailableTimes($start, $end $query .= "DATE_ADD(rq.end, INTERVAL 15 MINUTE) >= '$startdt' AND " . "rs.computerid IN ($incompids)) AND " . "c.id IN ($incompids) " - . "ORDER BY (c.procspeed * c.procnumber) DESC, " - . "RAM DESC, " - . "network DESC"; + . "ORDER BY RAM, " + . "(c.procspeed * c.procnumber), " + . "network"; $qh = doQuery($query, 101); while($row = mysql_fetch_assoc($qh)) { $row['duration'] = $reqduration; @@ -6799,7 +7652,10 @@ function findAvailableTimes($start, $end . "reservation rs2, " . "image i, " . "state s, " - . "computer c " + . "computer c, " + . "provisioningOSinstalltype poi, " + . "OSinstalltype oi, " + . "OS o " . "WHERE rq1.id = rs1.requestid AND " . "rs2.requestid = rq2.id AND " . "rq1.id != rq2.id AND " @@ -6811,6 +7667,10 @@ function findAvailableTimes($start, $end . "c.id = rs1.computerid AND " . "c.platformid = $platformid AND " . "c.scheduleid IN ($schedules) AND " + . "i.OSid = o.id AND " + . "o.installtype = oi.name AND " + . "oi.id = poi.OSinstalltypeid AND " + . "poi.provisioningid = c.provisioningid AND " . "c.RAM >= i.minram AND " . "c.procnumber >= i.minprocnumber AND " . "c.procspeed >= i.minprocspeed AND " @@ -6857,7 +7717,10 @@ function findAvailableTimes($start, $end . "reservation rs, " . "image i, " . "state s, " - . "computer c " + . "computer c, " + . "provisioningOSinstalltype poi, " + . "OSinstalltype oi, " + . "OS o " . "WHERE rs.requestid = rq.id AND " . "(rq.start > '$startdt' OR " . "(DATE_ADD(rq.end, INTERVAL 15 MINUTE) > '$startdt' AND rq.start <= '$startdt')) AND " @@ -6866,6 +7729,10 @@ function findAvailableTimes($start, $end . "c.id = rs.computerid AND " . "c.platformid = $platformid AND " . "c.scheduleid IN ($schedules) AND " + . "i.OSid = o.id AND " + . "o.installtype = oi.name AND " + . "oi.id = poi.OSinstalltypeid AND " + . "poi.provisioningid = c.provisioningid AND " . "c.RAM >= i.minram AND " . "c.procnumber >= i.minprocnumber AND " . "c.procspeed >= i.minprocspeed AND " @@ -6904,7 +7771,10 @@ function findAvailableTimes($start, $end . "reservation rs, " . "image i, " . "state s, " - . "computer c " + . "computer c, " + . "provisioningOSinstalltype poi, " + . "OSinstalltype oi, " + . "OS o " . "WHERE rs.requestid = rq.id AND " . "(rq.start > '$startdt' OR " . "(DATE_ADD(rq.end, INTERVAL 15 MINUTE) > '$startdt' AND rq.start <= '$startdt')) AND " @@ -6913,10 +7783,15 @@ function findAvailableTimes($start, $end . "c.id = rs.computerid AND " . "c.platformid = $platformid AND " . "c.scheduleid IN ($schedules) AND " + . "i.OSid = o.id AND " + . "o.installtype = oi.name AND " + . "oi.id = poi.OSinstalltypeid AND " + . "poi.provisioningid = c.provisioningid AND " . "c.RAM >= i.minram AND " . "c.procnumber >= i.minprocnumber AND " . "c.procspeed >= i.minprocspeed AND " . "c.network >= i.minnetwork AND " + . "c.deleted = 0 AND " . "c.stateid = s.id AND " . "s.name NOT IN ($ignorestates) AND "; if($reqid != '') @@ -7249,7 +8124,7 @@ function getComputers($sort=0, $included . "c.platformid AS platformid, " . "sc.name AS schedule, " . "c.scheduleid AS scheduleid, " - . "cur.name AS currentimg, " + . "cur.prettyname AS currentimg, " . "c.currentimageid AS currentimgid, " . "c.imagerevisionid, " . "next.name AS nextimg, " @@ -7269,6 +8144,7 @@ function getComputers($sort=0, $included . "c.notes, " . "c.vmhostid, " . "c2.hostname AS vmhost, " + . "c2.id AS vmhostcomputerid, " . "c.location, " . "c.provisioningid, " . "pr.prettyname AS provisioning, " @@ -7852,7 +8728,7 @@ function isImageBlockTimeActive($imageid /// \param $selectedid - (optional) index of $dataArr to be initially selected; /// use -1 for nothing to be selected /// \param $skip - (optional) this is used if the array from getImages is passed -/// as $dataArr so we know to skip index 4 since it is the noimage element +/// as $dataArr so we know to skip the 'No Image" element /// \param $multiple - (optional) use this to print select input with the /// multiple tag set /// \param $domid - (optional) use this to pass in the javascript id to be used @@ -7867,6 +8743,66 @@ function isImageBlockTimeActive($imageid //////////////////////////////////////////////////////////////////////////////// function printSelectInput($name, $dataArr, $selectedid=-1, $skip=0, $multiple=0, $domid="", $extra="") { + print selectInputHTML($name, $dataArr, $domid, $extra, $selectedid, $skip, + $multiple); +} + +//////////////////////////////////////////////////////////////////////////////// +/// +/// \fn selectInputAutoDijitHTML($name, $dataArr, $domid='', $extra='', +/// $selectedid=-1) { +/// +/// \param $name - name of input element +/// \param $dataArr - array containing options +/// \param $domid - (optional) use this to pass in the javascript id to be used +/// for the select object +/// \param $extra - (optional) any extra attributes that need to be set +/// \param $selectedid - (optional) index of $dataArr to be initially selected; +/// use -1 for nothing to be selected +/// +/// \return html +/// +/// \brief wrapper for calling selectInputHTML with the resulting element +/// being a dijit.form.Select if number of items is <= 10 and being a +/// dijit.form.FilteringSelect if number of items is > 10 +/// +//////////////////////////////////////////////////////////////////////////////// +function selectInputAutoDijitHTML($name, $dataArr, $domid='', $extra='', + $selectedid=-1) { + if(count($dataArr) > 10 && + USEFILTERINGSELECT && count($dataArr) < FILTERINGSELECTTHRESHOLD) + $type = 'dojoType="dijit.form.FilteringSelect" queryExpr="*${0}*"'; + else + $type = 'dojoType="dijit.form.Select" maxHeight="250"'; + return selectInputHTML($name, $dataArr, $domid, "$type $extra", $selectedid); +} + +//////////////////////////////////////////////////////////////////////////////// +/// +/// \fn selectInputHTML($name, $dataArr, $domid, $extra, $selectedid, $skip, +/// $multiple) +/// +/// \param $name - name of input element +/// \param $dataArr - array containing options +/// \param $domid - (optional) use this to pass in the javascript id to be used +/// for the select object +/// \param $extra - (optional) any extra attributes that need to be set +/// \param $selectedid - (optional) index of $dataArr to be initially selected; +/// use -1 for nothing to be selected +/// \param $skip - (optional) this is used if the array from getImages is passed +/// as $dataArr so we know to skip the 'No Image" element +/// \param $multiple - (optional) use this to print select input with the +/// multiple tag set +/// +/// \brief generates HTML for select input +/// it is assumed that if $selectedid is left off, we assume $dataArr has no +/// index '-1'\n +/// each OPTION's value is the index of that element of the array +/// +//////////////////////////////////////////////////////////////////////////////// +function selectInputHTML($name, $dataArr, $domid="", $extra="", $selectedid=-1, + $skip=0, $multiple=0) { + $h = ''; if(! empty($domid)) $domid = "id=\"$domid\""; if($multiple) @@ -7874,52 +8810,218 @@ function printSelectInput($name, $dataAr else $multiple = ""; if($name != '') - print " <select name=$name $multiple $domid $extra>\n"; + $h .= " <select name=$name $multiple $domid $extra>\n"; else - print " <select $multiple $domid $extra>\n"; + $h .= " <select $multiple $domid $extra>\n"; foreach(array_keys($dataArr) as $id) { - if(($skip && $id == 4) || ($dataArr[$id] != 0 && empty($dataArr[$id]))) + if(($dataArr[$id] != 0 && empty($dataArr[$id]))) continue; if($id == $selectedid) - print " <option value=\"$id\" selected=\"selected\">";
[... 2112 lines stripped ...]
