Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
function isAvailable($images, $imageid, $imagerevisionid, $start, $end, $holdcomps, $requestid = 0, $userid = 0, $ignoreprivileges = 0, $forimaging = 0, $ip = '', $mac = '', $skipconcurrentcheck = 0)
{
    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 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;
        $nowfuture = 'now';
    } else {
        $now = 0;
        $nowfuture = 'future';
    }
    $scheduleids = getAvailableSchedules($start, $end);
    $requestInfo["computers"] = array();
    $requestInfo["computers"][0] = 0;
    $requestInfo["images"][0] = $imageid;
    $requestInfo["imagerevisions"][0] = $imagerevisionid[$imageid][0];
    # 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++;
        }
    }
    $startstamp = unixToDatetime($start);
    $endstamp = unixToDatetime($end + 900);
    if (!empty($mac) || !empty($ip)) {
        # check for overlapping use of mac or ip
        $query = "SELECT rq.id " . "FROM reservation rs, " . "request rq, " . "serverrequest sr " . "WHERE '{$startstamp}' < (rq.end + INTERVAL 900 SECOND) AND " . "'{$endstamp}' > rq.start AND " . "sr.requestid = rq.id AND " . "rs.requestid = rq.id AND " . "(sr.fixedIP = '{$ip}' OR " . "sr.fixedMAC = '{$mac}') AND " . "rq.stateid NOT IN (1,5,11,12) ";
        if ($requestid) {
            $query .= "AND rq.id != {$requestid} ";
        }
        $query .= "LIMIT 1";
        $qh = doQuery($query, 101);
        if (mysql_num_rows($qh)) {
            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);
        }
    }
    if ($requestid) {
        $requestData = getRequestInfo($requestid);
    }
    $vmhostcheckdone = 0;
    $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');
            $query = "SELECT rs.computerid, " . "rq.id AS reqid " . "FROM reservation rs, " . "request rq " . "WHERE '{$startstamp}' < (rq.end + INTERVAL 900 SECOND) AND " . "'{$endstamp}' > rq.start AND " . "rs.requestid = rq.id AND " . "rs.imageid = {$imageid} AND " . "rq.stateid NOT IN (1,5,11,12,16,17) AND " . "rq.userid != {$reloadid}";
            $qh = doQuery($query, 101);
            while ($row = mysql_fetch_assoc($qh)) {
                $compids[] = $row['computerid'];
                if ($row['reqid'] == $requestid) {
                    $decforedit = 1;
                }
            }
            $usagecnt = count($compids);
            $allids = implode("','", $compids);
            $ignoregroups = implode("','", array_keys($usersgroups));
            $query = "SELECT COUNT(bc.imageid) AS currentusage " . "FROM blockComputers bc, " . "blockRequest br, " . "blockTimes bt " . "WHERE bc.blockTimeid = bt.id AND " . "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))) {
                cleanSemaphore();
                return debugIsAvailable(0, 3, $start, $end, $imagerevisionid);
            }
            if ($usagecnt + $row['currentusage'] - $decforedit >= $images[$imageid]['maxconcurrent']) {
                cleanSemaphore();
                return debugIsAvailable(-1, 4, $start, $end, $imagerevisionid);
            }
        }
        $platformid = getImagePlatform($imageid);
        if (is_null($platformid)) {
            cleanSemaphore();
            return debugIsAvailable(0, 5, $start, $end, $imagerevisionid);
        }
        # get computers $imageid maps to
        $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);
        }
        #get computers for available schedules and platforms
        $computerids = array();
        $currentids = array();
        $blockids = array();
        $altRemoveBlockCheck = 0;
        // if we are modifying a request and it is after the start time, only allow
        // the scheduled computer(s) to be modified
        if ($requestid && datetimeToUnix($requestData["start"]) <= time()) {
            $altRemoveBlockCheck = 1;
            foreach ($requestData["reservations"] as $key2 => $res) {
                if ($res["imageid"] == $imageid) {
                    $compid = $res["computerid"];
                    unset($requestData['reservations'][$key2]);
                    break;
                }
            }
            array_push($computerids, $compid);
            array_push($currentids, $compid);
            $query = "SELECT scheduleid " . "FROM computer " . "WHERE id = {$compid}";
            $qh = doQuery($query, 128);
            $row = mysql_fetch_row($qh);
            if (!in_array($row[0], $scheduleids)) {
                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;
        } else {
            # determine if image is bare metal or virtual
            $query = "SELECT OS.installtype " . "FROM image i " . "LEFT JOIN OS ON (i.OSid = OS.id) " . "WHERE i.id = {$imageid}";
            $qh = doQuery($query, 101);
            if (!($row = mysql_fetch_assoc($qh))) {
                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 {
                $virtual = 0;
            }
            # get list of available computers
            if (!$ignoreprivileges) {
                $resources = getUserResources(array("imageAdmin", "imageCheckOut"), array("available"), 0, 0, $userid);
                $usercomputers = implode("','", array_keys($resources["computer"]));
                $usercomputers = "'{$usercomputers}'";
            }
            $alloccompids = implode(",", $allocatedcompids);
            # get list of computers we can provision image to
            $schedules = implode(',', $scheduleids);
            #image.OSid->OS.installtype->OSinstalltype.id->provisioningOSinstalltype.provisioningid->computer.provisioningid
            $query = "SELECT DISTINCT c.id, " . "c.currentimageid, " . "c.imagerevisionid " . "FROM state s, " . "image i " . "LEFT JOIN OS o ON (o.id = i.OSid) " . "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 " . "c.stateid = s.id AND " . "s.name NOT IN ({$ignorestates}) 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.type != 'virtualmachine' OR c.vmhostid IS NOT NULL) AND ";
            if (!$ignoreprivileges) {
                $query .= "c.id IN ({$usercomputers}) AND ";
            }
            $query .= "c.id IN ({$mappedcomputers}) AND " . "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'] == $requestInfo['imagerevisions'][$key]) {
                    array_push($currentids, $row['id']);
                }
            }
            # get computer ids available from block allocations
            $blockdata = getAvailableBlockComputerids($imageid, $start, $end, $allocatedcompids);
            $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 " . "FROM reservation rs, " . "request rq " . "WHERE '{$startstamp}' < (rq.end + INTERVAL 900 SECOND) AND " . "'{$endstamp}' > rq.start AND " . "rq.id != {$requestid} AND " . "rs.requestid = rq.id AND " . "rq.stateid NOT IN (1, 5, 12)";
        # deleted, failed, complete
        $qh = doQuery($query, 130);
        while ($row = mysql_fetch_row($qh)) {
            array_push($usedComputerids, $row[0]);
        }
        $computerids = array_diff($computerids, $usedComputerids);
        $currentids = array_diff($currentids, $usedComputerids);
        $blockids = array_diff($blockids, $usedComputerids);
        // if modifying a reservation and $computerids is now empty, return 0
        if ($requestid && empty($computerids)) {
            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)) {
                cleanSemaphore();
                return debugIsAvailable(0, 10, $start, $end, $imagerevisionid, $computerids, $currentids, $blockids, array(), $virtual);
            }
        } elseif (!count($blockids)) {
            # && ! $altRemoveBlockCheck
            $usedBlockCompids = getUsedBlockComputerids($start, $end);
            $computerids = array_diff($computerids, $usedBlockCompids);
            $currentids = array_diff($currentids, $usedBlockCompids);
        }
        if ($virtual && empty($currentids) && !empty($computerids)) {
            # find computers whose hosts can handle the required RAM - we don't
            #   need to do this if there are VMs with the requested image already
            #   available because they would already fit within the host's available
            #   RAM
            if (!$vmhostcheckdone) {
                $vmhostcheckdone = 1;
                $query = "DROP TEMPORARY TABLE IF EXISTS VMhostCheck";
                doQuery($query, 101);
                $query = "CREATE TEMPORARY TABLE VMhostCheck ( " . "RAM mediumint unsigned NOT NULL, " . "allocRAM mediumint unsigned NOT NULL, " . "vmhostid smallint unsigned NOT NULL " . ") ENGINE=MEMORY";
                doQuery($query, 101);
                $query = "INSERT INTO VMhostCheck " . "SELECT c.RAM, " . "SUM(i.minram), " . "v.id " . "FROM vmhost v " . "LEFT JOIN computer c ON (v.computerid = c.id) " . "LEFT JOIN computer c2 ON (v.id = c2.vmhostid) " . "LEFT JOIN image i ON (c2.currentimageid = i.id) " . "WHERE c.stateid = 20 " . "GROUP BY v.id";
                doQuery($query, 101);
            }
            $inids = implode(',', $computerids);
            // if want overbooking, modify the last part of the WHERE clause
            $query = "SELECT c.id " . "FROM VMhostCheck v " . "LEFT JOIN computer c ON (v.vmhostid = c.vmhostid) " . "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.RAM, " . "(c.procspeed * c.procnumber), " . "c.network";
            $qh = doQuery($query, 101);
            $newcompids = array();
            while ($row = mysql_fetch_assoc($qh)) {
                $newcompids[] = $row['id'];
            }
            $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);
        $shortened = 0;
        if (!empty($failedids)) {
            $origcomputerids = $computerids;
            $origcurrentids = $currentids;
            $origblockids = $blockids;
            if (!empty($computerids)) {
                $testids = array_diff($computerids, $failedids);
                if (!empty($testids)) {
                    $shortened = 1;
                    $computerids = $testids;
                    $currentids = array_diff($currentids, $failedids);
                }
            }
            if (!empty($blockids)) {
                $testids = array_diff($blockids, $failedids);
                if (!empty($testids)) {
                    $shortened = 1;
                    $blockids = $testids;
                }
            }
        }
        # allocate a computer
        $_imgrevid = $requestInfo['imagerevisions'][$key];
        $comparr = allocComputer($blockids, $currentids, $computerids, $startstamp, $endstamp, $nowfuture, $imageid, $_imgrevid, $holdcomps, $requestid);
        if (empty($comparr) && $shortened) {
            $comparr = allocComputer($origblockids, $origcurrentids, $origcomputerids, $startstamp, $endstamp, $nowfuture, $imageid, $_imgrevid, $holdcomps, $requestid);
        }
        if (empty($comparr)) {
            cleanSemaphore();
            return debugIsAvailable(0, 11, $start, $end, $imagerevisionid, $computerids, $currentids, $blockids, $failedids, $virtual);
        }
        $requestInfo["computers"][$key] = $comparr['compid'];
        $requestInfo["mgmtnodes"][$key] = $comparr['mgmtid'];
        $requestInfo["loaded"][$key] = $comparr['loaded'];
        $requestInfo['fromblock'][$key] = $comparr['fromblock'];
        if ($comparr['fromblock']) {
            $requestInfo['blockdata'][$key] = $blockdata[$comparr['compid']];
        }
        array_push($allocatedcompids, $comparr['compid']);
    }
    return debugIsAvailable(1, 12, $start, $end, $imagerevisionid, $computerids, $currentids, $blockids, array(), $virtual);
}