=====Ein Oracle Linux 8 Basis System für Ansible verwenden - eine Oracle Umgebung mit Ansible warten==== **Aufgabe:** Das Verteilen von Oracle Patchen soll über Ansible automatisiert werden, dazu ist es aber im ersten Schritt notwendig sich mit Anible vertraut zu machen. Ansible (https://www.ansible.com/) ist ein Open-Source Werkzeug zur Konfiguration und Administration, insbesondere im Umfeld von RedHat basierenden Server Systemen. Für die Verwaltung von Ansible steht als OpenSource Projekt Ansible AWX ( https://github.com/ansible/awx ) zur Verfügung , die gleiche Applikation mit Support von Red Hat als Ansible Tower (https://www.ansible.com/). Siehe zur Installation und den ersten Schritten => [[linux:oracle_linux_8_ansible_tower|Ansible Tower unter CentOS 8]] ---- ==== Setup der Entwicklungs-Umgebung ==== In der produktiven Umgebung wird Ansible mit Ansible Tower als lizensierte Umgebung auf RedHat eingesetzt. Aber um die Oracle Skripte im Vorfeld zu entwickeln und sich in die Materie einzuarbeiten, wird eine reine Ansible Open Source Umgebung unter Oracle Linux 8 aufgesetzt. Im ersten Schritt wird ein Oracle Linux 8 als Standardsystem wie für eine DB Umgebung aufgesetzt => siehe dazu [[linux:linux_8_system_grundeinstellungen_oracle_datenbank_rac|Ein Oracle Linux 8 Basis System]] . Danach ist es wichtig eine gute vi Umgebung für das Erstellen der Ansible Scripts aufzusetzen => [[prog:yaml_check_syntax|Mit Ansible YAML arbeiten ohne Nerven Zusammenbruch]] ---- ==== Ansible über EPL unter Oracle Linux 8 installieren==== ===EPL Repositorie einrichten=== Wir benötigen noch das Oracle EPL Repostiory: #Was ist bereits aktiviert? dnf repolist # EPL nachinstallieren dnf info oracle-epel-release-el8.x86_64 dnf install oracle-epel-release-el8.x86_64 # oder falls nur dekativiert # yum-config-manager --enable ol8_developer_EPEL dnf repolist repo id repo name ol8_UEKR6 Latest Unbreakable Enterprise Kernel Release 6 for Oracle Linux 8 (x86_64) ol8_appstream Oracle Linux 8 Application Stream (x86_64) ol8_baseos_latest Oracle Linux 8 BaseOS Latest (x86_64) ol8_developer_EPEL Oracle Linux 8 EPEL Packages for Development (x86_64) ===Ansible installieren=== dnf search ansible dnf install ansible ansible-doc vim-ansible Version und Pfade prüfen: ansible --version ansible 2.9.21 config file = /etc/ansible/ansible.cfg configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python3.6/site-packages/ansible executable location = /usr/bin/ansible python version = 3.6.8 (default, May 19 2021, 10:00:09) [GCC 8.4.1 20200928 (Red Hat 8.4.1-1.0.1)] ---- === Master User anlegen === Gruppen und User anlegen: useradd ansible passwd ansible su - ansible #generate ssh key ssh-keygen -t rsa # Zugriff auf sich selbst konfigurieren! ssh ansible01.pipperr.local cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys #Auf die richtigen Rechte achten! chmod 600 ~/.ssh/authorized_keys ---- ==== Den Ansible User in der Umgebung anlegen und die Schlüssel in der Umgebung verteilen === Ansible arbeitet per SSH Key, d.h. auf den jeweiligen Maschinen muss zuvor der SSH Key verteilt und ein User wie "ansible" sollte auf den Maschinen existieren, das Arbeiten nur mit "root" ist nicht zu empfehlen. Der User Ansible muss auf der Maschine ohne Password sudo ausführen können, d.h. er muss in der Sudo Liste stehen! === Manuell anlegen === User manuell anlegen, diese Schritte wohlen wir aber im Anschluss automatisieren. Auf dem ersten Zielsystem: useradd ansible passwd ansible usermod -G wheel ansible visudo %wheel ALL=(ALL) NOPASSWD: ALL su - ansible ssh-keygen -t rsa Key Austausch mit den Key vom Ansible Server: # Vom Ansible Server aus! # Auf jedem Ziel System anmelden: ssh apex01.pipperr.local ssh ansible01.pipperr.local cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys exit ---- ==== Ansible Grundlagen und die ersten Playbooks erstellen ==== Begrifflichkeiten: * **Playbook** Kompletter Ablauf - enthält die **Plays** * **Plays** last die eigentlichen **Tasks** zusammen und verbindet diese mit einer Gruppe von Hosts * **Tasks** die eigentlichen konkreten Aufgaben die auf einem Host durchgeführt werden sollen Die eigentlichen Play Books werden unter dem User "ansible" erstellt. Um ein zentrale Stelle für die Entwicklung der Playbooks zu verwenden, folgende Struktur unter /srv/ansible angelegt: * /srv/ansible für alle ansible relevanten Daten * /srv/ansible/inventory - Die Server Liste * /srv/ansible/<> - Projektverzeichnis für das Playbook * Link /srv/ansible/<>/inventory auf /srv/ansible/inventory um in allen Playbooks die gesamte Serverliste zu verwenden #root mkdir /srv/ansible chown -R ansible:ansible /srv/ansible Im Playbook empfiehlt die Dokumentation von Ansible hier die folgende Struktur => https://docs.ansible.com/ansible/latest/user_guide/sample_setup.html . * README.md - Doku * groups_vars - Gruppen Definitionen * hosts_vars - Hosts Definitionen * inventory - Inventar Listen * side.yml - was wollen wir tun * templates - Templates auf die in den Tasks zugegriffen wird Aufbau einer Beispiel Umgebung, im ersten Schritt eine Template Struktur anlegen um diese immer wieder zu verwenden: su - ansible touch /srv/ansible/inventory mkdir /srv/ansible/play_book_template cd /srv/ansible/play_book_template # Grund Struktur anlegen touch README.md mkdir group_vars mkdir hosts_vars ln -s /srv/ansible/inventory inventory touch site.yml mkdir templates === Zentrales Inventory hinterlegen === Um nicht in jedem Playbook alle Ziel pflegen zu müssen, wird diese Datei zentral angelegt und verlinkt: Datei /srv/ansible/inventory vi /srv/ansible/inventory [ORA_SERVER] apex01.pipperr.local [MANAGMENT] ansible01.pipperr.local #Obergruppe definieren [LAB:children] ORA_SERVER MANAGMENT === Inventory aus KeePass erzeugen === Mit Hilfe des Pyhton Moduls PyKeePass https://pypi.org/project/pykeepass/ "https://github.com/libkeepass/pykeepass" lässt sich aus einer vorhanden Key Passdatei ein Inventroy erzeugen. Siehe dazu => [[python:python_read_keepass_file|Keepass Datei mit Python auslesen um Ansible Konfiguration zu erzeugen ]] ---- ==== Ohne Playbook arbeiten - auf allen Server ein Kommando ausführen ==== Liegt ein Inventory vor und ist der Zugriff konfiguriert kann ein Befehl auch auf allen Knoten mit der "-a" Option ausgeführt werden. #Hier noch mit Passwort: ansible ORA_SERVER -a "/bin/uname -a" -k SSH password: apex01.pipperr.local | CHANGED | rc=0 >> Linux apex01.pipperr.local 5.4.17-2036.103.3.1.el8uek.x86_64 #2 SMP Sun Feb 14 12:54:18 PST 2021 x86_64 x86_64 x86_64 GNU/Linux Oder ein einfaches PlayBook erstellen, und den Output ausgeben und in eine Datei schreiben lassen. --- - name: Execute Command hosts: all tasks: - name: Execute Command command: "/bin/uname -a" register: serverInfo - debug: var=serverInfo.stdout_lines - name: Write variable to file local_action: copy content="{{serverInfo}}" dest=./server_info [ansible@ansible01 deploy_ansible_user]$ ansible-playbook -l ALL execute.yml -k --verbose Using /srv/ansible/deploy_ansible_user/ansible.cfg as config file SSH password: PLAY [Execute Command] ********************************************************************************************************************* TASK [Gathering Facts] ********************************************************************************************************************* ok: [apex01.pipperr.local] ok: [ansible01.pipperr.local] TASK [Execute Command] ********************************************************************************************************************* changed: [ansible01.pipperr.local] => {"changed": true, "cmd": ["/bin/uname", "-a"], "delta": "0:00:00.003301", "end": "2021-06-12 17:47:09.810925", "rc": 0, "start": "2021-06-12 17:47:09.807624", "stderr": "", "stderr_lines": [], "stdout": "Linux ansible01.pipperr.local 5.4.17-2102.201.3.el8uek.x86_64 #2 SMP Fri Apr 23 09:05:57 PDT 2021 x86_64 x86_64 x86_64 GNU/Linux", "stdout_lines": ["Linux ansible01.pipperr.local 5.4.17-2102.201.3.el8uek.x86_64 #2 SMP Fri Apr 23 09:05:57 PDT 2021 x86_64 x86_64 x86_64 GNU/Linux"]} changed: [apex01.pipperr.local] => {"changed": true, "cmd": ["/bin/uname", "-a"], "delta": "0:00:00.004017", "end": "2021-06-12 17:47:09.864344", "rc": 0, "start": "2021-06-12 17:47:09.860327", "stderr": "", "stderr_lines": [], "stdout": "Linux apex01.pipperr.local 5.4.17-2036.103.3.1.el8uek.x86_64 #2 SMP Sun Feb 14 12:54:18 PST 2021 x86_64 x86_64 x86_64 GNU/Linux", "stdout_lines": ["Linux apex01.pipperr.local 5.4.17-2036.103.3.1.el8uek.x86_64 #2 SMP Sun Feb 14 12:54:18 PST 2021 x86_64 x86_64 x86_64 GNU/Linux"]} TASK [debug] ******************************************************************************************************************************* ok: [apex01.pipperr.local] => { "serverInfo.stdout_lines": [ "Linux apex01.pipperr.local 5.4.17-2036.103.3.1.el8uek.x86_64 #2 SMP Sun Feb 14 12:54:18 PST 2021 x86_64 x86_64 x86_64 GNU/Linux" ] } ok: [ansible01.pipperr.local] => { "serverInfo.stdout_lines": [ "Linux ansible01.pipperr.local 5.4.17-2102.201.3.el8uek.x86_64 #2 SMP Fri Apr 23 09:05:57 PDT 2021 x86_64 x86_64 x86_64 GNU/Linux" ] } PLAY RECAP ********************************************************************************************************************************* ansible01.pipperr.local : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 apex01.pipperr.local : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ---- ==== Playbook Beispiel - Ansible User auf den zu überwachenden Knoten über Root anlegen ==== Über den User Root soll im ersten Schritt der Ansible User mit dem jeweiligen Root Passwort angelegt werden. Wenn das Root Passwort aber nicht überall gleich ist muss das Password auf Host Ebene hinterlegt werden, falls gleich kann das auf der "all" Ebene erfolgen. Da das natürlich sehr unsicher ist, muss dann verschlüsselt abgelegt werden! Bzw. besser in diesem Schritt gar nicht hinterlegen und mit der Option -k interaktiv angeben (all wenigstens in einer Gruppe gleich!)! Unser Template kopieren: cp -r /srv/ansible/play_book_template /srv/ansible/deploy_ansible_user == Ansible konfigurieren == Um die -i Option zu sparen eine ansible.cfg anlegen vi ansible.cfg [defaults] inventory = ./inventory remote_user = root #Vault Password vault_password_file = ./vault-pass.txt # avoid warning message python path interpreter_python = auto_silent #noch check host keys to avoid errors host_key_checking = false [privilege_escalation] become = false ==Parameter für die Ziel Gruppe hinterlegen== Datei group_vars/<> vi group_vars/ORACLE_SERVER --- admin_group: wheel ==Parameter für alle Gruppen hinterlegen == Datei group_vars/all vi group_vars/all --- #Access to all servers default ansible_connection: ssh ansible_ssh_user: root ansible_ssh_pass: <> # management_user_pwd: Secret1! Im nächsten Schritt wird das verschlüsselt dazu kann i[[https://docs.ansible.com/ansible/latest/user_guide/vault.html|Ansible Vault]] verwendet werden. Vrschlüsseln mit: ansible-vault encrypt ./group_vars/all New Vault password: Confirm New Vault password: Encryption successful #Bei Bedarf anpassen ansible-vault edit ./group_vars/all Möglichkeiten nun das Vault Passwort beim Aufruf eines Playbooks zu hinterlegen: * Interaktiv das Passwort eingeben werden, Option "--ask-vault-pass" * Passwort in einer Datei wie vault-pass.txt hinterlegen, diese vor GIT und dem Zugriff schützen, beim Aufruf des Playbooks mit angeben - Option "– vault-password-file vault-pass.txt" * Die Datei mit dem Passwort in der ansible.cfg hinterlege mit "vault_password_file = ./vault-pass.txt" == Zugriff testen == Test des Zugriffes über: ansible all --list-hosts # mit der K Option für die Password Übergabe ansible all -m setup -u root -k #nur eine Gruppe aufrufen ansible ORA_SERVER -m ping -k == Die notwendigenTasks anlegen === - Erzeugeden Ansible User - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/user_module.html#ansible-collections-ansible-builtin-user-module - Sudo Konfiguration ausrollen - https://docs.ansible.com/ansible/latest/collections/ansible/posix/authorized_key_module.html - SSH Public Key der Management Umgebung verteilen - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/copy_module.html#ansible-collections-ansible-builtin-copy-module **Erzeugeden Ansible User** vi create_user.yml: --- - name: Create Ansible User hosts: ORA_SERVER tasks: - name: Create Ansible User ansible.builtin.user: name: ansible groups: "{{ admin_group }}" append: true create_home: true comment: "Ansible Management Account" expires: -1 password: "{{ management_user_pwd | password_hash('sha512','A512') }}" - name: Deploy Local User SSH Key authorized_key: user: ansible state: present manage_dir: true key: "{{ lookup('file', '/home/ansible/.ssh/id_rsa.pub') }}" - name: Setup Sudo Access for Devops User ansible.builtin.copy: dest: /etc/sudoers.d/ansible content: 'ansible ALL = NOPASSWD : ALL' validate: /usr/sbin/visudo -cf %s Check: ansible-playbook create_user.yml --syntax-check Starten: ansible-playbook create_user.yml -k SSH password: PLAY [Create Ansible User] ************************************************************************************************************* TASK [Gathering Facts] ***************************************************************************************************************** ok: [apex01.pipperr.local] TASK [Create Ansible User] ************************************************************************************************************* ok: [apex01.pipperr.local] TASK [Deploy Local User SSH Key] ******************************************************************************************************* ok: [apex01.pipperr.local] TASK [Setup Sudo Access for Devops User] *********************************************************************************************** changed: [apex01.pipperr.local] PLAY RECAP ***************************************************************************************************************************** apex01.pipperr.local : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ! Achtung - Soll das Playbool in Ansible Tower ausgerufen werden muss der Schlüssel mit in das Playbook Verzeichnis gelegt werden z.b nach public_key, das aus root im Tower nicht gelesen werden kann! Dann Anpassen auf " key: "{{ lookup('file', 'public_key/id_rsa.pub') }}" " **Löschen des Ansible User** vi remove_user.yml --- - name: drop Ansible User hosts: ORA_SERVER tasks: - name: drop Ansible User user: name: ansible state: absent remove: true Check: ansible-playbook remove_user.yml --syntax-check Ausführen: ansible-playbook remove_user.yml -k SSH password: PLAY [drop Ansible User] *************************************************************************************************************** TASK [Gathering Facts] ***************************************************************************************************************** ok: [apex01.pipperr.local] TASK [drop Ansible User] *************************************************************************************************************** changed: [apex01.pipperr.local] TASK [Remove Sudo Entry] *************************************************************************************************************** changed: [apex01.pipperr.local] PLAY RECAP ***************************************************************************************************************************** apex01.pipperr.local : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ---- ---- ==== Playbook Beispiel - SQL*Plus aufrufen und Script ausführen ==== Unser Template kopieren: cp -r /srv/ansible/play_book_template /srv/ansible/oracle_maintenance == Ansible konfigurieren == Ansible CFG auf das Projekt anpassen vi ansible.cfg [defaults] inventory = ./inventory remote_user = ansible # avoid warning message python path interpreter_python = auto_silent ==Parameter für die Ziel Hosts hinterlegen== Datei host_vars/<> vi host_vars/apex01.pipperr.local --- hostname: apex01.pipperr.local IP: 10.10.10.90 roles: - common - dbserver virtual: true oracle_envs: - oracle_home: /opt/oracle/product/19c/dbhome_1 oracle_sid: - GPIDB1 - PRDDB - oracle_home: /opt/oracle/product/18c/dbhome_1 oracle_sid: - GPIDB Pro Server so eine Datei anlegen, die Oracle Umgebungen werden als Listen angelegt da ja meherer Oracle Homes und Oracle Datenbaken auf dem Server liegen können. Im Ansible Script wird dann mit "with_items" bzw. "with_subelements" über diese Liste itteriert. ==Parameter für alle Gruppen hinterlegen == Datei group_vars/all vi group_vars/all --- #empty in this case == Zugriff testen == Test des Zugriffes über: ansible all --list-hosts # mit der K Option für die Password Übergabe ansible all -m setup -u root -k #nur eine Gruppe aufrufen ansible ORA_SERVER -m ping -k == Die notwendigenTasks anlegen === - Verzeichnis für die Skripte anlegen - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/file_module.html - Script auf dem Server kopieren - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/copy_module.html - Script in SQL*Plus ausführen - https://docs.ansible.com/ansible/latest/collections/ansible/builtin/command_module.html#ansible-collections-ansible-builtin-command-module vi execute_set_pack_access.yml: --- - name: Call SQL*Plus Script to disable all mangement packs hosts: ORA_SERVER tasks: - name: Create the Script Directory become: yes become_user: oracle ansible.builtin.file: owner: oracle group: oinstall path: "/home/oracle/ansible_scripts/" state: directory - name: Copy the sql*plus script become: yes become_user: oracle ansible.builtin.copy: src: ./scripts/set_pack_access.sql dest: /home/oracle/ansible_scripts - name: Call the script as oracle user become: yes become_user: oracle command: "$ORACLE_HOME/bin/sqlplus -s / as sysdba @/home/oracle/ansible_scripts/set_pack_access.sql" environment: ORACLE_HOME: "{{ item.0.oracle_home }}" ORACLE_SID: "{{ item.1 }}" with_subelements: - "{{ oracle_envs }}" - oracle_sid Check: ansible-playbook execute_set_pack_access.yml --syntax-check == SQL*Plus Script anlegen == vi ./scripts/set_pack_access.sql select user from dual; exit Starten: ansible-playbook execute_set_pack_access.yml --verbose Using /srv/ansible/oracle_maintenance/ansible.cfg as config file PLAY [Call SQL*Plus Script to disable all mangement packs] ********************************************************************************* TASK [Gathering Facts] ********************************************************************************************************************* ok: [apex01.pipperr.local] TASK [Create the Script Directory] ********************************************************************************************************* ok: [apex01.pipperr.local] => {"changed": false, "gid": 54321, "group": "oinstall", "mode": "0755", "owner": "oracle", "path": "/home/oracle/ansible_scripts/", "size": 33, "state": "directory", "uid": 54321} TASK [Copy the sql*plus script] ************************************************************************************************************ ok: [apex01.pipperr.local] => {"changed": false, "checksum": "8353662eb6e8d7ee1b6979d949ba695779046674", "dest": "/home/oracle/ansible_scripts/set_pack_access.sql", "gid": 54321, "group": "oinstall", "mode": "0644", "owner": "oracle", "path": "/home/oracle/ansible_scripts/set_pack_access.sql", "size": 29, "state": "file", "uid": 54321} TASK [Call the script as oracle user] ****************************************************************************************************** changed: [apex01.pipperr.local] => {"changed": true, "cmd": ["$ORACLE_HOME/bin/sqlplus", "-s", "/", "as", "sysdba", "@/home/oracle/ansible_scripts/set_pack_access.sql"], "delta": "0:00:00.051674", "end": "2021-06-13 00:45:36.059234", "rc": 0, "start": "2021-06-13 00:45:36.007560", "stderr": "", "stderr_lines": [], "stdout": "\nUSER\n--------------------------------------------------------------------------------\nSYS", "stdout_lines": ["", "USER", "--------------------------------------------------------------------------------", "SYS"]} PLAY RECAP ********************************************************************************************************************************* apex01.pipperr.local : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 Mit diesem ersten Elemente lassen sich nun einfach Scripte auf den Datenbank Server verteilen und ausführen. ---- ---- ==== Quellen ==== == Blog Einträge== * https://adamtheautomator.com/install-ansible/#Installing_Ansible_on_CentOS * https://martincarstenbach.wordpress.com/2021/03/11/installing-ansible-on-oracle-linux-8-for-test-and-development-use/ * https://blog.proact.de/blog/2017/08/09/ansible-fuer-automatisierte-roll-outs-der-einstieg/ * https://www.theurbanpenguin.com/using-ansible-playbooks/ * https://www.rogerperkin.co.uk/network-automation/ansible/vault-tutorial/ * https://chromatichq.com/insights/untangling-ansible-loops * https://www.digitalocean.com/community/cheatsheets/how-to-use-ansible-cheat-sheet-guide ==Code Beispiele== * https://github.com/ansible/ansible-examples/tree/master/language_features ==Tutorial== * https://www.youtube.com/playlist?list=PLVx1qovxj-al0Knm1A0eEXfGyd5kCi16p ==Oracle Beispiele== * https://fritshoogland.wordpress.com/2014/09/14/using-ansible-for-executing-oracle-dba-tasks/ * https://github.com/abessifi/ansible-sqlplus * https://github.com/oravirt/ansible-oracle-modules * https://oravirt.wordpress.com/ ==Tools und Erweiterungen für Ansible== Server Informationen sammen und als HTML Darstellen * https://ansible-cmdb.readthedocs.io/en/latest/ * https://www.electricmonk.nl/log/2015/01/21/host-inventory-overview-using-ansibles-facts/ * https://www.redhat.com/sysadmin/playing-ansible-facts