Friday, July 2, 2010

Installation of HP Array Configuration Utility CLI for Linux on Ubuntu 10.04 Lucid Lynx

HP Array Configuration Utility CLI for Linux (hpacucli) is a useful tool that allows you to manage your HP RAID controller from command line (via ssh, that is). It can also be used to monitor the state of the disk subsystem with tools like Nagios or Zabbix. The following controllers are supported:

  • Smart Array 5312 Controller
  • Smart Array 5302 Controller
  • Smart Array 5304 Controller
  • Smart Array 532 Controller
  • Smart Array 5i Controller
  • Smart Array 641 Controller
  • Smart Array 642 Controller
  • Smart Array 6400 Controller
  • Smart Array 6400 EM Controller
  • Smart Array 6i Controller
  • Smart Array P600 Controller
  • Smart Array P400 Controller
  • Smart Array P400i Controller
  • Smart Array E200 Controller
  • Smart Array E200i Controller
  • Smart Array P800 Controller
  • Smart Array E500 Controller
  • Smart Array P700m Contoller
  • Smart Array P410i Controller
  • Smart Array P411 Controller
  • Smart Array P212 Controller
  • Smart Array P712m Contoller
  • Smart Array B110i SATA RAID
  • Smart Array P812 Controller
  • MSA500 Controller
  • MSA500 G2 Controller
  • MSA1000 Controller
  • MSA1500 CS Controller
  • MSA20 Controller

The tool is supplied on HP Support Pack CDs, but you can download a newer version from the HP site. To install hpacucli, visit this page and download hpacucli-8.50-6.0.noarch.rpm. Now, copy it to the server you'll install it on. Next, we'll unpack the RPM file. You can do it using, for example, rpm2cpio, rpm2tgz, etc. In Ubuntu, there's a utility called alien, that can do the same:

alien --to-tgz hpacucli-8.50-6.0.noarch.rpm

alien will report some errors and warnings, but don't worry. You will now get a new file, called hpacucli-8.50.tgz.

tar -xzf hpacucli-8.50.tgz

Move the unpacked files to corresponding locations:

