array_push($headers, “Content-Type: text/plain\r\n”); $body = implode(‘’, $message); $search = array_keys($info); $replace = array_values($info); $body = preg_replace($search, $replace, $body); $subject = preg_replace($search, $replace, $subject); $headerStr = implode(‘’, $headers); if (DEBUG) echo “Sending mail to: $to ($subject)\n”; mail($to, $subject, $body, $headerStr); } function getDiskInfo($fs = null) { $info = array(); foreach($fs as $disk) { $mountPoint = $disk[‘mount’]; $percent = $disk[‘percent’]; // remove % sign $info[$mountPoint] = substr($percent, 0, strlen($percent) -1); } return $info; } ?> Chapter 16: Command-Line PHP Utilities 591 21 549669 ch16.qxd 4/4/03 9:27 AM Page 591 This script works as follows: 1. It requires the class.Linux.inc.php and common_functions.php classes. 2. It creates a sysinfo object called $system, which is used to retrieve host name, IP address, and kernel information, using the chostname(), ip_addr(), and kernel() methods. 3. It calls the getDiskInfo() function with an array of disk information returned by the filesystems() method of the $system object. 4. The getDiskInfo() function returns an array called $diskInfo, which returns each mount point (file system) in the system and the usage per- centage. 5. For each mount point returned in $diskInfo, the usage percentage is compared against the maximum allowed usage percentage stored in $MAX- SIZE (from the hdmonitor.conf file). 6. If current usage is greater than or equal to the $MAXSIZE usage specified for that mount point, an alert record is appended in $alertInfo[‘/ <%DISK_STATUS%>/’] . The alert count $alert is incremented. 7. If disk usage alerts (i.e., $alert > 0) are found, then sendAlert() is called to e-mail the alert information stored in the $alertInfo array. Listing 16-12 shows the alert message template. The To:, From:, Subject:, and Content-Type: headers are used in creating the e-mail message headers. There are custom tags such as <%HOST%>, <%IP_ADDR%>, <%KERNEL%>, and <%DISK_STATUS%>. These are replaced with the $alertInfo contents. The following message is in HTML, but you can use plain text as well by setting the Content-Type: header to text/plain and removing HTML tags from the message body as needed. Listing 16-12: hdmonitor_mail.txt To: kabir@example.com From: THE REDEYE GROUP <admin@example.com> Subject: Disk(s) on <%HOST%> need your attention Content-Type: text/html <html> <body> The following disk(s) have exceeded set limit in hdmonitor.conf: <br> <br> 592 Part IV: Using PHP for Sysadmin Tasks 21 549669 ch16.qxd 4/4/03 9:27 AM Page 592 <table border=0 cellpadding=1 cellspacing=0 width=”400” bgcolor=”#000000”> <tr> <td> <table border=0 cellpadding=3 cellspacing=0 width=”400” bgcolor=”red”> <tr> <td> <font color=”black”> <strong> Disk Information </strong> </font> </td> </tr> <tr> <td> <font color=”black”><%DISK_STATUS%> </font> </td> </tr> </table> </td> </tr> </table> <br> <table border=0 cellpadding=1 cellspacing=0 width=”400” bgcolor=”#000000”> <tr> <td> <table border=0 cellpadding=3 cellspacing=0 width=”400” bgcolor=”#cccccc”> <tr> <td colspan=2> System Information </td></tr> <tr> <td>Hostname </td><td> <%HOST%></td></tr> <tr> <td>IP Addr </td><td> <%IP_ADDR%></td></tr> <tr> <td>Kernel </td><td> <%KERNEL%></td></tr> </table> </td> </tr> </table> <br> Thanks, <br> The Wheel Group <br> </body> </html> The hdmonitor.php script contains the following functions. Chapter 16: Command-Line PHP Utilities 593 21 549669 ch16.qxd 4/4/03 9:27 AM Page 593 sendAlert() This function sends an e-mail message by loading the message template from the hdmonitor.conf configuration variable $GLOBALS[‘MAIL_TEMPLATE’]. Each line of this message is parsed for e-mail headers such as To:, From:, Cc:, Bcc:, Subject:, and Content-Type:, which are stored in variables needed for the mail() function. The lines constituting the body of the message are stored in $messages, which is later imploded into the $body string. The $body string is searched for special tags stored in $alertInfo, which is passed to the sendAlert() function as an associative array called $info. The keys of the $info array are stored in $search using the array_keys() function, and the values are stored in $replace using the array_values() function. The $search array contains tags such as <%HOST%>, <%IP_ADDR%>, <%DISK_STATUS%>, and so on, which were inserted into $info (i.e., $alertInfo) prior to calling the sendAlert() function. These tags are replaced with their values in the $body string using the preg_replace() function. The fully expanded template body is e-mailed along with the $headers using mail(). getDiskInfo() This function returns an associative array called $info with mount points as keys and their usage percentage as values. The function is called with disk statistics as a parameter. Installing the hdmonitor tool as a cron job To set up hdmonitor.php as a cron job under Linux, do the following: 1. As root, create a symbolic link in /etc/cron.daily as follows: ln -s /path/to/hdmonitor.php For example, if you kept hdmonitor.php and hdmonitor.conf in the /usr/local/src/hdmonitor directory, you could run the following com- mands as root to create the link: cd /etc/cron.daily ln -s /usr/local/src/hdmonitor/hdmonitor.php 2. Once the symlink is created, run /etc/cron.daily/hdmonitor.php as a test. If you get an error message that hdmonitor.conf was not found, or that any of the classes were not found (class.Linux.inc.php or common_functions.php), you need to edit hdmonitor.php to change require_once(‘hdmonitor.conf’), require_once(‘class. Linux.inc.php’) , and require_once(‘common_functions.php’); to require_once(‘/path/to/hdmonitor/hdmonitor.conf’), 594 Part IV: Using PHP for Sysadmin Tasks 21 549669 ch16.qxd 4/4/03 9:27 AM Page 594 require_once(‘/path/to/hdmonitor/class.Linux.inc.php), and require_once(‘/path/to/hdmonitor/common_functions.php’), respectively. For our example case, this would be require_once(‘/usr/ local/src/hdmonitor/hdmonitor.conf’) , require_once(‘/usr/ local/src/hdmonitor/class.Linux.inc.php’) , and require_once (‘/usr/local/src/hdmonitor/common_functions.php ‘). 3. Make sure hdmonitor.php is executable. You can run chown root:root hdmonitor.* \ class.Linux.inc.php \ common_functions.php chmod 700 hdmonitor.php from the directory of the script to allow root to own and be able to exe- cute the hdmonitor scripts. If your cron daemon does not run as root, make sure you replace root:root with the appropriate user and group names that enable cron to execute the script. 4. Configure the hdmonitor.conf file to reflect what mount points you want to monitor and at what level. In addition, customize the mail template as needed. 5. Let cron run the job at the regularly scheduled time and you should receive disk alert messages when any of your mount points exceeds the $MAXSIZE limit. 6. To test your installation, you can set the $MAXSIZE limits to a very low number, which will trigger an alert the next time hdmonitor.php is run by cron. If you do not receive an alert that you expect to receive, check the var/log/cron file for possible file execute permission issues. Building a CPU Load Monitoring Utility In this section, we will develop a system load-average monitoring tool that will enable us to monitor a Linux system’s load average automatically, and when the load average exceeds a specified limit, an alert message will be sent out to administrators. We define multiple levels of alert so that an administrator can take appropriate actions based on the alert levels indicated. Like the hdmonitor script, this script requires the class.Linux.inc.php and common_functions.php classes from the phpSysInfo project, which is located at http://phpsysinfo.sourceforge.net/project. Chapter 16: Command-Line PHP Utilities 595 21 549669 ch16.qxd 4/4/03 9:27 AM Page 595 . (class.Linux.inc .php or common_functions .php) , you need to edit hdmonitor .php to change require_once(‘hdmonitor.conf’), require_once(‘class. Linux.inc .php ) , and require_once(‘common_functions .php );. the class.Linux.inc .php and common_functions .php classes from the phpSysInfo project, which is located at http://phpsysinfo.sourceforge.net/project. Chapter 16: Command-Line PHP Utilities 595 21. require_once(‘/usr/ local/src/hdmonitor/class.Linux.inc .php ) , and require_once (‘/usr/local/src/hdmonitor/common_functions .php ‘). 3. Make sure hdmonitor .php is executable. You can run chown root:root hdmonitor.* class.Linux.inc .php common_functions .php chmod