El RAC se queda en estado [ROLLING PATCH]

Hoy vamos a ver una entrada sobre ago que puede dar mucho miedo pero que tiene una solucion muy sencila
Pongamos que tras aplicar una serie de parches comprobamos la version de nuesrto softare en el RAC y nos encontramos lo siguiente

[oracle@rac1~]$ sudo  $ORACLE_HOME/bin/crsctl query  crs  activeversion -f
Oracle Clusterware active version on the cluster is [19.0.0.0.0]. The cluster upgrade state is [ROLLING PATCH]. The cluster active patch level is [724960844].

Oracle Clusterware patch level on node rac1is [2701864972].
[oracle@rac1~]$ sudo  $ORACLE_HOME/bin/crsctl query  crs  softwarepatch rac2
Oracle Clusterware patch level on node rac2 is [387459443].

De alguna manera que no alcanzamos a entender ( o igual si), tenemos que tras finalizar un parcheado los parches de los dos nodos son iguales.

Que hacemos ??

Veamos a ver cuales son los parches que tenemos instalados.
Lo primero que se nos viene a la cabeza es tirar del comando optch
Y ecejutamos un
$ORACLE_HOME/OPatch/opatch -lsinventory
o bien
$ORACLE_HOME/OPatch/opatch -lspatches
Pero, para nuestra desesperacion resulta que Opatch nos dice que hay los mismos parches instalados.
¿que hacemos ahora?

La solucon esta en patchgen

Vamos a ver realmente que es lo que tenemos instalado en los nodos.
Para ello usaremos en ambos nodos el comando
$ORACLE_HOME/bin/kfod op=patches

[oracle@rac1~]$  $ORACLE_HOME/bin/kfod op=patches
---------------
List of Patches
===============
30489227
30489632
30557433
30655595

[oracle@rac2~]$ $ORACLE_HOME/bin/kfod op=patches
---------------
List of Patches
===============
29517242
29517247
29585399
30489227
30489632
30557433
30655595

Como podemos ver, en el rac2 nos aparecen 3 parches que no tenemos en rac1.
El siguiente paso deberia de ser el buscar cuales son esos parches y decidir si los queremos aplicar donde no estan , o quitrlos de donde estan.
Dado que quitar un parche suele ser mas complicado que ponerlo , vamos ha hacer esta segunda opcion y a eliminar esos 3 parches de rac2.

Para ello,lo primero que tendremos que hacer es como usuario root

. oaenv
 $ORACLE_HOME/crs/install/rootcrs.sh -prepatch

Y tras esto, eliminaremos los parches con

$ORACLE_HOME/bin/patchgen commit -rb 29517242 
$ORACLE_HOME/bin/patchgen commit -rb 29517247
$ORACLE_HOME/bin/patchgen commit -rb 29585399

Una vez eliminados, comprobamos d enuevo con kfod que tenemos solamente los parches deseados, y sera en ese momento cuando cerremos la operacion con (de nuevo como root)

 $ORACLE_HOME/crs/install/rootcrs.sh -postpatch

Tras esto solamente tenemos que comprobar que el estado del cluster es normal y que las versiones y parches son los correctos

[oracle@rac1~]$) crsctl query crs softwarepatch -all
Oracle Clusterware patch level on node rac1 is [2701864972].
[oracle@rac1~]$ crsctl query crs activeversion  -f
Oracle Clusterware active version on the cluster is [19.0.0.0.0]. The cluster upgrade state is [NORMAL]. The cluster active patch level is [2701864972].
[oracle@rac1~]$ crsctl query crs releasepatch
Oracle Clusterware release patch level is [2701864972] and the complete list of patches [30489227 30489632 30557433 30655595 ] have been applied on the local node. The release patch string is [19.6.0.0.0].
[oracle@rac2~]$ crsctl query crs releasepatch
Oracle Clusterware release patch level is [2701864972] and the complete list of patches [30489227 30489632 30557433 30655595 ] have been applied on the local node. The release patch string is [19.6.0.0.0].

Mas informacion como siempre en la documentacion de oracle

  • Troubleshooting OPatchAuto
  • KFOD, KFED, AMDU (Doc ID 1485597.1)
  • Note 1180491.1 – KFED Tool For Windows OS
  • Note 1346190.1 – KFED.PL for diagnosing – ORA-15036 ORA-15042 ORA-15020 ORA-15033
  • Note 1505005.1 – Where to find kfed utility before Oracle Grid Infrastructure is installed

