Aprovisionamiento de una base de datos con ansible

Llego la hora de la verdad.
Vamos a juntar todos los pasitos que hemos estado llevando a cabo en los distintos playbooks para llevar a cabo un aprovisionamiento total de un nuevo server Oracle v19.3 en su modalidad single server

Para ello vamos a usar el codigo que tenemos en GitHUB y las explicaciones detalladas de las anteriores entradas.

Recopilando un poco la informacion tenemos un árbol de playbooks y ficheros

  Root
   |
   |- vars:
        |- main.yaml                     Specific rules an locations of our oracle department
        |- oracle_files.yaml              Source  & patch files info and locations    
   |
   |- files
        |-CRQ001_asm_create_disks.yaml      Example of asm disks provisioning
        |-CRQ002_createdb_ASMTEST.yaml      Example of database provisioning
        |-CRQ003_createdb_FSTEST.yaml       Example of database provisioning
   |    
   | - roles
         |so_check                           Checks the pre requirements of S.O
            -|
             |vars
                |-  OracleLinux_7_oracle_19.3_requisites.yaml      Prerrequisites for a installation of a 19.3 oracle files at OEL7
            
         |oracle_directories                 Role wich checks all required file structure exsists
         |
         |unzip_binaries                     Role wich unzips selected files 
         |
         |asm_binaries_install               Role wich install and setus the CRS = Listener          
            |
            |Templates 
                |-asm_binaries_19.3.rsp.j2   Jinja files wich create the asm response file for 19.3 version 
                |-asm_binaries_12.1.rsp.j2   Jinja files wich create the asm response file for 12.1 version 
                |-asm_binaries_12.2.rsp.j2   Jinja files wich create the asm response file for 12.2 version 
         |    
         | asm_create                       Role which configures asmlib, create asmdisks, diskgroups and asm 
         |
         | db_create                        Role wich creates a database 
            |
            |Templates 
                |-rdbms_createdb_19.3.rsp.j2   Jinja files wich create the rdbms response file for 19.3 version 
                |-rdbms_createdb_12.1.rsp.j2   Jinja files wich create the rdbms response file for 12.1 version 
                |-rdbms_createdb_12.2.rsp.j2   Jinja files wich create the rdbms response file for 12.2 version 
         |
         |
    | check_so_prerrequisites.yaml     Playbook wich checks the S.O  prerrequisites
    |     
    | asm_only_binaries                Playbook which install CRS listener and setup them
    | 
    | asm_full_install                 Playbook which install CRS,listeners, confiurres asmlib, create asmdisks,diskgroups and asm 
    |
    | db_binaries_install              Playbook wich installs and inventory database binaries 
    |
    | asmfull_plus_db_binaries         Playbook   which install CRS,listeners, confiurres asmlib, create asmdisks,diskgroups, asm and database binaries 
    |
    | db_createdb                      Playbook wich creates a database 


Prerrequisitos del provisionamientio

Vamos a llevar a cabo el proceso en dos pasos.

Paso 1 REQ01

Desde la dirección del departamento nos indican que nos han enviado la petición REQ01 donde ya tenemos un servidor llamado alone.pamplona.name con la IP 192.168.51.6 donde el equipo de linux nos ha echo una instalación mínima de Oracle Linux 7.
Ademas de esto, nos han preparado los siguientes discos:

  • partición de 20G montado bajo /u01 que será dedicada para oracle
  • Dos discos para DATA que se corresponden con /dev/sda y /dev/sdb
  • Un disco para FRA que se se corresponde con /dev/sdc
  • Un disco para REDO1 que se corresponde con /dev/sdd
  • Un disco para REDO2 que se corresponde con /dev/sde

Paso 2 : REQ03

El segundo paso es que nos indican que necesitamos crear una Base de datos 19.3

Preparación del servidor

Lo primero que tenemos que llevar a cabo es la preparación del servidor, transfiriendo los mecanismos de conexión de Ansible y configurando el sudores tal como comentábamos en la entrada
Requisitos de los equipos cliente para automatizar con Ansible: SUDO

Plataformacion del sistema oeprativo

Este paso va a llevar a cabo las tareas de preinstalacion y configuración de sistema operativo que nos indica Oracle en sus manuales de instalacion.
Nosotros lo llevaremos a cabo mediante dos roles:

  • so_check
  • oracle_directories

Podemos ver mas detalle en la entrada Plataformando el sistema operativo con Ansible

Instalación de grid infraestructura

En este paso vamos a llevar a cabo la instacion del los recursos y el registro en el servidor del oracle restart.

