Building an RPM for the Oracle database on Oracle Linux 7

Thinking about automation a lot, especially in the context of cloud computing, I have decided to create a small series of related posts that hopefully help someone deploying environments in a fully automated way. As my colleague @fritshoogland has said many times: the only way to deploy database servers (or any other server for that matter) in a consistent way, is to do it via software. No matter how hard you try to set up 10 identical systems manually, there will be some, maybe ever so subtle, differences between them. And with the cloud you probably have 42 systems or more to deal with! In this context, my first post could be a building block: the provisioning of the Oracle RDBMS the form of an RPM.

The idea

In a nutshell, I would like to

  • Create a “golden image” of my database installation
  • Make this available for deployment via NFS
  • Create an RPM that allows me to deploy the “golden image” on the server I want to install and call clone.pl to complete the process
  • Execute the root scripts (orainstRoot.sh, root.sh)

This is actually quite easy to do! The oracle-validated RPM, and nowadays oracle-rdbms-server-release-preinstall.x86_64 packages simplify the task greatly as they can pull in dependent packages, set sensible default parameters and generally perform a lot of the tedious setup work for you. All I have to do in my RPM is to enforce the version of the system is Oracle Linux 7 and pull the preinstall RPM in if not yet installed. Since there is no more 12c RDBMS server for i686 this entire post implicitly is about Linux x86-64.

The Implementation

I am using a development system (linuxdev in this example) to build the RPM. It’s an Oracle Linux 7.2 system with all upgrades up to 24/10/2016. The first thing to do is to install the RPM dev tools and their dependencies. As always, you use yum to do so.

[root@linuxdev ~]# yum info rpmdevtools
Loaded plugins: ulninfo
Available Packages
Name        : rpmdevtools
Arch        : noarch
Version     : 8.3
Release     : 5.0.1.el7
Size        : 96 k
Repo        : ol7_latest/x86_64
Summary     : RPM Development Tools
URL         : https://fedorahosted.org/rpmdevtools/
Licence     : GPLv2+ and GPLv2
Description : This package contains scripts and (X)Emacs support files to aid in
            : development of RPM packages.
            : rpmdev-setuptree    Create RPM build tree within user's home directory
            : rpmdev-diff         Diff contents of two archives
            : rpmdev-newspec      Creates new .spec from template
            : rpmdev-rmdevelrpms  Find (and optionally remove) "development" RPMs
            : rpmdev-checksig     Check package signatures using alternate RPM keyring
            : rpminfo             Print information about executables and libraries
            : rpmdev-md5/sha*     Display checksums of all files in an archive file
            : rpmdev-vercmp       RPM version comparison checker
            : spectool            Expand and download sources and patches in specfiles
            : rpmdev-wipetree     Erase all files within dirs created by rpmdev-setuptree
            : rpmdev-extract      Extract various archives, "tar xvf" style
            : rpmdev-bumpspec     Bump revision in specfile
            : ...and many more.

[root@linuxdev ~]# yum install rpmdevtools

...

The development tools contain a lot of useful scripts, one of them I consider essential: rpmdev-setuptree. It sets up the relevant directory structure. Granted, the rpmdev tools are geared towards compiling software from their source, optionally apply patches and then create SRPMs and RPMs. RPM wasn’t designed for the purpose of packaging an Oracle database, but it can still be made to work. You can work around the size restriction using the %post hook in the SPEC file, as you will see later in this post. But I’m getting ahead of myself.

First I’m creating the RPM tree structure:

[oracle@linuxdev ~]$ rpmdev-setuptree
[oracle@linuxdev ~]$ ls -l rpmbuild/
total 0
drwxr-xr-x 2 oracle oinstall 6 Oct 24 10:50 BUILD
drwxr-xr-x 2 oracle oinstall 6 Oct 24 10:50 RPMS
drwxr-xr-x 2 oracle oinstall 6 Oct 24 10:50 SOURCES
drwxr-xr-x 2 oracle oinstall 6 Oct 24 10:50 SPECS
drwxr-xr-x 2 oracle oinstall 6 Oct 24 10:50 SRPMS
[oracle@linuxdev ~]$

Using another tool named rpmdev-newspec I create a new, empty SPEC file:

[oracle@linuxdev SPECS]$ rpmdev-newspec oracle_12102_jul16_psu_ojvm.spec
oracle_12102_jul16_psu_ojvm.spec created; type minimal, rpm version >= 4.11.
[oracle@linuxdev SPECS]$ ls -lrt
total 4
-rw-r--r-- 1 oracle oinstall 338 Oct 24 10:53 oracle_12102_jul16_psu_ojvm.spec
[oracle@linuxdev SPECS]$

