ci: use vault secret file and local dryrun; fix YAML/FQCN in roles; inventory tweaks

This commit is contained in:
Automation Admin 2025-08-08 01:58:30 +00:00
parent 3b17e5b405
commit ca24d66e7a
8 changed files with 72 additions and 59 deletions

View File

@ -13,7 +13,11 @@ steps:
image: python:3.11-slim image: python:3.11-slim
commands: commands:
- pip install --no-cache-dir ansible - pip install --no-cache-dir ansible
- ansible-playbook playbook/playbook.yml --check --list-tasks - echo "$ANSIBLE_VAULT_PASSWORD" > .vault_pass
- ansible-galaxy collection install -r playbook/requirements.yml --force
- ansible-playbook playbook/playbook.yml --check --list-tasks \
--vault-password-file .vault_pass -i 'localhost,' -c local -e 'gather_facts=false'
secrets: [ANSIBLE_VAULT_PASSWORD]
run_preflight: run_preflight:
when: when:
@ -21,7 +25,11 @@ steps:
image: python:3.11-slim image: python:3.11-slim
commands: commands:
- pip install --no-cache-dir ansible - pip install --no-cache-dir ansible
- ansible-playbook playbook/playbook.yml --tags preflight -l pdp-portal --ask-vault-pass - echo "$ANSIBLE_VAULT_PASSWORD" > .vault_pass
- ansible-galaxy collection install -r playbook/requirements.yml --force
- ansible-playbook playbook/playbook.yml --tags preflight -l pdp-portal \
--vault-password-file .vault_pass
secrets: [ANSIBLE_VAULT_PASSWORD]
run_patch: run_patch:
when: when:
@ -29,5 +37,8 @@ steps:
image: python:3.11-slim image: python:3.11-slim
commands: commands:
- pip install --no-cache-dir ansible - pip install --no-cache-dir ansible
- echo "$ANSIBLE_VAULT_PASSWORD" > .vault_pass
- ansible-galaxy collection install -r playbook/requirements.yml --force - ansible-galaxy collection install -r playbook/requirements.yml --force
- ansible-playbook playbook/playbook.yml -l pdp-portal -e "target_clm_version=prod-2024-06" --ask-vault-pass - ansible-playbook playbook/playbook.yml -l pdp-portal -e "target_clm_version=prod-2024-06" \
--vault-password-file .vault_pass
secrets: [ANSIBLE_VAULT_PASSWORD]

View File

@ -1,7 +1,7 @@
[defaults] [defaults]
inventory = playbook/servicenow_inventory.yml inventory = playbook/servicenow_inventory.yml
roles_path = playbook/roles roles_path = playbook/roles
collections_paths = ~/.ansible/collections:./collections collections_path = ~/.ansible/collections:./collections
host_key_checking = False host_key_checking = False
retry_files_enabled = False retry_files_enabled = False
stdout_callback = yaml stdout_callback = yaml

View File

@ -22,7 +22,7 @@ app_mail=git-app@example.com
# Optional: Gruppen für Umgebungen # Optional: Gruppen für Umgebungen
#[dev:children] #[dev:children]
#pdp-portal #pdp-portal
git #git
#[prod:children] #[prod:children]
#confluence #confluence

View File

@ -1,18 +1,21 @@
--- ---
- name: Compliance-Check: Führe OpenSCAP-Scan durch (sofern installiert) - name: "Compliance-Check: Führe OpenSCAP-Scan durch (sofern installiert)"
shell: oscap xccdf eval --profile xccdf_org.ssgproject.content_profile_standard --results {{ log_dir }}/oscap_result_{{ inventory_hostname }}.xml /usr/share/xml/scap/ssg/content/ssg-$(lsb_release -si | tr '[:upper:]' '[:lower:]')-ds.xml ansible.builtin.shell: >-
oscap xccdf eval --profile xccdf_org.ssgproject.content_profile_standard
--results {{ log_dir }}/oscap_result_{{ inventory_hostname }}.xml
/usr/share/xml/scap/ssg/content/ssg-$(lsb_release -si | tr '[:upper:]' '[:lower:]')-ds.xml
register: oscap_result register: oscap_result
ignore_errors: true ignore_errors: true
changed_when: false changed_when: false
- name: Compliance-Check: Führe Lynis-Scan durch (sofern installiert) - name: "Compliance-Check: Führe Lynis-Scan durch (sofern installiert)"
shell: lynis audit system --quiet --logfile {{ log_dir }}/lynis_{{ inventory_hostname }}.log ansible.builtin.shell: lynis audit system --quiet --logfile {{ log_dir }}/lynis_{{ inventory_hostname }}.log
register: lynis_result register: lynis_result
ignore_errors: true ignore_errors: true
changed_when: false changed_when: false
- name: Sende Compliance-Report an Linux-Admins - name: Sende Compliance-Report an Linux-Admins
mail: community.general.mail:
host: "localhost" host: "localhost"
port: 25 port: 25
to: "{{ linux_admins_mail }}" to: "{{ linux_admins_mail }}"