Comandos basicos en Orace RAC

Hoy vamoa a volver a las entradas para dummies, esta vez con los comandos basicos del RAC

Como paramos un RAC?

La manera mas sencilla escon permisos de root mediante el comando

export ORACLE_SID=+ASM1
export ORAENV_ASK=NO
. oraenv
sudo $ORACLE_HOME/bin/crsctl stop crs
sudo $ORACLE_HOME/bin/crsctl disable crs 

A la hora de arrancarlo ejecutaremos

export ORACLE_SID=+ASM1
export ORAENV_ASK=NO
. oraenv
sudo  $ORACLE_HOME/bin/crsctl enable crs
sudo $ORACLE_HOME/bin/crsctl start crs  

Como arrancamos/paramos una base de datos

srvctl stop database -d $DB_NAME

srvctl start database -d $DB_NAME

Como arrancamos/paramos una instancia en un nodo

Podemos hacerlo de varias maneras

srvctl start instance -d $DB_NAME-n $NODE_NAME 
srvctl start instance -d $DB_NAME -i $INSTANCE_NAME

Para pararla seria similar cambiando el start por stop

srvctl stop instance -d $DB_NAME-n $NODE_NAME 
srvctl stop instance -d $DB_NAME -i $INSTANCE_NAME

Parar elementos dedicados del RAC

Hay algunos componentes dedicados del RAC que no funcionan con la sintaxsis estandard, estos son:

  • Management database
  • ASM prxy

Administracion de la Management database

Los comados que podemos llevar a cabo sobre la management database son stop y relocate

srvctl start mgmtdb -n  $NODENAME 

srvctl stop mgmtdb -n $NODENAME 

srvctl relocate mgmtdb -n $OTRO_NODO

Administracion del ASM proxy

srvctl start res ora.proxy_advm -n  $NODENAME 

srvctl stop res ora.proxy_advm -n  $NODENAME

comandos sobre el CRS

Podemos ver la entrada Comprobar versiones del cluster

Comandos sobre el OCR

Podemos verlos en la entrada Oracle cluster registry OCR (componentes del grid)

Comandos sobre los voting disk

Podemos verlos en la entradas
Redundancia de los votingdisk en ASM
Voting disk (componentes del grid)

Comandos sobre ADVM

Introducción al ADVM

Mas entradas para dummies sobre RAC:
Comandos basicos en Orace RAC
Comandos basicos del RAC II
Eliminar un nodo del rac

Instalando el grid infraesturcure con Ansible

Hoy vamos a ver los pasos a llevar a cabo y el codigo para llevar a cabo una instalación de un Grid Infraestructura de la versión 19c en un standalone server .

Como puntos importantes a esta instalación tenemos:

Condiciones

1- Tenemos configurado el sudores del equipo cliente tal y como explicamos en Requisitos de los equipos cliente para automatizar con Ansible: SUDO
2- Vamos a instalar y configurar solamente el GI y el listener, en este paso no vamos a crear en ASM, de esta manera nos va a servir tanto para llevar a cabo una instalación de ASM como para un oracle restart sobre filesystem
3-Tendremos un punto compartido de red donde podremos obtener los binarios descargados de oracle


Para poder ejecutar esta automatización necesitamos:

  • variable env: Nombre del servidor que debe de estar inventariado. En nuestro laboratorio va a ser alone.pamplona.name
  • variable type: Esta variable en nuestro caso va a estar fija a asm
  • Variable version: Variable con el numero de version que queremos instalar,en nuestro laboratorio va a ser la 19.0.0.3

Como veremos, mas adelante , estas tres variables van a ser parseadas enpracticamente todos nuestros playbooks.

Nuestra estructura de Playbooks va a ser muy similar a la de un role de Ansible, nuestros ficheros estarán distribuidos de la siguiente manera


Raiz
|
|- vars:      Ficheros/Inventario de variables
|- templates: Ficheros de templates  
|- file:       Ficheros específicos para  playbooks 

Como veremos mas adelante, el contenido de los directorios Vars y templates va a ser común a todas las ejecuciones, pero el del directorio temp será único por ejecución.

Directorio de variables

Este directorio va a tener los ficheros con información de los estándares que queremos aplicar, por decirlo de una manera sencilla, son los ficheros de nuestras normas

En el lenguaje de Ansible este directorio se podría llamar también inventario de variables

Entr elos ficheros que vamos a usar están:

oracle_standard.yaml