Para ellos usaremos los roles:

  • unzip_binaries
  • asm_binaries_install
    Una vez finalizado este paso tendremos en funcionamiento un servidor plataformado con un CRS en funcionamiento, pero no tenemos asm en marcha
    Tenemos mas detalle de todos los pasos en Instalando el grid infraesturcure con Ansible

    Instalación de discos y ASM

    Dado que en la petición que nos han llegado nos solicitan una base de datos sobre ASM y nos dan los discos, necesitaremos configurar los discos y el asm, para eso utilizaremos los roles

    • asm_create

    Pero, ademas de usar el role , tendremos que generar un fichero de aprovisionamiento con la información de los discos, para ello crearemos el fichero files/REQ01_asm_create_disks.yml que será especifico para esta petición.

    Para tener mas detalles de lo que hace este bloque de playbooks y el formato y funcionamiento de este fichero podemos ver la entrada Creación de Discos y ASM con Ansible

    Instalación y creación de base de datos 19.3

    En el paso anterior habíamos acabado con la petición REQ01, pero también tenemos la petición REQ03 donde nos solicitan una base de datos 19.3 en ASM , esto lo vamos a llevar a cabo con los playbooks

    • db_binaries_install
    • db_createdb

    Al igual que en el paso anterior, esta petición de creación de base de datos tiene información dedicada, por lo que tendremos que crear un fichero de información especifico files/REQ03_createdb_TEST.yaml
    Para tener mas información de como completar este fichero y cuales son los pasos que ejecutan nuestros roles podemos ver la entrada Instalación y Creación de base de datos con Ansible

    Como podemos ver , el llevar a cabo este tipo de tareas con Ansible es extremadamente sencillo, en este taller hemos usado variedad de playbooks independientes ya que a nivel didáctico es mucho mas sencillo el explicarlo por bloques funcionales , pero en un entorno real se pueden crear tareas o roles con la union de varios de ellos mediante flujos de trabajo

Plataformando el sistema operativo con Ansible

Hoy vamos a recuperar la entrada de como preparar el sitema operativo (en este caaso un OEL 7)para una instalacion de Oracle.

Para esto vamos a usar el role so_check del que podemos encontrar la ultima version en nuestro GitHub

Este Playbok no hace nada del otro mundo, ya que simplemente traslada a Ansible los pasos que llevamos a cabo una y otra vez cada vez que preparamos un servidor, como vereis lo mas complicado del mismo es la sintaxsis.

Veamos el codigo completo y luego lo analizaremos por partes

[code lang=»py»]
# Pamplona 2019
# Playbook which checks if teh hosts has all the requested prereequisites
#
# requires
# env: name of the server which should be in the inventory
# vars/oracle_standard.yaml configuration file with all the deppartment values
# vars/so_[version]_requisites.yaml configuration file with the packages required for this version of the software

– 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 standard variables"
include_vars:
file: "vars/oracle_standard.yaml"

– name: "Including So {{version}} requisites"
include_vars:
file: "vars/so_{{version}}_requisites.yaml"

– name: Chequeamos the group
group:
name: "{{oracle_group}}"
gid: "{{oracle_gid}}"
state: present
tags: oragroup

– name: Check the oracle user
user:
name: "{{oracle_user}}"
uid: "{{oracle_uid}}"
group: "{{oracle_group}}"
shell: /bin/bash
tags: orauser

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

– name : Kernel values
sysctl:
name: "{{ item.name }}"
value: "{{item.value}}"
state: present
ignoreerrors: yes
sysctl_file: /etc/sysctl.d/30-oracle.conf
with_items: "{{kernel_values}}"
tags: sysctl

##We execute Huge Pages separately
– name: Huge Pages
sysctl:
name: vm.nr_hugepages
value: "{{huge_pages}}"
sysctl_set: yes
state: present
sysctl_file: /etc/sysctl.d/30-oracle.conf
ignoreerrors: yes
tags: huge_pages

– name: Limits para el usuario
pam_limits:
domain: oracle
use_max: yes
limit_type: "{{ item.tipo }}"
limit_item: "{{ item.name }}"
value: "{{item.value}}"
dest: /etc/security/limits.d/30-oracle.conf
with_items: "{{limits}}"
tags: limits

– name: Disable firewall
service:
name: firewalld
state: stopped
enabled: no
tags: firewall

– name: disabling SElinux
selinux:
policy: targeted
state: disabled
tags: SELinux
[/code]

Comprobamos usuarios y grupos

Lo primero que hacemos es la comprobacion de que tenemos los usuarios y grupos que necesitamos.
En nuestro taller usamos la configuracion mas basica , que es oracle:dba para toda la instalacion

