function scheduleVMsToAvailable($vmids) { # TODO test with vcld that will handle reservation for noimage okay # schedule $vmids to have noimage "loaded" on them in 15 minutes $allids = implode(',', $vmids); $query = "UPDATE computer " . "SET stateid = 5, " . "notes = '' " . "WHERE id IN ({$allids})"; doQuery($query); $imageid = getImageId('noimage'); $revid = getProductionRevisionid($imageid); $start = time() + 900; $end = $start + 3600; $startdt = unixToDatetime($start); $enddt = unixToDatetime($end); $vclreloadid = getUserlistID('vclreload@Local'); foreach ($vmids as $vmid) { // if simpleAddRequest fails, vm is left assigned and in failed state, which is fine simpleAddRequest($vmid, $imageid, $revid, $startdt, $enddt, 19, $vclreloadid); } }
function processRequestInput() { global $user; $baseaccess = getContinuationVar('baseaccess', 0); $imagingaccess = getContinuationVar('imagingaccess', 0); $serveraccess = getContinuationVar('serveraccess', 0); $openend = getContinuationVar('openend', 0); $nousercheck = getContinuationVar('nousercheck', 0); $return['imaging'] = getContinuationVar('imaging', 0); $maxinitial = getContinuationVar('maxinitial', 0); $noimaging = getContinuationVar('noimaging', array()); $return = array('err' => 0); # type $return['type'] = processInputVar('type', ARG_STRING); if (!preg_match('/^basic|imaging|server$/', $return['type'])) { $return['err'] = 1; $return['errmsg'] = i('Invalid data submitted'); return $return; } if ($return['type'] == 'basic' && !$baseaccess || $return['type'] == 'imaging' && !$imagingaccess || $return['type'] == 'server' && !$serveraccess) { $return['err'] = 1; $return['errmsg'] = i('No access to submitted reservation type'); return $return; } # ending $return['ending'] = processInputVar('ending', ARG_STRING); if (!preg_match('/^indefinite|endat|duration$/', $return['ending'])) { $return['err'] = 1; $return['errmsg'] = i('Invalid data submitted'); return $return; } if ($return['ending'] == 'duration' && !$baseaccess || $return['ending'] == 'indefinite' && !$serveraccess || $return['ending'] == 'endat' && !$openend && !$serveraccess) { $return['err'] = 1; $return['errmsg'] = i('No access to submitted end type'); return $return; } # imageid $return['imageid'] = processInputVar('imageid', ARG_NUMERIC); $resources = getUserResources(array("imageAdmin", "imageCheckOut")); $withnocheckout = $resources['image']; $images = removeNoCheckout($resources["image"]); $extraimages = getServerProfileImages($user['id']); if (!array_key_exists($return['imageid'], $images) && ($return['type'] != 'server' || !array_key_exists($return['imageid'], $extraimages)) && ($return['type'] != 'imaging' || !array_key_exists($return['imageid'], $withnocheckout)) || $return['type'] == 'imaging' && array_key_exists($return['imageid'], $noimaging)) { $return['err'] = 1; $return['errmsg'] = i('No access to submitted environment'); return $return; } # nousercheck $return['nousercheck'] = processInputVar('nousercheck', ARG_NUMERIC); if (!$nousercheck || $return['nousercheck'] != 1) { $return['nousercheck'] = 0; } # revisionid $revids = processInputVar("revisionid", ARG_STRING); $revids = explode(':', $revids); $images = getImages(0, $return['imageid']); $return['revisionids'] = array(); if (array_key_exists('subimages', $images[$return['imageid']])) { $subimages = $images[$return['imageid']]['subimages']; array_unshift($subimages, $return['imageid']); foreach ($subimages as $key => $imgid) { $revisions = getImageRevisions($imgid); if (!array_key_exists($key, $revids) || !is_numeric($revids[$key]) || !array_key_exists($revids[$key], $revisions)) { $revid = getProductionRevisionid($imgid); } else { $revid = $revids[$key]; } if (!array_key_exists($imgid, $return['revisionids'])) { $return['revisionids'][$imgid] = array(); } $return['revisionids'][$imgid][] = $revid; } } elseif ($revids[0] != '' && is_numeric($revids[0])) { $return['revisionids'][$return['imageid']][] = $revids[0]; } else { $return['revisionids'][$return['imageid']][] = getProductionRevisionid($return['imageid']); } # duration if ($return['ending'] == 'duration') { $return['duration'] = processInputVar('duration', ARG_NUMERIC, 0); if ($return['duration'] > $maxinitial) { $return['duration'] = $maxinitial; } } # start/end $return['start'] = processInputVar('start', ARG_NUMERIC); $return['end'] = processInputVar('end', ARG_NUMERIC, 0); $now = time(); if ($return['start'] == 0) { $start = $now; } else { $start = $return['start']; } if ($return['ending'] == 'endat') { $end = $return['end']; } if ($return['ending'] == 'indefinite') { $end = datetimeToUnix('2038-01-01 00:00:00'); } elseif ($return['ending'] == 'duration') { $end = $start + $return['duration'] * 60; } if ($start < $now) { $return['err'] = 1; $return['errmsg'] = i('The submitted start time is in the past.'); return $return; } if ($start + 900 > $end) { $return['err'] = 1; $return['errmsg'] = i('The end time must be at least 15 minutes later than the start time.'); return $return; } $return['ipaddr'] = ''; $return['macaddr'] = ''; # server specific input if ($return['type'] == 'server') { # name $return['name'] = processInputVar('name', ARG_STRING); if (!preg_match('/^([-a-zA-Z0-9_\\. ]){0,255}$/', $return['name'])) { $return['err'] = 1; $return['errmsg'] = i('The reservation name can only contain letters, numbers, spaces, dashes(-), underscores(_), and periods(.) and can be up to 255 characters long'); return $return; } # ipaddr $return['ipaddr'] = processInputVar('ipaddr', ARG_STRING); if ($return['ipaddr'] != '') { # validate fixed IP address if (!validateIPv4addr($return['ipaddr'])) { $return['err'] = 1; $return['errmsg'] = i('Invalid IP address. Must be w.x.y.z with each of w, x, y, and z being between 1 and 255 (inclusive)'); return $return; } # validate netmask $return['netmask'] = processInputVar('netmask', ARG_STRING); $bnetmask = ip2long($return['netmask']); if (!preg_match('/^[1]+0[^1]+$/', sprintf('%032b', $bnetmask))) { $return['err'] = 1; $return['errmsg'] = i('Invalid netmask specified'); return $return; } # validate router $return['router'] = processInputVar('router', ARG_STRING); if (!validateIPv4addr($return['router'])) { $return['err'] = 1; $return['errmsg'] = i('Invalid router address. Must be w.x.y.z with each of w, x, y, and z being between 1 and 255 (inclusive)'); return $return; } $return['network'] = ip2long($return['ipaddr']) & $bnetmask; if ($return['network'] != (ip2long($return['router']) & $bnetmask)) { $return['err'] = 1; $return['errmsg'] = i('IP address and router are not on the same subnet based on the specified netmask.'); return $return; } # validate dns server(s) $dns = processInputVar('dns', ARG_STRING); $tmp = explode(',', $dns); $cnt = 0; $return['dnsArr'] = array(); foreach ($tmp as $dnsaddr) { if ($cnt && $dnsaddr == '') { continue; } if ($cnt == 3) { $return['err'] = 1; $return['errmsg'] = i('Too many DNS servers specified - up to 3 are allowed.'); return $return; } if (!validateIPv4addr($dnsaddr)) { $return['err'] = 1; $return['errmsg'] = i('Invalid DNS server specified.'); return $return; } $return['dnsArr'][] = $dnsaddr; $cnt++; } # check that a management node can handle the network $mappedmns = getMnsFromImage($return['imageid']); $mnnets = checkAvailableNetworks($return['ipaddr']); $intersect = array_intersect($mappedmns, $mnnets); if (empty($intersect)) { $return['err'] = 1; $return['errmsg'] = i('There are no management nodes that can deploy the selected image with the specified IP address.'); return $return; } } # macaddr $return['macaddr'] = processInputVar('macaddr', ARG_STRING); if ($return['macaddr'] != '' && !preg_match('/^(([A-Fa-f0-9]){2}:){5}([A-Fa-f0-9]){2}$/', $return['macaddr'])) { $return['err'] = 1; $return['errmsg'] = i('Invalid MAC address. Must be XX:XX:XX:XX:XX:XX with each pair of XX being from 00 to FF (inclusive)'); return $return; } # profileid $return['profileid'] = processInputVar('profileid', ARG_NUMERIC, 0); $resources = getUserResources(array("serverCheckOut", "serverProfileAdmin"), array("available", "administer")); if (!array_key_exists($return['profileid'], $resources['serverprofile'])) { $return['profileid'] = 0; } elseif ($return['profileid'] != 0) { $tmp = getServerProfiles($return['profileid']); $tmp = $tmp[$return['profileid']]; if ($tmp['imageid'] != $return['imageid'] && ($tmp['fixedIP'] != $return['ipaddr'] && $tmp['fixedMAC'] != $return['macaddr'] || $tmp['fixedIP'] == $return['ipaddr'] && $return['ipaddr'] == '' && $tmp['fixedMAC'] == $return['macaddr'] && $return['macaddr'] == '')) { $return['profileid'] = 0; } } # admingroupid $usergroups = getUserGroups(); $return['admingroupid'] = processInputVar('admingroupid', ARG_NUMERIC); if ($return['admingroupid'] != 0 && !array_key_exists($return['admingroupid'], $usergroups)) { $return['err'] = 1; $return['errmsg'] = i('You do not have access to use the specified admin user group.'); return $return; } # logingroupid $return['logingroupid'] = processInputVar('logingroupid', ARG_NUMERIC); if ($return['logingroupid'] != 0 && !array_key_exists($return['logingroupid'], $usergroups)) { $return['err'] = 1; $return['errmsg'] = i('You do not have access to use the specified access user group.'); return $return; } # monitored $return['monitored'] = processInputVar('monitored', ARG_NUMERIC, 0); if ($return['monitored'] != 0 && $return['monitored'] != 1) { $return['monitored'] = 0; } # configs # TODO configs /*$tmp = getUserResources(array("configAdmin")); $userconfigs = $tmp['config']; $initconfigs = getMappedConfigs($return['imageid']); if(array_key_exists('configdata', $_POST)) { if(get_magic_quotes_gpc()) $_POST['configdata'] = stripslashes($_POST['configdata']); $configdata = json_decode($_POST['configdata']); } if(array_key_exists('configdata', $_POST) && isset($configdata->configs)) $configs = $configdata->configs; else $configs = (object)array(); $return['configs'] = array(); foreach($initconfigs as $id => $config) { if(isset($configs->{$id}) && isset($configs->{$id}->applied) && $configs->{$config['id']}->applied != 'true' && $configs->{$config['id']}->applied != 'false') unset($configs->{$config['id']}); if($config['optional'] && (! isset($configs->{$id}) || ! $configs->{$id}->applied)) continue; $return['configs'][$id] = array('configid' => $config['configid'], 'configmapid' => $config['configmapid'], 'imageid' => $config['subimageid']); if(isset($configs->{$id})) unset($configs->{$id}); } $rescfgmapids = array(); foreach($configs as $id => $config) { if(! array_key_exists($config->configid, $userconfigs)) continue; $return['configs'][$id] = array('configid' => $config->configid, 'configstageid' => $config->configstageid, 'imageid' => $config->imageid); $tmp = explode('/', $id); $rescfgmapids[$tmp[1]] = 1; } # configvars $tmp = array_splice($initconfigs, 0); $initconfigvars = getImageConfigVariables($tmp); if(array_key_exists('configdata', $_POST) && isset($configdata->configvars)) $configvars = $configdata->configvars; else $configvars = (object)array(); #print "/*"; #printArray($initconfigvars); #printArray($configvars); #print "*" . "/"; $return['configvars'] = array(); foreach($initconfigvars as $id => $configvar) { $tmp = explode('/', $id); $cfgid = "{$tmp[0]}/{$tmp[1]}"; $varid = $tmp[2]; if($configvar['ask'] == 0 || ! isset($configvars->{$id}) || ! isset($configvars->{$id}->value)) { $return['configvars'][$cfgid][$varid] = array('value' => $configvar['defaultvalue']); } else { switch($configvar['datatype']) { case 'bool': case 'int': case 'float': $value = processInputData($configvars->{$id}->value, ARG_NUMERIC); break; default: $value = processInputData($configvars->{$id}->value, ARG_STRING); break; } $return['configvars'][$cfgid][$varid] = array('value' => $value); } if(isset($configvars->{$id})) unset($configvars->{$id}); }*/ /*print "/*"; printArray($rescfgmapids); foreach($configvars as $id => $var) { $cfgid = explode('/', $id); print "cfgid: {$cfgid[1]}\n"; if(! array_key_exists($cfgid[1], $rescfgmapids)) continue; // TODO validate based on var type $value = processInputData($configvars->{$id}->value, ARG_STRING); $return['configvars']["{$cfgid[0]}/{$cfgid[1]}"][$cfgid[2]] = array('value' => $value); } printArray($configvars);*/ #print "*/"; } return $return; }
function addRequest($forimaging = 0, $revisionid = array()) { global $requestInfo, $user; $startstamp = unixToDatetime($requestInfo["start"]); $endstamp = unixToDatetime($requestInfo["end"]); $now = time(); if ($requestInfo["start"] <= $now) { $start = unixToDatetime($now); $nowfuture = "now"; } else { $start = $startstamp; $nowfuture = "future"; } addLogEntry($nowfuture, $start, $endstamp, 1, $requestInfo["imageid"]); $qh = doQuery("SELECT LAST_INSERT_ID() FROM log", 131); if (!($row = mysql_fetch_row($qh))) { abort(132); } $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, " . "userid, " . "laststateid, " . "logid, " . "forimaging, " . "start, " . "end, " . "daterequested) " . "VALUES " . "(13, " . "{$user['id']}, " . "13, " . "{$logid}, " . "{$forimaging}, " . "'{$startstamp}', " . "'{$endstamp}', " . "NOW())"; $qh = doQuery($query, 136); $qh = doQuery("SELECT LAST_INSERT_ID() FROM request", 134); if (!($row = mysql_fetch_row($qh))) { abort(135); } $requestid = $row[0]; # add requestid to log entry $query = "UPDATE log " . "SET requestid = {$requestid} " . "WHERE id = {$logid}"; doQuery($query, 101); # add an entry to the reservation table for each image # NOTE: make sure parent image is the first entry we add # so that it has the lowest reservationid foreach ($requestInfo["images"] as $key => $imageid) { if (array_key_exists($imageid, $revisionid) && !empty($revisionid[$imageid])) { $imagerevisionid = $revisionid[$imageid]; } else { $imagerevisionid = getProductionRevisionid($imageid); } $computerid = $requestInfo["computers"][$key]; $mgmtnodeid = $requestInfo['mgmtnodes'][$key]; $query = "INSERT INTO reservation " . "(requestid, " . "computerid, " . "imageid, " . "imagerevisionid, " . "managementnodeid) " . "VALUES " . "({$requestid}, " . "{$computerid}, " . "{$imageid}, " . "{$imagerevisionid}, " . "{$mgmtnodeid})"; doQuery($query, 133); addSublogEntry($logid, $imageid, $imagerevisionid, $computerid, $mgmtnodeid); } // release semaphore lock semUnlock(); return $requestid; }
function AJremImageConnectMethod() { $imageid = getContinuationVar('imageid'); $methods = getContinuationVar('methods'); $revids = getContinuationVar('revids'); $curmethods = getImageConnectMethods($imageid); $remidlist = mysql_real_escape_string(processInputVar('ids', ARG_STRING)); $remids = explode(',', $remidlist); $revid = processInputVar('revid', ARG_NUMERIC); $newimage = getContinuationVar('newimage'); foreach ($remids as $id) { if (!is_numeric($id)) { $arr = array('error' => 'invalidinput', 'msg' => i("Non-numeric data was submitted for a connection method id.")); sendJSON($arr); return; } } if ($revid != 0 && !in_array($revid, $revids)) { $arr = array('error' => 'invalidrevision', 'msg' => i("Invalid revision id submitted.")); sendJSON($arr); return; } if (!$newimage) { if ($revid == 0) { $revid = getProductionRevisionid($imageid); } # delete any current entries for method and image $query = "DELETE FROM connectmethodmap " . "WHERE imagerevisionid = {$revid} AND " . "connectmethodid IN ({$remidlist}) AND " . "autoprovisioned IS NULL"; doQuery($query, 101); # query to see if enabled for OStype or OS $insvals = array(); foreach ($remids as $id) { $query = "SELECT cm.connectmethodid " . "FROM connectmethodmap cm, " . "image i " . "LEFT JOIN OS o ON (o.id = i.OSid) " . "LEFT JOIN OStype ot ON (ot.name = o.type) " . "WHERE i.id = {$imageid} AND " . "cm.autoprovisioned IS NULL AND " . "cm.connectmethodid = {$id} AND " . "cm.disabled = 0 AND " . "(cm.OStypeid = ot.id OR " . "cm.OSid = o.id)"; $qh = doQuery($query, 101); if (mysql_num_rows($qh)) { # if so, add disabled entry for image revision and method $insvals[] = "({$id}, {$revid}, 1)"; } } if (count($insvals)) { $allinsvals = implode(',', $insvals); $query = "INSERT INTO connectmethodmap " . "(connectmethodid, " . "imagerevisionid, " . "disabled) " . "VALUES {$allinsvals}"; doQuery($query, 101); } } $cdata = $this->basecdata; $cdata['imageid'] = $imageid; $cdata['methods'] = $methods; $cdata['revids'] = $revids; $cdata['newimage'] = $newimage; $addcont = addContinuationsEntry('AJaddImageConnectMethod', $cdata, 3600, 1, 0); $remcont = addContinuationsEntry('AJremImageConnectMethod', $cdata, 3600, 1, 0); $arr = array('addcont' => $addcont, 'remcont' => $remcont); sendJSON($arr); $key = getKey(array('getImageConnectMethods', (int) $imageid, (int) $revid)); if (array_key_exists($key, $_SESSION['usersessiondata'])) { unset($_SESSION['usersessiondata'][$key]); } $key = getKey(array('getImageConnectMethods', (int) $imageid, 0)); if (array_key_exists($key, $_SESSION['usersessiondata'])) { unset($_SESSION['usersessiondata'][$key]); } }
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; }
function AJvmFromHostDelayed() { $data = getContinuationVar(); $vclreloadid = getUserlistID('vclreload@Local'); $imageid = getImageId('noimage'); $imagerevisionid = getProductionRevisionid($imageid); $fails = array(); foreach ($data as $comp) { $end = datetimeToUnix($comp['end2']) + SECINMONTH; $end = unixToDatetime($end); if (!simpleAddRequest($comp['id'], $imageid, $imagerevisionid, $comp['end2'], $end, 18, $vclreloadid)) { $fails[] = array('name' => $comp['hostname'], 'reason' => 'nomgtnode'); } } $cont = addContinuationsEntry('vmhostdata'); $arr = array('msg' => 'SUCCESS', 'cont' => $cont, 'fails' => $fails); sendJSON($arr); }
function XMLRPCprocessBlockTime($blockTimesid, $ignoreprivileges = 0) { global $requestInfo, $user, $xmlrpcBlockAPIUsers; if (!in_array($user['id'], $xmlrpcBlockAPIUsers)) { return array('status' => 'error', 'errorcode' => 34, 'errormsg' => 'access denied for managing block allocations'); } $return = array('status' => 'success'); $query = "SELECT bt.start, " . "bt.end, " . "br.imageid, " . "br.numMachines, " . "br.groupid, " . "br.expireTime " . "FROM blockRequest br, " . "blockTimes bt " . "WHERE bt.blockRequestid = br.id AND " . "bt.id = {$blockTimesid}"; $qh = doQuery($query, 101); if (!($rqdata = mysql_fetch_assoc($qh))) { return array('status' => 'error', 'errorcode' => 8, 'errormsg' => 'unknown blockTimesid'); } if (datetimeToUnix($rqdata['expireTime']) < time()) { return array('status' => 'error', 'errorcode' => 9, 'errormsg' => 'expired block reservation'); } $images = getImages(0, $rqdata['imageid']); if (empty($images)) { return array('status' => 'error', 'errorcode' => 10, 'errormsg' => 'invalid image associated with block request'); } # check to see if all computers have been allocated $query = "SELECT COUNT(computerid) AS allocated " . "FROM blockComputers " . "WHERE blockTimeid = {$blockTimesid}"; $qh = doQuery($query, 101); if (!($row = mysql_fetch_assoc($qh))) { return array('status' => 'error', 'errorcode' => 15, 'errormsg' => 'failure to communicate with database'); } $compCompleted = $row['allocated']; $compsPerRequest = 1 + count($images[$rqdata['imageid']]['subimages']); $toallocate = $rqdata['numMachines'] * $compsPerRequest - $compCompleted; if ($toallocate == 0) { return array('status' => 'completed'); } $reqToAlloc = $toallocate / $compsPerRequest; if (!$ignoreprivileges) { # get userids in user group $tmp = getUserGroupMembers($rqdata['groupid']); if (empty($tmp)) { return array('status' => 'error', 'errorcode' => 11, 'errormsg' => 'empty user group and ignoreprivileges set to 0'); } $userids = array_keys($tmp); # make length of $userids match $reqToAlloc by duplicating or trimming some users while ($reqToAlloc > count($userids)) { $userids = array_merge($userids, $userids); } if ($reqToAlloc < count($userids)) { $userids = array_splice($userids, 0, $reqToAlloc); } } # staggering: stagger start times for this round (ie, don't worry about # previous processing of this block time) such that there is 1 minute # between the start times for each request $stagExtra = $reqToAlloc * 60; # determine estimated load time $imgLoadTime = getImageLoadEstimate($rqdata['imageid']); if ($imgLoadTime == 0) { $imgLoadTime = $images[$rqdata['imageid']]['reloadtime'] * 60; } $loadtime = $imgLoadTime + 10 * 60; # add 10 minute fudge factor $unixstart = datetimeToUnix($rqdata['start']); if (time() + $loadtime + $stagExtra > $unixstart) { $return['status'] = 'warning'; $return['warningcode'] = 13; $return['warningmsg'] = 'possibly insufficient time to load machines'; } $start = unixToDatetime($unixstart - $loadtime); $unixend = datetimeToUnix($rqdata['end']); $userid = 0; $allocated = 0; $vclreloadid = getUserlistID('vclreload@Local'); $revisionid = getProductionRevisionid($rqdata['imageid']); $blockCompVals = array(); # FIXME (maybe) - if some subset of users in the user group have available # computers, but others do not, $allocated will be less than the desired # number of machines; however, calling this function enough times will # result in enough machines being allocated because they will continue to be # allocated based on the ones with machines available; this seems like odd # behavior $stagCnt = 0; for ($i = 0; $i < $reqToAlloc; $i++) { $stagunixstart = $unixstart - $loadtime - $stagCnt * 60; $stagstart = unixToDatetime($stagunixstart); if (!$ignoreprivileges) { $userid = array_pop($userids); } # use end of block time to find available computers, but... $rc = isAvailable($images, $rqdata['imageid'], $stagunixstart, $unixend, 0, 0, $userid, $ignoreprivileges); if ($rc < 1) { continue; } $compid = $requestInfo['computers'][0]; # ...use start of block time as end of reload reservation $reqid = simpleAddRequest($compid, $rqdata['imageid'], $revisionid, $stagstart, $rqdata['start'], 19, $vclreloadid); if ($reqid == 0) { continue; } $stagCnt++; $allocated++; $blockCompVals[] = "({$blockTimesid}, {$compid}, {$rqdata['imageid']})"; # process any subimages for ($key = 1; $key < count($requestInfo['computers']); $key++) { $subimageid = $requestInfo['images'][$key]; $subrevid = getProductionRevisionid($subimageid); $compid = $requestInfo['computers'][$key]; $mgmtnodeid = $requestInfo['mgmtnodes'][$key]; $blockCompVals[] = "({$blockTimesid}, {$compid}, {$subimageid})"; $query = "INSERT INTO reservation " . "(requestid, " . "computerid, " . "imageid, " . "imagerevisionid, " . "managementnodeid) " . "VALUES " . "({$reqid}, " . "{$compid}, " . "{$subimageid}, " . "{$subrevid}, " . "{$mgmtnodeid})"; doQuery($query, 101); } semUnlock(); $blockComps = implode(',', $blockCompVals); $query = "INSERT INTO blockComputers " . "(blockTimeid, computerid, imageid) " . "VALUES {$blockComps}"; doQuery($query, 101); $blockCompVals = array(); } if ($allocated == 0) { $return['status'] = 'warning'; $return['warningcode'] = 14; $return['warningmsg'] = 'unable to allocate any machines'; } $return['allocated'] = $compCompleted / $compsPerRequest + $allocated; $return['unallocated'] = $rqdata['numMachines'] - $return['allocated']; return $return; }
function submitCompStateChange() { global $user; print "<H2>Change State of Computers</H2>\n"; $data = getContinuationVar(); $computers = getComputers(1); # switching to available if ($data['stateid'] == 2) { $compids = implode(',', $data['computerids']); $query = "UPDATE computer " . "SET stateid = 2, " . "notes = '' " . "WHERE id IN ({$compids})"; doQuery($query, 101); print "The following computers were changed to the available state:\n"; print "<TABLE>\n"; foreach ($data['computerids'] as $compid) { print " <TR>\n"; print " <TD>{$computers[$compid]['hostname']}</TD>\n"; print " </TR>\n"; } print "</TABLE>\n"; } elseif ($data['stateid'] == 10) { $data['notes'] = processInputVar('notes', ARG_STRING); if (get_magic_quotes_gpc()) { $data['notes'] = stripslashes($data['notes']); } $data['notes'] = mysql_escape_string($data['notes']); $data["notes"] = $user["unityid"] . " " . unixToDatetime(time()) . "@" . $data["notes"]; $vclreloadid = getUserlistID('vclreload@Local'); // get semaphore lock if (!semLock()) { abort(3); } $noaction = array(); $changenow = array(); $changeasap = array(); $changetimes = array(); foreach ($data['computerids'] as $compid) { if ($computers[$compid]['state'] == 'maintenance') { array_push($noaction, $compid); } else { array_push($changeasap, $compid); } } $passes = array(); $fails = array(); foreach ($changeasap as $compid) { # TODO what about blockComputers? # try to move future reservations off of computer moveReservationsOffComputer($compid); # get end time of last reservation $query = "SELECT rq.end " . "FROM request rq, " . "reservation rs " . "WHERE rs.requestid = rq.id AND " . "rs.computerid = {$compid} AND " . "rq.stateid NOT IN (1,5,12) " . "ORDER BY end DESC " . "LIMIT 1"; $qh = doQuery($query, 101); # create a really long reservation starting at that time in state tomaintenance if ($row = mysql_fetch_assoc($qh)) { $start = $row['end']; $changetimes[$compid] = $start; $end = datetimeToUnix($start) + SECINWEEK; // hopefully keep future reservations off of it $end = unixToDatetime($end); if (simpleAddRequest($compid, 4, 3, $start, $end, 18, $vclreloadid)) { $passes[] = $compid; } else { $fails[] = $compid; } } else { $query = "UPDATE computer " . "SET stateid = 10, " . "notes = '{$data['notes']}' " . "WHERE id = {$compid}"; doQuery($query, 101); unset_by_val($compid, $changeasap); array_push($changenow, $compid); } } // release semaphore lock semUnlock(); if (count($noaction) || count($changeasap)) { $comparr = array_merge($noaction, $changeasap); $compids = implode(',', $comparr); $query = "UPDATE computer " . "SET notes = '{$data['notes']}' " . "WHERE id IN ({$compids})"; doQuery($query, 101); } if (count($changenow)) { print "The following computers were immediately placed into the "; print "maintenance state:\n"; print "<TABLE>\n"; foreach ($changenow as $compid) { print " <TR>\n"; print " <TD><font color=\"#008000\">{$computers[$compid]['hostname']}</font></TD>\n"; print " </TR>\n"; } print "</TABLE>\n"; print "<br>\n"; } if (count($passes)) { print "The following computers currently have reservations on them "; print "and will be placed in the maintenance state at the time listed "; print "for each computer:\n"; print "<TABLE>\n"; print " <TR>\n"; print " <TH>Computer</TH>\n"; print " <TH>Maintenance time</TH>\n"; print " </TR>\n"; foreach ($passes as $compid) { print " <TR>\n"; print " <TD align=center><font color=\"ff8c00\">{$computers[$compid]['hostname']}</font></TD>\n"; $time = date('n/j/y g:i a', datetimeToUnix($changetimes[$compid])); print " <TD align=center>{$time}</TD>\n"; print " </TR>\n"; } print "</TABLE>\n"; print "<br>\n"; } if (count($fails)) { print "The following computers currently have reservations on them "; print "but no functional management node was found for them. Nothing "; print "be done with them at this time:\n"; print "<TABLE>\n"; print " <TR>\n"; print " <TH>Computer</TH>\n"; print " </TR>\n"; foreach ($passes as $compid) { print " <TR>\n"; print " <TD align=center><font color=\"ff0000\">{$computers[$compid]['hostname']}</font></TD>\n"; print " </TR>\n"; } print "</TABLE>\n"; print "<br>\n"; } if (count($noaction)) { print "The following computers were already in the maintenance "; print "state and had their notes on being in the maintenance state "; print "updated:\n"; print "<TABLE>\n"; foreach ($noaction as $compid) { print " <TR>\n"; print " <TD>{$computers[$compid]['hostname']}</TD>\n"; print " </TR>\n"; } print "</TABLE>\n"; print "<br>\n"; } } elseif ($data['stateid'] == 20) { $profileid = processInputVar('profileid', ARG_NUMERIC); if (!array_key_exists($profileid, $data['profiles'])) { $keys = array_keys($data['profiles']); $profileid = $keys[0]; } $noaction = array(); $changenow = array(); $changeasap = array(); $changetimes = array(); foreach ($data['computerids'] as $compid) { if ($computers[$compid]['state'] == 'vmhostinuse') { array_push($noaction, $compid); } else { array_push($changeasap, $compid); } } if (!semLock()) { abort(3); } foreach ($changeasap as $compid) { # TODO what about blockComputers? moveReservationsOffComputer($compid); # get end time of last reservation $query = "SELECT rq.end " . "FROM request rq, " . "reservation rs " . "WHERE rs.requestid = rq.id AND " . "rs.computerid = {$compid} AND " . "rq.stateid NOT IN (1,5,12) " . "ORDER BY end DESC " . "LIMIT 1"; $qh = doQuery($query, 101); if ($row = mysql_fetch_assoc($qh)) { // if there is a reservation, leave in $changeasap so we can # notify that we can't change this one } else { # create a reload reservation to load machine with image # corresponding to selected vm profile $start = getReloadStartTime(); $end = $start + SECINYEAR; # don't want anyone making a future reservation for this machine $start = unixToDatetime($start); $end = unixToDatetime($end); $imagerevisionid = getProductionRevisionid($data['profiles'][$profileid]['imageid']); $vclreloadid = getUserlistID('vclreload@Local'); simpleAddRequest($compid, $data['profiles'][$profileid]['imageid'], $imagerevisionid, $start, $end, 21, $vclreloadid); unset_by_val($compid, $changeasap); array_push($changenow, $compid); # check for existing vmhost entry $query = "SELECT id, " . "vmprofileid " . "FROM vmhost " . "WHERE computerid = {$compid}"; $qh = doQuery($query, 101); if ($row = mysql_fetch_assoc($qh)) { if ($row['vmprofileid'] != $profileid) { # update vmprofile $query = "UPDATE vmhost " . "SET vmprofileid = {$profileid} " . "WHERE id = {$row['id']}"; doQuery($query, 101); } } else { # create vmhost entry $query = "INSERT INTO vmhost " . "(computerid, " . "vmlimit, " . "vmprofileid) " . "VALUES ({$compid}, " . "2, " . "{$profileid})"; doQuery($query, 101); } } } // release semaphore lock semUnlock(); if (count($changenow)) { print "The following computers were placed into the "; print "vmhostinuse state:\n"; print "<TABLE>\n"; foreach ($changenow as $compid) { print " <TR>\n"; print " <TD><font color=\"#008000\">{$computers[$compid]['hostname']}</font></TD>\n"; print " </TR>\n"; } print "</TABLE>\n"; print "<br>\n"; } if (count($changeasap)) { print "The following computers currently have reservations on them "; print "and cannot be placed in the vmhostinuse state at this time:\n"; print "<TABLE>\n"; foreach ($changeasap as $compid) { print " <TR>\n"; print " <TD><font color=\"ff0000\">{$computers[$compid]['hostname']}</font></TD>\n"; print " </TR>\n"; } print "</TABLE>\n"; print "<br>\n"; } if (count($noaction)) { print "The following computers were already in the vmhostinuse "; print "state:\n"; print "<TABLE>\n"; foreach ($noaction as $compid) { print " <TR>\n"; print " <TD>{$computers[$compid]['hostname']}</TD>\n"; print " </TR>\n"; } print "</TABLE>\n"; print "<br>\n"; } } elseif ($data['stateid'] == 23) { $noaction = array(); $changenow = array(); $changeasap = array(); $changetimes = array(); foreach ($data['computerids'] as $compid) { if ($computers[$compid]['state'] == 'hpc') { array_push($noaction, $compid); } else { array_push($changeasap, $compid); } } if (!semLock()) { abort(3); } foreach ($changeasap as $compid) { # TODO what about blockComputers? moveReservationsOffComputer($compid); # get end time of last reservation $query = "SELECT rq.end " . "FROM request rq, " . "reservation rs " . "WHERE rs.requestid = rq.id AND " . "rs.computerid = {$compid} AND " . "rq.stateid NOT IN (1,5,12) " . "ORDER BY end DESC " . "LIMIT 1"; $qh = doQuery($query, 101); if ($row = mysql_fetch_assoc($qh)) { // if there is a reservation, leave in $changeasap so we can # notify that we can't change this one } else { $query = "UPDATE computer " . "SET stateid = 23 " . "WHERE id = {$compid}"; doQuery($query, 101); unset_by_val($compid, $changeasap); array_push($changenow, $compid); } } // release semaphore lock semUnlock(); if (count($changenow)) { print "The following computers were placed into the "; print "hpc state:\n"; print "<TABLE>\n"; foreach ($changenow as $compid) { print " <TR>\n"; print " <TD><font color=\"#008000\">{$computers[$compid]['hostname']}</font></TD>\n"; print " </TR>\n"; } print "</TABLE>\n"; print "<br>\n"; } if (count($changeasap)) { print "The following computers currently have reservations on them "; print "and cannot be placed in the hpc state at this time:\n"; print "<TABLE>\n"; foreach ($changeasap as $compid) { print " <TR>\n"; print " <TD><font color=\"ff0000\">{$computers[$compid]['hostname']}</font></TD>\n"; print " </TR>\n"; } print "</TABLE>\n"; print "<br>\n"; } if (count($noaction)) { print "The following computers were already in the hpc "; print "state:\n"; print "<TABLE>\n"; foreach ($noaction as $compid) { print " <TR>\n"; print " <TD>{$computers[$compid]['hostname']}</TD>\n"; print " </TR>\n"; } print "</TABLE>\n"; print "<br>\n"; } } else { abort(50); } }
function XMLRPCprocessBlockTime($blockTimesid, $ignoreprivileges = 0) { global $requestInfo, $user, $xmlrpcBlockAPIUsers; if (!in_array($user['id'], $xmlrpcBlockAPIUsers)) { return array('status' => 'error', 'errorcode' => 34, 'errormsg' => 'access denied for managing block allocations'); } # validate $blockTimesid if (!is_numeric($blockTimesid)) { return array('status' => 'error', 'errorcode' => 77, 'errormsg' => 'Invalid blockTimesid specified'); } # validate ignoreprivileges if (!is_numeric($ignoreprivileges) || $ignoreprivileges < 0 || $ignoreprivileges > 1) { return array('status' => 'error', 'errorcode' => 86, 'errormsg' => 'ignoreprivileges must be 0 or 1'); } $return = array('status' => 'success'); $query = "SELECT bt.start, " . "bt.end, " . "br.imageid, " . "br.numMachines, " . "br.groupid, " . "br.expireTime " . "FROM blockRequest br, " . "blockTimes bt " . "WHERE bt.blockRequestid = br.id AND " . "bt.id = {$blockTimesid}"; $qh = doQuery($query, 101); if (!($rqdata = mysql_fetch_assoc($qh))) { return array('status' => 'error', 'errorcode' => 8, 'errormsg' => 'unknown blockTimesid'); } if (datetimeToUnix($rqdata['expireTime']) < time()) { return array('status' => 'error', 'errorcode' => 9, 'errormsg' => 'expired block allocation'); } $images = getImages(0, $rqdata['imageid']); if (empty($images)) { return array('status' => 'error', 'errorcode' => 10, 'errormsg' => 'invalid image associated with block allocation'); } $unixstart = datetimeToUnix($rqdata['start']); $unixend = datetimeToUnix($rqdata['end']); $revisionid = getProductionRevisionid($rqdata['imageid']); $imgLoadTime = getImageLoadEstimate($rqdata['imageid']); if ($imgLoadTime == 0) { $imgLoadTime = $images[$rqdata['imageid']]['reloadtime'] * 60; } $vclreloadid = getUserlistID('vclreload@Local'); $groupmembers = getUserGroupMembers($rqdata['groupid']); $userids = array_keys($groupmembers); # add any computers from future reservations users in the group made if (!empty($groupmembers)) { ## find reservations by users $allids = implode(',', $userids); $query = "SELECT rq.id AS reqid, " . "UNIX_TIMESTAMP(rq.start) AS start, " . "rq.userid " . "FROM request rq, " . "reservation rs " . "WHERE rs.requestid = rq.id AND " . "rq.userid IN ({$allids}) AND " . "rq.start < '{$rqdata['end']}' AND " . "rq.end > '{$rqdata['start']}' AND " . "rs.imageid = {$rqdata['imageid']} AND " . "rs.computerid NOT IN (SELECT computerid " . "FROM blockComputers " . "WHERE blockTimeid = {$blockTimesid})"; $qh = doQuery($query); $donereqids = array(); $blockCompVals = array(); $checkstartbase = $unixstart - $imgLoadTime - 300; $reloadstartbase = unixToDatetime($checkstartbase); $rows = mysql_num_rows($qh); while ($row = mysql_fetch_assoc($qh)) { if (array_key_exists($row['reqid'], $donereqids)) { continue; } $donereqids[$row['reqid']] = 1; if ($row['start'] < datetimeToUnix($rqdata['start'])) { $checkstart = $row['start'] - $imgLoadTime - 300; $reloadstart = unixToDatetime($checkstart); $reloadend = unixToDatetime($row['start']); } else { $checkstart = $checkstartbase; $reloadstart = $reloadstartbase; $reloadend = $rqdata['start']; } # check to see if computer is available for whole block $rc = isAvailable($images, $rqdata['imageid'], $revisionid, $checkstart, $unixend, 1, $row['reqid'], $row['userid'], $ignoreprivileges, 0, '', '', 1); // if not available for whole block, just skip this one if ($rc < 1) { continue; } $compid = $requestInfo['computers'][0]; # create reload reservation $reqid = simpleAddRequest($compid, $rqdata['imageid'], $revisionid, $reloadstart, $reloadend, 19, $vclreloadid); if ($reqid == 0) { continue; } # add to blockComputers $blockCompVals[] = "({$blockTimesid}, {$compid}, {$rqdata['imageid']}, {$reqid})"; # process any subimages for ($key = 1; $key < count($requestInfo['computers']); $key++) { $subimageid = $requestInfo['images'][$key]; $subrevid = getProductionRevisionid($subimageid); $compid = $requestInfo['computers'][$key]; $mgmtnodeid = $requestInfo['mgmtnodes'][$key]; $blockCompVals[] = "({$blockTimesid}, {$compid}, {$subimageid}, {$reqid})"; $query = "INSERT INTO reservation " . "(requestid, " . "computerid, " . "imageid, " . "imagerevisionid, " . "managementnodeid) " . "VALUES " . "({$reqid}, " . "{$compid}, " . "{$subimageid}, " . "{$subrevid}, " . "{$mgmtnodeid})"; doQuery($query, 101); } } if (count($blockCompVals)) { $blockComps = implode(',', $blockCompVals); $query = "INSERT INTO blockComputers " . "(blockTimeid, computerid, imageid, reloadrequestid) " . "VALUES {$blockComps}"; doQuery($query); } cleanSemaphore(); } # check to see if all computers have been allocated $query = "SELECT COUNT(computerid) AS allocated " . "FROM blockComputers " . "WHERE blockTimeid = {$blockTimesid}"; $qh = doQuery($query, 101); if (!($row = mysql_fetch_assoc($qh))) { return array('status' => 'error', 'errorcode' => 15, 'errormsg' => 'failure to communicate with database'); } $compCompleted = $row['allocated']; if (array_key_exists('subimages', $images[$rqdata['imageid']])) { $compsPerAlloc = 1 + count($images[$rqdata['imageid']]['subimages']); } else { $compsPerAlloc = 1; } $toallocate = $rqdata['numMachines'] * $compsPerAlloc - $compCompleted; if ($toallocate == 0) { if (count($blockCompVals)) { return array('status' => 'success', 'allocated' => $rqdata['numMachines'], 'unallocated' => 0); } return array('status' => 'completed'); } $reqToAlloc = $toallocate / $compsPerAlloc; if (!$ignoreprivileges) { # get userids in user group if (empty($groupmembers)) { return array('status' => 'error', 'errorcode' => 11, 'errormsg' => 'empty user group and ignoreprivileges set to 0'); } # make length of $userids match $reqToAlloc by duplicating or trimming some users while ($reqToAlloc > count($userids)) { $userids = array_merge($userids, $userids); } if ($reqToAlloc < count($userids)) { $userids = array_splice($userids, 0, $reqToAlloc); } } # staggering: stagger start times for this round (ie, do not worry about # previous processing of this block time) such that there is 1 minute # between the start times for each allocation $stagExtra = $reqToAlloc * 60; # determine estimated load time $loadtime = $imgLoadTime + 10 * 60; # add 10 minute fudge factor if (time() + $loadtime + $stagExtra > $unixstart) { $return['status'] = 'warning'; $return['warningcode'] = 13; $return['warningmsg'] = 'possibly insufficient time to load machines'; } $start = unixToDatetime($unixstart - $loadtime); $userid = 0; $allocated = 0; $blockCompVals = array(); # FIXME (maybe) - if some subset of users in the user group have available # computers, but others do not, $allocated will be less than the desired # number of machines; however, calling this function enough times will # result in enough machines being allocated because they will continue to be # allocated based on the ones with machines available; this seems like odd # behavior $stagCnt = 0; $stagTime = 60; # stagger reload reservations by 1 min if ($imgLoadTime > 840) { // if estimated load time is > 14 min $stagTime = 120; } # stagger reload reservations by 2 min for ($i = 0; $i < $reqToAlloc; $i++) { $stagunixstart = $unixstart - $loadtime - $stagCnt * $stagTime; $stagstart = unixToDatetime($stagunixstart); if (!$ignoreprivileges) { $userid = array_pop($userids); } # use end of block time to find available computers, but... $rc = isAvailable($images, $rqdata['imageid'], $revisionid, $stagunixstart, $unixend, 1, 0, $userid, $ignoreprivileges); if ($rc < 1) { continue; } $compid = $requestInfo['computers'][0]; # ...use start of block time as end of reload reservation $reqid = simpleAddRequest($compid, $rqdata['imageid'], $revisionid, $stagstart, $rqdata['start'], 19, $vclreloadid); if ($reqid == 0) { continue; } $stagCnt++; $allocated++; $blockCompVals[] = "({$blockTimesid}, {$compid}, {$rqdata['imageid']}, {$reqid})"; # process any subimages for ($key = 1; $key < count($requestInfo['computers']); $key++) { $subimageid = $requestInfo['images'][$key]; $subrevid = getProductionRevisionid($subimageid); $compid = $requestInfo['computers'][$key]; $mgmtnodeid = $requestInfo['mgmtnodes'][$key]; $blockCompVals[] = "({$blockTimesid}, {$compid}, {$subimageid}, {$reqid})"; $query = "INSERT INTO reservation " . "(requestid, " . "computerid, " . "imageid, " . "imagerevisionid, " . "managementnodeid) " . "VALUES " . "({$reqid}, " . "{$compid}, " . "{$subimageid}, " . "{$subrevid}, " . "{$mgmtnodeid})"; doQuery($query, 101); } $blockComps = implode(',', $blockCompVals); $query = "INSERT INTO blockComputers " . "(blockTimeid, computerid, imageid, reloadrequestid) " . "VALUES {$blockComps}"; doQuery($query, 101); cleanSemaphore(); $blockCompVals = array(); } if ($allocated == 0) { $return['status'] = 'warning'; $return['warningcode'] = 14; $return['warningmsg'] = 'unable to allocate any machines'; } $return['allocated'] = $compCompleted / $compsPerAlloc + $allocated; $return['unallocated'] = $rqdata['numMachines'] - $return['allocated']; return $return; }