k4200’s notes and thoughts

Programmer side of k4200

Installing PECL GeoIP on EC2 using CheckInstall

Background

I've been working on a web service that runs on Amazon Linux (an RPM based distro specific for Amazon EC2), and recently had to install PHP GeoIP module.

You could install it by "sudo pecl install geoip" after installing gcc, make and all bunch of libraries and headers, but I didn't want to do that on our production servers.

A few options came to mind:

  1. Build from SRPM
  2. Some tool that makes RPM out of pecl package
  3. Use CheckInstall
  4. Use PRM for other distros (apparently RHEL versions have one)

Actually, I tried "pear make-rpm-spec" at first after seeing some pages like this, but apparently, it works with pear packages but not pecl ones.

So, I chose 3 because it looked easy (and turned out a bit more involved than I had expected).

Installing CheckInstall

At first, I used 1.6.2 that can be downloaded here, but it didn't compile producing the following error.

installwatch.c:3080:5: error: conflicting types for ‘scandir’
/usr/include/dirent.h:252:12: note: previous declaration of ‘scandir’ was here
installwatch.c:3692:5: error: conflicting types for ‘scandir64’
/usr/include/dirent.h:275:12: note: previous declaration of ‘scandir64’ was here
make[1]: *** [installwatch.o] Error 1
make[1]: Leaving directory `/home/ec2-user/work/checkinstall-1.6.2/installwatch'
make: *** [all] Error 2

I googled it (yes, I switched back from Bing) and found the information that the problem had been fixed in the latest source. Here are the steps.

$ git clone http://asic-linux.com.mx/~izto/checkinstall/checkinstall.git
$ cd checkinstall
$ make && sudo make install

So far so good.

Creating php-pecl-geoip using CheckInstall

This required me some trials and errors.

You need rpm-build, of course...

I've known the name for maybe 10+ years, but this was my first time to use CheckInstall.

My first attempt failed because rpm-build wasn't installed.

$ checkinstall sudo yum pecl install geoip
(snip)
Building file list... FAILED!

*** The "rpmbuild" program is not in your PATH!

*** RPM package creation aborted

Erasing temporary files...OK

That makes sense... By the way, you need to input package information like the following after executing the command:

1 -  Summary: [ This PHP extension allows you to find the location of an IP address - City, State, Country, Longitude, Latitude, and other information as all, such as ISP and connection type. For more info, please visit Maxmind's website. ]
2 -  Name:    [ php-pecl-geoip ]
3 -  Version: [ 1.0.8 ]
4 -  Release: [ 1 ]
5 -  License: [ PHP ]
6 -  Group:   [ Development/Languages ]
7 -  Architecture: [ i686 ]
8 -  Source location: [ http://pecl.php.net/get/geoip-1.0.8.tgz ]
9 -  Alternate source location: [  ]
10 - Requires: [ php ]
11 - Provides: [ php-pecl-geoip ]
sudo!

I installed rpm-build using yum and tried again. Building files by pecl looked okay, but after the compilation, the following error was displayed.

$ checkinstall sudo yum pecl install geoip
(snip)
======================== Installation successful ==========================
cp: cannot stat `//var/tmp/tmp.kARXCq4ABm/newfiles.tmp': No such file or directory

Copying files to the temporary directory...OK

Stripping ELF binaries...OK

Compressing man pages...OK

Building file list... FAILED!

I didn't know how CheckInstall works, but did a rough guess, which was, it should be a permission problem, and that was right.

And a success

The following command finished successfully.

$ sudo checkinstall yum pecl install geoip
(snip)
======================== Installation successful ==========================

Copying files to the temporary directory...OK

Stripping ELF binaries...OK

Compressing man pages...OK

Building file list...OK

Building RPM package...OK

NOTE: The package will not be installed

Erasing temporary files...OK

Deleting doc-pak directory...OK

Writing backup package...OK

Deleting temp dir...OK


**********************************************************************

 Done. The new package has been saved to

 /root/rpmbuild/RPMS/i686/php-pecl-geoip-1.0.8-1.i686.rpm
 You can install it in your system anytime using: 

      rpm -i php-pecl-geoip-1.0.8-1.i686.rpm

**********************************************************************

Modifying the package using rpmrebuild

Removing files from the package

Now, time to install it.

