Saturday, February 18, 2023

How to prevent sed to destroy your symlinks

Because of EBS, we have a subdirectory in our $TNS_ADMIN which has the following name
PDB1_test1.oric.no
In other words, the files listener.ora, sqlnet.ora and tnsnames.ora are symlinks pointing to this subdirectory:
# ls -altr
lrwxrwxrwx  1 oracle dba   34 Feb 10 13:29 sqlnet.ora -> PDB1_test1.oric.no/sqlnet.ora
lrwxrwxrwx  1 oracle dba   36 Feb 10 13:29 tnsnames.ora -> PDB1_test1.oric.no/tnsnames.ora
lrwxrwxrwx  1 oracle dba   36 Feb 18 12:17 listener.ora -> PDB1_test1.oric.no/listener.ora
drwxr-xr-x  2 oracle dba 4096 Feb 18 12:18 PDB1_test1.oric.no
drwxr-xr-x  5 oracle dba 4096 Feb 18 12:19 .
If you are to exchange a string in these files, for example when switching to a new version of the Oracle software, make sure you use the directive --follow-symlinks to preserve your symlinks:
export PRE_ORACLE_VERSION=19.17
export NEW_ORACLE_VERSION=19.18
cd $TNS_ADMIN
sed --follow-symlinks -i "s/$PRE_ORACLE_VERSION/$NEW_ORACLE_VERSION/g" listener.ora
If you don't, the listener.ora will be placed directly in $TNS_ADMIN, and the symlinks will be dropped.

Tuesday, February 14, 2023

Error fetching the value from a shell script executed by root, when doing "su - oracle"

Problem:
Inside a new bash shell session, executed as user "oracle", like this:
su - oracle <<!

instructions here

!
I was not able to save the value of a string extracted from an xml file in a session variable.
I tried all possible variants (I thought), but was still unable to get my shell script to hold the value in a variable and use it locally within the oracle user session.