Comprobamos los paquetes del sistema operativo

En este bloque comprobamos los paquetes del sistema operativo.
Para ello usuaremos el modulo yum de Ansible con una lista de los paquetes, esta lista los vamos a leer de un fichero de variables en el que tendremos reflejado todo lo necesario para la plataformacion de un servidor para la version especifica de Oracle que tenemos.

El conenido de este fichero refrente a los paquetes es una simple lista
[code lang=»py»]
package_name :
– binutils
– oracleasm
– oracleasm-support
– compat-libcap1
– compat-libstdc++-33
– elfutils-libelf-devel
– fontconfig-devel
– glibc
– glibc-devel
[/code]

Valores del Kernel

El siguiente paso es el configurar los parametros del kernel que queremos.
Para este paso vamos a usar el modulo sysctl, aplicando tantos valores como queramos de nuestro fichero de requerimientos
La sintaxsis de estos requerimientos es

[code lang=»py»]
kernel_values:
– { name: fs.file-max, value: 6815744 }
– { name: kernel.sem, value: "250 32000 100 128" }
– { name: kernel.shmmni, value: 4096 }
[/code]

Huge Pages

Las Huge pages es un parametro del kernel como cualquier otro, podriamos haberlo incluido dentro de los kernel parameters pero a mi personalmente me gusta tenerlo separado .
En nuestro caso no estamos dandole un valor fijo, sino que le asignamos el 60% del total del servidor

[code lang=»py»]
#60 percent huge pages
huge_pages: "{{((0.6 * ansible_memtotal_mb)*1024/2)|round|int }}"
[/code]

Limites

El siguiente paso en la plataformacion del sistema operativo es ajustar los soft y hard limits para el usuario Oracle.
Para esto usaremos el modulo pam_limits. El codigo asociado del fichero de variables es muy similar al que usamos en el kernel y, al igual que haciamos con las huge pages obtendremos alguno de estos valores dinamicamente en funcion de los recursos del servidor que vayamos a plataformar

[code lang=»py»]
limits:
– { tipo: ‘soft’ ,name: ‘nproc’, value: 16384 }
– { tipo: ‘hard’ ,name: ‘nproc’, value: 16384 }
– { tipo: ‘soft’ ,name: ‘memlock’, value: "{{ ((0.9 * ansible_memtotal_mb)*1024)|round|int }}" }
– { tipo: ‘hard’ ,name: ‘memlock’, value: "{{ ((0.9 * ansible_memtotal_mb)*1024)|round|int }}" }
[/code]

Desabilitar SElinux y Firewall

Este ultimo paso es mas bien opcional, ya que no deberia de ser un requisito, pero, en la mayoria de las plataformaciones la seguridad suele estar delegada en los elementos de red y el SELinux se deshabilita, por lo que, lo hemos incluido en nuestro playbook

[code lang=»py»]
– name: Disable firewall
service:
name: firewalld
state: stopped
enabled: no
tags: firewall

– name: disabling SElinux
selinux:
policy: targeted
state: disabled
tags: SELinux
[/code]

Como habeis podido ver,como os comentaba al principio no es nada del otro mundo, simplemente es trasladar a lenguaje de ansible los pasos que llevamos a cabo manualmente 1000 veces .

Como siempre, esta entrada es solamente un taller basico, no dudeis en encontrar la ultima y valida version del role en proyecto provisioning e GitHub

Espacios y tabulaciones en Ansible

Hoy vamos a empezar con una pequeña entrada referente a la automatización con Ansible

Como sabemos, Ansible a diferencia de los lenguajes de programación clásicos basa los bloques de código en las sangrías ( creo que sangría es en nuestro caso la traducción mas correcta del ingles >i>Identation)

Llegados a este punto, los programadores de toda la vida, aquellos que siempre hemos programado en la ventana de terminal, gente precisa y que optimiza el código, usamos tabulaciones, pero , hemos de tener cuidado, ya que Ansible no nos lo permite.

Esto nos lleva a el siguiente video

A parte de bromas, para todos aquellos que estamos acostumbrados a las tabulaciones, hay un pequeño truco para indicarle al vim que traslade las tabulaciones a espacios

[code lang=plain]
autocmd FileType yaml set local ai ts=2 sw=2 et
[code]

Con este sencillo comando podremos seguir usando nuestras tabulaciones mientras programamos en Ansible

Creación de Discos y ASM con Ansible

Siguiendo con las entradas de Aprovisionamiento de una base de datos con ansible vamos a ver la manera de automatizar la configuracion de discos de ASM mediante ansible.

