Introduction

Voici une action qui peut sembler banale et simple en utilisant l'utilitaire graphique DBCA. Force est de constater qu'en entreprise on est le plus souvent astreint à n'avoir comme outil que la ligne de commande et la connexion ssh (Ah Putty... ). De ce fait ( j'ai failli écrire "du coup !" ) un bon vieux script en shell peut être très utile, c'est l'objet de ce billet.

Configuration

Elle est classique d'un RAC à 2 noeuds(2 serveurs, stockage ASM, HAIP... ). Deux diskgroups sont en place :

  • DONNEES
  • FAST

Les noms parlent d'eux mêmes. La gestion OMF sera utilisée.

La base sera mise en archivelog.

Le script

Il contient au début quelques variables servant à paramétrer la création :

  • DB=YODA
  • DBUNIQ=${DB}
  • DATA=DONNEES
  • FRA=FAST
  • INSTANCE1=${DBUNIQ}1
  • INSTANCE2=${DBUNIQ}2
  • SGA=1280M
  • PGA=320M
  • MDP=Manager12
  • SERVEUR1=ora01
  • SERVEUR2=ora02

Ici encore rien de bien novateur. J'ai mis dans le script les commentaires utiles. Il est important que l'environnement Oracle soit correct avant lancement (ORACLE_BASE, ORACLE_HOME... ).

Des fichiers intermédiaires seront créés sous /home/oracle/sql

#!/bin/bash
export DEBUT=$(date +%s)
echo $(date)

# Variables a spécifier
export DB=YODA
export DBUNIQ=${DB}
export DATA=DONNEES
export FRA=FAST
export INSTANCE1=${DBUNIQ}1
export INSTANCE2=${DBUNIQ}2
export SGA=1280M
export PGA=320M
export MDP=Manager12
export SERVEUR1=ora01
export SERVEUR2=ora02

echo "Création base RAC ${DBUNIQ} sur 2 noeuds ( ${SERVEUR1} - ${SERVEUR2} )"

# Intégration GRID
srvctl add database -d ${DBUNIQ} -pwfile +${DATA}/${DBUNIQ}/orapw${DBUNIQ} -o ${ORACLE_HOME}
srvctl add instance -d ${DBUNIQ} -i $INSTANCE1 -n ${SERVEUR1}
srvctl add instance -d ${DBUNIQ} -i $INSTANCE2 -n ${SERVEUR2}
srvctl setenv database -d ${DBUNIQ} -t ORACLE_BASE=${ORACLE_BASE}
srvctl disable database -d ${DBUNIQ}

echo "Base ${DBUNIQ} enregistrée sur le GRID"
srvctl config database -d ${DBUNIQ}

# Repertoire pour fichiers init et create
if [ ! -d /home/oracle/sql ]
then
  mkdir -p /home/oracle/sql
fi

# Fichier init.ora
cat <<EOF > /home/oracle/sql/init${DB}.ora
*.db_name=${DB}
*.db_unique_name=${DBUNIQ}
*.db_block_size=8192
*.db_create_file_dest=+${DATA}
*.db_recovery_file_dest=+${FRA}
*.db_recovery_file_dest_size=5000M
*.open_cursors=300
*.processes=300
*.log_archive_format=${DB}_%t_%s_%r.arch
*.sga_target=${SGA}
*.pga_aggregate_target=${PGA}
${INSTANCE1}.instance_number=1
${INSTANCE2}.instance_number=2
${INSTANCE1}.thread=1
${INSTANCE2}.thread=2
${INSTANCE1}.undo_tablespace=UNDOTBS1
${INSTANCE2}.undo_tablespace=UNDOTBS2
*.remote_login_passwordfile=exclusive
EOF

# Script de creation
cat <<EOF > /home/oracle/sql/create${DB}.sql
create database ${DB}
character set AL32UTF8
national character set AL16UTF16
datafile size 500M autoextend on next 500M maxsize 2G extent management local 
sysaux datafile size 500M autoextend on next 500M maxsize 2G 
undo tablespace UNDOTBS1 datafile size 500M
default temporary tablespace TEMP tempfile size 500M
default tablespace USERS datafile size 100K
logfile group 1 size 50M,
        group 2 size 50M,
        group 3 size 50M
