8 min read
The final rpm packaging guide
A customer required that every component of a software project I worked for is delivered as rpm.
This was problematic for Apache ActiveMQ Artemis as there is no rpm available.
But, the maintainer publishes a binary tarball and this is all we need to build an rpm.
So in this post I am going to show how to build an rpm from a tarball and explain the rpm build process in detail.
Introduction
I highly recommend to read the RPM Packaging Guide to get a basic understanding of the rpm build and packaging process.
Requirements
Lets get started by installing some dev tools.
httpie - Modern alternative to wget and curl.
sudo yum install httpie
rpmbuild - Utility to build rpms.
sudo yum install rpm-build
rpmdev - Dev utilities to build rpms.
sudo yum install rpmdevtools
rpmlint - Tool for checking common errors in rpm packages.
sudo yum install rpmlint
Test Setup
Before we setup the dev chain for the apache Artemis package, let’s get familiar with an hello world example.
Create a working dir wherever you would like.
mkdir rpmbuild
Create a symbolic to the rpmbuild
folder from the home folder.
ln -s /path/to/rpmbuild ~/rpmbuild
Add default directories to build the RPM
cd ~/rpmbuild; rpmdev-setuptree
Macro Name | Name | Location | Purpose |
---|---|---|---|
%_specdir |
Specification directory | ~/rpmbuild/SPECS |
RPM specifications (.spec ) files |
%_sourcedir |
Source directory | ~/rpmbuild/SOURCES |
Pristine source package (e.g. tarballs) and patches |
%_builddir |
Build directory | ~/rpmbuild/BUILD |
Source files are unpacked and compiled in a subdirectory underneath this. |
%_buildrootdir |
Build root directory | ~/rpmbuild/BUILDROOT |
Files are installed under here during the %install stage. |
%_rpmdir |
Binary RPM directory | ~/rpmbuild/RPMS |
Binary rpms are created and stored under here. |
%_srcrpmdir |
Source RPM directory | ~/rpmbuild/SRPMS |
Source rpms are created and stored here. |
Create spec file for the hello world example.
touch ~/rpmbuild/SPECS/hello-world.spec
And set the following content.
Name: hello-world
Version: 1
Release: 0
Summary: Most simple RPM package
License: FIXME
%description
This is my first RPM package, which does nothing.
%prep
# we have no source, so nothing here
%build
cat > hello-world.sh <<EOF
#!/usr/bin/bash
echo Hello world
EOF
%install
mkdir -p %{buildroot}/usr/bin/
install -m 755 hello-world.sh %{buildroot}/usr/bin/hello-world.sh
%files
/usr/bin/hello-world.sh
%changelog
# let skip this for now
Build the hello world rpm.
cd ~/rpmbuild; rpmbuild -ba SPECS/hello-world.spec
Install the rpm.
sudo yum install RPMS/x86_64/hello-world-1-0.x86_64.rpm -y
Run hello world.
hello-world.sh
If the installation was successful you should see now the output: hello world
.
Uninstall the hello world rpm.
sudo yum remove hello-world -y
Now the hello world command must not be available.
I assume that the hello world spec file is easy to understand. The install section might be misleading, but I will cover that in the next chapter.
Lets move with the more complex case.
Apache Artemis Spec File
Create the spec file for the apache Artemis.
touch ~/rpmbuild/SPECS/apache-artemis.spec
Navigate into the sources folder.
cd ~/rpmbuild/SOURCES
And download the apache Artemis binary.
http -d http://www.pirbot.com/mirrors/apache/activemq/activemq-artemis/2.6.4/apache-artemis-2.6.4-bin.tar.gz
Sections
The spec file has been split into multiple sections. Copy and paste the snippet for every section and read the notes carefully.
Header
##### HEADER SECTION #####
Name: apache-artemis
Version: 2.6.4
Release: 0
Summary: Rpm package for Apache ActiveMQ Artemis
License: ASL 2.0
URL: http://activemq.apache.org/artemis/
Source0: %{name}-%{version}-bin.tar.gz
Requires: shadow-utils,bash
BuildArch: noarch
%description
%{summary}
# disable debuginfo, which is useless on binary-only packages
%define debug_package %{nil}
In the header section metadata is defined for the build process and for the package itself.
Build
##### PREPARATION SECTION #####
%prep
# unpack tarball
%setup -q
##### BUILD SECTION #####
%build
# empty section
We use a tarball source, so no build step apart from unpacking the file is required. The %setup
is a macro that extracts the tarball.
Install
##### PREINSTALL SECTION #####
%pre
# create Apache Artemis service group
getent group artemis >/dev/null || groupadd -f -g 30101 -r artemis
# create Apache Artemis service user
if ! getent passwd artemis >/dev/null ; then
if ! getent passwd 30101 >/dev/null ; then
useradd -r -u 30101 -g artemis -d /home/artemis -s /sbin/nologin -c "Apache Artemis service account" artemis
else
useradd -r -g artemis -d /home/artemis -s /sbin/nologin -c "Apache Artemis service account" artemis
fi
fi
exit 0
##### INSTALL SECTION #####
%install
app_dir=%{buildroot}/opt/app/artemis
data_dir=%{buildroot}/opt/data/artemis
# cleanup build root
rm -rf %{buildroot}
mkdir -p %{buildroot}
# create app folder
mkdir -p $app_dir
# create data folder
mkdir -p $data_dir
# copy all files
cp LICENSE $app_dir
cp README.html $app_dir
cp -R bin $app_dir
cp -R lib $app_dir
cp -R schema $app_dir
cp -R web $app_dir
Here we create the Artemis service user and group and copy selected files from the build to buildroot folder.
The %install
section of an rpm spec file is not run on rpm package installation.
The %install
section is run during package creation to install the files that need to be packaged such that the rpmbuild process can package them up.
File
##### FILES SECTION #####
%files
# define default file attributes
%defattr(-,artemis,artemis,-)
# list of directories that are packaged
%dir /opt/app/artemis
/opt/app/artemis/bin/*
/opt/app/artemis/lib/*
/opt/app/artemis/schema/*
/opt/app/artemis/web/*
%dir %attr(660, -, -) /opt/data/artemis
# list of files that are packaged
%doc /opt/app/artemis/README.html
%license /opt/app/artemis/LICENSE
The %files
section lists all the files and directories that the package contains. The uninstallation process for an rpm is simply the removal of all the packaged files.
Uninstall
##### UNINSTALL SECTION #####
%postun
case "$1" in
0) # This is a package remove
# remove app and data folders
rm -rf /opt/app/artemis
rm -rf /opt/data/artemis
# remove Apache Artemis service user and group
userdel artemis
;;
1) # This is a package upgrade
# do nothing
;;
esac
If additional work needs to be done before or after the files are removed the %preun
and %postun
scriptlets are available in the spec file for that work.
Changelog
##### CHANGELOG SECTION #####
%changelog
* Wed Mar 20 2019 Janik vonRotz <contact@janikvonrotz.ch> - 2.6.4-0
- Init apache-artemis package
Every time you make change, that is, whenever version or release of the package is incremented, add a comment to the changelog section
Full Spec File
The final spec file should look like this.
##### HEADER SECTION #####
Name: apache-artemis
Version: 2.6.4
Release: 0
Summary: Rpm package for Apache ActiveMQ Artemis
License: ASL 2.0
URL: http://activemq.apache.org/artemis/
Source0: %{name}-%{version}-bin.tar.gz
Requires: shadow-utils,bash
BuildArch: x86_64
%description
%{summary}
# disable debuginfo, which is useless on binary-only packages
%define debug_package %{nil}
##### PREPARATION SECTION #####
%prep
# unpack tarball
%setup -q
##### BUILD SECTION #####
%build
# empty section
##### PREINSTALL SECTION #####
%pre
# create Apache Artemis service group
getent group artemis >/dev/null || groupadd -f -g 30101 -r artemis
# create Apache Artemis service user
if ! getent passwd artemis >/dev/null ; then
if ! getent passwd 30101 >/dev/null ; then
useradd -r -u 30101 -g artemis -d /home/artemis -s /sbin/nologin -c "Apache Artemis service account" artemis
else
useradd -r -g artemis -d /home/artemis -s /sbin/nologin -c "Apache Artemis service account" artemis
fi
fi
exit 0
##### INSTALL SECTION #####
%install
app_dir=%{buildroot}/opt/app/artemis
data_dir=%{buildroot}/opt/data/artemis
# cleanup build root
rm -rf %{buildroot}
mkdir -p %{buildroot}
# create app folder
mkdir -p $app_dir
# create data folder
mkdir -p $data_dir
# copy all files
cp LICENSE $app_dir
cp README.html $app_dir
cp -R bin $app_dir
cp -R lib $app_dir
cp -R schema $app_dir
cp -R web $app_dir
##### FILES SECTION #####
%files
# define default file attributes
%defattr(-,artemis,artemis,-)
# list of directories that are packaged
%dir /opt/app/artemis
/opt/app/artemis/bin/*
/opt/app/artemis/lib/*
/opt/app/artemis/schema/*
/opt/app/artemis/web/*
%dir %attr(660, -, -) /opt/data/artemis
# list of files that are packaged
%doc /opt/app/artemis/README.html
%license /opt/app/artemis/LICENSE
##### UNINSTALL SECTION #####
%postun
case "$1" in
0) # This is a package remove
# remove app and data folders
rm -rf /opt/app/artemis
rm -rf /opt/data/artemis
# remove Apache Artemis service user and group
userdel artemis
;;
1) # This is a package upgrade
# do nothing
;;
esac
##### CHANGELOG SECTION #####
%changelog
* Wed Mar 20 2019 Janik vonRotz <contact@janikvonrotz.ch> - 2.6.4-0
- Init apache-artemis package
Installation
Navigate to the rpm build directory
cd ~/rpmbuild
Build the rpm.
rpmbuild -ba SPECS/apache-artemis.spec
Lint the rpm.
rpmlint RPMS/x86_64/apache-artemis-2.6.4-0.x86_64.rpm
There will be thousands of error and warnings. Ignore them for now.
Install the rpm.
sudo yum install RPMS/x86_64/apache-artemis-2.6.4-0.May.rpm -y
Create a broker instance.
sudo /opt/app/artemis/bin/artemis create broker /opt/data/artemis/broker --user artemis --password artemis --require-login
Start the Artemis instance.
sudo "/opt/data/artemis/broker/bin/artemis-service" start
Open the browser to localhost:8161/console and check if you can login with artemis:artemis
.
If everything worked you can stop the service.
sudo "/opt/data/artemis/broker/bin/artemis-service" stop
And check if there is really no Artemis service running.
ps aux | grep artemis
Finally remove the package.
sudo yum remove apache-artemis -y
Disclaimer
Apache Artemis has been installed to /opt/app/artemis
and the instance has been created in /opt/data/artemis
. Note that this is not best practice. The Filesystem Hierarchy Standard tells where to put what.
Conclusion
That’s it! Lets recap what we just learned.
- First we created the rpmbuild folder structure
- Then created an example spec file for an hello world script
- Next we prepared the assets for the Apache Artemis package
- We defined the spec file for the rpm
- Following-up we installed the rpm
- Then created, started, tested and killed an Artemis instance
- Finally we uninstalled the Apache Artemis package
This is also resembles the life cycle of an rpm service.
As usual if you have any questions, concerns or inputs feel free to make a comment.
Edits
Edit 1: Upgrade
I also investigated the behavior in an upgrade scenario.
Assuming the following points apply:
- Release or version is incremented
- A file e.g. README.html has been removed
- An rpm is already installed
- Yum does an rpm install
The results are as followed:
- Yum detects the upgrade
- The README file is removed
It behaves as expected.
Edit 2: Gradle Project
I have created a gradle project to facilitate the build process.
Link: GitHub - Apache Artemis RPM
Sources
Sources I relied on to build this tutorials:
superuser - Managing service accounts in an RPM spec
packagecloud - Building RPM packages with rpmbuild
Categories: Software Configuration ManagementTags: rpm , apache , artemis , fedora , best practice , guide
Edit this page
Show statistic for this page