Create an RPM for ANYTHING
In the modern era of Sysadmining it’s fairly common to have a configuration management tool such as Puppet, Chef, Ansible, or my personal favorite Saltstack. These tools make managing your systems a simple joy compared to maintaining all your configurations independently. One area that can often be a shortcoming of all of these tools is managing software that is not packaged. Either something home brewed that you’ve whipped together to perform a task, or something that needs to be compiled from source such as python. There are way’s to manage these things but they often make life more complicated than simple.
Recently I discovered a Ruby Gem called FPM. It’s a simple tool that lets you package…well.. ANYTHING. What is particularly nice about it, is that it includes versioning. So even if you are doing something as silly as just packaging a directory, you could add an arbitrary version number to said package, and if you make a change that you want to push out later, you can update the version and the package manager on the OS will recognize that the new package should take precedence. It’s beautiful.
So how is this to be done? Well, let’s start with the install(as always I assume Centos/RHEL OS, Currently working on 7).
You will need ruby development packages, gcc, and rpm-build
yum install ruby-devel rubygems gcc rpm-build rubygems
Once that is done, you can install the gem with:
gem install -no-ri --no-rdoc fpm
Simple enough right? For usage, there is A LOT you can do, but I’ll cover just the basic concept here. Packaging a directory, for something such as python… First go through your standard configure/make/make install for python. Once that is compiled, you can simply point fpm at it and go nuts.
# fpm -s <source type> -t <target type> -n <package name> -v <package version> <source directory>=<install directory> fpm -s dir -t rpm -n python-3.6 -v 3.6.4 ~/python-3.6=/usr/local
So you may notice, we’re sourcing a directory (dir), and targeting an rpm package type. I name the python version 3.6 so that separate versions of python can co-exist without overwriting each other. After the full version is given, and then the source directory “~/python-3.6” is what will be packaged. Finally the “=” sign points to “/usr/local” this is where the package will be installed by the package manager. So if you were to issue an “rpm -i” on the final package, you would end up with a directory structure:
Later if you get a new version of python-3.6 you can update the version number, and your directory will be updated by the package manager. I now use this with my salt-master server to deploy those tricky applications that can’t normally be managed as simply as with a package.
It is worth noting that FPM supports far more than just directory to rpm, it can also do: deb’s, python modules, ruby gems, and many other formats, and can even repackage things between formats… but for my use cases I have not played around with those other options.