Using FPM to package unwieldy 3rd-party vendor packages
by actionjack on July 20, 2012 | Leave your comment
Sometimes you have a requirement to package a third-party vendors software which hasn’t been delivered in your package format of choice (let us say rpm in this case), so no problem you think, you then proceed to install it and create a rpm package from it.
9 times out of 10 this just works and works well but sometimes you will run into problems for example:
- The size of the package is greater than the rpm cpio limit of 2Gb;
- The application has a manifest that holds a checksum of the files which is stripped using a standard build;
- The are multiple CPU architectures, OS versions, test versions supported in within the package
Funnily enough I hit the jackpot and had all 3 to contend with:
- The package was 10 gig compressed and 22 gig uncompressed;
- It had a manifest file that had a checksum of every file listed (181347 of them) and refused to run unless they were valid and;
- Had to be packaged to handle 10 different situation types these situation types were scattered in different directories (there were 5266 directories);
Now I’m quite confident with my rpm-fu but this looked like could take a while and be more than a little painful so I thought what would be the fastest most convenient way to package this (insert curse word here) application with the least cost and most benefit.
Enter Effing Package Management!
If you have never heard or used Jordan Sissel’s Effing Package Management tool (https://github.com/jordansissel/fpm) before you are in for a real treat! It slices, it dices but wait! There’s more it can create packages from multiple source types e.g. dir, gem, python, deb and spit them out as rpm’s, deb’s, solaris pkg’s and even with for it! Puppet modules!
Installing FPM
Hint you will need the epel repository installed
$ yum groupinstall "Development Tools"
$ curl -L https://get.rvm.io | bash -s stable --ruby
$ source /usr/local/rvm/scripts/rvm
$ gem install fpm
Dealing with the B*tard package from Hell
What you are doing here is creating a clean copy of the application and a base application tree without the architecture specific stuff (this will depend on what format your package takes or it may not even be needed at all)
$ cd bitbucket
$ mkdir -p application/opt application-base/opt
$ rsync -av --progress /path/to/application/root/* application/opt/application
$ rsync -av --progress --exclude='*Option*' application/opt/* application-base/opt
Now the fun part
To create an unstripped noarch rpm using the stripped application-base with a dependency on libstdc++ using fpm:
To create 2 unstripped x86_64 rpms using the full application tree with all files/directories that contain OptionLowMem|OptionHighMem and OptionLowMem-Support|OptionHighMem-Support:
$ fpm -s dir -t rpm -n application-optionhighmem -v 1.0 -d application -d libstdc++ -a x86_64 -C application/ `find opt/ -name *OptionHighMem -print && find opt/ -name *OptionLowHigh-Support -print`
Both of these will produce 3 RPM’s
application-optionlowmem-1.0-1.x86_64.rpm
application-optionhighmem-1.0-1.x86_64.rpm
Now this simple example could save hours of time and effort, in the real life scenario that this was based on it saved me days even weeks of rpm spec file writing, tuning and testing.
Leave your comment