sudo mv opt/compaq /opt/
sudo mv usr/sbin/* /usr/sbin/
Now, if you run a i386 kernel, you can run hpacucli, which is a 32-bit program. However, if your Ubuntu is a 64-bit system, you will have to allow execution of 32-bit binaries. One of the ways to do so is to install ia32-libs package. After the installation you can run hpacucli.

hpacucli gives you a prompt where you can enter commands or you can give the commands from the shell command line, like:

$ sudo hpacucli help

or

$ sudo hpacucli ctrl all show config

Smart Array P212 in Slot 1                (sn: PACCP9SYJ067  )

   array A (SAS, Unused Space: 0 MB)


      logicaldrive 1 (419.2 GB, RAID 1, OK)

      physicaldrive 1I:1:1 (port 1I:box 1:bay 1, SAS, 450 GB, OK)
      physicaldrive 1I:1:2 (port 1I:box 1:bay 2, SAS, 450 GB, OK)

   Expander 250 (WWID: 50014380065D7410, Port: 1I, Box: 1)

   Enclosure SEP (Vendor ID HP, Model DL18xG6BP) 248 (WWID: 50014380065D7423, Port: 1I, Box: 1)

   SEP (Vendor ID PMCSIERA, Model  SRC 8x6G) 249 (WWID: 50014380069159CF)

A similar command will give you even more information on the state of your RAID:

$ sudo hpacucli ctrl all show config detail

Now you can use this plugin to monitor the state of the array in Nagios. Besides, the information from hpacucli helped me to identify the causes of the significantly degraded performance of one of my servers (the battery of the write-cache was dead).

Tuesday, June 29, 2010

logrotate: rotating logs in multiple directories

I've got a server with almost one hundred web-sites. Each of the sites is in its own directory and runs its own logs in /usr/local/www/SITENAME/logs/*.log. When the logs grew up, I decided to set up logrotate. Since there were so many web-sites, my first idea was to create one configuration file for every site in logrotate.d and leave just one line in logrotate.conf:

include /usr/local/etc/logrotate.d

Only one hour later I understood that I can just write a path with multiple meta-characters to include ALL logs in just one line:

/usr/local/www/*/logs/*.log {
    daily
    rotate 60
    compress
    notifempty
    postrotate
          [ ! -f /var/run/nginx.pid ] || kill -USR1 `cat /var/run/nginx.pid`
    endscript

}

Thursday, June 24, 2010

PINBA: PHP Is Not a Bottleneck Anymore

Yesterday I installed Pinba on one of my servers. Pinba is a set of tools to monitor performance of PHP scripts. Pinba MySQL database engine runs a list of timers and automatically fills report databases. Pinba PHP extension uses two functions to open and close these timers. Besides, there are default timers, which open when a script is executed and close when it finishes. If you put a timer around some critical piece of code you can get information on how often it runs and how much time it is being executed. Timers can be tagged and the data can be grouped by tags. So, in some pieces of code you can set tags "author" and "task" with corresponding values. Then you'll manage to compare the performance of code written by different developers and identify the most time-consuming parts. The most interesting thing is that when you create database tables following certain rules, these tables become automagically filled with the necessary data. So, if you use the tags "author" and "tags" to group the data, the reports will include all valid combinations of these tags and show summaries on these combinations: how much time Joe's scripts parsed new documents and how often Jackie's front-end scripts were called. Very impressive.

By default, Pinba stores this information for some limited period of time (15 minutes, IIUC), so you need some way to make the data persistent. Since we use Munin to monitor various system indicators, I wrote a couple of plugins (in TCL and Lua, just for fun :)) to display the frequency of execution and the average execution time for each timer. Our developers added a handful of timers in various places of code and here it is:

The last graph looks cluttered and not too informative, so I plan to employ Munin's 'suggest' feature to draw some diagrams using one script. Perhaps, organizing the graphs will be the most difficult part of the deployment. I have to say, though, that the installation was not simple, either. Prerequisites include compiled sources of the installed MySQL (Percona Server 10.2 in my case), Google Protocol Buffers, Judy library, libevent 1.4.1+ (Ubuntu's default one will do) and Hoard memory allocator. And here is the installation process (paths will be different for you, so check carefully):

wget http://pinba.org/files/pinba_engine-0.0.5.tar.gz
tar -xzf pinba_engine-0.0.5.tar.gz
wget http://pinba.org/files/pinba_extension-0.0.5.tgz
tar -xzf pinba_extension-0.0.5.tgz
wget http://protobuf.googlecode.com/files/protobuf-2.3.0.tar.gz
tar -xzf protobuf-2.3.0.tar.gz
wget http://downloads.sourceforge.net/project/judy/judy/\
Judy-1.0.5/Judy-1.0.5.tar.gz?use_mirror=ignum
tar -xzf Judy-1.0.5.tar.gz
wget http://www.cs.umass.edu/%7Eemery/hoard/hoard-3.8/source/hoard-38.tar.gz
tar -xzf hoard-38.tar.gz
sudo aptitude install libevent-1.4-2 libevent-dev
cd protobuf-2.3.0
./configure
make -j
sudo make install
cd ../judy-1.0.5/
./configure
make
sudo make install
cd ../hoard-38/src
make linux-gcc-x86-64
sudo cp libhoard.so /usr/local/lib
sudo cp *.h /usr/local/include
sudo ldconfig
cd pinba_engine-0.0.5/
./configure --with-mysql=/home/minaev/Percona-Server-10.2/ \
--with-judy=/usr/local --with-protobuf=/usr/local \
--with-event=/usr --libdir=/usr/lib/mysql/plugin/ \
--with-hoard=/usr/local
make 
sudo make install
echo "INSTALL PLUGIN pinba SONAME 'libpinba_engine.so'"|mysql
echo "CREATE DATABASE pinba"|mysql
mysql -D pinba <default_tables.sql
cd pinba-0.0.5/
sed -i 's/NOTICE/CHECKING/' config.m4
phpize
./configure --with-pinba=/usr/local
sudo make install

I had to edit config.m4 because my version autoconf was a bit buggy. After this process you'll have to add three lines to your php.ini:

extension=pinba.so
pinba.enabled=1
pinba.server=[MySQL server address]

And here is one of Munin plugins, written in TCL. It collects data on how often certain API parts were called.

#!/usr/bin/tclsh

package require mysqltcl 3.05


proc clean_fieldname arg {
    return [regsub -all {[^A-Za-z]} $arg "_"]
}

set dbuser "pinba"
set db "pinba"

set conn [::mysql::connect -user $dbuser -db $db]

set fields [::mysql::sel $conn 
  "select concat(module_value, '+', action_value) from \
tag_info_module_action" -list]

if {$argc > 0} {
    switch [lindex $argv 0] {
        "config" {
            puts "graph_title PHP Actions per second"
            puts "graph_vlabel reqs per second"
            puts "graph_category Pinba"
            foreach fld $fields {
                set clean [clean_fieldname $fld]
                 puts "$clean.label $fld"
                 puts "$clean.draw LINE3"
            }
        }
        "autoconf" {
            puts "yes"
        }
    }
} else {
    foreach fld $fields {
        set clean [clean_fieldname $fld]
        set data [::mysql::sel $conn 
  "select req_per_sec from tag_info_module_action where \
  concat(module_value, '+', action_value)='$fld'" -list]
        puts "$clean.value $data"
    }
}

::mysql::close $conn

BTW, you may find it interesting that the performance of TCL scripts was almost the same as that of Lua scripts and about 3-4 times higher than for Bash.

Tuesday, June 15, 2010

Dark sides of Python

While reading about Python and playing around with its objects and classes (OOP being a perversions in itself), I witnessed a slightly weird behaviour. Define a class with a class variable.

class Parent:
  variable = "parent 1"

Then define a descendant class that inherits the class variable:

class Child(Parent):
  pass

(That funny single pass stands for empty definition body) Now, let's have a look at the value of variable in Parent and Child:

print Parent.variable
parent 1
print Child.variable
parent 1

Then, change the value of the variable in the parent class and it should also change in the child class:

Parent.variable = "parent 2"
print Parent.variable
parent 2
print Child.variable
parent 2

Sounds good. The variable must be shared between the two classes. Now, let's change the value of this allegedly shared variable in the child class:

Child.variable = "child 1"
print Parent.variable
parent 2
print Child.variable
child 1

Quite of a sudden, the variable turns out to be two separate variables. We have somehow broke the link that connected them and now, even if we change the value of the variable in Parent, this will not affect the variable in Child anymore:

Parent.variable = "parent 3"
print Parent.variable
parent 3
print Child.variable
child 1

And how a language with such non-trivial idiosyncrasies can be promoted as newbie-friendly, "does-what-you-want" language? My interest to Python evaporates so fast that I will probably never get to the famous included "batteries".

Tuesday, May 4, 2010

Errors when installing PHP 5.3 with FPM on Ubuntu

If you try to install PHP 5.3 with FPM on Ubuntu, no matter which installation path you follow, patching sources or downloading FPM from SVN, you will most likely see a lot of error messages similar to the following:

$ ./configure 
cat: confdefs.h: No such file or directory
./configure: 490: ac_fn_c_try_run: not found
./configure: 490: 5: Bad file descriptor    
./configure: 490: :: checking for pthreads_cflags: not found
./configure: 490: 6: Bad file descriptor                    
./configure: 490: checking for pthreads_cflags... : not found
cat: confdefs.h: No such file or directory                   
./configure: 490: ac_fn_c_try_run: not found                 
cat: confdefs.h: No such file or directory                   
./configure: 490: ac_fn_c_try_run: not found                 
cat: confdefs.h: No such file or directory                   
./configure: 490: ac_fn_c_try_run: not found                 
cat: confdefs.h: No such file or directory                   
./configure: 490: ac_fn_c_try_run: not found                 
cat: confdefs.h: No such file or directory                   
./configure: 490: ac_fn_c_try_run: not found                 
cat: confdefs.h: No such file or directory                   
./configure: 490: ac_fn_c_try_run: not found                 
cat: confdefs.h: No such file or directory                   
./configure: 490: ac_fn_c_try_run: not found                 
cat: confdefs.h: No such file or directory                   
./configure: 490: ac_fn_c_try_run: not found                 
./configure: 492: 5: Bad file descriptor                     
./configure: 492: :: result: : not found                     
./configure: 492: 6: Bad file descriptor                     
./configure: 492: : Permission denied                        
./configure: 495: 5: Bad file descriptor                     
./configure: 495: :: checking for pthreads_lib: not found    
./configure: 495: 6: Bad file descriptor                     
./configure: 495: checking for pthreads_lib... : not found   
cat: confdefs.h: No such file or directory                   
./configure: 555: ac_fn_c_try_run: not found                 
cat: confdefs.h: No such file or directory                   
./configure: 555: ac_fn_c_try_run: not found                 
cat: confdefs.h: No such file or directory                   
./configure: 555: ac_fn_c_try_run: not found                 
./configure: 557: 5: Bad file descriptor                     
./configure: 557: :: result: : not found                     
./configure: 557: 6: Bad file descriptor                     
./configure: 557: : Permission denied                        
./configure: 633: 5: Bad file descriptor                     
./configure: 633: :: result: : not found                     
./configure: 633: 6: Bad file descriptor                     
./configure: 633: : Permission denied                        
./configure: 635: 5: Bad file descriptor                     
./configure: 635: :: result: Configuring SAPI modules: not found
./configure: 635: 6: Bad file descriptor                        
./configure: 635: Configuring SAPI modules: not found           
./configure: 666: 5: Bad file descriptor

If so, don't be a fool like me, check what buildconf reported above:

$ ./buildconf --force                                                                                                          
Forcing buildconf                                                                                                                                       
buildconf: checking installation...                                                                                                                     
buildconf: autoconf version 2.64 (ok)                                                                                                                   
buildconf: Your version of autoconf likely contains buggy cache code.                                                                                   
           Running vcsclean for you.                                                                                                                    
           To avoid this, install autoconf-2.13.                                                                                                        
Can't figure out your VCS, not cleaning. 

This is not just a regular warning you can neglect, you have to use autoconf-2.13. You don't have to install it from sources, though. This version is a separate package, so just run sudo aptitude install autoconf-2.13. You will have also to install libevent-1.4 and libevent-dev. Now, you can run buildconf again and then configure.

The full installation procedure would be:

sudo apt-get install autoconf2.13
wget http://ru.php.net/get/php-5.3.2.tar.bz2/from/ru2.php.net/mirror
tar -xjf php-5.3.2.tar.bz2
sudo aptitude install libevent-dev
cd php-5.3.2/
svn co http://svn.php.net/repository/php/php-src/trunk/sapi/fpm sapi/fpm
./buildconf --force
./configure --enable-fpm --with-zlib \
--enable-pdo --with-pdo-mysql --enable-sockets \
--with-mysql --with-config-file-path=/etc \
--enable-calendar --with-iconv --enable-exif\
 --enable-soap --enable-ftp --enable-wddx \
--with-zlib --with-bz2 --with-gettext \
--with-xmlrpc --enable-pcntl --enable-soap \
--enable-bcmath --enable-mbstring --enable-dba \
--with-openssl --with-mhash --with-mcrypt \
--with-xsl --with-curl --with-pcre-regex 
--with-gd --enable-gd-native-ttf --with-ldap \
--enable-pdo --with-pdo-mysql --with-mysql \
--with-sqlite --with-pdo-sqlite --enable-zip \
--enable-sqlite-utf8 --with-pear \
--with-freetype-dir=/usr --with-jpeg-dir=/usr \
--with-mysqli --with-fpm-conf=/etc/php/php-fpm.conf \
--with-fpm-pid=/var/run/php-fpm.pid \
--with-config-file-path=/etc/php/ \
--with-config-file-scan-dir=/etc/php/conf.d/

Of course, your php configure options can be different.

Wednesday, April 28, 2010

Naïve question

Been installing FineReader under Windows today. The question is why does installation process pause when I click'n'hold on the window title bar to move it? No reply...

Wednesday, April 21, 2010

Split screen vertically. You won't find it in `man screen`

Now I know what `serendipity' means. It's when you are not quite awake, sit at the keyboard, your fingers fumble and you suddenly see that your xterm window where `screen' is running, gets split in two, but not horizontally (one above another), as it should according to the documentation, but vertically (one beside another). I didn't even understand what keys I pressed to get this effect. `man screen' includes only familiar `split' command. It took me some time to google out the answer.

It turns out that this feature was included in `screen' quite some time ago, but somehow nobody cared to describe it in man. Pressing `C-a |' splits the screen in left and right regions. To get rid of one of the regions, use the usual `C-a X' or `C-a S'.