Este fichero va a ser el que contenga los estándares del departamento.
Va a ser común para todas las acciones que se llevan a cabo para las bases de datos de oracle, ya sea instalación de binarios, creación de bases de datos y/o parchados
El ejemplo de nuestro laboratorio es:

[code lang=»py»]
root_user: "root"
oracle_user: "oracle"
oracle_group: "dba"
media_dir: "/mnt/media"
root_directory: "/u01/app"
oracle_inventory: "{{root_directory}}/oraInventory"
oracle_base: "{{root_directory}}/oracle"
stage_directory: "{{oracle_base}}/stage"
oracle_home_directory:
db: "{{oracle_base}}/product/{{version}}/dbhome1"
asm: "{{oracle_base}}/product/{{version}}/grid"
response_file: "{{type}_{{action}}_{{version}}.rsp"
data_location:
FS: "/oradata/{{SID}}/data"
ASM: "+{{oracle_hostname}}_DATA"
fra_location:
FS: "/oradata/{{SID}}/data"
ASM: "+{{oracle_hostname}}_FRA"
redo1_location:
FS: "/oradata/{{SID}}/redo"
ASM: "+{{oracle_hostname}}_REDO1"
redo2_location:
FS: "/oradata/{{SID}}/redo2"
ASM: "+{{oracle_hostname}}_REDO2"
sysasm_passd: changueme2020
asmdbsnmp_passwd: changueme2020

[/code]
Como cosas curiosas podeis ver que

  • Nuestros directorios raices estarán como indican las Oracle Best Practices
  • Cuando la base de datos tenga ASM los diskgroups no se llamaran DATA,REDO y FRA, sino que tendrán como prefijo el nombre del equipo y tendremos dos REDOS
  • Al contrario de las best practices de Oracle vamos ha hacer el taller a lo «old style » todo bajo el grupo dba, el añadir los temas grupos es algo trivial una vez se ha visto la manera en la que funciona el playbook

asm_SO_precondition_19.0.0.3.yaml

La notación de este fichero va a ser $TYPE_SO_precondition_$VERSION.yaml, este este fichero es el que va a ser utilizado para comprobar las precondiciones de la instalación.

En el laboratorio vamos a incluir solamente a modo de ejemplo cinco de paquetes, pero podríamos extenderlo a todo lo que queramos que se compruebe como precondicion de la instalación, como parámetros del kernel, configuraciones del equipo ( selinux, firewall ) …

En caso de tener varias distribuciones de sistemas operativos (asumimos que trabajamos bajo linux) o versiones de los mismos, seria este único fichero el que guardaría las precondiciones tanto de los valores comunes como de los específicos para cada sistema distribución/version

[code lang=»py»]
package_name :
– binutils
– elfutils-libelf
– elfutils-libelf
– oracleasm
– oracleasm-support
[/code]

asm_binaries.yaml

La notación de este fichero va a ser $TYPE_binaries.yaml, aqui tenemos información física del paquete y del response file a usar.
Este fichero no dispone del sufijo version, ya que contendrá a modo de inventario la información de todos los binarios.

[code lang=»py»]
19.0.0.3:
response_file: "asm_binaries_19.0.0.3.rsp"
binary_name: "LINUX.X64_193000_grid_home.zip"
19.0.0.5:
response_file: "asm_binaries_19.0.0.5.rsp"
binary_name: "LINUX.X64_195000_grid_home.zip"[/code]
Otra información adicional que podríamos añadir es el MD5 del binario para comprobar su estado.

Playbooks

En este laboratorio vamos a ejecutar un trabajo en AWX-RPM que va a estar formado por una secuencia de playbooks independientes.
El orden y contenido de cada uno de ellos es:

so_packages

El primer playbook a ejecutar es el que va a comprobar los prerrequisitios de nuestra instalación.
Los chequeos básicos a llevar a cabo son los paquetes y usuarios y grupos

[code lang=»py»]
# Pamplona 2019
# Playbook which checks if required packages ares installed at the destination server
#
# requires
# env: name of the server which should be in the inventory
# type: type of installation [asm|db]
# vars/[type]_SO_precomdition_[version].yaml configuration file with the S.O preconditions

– hosts: "{{env}}"
remote_user: ansible
become: yes
become_user: root
tasks:
– fail: msg="Error no server definied, please define the env variable in the job"
when: env is not defined

– name: Including package
include_vars:
file: "{{type}}_SO_precondition_{{version}}.yaml"

