Search This Blog

Wednesday, March 27, 2013

Symfony Project sfservermon Post 7 - Update Details - UpdaterServer class


Post 6 discussed the high level ServerUpdate class, this post finally documents the details of the UpdaterStatus class.

UpdaterStatus Class

This class in particular has about 90% of its code excellent taken from the original phpServerMon:

The class has the following methods:

  • Constructor - which saves references to the Entity manager, configuration and logger
  • getStatus - which calls update to update the server status.
  • update - which switches based on server type service or website to get the server status. It will recall itself recursively - to max runs to retry a connetion attempt.
  • updateService - checks a service server type
  • updateWebsite - checks a website server type.
  • notify - sends the required notification.
The first 3 methods are straightforward:
public function __construct($em, $configuration, $monitorLog)
{
    $this->em = $em;
    $this->config = $configuration;
    $this->monitorLog = $monitorLog;
}

public function setServer($server, $status_org) {
$this->clearResults();
$this->server = $server;
$this->status_org = $status_org;
}

/**
 * Get the new status of the selected server.
 *  If the update has not been performed yet it will do so first
 *
 * @return string
 */
public function getStatus() {

if(!$this->server) {
return false;
}
if(!$this->status_new) {
$this->update(3);
}
return $this->status_new;
}

public function update($max_runs=2)
{
switch($this->server->getType()) {
case 'service':
$result = $this->updateService($max_runs);
break;
case 'website':
$result = $this->updateWebsite($max_runs);
break;
}
return $result;
}



update Service Method

The updateService method checks a service -for example a database port on a server.
It requires a server tcp/udp port number and an ip address/hostname.
This method - and updateWebsite also record the response time.


protected function updateService($max_runs, $run = 1) {
// save response time
$time = explode(' ', microtime());
$starttime = $time[1] + $time[0];

@$fp = fsockopen ($this->server->getIp(), $this->server->getPort(), $errno, $errstr, 10);
Try to open a socket connection to the port using fsockopen , the last parameter is a timeout value - this should probably be stored in the server configuration, here it is 10 seconds.

$time = explode(" ", microtime());
$endtime = $time[1] + $time[0];
$this->rtime = ($endtime - $starttime);


$this->status_new = ($fp === false) ? 'off' : 'on';
$this->error = $errstr;
// add the error to the server array for when parsing the messages
$this->server->setError($this->error);
Was the socket opened? Check and save the setting, also save the error string.

@fclose($fp);

// check if server is available and rerun if asked.
if($this->status_new == 'off' && $run < $max_runs) {
return $this->updateService($max_runs, $run + 1);

If failed call again. return $this->status_new;

}

update Website Method.

This uses curl to opena connection to the website, it then checks the http status code.
An error can happen if
  • There is no response.
  • An unreadable response
  • Code is not as expected: HTTP/1.1 200 OK

protected function updateWebsite($max_runs, $run = 1) {
// save response time
$time = explode(' ', microtime());
$starttime = $time[1] + $time[0];

as before, record the start time.

$ch = curl_init();
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_URL, $this->server->getIp());
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt ($ch, CURLOPT_TIMEOUT, 10);
curl_setopt ($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11');

// We're only interested in the header, because that should tell us plenty!
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_NOBODY, true);
Create and initialise a curl object, we are only interested in the headers.

$headers = curl_exec ($ch);
curl_close ($ch);
Attempt to connect, and save the headers.
$time = explode(" ", microtime());
$endtime = $time[1] + $time[0];
$this->rtime = ($endtime - $starttime);
Record the time taken.
// the first line would be the status code..
$status_code = strtok($headers, "\r\n");
// keep it general
// $code[1][0] = status code
// $code[2][0] = name of status code
preg_match_all("/[A-Z]{2,5}\/\d\.\d\s(\d{3})\s(.*)/", $status_code, $code_matches);

Check and examine the http status.

if(empty($code_matches[0])) {
// somehow we dont have a proper response.
$this->error = 'no response from server';
$this->server->setError($this->error);
$this->status_new = 'off';
} else {
$code = $code_matches[1][0];
$msg = $code_matches[2][0];

// All status codes starting with a 4 or higher mean trouble!
if(substr($code, 0, 1) >= '4') {
$this->error = $code . ' ' . $msg;
$this->server->setError($this->error);
$this->status_new = 'off';
} else {
$this->status_new = 'on';
}
}

// check if server is available and rerun if asked.
if($this->status_new == 'off' && $run < $max_runs) {
return $this->updateWebsite($max_runs, $run + 1);
}


Recall if necessary

return $this->status_new;
}


The next post discussed the notification after a server status check.


No comments:

Post a Comment