Completing the SPEC file is easy if you know how to :) To save you the pain I put a stub together that is far from perfect, but should give you an idea. This is just a demo, the code especially lacks all (error, space, etc) checking which really should be in.

[oracle@linuxdev SPECS]$ cat oracle_12102_jul16_psu_ojvm.spec
Name:           oracle_12102_jul16_psu_ojvm
Version:        0
Release:        1%{?dist}
Summary:        a spec file for Oracle 12.1.0.2 with patch 23615289 (combo for 23054246 and 23177536)
Group:          Application/Databases
License:        Commercial
URL:            https://martincarstenbach.wordpress.com/
Requires:       oraclelinux-release >= 7:7.0, oracle-rdbms-server-12cR1-preinstall

%description
Oracle 12.1.0.2 EE patched with the July 2016 PSU and OJVM patch
Requires Oracle Linux 7, depends on the preinstall RPM to set up users, groups and defaults

ONLY A PROTOTYPE, USED FOR DEMONSTRATION PURPOSES ONLY

%files
%defattr(-,root,root,-)

%post
ORACLE_HOME=/u01/app/oracle/product/12.1.0.2/dbhome_1

if [ -d "$ORACLE_HOME" ]; then
        /usr/bin/echo "ORACLE_HOME directory $ORACLE_HOME exists-aborting";
        exit 127
fi

/usr/bin/echo "cloning the oracle home now to $ORACLE_HOME"
/usr/bin/mkdir -p $ORACLE_HOME

/usr/bin/umount /mnt
/usr/bin/mount -t nfs linuxdev:/u01/nfs_export /mnt

/usr/bin/tar --gzip -xf /mnt/oracle/12.1.0.2/oracle_12102_jul16_psu_ojvm.tar.gz -C $ORACLE_HOME

/usr/bin/chown -R oracle:oinstall /u01

/usr/bin/su - oracle -c "cd $ORACLE_HOME/clone/bin && ./clone.pl ORACLE_HOME=$ORACLE_HOME ORACLE_BASE=/u01/app/oracle -defaultHomeName"

/u01/app/oraInventory/orainstRoot.sh
$ORACLE_HOME/root.sh

umount /mnt

%changelog
* Mon Oct 24 2016 Martin Bach 
- initial version

Again, at the risk of repeating myself, this is just a stub and needs to be extended to include error handling and other things that we consider good coding practice. You also should check if there is sufficient space in the $ORACLE_HOME directory etc… you get the idea. Also, if you create another SPEC file for a 12c installation you currently can’t install a new Oracle Home as the path is hard coded to dbhome_1.

The script – which is the part in the %post section – is so simple it should be self-explanatory. It will be passed to /bin/sh and executed as part of the installation process.

With the SPEC file in place you can try and build the RPM. Funny enough, the rpmbuild tool is used for that:

[oracle@linuxdev SPECS]$ rpmbuild -ba oracle_12102_jul16_psu_ojvm.spec
Processing files: oracle_12102_jul16_psu_ojvm-0-1.el7.x86_64
Provides: oracle_12102_jul16_psu_ojvm = 0-1.el7 oracle_12102_jul16_psu_ojvm(x86-64) = 0-1.el7
Requires(interp): /bin/sh
Requires(rpmlib): rpmlib(FileDigests) <= 4.6.0-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1 rpmlib(CompressedFileNames) <= 3.0.4-1
Requires(post): /bin/sh
Checking for unpackaged file(s): /usr/lib/rpm/check-files /home/oracle/rpmbuild/BUILDROOT/oracle_12102_jul16_psu_ojvm-0-1.el7.x86_64
Wrote: /home/oracle/rpmbuild/SRPMS/oracle_12102_jul16_psu_ojvm-0-1.el7.src.rpm
Wrote: /home/oracle/rpmbuild/RPMS/x86_64/oracle_12102_jul16_psu_ojvm-0-1.el7.x86_64.rpm
Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.4xSozZ
+ umask 022
+ cd /home/oracle/rpmbuild/BUILD
+ /usr/bin/rm -rf /home/oracle/rpmbuild/BUILDROOT/oracle_12102_jul16_psu_ojvm-0-1.el7.x86_64
+ exit 0

This command has created a Source RPM, and the RPM file to be used, as you can see here:

