Archive for Server Administration

ImageMagick `convert` 100% CPU Usage

Plain and simple: upgrade to the latest, if necessary, and compile with the flag:

–disable-openmp

Flashy and complicated: if you’re on CentOS5, specifically, you can do what I needed to do. I needed to write a patch for a client’s network of systems. You don’t need to do that, though, unless you need OpenMP on there (which you probably don’t). Wish I’d realized that was the issue before I went hog-wild.

So if you’re running into an issue where the ‘convert’ command is using 100% of your CPU (we had it running 800% — 100% x 8 cores), try the above. Most likely, that’ll fix ‘er.

Add New Domains to Apache On Command Line

I had a need to add several domains to Apache for a client about an hour ago, and instead of copying, pasting, changing, and repeating, I opted to script it. It’s very simple (read: not secure for multiple users in production), but served my needs today beautifully. Feel free to clean it up and use it, change it, whatever.

The primary reason this is added is to show how CLI scripts can be made to wait for and accept user input. Note the use of STDOUT and STDIN in the script. This is something that I’ve found to be quite unfortunately overlooked in a lot of CLI scripts. Using this, you can make a PHP CLI script interactive, instead of requiring arguments to be passed on the command line.

Also, note that this particular script wasn’t needed for user creation, DNS, or anything of the like. Strictly for adding an Apache directive for the domain.

(The code itself is indented, but I’m learning more and more why Philip Olsen scoffed at me for installing Serendipity last year. Eventually my error in judgment shall be rectified.)


#!/usr/bin/php
<?php

if(trim(`whoami`) != 'root') die("You must be root to run this command.\n");

fwrite(STDOUT,"Domain to be added: ");
$domain = trim(fgets(STDIN));

fwrite(STDOUT,"Username to use for this domain: ");
$user = trim(fgets(STDIN));

fwrite(STDOUT,"Group to use for this domain: ");
$group = trim(fgets(STDIN));

fwrite(STDOUT,"Path to use for the web root of this domain: ");
$path = trim(fgets(STDIN));

fwrite(STDOUT,"Server administrator's email address to use: ");
$email = trim(fgets(STDIN));

echo "Writing.... ";

$newHost =<<<TXT

NameVirtualHost *:80
<VirtualHost *:80>
ServerAdmin $email
DocumentRoot $path
ServerName $domain
ServerAlias www.$domain
ErrorLog logs/$domain-error_log
CustomLog logs/$domain-access_log combined
<IfModule mod_suphp.c>
suPHP_Engine On
suPHP_ConfigPath "/etc/"
suPHP_AddHandler x-httpd-php
suPHP_AddHandler php5-script .php
suPHP_UserGroup $user $group
</IfModule>
</VirtualHost>
TXT;

file_put_contents('/etc/httpd/conf/httpd.conf',$newHost,FILE_APPEND);

echo "Done.\n";

fwrite(STDOUT,"Should I restart Apache now for the changes to take effect? (y/N) ");
if(preg_match('/^ye?s?$/i',trim(fgets(STDIN)))) {
exec('service httpd restart');
echo "Apache restarted.\n";
}

?>

PHP Network Upgrade Operation, Phase III: SQLite Compliance

The final of three planned phases of upgrades and improvements to the official worldwide PHP network is nearing a close, and this particular phase – though it was the simplest of the three – proved to be the most error-prone on our side. You can page through my communications with our army of mirror maintainers in the PHP news server archives.

First came the glitch with the Google Docs link to the application to become an official php.net mirror. After a few rather embarrassing moments – despite the fact that the same link had worked every time until now – it appeared to be resolved.

Almost simultaneously, a bug was discovered in the console we use to administer the mirrors around the world. After receiving reports from systems administrators and datacenters from all corners of the globe stating that they were, indeed, in compliance, Hannes Magnusson applied a patch which successfully corrected the issues.

Now, however, it seems that we’re pretty much back on track for a successful completion of the third upgrade phase, which means that the PHP Webmaster Team can then focus on adding new features and fixing bugs with a common target system configuration in mind. It also means that the general PHP community will reap the benefits of a better, more stable, more powerful network.

As a side note, if you love PHP and want to give a quick thanks to the folks in your country who operate the mirrors you use, please check out the list of official mirrors and visit the website of the corresponding maintainer. If it weren’t for these dedicated folks providing hardware, bandwidth, and maintenance services free-of-charge, the PHP project would probably not be nearly as successful as it is today…. and you might still be waiting for that download of PHP 3 to finish!

Finding Which php.ini Is Loaded

This is actually a throwback to the post Overriding PHP Settings, but is presented here separately due to the number of times the question is asked.

If you’re on a *NIX-based system and are trying to figure out which php.ini is being loaded by the CLI, simply run the following command:

ls -l `/bin/env php -i | grep "Loaded Configuration File" | sed 's/.*=> //g'`

If you want to edit the file right from that command, simply replace ‘ls -l’ with an editor of your choice, such as:

vi `/bin/env php -i | grep "Loaded Configuration File" | sed 's/.*=> //g'`

Script to Automate Multi-User Development Permissions In Linux: Part II

As discussed in the previous entry a few moments ago:

While deploying a large virtual server for a client, one of the obstacles they had faced with their previous setup was multi-user permissions with regard to everyone modifying files and directories with their own FTP and/or SSH accounts. Unfortunately, for reasons that won’t be divulged here (quite frankly because I don’t know), and even after I suggested alternatives such as updating policies and standard operating procedures, the client opted to continue using previous methods, but still wanted a resolution to issues they faced in their multi-developer environment.