View File

@ -1,17 +1,17 @@
--- ---
- name: Reboot nach Upgrade (optional) - name: Reboot nach Upgrade (optional)
reboot: ansible.builtin.reboot:
msg: "Reboot nach Auto-Upgrade" msg: "Reboot nach Auto-Upgrade"
pre_reboot_delay: 60 pre_reboot_delay: 60
when: reboot_after_upgrade when: reboot_after_upgrade
tags: reboot tags: reboot
- name: Health-Check: Prüfe, ob kritische Dienste laufen - name: "Health-Check: Prüfe, ob kritische Dienste laufen"
service_facts: ansible.builtin.service_facts:
tags: health tags: health
- name: Prüfe Status der kritischen Dienste - name: Prüfe Status der kritischen Dienste
assert: ansible.builtin.assert:
that: that:
- "(services[item].state == 'running') or (services[item].state == 'started')" - "(services[item].state == 'running') or (services[item].state == 'started')"
fail_msg: "Kritischer Dienst {{ item }} läuft nicht!" fail_msg: "Kritischer Dienst {{ item }} läuft nicht!"

View File

@ -1,14 +1,14 @@
--- ---
- name: Prüfe, ob aktueller Zeitpunkt im Maintenance-Window liegt - name: "Prüfe, ob aktueller Zeitpunkt im Maintenance-Window liegt"
set_fact: ansible.builtin.set_fact:
now: "{{ lookup('pipe', 'date +%H:%M') }}" now: "{{ lookup('pipe', 'date +%H:%M') }}"
window_start: "{{ maintenance_window_start }}" window_start: "{{ maintenance_window_start }}"
window_end: "{{ maintenance_window_end }}" window_end: "{{ maintenance_window_end }}"
changed_when: false changed_when: false
tags: preflight tags: preflight
- name: Maintenance-Window-Check (Abbruch, wenn außerhalb) - name: "Maintenance-Window-Check (Abbruch, wenn außerhalb)"
fail: ansible.builtin.fail:
msg: "Aktuelle Zeit {{ now }} liegt außerhalb des Maintenance-Windows ({{ window_start }} - {{ window_end }}). Upgrade wird abgebrochen!" msg: "Aktuelle Zeit {{ now }} liegt außerhalb des Maintenance-Windows ({{ window_start }} - {{ window_end }}). Upgrade wird abgebrochen!"
when: >- when: >-
( (
@ -18,14 +18,14 @@
) )
tags: preflight tags: preflight
- name: Prüfe freien Speicherplatz auf / (mind. 5GB empfohlen) - name: "Prüfe freien Speicherplatz auf / (mind. 5GB empfohlen)"
stat: ansible.builtin.stat:
path: / path: /
register: root_stat register: root_stat
tags: preflight tags: preflight
- name: Warnung bei zu wenig Speicherplatz - name: Warnung bei zu wenig Speicherplatz
assert: ansible.builtin.assert:
that: that:
- root_stat.stat.avail_bytes > 5368709120 - root_stat.stat.avail_bytes > 5368709120
fail_msg: "Wenig freier Speicherplatz auf /: {{ root_stat.stat.avail_bytes | human_readable }} (mind. 5GB empfohlen)" fail_msg: "Wenig freier Speicherplatz auf /: {{ root_stat.stat.avail_bytes | human_readable }} (mind. 5GB empfohlen)"
@ -33,7 +33,7 @@
tags: preflight tags: preflight
- name: Prüfe Erreichbarkeit von SUSE Manager - name: Prüfe Erreichbarkeit von SUSE Manager
uri: ansible.builtin.uri:
url: "{{ suma_api_url }}" url: "{{ suma_api_url }}"
method: GET method: GET
validate_certs: no validate_certs: no
@ -45,7 +45,7 @@
tags: preflight tags: preflight
- name: Warnung, wenn SUSE Manager nicht erreichbar - name: Warnung, wenn SUSE Manager nicht erreichbar
assert: ansible.builtin.assert:
that: that:
- suma_reachable.status is defined and suma_reachable.status == 200 - suma_reachable.status is defined and suma_reachable.status == 200
fail_msg: "SUSE Manager API nicht erreichbar!" fail_msg: "SUSE Manager API nicht erreichbar!"
@ -53,14 +53,14 @@
tags: preflight tags: preflight
- name: Prüfe, ob VMware-Snapshot-Modul verfügbar ist - name: Prüfe, ob VMware-Snapshot-Modul verfügbar ist
shell: "python3 -c 'import pyVmomi'" ansible.builtin.shell: "python3 -c 'import pyVmomi'"
register: pyvmomi_check register: pyvmomi_check
ignore_errors: true ignore_errors: true
changed_when: false changed_when: false
tags: preflight tags: preflight
- name: Warnung, wenn pyVmomi nicht installiert ist - name: Warnung, wenn pyVmomi nicht installiert ist
assert: ansible.builtin.assert:
that: that:
- pyvmomi_check.rc == 0 - pyvmomi_check.rc == 0
fail_msg: "pyVmomi (VMware-Modul) nicht installiert!" fail_msg: "pyVmomi (VMware-Modul) nicht installiert!"
@ -68,7 +68,7 @@
tags: preflight tags: preflight
- name: Prüfe, ob aktueller SUSE Manager Channel synchronisiert ist - name: Prüfe, ob aktueller SUSE Manager Channel synchronisiert ist
uri: ansible.builtin.uri:
url: "{{ suma_api_url }}" url: "{{ suma_api_url }}"
method: POST method: POST
body_format: json body_format: json
@ -91,7 +91,7 @@
tags: preflight tags: preflight
- name: Hole Channel-Details für Ziel-CLM-Version - name: Hole Channel-Details für Ziel-CLM-Version
uri: ansible.builtin.uri:
url: "{{ suma_api_url }}" url: "{{ suma_api_url }}"
method: POST method: POST
body_format: json body_format: json
@ -114,7 +114,7 @@
tags: preflight tags: preflight
- name: Prüfe Channel-Sync-Status - name: Prüfe Channel-Sync-Status
assert: ansible.builtin.assert:
that: that:
- suma_channel_details.json.result.last_sync is defined - suma_channel_details.json.result.last_sync is defined
fail_msg: "Channel {{ target_clm_version }} ist nicht synchronisiert!" fail_msg: "Channel {{ target_clm_version }} ist nicht synchronisiert!"
@ -122,7 +122,7 @@
tags: preflight tags: preflight
- name: Slack-Benachrichtigung bei kritischen Fehlern (Beispiel) - name: Slack-Benachrichtigung bei kritischen Fehlern (Beispiel)
slack: community.general.slack:
token: "{{ slack_token | default('xoxb-...') }}" token: "{{ slack_token | default('xoxb-...') }}"
msg: "[CRITICAL] Fehler beim Preflight-Check auf {{ inventory_hostname }}: {{ ansible_failed_result.msg | default('Unbekannter Fehler') }}" msg: "[CRITICAL] Fehler beim Preflight-Check auf {{ inventory_hostname }}: {{ ansible_failed_result.msg | default('Unbekannter Fehler') }}"
channel: "#linux-admins" channel: "#linux-admins"