[oracle@linuxdev SPECS]$ ls -l ../RPMS/x86_64/
total 4
-rw-r--r-- 1 oracle oinstall 2832 Oct 26 16:24 oracle_12102_jul16_psu_ojvm-0-1.el7.x86_64.rpm
[oracle@linuxdev SPECS]$ rpm -qpil  --requires ../RPMS/x86_64/oracle_12102_jul16_psu_ojvm-0-1.el7.x86_64.rpm
Name        : oracle_12102_jul16_psu_ojvm
Version     : 0
Release     : 1.el7
Architecture: x86_64
Install Date: (not installed)
Group       : Application/Databases
Size        : 0
License     : Commercial
Signature   : (none)
Source RPM  : oracle_12102_jul16_psu_ojvm-0-1.el7.src.rpm
Build Date  : Wed 26 Oct 2016 16:24:02 BST
Build Host  : linuxdev.example.com
Relocations : (not relocatable)
URL         : https://martincarstenbach.wordpress.com/
Summary     : a spec file for Oracle 12.1.0.2 with patch 23615289 (combo for 23054246 and 23177536)
Description :
Oracle 12.1.0.2 EE patched with the July 2016 PSU and OJVM patch
Requires Oracle Linux 7, depends on the preinstall RPM to set up users, groups and defaults

ONLY A PROTOTYPE, USED FOR DEMONSTRATION PURPOSES ONLY
oraclelinux-release >= 7:7.0
oracle-rdbms-server-12cR1-preinstall
/bin/sh
rpmlib(FileDigests) <= 4.6.0-1
rpmlib(PayloadFilesHavePrefix) <= 4.0-1
rpmlib(CompressedFileNames) <= 3.0.4-1
rpmlib(PayloadIsXz) <= 5.2-1
(contains no files)

You require a “gold image” binary copy for cloning as well. I am assuming it is in place and NFS-accessible in the location specified by the %post scriptlet.

You can refer to Frits Hoogland’s post for more detail about creating the gold image: https://fritshoogland.wordpress.com/2010/07/03/cloning-your-oracle-database-software-installation/. There are probably lots of other posts out there describing the same procedure.

Installation

Here is an example install session, executed as root on a new box I created: server9.

[root@server9 ~]# rpm -ihv /tmp/oracle_12102_jul16_psu_ojvm-0-1.el7.x86_64.rpm

Preparing...                          ################################# [100%]
Updating / installing...
   1:oracle_12102_jul16_psu_ojvm-0-1.e################################# [100%]
cloning the oracle home now to /u01/app/oracle/product/12.1.0.2/dbhome_1
./runInstaller -clone -waitForCompletion  "ORACLE_HOME=/u01/app/oracle/product/12.1.0.2/dbhome_1" 
"ORACLE_BASE=/u01/app/oracle" -defaultHomeName  -silent -paramFile 
/u01/app/oracle/product/12.1.0.2/dbhome_1/clone/clone_oraparam.ini
Starting Oracle Universal Installer...

Checking Temp space: must be greater than 500 MB.   Actual 9204 MB    Passed
Checking swap space: must be greater than 500 MB.   Actual 767 MB    Passed
Preparing to launch Oracle Universal Installer from /tmp/OraInstall2016-10-26_05-03-05PM. 
Please wait ...You can find the log of this install session at:
 /u01/app/oraInventory/logs/cloneActions2016-10-26_05-03-05PM.log
..................................................   5% Done.
..................................................   10% Done.
..................................................   15% Done.
..................................................   20% Done.
..................................................   25% Done.
..................................................   30% Done.
..................................................   35% Done.
..................................................   40% Done.
..................................................   45% Done.
..................................................   50% Done.
..................................................   55% Done.
..................................................   60% Done.
..................................................   65% Done.
..................................................   70% Done.
..................................................   75% Done.
..................................................   80% Done.
..................................................   85% Done.
..........
Copy files in progress.

Copy files successful.

Link binaries in progress.

Link binaries successful.

Setup files in progress.

Setup files successful.

Setup Inventory in progress.

Setup Inventory successful.

Finish Setup successful.
The cloning of OraHome1 was successful.
Please check '/u01/app/oraInventory/logs/cloneActions2016-10-26_05-03-05PM.log' for more details.

Setup Oracle Base in progress.

Setup Oracle Base successful.
..................................................   95% Done.

As a root user, execute the following script(s):
        1. /u01/app/oraInventory/orainstRoot.sh
        2. /u01/app/oracle/product/12.1.0.2/dbhome_1/root.sh



..................................................   100% Done.
Changing permissions of /u01/app/oraInventory.
Adding read,write permissions for group.
Removing read,write,execute permissions for world.

Changing groupname of /u01/app/oraInventory to oinstall.
The execution of the script is complete.
Check /u01/app/oracle/product/12.1.0.2/dbhome_1/install/root_server9_2016-10-26_17-04-05.log 
for the output of root script

The “post” script that is executed spawns a shell (/bin/sh) and executes a script stored in /var/tmp. In my case, this is the contents; pretty much exactly the %post section of the SPEC file:

[root@server9 ~]# cat /var/tmp/rpm-tmp.tZ4pYf
ORACLE_HOME=/u01/app/oracle/product/12.1.0.2/dbhome_1

if [ -d "$ORACLE_HOME" ]; then
        /usr/bin/echo "ORACLE_HOME directory $ORACLE_HOME exists-aborting";
        exit 127
fi

/usr/bin/echo "cloning the oracle home now to $ORACLE_HOME"
/usr/bin/mkdir -p $ORACLE_HOME

/usr/bin/umount /mnt
/usr/bin/mount -t nfs linuxdev:/u01/nfs_export /mnt

/usr/bin/tar --gzip -xf /mnt/oracle/12.1.0.2/oracle_12102_jul16_psu_ojvm.tar.gz -C $ORACLE_HOME

/usr/bin/chown -R oracle:oinstall /u01

/usr/bin/su - oracle -c "cd $ORACLE_HOME/clone/bin && ./clone.pl ORACLE_HOME=$ORACLE_HOME ORACLE_BASE=/u01/app/oracle -defaultHomeName"

/u01/app/oraInventory/orainstRoot.sh
$ORACLE_HOME/root.sh

umount /mnt
[root@server9 ~]#

And that’s it! One of the slightly more complex things was to ensure that this can be installed on Oracle Linux 7 only. One way to do this is to add the oraclelinux-release package as a dependency. I had to fiddle around with it a bit as it uses the epoch field (which seems rare), and not just the version. After I worked it out I managed to enforce the release. On my Oracle Linux 6 system the RPM could not be installed:

[root@linux6 ~]# rpm -ihv /tmp/oracle_12102_jul16_psu_ojvm-1-0.el7.x86_64.rpm
error: Failed dependencies:
	oraclelinux-release >= 7:7.0 is needed by oracle_12102_jul16_psu_ojvm-1-0.el7.x86_64

If you are now thinking of using the epoch:version to check for the oraclelinux-release on Oracle Linux 6, don’t. This is the current oraclelinux-release RPM taken from the “latest” channel in public-yum:

[oracle@linux6 ~]$ rpm -qpi --provides ./oraclelinux-release-6Server-8.0.3.x86_64.rpm
Name        : oraclelinux-release          Relocations: (not relocatable)
Version     : 6Server                           Vendor: Oracle America
Release     : 8.0.3                         Build Date: Wed May 11 11:51:57 2016
Install Date: (not installed)               Build Host: x86-ol6-builder-05.us.oracle.com
Group       : System Environment/Base       Source RPM: oraclelinux-release-6Server-8.0.3.src.rpm
Size        : 49976                            License: GPL
Signature   : RSA/8, Wed May 11 11:44:59 2016, Key ID 72f97b74ec551f03
Summary     : Oracle Linux 6 release file
Description :
System release and information files
config(oraclelinux-release) = 6:6Server-8.0.3
oraclelinux-release = 6:6Server-8.0.3
oraclelinux-release(x86-64) = 6:6Server-8.0.3

So instead of “Requires: oraclelinux-release >= 7:7.0”, … you probably need to replace that with “Requires: oraclelinux-release >= 6:6Server-2.0” for 12c (Oracle Linux 6 update 2 or newer, according to the Linux installation guide).

Advertisements

6 thoughts on “Building an RPM for the Oracle database on Oracle Linux 7

  1. Michael

    Do you know if oracle-rdbms-server-release-preinstall.x86_64 packages set kernel parameters based on system configuration of mininum required configuration. Let’s say system has 96G RAM, will all the kernel parameters be set accordingly? Thanks Michael.

    Reply
    1. Martin Bach Post author

      Hi Michael,

      that’s a good question, and I think I know the answer but need to double-check. This is a great topic for a blog post!

      Reply
  2. Gilbert Standen

    Might be worth noting that such RPM can be used within ones own organization, but cannot generally be redistributed as Oracle Corporation does not allow redistribution of its software.

    Reply
    1. Martin Bach Post author

      Hi, thanks for your comment. As I said this SPEC file is just a prototype and needs to be made production ready even before thinking of using the resulting RPM in house. I never intended the RPM to be out in the wild. One aspect of your comment made me curious though. I am not sure where you see Oracle software as part of the RPM? The code in the post section merely refers to a clone of an Oracle binary which is not included. It is mounted via NFS from a different host. I didn’t say it explicitly in the post but for this clone of the binaries you need a valid license (of course).

      Reply
      1. gstanden

        Ingenious! Yes good point my bad. I did not understand at first that the Oracle binaries were pulled from an NFS mounted gold copy.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s