The following simple Bash script is called directly via a cron job every fifteen minutes:


#!/bin/bash

mode='4771';

# The directory in which "multiUserPermissionsFix" resides.
dir='/danbrown/scripts/';

if ( test "`whoami`" != 'root' ); then
echo "$0 MUST be run as root!";
exit -1;
fi;

if ( test "$1" == "" ); then
echo "You must specify the base directory.";
exit -1;
fi;

if ( test "$2" == "" ); then
echo "You must specify the group ownership to set.";
exit -1;
fi;

if [ -d "$1" ]; then

echo -n "Verifying ownership and group ownership of all files.... ";
chown -R $2:$2 $1;
echo "Done.";

cd $1;

echo -n "Resetting permissions now.... ";
find . -type d -exec chmod $mode '{}' \;
# for i in `find . -type d`; do
# chmod $mode $i;
# done;
echo "Done.";

echo -n "Verifying ownership requirements.... ";
find . -type d -exec chmod o+s '{}' \;
# for i in `find . -type d`; do
# chmod o+s $i;
# done;
echo "Good.";

echo -n "Verifying group requirements.... ";
find . -type d -exec chmod g+s '{}' \;
# for i in `find . -type d`; do
# chmod g+s $i >> /dev/null 2>&1
# done;
echo "Good.";

if [ "$?" != "0" ]; then
echo "That group does not exist!";
exit -1;
fi;

echo -n "Fixing bad permissions.... ";
$dir/multiUserPermissionsFix $1;
echo "Done.";

echo "Task Complete.";

exit 0;

else

echo "That directory doesn't exist!";
exit -1;

fi;

Script to Automate Multi-User Development Permissions In Linux: Part I

While deploying a large virtual server for a client, one of the obstacles they had faced with their previous setup was multi-user permissions with regard to everyone modifying files and directories with their own FTP and/or SSH accounts. Unfortunately, for reasons that won’t be divulged here (quite frankly because I don’t know), and even after I suggested alternatives such as updating policies and standard operating procedures, the client opted to continue using previous methods, but still wanted a resolution to issues they faced in their multi-developer environment.

To address one particular issue, I wrote the following very simple Bash script and set it on a cron running every 15 minutes, dumping all errors and standard output to a black hole.


#!/bin/bash
# Name: multiUserPermissionsFix
# Mode: 0755

function usage {
echo "USAGE: $0 base_directory";
exit -1;
}

# If we didn't even bother to pass an argument to this script, die.
if ( test "$1" == "" ); then
usage;
fi;

# Set up find correctly.
export IFS=$'\n';

# If this is a valid directory, do the work.
if [ -d "$1" ]; then

# Force a trailing slash - workaround for symlinked directories, etc.
d="$1/";

# Find and fix all file permissions --- but ignore all 'cache' cases.
find . -type f -not -path "*cache*" -exec chmod 0664 '{}' \;

exit 0;

# If it wasn't a valid directory passed to this script, die on an error.
else
echo "That directory does not exist!";
exit -1;
fi;

This script is actually not called directly, but instead by a parent script. It recursively runs through all files and sets the permissions to 0664 (owner read/write, group read/write, world read) so that users within the group can update or delete the files within the directory without requiring administrative intervention.

PHP Network Upgrade Operation, Phase II: 100% PHP 5 Compliance

Well, the email from last night summarizes it appropriately:

ALL:

After the expulsion of the four non-compliant mirrors, the PHP
Network Infrastructure is now running no less than the common
distro-supplied version of 5.1.6, as outlined over the last two
months.

For those of you who put forth fantastic efforts to pull your
mirrors into compliance, we would like to thank you VERY much! And to
everyone as a whole, thanks for everything, as always. Keep up the
great work, and get ready for SQLite as a requirement, which will be
announced this month.

Thanks again!



daniel.brown@parasane.net || danbrown@php.net
http://www.parasane.net/ || http://www.pilotpig.net/

One phase remains: the addition of SQLite to all official mirrors around the world. Updates on that to follow as we near completion.

Overriding PHP Settings

Getting the following error?

Invalid command ‘php_flag’, perhaps mis-spelled or defined by a module not included in the server configuration

Well, if your host and server configuration allow it, and should you so desire, you can override some of the php.ini settings for your site (and each subdirectory within your web directory). While you can’t override PHP_INI_SYSTEM settings, there’s still a host of other settings that can be overridden while still maintaining the rest of the configuration of the system – if your server is set up to allow it. And no, n00bZ, it won’t override php.ini for the rest of the box.

To grab your php.ini and copy it to the current directory, just run this command:

cp `/bin/env php -i | grep "Loaded Configuration File" | sed 's/.*=> //g'` .

Then just edit the php.ini and save it in place. Voila! No need to restart Apache or anything.

Finding the Maximum Number of Command Line Characters

Whilst idling in EFNet #php.doc, Kalle brought up the question about maximum input length from the command line on Linux. It’s acceptable to presume that the maximum length is ~65536, as you might expect ((32 * 8)2). But how can one be sure?

A bit of code:


#!/bin/bash
i=0;
str="PHP";
len=0;
while(test "X`echo $str`" = "X$str") > /dev/null 2>1 && res=`expr "X$str" : ".*" 2>&1` && len=$res; do
i=`expr $i + 1`;
str=$str"X"$str;
done;
echo "Maximum characters allowed via command line: $len";

That’ll do, pig. That’ll do.