View File

@ -1,27 +1,26 @@
---
- name: Prüfe, ob HTTP-Service installiert ist (Apache/Nginx) - name: Prüfe, ob HTTP-Service installiert ist (Apache/Nginx)
stat: ansible.builtin.stat:
path: /usr/sbin/httpd path: /usr/sbin/httpd
register: apache_check register: apache_check
ignore_errors: true ignore_errors: true
- name: Prüfe, ob Nginx installiert ist - name: Prüfe, ob Nginx installiert ist
stat: ansible.builtin.stat:
path: /usr/sbin/nginx path: /usr/sbin/nginx
register: nginx_check register: nginx_check
ignore_errors: true ignore_errors: true
- name: Smoke-Test: Prüfe HTTP-Endpoint (nur wenn Web-Server installiert) - name: "Smoke-Test: Prüfe HTTP-Endpoint (nur wenn Web-Server installiert)"
uri: ansible.builtin.uri:
url: "{{ smoke_test_url | default('http://localhost') }}" url: "{{ smoke_test_url | default('http://localhost') }}"
status_code: 200 status_code: 200
return_content: no return_content: false
register: http_result register: http_result
ignore_errors: true ignore_errors: true
when: apache_check.stat.exists or nginx_check.stat.exists when: apache_check.stat.exists or nginx_check.stat.exists
- name: Smoke-Test: Prüfe offenen Port (optional) - name: "Smoke-Test: Prüfe offenen Port (optional)"
wait_for: ansible.builtin.wait_for:
port: "{{ smoke_test_port | default(80) }}" port: "{{ smoke_test_port | default(80) }}"
host: "{{ smoke_test_host | default('localhost') }}" host: "{{ smoke_test_host | default('localhost') }}"
timeout: 5 timeout: 5
@ -29,41 +28,41 @@
ignore_errors: true ignore_errors: true
- name: Prüfe, ob MySQL/MariaDB installiert ist - name: Prüfe, ob MySQL/MariaDB installiert ist
stat: ansible.builtin.stat:
path: /usr/bin/mysql path: /usr/bin/mysql
register: mysql_check register: mysql_check
ignore_errors: true ignore_errors: true
- name: Smoke-Test: Prüfe Datenbankverbindung (nur wenn MySQL installiert) - name: "Smoke-Test: Prüfe Datenbankverbindung (nur wenn MySQL installiert)"
shell: "echo 'select 1' | mysql -h {{ smoke_test_db_host | default('localhost') }} -u {{ smoke_test_db_user | default('root') }} --password={{ smoke_test_db_pass | default('') }} {{ smoke_test_db_name | default('') }}" ansible.builtin.shell: "echo 'select 1' | mysql -h {{ smoke_test_db_host | default('localhost') }} -u {{ smoke_test_db_user | default('root') }} --password={{ smoke_test_db_pass | default('') }} {{ smoke_test_db_name | default('') }}"
register: db_result register: db_result
ignore_errors: true ignore_errors: true
when: mysql_check.stat.exists and smoke_test_db_host is defined when: mysql_check.stat.exists and smoke_test_db_host is defined
- name: Prüfe, ob Oracle installiert ist - name: Prüfe, ob Oracle installiert ist
stat: ansible.builtin.stat:
path: /u01/app/oracle/product path: /u01/app/oracle/product
register: oracle_check register: oracle_check
ignore_errors: true ignore_errors: true
- name: Oracle DB: Finde alle Oracle SIDs (nur wenn Oracle installiert) - name: "Oracle DB: Finde alle Oracle SIDs (nur wenn Oracle installiert)"
shell: | ansible.builtin.shell: |
ps -ef | grep -E "ora_pmon_[A-Z0-9_]+" | grep -v grep | awk '{print $NF}' | sed 's/ora_pmon_//' ps -ef | grep -E "ora_pmon_[A-Z0-9_]+" | grep -v grep | awk '{print $NF}' | sed 's/ora_pmon_//'
register: oracle_sids register: oracle_sids
changed_when: false changed_when: false
ignore_errors: true ignore_errors: true
when: oracle_check.stat.exists when: oracle_check.stat.exists
- name: Oracle DB: Finde alle Oracle Listener (nur wenn Oracle installiert) - name: "Oracle DB: Finde alle Oracle Listener (nur wenn Oracle installiert)"
shell: | ansible.builtin.shell: |
ps -ef | grep -E "tnslsnr" | grep -v grep | awk '{print $NF}' | sed 's/tnslsnr//' ps -ef | grep -E "tnslsnr" | grep -v grep | awk '{print $NF}' | sed 's/tnslsnr//'
register: oracle_listeners register: oracle_listeners
changed_when: false changed_when: false
ignore_errors: true ignore_errors: true
when: oracle_check.stat.exists when: oracle_check.stat.exists
- name: Oracle DB: Prüfe alle gefundenen SIDs (nur wenn Oracle installiert) - name: "Oracle DB: Prüfe alle gefundenen SIDs (nur wenn Oracle installiert)"
shell: | ansible.builtin.shell: |
export ORACLE_HOME={{ item.oracle_home | default('/u01/app/oracle/product/19.0.0/dbhome_1') }} export ORACLE_HOME={{ item.oracle_home | default('/u01/app/oracle/product/19.0.0/dbhome_1') }}
export PATH=$ORACLE_HOME/bin:$PATH export PATH=$ORACLE_HOME/bin:$PATH
export ORACLE_SID={{ item.sid }} export ORACLE_SID={{ item.sid }}
@ -76,8 +75,8 @@
ignore_errors: true ignore_errors: true
when: oracle_check.stat.exists and oracle_sids.stdout_lines | length > 0 when: oracle_check.stat.exists and oracle_sids.stdout_lines | length > 0
- name: Oracle DB: Prüfe alle gefundenen Listener (nur wenn Oracle installiert) - name: "Oracle DB: Prüfe alle gefundenen Listener (nur wenn Oracle installiert)"
shell: | ansible.builtin.shell: |
export ORACLE_HOME={{ item.oracle_home | default('/u01/app/oracle/product/19.0.0/dbhome_1') }} export ORACLE_HOME={{ item.oracle_home | default('/u01/app/oracle/product/19.0.0/dbhome_1') }}
export PATH=$ORACLE_HOME/bin:$PATH export PATH=$ORACLE_HOME/bin:$PATH
lsnrctl status {{ item.listener }} lsnrctl status {{ item.listener }}
@ -86,8 +85,8 @@
ignore_errors: true ignore_errors: true
when: oracle_check.stat.exists and oracle_listeners.stdout_lines | length > 0 when: oracle_check.stat.exists and oracle_listeners.stdout_lines | length > 0
- name: Oracle DB: Logge Oracle-Check-Ergebnisse (nur wenn Oracle installiert) - name: "Oracle DB: Logge Oracle-Check-Ergebnisse (nur wenn Oracle installiert)"
copy: ansible.builtin.copy:
content: | content: |
Oracle DB Check für {{ inventory_hostname }} Oracle DB Check für {{ inventory_hostname }}
Zeit: {{ ansible_date_time.iso8601 }} Zeit: {{ ansible_date_time.iso8601 }}
@ -100,7 +99,7 @@
when: oracle_check.stat.exists when: oracle_check.stat.exists
- name: Smoke-Test Ergebnis zusammenfassen - name: Smoke-Test Ergebnis zusammenfassen
debug: ansible.builtin.debug:
msg: msg:
- "HTTP-Test: {{ http_result.status | default('NOT INSTALLED') }}" - "HTTP-Test: {{ http_result.status | default('NOT INSTALLED') }}"
- "Port-Test: {{ port_result.state | default('FAILED') }}" - "Port-Test: {{ port_result.state | default('FAILED') }}"