$ sudo rpm -i /root/rpmbuild/RPMS/i686/php-pecl-geoip-1.0.8-1.i686.rpm
	file /usr/share/pear/.depdb from install of php-pecl-geoip-1.0.8-1.i686 conflicts with file from package php-pear-1:1.9.4-4.8.amzn1.noarch
	file /usr/share/pear/.filemap from install of php-pecl-geoip-1.0.8-1.i686 conflicts with file from package php-pear-1:1.9.4-4.8.amzn1.noarch

It failed because of some file conflicts. From what I understand from the CheckInstall documantation, it reads the file I/O of the command passed as the argument (in this case "pecl install geoip") .depdb and .filemap are probably some kind of information related to installed pecl packages as the names suggest, and they must have been modified while the pecl package was being "installed" by the "checkinstall pecl install geoip" command.

If I had been creating a package to distribute, I would have spent more time to find a "better" way in terms of pecl and PHP ecosystem, but it's only for our service. Stripping those files away from the package should be enough. The problem is how?

I asked Google again and found a program called "rpmrebuild". I installed it using the package and ran the following command:

$ rpmrebuild -e -p php-pecl-geoip-1.0.8-1.i686.rpm

Then, vi was opened, where I was able to modify the spec file. I removed the files that had caused the conflicts from the %files section, and saved the buffer. The modified package was saved in $HOME/rpmbuild/RPMS//

Finally, the new package was installed successfully!

$ sudo rpm -ivh ~/rpmbuild/RPMS/i686/php-pecl-geoip-1.0.8-1.i686.rpm 
Preparing...                ########################################### [100%]
   1:php-pecl-geoip         ########################################### [100%]

One last thing that was missing was ini file that loads geoip.so. The ini file should be placed in /etc/php.d/.

I created /etc/php.d/geoip.ini like the following, restarted httpd and everything seemed working.

extension=geoip.so

That's it. You can stop here, but I wanted to include the ini file to the rpm package.

Adding a file to the package

I was looking for a way how to add files to an existing rpm package. The manual has the following simple explanation.

you need to know the specfile syntaxe ( read the RPM-HOWTO, or go to rpm.org).
Put the file on the wanted directory.
you will use rpmrebuild -e package_name. rpmrebuild will open the specfile in your favorite editor and allow you to add the wanted file in the "%files" section.

Unfortunately, this wasn't enough for an ordinary geek like me. I executed the command again and tried adding the following lines in the %files section.

%dir %attr(0755, root, root) "/etc"
%dir %attr(0755, root, root) "/etc/php.d"
%attr(0644, root, root) "/etc/php.d/geoip.ini"

And got the following error.

$ rpmrebuild -e -p php-pecl-geoip-1.0.8-1.i686.rpm 
Do you want to continue ? (y/N) y
error: File not found: /home/ec2-user/.tmp/rpmrebuild.15753/work/root/etc
error: File not found: /home/ec2-user/.tmp/rpmrebuild.15753/work/root/etc/php.d
error: File not found: /home/ec2-user/.tmp/rpmrebuild.15753/work/root/etc/php.d/geoip.ini
    File not found: /home/ec2-user/.tmp/rpmrebuild.15753/work/root/etc
    File not found: /home/ec2-user/.tmp/rpmrebuild.15753/work/root/etc/php.d
    File not found: /home/ec2-user/.tmp/rpmrebuild.15753/work/root/etc/php.d/geoip.ini
/usr/lib/rpmrebuild/rpmrebuild.sh: ERROR: package 'php-pecl-geoip-1.0.8-1.i686.rpm' build failed

Pretty understandable. But, I couldn't think of/find a good way to deal with this problem, so tried a simple workaround.

I executed the command once again. This time, I opned up a new terminal before saving the spec file and issued the following commands.

$ mkdir -d /home/ec2-user/.tmp/rpmrebuild.<process id>/work/root/etc/php.d/
$ cp /etc/php.d/geoip.ini /home/ec2-user/.tmp/rpmrebuild.<process id>/work/root/etc/php.d/

Voila. Now the ini file is in the rpm package.

It took me a few hours to get this working, so wrote this hoping this might help someone.

Conclusion(?)

This was quite a bit of work for me. I chose Amazon Linux just because it looked the default, but maybe other distros are better in terms of number of packages they provide.

Here is a "wish list" for programs that users want the packages of, and actually, somebody mentioned php-pecl-geoip, but it hasn't been pushed to their repository yet.