23 October 2014
I have been doing some work with Cloudera Hadoop recently, and as part of building a cluster I took the opportunity to automated it using Puppet.
For Cloudera, pretty much all of the setup is done via RPMs and config files, which are easily deployed with Puppet, but there was one initial step that did not have an RPM available - the specific Java version that needs to be installed.
Java is available as a download from Oracle as a tar.gz file - you can extract the tar file anywhere on your system and point your PATH at the extract and Java will work. I decided it would be interesting to turn the tar file downloaded from Oracle into an RPM that is easily deployed from Puppet.
Building an RPM is pretty simple using the rpmbuild command. By default, there is a directory structure in /root/rpmbuild
and inside it are several directories:
BUILDROOT is interesting - imagine it is like an empty root file system. If you need to compile source code as part of your RMP build (using the traditional configure, make, make install sequence), you should set the --prefix parameter to configure $RPM_BUILD_ROOT/usr/local - in this way, your package will be installed into $BUILD_ROOT/usr/local and will not affect anything else installed on your machine.
When the RPM is built, rpmbuild will grab all the files inside $RPM_BUILD_ROOT and strip the $RPM_BUILD_ROOT off, leaving you with an RPM that puts the files in the correct place.
Hadoop wants Java to be installed in /usr/java, eg:
/usr/java/jdk-7u55-linux-x64
With a symlink /usr/java/default
pointing at the active Java version.
The spec file is where you outline how to turn your sources into a working build, and also list out the files that should be included in the RPM. Create the file jdk-7u55-linux-x64.spec in the SPECS directory containing:
Summary: Java JDK
Name: javajdk
Version: 1.7.0
Release: 55
Group: Software Development
Distribution: Java 7 for RedHat Linux
Vendor: Oracle
Packager: Stephen ODOnnell
License: GPL
# Skip autogenerating RPM dependencies
AutoReqProv: no
%description
Java JDK packaged as an RPM
%prep
rm -rf $RPM_BUILD_DIR/jdk%{version}_%{release}
rm -rf $RPM_BUILD_ROOT/*
tar zxf $RPM_SOURCE_DIR/jdk-7u55-linux-x64.tar.gz -C $RPM_BUILD_DIR
%build
%install
mkdir -p $RPM_BUILD_ROOT/usr/java
cp -r $RPM_BUILD_DIR/jdk%{version}_%{release} $RPM_BUILD_ROOT/usr/java/
%files
/usr/java/jdk%{version}_%{release}
%post
ln -s /usr/java/jdk%{version}_%{release} /usr/java/default
The prep step simply untars the source code and copies it intop the BUILD_DIR.
Normally the build step is where you would compile the source using make etc, but in this case that isn't necessary.
The install step is generally where you would run the make install command, but in this case, we just copy the contents of the BUILD_DIR into the BUILD_ROOT.
The files step gathers up all the files you want to be included in the RPM - notice that you do not include the RPM_BUILD_ROOT prefix at the start of file paths - rpmbuild is smart enough to know where to file the files.
The final step in this RPM is the post step - this is executed at the end of RPM installation and creates the symlink we require.
$ cd /root/rpmbuild/SPECS
$ rpmbuild -ba jdk-7u55-linux-x64.spec
The resulting RPM will be generated in /root/rpmbuild/RPMS/x86_64/javajdk-1.7.0-55.x86_64.rpm
and can be installed as usual:
rpm -ivh /root/rpmbuild/RPMS/x86_64/javajdk-1.7.0-55.x86_64.rpm