View File

@ -1,6 +1,6 @@
--- ---
- name: Erstelle VMware Snapshot vor Upgrade - name: Erstelle VMware Snapshot vor Upgrade
vmware_guest_snapshot: community.vmware.vmware_guest_snapshot:
hostname: "{{ vcenter_hostname }}" hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_user }}" username: "{{ vcenter_user }}"
password: "{{ vcenter_password }}" password: "{{ vcenter_password }}"
@ -20,23 +20,23 @@
delay: 10 delay: 10
- name: Logge Fehler bei Snapshot-Erstellung - name: Logge Fehler bei Snapshot-Erstellung
copy: ansible.builtin.copy:
content: "Snapshot-Fehler: {{ snapshot_result.msg | default('Unbekannter Fehler') }}" content: "Snapshot-Fehler: {{ snapshot_result.msg | default('Unbekannter Fehler') }}"
dest: "{{ log_dir }}/snapshot_error_{{ inventory_hostname }}.log" dest: "{{ log_dir }}/snapshot_error_{{ inventory_hostname }}.log"
when: snapshot_result is failed when: snapshot_result is failed
- name: Setze Rollback-Flag, falls Snapshot-Erstellung fehlschlägt - name: Setze Rollback-Flag, falls Snapshot-Erstellung fehlschlägt
set_fact: ansible.builtin.set_fact:
rollback: true rollback: true
when: snapshot_result is failed when: snapshot_result is failed
- name: Breche Playbook ab, wenn Snapshot-Erstellung fehlschlägt - name: Breche Playbook ab, wenn Snapshot-Erstellung fehlschlägt
fail: ansible.builtin.fail:
msg: "Snapshot-Erstellung fehlgeschlagen, Upgrade wird abgebrochen! Siehe Log: {{ log_dir }}/snapshot_error_{{ inventory_hostname }}.log" msg: "Snapshot-Erstellung fehlgeschlagen, Upgrade wird abgebrochen! Siehe Log: {{ log_dir }}/snapshot_error_{{ inventory_hostname }}.log"
when: snapshot_result is failed when: snapshot_result is failed
- name: Rollback: Setze VM auf Snapshot zurück (nur bei Fehler und wenn aktiviert) - name: "Rollback: Setze VM auf Snapshot zurück (nur bei Fehler und wenn aktiviert)"
vmware_guest_snapshot: community.vmware.vmware_guest_snapshot:
hostname: "{{ vcenter_hostname }}" hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_user }}" username: "{{ vcenter_user }}"
password: "{{ vcenter_password }}" password: "{{ vcenter_password }}"
@ -50,7 +50,7 @@
delegate_to: localhost delegate_to: localhost
- name: Lösche VMware Snapshot nach erfolgreichem Patchlauf (optional) - name: Lösche VMware Snapshot nach erfolgreichem Patchlauf (optional)
vmware_guest_snapshot: community.vmware.vmware_guest_snapshot:
hostname: "{{ vcenter_hostname }}" hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_user }}" username: "{{ vcenter_user }}"
password: "{{ vcenter_password }}" password: "{{ vcenter_password }}"