– name: check packages "{{package_name}}"
yum:
name: "{{package_name}}"
state: latest
with_items:
– "{{ package_name }}"

[/code]
Como veíamos en el apartado de variables, carga los paquetes necesarios de un fichero de inventario {{type}}_SO_preconditions_{{version}}.yaml , de esta manera reutilizaremos el mismo fichero para todas las versiones, teniendo que añadir simplemente ficheros de requisitos para las distintas versiones que soportemos.

oracle_directories.yaml

Tenemos un sistema que cumple con los requisitos de configuración de sistema operativo, el siguiente paso es comprobar que nuestra estructura de directorios de oracle existe y en caso contrario crearla.
Para este playbook usaremos el fichero de inventario oracle_standard.yaml en el que , como explicábamos al principio tenemos todos los estándares de nuestra compañía.

[code lang=»py»]
# Pamplona 2019
# Playbook which create the required directories
#
# requires
# env: name of the server which should be in the inventory
# type: type of installation [asm|db]
# version: version of database or asm
# vars/oracle_standard.yaml standard values for Oracle
# ignore if it can ignore errors

– hosts: "{{env}}"
remote_user: ansible
become: yes
become_user: oracle
tasks:
# checking prerrequisites
– fail: msg="Error no server definied, please define the env,type and version variables in the job"
when: env is not defined or version is not defined or type is not defined
# End prerrequisites + check var file for improvement

# Loading env
– name: Including Standard_values
include_vars:
file: "vars/oracle_standard.yaml"

– set_fact:
oracle_home: "{{oracle_home_directory.db}}"
when: type == "db"

– set_fact:
oracle_home: "{{oracle_home_directory.asm}}"
when: type == "asm"

#
– name: create directories
file:
path: "{{ item }}"
state: directory
owner: "{{ oracle_user }}"
group: "{{ oracle_group }}"
mode: ‘0775’
with_items:
– "{{ root_directory }}"
– "{{ stage_directory }}"
– "{{ oracle_inventory }}"
– "{{ oracle_base }}"
– "{{ oracle_home }}"
ignore_errors: "{{ ignore}}"
tags:
– create_directories

[/code]

unzip_binaries.yaml

El propio nombre del playbook lo dice todo.
Vamos a obtener en el equipo cliente el fichero de binarios descargable de Oracle y lo descomprimiremos en la ubiacion que hayamos elegido como $ORACLE_HOME

[code lang=»py»]
# Pamplona 2020
# Playbook which unzips the requested file
#
# requires
# env: name of the server which should be in the inventory
# type: type of installation [asm|db]
# version: version of database or asm
# vars/oracle_standard.yaml standard values for Oracle
# vars/[type]_binaries.yaml configuration file with the variables requested for the extraction
#

– hosts: "{{env}}"
remote_user: ansible
become: yes
become_user: root
tasks:
# checking prerrequisites
– fail: msg="Error no server definied, please define the env and type variable in the job"
when: env is not defined or type is not defined
# Loading env
– name: Including Standard_values
include_vars:
file: "vars/oracle_standard.yaml"

– name: Including binaries info
include_vars:
file: "vars/{{type}}_binaries.yaml"

– name: check for required binaries
stat:
path: "{{media_dir}}/{{version.binary_name}}"
register: exsists
– debug:
msg: The file is availabe
when: exsists.stat.readable == True

– fail:
msg: "ERROR: Source zip file not found"
when: exsists.stat.readable == False
ignore_errors: False

– set_fact:
oracle_home: "{{oracle_home_directory.db}}"
when: type == ‘db’

– set_fact:
oracle_home: "{{oracle_home_directory.asm}}"
when: type == ‘asm’

– name: Extract "{{media_dir}}/{{version.binary_name}} {{ oracle_home }}"
unarchive:
src: "{{media_dir}}/{{version.binary_name}}"
remote_src: yes
dest: "{{ oracle_home }}"
become: yes
become_user: "{{ oracle_user}}"

[/code]

asm_binaries_instal.yaml

