function moveReservationsOffComputer($compid = 0, $count = 0) { global $requestInfo, $user; $resInfo = array(); $checkstart = unixToDatetime(time() + 180); if ($compid == 0) { $resources = getUserResources(array("imageAdmin", "imageCheckOut"), array("available"), 0, 0); $computers = implode("','", array_keys($resources["computer"])); $computers = "'{$computers}'"; $query = "SELECT DISTINCT COUNT(rs.id) AS reservations, " . "rs.computerid " . "FROM reservation rs, " . "request rq " . "WHERE rq.start > '{$checkstart}' AND " . "rs.computerid IN ({$computers}) " . "GROUP BY computerid " . "ORDER BY reservations " . "LIMIT 1"; $qh = doQuery($query, 101); if ($row = mysql_fetch_assoc($qh)) { $compid = $row["computerid"]; } else { return -1; } } # get all reservation info for $compid $query = "SELECT rs.id, " . "rs.requestid, " . "rs.imageid, " . "rq.logid, " . "rq.userid, " . "rq.start, " . "rq.end " . "FROM reservation rs, " . "request rq " . "WHERE rs.computerid = {$compid} AND " . "rs.requestid = rq.id AND " . "rq.start > '{$checkstart}' AND " . "rq.stateid NOT IN (1, 5, 11, 12) " . "ORDER BY rq.start"; if ($count) { $query .= " LIMIT {$count}"; } $qh = doQuery($query, 101); while ($row = mysql_fetch_assoc($qh)) { $resInfo[$row["id"]] = $row; } if (!count($resInfo)) { return -1; } $images = getImages(); $allmovable = 1; foreach ($resInfo as $res) { $rc = isAvailable($images, $res["imageid"], datetimeToUnix($res["start"]), datetimeToUnix($res["end"]), "dummy", 0, $res["userid"]); if ($rc < 1) { $allmovable = 0; break; } } if (!$allmovable) { return 0; } foreach ($resInfo as $res) { $rc = isAvailable($images, $res["imageid"], datetimeToUnix($res["start"]), datetimeToUnix($res["end"]), "dummy", 0, $res["userid"]); if ($rc > 0) { $newcompid = array_shift($requestInfo["computers"]); # get mgmt node for computer $mgmtnodeid = findManagementNode($newcompid, $res['start'], 'future'); # update mgmt node and computer in reservation table $query = "UPDATE reservation " . "SET computerid = {$newcompid}, " . "managementnodeid = {$mgmtnodeid} " . "WHERE id = {$res["id"]}"; doQuery($query, 101); # add changelog entry addChangeLogEntry($res['logid'], NULL, NULL, NULL, $newcompid); # update sublog entry $query = "UPDATE sublog " . "SET computerid = {$newcompid} " . "WHERE logid = {$res['logid']} AND " . "computerid = {$compid}"; doQuery($query, 101); } else { return 0; } } return 1; }
function AJsubmitReloadComputers() { $data = getContinuationVar(); # imageid, compids, imagename $start = getReloadStartTime(); $end = $start + 1200; // + 20 minutes $startstamp = unixToDatetime($start); $endstamp = unixToDatetime($end); $imagerevisionid = getProductionRevisionid($data['imageid']); $computers = $this->getData($this->defaultGetDataArgs); $reloadnow = array(); $reloadasap = array(); $fails = array(); $passes = array(); foreach ($data['compids'] as $compid) { if ($computers[$compid]['state'] == 'available' || $computers[$compid]['state'] == 'failed') { $mn = findManagementNode($compid, unixToDatetime($start), 1); if ($mn == 0) { $fails[] = $compid; continue; } if (getSemaphore($data['imageid'], $imagerevisionid, $mn, $compid, $startstamp, $endstamp)) { $query = "SELECT rq.id " . "FROM request rq, " . "reservation rs, " . "state s " . "WHERE rs.requestid = rq.id AND " . "rq.stateid = s.id AND " . "rs.computerid = {$compid} AND " . "rq.start < '{$endstamp}' AND " . "rq.end > '{$startstamp}' AND " . "s.name NOT IN ('complete', 'deleted', 'failed', 'timeout')"; $qh = doQuery($query); if (!mysql_num_rows($qh)) { $reloadnow[] = $compid; } else { $reloadasap[] = $compid; } } else { $reloadasap[] = $compid; } } } $vclreloadid = getUserlistID('vclreload@Local'); foreach ($reloadnow as $compid) { if (simpleAddRequest($compid, $data['imageid'], $imagerevisionid, $startstamp, $endstamp, 19, $vclreloadid)) { $passes[] = $compid; } else { $fails[] = $compid; } } // release semaphore lock on nodes cleanSemaphore(); if (count($reloadasap)) { $compids = implode(',', $reloadasap); $query = "UPDATE computer " . "SET nextimageid = {$data['imageid']} " . "WHERE id IN ({$compids})"; doQuery($query, 101); } $msg = ''; if (count($passes)) { $msg .= "The following computers are being immediately reloaded with "; $msg .= "<strong>{$data['imagename']}</strong>:<br>\n"; foreach ($passes as $compid) { $msg .= "<span class=\"ready\">{$computers[$compid]['hostname']}</span><br>\n"; } } if (count($reloadasap)) { if (count($passes)) { $msg .= "<br>"; } $msg .= "The following computers have <strong>{$data['imagename']}</strong> "; $msg .= "set as a priority for reloading at the end of their existing "; $msg .= "reservations:<br>\n"; foreach ($reloadasap as $compid) { $msg .= "<span class=\"wait\">{$computers[$compid]['hostname']}</span><br>\n"; } } if (count($fails)) { if (count($passes) || count($reloadasap)) { $msg .= "<br>"; } $msg .= "No functional management node was found for the following "; $msg .= "computers. They could not be reloaded at this time:<br>\n"; foreach ($fails as $compid) { $msg .= "<span class=\"rederrormsg\">{$computers[$compid]['hostname']}</span><br>\n"; } } $ret = array('status' => 'success', 'title' => "Reload Computers", 'refreshcount' => 4, 'msg' => $msg); sendJSON($ret); }
function findAvailableTimes($start, $end, $imageid, $userid, $usedaysahead, $reqid = '', $extendonly = 0, $ip = '', $mac = '') { global $user; if ($userid == $user['id']) { $ingroups = implode(',', array_keys($user['groups'])); } else { $userdata = getUserInfo($userid, 0, 1); $ingroups = implode(',', array_keys($userdata['groups'])); } # TODO make this work for cluster images if (!$extendonly) { $mappedcomputers = getMappedResources($imageid, 'image', 'computer'); $resources = getUserResources(array('imageAdmin', 'imageCheckOut'), array('available'), 0, 0, $userid); $compids = array_intersect($mappedcomputers, array_keys($resources['computer'])); if (!count($compids)) { return array(); } $incompids = implode(',', $compids); } else { $request = getRequestInfo($reqid); $incompids = $request['reservations'][0]['computerid']; } $scheduleids = getAvailableSchedules($start, $end); if (empty($scheduleids)) { return array(); } $schedules = implode(',', $scheduleids); $platformid = getImagePlatform($imageid); if (is_null($platformid)) { return array(); } $reqduration = $end - $start; $startdt = unixToDatetime($start); $end += 900; $enddt = unixToDatetime($end); $ignorestates = "'maintenance','vmhostinuse','hpc','failed'"; $nowignorestates = "{$ignorestates},'timeout'"; if (!$extendonly) { $nowignorestates .= ",'reloading','reload','inuse'"; } $slots = array(); $removes = array(); $minstart = $start; $maxend = $start; $newcompids = array(); $daysahead = time() + DAYSAHEAD * SECINDAY; # add computers that are available now with no future reservations # restricting duration; we do this so that they'll be in our arrays to check # for concurrent image use, block allocations, ip/mac overlap, and # maintenance window overlap $query = "SELECT c.id AS compid " . "FROM computer c, " . "image i, " . "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 " . "c.network >= i.minnetwork AND " . "c.id NOT IN (SELECT rs.computerid " . "FROM reservation rs, " . "request rq " . "WHERE rs.requestid = rq.id AND "; if ($reqid != '') { $query .= "rq.id != {$reqid} AND "; } $query .= "DATE_ADD(rq.end, INTERVAL 15 MINUTE) >= '{$startdt}' AND " . "rs.computerid IN ({$incompids})) AND " . "c.id IN ({$incompids}) " . "ORDER BY RAM, " . "(c.procspeed * c.procnumber), " . "network"; $qh = doQuery($query, 101); while ($row = mysql_fetch_assoc($qh)) { $row['duration'] = $reqduration; $row['startts'] = $start; $row['start'] = $startdt; $row['endts'] = $start + $reqduration; $slots[$row['compid']] = array(); $slots[$row['compid']][] = $row; $newcompids[] = $row['compid']; } if (!$extendonly) { # find available timeslots based on spacing between existing reservations $query = "SELECT rs1.computerid AS compid, " . "DATE_ADD(rq1.end, INTERVAL 15 MINUTE) AS start, " . "MIN(UNIX_TIMESTAMP(rq2.start) - UNIX_TIMESTAMP(rq1.end) - 1800) AS duration " . "FROM request rq1, " . "request rq2, " . "reservation rs1, " . "reservation rs2, " . "image i, " . "state s, " . "computer c, " . "provisioningOSinstalltype poi, " . "OSinstalltype oi, " . "OS o " . "WHERE rq1.id = rs1.requestid AND " . "rs2.requestid = rq2.id AND " . "rq1.id != rq2.id AND " . "rq1.start < rq2.start AND " . "DATE_ADD(rq1.end, INTERVAL 15 MINUTE) >= '{$startdt}' AND " . "rs1.computerid = rs2.computerid AND " . "rs1.computerid IN ({$incompids}) AND " . "i.id = {$imageid} AND " . "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 " . "c.network >= i.minnetwork AND " . "c.stateid = s.id AND " . "s.name NOT IN ({$ignorestates}) AND "; if ($reqid != '') { $query .= "rq1.id != {$reqid} AND " . "rq2.id != {$reqid} AND "; } $query .= "(c.type != 'virtualmachine' OR c.vmhostid IS NOT NULL) " . "GROUP BY rq1.id "; $query .= "ORDER BY rs1.computerid, rq1.start, rq1.end"; $qh = doQuery($query, 101); while ($row = mysql_fetch_assoc($qh)) { $row['startts'] = datetimeToUnix($row['start']); if ($row['startts'] % 900) { $row['startts'] = $row['startts'] - $row['startts'] % 900 + 900; $row['start'] = unixToDatetime($row['startts']); $row['duration'] -= 900; } if ($row['duration'] >= 1800) { if ($usedaysahead && $row['startts'] > $daysahead) { continue; } if ($row['duration'] > $reqduration) { $row['duration'] = $reqduration; } $row['endts'] = $row['startts'] + $row['duration']; if (!array_key_exists($row['compid'], $slots)) { $slots[$row['compid']] = array(); } $slots[$row['compid']][] = $row; if ($row['startts'] < $minstart) { $minstart = $row['startts']; } if ($row['endts'] > $maxend) { $maxend = $row['endts']; } $newcompids[] = $row['compid']; } } } # find slots that are available now $query = "SELECT UNIX_TIMESTAMP(MIN(rq.start)) - UNIX_TIMESTAMP('{$startdt}') - 900 AS duration, " . "UNIX_TIMESTAMP(MIN(rq.start)) AS endts, " . "rs.computerid AS compid " . "FROM request rq, " . "reservation rs, " . "image i, " . "state s, " . "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 " . "rs.computerid IN ({$incompids}) AND " . "i.id = {$imageid} AND " . "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.stateid = s.id AND " . "s.name NOT IN ({$nowignorestates}) AND "; if ($reqid != '') { $query .= "rq.id != {$reqid} AND "; } $query .= "(c.type != 'virtualmachine' OR c.vmhostid IS NOT NULL) " . "GROUP BY rs.computerid"; $qh = doQuery($query, 101); while ($row = mysql_fetch_assoc($qh)) { if ($row['endts'] % 900) { $row['endts'] = $row['endts'] - $row['endts'] % 900; $row['duration'] -= 900; } if ($row['duration'] >= 1800) { if ($row['duration'] > $reqduration) { $row['duration'] = $reqduration; } $row['start'] = $startdt; $row['startts'] = $start; if (!array_key_exists($row['compid'], $slots)) { $slots[$row['compid']] = array(); } $slots[$row['compid']][] = $row; if ($row['endts'] > $maxend) { $maxend = $row['endts']; } $newcompids[] = $row['compid']; } } # find slots that are available after all reservations are over $query = "SELECT UNIX_TIMESTAMP(MAX(rq.end)) + 900 AS startts, " . "DATE_ADD(MAX(rq.end), INTERVAL 15 MINUTE) AS start, " . "rs.computerid AS compid " . "FROM request rq, " . "reservation rs, " . "image i, " . "state s, " . "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 " . "rs.computerid IN ({$incompids}) AND " . "i.id = {$imageid} AND " . "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 != '') { $query .= "rq.id != {$reqid} AND "; } $query .= "(c.type != 'virtualmachine' OR c.vmhostid IS NOT NULL) " . "GROUP BY rs.computerid"; if ($extendonly) { $query .= " HAVING start = '{$startdt}'"; } $qh = doQuery($query, 101); while ($row = mysql_fetch_assoc($qh)) { if ($usedaysahead && $row['startts'] > $daysahead) { continue; } if ($row['startts'] % 900) { $row['startts'] = $row['startts'] - $row['startts'] % 900 + 900; $row['start'] = unixToDatetime($row['startts']); } $row['endts'] = $row['startts'] + $reqduration; $row['duration'] = $reqduration; if (!array_key_exists($row['compid'], $slots)) { $slots[$row['compid']] = array(); } $slots[$row['compid']][] = $row; if ($row['endts'] > $maxend) { $maxend = $row['endts']; } $newcompids[] = $row['compid']; } if (empty($newcompids)) { return array(); } # remove block computers $minstartdt = unixToDatetime($minstart); $maxenddt = unixToDatetime($maxend); $newincompids = implode(',', $newcompids); $query = "SELECT bc.computerid AS compid, " . "UNIX_TIMESTAMP(bt.start) AS start, " . "UNIX_TIMESTAMP(bt.end) AS end " . "FROM blockComputers bc, " . "blockTimes bt, " . "blockRequest br " . "WHERE bt.id = bc.blockTimeid AND " . "br.id = bt.blockRequestid AND " . "bt.skip = 0 AND " . "bt.start < '{$maxenddt}' AND " . "bt.end > '{$minstartdt}' AND "; if ($ingroups != '') { $query .= "(br.groupid NOT IN ({$ingroups}) OR " . "br.imageid != {$imageid}) AND "; } $query .= "bc.computerid IN ({$newincompids})"; $qh = doQuery($query); while ($row = mysql_fetch_assoc($qh)) { if (array_key_exists($row['compid'], $slots)) { fATremoveOverlaps($slots, $row['compid'], $row['start'], $row['end'], 0); } } # remove mac/ip overlaps $newcompids = array_keys($slots); $newincompids = implode(',', $newcompids); if (!empty($ip) || !empty($mac)) { $query = "SELECT rs.computerid AS compid, " . "UNIX_TIMESTAMP(rq.start) AS start, " . "UNIX_TIMESTAMP(rq.end) AS end " . "FROM serverrequest s, " . "request rq, " . "reservation rs " . "WHERE s.requestid = rq.id AND " . "rs.requestid = rq.id AND " . "rq.start < '{$maxenddt}' AND " . "rq.end > '{$minstartdt}' AND " . "rs.computerid IN ({$newincompids}) AND "; if ($reqid != '') { $query .= "rq.id != {$reqid} AND "; } if (!empty($ip) && !empty($mac)) { $query .= "(s.fixedIP = '{$ip}' OR s.fixedMAC = '{$mac}')"; } elseif (!empty($ip)) { $query .= "s.fixedIP = '{$ip}'"; } elseif (!empty($mac)) { $query .= "s.fixedIP = '{$mac}'"; } $qh = doQuery($query); while ($row = mysql_fetch_assoc($qh)) { if (array_key_exists($row['compid'], $slots)) { fATremoveOverlaps($slots, $row['compid'], $row['start'], $row['end'], 0); } } } # remove slots overlapping with scheduled maintenance $query = "SELECT UNIX_TIMESTAMP(start) AS start, " . "UNIX_TIMESTAMP(end) AS end, " . "allowreservations " . "FROM sitemaintenance " . "WHERE start < '{$maxenddt}' AND " . "end > '{$minstartdt}'"; $qh = doQuery($query); while ($row = mysql_fetch_assoc($qh)) { foreach (array_keys($slots) as $compid) { fATremoveOverlaps($slots, $compid, $row['start'], $row['end'], $row['allowreservations']); } } $imgdata = getImages(0, $imageid); $options = array(); foreach ($slots as $comp) { foreach ($comp as $data) { $data['duration'] = $data['duration'] - $data['duration'] % 900; if (!$extendonly) { if ($data['duration'] > 3600 && $data['duration'] < 7200) { $data['duration'] = 3600; } elseif ($data['duration'] > 7200 && $data['duration'] < SECINDAY * 2) { $data['duration'] = $data['duration'] - $data['duration'] % 7200; } elseif ($data['duration'] > SECINDAY * 2) { $data['duration'] = $data['duration'] - $data['duration'] % SECINDAY; } } # skip computers that have no controlling management node if (!findManagementNode($data['compid'], $data['start'], 'future')) { continue; } # skip slots that would cause a concurrent use violation if ($imgdata[$imageid]['maxconcurrent'] != NULL && fATconcurrentOverlap($data['startts'], $data['duration'], $imageid, $imgdata[$imageid]['maxconcurrent'], $ignorestates, $extendonly, $reqid)) { continue; } if (array_key_exists($data['startts'], $options)) { if ($data['duration'] > $options[$data['startts']]['duration']) { $options[$data['startts']]['duration'] = $data['duration']; if (checkUserHasPerm('View Debug Information')) { $options[$data['startts']]['compid'] = $data['compid']; } } } else { $options[$data['startts']] = array('start' => $data['start'], 'startts' => $data['startts'], 'duration' => $data['duration']); if (checkUserHasPerm('View Debug Information')) { $options[$data['startts']]['compid'] = $data['compid']; } } } } uasort($options, "sortAvailableTimesByStart"); return $options; }