Building a RPM for startup script on Linux

Lately, there comes a need where needed to configure a sysemctl startup script for stop and start of services on Linux servers. Usually, oracle services come with high availability and cluster-based services which provides this similar capability but in cases where we don't have this capability, we as an administrator may need to understand how to perform such operations. Now systemctl services can be created easily but if one wants to package that as an rpm and deploy on the various services we can use the following steps. 


RPM stands for Red Hat Package Manager. It was developed by Red Hat and is primarily used on Red Hat-based Linux operating systems. These packages come up with a .rpm extension and use the following format:


                    <name>-<version>-<release>.<arch>.rpm


Each of these components is critical and will be tied up together as we create the package in the coming section of this blog.

To build an RPM we first need to create the following directory structure where every directory has its significance. 


    rpmbuild/     
    ├── BUILD     ├── RPMS     ├── SOURCES     ├── SPECS 

    └── SRPMS 

Let's discuss in more detail the directory structure 

BUILD directory is used during the build process of the RPM package. This is where the temporary files are stored, moved around, etc.

RPMS directory holds RPM packages built for different architectures and noarch if specified in .spec file or during the build. This will hold the resultant package created and to be used for consumption. 

SOURCES directory, as the name implies, holds sources. This can be a simple script, a complex C project that needs to be compiled, a pre-compiled program, etc. Usually, the sources are compressed as .tar.gz or .tgz files.

SPEC directory contains the .spec files. The .spec file defines how a package is built. More details in coming sections on this.

SRPMS directory holds the .src.rpm packages. A Source RPM package doesn't belong to architecture or distribution. The actual .rpm package build is based on the .src.rpm package.


There is a utility named rpmdev-setuptree which can be made available by installing rpmdevtools. This will create the directory structure needed to build RPM and we have to place the necessary files in SPEC and SOURCES folder.


To create a systemd startup script we need to first create a unit file of that component which will be used to stop and start the component. One sample unit file is shown below:


    [Unit]

    Description=Component System D

    After=network.target local-fs.target sssd.service


    [Service]

    Type=forking

    User=oracle

    Group=oinstall

    LimitNOFILE=131072

    LimitNPROD=131072

    LimitCORE=infinity


    ExecStart=<path>/<startup_script>.sh start

    ExecStop=<path>/<stop_script>.sh stop

    TimeoutStartSec=200

    TimeoutStopSec=100


    [Install]

    WantedBy=multi-user.target


Kindly note startup_script.sh and stop_script.sh are two shell scripts that will be used by this systemd service for stopping and starting the services respectively. They must also be available at the specified path. This stop/start script can also be packaged into the same rpm along with the unit file.

The next step is to create a file and place that into the SOURCES directory which as we mentioned earlier in the source code of this RPM. 


Now here is one catch we have to create a tar file with the same as specified in the specification file like

    <Name>-<Version>-<Release>.tar.gz


Here <Name> is the name of the package specified in a specification file

        <Version> is the version of the package specified in a specification file

        <Release> is the release version of the package-specific in the specification file.


Also, make sure within this tar file directory structure remains the same as that you want to unpack on the server. For example, let's say here

    Name: oraclestartup

    Version: 0.0.1

    Release: 1


 Two scripts needs to be unpacked like component.service in directory /user/lib/systemd/system and startup.sh to be copied under /opt. In this case tar file must look like


    oraclestartup-0.0.1-1/opt/startup.sh

    oraclestartup-0.0.1-1/user/lib/systemd/system/component.service

    tar -zcvf oraclestartup-0.0.1-1.tar.gz oraclestartup-0.0.1-1

    cp raclestartup-0.0.1-1.tar.gz ~/SOURCES/


The above source code will unpack the unit service file in systemd and startup shell script under /opt which is needed for the systemctl service to run properly.

Now since our source code is ready now it's time to build the specification file.


The specification file comes up with .spec extension and it is better to create with the same name as the name used in the specification file for the rpm. For example in this case it's oraclestartup.spec. Specification file template can also be created using utility rpmdev-newspec <file_name>. 


    BuildArch:     noarch

    Name:             oraclestartup

    Version:          0.0.1

    Release:         1

    License:        None

    Group:            None

    Summary:        Prerequisites for oracle startup installation

    Source0:          %{name}-%{version}-%{release}.tar.gz

    %description

    Package to deploy oraclestartup script

    

    %prep

    %setup -n  ccc


    %install

    rm -rf $RPM_BUILD_ROOT

    install -d -m 755 $RPM_BUILD_ROOT/%{name}-%{version}-%{release}

    cp -R %{_builddir}/%{name}-%{version}-%{release}/* $RPM_BUILD_ROOT


    %files

    %attr(0700, oracle, oinstall) "/opt/startup.sh"

    %attr(0644, root, root) "/usr/lib/systemd/system/component.service"


    %pre -p /bin/sh

    if [[ ! -d /opt ]]; then

        echo "Directory /opt does not exists can not install rpm" >&2

        return 1    

    fi

    

    %post -d /bin/sh

    if [[ $1 = 1 ]]; then

        systemctl enable pmcd

        systemctl enable pmlogger

        systemctl start pmcd

        systemctl start pmlogger

    fi

    systemctl daemon-reload

    %preun -p /bin/sh

    %postun -p /bin/sh

    systemctl daemon-reload

    

    %changelog

    * Thu Apr 15 2022 Arpit Agrawal <example.co.in>

    - Initial release


Now it's time to build the package as our source code and specification files are ready. For this, we will use rpmbuild.


    rpmbuild -bb ~rpmbuild/SPECS/oraclestartup.spec


This will create the RPM file named  <name>-<version>-<release>.<arch>.rpm and can be used for consumption. In order to install the RPM package we can use:


    sudo rpm -ivh ~rpmbuild/RPMS/noarch/<name>-<version>-<release>.<arch>.rpm


In some organizations where we may need to sign the RPM and it can be done using the following command.


    rpm --addsign <name>-<version>-<release>.<arch>.rpm


If someone wants to check whether packages is already signed


    rpm --checksig <name>-<version>-<release>.<arch>.rpm


In some cases where you have to build another rpm, a yum repository may still show the old version. In this case, we may need to clean metadata.


    yum --enablerepo-<reponame> clean metadata

    yum clean all



Comments

Popular posts from this blog

How to Solve - "WAIT FOR EMON PROCESS NTFNS"

Query Regression - "OR" Transformation Oracle 19c

ORA - 12537: TNS: connection closed