user sys identified by "${MDP}"
user system identified by "${MDP}";
EOF

# Creation de la base
echo "Création de l'instance et des fichiers principaux"
export ORACLE_SID=${DBUNIQ}
resultat=`sqlplus -s "/ as sysdba" <<EOF
startup nomount pfile=/home/oracle/sql/init${DB}.ora;
start /home/oracle/sql/create${DB}.sql;
exit;
EOF`

# Recuperation fichiers de controle
resultat=`sqlplus -s "/ as sysdba" <<EOF
set echo off
set feedback off
set pages 0
set linesize 2000
set heading off
select concat('*.control_files=''', concat(replace(value, ', ', ''','''), '''')) ctl_files from v\\$parameter where name ='control_files';
exit
EOF`
echo $resultat >> /home/oracle/sql/init${DB}.ora

echo "Base de données ${DBUNIQ} créée. Les fichiers de controle sont en place."
echo $resultat

# Fichier de mot de passe
orapwd file=+${DATA}/${DBUNIQ}/orapw${DBUNIQ} force=y format=12 dbuniquename=${DBUNIQ} password=${MDP}

echo "Création des vues du dictionnaire. Phase assez longue"
resultat=`sqlplus -s "/ as sysdba" <<EOF
create undo tablespace UNDOTBS2 datafile size 500M;

@?/rdbms/admin/catalog.sql
@?/rdbms/admin/catproc.sql

# Placer ici tout ce qui peut être utile selon la configuration
@?/rdbms/admin/catoctk.sql
@?/rdbms/admin/owminst.plb
@?/rdbms/admin/catclust.sql

# Inscription des droits dans le fichier de mot de passe
grant sysdg to sysdg;
grant sysbackup to sysbackup;
grant syskm to syskm;

# Pour utiliser l'agent OEM13c
alter user dbsnmp identified by ${MDP} account unlock;

# Verouillage des comptes non utiles
BEGIN
 FOR item IN ( SELECT USERNAME FROM DBA_USERS WHERE ACCOUNT_STATUS IN ('OPEN', 'LOCKED', 'EXPIRED') AND USERNAME NOT IN (
'SYS','SYSTEM','DBSNMP') )
 LOOP
  dbms_output.put_line('Locking and Expiring: ' || item.USERNAME);
  execute immediate 'alter user ' ||
         sys.dbms_assert.enquote_name(
         sys.dbms_assert.schema_name(
         item.USERNAME),false) || ' password expire account lock' ;
 END LOOP;
END;
/

shutdown immediate;
startup mount pfile=/home/oracle/sql/init${DB}.ora
alter database archivelog;
alter database open;
alter database add logfile thread 2 size 50M;
alter database add logfile thread 2 size 50M;
alter database add logfile thread 2 size 50M;
alter database enable public thread 2;

host echo "*.cluster_database=true" >> /home/oracle/sql/init${DB}.ora
create spfile='+${DATA}/${DBUNIQ}/spfile${DB}' from pfile='/home/oracle/sql/init${DB}.ora';

connect system/${MDP}
@?/sqlplus/admin/pupdld.sql
exit;
EOF`

resultat=`sqlplus -s "/ as sysdba" <<EOF
shutdown immediate;
exit;
EOF`

# Finalisation
# Activation des spfile par instance

echo "Finalisation et integration définitive au GRID"
srvctl modify database -d ${DBUNIQ} -p '+${DATA}/${DBUNIQ}/spfile${DB}'

echo "SPFILE='+${DATA}/${DBUNIQ}/spfile${DB}'" > $ORACLE_HOME/dbs/init${INSTANCE1}.ora
scp -q  $ORACLE_HOME/dbs/init${INSTANCE1}.ora ${SERVEUR2}:$ORACLE_HOME/dbs/init${INSTANCE2}.ora

# Activation de la BD par le GRID
srvctl enable database -d ${DBUNIQ}
srvctl start database -d ${DBUNIQ}
srvctl status database -d ${DBUNIQ}

export FIN=$(date +%s)
echo $(date)
export DUREE=$(( ${FIN} - ${DEBUT} ))
echo "Fin de création. Durée -> ${DUREE}"
exit 0

Selon la puissance de la machine, la SGA et autres la création dure entre 20 et 30 minutes.