Supongamos tenemos los prerrequisitos:

  • Un servidor OEL7 con el CRS instalado y el listener en marcha tal y como explicabamos en Instalando el grid infraesturcure con Ansible
    • Dos discos para nuestro diskgroup DATA
    • un disco para nuestro diskgroup FRA
    • un disco para nuestro diskgroup REDO1
    • un disco para nuestro diskgroup REDO2

        Para la ejecucion de nuestro taller de creacion de asm usaremos los siguientes ficheros del repositorio

        Raiz
        |
        |- vars:
             |- oracle_standard.yaml      Fichero con los estandares del departamento
        |
        |- templates
        |
         |- files
         |-REQ01_asm_create_disks.yaml  Ejemplo de informacon de  provisionamiento de discos para el ASM 
        |  
        | asmlib_configure.yaml         Playbook que configura el asmlib
        | asmlib_create_disks.yaml      Playbook que configura los discos de ASM 
        | asm_create.yaml               Playbook que crea una instancia +ASM con en el GRID y con los discos previamente instalados
        

        Ficheros de variables

        Al igual que en el resto de ejecuciones del taller vamos a necesitar el fichero oracle_standard.yaml que contiene todas la estandarizacion de nuestro departamento

        Ficheros informacion

        La creacion de discos necesita de la informacion de que discos del sistema operativo van a ir dedicados a que diskgroup, esta informacion la depositaremos en el directorio files, que va a ser el unico directorio donde deberemos/podremos modificar los ficheros .

        El formato del fichero sera el de una lista en yaml en el que indicaremos el nombre del dispositivo para cada uno de los diskgroups.
        [code lang=»py»]
        DATA:
        – /dev/sda
        – /dev/sdb
        FRA:
        – /dev/sdc
        REDO1:
        – /dev/sdd
        REDO2:
        – /dev/sde
        [/code]

        El nomre del fichero sera [REQ]_asm_create_disks. Donde REQ es el valor en mayusculas de la variable req que es el identificador unico de nuestro fichero, este identificador en un entorno de produccion real podria corresponderse con el numero de peticion del sistema gestion de la compañia.

        Creacion de los discos

        Una vez tenemos claros los ficheros de fuentes y variables ejecutaremos nuestros playbooks.

        asmlib_configure.yaml

        El playbook asmlib_configure.yaml vieje a ser el equialente a la ejecucion manual de oracleasm configure -i
        Como podeis ver en el codigo que es bastante basico, ejecuta la configuracion del oracleasm para cada uno de los campos obteniendo la informacion del fichero de variables generico

        [code lang=»py»]
        # Pamplona 2019
        # Playbook which configures_asmlib
        #
        # requires
        # env: name of the server which should be in the inventory
        # vars/oracle_standard.yaml configuration file with all the deppartment values

        – 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 standard variables"
        include_vars:
        file: "vars/oracle_standard.yaml"
        – name: configirando usuario
        command: /usr/sbin/oracleasm configure -u "{{oracle_user}}"

        – name: configurando grupo
        command: /usr/sbin/oracleasm configure -g "{{oracle_group}}"

        – name: seteamos al arranque
        command: /usr/sbin/oracleasm configure -e

        – name: activamos el logical block
        command: /usr/sbin/oracleasm configure -b

        – name: arrancamos
        command: /usr/sbin/oracleasm init

        – name: estado
        command: /usr/sbin/oracleasm status
        register: oasm_status

        [/code]

        asmlib_create_disks.yaml

        El segundo paso es la creacion de los discos en el asmlib .
        Este es el playbook que va a requerir de ese fichero externo [REQ]_asm_create_disks, para cada uno de los discos fisios incluidos.

        [code lang=»py»]
        # Pamplona 2019
        # Playbook which checks if the hosts has all the requested prerequisites
        #
        # requires
        # env: name of the server which should be in the inventory
        # REQ: number of request
        # vars/oracle_standard.yaml configuration file with all the department values

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

        – name: "Including standard variables"
        include_vars:
        file: "vars/oracle_standard.yaml"

        – name: "Including So {{version}} requisites"
        include_vars:
        file: "files/{{req|upper}}_asm_create_disks.yaml"

        – name: creating DATA disks
        shell:
        cmd: "/usr/sbin/asmtool -C -l /dev/oracleasm -n {{oracle_hostname|upper}}_DATA0{{ansible_loop.index}} -s {{item}} -a force=yes "
        loop: "{{DATA}}"
        loop_control:
        extended: yes

        – name: Creating FRA disks
        shell:
        cmd: "/usr/sbin/asmtool -C -l /dev/oracleasm -n {{oracle_hostname|upper}}_FRA0{{ansible_loop.index}} -s {{item}} -a force=yes "
        loop: "{{FRA}}"
        loop_control:
        extended: yes

        – name: Creating REDO1 disks
        shell:
        cmd: "/usr/sbin/asmtool -C -l /dev/oracleasm -n {{oracle_hostname|upper}}_REDO1_{{ansible_loop.index}} -s {{item}} -a force=yes "
        loop: "{{REDO1}}"
        loop_control:
        extended: yes

        – name: Creating REDO2 disks
        shell:
        cmd: "/usr/sbin/asmtool -C -l /dev/oracleasm -n {{oracle_hostname|upper}}_REDO2_{{ansible_loop.index}} -s {{item}} -a force=yes "
        loop: "{{REDO2}}"
        loop_control:
        extended: yes

        – name: scanning disks
        shell:
        cmd: "/usr/sbin/oracleasm scandisks"

        [/code]
        debilidades
        -Como curiosidad podeis ver que en mi taller no sigo las normativa de oracle, llamando a los diskgroups HOSTNAME_DATA en ved de DATA y manteniendo 2 grupos de REDO en ved e uno.
        -Este playbook solamente puede usarse para provisionamiento y no para añadir nuevos discos a un diskgroup ya exsistente ya que numerara los discos empezando desde cero. (uso del fact ansible_loop.index)

        Creacion del asm

        Llegados a este punto, tenemos el grid corriendo, el listener arriba y los dispositivos creados , por lo que solamente nos queda el crear el ASM
        El siguiente playbook simplemente va a llevar a cabo una creacion del ASM en modo command line silent y añadirle los discos a sus respectivos diskgroups

        [code lang=»py»]
        # Pamplona 2020
        # Playbook which creates a database
        #
        # requires
        # env: name of the server which should be in the inventory
        # vars/oracle_standard.yaml standard values for Oracle
        #

        – hosts: "{{env}}"
        vars:
        type: asm
        remote_user: ansible
        tasks:

        # checking prerequisites
        – fail:
        msg: "Error no server defined, please define the env variable in the job"
        when: env is not defined

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

        – name: checking oratab
        shell:
        cmd: "cat /etc/oratab|grep +ASM |sed -e ‘s/# line added by Agent/ /g’ -e ‘s/:/ /g’|awk ‘{ print $1}’ "
        register: count

        – fail:
        msg: "ERROR: The chain {{item}} exists at {{env}} /etc/oratab file "
        when: item == "+ASM"
        with_items:
        – "{{count.stdout_lines}}"

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

        – name: Creating syslog file
        copy:
        dest: /etc/rsyslog.d/30-oracle.conf
        content: |
        "local0.info {{oracle_home}}/rdbms/audit/asmaudit.log
        &~"
        force: yes
        become: yes
        become_user: root

        – name: Creating logrotate file
        copy:
        dest: /etc/logrotate.d/30-oracle_logs
        content: |
        "{{oracle_home}}/rdbms/audit/asmaudit.log {
        weekly
        rotate 4
        compress
        copytruncate
        delaycompress
        notifyempty
        }"
        force: yes
        become: yes
        become_user: root

        – name: create ASM
        become: yes
        become_user: "{{oracle_user}}"
        shell:
        cmd: "{{ oracle_home }}/bin/asmca -silent
        -configureASM
        -sysAsmPassword {{sysasm_passd}}
        -asmsnmpPassword {{asmdbsnmp_passwd}}
        -diskString \"/dev/oracleasm/disks/*\"
        -diskGroupName {{oracle_hostname|upper}}_DATA
        -disk \"/dev/oracleasm/disks/{{oracle_hostname|upper}}_DATA*\"
        -param ASM_POWER_LIMIT=1
        -param DIAGNOSTIC_DEST={{oracle_base}}
        -param AUDIT_SYSLOG_LEVEL=’local0.info’
        -param AUDIT_SYS_OPERATIONS=TRUE
        -redundancy EXTERNAL"

        – name: Create FRA, REDO1 and REDO2
        become: yes
        become_user: "{{oracle_user}}"
        shell:
        cmd: "{{ oracle_home }}/bin/asmca -silent
        -createDiskGroup
        -sysAsmPassword {{sysasm_passd}}
        -diskString \"/dev/oracleasm/disks/*\"
        -diskGroupName {{oracle_hostname|upper}}_{{item}}
        -disk \"/dev/oracleasm/disks/{{oracle_hostname|upper}}_{{item}}*\"
        -redundancy EXTERNAL "
        with_items:
        – FRA
        – REDO1
        – REDO2
        [/code]

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