setAllowedLocationsFromPermission('view.list')) { Message::addError('main.no-permission'); Util::redirect('?do=main'); } StatisticsFilter::renderFilterBox('list', $filterSet); self::showMachineList($filterSet); } /** * @param \StatisticsFilterSet $filterSet */ private static function showMachineList($filterSet) { Module::isAvailable('js_stupidtable'); $filterSet->makeFragments($where, $join, $args); $xtra = ''; if (Module::isAvailable('runmode')) { $xtra .= ', runmode.module AS rmmodule, runmode.isclient'; if (strpos($join, 'runmode') === false) { $join .= ' LEFT JOIN runmode ON (m.machineuuid = runmode.machineuuid) '; } } $allRows = Database::queryAll("SELECT m.machineuuid, m.locationid, m.macaddr, m.clientip, m.lastseen, m.logintime, m.state, m.currentuser, m.currentrunmode, m.realcores, m.mbram, m.kvmstate, m.cpumodel, m.id44mb, m.hostname, m.notes IS NOT NULL AS hasnotes, m.badsectors, Count(s.machineuuid) AS confvars $xtra FROM machine m LEFT JOIN setting_machine s ON (m.machineuuid = s.machineuuid) $join WHERE $where GROUP BY m.machineuuid", $args); // If filter results in just one result, redirect to machine details if (count($allRows) === 1) { Util::redirect('?do=statistics&uuid=' . $allRows[0]['machineuuid']); } // Gather additional info that would be ugly to fetch via joins above $uuids = array_column($allRows, 'machineuuid'); $machineWithHdds = Database::queryKeyValueList("SELECT mxx.machineuuid, Count(s.hwid) AS num FROM statistic_hw s INNER JOIN machine_x_hw AS mxx ON (s.hwid = mxx.hwid AND s.hwtype = :type AND mxx.disconnecttime = 0 AND mxx.machineuuid IN (:ids)) GROUP BY mxx.machineuuid", ['type' => HardwareInfo::HDD, 'ids' => $uuids]); $machineWithConfigOverrides = Database::queryKeyValueList("SELECT machineuuid, Count(machineuuid) AS num FROM setting_machine WHERE machineuuid IN (:ids) GROUP BY machineuuid", ['ids' => $uuids]); // TODO: Cannot disable checkbox for those where user has no permission, since we got multiple actions now // We should pass these lists to the output and add some JS magic // Either disable the delete/reboot/... buttons as soon as at least one "forbidden" client is selected (potentially annoying) // or add a notice to the confirmation dialog of the according action (nicer but a little more work) $deleteAllowedLocations = User::getAllowedLocations("machine.delete"); $rebootAllowedLocations = User::getAllowedLocations('.rebootcontrol.action.reboot'); $shutdownAllowedLocations = User::getAllowedLocations('.rebootcontrol.action.reboot'); $wolAllowedLocations = User::getAllowedLocations('.rebootcontrol.action.wol'); $execAllowedLocations = User::getAllowedLocations('.rebootcontrol.action.exec'); $benchmarkAllowedLocations = User::getAllowedLocations('.vmstore.benchmark'); // Only make client clickable if user is allowed to view details page $detailsAllowedLocations = User::getAllowedLocations("machine.view-details"); $location = self::buildLocationLookup(); $rows = []; foreach ($allRows as &$row) { $row['link_details'] = in_array($row['locationid'], $detailsAllowedLocations); //$row['firstseen'] = Util::prettyTime($row['firstseen']); $row['lastseen_int'] = $row['lastseen']; $row['lastseen'] = Util::prettyTime($row['lastseen']); //$row['lastboot'] = Util::prettyTime($row['lastboot']); $row['gbram'] = round(ceil($row['mbram'] / 512) / 2, 1); // Trial and error until we got "expected" rounding.. $row['gbtmp'] = round($row['id44mb'] / 1024); $octets = explode('.', $row['clientip']); if (count($octets) === 4) { $row['subnet'] = "$octets[0].$octets[1].$octets[2]"; $row['lastoctet'] = $octets[3]; } $row['ramclass'] = StatisticsStyling::ramColorClass($row['mbram']); $row['kvmclass'] = StatisticsStyling::kvmColorClass($row['kvmstate']); $row['hddclass'] = StatisticsStyling::hddColorClass($row['gbtmp']); if (empty($row['hostname'])) { $row['hostname'] = $row['clientip']; } if (isset($machineWithConfigOverrides[$row['machineuuid']])) { $row['confvars'] = $machineWithConfigOverrides[$row['machineuuid']]; } if (isset($machineWithHdds[$row['machineuuid']])) { $row['hddcount'] = $machineWithHdds[$row['machineuuid']]; } else if ($row['id44mb'] > 0) { // This might be a machine that wasn't booted with a recent system, and hence doesn't have HWinfo in DB // If we have ID44 space in our main table, we most likely got an HDD, so fake a count of 1 $row['hddcount'] = 1; } if (isset($row['data']) && !$row['data']) { $row['nohdd'] = true; } $row['cpumodel'] = preg_replace('/\(R\)|\(TM\)|\bintel\b|\bamd\b|\bcpu\b|dual-core|\bdual\s+core\b|\bdual\b|\bprocessor\b/i', ' ', $row['cpumodel']); if (!empty($row['rmmodule'])) { $data = RunMode::getRunMode($row['machineuuid'], RunMode::DATA_STRINGS); if ($data !== false) { $row['moduleName'] = $data['moduleName']; $row['modeName'] = $data['modeName']; } if (!$row['isclient'] && $row['state'] === 'IDLE') { $row['state'] = 'OCCUPIED'; } if (!$row['isclient']) { unset($row['currentuser']); } } if ($row['state'] === 'IDLE' || $row['state'] === 'OCCUPIED') { if ((!empty($row['currentrunmode']) || !empty($row['rmmodule'])) && $row['currentrunmode'] !== $row['rmmodule']) { $row['wrongRunMode'] = true; if (!empty($row['currentrunmode'])) { $wrongModule = Module::get($row['currentrunmode']); $row['currentrunmode'] = $wrongModule === false ? $row['currentrunmode'] : $wrongModule->getDisplayName(); } } } $row['state_' . $row['state']] = true; if ($row['locationid'] > 0) { $row['location'] = $location[$row['locationid']]; } $rows[] =& $row; } $data = array( 'rowCount' => count($rows), 'rows' => $rows, 'showList' => 1, 'show' => 'list', 'redirect' => $_SERVER['QUERY_STRING'], 'rebootcontrol' => (Module::get('rebootcontrol') !== false), 'canReboot' => !empty($rebootAllowedLocations), 'canShutdown' => !empty($shutdownAllowedLocations), 'canDelete' => !empty($deleteAllowedLocations), 'canWol' => !empty($wolAllowedLocations), 'canExec' => !empty($execAllowedLocations), 'canBenchmark' => !empty($benchmarkAllowedLocations), ); Render::addTemplate('clientlist', $data); } private static function buildLocationLookup() { $ret = []; $i = 0; foreach (Location::getLocationsAssoc() as $lid => $data) { $ret[$lid] = ['sort' => ++$i, 'name' => $data['locationname']]; } return $ret; } }