Este es el playbook que lleva a cabo la acción real, veamos los pasos que lleva a cabo

  • carga de entornos comprueba los prerrequisitos y carga los ficheros de variables
  • Genera un response file: Este paso es importante ya que, utiliza una template en Jinja para , con las variables obtenidas de nuestro inventario de variables oracle_standard generar un fichero de response en el formato especifico para nuestra version de asm
  • Instalación de binarios: Ejecuta el comando de instalación con el response file generado anteriormente, esta instalación da muchos warnings, entre otras cosas por que , en este laboratorio no estamos cumpliendo todas las Oracle Best practices ( usuarios, grupos, ubicaciones), de ahí que le añadamos la calusula ignore Errors: True
  • Ejecutamos el conocido root.sh
  • Registro del CRS: Hemos instalado e inventariado los binarios, pero el CRS no esta instalado, este paso DEBE de tener ASM, pero, nosotros vamos a llevarlo a cabo sin la necesidad de decirle que tenemos uno, de ahí que lo hagamos ahora en un paso separado , como podemos observar, este paso se lleva a cabo como root, no como usuario oracle
  • Creación de un Listener: Tenemos nuestro CRS instalado y registrado, pero esta vacío, por lo que , vamos a crear un listener bajo esta rama de binarios
  • Habiitar un Listener: Este paso es redundante y da error , ya que el paso anterior lo deja habilitado, simplemente lo ejecutamos como guarda de seguridad
  • Arrancar el Listener: Aunque el objetivo de nuestro laboratorio de hoy era el de tener instalado un cls que funcione, hemos de pensar que , en un futuro crearemos el asm y probablemente instalemos las bases de datos, por lo que, es importante asegurarse que una vez acabamos esta todo encendido

[code lang=»py»]
# Pamplona 2020
# Playbook which sends a respone file and uses it to install Oracle restart/ CRS / Grid on alone server
# requires
# env: name of the server which should be in the inventory
# type: asm or dba
# version: version of database or asm
# vars/oracle_standard.yaml standard values for Oracle
# vars/asm_binaries.yaml: Info with the asm binaries

– hosts: "{{ env }}"
remote_user: ansible
become: yes
become_user: root
tasks:
# checking prerrequisites
– fail: msg="Error no server definied, please define the env variable in the job"
when: env is not defined or version is not defined or type is not defined
# Loading env
– name: Including Standard_values
include_vars:
file: "vars/oracle_standard.yaml"

– name: Including binaries info
include_vars:
file: "vars/{{type}}_binaries.yaml"
– set_fact:
oracle_home: "{{oracle_home_directory.db}}"
when: type == ‘db’

– set_fact:
oracle_home: "{{oracle_home_directory.asm}}"
when: type == ‘asm’
#
– name: generate response file
template:
src: "templates/{{ version.response_file }}.j2"
dest: "{{ stage_directory }}/{{version.response_file}}"
mode: ‘0644’

– name: Install Grid 19c Software
shell: "{{ oracle_home }}/gridSetup.sh -silent -responseFile {{ stage_directory }}/{{version.response_file}}"
become: yes
become_user: "{{ oracle_user }}"
args:
chdir: "{{ oracle_home }}"
ignore_errors: True

– name: execute root.sh
shell: "{{ oracle_home }}/root.sh"
become: yes
become_user: root
args:
chdir: "{{ oracle_home }}"

– name: Configure CRS
shell: $GI_HOME/perl/bin/perl -I $GI_HOME/perl/lib -I $GI_HOME/crs/install $GI_HOME/crs/install/roothas.pl
become: yes
become_user: root
args:
chdir: "{{ oracle_home }}"
environment:
GI_HOME: "{{ oracle_home }}"
ignore_errors: True

– name: Create listener
shell: "$GI_HOME/bin/srvctl add listener -listener LISTENER -oraclehome {{ oracle_home }}"
become: yes
become_user: "{{oracle_user}}"
args:
chdir: "{{ oracle_home }}"
environment:
GI_HOME: "{{ oracle_home }}"
ORACLE_BASE: "{{ oracle_base}}"
ignore_errors: False

– name: Enable listener
shell: $GI_HOME/bin/srvctl enable listener -listener LISTENER
become: yes
become_user: "{{oracle_user}}"
args:
chdir: "{{ oracle_home }}"
environment:
GI_HOME: "{{ oracle_home }}"
ORACLE_BASE: "{{ oracle_base}}"
ignore_errors: True

– name: Start listener
shell: $GI_HOME/bin/srvctl start listener -listener LISTENER
become: yes
become_user: "{{oracle_user}}"
args:
chdir: "{{ oracle_home }}"
environment:
GI_HOME: "{{ oracle_home }}"
ORACLE_BASE: "{{ oracle_base}}"
ignore_errors: False

[/code]

Como siempre, las ultimas versiones de este codigo están disponibles en el proyecto provisioning en GITHUB