Script de arranque con el systemctl

Hoy vamos a ver (con mucho retraso) como hacer un script de arranque para el systemctl para nuestra base de datos 12c

Vamos a poner el supuesto de que tenemos una base de datos 12c, en filesystem en una OL7. Al no haber instalado el grid control, nadie arrancará nuestra base de datos.
¿Como hacemos para que arranque en el inicio ?
Simplemente hay que crearlos servicios de arranque

Scripts de arranque

Al igual que en un linux clásico, necesitaremos un script de start y stop para nuestra base de datos, nosotros crearemos :

  • listener.sh para el listener
  • cdbtest.sh para nuestra instancia cdbtest.

Por compatibilidad con los sistemas antiguos, lo dejaremos en /etc/init.d (auqnue toda la información que he visto en internet lo deja ene l propio $HOME de oracle ) y le añadiremos una guarda que compruebe que solamente pueda arrancase con el usuario oracle (y evitar asi que alguien lo use como root)

/etc/init.d/listener.sh

#!/bin/bash
##  Configuramos el nombre del usuario que arranca la BBDD
export USUARIO=oracle
if [ $UID -ne  `id -u $USUARIO`  ];then
 echo "Programa invocado con  incorrecto, debe de invocarse como $USUARIO "
 exit 1 ;
fi
export ORAENV_ASK=no
export export ORACLE_HOME=/u01/app/oracle/product/12.1.0/dbhome_1
case $1 in 
start)
	$ORACLE_HOME/bin/lsnrctl start 
;;
stop)
        $ORACLE_HOME/bin/lsnrctl stop
;;
status)
        $ORACLE_HOME/bin/lsnrctl status
;;
*)
  echo "Usage $0 start|stop|status "
  ;;
esac

/etc/init.d/cdbtest.sh

#!/bin/bash
##  Configuramos el nombre del usuario que arranca la BBDD
export USUARIO=oracle
if [ $UID -ne  `id -u $USUARIO`  ];then
 echo "Programa invocado con  incorrecto, debe de invocarse como $USUARIO "
 exit 1 ;
fi
export ORACLE_SID=cdbtest
export ORAENV_ASK=NO
. oraenv
case $1 in 
start)
$ORACLE_HOME/bin/sqlplus "/as sysdba" << EOF
	startup;
	exit;
EOF
;;
stop)
$ORACLE_HOME/bin/sqlplus "/as sysdba" << EOF
	shutdown immediate;
	exit;
EOF
;;
*)
  echo "Usage $0 start|stop "
  ;;

Creamos los servicios de systemctl

Ahora que tenemos ya los scripts que arrancaran y pararan el listener y la base de datos, crearemos nuestros servicios de arranque.
Crearemos uno especifico para el listener y otro para nuestra instancia cdbtest.
Para identificar cuales son nuestros servicios , los llamaremos dbora-XXX . Esto no es una convención genérica ni una best practice , sino que es simplemente un patrón propio para facilitarme su futura identificación.

Servicio dbora-listener.service

Crearemos un fichero llamado /lib/systemd/system/dbora-listener.service

[Unit]
Description=The Oracle Listener
After=syslog.target network.target

[Service]
LimitMEMLOCK=infinity
LimitNOFILE=65535

RemainAfterExit=yes
User=oracle
Group=oinstall
ExecStart=/etc/init.d/listener.sh start 
ExecStop=/etc/init.d/listener.sh stop 
Type=idle
RemainAfterExit=yes
User=oracle
Group=oinstall
[Install]
WantedBy=multi-user.target

Servcio dbora-cdbtets.service

Ahora crearemos un servicio de arranque para nuestra instancia /lib/systemd/system/dbora-cdbtets.service

[Unit]
Description=Base de datos cdbtest
After=syslog.target network.target dbora-listener.service

[Service]
LimitMEMLOCK=infinity
LimitNOFILE=65535
RemainAfterExit=yes
User=oracle
Group=dba
ExecStart=/etc/init.d/cdbtest.sh start  >> /tmp/startup_cdbtestlog 2>&1 &
ExecStop=/etc/init.d/cdbtest.sh stop  >> /tmp/shutdown_cdbtestlog 2>&1 &
Type=idle
[Install]
WantedBy=multi-user.target

Configuramos los servicios

Ya tenemos los scripts de arranque y los scripts de los servicios. Ahora simplemente nos quedará el habilitarlos para su funcionamiento.
Para ello, primero haremos un reload para refrescar los servicios

# systemctl daemon-reload
Y luego los cargaremos y habilitaremos
systemctl start dbora-listener.service
systemctl enable dbora-listener.service
systemctl start dbora-cdbtest.service
systemctl enable dbora-cdbtest.service

Así pues, si queremos ver el estado del service, podremos ver como :

