Table of Contents
In software field, whoever develops an application with Linux as its base OS will be familiar with RPM and RPM spec. In the modern growing world, it is seen that MNC's support their software products in multiple platforms. Since the code may be platform dependent, engineers are trying to create a common code base to remove the overhead of maintaining two code which is doing almost same operation. Similarly I was looking a way to create a common rpm spec file but with conditional inclusion of files in the rpm, which means, One rpm spec will create rpms but the content of the rpm varies.
To Quote an example, I was having some file which are common in both CNF and VNF, while some other files are only required in either one. So the tedious way was to maintain two spec file with some common code between these two spec. Easy way was to add conditional macro in single spec file.
Pre-Requisite
Basic Knowledge on RPM spec and RPM-build environment
Spec File with Conditional Macro
Approach 1
- A dummy spec file is created which will package three files from my own private git repo
- My aim is to deliver either pam or openssl related files to the rpm based on a condition, whereas i want to deliver Readme.md in both cases
- Below code snippet shows the same.(Step by Step Explanation is given here)
%define ROOT_DIR /root/babugeet Summary: Linux Data Hub Example Source codes Name: linux-data-hub Version: 01 Release: 2022 License: Linux Data Hub Group: Applications/LDH URL: https://github.com/babugeet Vendor : LDH BuildArch: noarch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root %description %{summary} %prep %build %install rm -rf %{buildroot} mkdir -p %{buildroot}/opt/pam # in builddir %if %{mode} == "openssl" mkdir -p %{buildroot}/opt/openssl_server cp -a %{ROOT_DIR}/openssl/server/web-server.js %{buildroot}/opt/openssl_server cp -a %{ROOT_DIR}/openssl/server/nds_2ca.pcap %{buildroot}/opt/openssl_server %endif %if %{mode} == "pam" mkdir -p %{buildroot}/opt/openssl_server cp -a %{ROOT_DIR}/pam_tutorials/basic_pam.c %{buildroot}/opt/pam cp -a %{ROOT_DIR}/pam_tutorials/simple_pam.c %{buildroot}/opt/pam %endif mkdir -p %{buildroot}/opt cp -a %{ROOT_DIR}/Readme.md /opt/ %post %clean rm -rf %{buildroot} %files %defattr(500,root,root,-) /opt/Readme.md %if %{mode} == "openssl" %attr(500,root,root) /opt/openssl_server/web-server.js %attr(500,root,root) /opt/openssl_server/nds_2ca.pcap %endif %if %{mode} == "pam" %attr(500,root,root) /opt/pam/basic_pam.c %attr(500,root,root) /opt/pam/simple_pam.c %endif
RPM Build and Verification for Approach1
- Below code snippet shows the rpm build command. It can be seen that, we are passing the key value pair using the argument --define
[root@n-server babugeet]# rpmbuild --ba Linux/rpm/rpm_condit.spec --define="mode openssl" Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.tLGbEh + umask 022 <trimmed> Processing files: linux-data-hub-01-2022.noarch Provides: linux-data-hub = 01-2022 Requires(interp): /bin/sh + cd /root/rpmbuild/BUILD + rm -rf /root/rpmbuild/BUILDROOT/linux-data-hub-01-2022.x86_64 + exit 0
- Below snippet shows the verification of the files packaged in the rpm. Since we have given openssl as the value, it can be seen that only openssl files and one common (Read me) file got packaged and not the pam files
[root@n-server babugeet]# rpm -qlp /root/rpmbuild/RPMS/noarch/linux-data-hub-01-2022.noarch.rpm /opt/Readme.md /opt/openssl_server/nds_2ca.pcap /opt/openssl_server/web-server.js
- Similarly if we use pam as the value in the argument --define, files present under the pam conditional macro, along with the Readme.md file will be packaged
Step By Step Explanation for Approach1
- In the %install section, we are using Conditional Macro "if", where we are verifying for a key value pair
- In our example, key is mode and the value can be either openssl or pam
- we are copying the files to the build root path based on the condition
%if %{mode} == "openssl"
mkdir -p %{buildroot}/opt/openssl_server
cp -a %{ROOT_DIR}/openssl/server/web-server.js %{buildroot}/opt/openssl_server
cp -a %{ROOT_DIR}/openssl/server/nds_2ca.pcap %{buildroot}/opt/openssl_server
%endif
%if %{mode} == "pam"
mkdir -p %{buildroot}/opt/openssl_server
cp -a %{ROOT_DIR}/pam_tutorials/basic_pam.c %{buildroot}/opt/pam
cp -a %{ROOT_DIR}/pam_tutorials/simple_pam.c %{buildroot}/opt/pam
%endif
- Similary in the %files section, we are using Conditional If to package it in the rpm
%files %defattr(500,root,root,-) /opt/Readme.md %if %{mode} == "openssl" %attr(500,root,root) /opt/openssl_server/web-server.js %attr(500,root,root) /opt/openssl_server/nds_2ca.pcap %endif %if %{mode} == "pam" %attr(500,root,root) /opt/pam/basic_pam.c %attr(500,root,root) /opt/pam/simple_pam.c %endif
Approach 2
- Our Requirement is to create conditional file delivery to spec, based on another conditoinal check in the build enviornemnt
- In Approach1, we passed the condition via rpm build argument --define
- In Approach2, we will be checking if there is an empty file called openssl or pam in /tmp, based on that files will be packaged
- Below shows the spec file
%define ROOT_DIR /root/babugeet Summary: Linux Data Hub Example Source codes Name: linux-data-hub Version: 01 Release: 2022 License: Linux Data Hub Group: Applications/LDH URL: https://github.com/babugeet Vendor : LDH BuildArch: noarch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root %description %{summary} %prep %build %define pam %( if [ -f /tmp/pam ]; then echo "1" ; else echo "0"; fi ) %define openssl %( if [ -f /tmp/openssl ]; then echo "1" ; else echo "0"; fi ) %install rm -rf %{buildroot} # in builddir %if %openssl mkdir -p %{buildroot}/opt/openssl_server cp -a %{ROOT_DIR}/openssl/server/web-server.js %{buildroot}/opt/openssl_server cp -a %{ROOT_DIR}/openssl/server/nds_2ca.pcap %{buildroot}/opt/openssl_server %endif %if %pam mkdir -p %{buildroot}/opt/pam cp -a %{ROOT_DIR}/pam_tutorials/basic_pam.c %{buildroot}/opt/pam cp -a %{ROOT_DIR}/pam_tutorials/simple_pam.c %{buildroot}/opt/pam %endif mkdir -p %{buildroot}/opt/ cp -a %{ROOT_DIR}/Readme.md %{buildroot}/opt %post %clean rm -rf %{buildroot} %files %defattr(500,root,root,-) /opt/Readme.md %if %openssl %attr(500,root,root) /opt/openssl_server/web-server.js %attr(500,root,root) /opt/openssl_server/nds_2ca.pcap %endif %if %pam %attr(500,root,root) /opt/pam/basic_pam.c %attr(500,root,root) /opt/pam/simple_pam.c %endif
Explanation for Approach 2
- From the above spec file, it is self explained that we are defining a variable based on the file availability on the build environment under %build section
- We are doing conditional check on the variables which are defined, based on that rpm build will package the files
RPM Build and Verification for Approach2
- An empty file /tmp/pam is present in the build machine
- Below code snippet shows, since only /tmp/pam file was present, only the pam related file along with the common Readme.md file got packaged
[root@n-server babugeet]# ls -l /tmp/pam -rw-r--r--. 1 root root 0 Nov 1 12:07 /tmp/pam [root@n-server babugeet]# rpmbuild --ba Linux/rpm/rpm_conditional_.spec Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.69jzPK + umask 022 + cd /root/rpmbuild/BUILD + exit 0 Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.ao04dk + umask 022 + cd /root/rpmbuild/BUILD + exit 0 Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.3Ui7DT + umask 022 <trimmed> + cd /root/rpmbuild/BUILD + rm -rf /root/rpmbuild/BUILDROOT/linux-data-hub-01-2022.x86_64 + exit 0 [root@n-server babugeet]# rpm -qlp /root/rpmbuild/RPMS/noarch/linux-data-hub-01-2022.noarch.rpm /opt/Readme.md /opt/pam/basic_pam.c /opt/pam/simple_pam.c