Solution:
Use backslash around the entire command, marked in yellow below:
su - oracle <<!
export CNTXT_FILE_PERL_VERSION=\`grep PERL5LIB \$CONTEXT_FILE | awk -F "site_perl/" '{print \$2}' | cut -f 1 -d":"\`
!

Credit goes to an experienced and clever colleague of mine, who shall remain nameless unless he actively wants his name listed on my blog ;-)

Wednesday, January 25, 2023

clone.pl is deprecated, substituted by runInstaller - how to use

1. create a "Golden Image" of the Oracle software home you want to clone
oracle@testserver1.oric.no:[testdb01]# /sw/oracle/product/19c_230117/runInstaller -silent -createGoldImage -destinationLocation /sw/oracle/product
Launching Oracle Database Setup Wizard...

Successfully Setup Software.
Gold Image location: /sw/oracle/product/db_home_2023-01-24_04-05-28PM.zip
Note that I use the -silent flag. Without it, I received the following two errors:

ERROR: Could not read any NLS message catalogue!

and

Can't connect to X11 window server using 'localhost:10.0' as the value of the DISPLAY variable.

2. Transfer the zip file to your destination server using scp
ssh testserver2.oric.no
su - oracle
cd /sw/oracle/product
scp testserver1:/sw/oracle/product/db_home_2023-01-24_04-05-28PM.zip .
3. Make a directory for the new ORACLE_HOME
mkdir 19c_230117
4. Unzip the image file
unzip -d 19c_230117 db_home_2023-01-24_04-05-28PM.zip
5. create a simple script for the installation process
vi exec_runInstaller.sh; chmod 755 exec_runInstaller.sh
Add the following to exec_runInstaller.sh:
#!/bin/bash
export GLOGFILE=/sw/oracle/product/exec_runInstaller.log
touch ${GLOGFILE}
chmod 666 ${GLOGFILE}
exec 1> ${GLOGFILE} 2>&1
echo "starting installer at " `date`
export CV_ASSUME_DISTID=OEL8.1
export NEW_ORACLE_HOME=/sw/oracle/product/19c_230117
cd $NEW_ORACLE_HOME
./runInstaller -silent -debug -force \
oracle.install.responseFileVersion=/oracle/install/rspfmt_dbinstall_response_schema_v19.0.0 \
oracle.install.option=INSTALL_DB_SWONLY \
UNIX_GROUP_NAME=dba \
ORACLE_HOME=$NEW_ORACLE_HOME \
ORACLE_BASE=$ORACLE_BASE \
oracle.install.db.InstallEdition=EE \
oracle.install.db.DBA_GROUP=dba \
oracle.install.db.OPER_GROUP=dba \
oracle.install.db.OSBACKUPDBA_GROUP=dba \
oracle.install.db.OSDGDBA_GROUP=dba \
oracle.install.db.OSKMDBA_GROUP=dba \
oracle.install.db.OSRACDBA_GROUP=dba \
DECLINE_SECURITY_UPDATES=true

exit
Note that I enter the newly unpacked ORACLE_HOME to execute runInstaller.

6. execute the script
./exec_runInstaller.sh
7. Run root scripts

Upon completion, check the logfile /sw/oracle/product/install_sw_${TS}.log and you are reminded to run two root scripts:
You can find the log of this install session at:
 /home/oracle/oraInventory/logs/InstallActions2023-01-25_10-04-01AM/installActions2023-01-25_10-04-01AM.log

As a root user, execute the following script(s):
        1. /sw/oracle/product/19c_230117/root.sh

Execute /sw/oracle/product/19c_230117/root.sh on the following nodes:
[testserver02.oric.no]

8. Verify that the new ORACLE_HOME is registered in the inventory
cat  /home/oracle/oraInventory/ContentsXML/inventory.xml
Output (abbreviated):
<HOME NAME="OraDB19Home1" LOC="/sw/oracle/product/19c_230117" TYPE="O" IDX="3"/>

Tuesday, January 24, 2023

How to avoid error Perl lib version (5.28.1) doesn't match executable version (5.36.0)

When trying to use clone.pl to clone the latest version of the Oracle 19c database, the following error stopped me from proceeding:
/sw/oracle/product/19.18/clone/bin/clone.pl: 
Perl lib version (5.28.1) doesn't match executable '/sw/oracle/product/19.18/perl/bin/perl' 
version (5.36.0) at /sw/oracle/product/19.17/perl/lib/5.28.1/x86_64-linux-thread-multi/Config.pm 
line 62.
Turns out that that the error occured at the following point in my code:
export NEW_ORACLE_HOME=$ORACLE_BASE/product/19.18
export PRE_ORACLE_HOME=$ORACLE_BASE/product/19.17
export NEW_ORACLE_VERSION=19C_230117
su - oracle <<!
cd $NEW_ORACLE_HOME/clone/bin
perl clone.pl ORACLE_HOME=$NEW_ORACLE_HOME ORACLE_HOME_NAME=$NEW_ORACLE_VERSION ORACLE_BASE=$ORACLE_BASE OSDBA_GROUP=dba
!
Cause:
The .bash_profile of the oracle user contained a variable commonly used in EBS database environments:
export PERL5LIB=/sw/oracle/product/19.17/perl/lib/5.28.1:/sw/oracle/product/19.17/perl/lib/site_perl/5.28.1:/sw/oracle/product/19.17/appsutil/perl
and when trying to run the clone.pl program from the new ORACLE_HOME, perl was unable to find the matching libraries.

Solution:
unset the PERL5LIB before running the clone.pl program:
export NEW_ORACLE_HOME=$ORACLE_BASE/product/19.18
export PRE_ORACLE_HOME=$ORACLE_BASE/product/19.17
export NEW_ORACLE_VERSION=19C_230117
su - oracle <<!
cd $NEW_ORACLE_HOME/clone/bin
unset PERL5LIB
perl clone.pl ORACLE_HOME=$NEW_ORACLE_HOME ORACLE_HOME_NAME=$NEW_ORACLE_VERSION ORACLE_BASE=$ORACLE_BASE OSDBA_GROUP=dba
!

Thursday, January 19, 2023

What is the ifile directive sometimes used in tnsnames.ora?

My customer is using Oracle E-Business Suite, and during a so-called "autoconfig", some files in the Oracle RDBMS home on the database server is overwritten.

Oracle eBS actually warns the DBA against changing these files manually. Here is an example from the $TNS_ADMIN/tnsnames.ora:
###############################################################
#
# Do not edit settings in this file manually. They are managed
# automatically and will be overwritten when AutoConfig runs.
# For more information about AutoConfig, refer to the Oracle
# E-Business Suite Setup Guide.
###############################################################
Since we are using multitenant architecture, and also use Golden Gate to extract data, we need to tnsnames.ora entries for the Golden Gate setup:

  • One entry for the pluggable database
  • One entry for the container database

    After the initial setup, before the Golden Gate installation was ready, the $TNS_ADMIN/tnsnames.ora contained only the first of these two entries:
    ebsref=
            (DESCRIPTION=
                (ADDRESS=(PROTOCOL=tcp)(HOST=ebs-ref-db01.oric.no)(PORT=1537))
                (CONNECT_DATA=
                    (SERVICE_NAME=ebs_ebsref)
                    (INSTANCE_NAME=cdb)
                )
            )
    
    This entry is fine for the first of our two required connections. But there was no one supporting a direct connection to the root container, in my case called "cdb".
    The listener process already supports a service called "cdb":
    Services Summary...
    Service "cdb" has 1 instance(s).
      Instance "cdb", status READY, has 1 handler(s) for this service...
    Service "ebsref" has 1 instance(s).
      Instance "ebsref", status UNKNOWN, has 1 handler(s) for this service...
    
    But we cannot add the necessary Golden Gate configuration unless we add another entry in the tnsnames.ora file.

    How to do this, when we are not supposed to edit the tnsnames.ora because it eventually will be overwritten by autoconfig?

    The answer was actually already in the tnsnames.ora file.

    Oracle has included an example of how to use an include file in the tnsnames.ora file, so we can add our entries according to our needs. At the bottom of the file, you can see this string:
    IFILE=/u01/oracle/sw/19c/network/admin/ebsref_ebs-ref-db01/ebsref_ebs-ref-ref-db01_ifile.ora
    
    The file does not exist, so you need to create it:
    vi /u01/oracle/sw/19c/network/admin/ebsref_ebs-ref-db01/ebsref_ebs-ref-ref-db01_ifile.ora
    
    Add the following:
    cdb = (DESCRIPTION=
              (ADDRESS=(PROTOCOL=tcp)(HOST=ebs-ref-db01.skead.no)(PORT=1537))
                    (CONNECT_DATA= (SERVICE_NAME=cdb)
                    (INSTANCE_NAME=cdb))
          )
    
    And you've solved your problem, the connect identifier "cdb" can now be used by Golden Gate connections to the container database. Burleson Consulting has an article about ifile that actually points out eBS as the very reason for the ifile directive:

    According to some Oracle experts, the ifile facility was designed for the init.ora file and ifile is not supported for the listener.ora, sqlnet.ora and protocol.ora files, but Oracle eBusiness Suite (EBS) release 11 uses ifile in their parameter files, ostensibly for reasons of customizations. With a ifile, you can leave the original file intact and not wonder what was added later.
  • Wednesday, January 11, 2023

    More on setting redo routes property when adding a terminal standby database to your data guard broker configuration

    As described in an earlier post, it is possible to set up a "terminal standby database" which fetches its redo information from another standby database, rather than directly from the primary database.

    It is quite facinating to see how the data guard broker simplifies this setup for the DBA.

    In a recent excercise @ work, I had a data guard configuration consisting of 1 primary and 3 physical standby database.

    A fourth was to be added as a terminal standby database.

    First, clone the new database for standby.

    You can use any of the databases in the configuration as a source, from which to create a terminal database, both primary or any of the mounted physical standby databases.

    When the clone is finished, add the new database to the broker config:
    dgmgrl -echo sys/password@primdb_dgmgrl.oric.no as sysdba
    
    Welcome to DGMGRL, type "help" for information.
    Connected to "primdb"
    Connected as SYSDBA.
    
    Add the new database:
    DGMGRL> add database 'tstby' as connect identifier is tstby.oric.no maintained as physical;
    add database 'tstby' as connect identifier is tstb.oric.no maintained as physical;
    Database "tstby" added
    DGMGRL> show configuration;
    show configuration;
    
    Configuration - dgconfig1
    
      Protection Mode: MaxPerformance
      Members:
      primdb     - Primary database
        stby1     - Physical standby database
        stby2     - Physical standby database
        stby3     - Physical standby database
        tstby    - Physical standby database (disabled)
    
    Fast-Start Failover: DISABLED
    
    Notice how all the standby databases are indented directly underneath the primary database, indicating that they receive their redo information directly from the primary database.

    I then add the redoroutes property to the primary:
    DGMGRL> edit database primdb set property redoroutes='(LOCAL:stby1,stby2,stby3 ASYNC)(stby1:tstby ASYNC)';
    edit database primdb set property redoroutes='(LOCAL:stby1,stby2,stby3 ASYNC)(stby1:tstby ASYNC)';
    Property "redoroutes" updated
    
    Add the redoroutes property for when the primary and the choosen standby switches roles:
    DGMGRL> edit database stby1 set property redoroutes='(LOCAL:primdb,stby2,stby3 ASYNC)(primdb:tstb ASYNC)';
    edit database stby1 set property redoroutes='(LOCAL:primdb,stby2,stby3 ASYNC)(primdb:tstb ASYNC)';
    Property "redoroutes" updated
    
    Note that both of these rules must be set, otherwise your terminal standby database will not receive logs. You will see messages like the follwing:
    Configuration - dgconfig1
    
      Protection Mode: MaxPerformance
      Members:
      primdb     - Primary database
        stby1  - Physical standby database
        stby2  - Physical standby database
        stby3  - Physical standby database
    
      Members Not Receiving Redo:
      tstby  - Physical standby database
        Error: ORA-16685: database does not receive redo data
    

    View the configuration again
    You will see that the broker has understood that the tstb is acting like a terminal standby database for physical standby database "stby2":
    DGMGRL> show configuration;
    show configuration;
    
    Configuration - dgconfig1
    
      Protection Mode: MaxPerformance
      Members:
      primdb     - Primary database
        stby1  - Physical standby database
          tstby  - Physical standby database (disabled)
        stby2 - Physical standby database
        stby3 - Physical standby database
    
    Fast-Start Failover: DISABLED
    
    Configuration Status:
    SUCCESS   (status updated 27 seconds ago)
    
    Finally, enable the database:
    DGMGRL> enable database 'tstb';
    enable database 'tsbt';
    Enabled.
    
    The output you should see at the end is:
    DGMGRL> show configuration;
    show configuration;
    
    Configuration - dgconfig1
    
      Protection Mode: MaxPerformance
      Members:
      primdb     - Primary database
        stby1  - Physical standby database
          tstby  - Physical standby database (receiving current redo)
        stby2 - Physical standby database
        stby3 - Physical standby database
    

    Friday, January 6, 2023

    How to solve script error $'\r': command not found syntax error: unexpected end of file

    when trying to execute a script from root, like the following:
     su - oracle -c "/tmp/set_params.sh"
    
    You may see errors like the following:
    set_params.sh: line 6: $'\r': command not found
    set_params.sh: line 42: syntax error: unexpected end of file
    
    Root cause:

    You have windows-style formatting in your file

    Solution:
    dos2unix set_params.sh
    dos2unix: converting file flexpod_params.sh to Unix format...
    
    When executed again, the above errors should be gone!