[root@alone ~]# systemctl status dbora-cdbtest.service
● dbora-cdbtest.service - Base de datos cdbtest
   Loaded: loaded (/usr/lib/systemd/system/dbora-cdbtest.service; enabled; vendor preset: disabled)
   Active: active (exited) since mar 2017-02-21 13:16:19 CET; 9min ago
  Process: 1039 ExecStart=/etc/init.d/cdbtest.sh start >> /tmp/startup_cdbtestlog 2>&1 & (code=exited, status=0/SUCCESS)
 Main PID: 1039 (code=exited, status=0/SUCCESS)
   CGroup: /system.slice/dbora-cdbtest.service
           ├─2303 ora_pmon_cdbtest
           ├─2305 ora_psp0_cdbtest
           ├─2307 ora_vktm_cdbtest
           ├─2311 ora_gen0_cdbtest
           ├─2315 ora_mman_cdbtest
           ├─2317 ora_diag_cdbtest
           ├─2319 ora_dbrm_cdbtest
           ├─2321 ora_vkrm_cdbtest
           ├─2323 ora_dia0_cdbtest
           ├─2325 ora_dbw0_cdbtest
           ├─2327 ora_lgwr_cdbtest
           ├─2329 ora_ckpt_cdbtest
           ├─2331 ora_smon_cdbtest
           ├─2333 ora_reco_cdbtest
           ├─2335 ora_lreg_cdbtest
           ├─2337 ora_pxmn_cdbtest
           ├─2339 ora_mmon_cdbtest
           ├─2341 ora_mmnl_cdbtest
           ├─2343 ora_d000_cdbtest
           ├─2345 ora_s000_cdbtest
           ├─2357 ora_tmon_cdbtest
           ├─2359 ora_tt00_cdbtest
           ├─2361 ora_smco_cdbtest
           ├─2363 ora_w000_cdbtest
           ├─2365 ora_w001_cdbtest
           ├─2369 ora_aqpc_cdbtest
           ├─2373 ora_p000_cdbtest
           ├─2375 ora_p001_cdbtest
           ├─2377 ora_p002_cdbtest
           ├─2379 ora_p003_cdbtest
           ├─2381 ora_qm02_cdbtest
           ├─2385 ora_q002_cdbtest
           ├─2387 ora_q003_cdbtest
           └─2452 ora_cjq0_cdbtest

feb 21 13:16:33 alone.pamplona.name cdbtest.sh[1039]: Copyright (c) 1982, 2014, Oracle.  All rights reserved.
feb 21 13:16:51 alone.pamplona.name cdbtest.sh[1039]: Connected to an idle instance.
feb 21 13:17:00 alone.pamplona.name cdbtest.sh[1039]: SQL> ORACLE instance started.
feb 21 13:17:00 alone.pamplona.name cdbtest.sh[1039]: Total System Global Area 6291456000 bytes
feb 21 13:17:00 alone.pamplona.name cdbtest.sh[1039]: Fixed Size                    2938352 bytes
feb 21 13:17:00 alone.pamplona.name cdbtest.sh[1039]: Variable Size                 3372222992 bytes
feb 21 13:17:00 alone.pamplona.name cdbtest.sh[1039]: Database Buffers         2902458368 bytes
feb 21 13:17:00 alone.pamplona.name cdbtest.sh[1039]: Redo Buffers                   13836288 bytes
feb 21 13:17:05 alone.pamplona.name cdbtest.sh[1039]: Database mounted.
feb 21 13:17:30 alone.pamplona.name cdbtest.sh[1039]: Database opened.

Introduccion a los servicios de Oracle

Uno de los elementos mas potentes que introdujo Oracle en la versión 10g fué el uso de servicios.
Los servicios de Oracle no son otra cosa que una abstracción lógica de una instancia de base de datos. Aunque los servicios tienen mas sentido en entorno RAC, hoy vamos a ver como se configuran y para que pueden servir en un entorno de «single instance».

Supongamos tenemos una base de datos produccion en la que tenemos consolidados 4 entornos distintos ( Webfotos,Cargas,Contabilidad y Desarrollo ) que acceden a nuestra instancia con el mismo esquema,y desde servidores de aplicaciones que comparten máquina entre ellos, en el momento en que la base de datos tiene problemas nos es muy difícil el saber quien es quien.
Si pudiésemos discriminar las conexiones por una agrupación lógica, sería mas fácil el verlo, y , mas aún, si el EMC fuese capaz de separar las gráficas y estadísticas por esa agrupación.

Pues esto es exactamente lo que nos proporcionan los servicios Oracle.
En nuestro caso ficticio, vamos a crear los distintos servicios:

  • Webfotos
  • Cargas
  • Contabilidad
  • Desarrollo

De esta forma, cada conexión de estos 4 entornos usara un service_name distinto en su TNS_NAMES de cliente, y , la base de datos podrá identificar ( y limitar) a cada uno de ellos de manera separada.

Lo primero que tendremos que hacer es crear los servicios. Para esto tenemos dos maneras, o bien desde el srvctl ( en caso de RAC,Grid control u Oracle restart), o mediante el paquete DBMS_SERVICES , como nuestro caso es el de una «single instance», no nos va a quedar mas remedio que usar este paquete.
Mediante la función CREATE_SERVICE crearemos los servicios de la manera:

exec dbms_service.CREATE_SERVICE(SERVICE_NAME=>'webfotos', NETWORK_NAME=>'webfotos')
exec dbms_service.CREATE_SERVICE(SERVICE_NAME=>'cargas', NETWORK_NAME=>'cargas')
exec dbms_service.CREATE_SERVICE(SERVICE_NAME=>'contabilidad', NETWORK_NAME=>'contabilidad')
exec dbms_service.CREATE_SERVICE(SERVICE_NAME=>'desarrollo', NETWORK_NAME=>'desarrollo')

Una vez creados los servicios, los arrancaremos con la función

exec dbms_service.START_SERVICE('webfotos')
exec dbms_service.START_SERVICE('cargas')
exec dbms_service.START_SERVICE('contabilidad')
exec dbms_service.START_SERVICE('desarrollo')

Para comprobar si la creación de nuestros servicios ha funcionado, podemos chequear el parámetro service_names

SQL> select value from v$parameter where NAME='service_names';
VALUE
---------------------------
produccion,webfotos,cargas,contabilidad,desarrollo

O bien el listener con lsnrctl services

[oracle@blog] [$lsnrctl services

LSNRCTL for Linux: Version 11.2.0.2.0 - Production on 17-MAY-2013 13:31:06

Copyright (c) 1991, 2011, Oracle.  All rights reserved.

Connecting to (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521))
Services Summary...
Service "PLSExtProc" has 1 instance(s).
  Instance "PLSExtProc", status UNKNOWN, has 1 handler(s) for this service...
    Handler(s):
      "DEDICATED" established:0 refused:0
         LOCAL SERVER
Service "produccion" has 1 instance(s).
  Instance "XE", status READY, has 1 handler(s) for this service...
    Handler(s):
      "DEDICATED" established:34 refused:0 state:ready
         LOCAL SERVER
Service "webfotos" has 1 instance(s).
  Instance "XE", status READY, has 1 handler(s) for this service...
    Handler(s):
      "DEDICATED" established:34 refused:0 state:ready
         LOCAL SERVER
Service "contabilidad" has 1 instance(s).
  Instance "XE", status READY, has 1 handler(s) for this service...
    Handler(s):
      "DEDICATED" established:34 refused:0 state:ready
         LOCAL SERVER
Service "desarrollo" has 1 instance(s).
  Instance "XE", status READY, has 1 handler(s) for this service...
    Handler(s):
      "DEDICATED" established:34 refused:0 state:ready
         LOCAL SERVER
Service "cargas" has 1 instance(s).
  Instance "XE", status READY, has 1 handler(s) for this service...
    Handler(s):
      "DEDICATED" established:34 refused:0 state:ready
         LOCAL SERVER
The command completed successfully

Ahora, solamente tendremos que modificar los respectivos TNSNAMES de los distntos entornos para que se conecten mediante SERVICE_NAME y no mediante SID y tendremos identificados cada una de la sesiones de oracle con el servicio.

¿que beneficios nos aporta todo esto?

  • Trazabilidad: Nos va a ser sencillísimo encontrar quien es el que esta haciendo algo ya que en un primer vistazo encontraremos al culpable «logico» del problema, una vez tenemos el origen del problema es mas sencillo abordarlo.
  • Accounting: Vamos a poder ser capaces de ver los consumos de cada aplicacion/grupo lógico en la base de datos, lo que nos puede ser muy bueno a la hora de derivar costes o limitar recursos
  • control de accesos: Si en un momento específico queremos asegurarnos de que un elemento lógico no acceda a la aplicacion, podemos detener el servicio y el resto funcionaría correctamente.Esto puede ser muy útil por ejemplo, para evitar cargas en horario diurno, o para controlar los equipos de desarrollo

Hasta ahora lo hemos visto todo muy fácil, pero .. ¿que ocurre cuando reinicias la base de datos?.
Para que la instancia levante los servicios al arrancar deberán de estar en el init.ora con la sintaxsis:


service_names='produccion','webfotos','cargas','desarrollo'

Si no es así , cuando se levante nuestra base de datos no se levantan los servicios, y esto hace que no funcione nada de lo que apunta a ellos.
La solución como os decía la principio es hacerlo desde el srvctl, pero …
¿como lo hacemos si no tenemos RAC,Grid u Oracle restart?
La respuesta es brutalmente sencilla.

[oracle@blog] [$sqlplus "/as sysdba"
SQL*Plus: Release 11.2.0.2.0 Production on Vie May 17 13:09:11 2013
Copyright (c) 1982, 2011, Oracle.  All rights reserved.

Connected to:
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
SQL> alter system set service_names='produccion,webfotos,cargas,contabilidad,desarrollo';
System altered.

Tan sencillo como acabáis de ver, simplemente hemos de conectarnos desde el sqlplus y hacer un ALTER SYSTEM para el parámetro service_names poniendo nuestros servicios separados por comas.

Como siempre, para mas información, tenemos la documentación de Oracle del paqueteDBMS_SERVICES