diff --git a/includes/global.php b/includes/global.php index cb493cd..f0dba41 100644 --- a/includes/global.php +++ b/includes/global.php @@ -101,6 +101,13 @@ if ($version != $config["tsm_monitor_version"] && basename($_SERVER['REQUEST_URI exit; } +$polld_maxproc = $adodb->fetchCellDB("SELECT confval FROM cfg_config WHERE confkey='polld_maxproc'", ''); +if (isset($polld_maxproc)) { + $config["polld_maxproc"] = $polld_maxproc; +} else { + $config["polld_maxproc"] = 5; +} + // ** Include generic code and external libraries ** // // ... more includes here diff --git a/includes/polld.php b/includes/polld.php index ab7881e..54f8e51 100644 --- a/includes/polld.php +++ b/includes/polld.php @@ -23,11 +23,11 @@ /** * * polld.php, TSM Monitor - * + * * This file is the TSM Monitor Polling Daemon. It executes queries against TSM - * and inserts them into TMS Monitor's MySQL Database - * - * @author Michael Clemens + * and inserts them into TSM Monitor's MySQL Database + * + * @author Michael Clemens, Frank Fegert * @version 1.0 * @package tsmmonitor */ @@ -60,9 +60,9 @@ class PollD { /** - * PollD - * - * @param mixed $adodb + * PollD + * + * @param mixed $adodb * @access public * @return void */ @@ -94,7 +94,7 @@ class PollD { $this->writeMSG("TSM Monitor has not been installed correctly, path to dsmadmc could not be found.\n", "ERROR"); exit; } - + $this->servers = $this->getServers(); $this->queries = $this->getQueries(); $this->overviewqueries = $this->getOverviewQueries(); @@ -102,9 +102,9 @@ class PollD { /** - * writeMSG - * - * @param mixed $msg + * writeMSG + * + * @param mixed $msg * @param mixed $level VERBOSE, INFO, WARN, ERROR, OFF * @access public * @return void @@ -141,8 +141,8 @@ class PollD { /** - * setDebuglevel - * + * setDebuglevel + * * @param mixed $debuglevel VERBOSE, INFO, WARN, ERROR, OFF * @access public * @return void @@ -172,6 +172,7 @@ class PollD { /** * getQueries - returns an array filled with all configured TSM queries * + * @return array */ function getQueries() { $queries = array(); @@ -230,7 +231,7 @@ class PollD { * @param string $query TSM query * @param string $servername name of the TSM server * @param string $restable - * @param string $timestamp + * @param string $timestamp * @param string $overviewname * @return array */ @@ -441,7 +442,7 @@ class PollD { } } else { $this->writeMSG("There was a problem querying the TSM Server ".$server["servername"]."!\n", "ERROR"); - } + } } else { $this->writeMSG("no need to update result -> pollfreq not reached!\n", "INFO"); $this->log_pollfreqnoreached++; @@ -482,7 +483,7 @@ class PollD { /** * cleanupDatabase - cleans up database (single result tables and/or hash entry) * - * @param string $servername + * @param string $servername * @param string $queryname * @param string $overviewqueryname * @param string $hashonly do not drop table, just delete entry in log_hashes @@ -492,7 +493,7 @@ class PollD { if ($servername != "" && $queryname != "" && $overviewqueryname != "") { $time = time()-($months*30*24*60*60); $wc = " WHERE `timestamp`<'".$time."'"; - foreach ($this->servers as $server) { + foreach ($this->servers as $server) { if ($servername == "all" || $server["servername"] == $servername) { foreach ($this->queries as $query) { if (($queryname == "all" || $query["name"] == $queryname) && $queryname != "none") { @@ -620,21 +621,21 @@ class PollD { foreach ($this->overviewqueries as $query) { $this->pollOverviewQuery($query, $server, $timestamp); } - $sql = 'INSERT INTO log_polldlog VALUES ("'.$timestamp.'", "'.$server["servername"].'", "'.$log_updated.'", "'.$log_unchangedresult.'", "'.$log_pollfreqnoreached.'", "'.(time()-$log_timeneeded).'")'; + $sql = 'INSERT INTO log_polldlog VALUES ("'.$timestamp.'", "'.$server["servername"].'", "'.$this->log_updated.'", "'.$this->log_unchangedresult.'", "'.$this->log_pollfreqnoreached.'", "'.(time() - $this->log_timeneeded).'")'; $this->adodb->execDB($sql); } $init = "no"; - $this->writeMSG("needed ".(time()-$timestamp)." seconds for this run.\n", "INFO"); - $tempsleeptime = 900 -(time()-$timestamp); + $this->writeMSG("needed ".(time() - $timestamp)." seconds for this run.\n", "INFO"); + $tempsleeptime = 900 - (time() - $timestamp); if ($tempsleeptime < 0) { $tempsleeptime = 0; } $this->writeMSG("sleeping for ".$tempsleeptime." seconds...\n", "WARN"); - $this->writeMSG("next run will be at ".strftime("%H:%M:%S", (time()+$tempsleeptime))."\n\n", "WARN"); + $this->writeMSG("next run will be at ".strftime("%H:%M:%S", (time() + $tempsleeptime))."\n\n", "WARN"); - $this->setPollDStatus("sleeping", $timestamp, (time()+$tempsleeptime)); + $this->setPollDStatus("sleeping", $timestamp, (time() + $tempsleeptime)); sleep ($tempsleeptime); @@ -648,4 +649,691 @@ class PollD { } } + +/** + * + * Class PollD_MP + * + */ +class PollD_MP { + + var $cfg; + var $queries; + var $lastrun; + var $overviewqueries; + var $adodb; + var $dsmadmc; + + var $debuglevel; // VERBOSE=4, INFO=3, WARN=2, ERROR=1, OFF=0 + var $logfile; + + var $log_timeneeded; + var $log_unchangedresult; + var $log_pollfreqnoreached; + var $log_updated; + var $pid; + var $child_pid; + var $worker_pids = array(); + + /** + * PollD_MP + * + * @param mixed $cfg + * @access public + * @return void + */ + function PollD_MP($cfg) { + + $this->cfg = $cfg; + $funcs = array("pcntl_fork", "pcntl_waitpid", "posix_kill"); + $func_miss = array(); + $func_ena = true; + + // pcntl_fork() not available on win32, sorry folks! + if ($cfg["server_os"] == "win32") { + echo "ERROR: The PHP function \"pcntl_fork()\" is not available on Windows platforms, please use the regular tmonpolld.php!\n"; + exit; + } + + // Check if PHP has pcntl_fork() enabled. + foreach ($funcs as $func) { + if (!function_exists($func)){ + $func_ena = false; + array_push($func_miss, $func); + } + } + if (!$func_ena) { + echo "ERROR: The following PHP functions are missing: ".(implode(", ", $func_miss)).".\n"; + exit; + } + + $this->setDebuglevel("INFO"); + $this->adodb = new ADOdb($this->cfg["db_host"], $this->cfg["db_port"], $this->cfg["db_user"], $this->cfg["db_password"], $this->cfg["db_name"], $this->cfg["db_type"]); + $sql = "select confval from cfg_config WHERE `confkey`='loglevel_polld'"; + $loglevel = $this->adodb->fetchArrayDB($sql); + $loglevel = strtoupper($loglevel[0]["confval"]); + $this->setDebuglevel("$loglevel"); + $sql = "select confval from cfg_config WHERE `confkey`='path_polldlog'"; + $lf = $this->adodb->fetchArrayDB($sql); + if ($lf[0]["confval"] != "") { + $this->logfile = $lf[0]["confval"]; + } else { + unset($this->logfile); + } + $sql = "select confval from cfg_config WHERE `confkey`='path_dsmadmc'"; + $tsmclient = $this->adodb->fetchArrayDB($sql); + if ($tsmclient[0]["confval"] != "") { + $this->dsmadmc = $tsmclient[0]["confval"]; + if (!is_executable($this->dsmadmc)) { + $this->writeMSG("$this->dsmadmc is not executable.\n", "ERROR"); + exit; + } + } else { + $this->writeMSG("TSM Monitor has not been installed correctly, path to dsmadmc could not be found.\n", "ERROR"); + exit; + } + + $this->servers = $this->getServers(); + $this->queries = $this->getQueries(); + $this->overviewqueries = $this->getOverviewQueries(); + } + + + /** + * writeMSG + * + * @param mixed $msg + * @param mixed $level VERBOSE, INFO, WARN, ERROR, OFF + * @access public + * @return void + */ + function writeMSG($msg, $level) { + + switch ($level) { + case ("OFF"): + $ilevel = 0; + break; + case ("ERROR"): + $ilevel = 1; + break; + case ("WARN"): + $ilevel = 2; + break; + case ("INFO"): + $ilevel = 3; + break; + case ("VERBOSE"): + $ilevel = 4; + break; + } + + if ($this->debuglevel >= $ilevel) { + if ($loghandle = fopen($this->logfile, 'a')) { + $starttime = microtime(); + do { + $lock = flock($loghandle, LOCK_EX); + if (!$lock) usleep(round(rand(0, 100) * 1000)); + } while (!$lock && ((microtime() - $starttime) < 1000)); + + if ($lock) { + fwrite($loghandle, $level.": ".$msg); + } + fclose($loghandle); + } else { + echo "ERROR: Cannot open logfile: '".$logfile."' for writing. Falling back to STDOUT.\n"; + echo $level.": ".$msg; + } + } + } + + + /** + * setDebuglevel + * + * @param mixed $debuglevel VERBOSE, INFO, WARN, ERROR, OFF + * @access public + * @return void + */ + function setDebuglevel($debuglevel) { + + switch ($debuglevel) { + case ("OFF"): + $this->debuglevel = 0; + break; + case ("ERROR"): + $this->debuglevel = 1; + break; + case ("WARN"): + $this->debuglevel = 2; + break; + case ("INFO"): + $this->debuglevel = 3; + break; + case ("VERBOSE"): + $this->debuglevel = 4; + break; + } + } + + + /** + * getQueries - returns an array filled with all configured TSM queries + * + * @return array + */ + function getQueries() { + $queries = array(); + $query = "select * from cfg_queries"; + $querytablerows = $this->adodb->fetchArrayDB($query); + while (list ($subkey, $queryrow) = each ($querytablerows)) { + $queries[$queryrow["name"]] = (array)$queryrow; + $temparray=split(",", $queryrow->Fields); + $cols = array(); + while (list ($subkey, $col) = each ($temparray)) { + $temp = split("!", $col); + $cols[$subkey]["label"] = $temp[0]; + $cols[$subkey]["name"] = $temp[1]; + } + if ($queryrow->name != "") $queries[$queryrow->name]["header"]["column"] = $cols; + } + return $queries; + } + + + /** + * getOverviewQueries - returns an array filled with all configured TSM overview queries + * + * @return array + */ + function getOverviewQueries() { + $queries = array(); + $query = "select * from cfg_overviewqueries"; + $querytablerows = $this->adodb->fetchArrayDB($query); + while (list ($subkey, $queryrow) = each ($querytablerows)) { + $queries[$queryrow["name"]] = (array)$queryrow; + } + return $queries; + } + + + /** + * getServers - returns an array containing all defined servers + * + * @return array + */ + function getServers() { + $query = "SELECT * FROM cfg_servers"; + $rows = $this->adodb->fetchArrayDB($query); + $servers = array(); + while (list ($key, $val) = each ($rows)) { + $servers[$val["servername"]] = (array)$val; + } + return $servers; + } + + + /** + * updateJoblist - update the job list for the worker processes + * + * @return void + */ + function updateJoblist() { + $servers = $this->getServers(); + $query = "SELECT * FROM job_list"; + $jobs = $this->adodb->fetchArrayDB($query); + $insert = array(); + + foreach ($servers as $skey => $sval) { + $found = 0; + $sservername = strtoupper($sval["servername"]); + foreach ($jobs as $jkey => $jval) { + $jservername = strtoupper($jval["servername"]); + if (isset($sservername) && isset($jservername)) { + if ($sservername == $jservername) { + $found = 1; + continue; + } + } + } + if ($found == 0) array_push($insert, "('".$sservername."')"); + } + + if (count($insert) > 0) { + $sql = "INSERT INTO `job_list` (`servername`) VALUES ".join(', ', $insert); + $this->adodb->execDB($sql); + } + } + + /** + * execute - executes a TSM query on a TSM server and returns an array containing SQL insert statements including the results + * + * @param string $query TSM query + * @param string $servername name of the TSM server + * @param string $restable + * @param string $timestamp + * @param string $overviewname + * @return array + */ + function execute($query = '', $servername = '', $restable = '', $timestamp = '', $overviewname = '') { + + $server = $this->servers[$servername]; + $ip = $server["ip"]; + $port = $server["port"]; + $user = $server["username"]; + $pass = $server["password"]; + $out = array(); + + $originalquery = $query; + $query = ereg_replace("NOTEQUAL","<>",$query); + $query = ereg_replace("LESS","<",$query); + + if (ereg(" summary ", $query)) { + if ($this->lastrun > 0) { + $tdiff = $timestamp - $this->lastrun; + $tdiff = ceil($tdiff / 60) * 60; + $query = ereg_replace(" @@@WHERE@@@ "," AND start_time>current_timestamp-($tdiff)seconds ",$query); + } else { + $query = ereg_replace(" @@@WHERE@@@ "," ",$query); + } + } + + $popen_flags = ($this->cfg["server_os"] == "win32") ? 'rb' : 'r'; + $handle = popen("$this->dsmadmc -se=$servername -id=$user -password=$pass -TCPServeraddress=$ip -COMMMethod=TCPIP -TCPPort=$port -dataonly=yes -TAB \"$query\" ", "$popen_flags"); + + $hashstring = ""; + + if ($handle) { + while (!feof($handle) && !$stop) { + $read = fgets($handle, 4096); + $hashstring .= $read; + $stop = strstr($read, 'ANR2034E'); + $stop = strstr($read, 'ANS1017E'); + $stop = strstr($read, 'ANS8023E'); + $blank = strstr($read, 'ANR2034E'); // dsmadmc runs correctly but result is empty (e.g. processes) + if ($read != ' ' && $read != '' && !$stop) { + if ($blank == "") { + $read = preg_replace('/[\n]+/', '', $read); + $read = ereg_replace("\t","\",\"",$read); + $read = ereg_replace("\\\\",'\\\\',$read); + if ($overviewname == '') { + $out[] = 'INSERT IGNORE INTO '.$restable.' values ("'.$timestamp.'", "'.$read.'")'; + } else { + $out[] = 'INSERT INTO '.$restable.' (timestamp, name, result) values ("'.$timestamp.'", "'.$overviewname.'", "'.$read.'") ON DUPLICATE KEY update result="'.$read.'", timestamp="'.$timestamp.'"'; + } + } else { // result is empty and it's ok + $out[0] = 'INSERT IGNORE INTO '.$restable.' (timestamp) values ("'.$timestamp.'")'; + $hashstring = ""; + $stop = TRUE; + } + } + } + } + + $return["sql"] = $out; + $return["md5"] = md5($hashstring); + if (!$stop || ($blank && $stop)) { + return $return; + } else { + return ""; + } + } + + + /** + * checkHash - checks with checksum if there's already the same result in the result database. If not, the hash will be stored. + * + * @param string $tablename name of table + * @param string $hash md5 hash checksum of current resultSet + * @return boolean + */ + function checkHash($tablename = '', $hash = '') { + + $sql = "select count(*) from log_hashes where TABLENAME='".$tablename."' and HASH='".$hash."'"; + $countobj = $this->adodb->fetchArrayDB($sql); + $countarray = (array)$countobj[0]; + $count = $countarray["count(*)"]; + + if ($count > 0) { + return TRUE; + } else { + $colarray = array(); + $colarray["tablename"] = $tablename; + $colarray["hash"] = $hash; + $this->adodb->updateDB("log_hashes", $colarray, 'tablename'); + return FALSE; + } + + } + + + /** + * checkFreq - checks if configured checking frequency is reached + * + * @param string $tablename name of table + * @param string $pollfreq polling frequency + * @param string $timestamp timestamp + * @return boolean + */ + function checkFreq($tablename, $pollfreq, $timestamp) { + + $sql = "select MAX(TimeStamp) from ".$tablename; + $res = $this->adodb->fetchArrayDB($sql); + $resarray = $res[0]; + $lastinsert = $resarray["MAX(TimeStamp)"]; + + if ($lastinsert != "") { + $this->lastrun = $lastinsert; + } else { + $this->lastrun = 0; + } + + if ($lastinsert != "" && ($lastinsert+($pollfreq*60)) >= $timestamp) { + return TRUE; + } else { + return FALSE; + } + } + + + /** + * getSleeptime - searches for the smallest polling frequency and returns the time to sleep + * + * @return string + */ + function getSleeptime() { + + $sql = "select MIN(pollfreq) from cfg_queries"; + $res = $this->adodb->fetchArrayDB($sql); + $resarray = (array)$res[0]; + $minqueries = $resarray["MIN(pollfreq)"]; + + $sql = "select MIN(pollfreq) from cfg_overviewqueries"; + $res = $this->adodb->fetchArrayDB($sql); + $resarray = (array)$res[0]; + $minoverview = $resarray["MIN(pollfreq)"]; + + return min($minoverview,$minqueries)*60; + + } + + + /** + * pollQuery - executes a TSM query and stores result in MySQL DB + * + * @param array $query + * @param array $server + * @param boolean $ignorePollFreq + * @param string $timestamp + */ + function pollQuery($query = "", $server = "", $ignorePollFreq = TRUE, $timestamp) { + $starttquery = time(); + $querytime = 0; + + $logprefix = "Worker(".$this->child_pid.") ".sprintf('%-16s', $server)." ---------".$query["name"]; + $tablename = "res_".$query["name"]."_".$server; + + // create table if not exists + $showsql = "SHOW TABLES LIKE '".$tablename."'"; + $res = $this->adodb->fetchArrayDB($showsql); + if (!isset($res[0])) { + $fieldsql = "select fields from cfg_queries where name='".$query["name"]."'"; + $fields = $this->adodb->fetchArrayDB($fieldsql); + $ctsql = "CREATE TABLE `".$tablename."` (".$fields[0]['fields'].") DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci"; + if (!$ignorePollFreq) { + $this->writeMSG($logprefix.": created table ".$tablename."\n", "INFO"); + } + $this->adodb->execDB($ctsql); + } + // execute query and store result in mysql db + if ($ignorePollFreq || !$this->checkFreq($tablename, $query["pollfreq"], $timestamp)) { + try { + $result = $this->execute($query["tsmquery"], $server, $tablename, $timestamp); + } catch (exception $e) { + $this->writeMSG($logprefix.": Problem while querying from TSM Server!\n", "ERROR"); + } + if ($result != "") { + if (!$this->checkHash($tablename, $result["md5"])) { + if ($query["polltype"] == "update") { + $dropsql = "truncate table ".$tablename; + try { + $this->adodb->execDB($dropsql); + } catch (exception $e) { + $this->writeMSG($logprefix.": Error while truncating table (".$dropsql.")\n", "ERROR"); + } + $this->writeMSG($logprefix.": TRUNCATED TABLE\n", "INFO"); + } + foreach ($result["sql"] as $insertquery) { + try { + $this->adodb->execDB($insertquery); + } catch (exception $e) { + $this->writeMSG($logprefix.": Error while inserting into table (".$insertquery.")\n", "ERROR"); + } + } + $querytime = time() - $starttquery; + $this->writeMSG($logprefix.": Inserted new rows into ".$tablename." ($querytime sec)\n", "INFO"); + $this->log_updated++; + } else { + $querytime = time() - $starttquery; + $this->writeMSG($logprefix.": No need to update result -> result is the same as last time ($querytime sec)\n", "INFO"); + $this->log_unchangedresult++; + } + } else { + $this->writeMSG($logprefix.": There was a problem querying the TSM Server ".$server."!\n", "ERROR"); + } + } else { + $this->writeMSG($logprefix.": No need to update result -> pollfreq not reached!\n", "INFO"); + $this->log_pollfreqnoreached++; + } + } + + + /** + * pollOverviewQuery - executes a TSM overview query and stores result in MySQL DB + * + * @param array $query + * @param array $server + * @param boolean $ignorePollFreq + * @param string $timestamp + */ + function pollOverviewQuery($query = "", $server = "", $timestamp) { + + $starttquery = time(); + $querytime = 0; + + $tablename = "res_overview_".$server; + $logprefix = "Worker(".$this->child_pid.") ".sprintf('%-16s', $server)." ---------".$query["name"]; + $ctsql = "CREATE TABLE IF NOT EXISTS ".$tablename." ( `timestamp` int(11) collate utf8_unicode_ci NOT NULL, `name` varchar(35) collate utf8_unicode_ci NOT NULL, `result` varchar(255) collate utf8_unicode_ci NOT NULL, UNIQUE KEY `name` (`name`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci"; + $this->adodb->execDB($ctsql); + $result = $this->execute($query["query"], $server, $tablename, $timestamp, $query["name"]); + if ($result != "") { + foreach ($result["sql"] as $insertquery) { + $this->adodb->execDB($insertquery); + $querytime = time() - $starttquery; + $this->writeMSG($logprefix.": Inserted row ($querytime sec)\n", "INFO"); + } + } else { + $this->writeMSG($logprefix.": There was a problem querying the TSM Server ".$server."!\n", "ERROR"); + } + + } + + + /** + * setPollDStatus + * + * @param string $server + * @param string $status + * @param string $pid + * @param string $lastrun + * @param string $nextrun + */ + function setPollDStatus($server, $status, $pid, $lastrun, $nextrun) { + + if ($server != "") $servername = $server; + $sqlset = array(); + array_push($sqlset, "`status`='".$status."'"); + array_push($sqlset, "`pid`='".$pid."'"); + array_push($sqlset, "`lastrun`='".$lastrun."'"); + array_push($sqlset, "`nextrun`='".$nextrun."'"); + + $sql = "UPDATE job_list SET ".(join(', ', $sqlset))." WHERE servername='".$server."'"; + $this->adodb->execDB($sql); + } + + + /** + * isEnabled - returns true if PollD is enabled + * + * @returns boolean + */ + function isEnabled() { + + $sql = "select enabled from log_polldstat WHERE `id`='1'"; + $result = $this->adodb->fetchArrayDB($sql); + + if ($result != "" && $result[0]["enabled"] == "1") { + return TRUE; + } else { + return FALSE; + } + } + + + /** + * controlPollD - enables or disables polld + * + * @param string switch on or off + */ + function controlPollD($switch = "") { + + if ($switch == "on") { + $val = "1"; + } else if ($switch == "off") { + $val = "0"; + } else { + return ""; + } + $sql = "update log_polldstat set `enabled` = '".$val."' WHERE `id`='1'"; + $this->adodb->execDB($sql); + + } + + + /** + * poll - the main function that polls the data + * + * @return boolean + */ + function poll() { + + $sleeptime = $this->getSleeptime(); + $this->writeMSG("Sleeptime will be ".$sleeptime." seconds\n", "WARN"); + + if ($this->isEnabled()) { + // Main loop for dispatcher + while(true) { + $this->adodb = new ADOdb($this->cfg["db_host"], $this->cfg["db_port"], $this->cfg["db_user"], $this->cfg["db_password"], $this->cfg["db_name"], $this->cfg["db_type"]); + $this->updateJoblist($this->adodb); + $query = "SELECT * FROM job_list"; + $jobs = $this->adodb->fetchArrayDB($query); + $this->adodb->closeDB(); + + foreach ($jobs as $key => $job) { + $this->lastrun = $job["lastrun"]; + $lastrun = $job["lastrun"]; + $lastpid = $job["pid"]; + $nextrun = $job["nextrun"]; + $server = $job["servername"]; + $status = $job["status"]; + if ($lastrun == "NULL" || $lastrun == "") $lastrun = 0; + if ($nextrun == "NULL" || $nextrun == "") $nextrun = 0; + $thisrun = time(); + + // Check for unclean child shutdown or hung child. + if ($status == "running" ) { + if ((posix_kill($lastpid, 0)) && (($thisrun - $lastrun) > 3600)) { + $this->writeMSG("Killing child: $lastpid for server: $server after 3600 sec.\n", INFO); + posix_kill($lastpid, SIGTERM); + unset($this->worker_pids[$lastpid]); + $nextrun = 0; + $status = ""; + } else if (!posix_kill($lastpid, 0)) { + $this->writeMSG("Removing non-existing child: $lastpid for server: $server from job list.\n", INFO); + unset($this->worker_pids[$lastpid]); + $nextrun = 0; + $status = ""; + } + } + + if ($status == "" && $thisrun >= $nextrun) { + if (count($this->worker_pids) < $this->cfg["polld_maxproc"]) { + $pid = pcntl_fork(); + + if ($pid == -1) { + echo "ERROR: Couldn't fork() worker process!"; + exit; + } else if ($pid) { + // Parent + $this->worker_pids[$pid] = 1; + $this->writeMSG("Dispatcher: ".(posix_getpid())."; Workers: ".(join(', ', array_keys($this->worker_pids)))."\n", INFO); + + } else { + // Child + $this->child_pid = posix_getpid(); + $timestamp = time(); + $this->writeMSG("Worker(".$this->child_pid.") ".sprintf('%-16s', $server)." Timestamp for this run is $timestamp.\n", INFO); + $this->adodb = new ADOdb($this->cfg["db_host"], $this->cfg["db_port"], $this->cfg["db_user"], $this->cfg["db_password"], $this->cfg["db_name"], $this->cfg["db_type"]); + $this->setPollDStatus($server, "running", $this->child_pid, $timestamp, ""); + + // Process job + $this->log_timeneeded = $timestamp; + $this->log_unchangedresult = 0; + $this->log_pollfreqnoreached = 0; + $this->log_updated = 0; + + $this->writeMSG("Worker(".$this->child_pid.") ".sprintf('%-16s', $server)." ---querying server $server\n", "WARN"); + $this->writeMSG("Worker(".$this->child_pid.") ".sprintf('%-16s', $server)." ------querying normal queries\n", "WARN"); + foreach ($this->queries as $query) { + $this->pollQuery($query, $server, FALSE, $timestamp); + } + $this->writeMSG("Worker(".$this->child_pid.") ".sprintf('%-16s', $server)." ------querying overview queries\n", "WARN"); + foreach ($this->overviewqueries as $query) { + $this->pollOverviewQuery($query, $server, $timestamp); + } + + $this->writeMSG("Worker(".$this->child_pid.") ".sprintf('%-16s', $server)." Needed ".(time()-$timestamp)." seconds for this run.\n", "INFO"); + $tempsleeptime = 900 - (time() - $timestamp); + if ($tempsleeptime < 0) $tempsleeptime = 0; + $this->writeMSG("Worker(".$this->child_pid.") ".sprintf('%-16s', $server)." Next run will be at ".strftime("%H:%M:%S", (time() + $tempsleeptime))."\n", "WARN"); + + $sql = 'INSERT INTO log_polldlog VALUES ("'.$timestamp.'", "'.$server.'", "'.$this->log_updated.'", "'.$this->log_unchangedresult.'", "'.$this->log_pollfreqnoreached.'", "'.(time() - $this->log_timeneeded).'")'; + $this->adodb->execDB($sql); + + $this->setPollDStatus($server, "", "", $timestamp, (time() + $tempsleeptime)); + $this->adodb->closeDB(); + exit; + } + } + } + } + + foreach ($this->worker_pids as $wpid => $val) { + $wpid_status = pcntl_waitpid($wpid, $status, WNOHANG); + if ($wpid_status < 0) { + echo "ERROR: pcntl_waitpid returned $wpid_status\n"; + exit; + } else if ($wpid_status > 0) { + $this->writeMSG("Worker($wpid_status) has exited.\n", INFO); + unset($this->worker_pids[$wpid]); + } + } + sleep(rand(5,10)); + } + } else { + $this->writeMSG("PollD is disabled. Sleeping for 5 minutes ...\n", "ERROR"); + sleep (3); + } + } +} + ?> diff --git a/polld/tmonpolld_mp.php b/polld/tmonpolld_mp.php new file mode 100644 index 0000000..9087c51 --- /dev/null +++ b/polld/tmonpolld_mp.php @@ -0,0 +1,43 @@ +. + ************************************************************************ + */ + + +/** + * + * tmonpolld_mp.php, TSM Monitor + * + * This file instantiates PollD_MP and executes the multi-process polling. + * Start it like this: 'nohup php tmonpolld_mp.php &' + * + * + * @author Michael Clemens, Frank Fegert + * @version 1.0 + * @package tsmmonitor + */ + +include_once("../includes/global.php"); + +$tmonpolld = new PollD_MP($config); +$tmonpolld->controlPollD("on"); +$tmonpolld->poll(); + + +?> diff --git a/scripts/tsmmonitor.sql b/scripts/tsmmonitor.sql index 04dd795..3ea8f97 100644 --- a/scripts/tsmmonitor.sql +++ b/scripts/tsmmonitor.sql @@ -62,7 +62,8 @@ INSERT INTO `cfg_config` (`id`, `confkey`, `confval`, `description`) VALUES (5, 'loglevel_tm', 'INFO', 'TSM Monitor Log Level'), (6, 'loglevel_polld', 'INFO', 'PollD Log Level'), (7, 'path_dsmadmc', '', 'dsmadmc Binary Path'), -(8, 'path_php', '', 'PHP Binary Path'); +(8, 'path_php', '', 'PHP Binary Path'), +(9, 'polld_maxproc', '5', 'PollD maximum concurrent processes'); -- -------------------------------------------------------- @@ -364,3 +365,21 @@ CREATE TABLE IF NOT EXISTS `log_polldstat` ( INSERT INTO `log_polldstat` (`id`, `enabled`, `status`, `lastrun`, `nextrun`) VALUES (1, 0, '', 0, 0); + + +-- -------------------------------------------------------- + + +-- +-- Table structure for table `job_list` +-- + +CREATE TABLE IF NOT EXISTS `job_list` ( + `id` int(11) NOT NULL auto_increment, + `servername` varchar(35) collate utf8_unicode_ci NOT NULL, + `status` varchar(35) collate utf8_unicode_ci NOT NULL, + `pid` int(11) default NULL, + `lastrun` int(11) default NULL, + `nextrun` int(11) default NULL + PRIMARY KEY (`id`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;