From 841ab1c59e07e394efed1562de224f9b8f551dd9 Mon Sep 17 00:00:00 2001 From: Marcel Mamula Date: Tue, 30 Sep 2025 15:16:46 +0200 Subject: [PATCH 1/4] feat: enhance hana install with delegate to achieve proper idempotency in addhosts --- .../tasks/assert-addhosts-loop-block.yml | 38 -- .../sap_hana_install/tasks/hana_addhosts.yml | 49 +-- roles/sap_hana_install/tasks/hana_install.yml | 20 +- roles/sap_hana_install/tasks/main.yml | 91 +++-- .../sap_hana_install/tasks/post_addhosts.yml | 89 +++++ roles/sap_hana_install/tasks/post_install.yml | 83 ++-- .../tasks/post_install/firewall.yml | 72 ---- .../tasks/post_install/update_etchosts.yml | 14 - .../tasks/post_install/update_firewall.yml | 11 - .../check_installation.yml | 39 +- .../fapolicyd.yml | 36 +- .../tasks/post_tasks/firewall.yml | 67 ++++ .../hdbuserstore.yml | 7 +- .../{post_install => post_tasks}/license.yml | 4 +- .../{post_install => post_tasks}/log_mode.yml | 14 +- .../recreate_tenant_database.yml | 7 +- .../tasks/post_tasks/selinux.yml | 17 + .../tasks/post_tasks/user_expiration.yml | 12 + roles/sap_hana_install/tasks/pre_addhosts.yml | 138 +++++++ roles/sap_hana_install/tasks/pre_install.yml | 360 +++++++----------- .../{ => pre_tasks}/assert_variables.yml | 9 +- .../tasks/pre_tasks/check_addhosts.yml | 87 +++++ .../tasks/pre_tasks/create_users_groups.yml | 28 ++ .../extract_sarfile.yml | 14 +- .../tasks/pre_tasks/fapolicyd.yml | 25 ++ .../pre_tasks/hana_directory_permissions.yml | 16 + .../tasks/{ => pre_tasks}/hana_exists.yml | 79 ++-- .../tasks/{ => pre_tasks}/hana_start.yml | 8 +- .../hdblcm_configfile.yml | 24 +- .../hdblcm_prepare.yml | 22 +- .../prepare_sapcar.yml | 18 +- .../prepare_sarfiles.yml | 31 +- .../tasks/pre_tasks/selinux.yml | 14 + .../software_directory_permissions.yml} | 12 +- .../verify_checksum.yml | 12 +- 35 files changed, 949 insertions(+), 618 deletions(-) delete mode 100644 roles/sap_hana_install/tasks/assert-addhosts-loop-block.yml create mode 100644 roles/sap_hana_install/tasks/post_addhosts.yml delete mode 100644 roles/sap_hana_install/tasks/post_install/firewall.yml delete mode 100644 roles/sap_hana_install/tasks/post_install/update_etchosts.yml delete mode 100644 roles/sap_hana_install/tasks/post_install/update_firewall.yml rename roles/sap_hana_install/tasks/{post_install => post_tasks}/check_installation.yml (68%) rename roles/sap_hana_install/tasks/{post_install => post_tasks}/fapolicyd.yml (66%) create mode 100644 roles/sap_hana_install/tasks/post_tasks/firewall.yml rename roles/sap_hana_install/tasks/{post_install => post_tasks}/hdbuserstore.yml (71%) rename roles/sap_hana_install/tasks/{post_install => post_tasks}/license.yml (83%) rename roles/sap_hana_install/tasks/{post_install => post_tasks}/log_mode.yml (82%) rename roles/sap_hana_install/tasks/{post_install => post_tasks}/recreate_tenant_database.yml (79%) create mode 100644 roles/sap_hana_install/tasks/post_tasks/selinux.yml create mode 100644 roles/sap_hana_install/tasks/post_tasks/user_expiration.yml create mode 100644 roles/sap_hana_install/tasks/pre_addhosts.yml rename roles/sap_hana_install/tasks/{ => pre_tasks}/assert_variables.yml (85%) create mode 100644 roles/sap_hana_install/tasks/pre_tasks/check_addhosts.yml create mode 100644 roles/sap_hana_install/tasks/pre_tasks/create_users_groups.yml rename roles/sap_hana_install/tasks/{pre_install => pre_tasks}/extract_sarfile.yml (70%) create mode 100644 roles/sap_hana_install/tasks/pre_tasks/fapolicyd.yml create mode 100644 roles/sap_hana_install/tasks/pre_tasks/hana_directory_permissions.yml rename roles/sap_hana_install/tasks/{ => pre_tasks}/hana_exists.yml (66%) rename roles/sap_hana_install/tasks/{ => pre_tasks}/hana_start.yml (84%) rename roles/sap_hana_install/tasks/{pre_install => pre_tasks}/hdblcm_configfile.yml (87%) rename roles/sap_hana_install/tasks/{pre_install => pre_tasks}/hdblcm_prepare.yml (67%) rename roles/sap_hana_install/tasks/{pre_install => pre_tasks}/prepare_sapcar.yml (92%) rename roles/sap_hana_install/tasks/{pre_install => pre_tasks}/prepare_sarfiles.yml (72%) create mode 100644 roles/sap_hana_install/tasks/pre_tasks/selinux.yml rename roles/sap_hana_install/tasks/{pre_install-loop-block.yml => pre_tasks/software_directory_permissions.yml} (71%) rename roles/sap_hana_install/tasks/{pre_install => pre_tasks}/verify_checksum.yml (80%) diff --git a/roles/sap_hana_install/tasks/assert-addhosts-loop-block.yml b/roles/sap_hana_install/tasks/assert-addhosts-loop-block.yml deleted file mode 100644 index 0b79a30a3..000000000 --- a/roles/sap_hana_install/tasks/assert-addhosts-loop-block.yml +++ /dev/null @@ -1,38 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 ---- - -- name: SAP HANA Add Hosts - Check for SAP HANA instance profile for '{{ line_item }}' - ansible.builtin.stat: - path: "{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}/profile/{{ sap_hana_install_sid }}_HDB{{ sap_hana_install_number }}_{{ line_item }}" - register: __sap_hana_install_register_instance_profile_addhost - -- name: SAP HANA Add Hosts - Show the path name of the instance profile - ansible.builtin.debug: - msg: >- - Instance profile: '{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}/profile/ - {{ sap_hana_install_sid }}_HDB{{ sap_hana_install_number }}_{{ line_item }}' - -- name: SAP HANA Add Hosts - Assert that there is no instance profile for the additional hosts - ansible.builtin.assert: - that: not __sap_hana_install_register_instance_profile_addhost.stat.exists - fail_msg: >- - FAIL: Addhost operation will not be performed because there is already an instance profile for host {{ line_item }} at - {{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}/profile/{{ sap_hana_install_sid }}_HDB{{ sap_hana_install_number }}_{{ line_item }} - success_msg: "PASS: No instance profile was found for host '{{ line_item }}'." - -- name: SAP HANA Add Hosts - Check for SAP HANA instance directory in '/usr/sap' - ansible.builtin.stat: - path: "/usr/sap/{{ sap_hana_install_sid }}/HDB{{ sap_hana_install_number }}/{{ line_item }}" - register: __sap_hana_install_register_usr_sap_instance_directory - -- name: SAP HANA Add Hosts - Show the path name of the instance directory in '/usr/sap' - ansible.builtin.debug: - msg: "Instance directory in /usr/sap: '/usr/sap/{{ sap_hana_install_sid }}/HDB{{ sap_hana_install_number }}/{{ line_item }}'" - -- name: SAP HANA Add Hosts - Assert that there is no SAP HANA instance directory in '/usr/sap' for the additional hosts - ansible.builtin.assert: - that: not __sap_hana_install_register_usr_sap_instance_directory.stat.exists - fail_msg: >- - FAIL: Addhost operation will not be performed because there is already an instance directory for host {{ line_item }} at location - /usr/sap/{{ sap_hana_install_sid }}/HDB{{ sap_hana_install_number }}/{{ line_item }} - success_msg: "PASS: No instance directory was found for host '{{ line_item }}' in /usr/sap." diff --git a/roles/sap_hana_install/tasks/hana_addhosts.yml b/roles/sap_hana_install/tasks/hana_addhosts.yml index 9f65c381f..1a70de892 100644 --- a/roles/sap_hana_install/tasks/hana_addhosts.yml +++ b/roles/sap_hana_install/tasks/hana_addhosts.yml @@ -1,31 +1,12 @@ # SPDX-License-Identifier: Apache-2.0 --- -- name: SAP HANA Add Hosts - Fill new variable __sap_hana_install_addhosts_hosts - ansible.builtin.set_fact: - __sap_hana_install_addhosts_hosts: "{{ __sap_hana_install_addhosts_hosts | d([]) + [item.split(':')[0]] }}" - with_items: "{{ sap_hana_install_addhosts.split(',') }}" - -- name: SAP HANA Add Hosts - Show the contents of __sap_hana_install_addhosts_hosts - ansible.builtin.debug: - var: __sap_hana_install_addhosts_hosts - -- name: SAP HANA Add Hosts - Show the additional hosts to be added - ansible.builtin.debug: - msg: "Additional hosts: '{{ __sap_hana_install_addhosts_hosts }}'" - -- name: SAP HANA Add Hosts - Make sure the additional hosts are not yet part of the exiting SAP HANA system - file checks - ansible.builtin.include_tasks: assert-addhosts-loop-block.yml - loop: "{{ __sap_hana_install_addhosts_hosts }}" - loop_control: - loop_var: line_item - -- name: SAP HANA Add Hosts - Make sure the additional hosts are not yet part of the exiting SAP HANA system - hdblcm checks +- name: SAP HANA - Addhosts - Make sure the additional hosts are not yet part of the exiting SAP HANA system - hdblcm checks when: not ansible_check_mode block: # Reason for noqa: We can safely fail at the last command in the pipeline. - - name: SAP HANA Add Hosts - Run 'hdblcm --list_systems' # noqa risky-shell-pipe + - name: SAP HANA - Addhosts - Run 'hdblcm --list_systems' # noqa risky-shell-pipe ansible.builtin.shell: | ./hdblcm --list_systems | awk '/\/hana\/shared\/{{ sap_hana_install_sid }}/{a=1} /hosts:/{if (a==1){ @@ -36,22 +17,22 @@ register: __sap_hana_install_register_hdblcm_list_systems changed_when: false - - name: SAP HANA Add Hosts - Show the output of hdblcm --list_systems + - name: SAP HANA - Addhosts - Show the output of hdblcm --list_systems ansible.builtin.debug: - var: __sap_hana_install_register_hdblcm_list_systems + msg: "{{ __sap_hana_install_register_hdblcm_list_systems.stdout_lines }}" - - name: SAP HANA Add Hosts - Assert that the additional hosts are not shown in hdblcm --list_systems + - name: SAP HANA - Addhosts - Assert that the additional hosts are not shown in hdblcm --list_systems ansible.builtin.assert: that: line_item not in __sap_hana_install_register_hdblcm_list_systems.stdout fail_msg: >- FAIL: The host '{{ line_item }}' is already part of system '{{ sap_hana_install_sid }}' and addhosts operation will not be performed. success_msg: "PASS: Host '{{ line_item }}' is not yet part of system '{{ sap_hana_install_sid }}'." - loop: "{{ __sap_hana_install_addhosts_hosts }}" + loop: "{{ __sap_hana_install_fact_addhosts_hosts }}" loop_control: loop_var: line_item -- name: SAP HANA Add Hosts - Set fact for hdblcm command line +- name: SAP HANA - Addhosts - Set fact for hdblcm command line ansible.builtin.set_fact: __sap_hana_install_hdblcm_command: "./hdblcm {{ sap_hana_install_hdblcm_extraargs | d('') }} --action=add_hosts @@ -60,12 +41,12 @@ -b" tags: sap_hana_install_hdblcm_commandline -- name: SAP HANA Add Hosts - Show the hdblcm addhosts command line +- name: SAP HANA - Addhosts - Show the hdblcm addhosts command line ansible.builtin.debug: msg: "SAP HANA addhosts command: '{{ __sap_hana_install_hdblcm_command }}'" tags: sap_hana_install_hdblcm_commandline -- name: SAP HANA Add Hosts - Add hosts to the existing SAP HANA installation +- name: SAP HANA - Addhosts - Add hosts to the existing SAP HANA installation ansible.builtin.command: "{{ __sap_hana_install_hdblcm_command }}" register: __sap_hana_install_register_hdblcm_add_hosts args: @@ -73,12 +54,14 @@ changed_when: "'SAP HANA Lifecycle Management' in __sap_hana_install_register_hdblcm_add_hosts.stdout" when: not ansible_check_mode -- name: SAP HANA Add Hosts - Show the result of hdblcm add_hosts +- name: SAP HANA - Addhosts - Show the result of hdblcm add_hosts ansible.builtin.debug: - var: __sap_hana_install_register_hdblcm_add_hosts.stdout - when: not ansible_check_mode + msg: "{{ __sap_hana_install_register_hdblcm_add_hosts.stdout }}" + when: + - not ansible_check_mode + - __sap_hana_install_register_hdblcm_add_hosts.stdout is defined -- name: SAP HANA Add Hosts - Run 'hdblcm --list_systems' after the installation +- name: SAP HANA - Addhosts - Run 'hdblcm --list_systems' after the installation ansible.builtin.shell: | set -o pipefail && ./hdblcm --list_systems | awk '/\/hana\/shared\/{{ sap_hana_install_sid }}/{a=1} /version:/{if (a==1){ @@ -93,7 +76,7 @@ changed_when: false when: not ansible_check_mode -- name: SAP HANA Add Hosts - Show the HANA version and hosts +- name: SAP HANA - Addhosts - Show the HANA version and hosts ansible.builtin.debug: msg: "HANA system '{{ sap_hana_install_sid }}': {{ __sap_hana_install_register_addhosts_result.stdout }}" when: not ansible_check_mode diff --git a/roles/sap_hana_install/tasks/hana_install.yml b/roles/sap_hana_install/tasks/hana_install.yml index 66c480f0b..d41b17ea9 100644 --- a/roles/sap_hana_install/tasks/hana_install.yml +++ b/roles/sap_hana_install/tasks/hana_install.yml @@ -3,7 +3,7 @@ # Ansible does not support streaming of stdout, so we offer a workaround. # For more information, see https://github.com/ansible/proposals/issues/92 -- name: Install SAP HANA - Copy file tail-f-hdblcm-install-trc.sh to '{{ __sap_hana_install_register_tmpdir.path }}' +- name: SAP HANA - Install - Copy file tail-f-hdblcm-install-trc.sh to '{{ __sap_hana_install_register_tmpdir.path }}' ansible.builtin.copy: src: tmp/tail-f-hdblcm-install-trc.sh dest: "{{ __sap_hana_install_register_tmpdir.path }}/tail-f-hdblcm-install-trc.sh" @@ -12,7 +12,7 @@ mode: '0755' # Show how to use the workaround: -- name: Install SAP HANA - Show how to watch the install process in real time +- name: SAP HANA - Install - Show how to watch the install process in real time ansible.builtin.debug: msg: - 'Once the task "Install SAP HANA" has started, you can use the following command' @@ -21,12 +21,12 @@ - 'Alternatively, you can run the following command on the control node:' - "ssh {{ inventory_hostname }} {{ __sap_hana_install_register_tmpdir.path }}/tail-f-hdblcm-install-trc.sh" -- name: Install SAP HANA - Set fact for the hdblcm verify_signature argument +- name: SAP HANA - Install - Set fact for the hdblcm verify_signature argument ansible.builtin.set_fact: __sap_hana_install_fact_verify_signature: '--verify_signature' when: sap_hana_install_verify_signature -- name: Install SAP HANA - Set fact for the hdblcm command line +- name: SAP HANA - Install - Set fact for the hdblcm command line ansible.builtin.set_fact: __sap_hana_install_hdblcm_command: "./hdblcm {{ sap_hana_install_hdblcm_extraargs | d('') }} {{ __sap_hana_install_fact_verify_signature | d('') }} @@ -34,12 +34,12 @@ -b" tags: sap_hana_install_hdblcm_commandline -- name: Install SAP HANA - Display the hdblcm command line +- name: SAP HANA - Install - Display the hdblcm command line ansible.builtin.debug: msg: "SAP HANA install command: '{{ __sap_hana_install_hdblcm_command }}'" tags: sap_hana_install_hdblcm_commandline -- name: Install SAP HANA - {{ sap_hana_install_sid }} {{ sap_hana_install_number }} +- name: SAP HANA - Install - {{ sap_hana_install_sid }} {{ sap_hana_install_number }} ansible.builtin.command: "{{ __sap_hana_install_hdblcm_command }}" register: __sap_hana_install_register_hdblcm_install_async_job args: @@ -49,7 +49,7 @@ changed_when: true when: not ansible_check_mode -- name: Install SAP HANA - Wait for hdblcm process to exit, poll every 60 seconds +- name: SAP HANA - Install - Wait for hdblcm process to exit, poll every 60 seconds ansible.builtin.shell: cmd: set -o pipefail && ps -ef | awk '/ hdblcm /&&/ {{ __sap_hana_install_configfile_arg }} /&&!/ awk /{print}' register: __sap_hana_install_register_pids_sapinst @@ -60,17 +60,17 @@ __sap_hana_install_configfile_arg: "{{ '--configfile=' + (__sap_hana_install_register_tmpdir.path + '/configfile.cfg') | regex_replace('/', '\\/') }}" changed_when: false -- name: Install SAP HANA - Verify if hdblcm process finished successfully +- name: SAP HANA - Install - Verify if hdblcm process finished successfully ansible.builtin.async_status: jid: "{{ __sap_hana_install_register_hdblcm_install_async_job.ansible_job_id }}" register: __sap_hana_install_register_sapinst failed_when: __sap_hana_install_register_sapinst.finished != 1 or __sap_hana_install_register_sapinst.rc != 0 -- name: Install SAP HANA - Display the hdblcm return code +- name: SAP HANA - Install - Display the hdblcm return code ansible.builtin.debug: msg: "{{ __sap_hana_install_register_sapinst.rc }}" -- name: Install SAP HANA - Display the hdblcm output +- name: SAP HANA - Install - Display the hdblcm output ansible.builtin.debug: msg: "{{ __sap_hana_install_register_sapinst.stdout_lines }}" when: sap_hana_install_display_unattended_output diff --git a/roles/sap_hana_install/tasks/main.yml b/roles/sap_hana_install/tasks/main.yml index 6fa61915f..7e9e586ac 100644 --- a/roles/sap_hana_install/tasks/main.yml +++ b/roles/sap_hana_install/tasks/main.yml @@ -5,7 +5,7 @@ # Check if variable is defined and non-empty before using it, otherwise fall back to backwards # compatible variable or default empty string that will fail asserts afterwards. # NOTE: This is not __var assignment so it will not override user specified vars due to precedence! -- name: Rename some variables used by hdblcm configfile +- name: Set mandatory variables used by hdblcm configfile ansible.builtin.set_fact: sap_hana_install_sid: "{{ sap_hana_sid | d('') @@ -25,7 +25,7 @@ - sap_hana_install_configure_firewall # Separate task for password with no_log -- name: Rename some variables used by hdblcm configfile - passwords +- name: Set mandatory variables used by hdblcm configfile - passwords ansible.builtin.set_fact: sap_hana_install_master_password: "{{ sap_hana_install_common_master_password | d('') @@ -41,7 +41,7 @@ - name: Validate the role variables ansible.builtin.include_tasks: - file: assert_variables.yml + file: pre_tasks/assert_variables.yml tags: - sap_hana_install_check_hana_exists - sap_hana_install_check_installation @@ -60,7 +60,7 @@ # SAP HANA presence has to be validated for both new system and adding new hosts. - name: Validate presence of existing SAP HANA database ansible.builtin.include_tasks: - file: hana_exists.yml + file: pre_tasks/hana_exists.yml when: - (sap_hana_install_new_system and not sap_hana_install_force) or not sap_hana_install_new_system @@ -71,43 +71,70 @@ - name: Ensure SAP HANA is running for existing systems or addhosts operations ansible.builtin.include_tasks: - file: hana_start.yml + file: pre_tasks/hana_start.yml when: __sap_hana_install_fact_is_installed | d(false) +- name: Validate connection to provided addhosts + ansible.builtin.include_tasks: + file: pre_tasks/check_addhosts.yml + when: + - sap_hana_install_addhosts is defined + - sap_hana_install_addhosts is string + - sap_hana_install_addhosts | trim | length > 0 + +# The list is used for all configuration tasks. +# Ensures that current managed node is included for all configuration tasks. +- name: Set fact with list of all hostnames + ansible.builtin.set_fact: + __sap_hana_install_fact_all_hosts: + "{{ __sap_hana_install_fact_addhosts_hosts | d([]) + [inventory_hostname_short | d('')] | unique }}" + + # Instructions for separating tasks to achieve idempotency: # - Installation - Run once for new installations, never repeated. # - Configuration - Run always to ensure idempotent outcome. -# Pre-installation currently does not contain configuration tasks, which would require idempotency. -# Executed for new installations and addhosts, because addhosts configfile creation is included. -- name: SAP HANA pre-install steps - ansible.builtin.include_tasks: - file: pre_install.yml - tags: sap_hana_install_preinstall - when: - - (sap_hana_install_new_system and not __sap_hana_install_fact_is_installed | d(false)) - or not sap_hana_install_new_system +- name: Block for Installation tasks + when: sap_hana_install_new_system + block: + - name: SAP HANA - Install - Pre-Tasks + ansible.builtin.include_tasks: + file: pre_install.yml + tags: sap_hana_install_preinstall + when: not __sap_hana_install_fact_is_installed | d(false) -# Installation currently does not contain configuration tasks, which would require idempotency. -# Executed only for new installations. -- name: SAP HANA installation steps - ansible.builtin.include_tasks: - file: hana_install.yml - when: - - not __sap_hana_install_fact_is_installed | d(false) - - sap_hana_install_new_system + - name: SAP HANA - Install + ansible.builtin.include_tasks: + file: hana_install.yml + when: + - not __sap_hana_install_fact_is_installed | d(false) -# Executed only for addhosts. -- name: SAP HANA addhosts steps - ansible.builtin.include_tasks: - file: hana_addhosts.yml + - name: SAP HANA - Install - Post-tasks + ansible.builtin.include_tasks: + file: post_install.yml + + +# hana_exists already fails if HANA is not detected. +- name: Block for Addhosts tasks when: - - __sap_hana_install_fact_is_installed | d(false) - not sap_hana_install_new_system + - __sap_hana_install_fact_is_installed | d(false) + block: + # Execute only if new hosts are to be added. + - name: SAP HANA - Addhosts - Pre-Tasks + ansible.builtin.include_tasks: + file: pre_addhosts.yml + when: __sap_hana_install_fact_addhosts_hosts_new | d([]) | length > 0 + tags: sap_hana_install_preinstall -# Post-installation contains both installation and configuration tasks. -# Executed for new or existing installations and addhosts. -- name: SAP HANA post-install steps - ansible.builtin.include_tasks: - file: post_install.yml + - name: SAP HANA - Addhosts + ansible.builtin.include_tasks: + file: hana_addhosts.yml + when: __sap_hana_install_fact_addhosts_hosts_new | d([]) | length > 0 + + - name: SAP HANA - Addhosts - Post-tasks + ansible.builtin.include_tasks: + file: post_addhosts.yml + +# TODO: Check hosts in post_install and compare against addhosts string, then debug explanation! diff --git a/roles/sap_hana_install/tasks/post_addhosts.yml b/roles/sap_hana_install/tasks/post_addhosts.yml new file mode 100644 index 000000000..1a34c6e63 --- /dev/null +++ b/roles/sap_hana_install/tasks/post_addhosts.yml @@ -0,0 +1,89 @@ +# SPDX-License-Identifier: Apache-2.0 +--- + +# Execute only on new addhosts, if present. +- name: SAP HANA - Addhosts - Post-Tasks - Set user expiration + ansible.builtin.include_tasks: + file: post_tasks/user_expiration.yml + loop: "{{ __sap_hana_install_fact_addhosts_hosts_new }}" + loop_control: + loop_var: target_host + when: + - __sap_hana_install_fact_addhosts_hosts_new | length > 0 + - sap_hana_install_set_sidadm_noexpire | d(true) + + +# Execute on all hosts in play to achieve idempotency. +- name: SAP HANA - Addhosts - Post-Tasks - Firewall + ansible.builtin.include_tasks: + file: post_tasks/firewall.yml + loop: "{{ __sap_hana_install_fact_all_hosts }}" + loop_control: + loop_var: target_host + when: sap_hana_install_update_firewall + tags: sap_hana_install_configure_firewall + +- name: SAP HANA - Addhosts - Post-Tasks - SELinux + ansible.builtin.include_tasks: + file: post_tasks/selinux.yml + loop: "{{ __sap_hana_install_fact_all_hosts }}" + loop_control: + loop_var: target_host + when: sap_hana_install_modify_selinux_labels + +- name: SAP HANA - Addhosts - Post-Tasks - Fapolicyd + ansible.builtin.include_tasks: + file: post_tasks/fapolicyd.yml + loop: "{{ __sap_hana_install_fact_all_hosts }}" + loop_control: + loop_var: target_host + when: + # Ensure fapolicyd is checked only on supported systems. + - ansible_os_family == "RedHat" + - sap_hana_install_use_fapolicyd + tags: sap_hana_install_use_fapolicyd + + +# Gather details about installed database for finished message +- name: SAP HANA - Addhosts - Post-Tasks - Run 'hdblcm --list_systems' after the installation + ansible.builtin.shell: | + set -o pipefail && ./hdblcm --list_systems | awk '/\/hana\/shared\/{{ sap_hana_install_sid }}/{a=1} + /version:/{if (a==1){ + gsub ("^\\s*version: ", "");printf ("%s;", $NF)} + } + /hosts?:/{if (a==1){ + gsub ("^\\s*hosts?: ", ""); gsub (", ", ","); print; a=0} + }' + args: + chdir: "{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}/hdblcm" + register: __sap_hana_install_register_install_result + changed_when: false + when: not ansible_check_mode + +- name: SAP HANA - Addhosts - Post-Tasks - Set facts with HANA version and hosts + ansible.builtin.set_fact: + __sap_hana_install_fact_hana_version: "{{ __sap_hana_install_register_install_result.stdout.split(';')[0] }}" + __sap_hana_install_fact_hana_hosts: "{{ __sap_hana_install_register_install_result.stdout.split(';')[1] }}" + when: not ansible_check_mode + + +- name: SAP HANA - Addhosts - Post-Tasks - Display SAP HANA details and completed post tasks + ansible.builtin.debug: + msg: | + SAP HANA database is installed and running: + HANA Version - {{ __sap_hana_install_fact_hana_version }} + Hosts - {{ __sap_hana_install_fact_hana_hosts }} + SID - {{ sap_hana_install_sid }} + NR - {{ sap_hana_install_number }} + + {% if sap_hana_install_update_firewall %} + Firewall is enabled and SAP HANA ports are open. + {% endif %} + {% if sap_hana_install_modify_selinux_labels %} + SELinux file contexts are configured for SAP folders '{{ sap_hana_install_root_path }}' and '/usr/sap'. + {% endif %} + {% if ansible_os_family == "RedHat" and sap_hana_install_use_fapolicyd %} + Fapolicyd is configured for SAP folders '{{ sap_hana_install_root_path }}' and '/usr/sap'. + {% endif %} + when: + - not ansible_check_mode diff --git a/roles/sap_hana_install/tasks/post_install.yml b/roles/sap_hana_install/tasks/post_install.yml index 1e58f2f5a..4b524ecb7 100644 --- a/roles/sap_hana_install/tasks/post_install.yml +++ b/roles/sap_hana_install/tasks/post_install.yml @@ -7,43 +7,41 @@ - not __sap_hana_install_fact_is_installed | d(false) block: - - name: SAP HANA Post Install - Store connection information + - name: SAP HANA - Install - Post-Tasks - Store connection information ansible.builtin.include_tasks: - file: post_install/hdbuserstore.yml + file: post_tasks/hdbuserstore.yml tags: sap_hana_install_store_connection_information - - name: SAP HANA Post Install - Set log_mode + - name: SAP HANA - Install - Post-Tasks - Set log_mode ansible.builtin.include_tasks: - file: post_install/log_mode.yml + file: post_tasks/log_mode.yml tags: sap_hana_install_set_log_mode - - name: SAP HANA Post Install - Apply license + - name: SAP HANA - Install - Post-Tasks - Apply license ansible.builtin.include_tasks: - file: post_install/license.yml + file: post_tasks/license.yml when: sap_hana_install_apply_license - - name: SAP HANA Post Install - Recreate the initial tenant database + - name: SAP HANA - Install - Post-Tasks - Recreate the initial tenant database ansible.builtin.include_tasks: - file: post_install/recreate_tenant_database.yml + file: post_tasks/recreate_tenant_database.yml when: sap_hana_install_recreate_tenant_database | d(true) - - name: SAP HANA Post Install - Set '{{ sap_hana_install_sid | lower }}adm' to not expire - ansible.builtin.shell: | - chage -m 0 -M 99999 -I -1 -E -1 {{ sap_hana_install_sid | lower }}adm - args: - executable: /bin/bash - become: true - register: __sap_hana_install_post_install_register_sidadm_noexpire - changed_when: __sap_hana_install_post_install_register_sidadm_noexpire.rc == 0 + - name: SAP HANA - Install - Post-Tasks - Set user expiration + ansible.builtin.include_tasks: + file: post_tasks/user_expiration.yml + loop: "{{ __sap_hana_install_fact_all_hosts }}" + loop_control: + loop_var: target_host when: sap_hana_install_set_sidadm_noexpire | d(true) - - name: SAP HANA Post Install - Perform an hdblcm installation check + - name: SAP HANA - Install - Post-Tasks - Perform an hdblcm installation check ansible.builtin.include_tasks: - file: post_install/check_installation.yml + file: post_tasks/check_installation.yml when: sap_hana_install_check_installation | d(false) tags: sap_hana_install_check_installation - - name: SAP HANA Post Install - Generate Input File for SAP Application Deployment + - name: SAP HANA - Install - Post-Tasks - Generate Input File for SAP Application Deployment '{{ sap_hana_install_nw_input_location }}/{{ sap_hana_install_sid }}.info.nw.install' ansible.builtin.template: src: "{{ role_path }}/templates/sap-nw-input.j2" @@ -56,49 +54,51 @@ tags: sap_hana_install_generate_input_file # Cleanup extracted software - - name: SAP HANA Post Install - Deleting software extract directory '{{ sap_hana_install_software_extract_directory }}' + - name: SAP HANA - Install - Post-Tasks - Deleting software extract directory '{{ sap_hana_install_software_extract_directory }}' ansible.builtin.file: path: "{{ sap_hana_install_software_extract_directory }}" state: absent when: sap_hana_install_cleanup_extract_directory - - name: SAP HANA Post Install - Deleting Configfile Directory '{{ sap_hana_install_configfile_directory }}' + - name: SAP HANA - Install - Post-Tasks - Deleting Configfile Directory '{{ sap_hana_install_configfile_directory }}' ansible.builtin.file: path: "{{ sap_hana_install_configfile_directory }}" state: absent when: sap_hana_install_cleanup_configfile_directory -# Idempotent tasks for new and existing HANA Systems -- name: SAP HANA Post Install - Firewall +- name: SAP HANA - Install - Post-Tasks - Firewall ansible.builtin.include_tasks: - file: post_install/firewall.yml + file: post_tasks/firewall.yml + loop: "{{ __sap_hana_install_fact_all_hosts }}" + loop_control: + loop_var: target_host when: sap_hana_install_update_firewall tags: sap_hana_install_configure_firewall -- name: SAP HANA Post Install - SELinux - ansible.builtin.include_role: - name: '{{ sap_hana_install_system_roles_collection }}.selinux' - vars: - selinux_fcontexts: - - { target: '/usr/sap(/.*)?', setype: 'usr_t' } - selinux_restore_dirs: - - /usr/sap +- name: SAP HANA - Install - Post-Tasks - SELinux + ansible.builtin.include_tasks: + file: post_tasks/selinux.yml + loop: "{{ __sap_hana_install_fact_all_hosts }}" + loop_control: + loop_var: target_host when: sap_hana_install_modify_selinux_labels -- name: SAP HANA Post Install - Fapolicyd +- name: SAP HANA - Install - Post-Tasks - Fapolicyd ansible.builtin.include_tasks: - file: post_install/fapolicyd.yml + file: post_tasks/fapolicyd.yml + loop: "{{ __sap_hana_install_fact_all_hosts }}" + loop_control: + loop_var: target_host when: # Ensure fapolicyd is checked only on supported systems. - ansible_os_family == "RedHat" - sap_hana_install_use_fapolicyd - - '"fapolicyd" in ansible_facts.packages' tags: sap_hana_install_use_fapolicyd # Gather details about installed database for finished message -- name: SAP HANA Install - Run 'hdblcm --list_systems' after the installation +- name: SAP HANA - Install - Post-Tasks - Run 'hdblcm --list_systems' after the installation ansible.builtin.shell: | set -o pipefail && ./hdblcm --list_systems | awk '/\/hana\/shared\/{{ sap_hana_install_sid }}/{a=1} /version:/{if (a==1){ @@ -113,14 +113,14 @@ changed_when: false when: not ansible_check_mode -- name: SAP HANA Post Install - Set facts with HANA version and hosts +- name: SAP HANA - Install - Post-Tasks - Set facts with HANA version and hosts ansible.builtin.set_fact: __sap_hana_install_fact_hana_version: "{{ __sap_hana_install_register_install_result.stdout.split(';')[0] }}" __sap_hana_install_fact_hana_hosts: "{{ __sap_hana_install_register_install_result.stdout.split(';')[1] }}" when: not ansible_check_mode -- name: SAP HANA Post Install - Display SAP HANA details and completed post tasks +- name: SAP HANA - Install - Post-Tasks - Display SAP HANA details and completed post tasks ansible.builtin.debug: msg: | SAP HANA database is installed and running: @@ -129,13 +129,18 @@ SID - {{ sap_hana_install_sid }} NR - {{ sap_hana_install_number }} + {% if sap_hana_install_new_system and __sap_hana_install_fact_is_installed and __sap_hana_install_fact_addhosts_hosts | length > 0 %} + The hosts defined in the variable 'sap_hana_install_addhosts' were not added. + Execute this role with the variable 'sap_hana_install_new_system' set to false to add new hosts. + {% endif %} + {% if sap_hana_install_update_firewall %} Firewall is enabled and SAP HANA ports are open. {% endif %} {% if sap_hana_install_modify_selinux_labels %} SELinux file contexts are configured for SAP folders '{{ sap_hana_install_root_path }}' and '/usr/sap'. {% endif %} - {% if ansible_os_family == "RedHat" and sap_hana_install_use_fapolicyd and "fapolicyd" in ansible_facts.packages %} + {% if ansible_os_family == "RedHat" and sap_hana_install_use_fapolicyd %} Fapolicyd is configured for SAP folders '{{ sap_hana_install_root_path }}' and '/usr/sap'. {% endif %} when: diff --git a/roles/sap_hana_install/tasks/post_install/firewall.yml b/roles/sap_hana_install/tasks/post_install/firewall.yml deleted file mode 100644 index a213584ac..000000000 --- a/roles/sap_hana_install/tasks/post_install/firewall.yml +++ /dev/null @@ -1,72 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 ---- - -- name: SAP HANA Post Install - Enable and start the firewalld service - ansible.builtin.systemd: - name: firewalld - state: started - enabled: true - tags: sap_hana_install_configure_firewall - -- name: SAP HANA Post Install - Construct the argument list for 'firewall-cmd --add-port' - ansible.builtin.set_fact: - __sap_hana_install_fact_firewall_cmd_args: - "{{ ['--add-port='] | product(sap_hana_install_firewall[0].port) | map('join') | list }}" - when: sap_hana_install_firewall[0].state == 'enabled' - tags: sap_hana_install_configure_firewall - -- name: SAP HANA Post Install - Construct the argument list for 'firewall-cmd --remove-port' - ansible.builtin.set_fact: - __sap_hana_install_fact_firewall_cmd_args: - "{{ ['--remove-port='] | product(sap_hana_install_firewall[0].port) | map('join') | list }}" - when: sap_hana_install_firewall[0].state == 'disabled' - tags: sap_hana_install_configure_firewall - -- name: SAP HANA Post Install - Set fact for the 'firewall-cmd' command - ansible.builtin.set_fact: - __sap_hana_install_fact_firewall_cmd_command: - "firewall-cmd --zone=public {{ __sap_hana_install_fact_firewall_cmd_args | map('quote') | join(' ') }}" - tags: sap_hana_install_configure_firewall - -- name: SAP HANA Post Install - Display the 'firewall-cmd' command - ansible.builtin.debug: - var: __sap_hana_install_fact_firewall_cmd_command - tags: sap_hana_install_configure_firewall - -# No matter if the ports have already been enabled or not, the changed state -# of the command is always true. For avoiding ansible-lint to report a violation -# of the no-changed-when rule, we just set changed_when to true here. -- name: SAP HANA Post Install - Enable the required ports immediately - ansible.builtin.command: "{{ __sap_hana_install_fact_firewall_cmd_command }}" - changed_when: true - tags: sap_hana_install_configure_firewall - -- name: SAP HANA Post Install - Get the current firewall configuration of the default zone - ansible.builtin.command: firewall-cmd --list-all - changed_when: false - register: __sap_hana_install_register_current_firewall_ports - tags: sap_hana_install_configure_firewall - -- name: SAP HANA Post Install - Display the current firewall configuration of the default zone - ansible.builtin.debug: - var: __sap_hana_install_register_current_firewall_ports.stdout_lines - tags: sap_hana_install_configure_firewall - -# No matter if the ports have already been enabled or not, the changed state -# of the command is always true. For avoiding ansible-lint to report a violation -# of the no-changed-when rule, we just set changed_when to true here. -- name: SAP HANA Post Install - Enable the required ports permanently - ansible.builtin.command: "{{ __sap_hana_install_fact_firewall_cmd_command }} --permanent" - changed_when: true - tags: sap_hana_install_configure_firewall - -- name: SAP HANA Post Install - Get the permanent firewall configuration of the default zone - ansible.builtin.command: firewall-cmd --list-all - changed_when: false - register: __sap_hana_install_register_permanent_firewall_ports - tags: sap_hana_install_configure_firewall - -- name: SAP HANA Post Install - Display the permanent firewall configuration of the default zone - ansible.builtin.debug: - var: __sap_hana_install_register_permanent_firewall_ports.stdout_lines - tags: sap_hana_install_configure_firewall diff --git a/roles/sap_hana_install/tasks/post_install/update_etchosts.yml b/roles/sap_hana_install/tasks/post_install/update_etchosts.yml deleted file mode 100644 index 79c922a33..000000000 --- a/roles/sap_hana_install/tasks/post_install/update_etchosts.yml +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 ---- - -- name: SAP HANA Post Install - Deduplicate values from /etc/hosts - ansible.builtin.lineinfile: - path: /etc/hosts - create: false - regexp: (?i)^\s*{{ ansible_default_ipv4.address | default(ansible_all_ipv4_addresses[0]) }}\s+ - state: absent - -- name: SAP HANA Post Install - Update /etc/hosts - ansible.builtin.lineinfile: - path: /etc/hosts - line: "{{ ansible_default_ipv4.address | default(ansible_all_ipv4_addresses[0]) }} {{ ansible_fqdn }} {{ ansible_hostname }}" diff --git a/roles/sap_hana_install/tasks/post_install/update_firewall.yml b/roles/sap_hana_install/tasks/post_install/update_firewall.yml deleted file mode 100644 index d5fca3fe3..000000000 --- a/roles/sap_hana_install/tasks/post_install/update_firewall.yml +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 ---- -# This task requires the variable passed_port - -- name: Update Firewall - {{ passed_port }}/tcp - ansible.posix.firewalld: - zone: public - port: "{{ passed_port }}/tcp" - permanent: true - immediate: true - state: enabled diff --git a/roles/sap_hana_install/tasks/post_install/check_installation.yml b/roles/sap_hana_install/tasks/post_tasks/check_installation.yml similarity index 68% rename from roles/sap_hana_install/tasks/post_install/check_installation.yml rename to roles/sap_hana_install/tasks/post_tasks/check_installation.yml index 1bb100b3b..7921cf252 100644 --- a/roles/sap_hana_install/tasks/post_install/check_installation.yml +++ b/roles/sap_hana_install/tasks/post_tasks/check_installation.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 --- -- name: SAP HANA hdblcm installation check - Create a Jinja2 template from the hdblcm xml configfile template +- name: SAP HANA - Post-Tasks - Create a Jinja2 template from the hdblcm xml configfile template ansible.builtin.shell: | set -o pipefail && awk ' @@ -11,24 +11,24 @@ register: __sap_hana_install_create_jinja2_template changed_when: false -- name: SAP HANA hdblcm installation check - Display the location of the remote Jinja2 template +- name: SAP HANA - Post-Tasks - Display the location of the remote Jinja2 template ansible.builtin.debug: msg: | The Jinja2 template for creating the hdblcm configfile xml has been saved to '{{ sap_hana_install_configfile_directory }}/{{ sap_hana_install_configfile_template_prefix }}.xml.j2'. -- name: SAP HANA hdblcm installation check - Download the Jinja2 template +- name: SAP HANA - Post-Tasks - Download the Jinja2 template ansible.builtin.fetch: src: "{{ sap_hana_install_configfile_directory }}/{{ sap_hana_install_configfile_template_prefix }}.xml.j2" dest: "{{ sap_hana_install_local_configfile_directory }}" register: __sap_hana_install_register_fetch_hdblcm_configfile_xml_jinja2_template -- name: SAP HANA hdblcm installation check - Display the location of the local Jinja2 template +- name: SAP HANA - Post-Tasks - Display the location of the local Jinja2 template ansible.builtin.debug: msg: "The Jinja2 template has been downloaded to '{{ __sap_hana_install_register_fetch_hdblcm_configfile_xml_jinja2_template.dest }}'." when: not ansible_check_mode -- name: SAP HANA hdblcm installation check - Process the Jinja2 template to create the hdblcm xml configfile +- name: SAP HANA - Post-Tasks - Process the Jinja2 template to create the hdblcm xml configfile ansible.builtin.template: src: "{{ __sap_hana_install_register_fetch_hdblcm_configfile_xml_jinja2_template.dest }}" dest: "{{ __sap_hana_install_register_tmpdir.path }}/configfile.cfg.xml" @@ -36,7 +36,7 @@ register: __sap_hana_install_register_cftemplate when: not ansible_check_mode -- name: SAP HANA hdblcm installation check - Construct an hdbcheck command line +- name: SAP HANA - Post-Tasks - Construct an hdbcheck command line ansible.builtin.set_fact: __sap_hana_install_fact_installation_check_command: "set -o pipefail && ./hdbcheck -b --read_password_from_stdin=xml --property_file={{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}/global/hdb/install/support/hdbcheck.xml @@ -45,19 +45,20 @@ -b < {{ __sap_hana_install_register_tmpdir.path }}/configfile.cfg.xml" when: sap_hana_install_use_hdbcheck | d(true) -- name: SAP HANA hdblcm installation check - Construct an hdblcm command line +- name: SAP HANA - Post-Tasks - Construct an hdblcm command line ansible.builtin.set_fact: __sap_hana_install_fact_installation_check_command: "set -o pipefail && ./hdblcm --action=check_installation --read_password_from_stdin=xml -b < {{ __sap_hana_install_register_tmpdir.path }}/configfile.cfg.xml" when: not sap_hana_install_use_hdbcheck | d(true) -- name: SAP HANA hdblcm installation check - Display the command line +- name: SAP HANA - Post-Tasks - Display the command line ansible.builtin.debug: - var: __sap_hana_install_fact_installation_check_command + msg: "{{ __sap_hana_install_fact_installation_check_command }}" + when: __sap_hana_install_fact_installation_check_command is defined # Reason for noqa: The command to be executed contains input redirection -- name: SAP HANA hdblcm installation check with hdbcheck - Perform the check # noqa command-instead-of-shell +- name: SAP HANA - Post-Tasks - hdbcheck - Perform the check # noqa command-instead-of-shell ansible.builtin.shell: "{{ __sap_hana_install_fact_installation_check_command }}" args: chdir: "{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}/global/hdb/install/bin" @@ -65,13 +66,15 @@ changed_when: false when: sap_hana_install_use_hdbcheck | d(true) -- name: SAP HANA hdblcm installation check with hdbcheck - Display the result +- name: SAP HANA - Post-Tasks - hdbcheck - Display the result ansible.builtin.debug: - var: __sap_hana_install_register_installation_check.stdout_lines - when: sap_hana_install_use_hdbcheck | d(true) + msg: "{{ __sap_hana_install_register_installation_check.stdout_lines }}" + when: + - sap_hana_install_use_hdbcheck | d(true) + - __sap_hana_install_register_installation_check.stdout_lines is defined # Reason for noqa: The command to be executed contains input redirection -- name: SAP HANA hdblcm installation check with hdblcm - Perform the check # noqa command-instead-of-shell +- name: SAP HANA - Post-Tasks - hdblcm - Perform the check # noqa command-instead-of-shell ansible.builtin.shell: "{{ __sap_hana_install_fact_installation_check_command }}" args: chdir: "{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}/hdblcm" @@ -79,7 +82,9 @@ changed_when: false when: not sap_hana_install_use_hdbcheck | d(true) -- name: SAP HANA hdblcm installation check with hdblcm - Display the result +- name: SAP HANA - Post-Tasks - hdblcm - Display the result ansible.builtin.debug: - var: __sap_hana_install_register_installation_check.stdout_lines - when: not sap_hana_install_use_hdbcheck | d(true) + msg: "{{ __sap_hana_install_register_installation_check.stdout_lines }}" + when: + - not sap_hana_install_use_hdbcheck | d(true) + - __sap_hana_install_register_installation_check.stdout_lines is defined diff --git a/roles/sap_hana_install/tasks/post_install/fapolicyd.yml b/roles/sap_hana_install/tasks/post_tasks/fapolicyd.yml similarity index 66% rename from roles/sap_hana_install/tasks/post_install/fapolicyd.yml rename to roles/sap_hana_install/tasks/post_tasks/fapolicyd.yml index 7fe169ead..362532436 100644 --- a/roles/sap_hana_install/tasks/post_install/fapolicyd.yml +++ b/roles/sap_hana_install/tasks/post_tasks/fapolicyd.yml @@ -1,16 +1,25 @@ # SPDX-License-Identifier: Apache-2.0 --- -- name: SAP HANA Post Install, fapolicyd - Update config for desired integrity level and revert if validation fails +# This is required for addhosts pre-tasks are not run and package must be present. +- name: SAP HANA - Post-Tasks - Ensure the presence of fapolicyd + ansible.builtin.package: + name: fapolicyd + state: present + delegate_to: "{{ target_host }}" + when: not sap_hana_install_new_system + +- name: SAP HANA - Post-Tasks - Update config for desired integrity level and revert if validation fails + delegate_to: "{{ target_host }}" block: - - name: SAP HANA Post Install, fapolicyd - Ensure Ansible marker for 'integrity' is present in fapolicyd config file + - name: SAP HANA - Post-Tasks - Ensure Ansible marker for 'integrity' is present in fapolicyd config file ansible.builtin.lineinfile: path: /etc/fapolicyd/fapolicyd.conf regexp: '# "integrity" managed by Ansible' insertbefore: '^integrity\s*=.*' line: '# "integrity" managed by Ansible' - - name: SAP HANA Post Install, fapolicyd - Ensure integrity level '{{ sap_hana_install_fapolicyd_integrity }}' is configured" + - name: SAP HANA - Post-Tasks - Ensure integrity level '{{ sap_hana_install_fapolicyd_integrity }}' is configured" ansible.builtin.lineinfile: path: /etc/fapolicyd/fapolicyd.conf regexp: '^(integrity\s*=.*)' @@ -19,13 +28,13 @@ backup: true register: __sap_hana_install_fapolicyd_conf_updated - - name: SAP HANA Post Install, fapolicyd - Validate the new version of the fapolicyd config file + - name: SAP HANA - Post-Tasks - Validate the new version of the fapolicyd config file ansible.builtin.command: fapolicyd-cli --check-config changed_when: false rescue: - - name: SAP HANA Post Install, fapolicyd - Restore fapolicyd config file from backup if validation fails + - name: SAP HANA - Post-Tasks - Restore fapolicyd config file from backup if validation fails ansible.builtin.copy: remote_src: true dest: /etc/fapolicyd/fapolicyd.conf @@ -34,17 +43,18 @@ group: fapolicyd mode: '0644' - - name: SAP HANA Post Install, fapolicyd - Notify about failed validation + - name: SAP HANA - Post-Tasks - Notify about failed validation ansible.builtin.fail: msg: >- "The update of the fapolicyd config file failed, likely because an unsupported value has been used for the parameter 'sap_hana_install_fapolicyd_integrity'. The previous version has been successfully restored." -- name: SAP HANA Post Install, fapolicyd - Create rule and trust files, enable fapolicyd +- name: SAP HANA - Post-Tasks - Create rule and trust files, enable fapolicyd + delegate_to: "{{ target_host }}" block: - - name: SAP HANA Post Install, fapolicyd - Process template for creating rule file '{{ sap_hana_install_fapolicyd_rule_file }}' + - name: SAP HANA - Post-Tasks - Process template for creating rule file '{{ sap_hana_install_fapolicyd_rule_file }}' ansible.builtin.template: src: fapolicyd-rules.j2 dest: "/etc/fapolicyd/rules.d/{{ sap_hana_install_fapolicyd_rule_file }}.rules" @@ -53,11 +63,11 @@ mode: '0644' # Reason for noqa: The return code of the command is always 0 no matter if there was a change or not - - name: SAP HANA Post Install, fapolicyd - Merge rule files # noqa no-changed-when + - name: SAP HANA - Post-Tasks - Merge rule files # noqa no-changed-when ansible.builtin.command: fagenrules --load register: sap_hana_install_register_fagenrules_load - - name: SAP HANA Post Install, fapolicyd - Display the output of the command 'fagenrules --load' + - name: SAP HANA - Post-Tasks - Display the output of the command 'fagenrules --load' ansible.builtin.debug: msg: "{{ sap_hana_install_register_fagenrules_load.stdout_lines }}" @@ -65,7 +75,7 @@ # by fapolicyd-cli -t, one for each directory of sap_hana_install_fapolicyd_trusted_directories. # The fapolicy trust file name will be created from the directory names by replacing '/' by '_' and # omitting the first '_'. - - name: SAP HANA Post Install, fapolicyd - Put all executable files from 'sap_hana_install_fapolicyd_trusted_directories' into fapolicyd trust files + - name: SAP HANA - Post-Tasks - Put all executable files from 'sap_hana_install_fapolicyd_trusted_directories' into fapolicyd trust files ansible.builtin.shell: | set -o pipefail && find {{ __sap_hana_install_item }} -type f -executable -exec fapolicyd-cli -t {} \; -print | @@ -86,13 +96,13 @@ regex_replace('^_', '') }}" changed_when: true - - name: SAP HANA Post Install, fapolicyd - Enable fapolicyd + - name: SAP HANA - Post-Tasks - Enable fapolicyd ansible.builtin.service: name: fapolicyd enabled: true state: started - - name: SAP HANA Post Install, fapolicyd - Restart fapolicyd + - name: SAP HANA - Post-Tasks - Restart fapolicyd ansible.builtin.service: name: fapolicyd enabled: true diff --git a/roles/sap_hana_install/tasks/post_tasks/firewall.yml b/roles/sap_hana_install/tasks/post_tasks/firewall.yml new file mode 100644 index 000000000..23bd5705b --- /dev/null +++ b/roles/sap_hana_install/tasks/post_tasks/firewall.yml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: Apache-2.0 +--- + +- name: Block to delegate_to all tasks + delegate_to: "{{ target_host }}" + block: + + - name: SAP HANA - Post-Tasks - Enable and start the firewalld service + ansible.builtin.systemd: + name: firewalld + state: started + enabled: true + + - name: SAP HANA - Post-Tasks - Construct the argument list for 'firewall-cmd --add-port' + ansible.builtin.set_fact: + __sap_hana_install_fact_firewall_cmd_args: + "{{ ['--add-port='] | product(sap_hana_install_firewall[0].port) | map('join') | list }}" + when: sap_hana_install_firewall[0].state == 'enabled' + + - name: SAP HANA - Post-Tasks - Construct the argument list for 'firewall-cmd --remove-port' + ansible.builtin.set_fact: + __sap_hana_install_fact_firewall_cmd_args: + "{{ ['--remove-port='] | product(sap_hana_install_firewall[0].port) | map('join') | list }}" + when: sap_hana_install_firewall[0].state == 'disabled' + + - name: SAP HANA - Post-Tasks - Set fact for the 'firewall-cmd' command + ansible.builtin.set_fact: + __sap_hana_install_fact_firewall_cmd_command: + "firewall-cmd --zone=public {{ __sap_hana_install_fact_firewall_cmd_args | map('quote') | join(' ') }}" + + - name: SAP HANA - Post-Tasks - Display the 'firewall-cmd' command + ansible.builtin.debug: + msg: "{{ __sap_hana_install_fact_firewall_cmd_command }}" + + # No matter if the ports have already been enabled or not, the changed state + # of the command is always true. For avoiding ansible-lint to report a violation + # of the no-changed-when rule, we just set changed_when to true here. + - name: SAP HANA - Post-Tasks - Enable the required ports immediately + ansible.builtin.command: "{{ __sap_hana_install_fact_firewall_cmd_command }}" + changed_when: true + + - name: SAP HANA - Post-Tasks - Get the current firewall configuration of the default zone + ansible.builtin.command: firewall-cmd --list-all + changed_when: false + register: __sap_hana_install_register_current_firewall_ports + + - name: SAP HANA - Post-Tasks - Display the current firewall configuration of the default zone + ansible.builtin.debug: + msg: "{{ __sap_hana_install_register_current_firewall_ports.stdout_lines }}" + when: __sap_hana_install_register_current_firewall_ports.stdout_lines is defined + + # No matter if the ports have already been enabled or not, the changed state + # of the command is always true. For avoiding ansible-lint to report a violation + # of the no-changed-when rule, we just set changed_when to true here. + - name: SAP HANA - Post-Tasks - Enable the required ports permanently + ansible.builtin.command: "{{ __sap_hana_install_fact_firewall_cmd_command }} --permanent" + changed_when: true + + - name: SAP HANA - Post-Tasks - Get the permanent firewall configuration of the default zone + ansible.builtin.command: firewall-cmd --list-all + changed_when: false + register: __sap_hana_install_register_permanent_firewall_ports + + - name: SAP HANA - Post-Tasks - Display the permanent firewall configuration of the default zone + ansible.builtin.debug: + msg: "{{ __sap_hana_install_register_permanent_firewall_ports.stdout_lines }}" + when: __sap_hana_install_register_permanent_firewall_ports.stdout_lines is defined diff --git a/roles/sap_hana_install/tasks/post_install/hdbuserstore.yml b/roles/sap_hana_install/tasks/post_tasks/hdbuserstore.yml similarity index 71% rename from roles/sap_hana_install/tasks/post_install/hdbuserstore.yml rename to roles/sap_hana_install/tasks/post_tasks/hdbuserstore.yml index 2593e5384..5162b4a65 100644 --- a/roles/sap_hana_install/tasks/post_install/hdbuserstore.yml +++ b/roles/sap_hana_install/tasks/post_tasks/hdbuserstore.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 --- -- name: SAP HANA Post Install - Create and Store Connection Info in hdbuserstore +- name: SAP HANA - Post-Tasks - Create and Store Connection Info in hdbuserstore ansible.builtin.shell: | /usr/sap/{{ sap_hana_install_sid }}/SYS/exe/hdb/hdbuserstore \ SET {{ sap_hana_install_hdbuserstore_key }} \ @@ -16,7 +16,8 @@ register: __sap_hana_install_store_connection_information tags: sap_hana_install_store_connection_information -- name: SAP HANA Post Install - Display the output of hdbuserstore +- name: SAP HANA - Post-Tasks - Display the output of hdbuserstore ansible.builtin.debug: - var: __sap_hana_install_store_connection_information.stdout_lines + msg: "{{ __sap_hana_install_store_connection_information.stdout_lines }}" tags: sap_hana_install_store_connection_information + when: __sap_hana_install_store_connection_information.stdout_lines is defined diff --git a/roles/sap_hana_install/tasks/post_install/license.yml b/roles/sap_hana_install/tasks/post_tasks/license.yml similarity index 83% rename from roles/sap_hana_install/tasks/post_install/license.yml rename to roles/sap_hana_install/tasks/post_tasks/license.yml index 409cfadd9..d557cdf69 100644 --- a/roles/sap_hana_install/tasks/post_install/license.yml +++ b/roles/sap_hana_install/tasks/post_tasks/license.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 --- -- name: SAP HANA Post Install - Apply the SAP HANA license +- name: SAP HANA - Post-Tasks - Apply the SAP HANA license ansible.builtin.shell: | /usr/sap/{{ sap_hana_install_sid | upper }}/HDB{{ sap_hana_install_number }}/exe/hdbsql \ -i {{ sap_hana_install_number }} -u SYSTEM @@ -14,5 +14,5 @@ become_user: "{{ sap_hana_install_sid | lower }}adm" changed_when: "'0 rows affected' in addlicense.stdout" # Variable not used: -# register: __sap_hana_install_register_post_install_apply_license +# register: __sap_hana_install_register_post_tasks_apply_license when: sap_hana_install_apply_license diff --git a/roles/sap_hana_install/tasks/post_install/log_mode.yml b/roles/sap_hana_install/tasks/post_tasks/log_mode.yml similarity index 82% rename from roles/sap_hana_install/tasks/post_install/log_mode.yml rename to roles/sap_hana_install/tasks/post_tasks/log_mode.yml index b490f7be8..f5fa90b98 100644 --- a/roles/sap_hana_install/tasks/post_install/log_mode.yml +++ b/roles/sap_hana_install/tasks/post_tasks/log_mode.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 --- -- name: SAP HANA Post Install - Set log_mode to overwrite, no initial tenant +- name: SAP HANA - Post-Tasks - Set log_mode to overwrite, no initial tenant ansible.builtin.shell: | LD_LIBRARY_PATH=/usr/sap/{{ sap_hana_install_sid }}/HDB{{ sap_hana_install_number }}/exe \ /usr/sap/{{ sap_hana_install_sid }}/SYS/exe/hdb/hdbsql \ @@ -26,16 +26,17 @@ register: __sap_hana_install_register_hdbsql_logmode_no_initial_tenant tags: sap_hana_install_set_log_mode -- name: SAP HANA Post Install - Display the output of hdbsql, no initial tenant +- name: SAP HANA - Post-Tasks - Display the output of hdbsql, no initial tenant ansible.builtin.debug: - var: __sap_hana_install_register_hdbsql_logmode_no_initial_tenant.stdout_lines + msg: "{{ __sap_hana_install_register_hdbsql_logmode_no_initial_tenant.stdout_lines }}" tags: sap_hana_install_set_log_mode when: - not ansible_check_mode - sap_hana_install_create_initial_tenant == 'n' - sap_hana_install_log_mode | d('') == 'overwrite' + - __sap_hana_install_register_hdbsql_logmode_no_initial_tenant.stdout_lines is defined -- name: SAP HANA Post Install - Set log_mode to overwrite, with initial tenant +- name: SAP HANA - Post-Tasks - Set log_mode to overwrite, with initial tenant ansible.builtin.shell: | LD_LIBRARY_PATH=/usr/sap/{{ sap_hana_install_sid }}/HDB{{ sap_hana_install_number }}/exe \ /usr/sap/{{ sap_hana_install_sid }}/SYS/exe/hdb/hdbsql \ @@ -61,11 +62,12 @@ register: __sap_hana_install_register_hdbsql_logmode_with_initial_tenant tags: sap_hana_install_set_log_mode -- name: SAP HANA Post Install - Display the output of hdbsql, with initial tenant +- name: SAP HANA - Post-Tasks - Display the output of hdbsql, with initial tenant ansible.builtin.debug: - var: __sap_hana_install_register_hdbsql_logmode_with_initial_tenant.stdout_lines + msg: "{{ __sap_hana_install_register_hdbsql_logmode_with_initial_tenant.stdout_lines }}" tags: sap_hana_install_set_log_mode when: - not ansible_check_mode - sap_hana_install_create_initial_tenant == 'y' - sap_hana_install_log_mode | d('') == 'overwrite' + - __sap_hana_install_register_hdbsql_logmode_with_initial_tenant.stdout_lines is defined diff --git a/roles/sap_hana_install/tasks/post_install/recreate_tenant_database.yml b/roles/sap_hana_install/tasks/post_tasks/recreate_tenant_database.yml similarity index 79% rename from roles/sap_hana_install/tasks/post_install/recreate_tenant_database.yml rename to roles/sap_hana_install/tasks/post_tasks/recreate_tenant_database.yml index e12f394fe..4108c9f13 100644 --- a/roles/sap_hana_install/tasks/post_install/recreate_tenant_database.yml +++ b/roles/sap_hana_install/tasks/post_tasks/recreate_tenant_database.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 --- -- name: SAP HANA Post Install - Recreate the tenant database +- name: SAP HANA - Post-Tasks - Recreate the tenant database ansible.builtin.shell: | LD_LIBRARY_PATH=/usr/sap/{{ sap_hana_install_sid }}/HDB{{ sap_hana_install_number }}/exe \ /usr/sap/{{ sap_hana_install_sid }}/SYS/exe/hdb/hdbsql \ @@ -25,6 +25,7 @@ changed_when: false register: __sap_hana_install_register_recreate_tenant_database -- name: SAP HANA Post Install - Display the result of the hdbsql command +- name: SAP HANA - Post-Tasks - Display the result of the hdbsql command ansible.builtin.debug: - var: __sap_hana_install_register_recreate_tenant_database.stdout_lines + msg: "{{ __sap_hana_install_register_recreate_tenant_database.stdout_lines }}" + when: __sap_hana_install_register_recreate_tenant_database.stdout_lines is defined diff --git a/roles/sap_hana_install/tasks/post_tasks/selinux.yml b/roles/sap_hana_install/tasks/post_tasks/selinux.yml new file mode 100644 index 000000000..ecd9f45e5 --- /dev/null +++ b/roles/sap_hana_install/tasks/post_tasks/selinux.yml @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: Apache-2.0 +--- + +# This configuration includes also Pre-Tasks content to ensure they are all set same. +- name: SAP HANA - Post-Tasks - Configure 'sap_hana_install_root_path' SELinux file contexts + ansible.builtin.include_role: + name: '{{ sap_hana_install_system_roles_collection }}.selinux' + vars: + selinux_booleans: + - { name: 'selinuxuser_execmod', state: 'on' } + selinux_fcontexts: + - { target: '{{ sap_hana_install_root_path }}(/.*)?', setype: 'usr_t' } + - { target: '/usr/sap(/.*)?', setype: 'usr_t' } + selinux_restore_dirs: + - '{{ sap_hana_install_root_path }}' + - /usr/sap + delegate_to: "{{ target_host }}" diff --git a/roles/sap_hana_install/tasks/post_tasks/user_expiration.yml b/roles/sap_hana_install/tasks/post_tasks/user_expiration.yml new file mode 100644 index 000000000..1e82cf000 --- /dev/null +++ b/roles/sap_hana_install/tasks/post_tasks/user_expiration.yml @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 +--- + +- name: SAP HANA - Post-Tasks - Set '{{ sap_hana_install_sid | lower }}adm' to not expire + ansible.builtin.shell: | + chage -m 0 -M 99999 -I -1 -E -1 {{ sap_hana_install_sid | lower }}adm + args: + executable: /bin/bash + become: true + delegate_to: "{{ target_host }}" + register: __sap_hana_install_post_tasks_register_sidadm_noexpire + changed_when: __sap_hana_install_post_tasks_register_sidadm_noexpire.rc == 0 diff --git a/roles/sap_hana_install/tasks/pre_addhosts.yml b/roles/sap_hana_install/tasks/pre_addhosts.yml new file mode 100644 index 000000000..aa9fe18d8 --- /dev/null +++ b/roles/sap_hana_install/tasks/pre_addhosts.yml @@ -0,0 +1,138 @@ +# SPDX-License-Identifier: Apache-2.0 +--- + +# Delegate tasks are not executed on existing Addhosts to avoid +# potential issues with existing SAP HANA installations. + + +# Get details of user 'sapadm' and group 'sapsys' on current node. +- name: SAP HANA - Addhosts - Pre-Tasks - Get details of the 'sapsys' group + ansible.builtin.getent: + database: group + key: sapsys + failed_when: false + +- name: SAP HANA - Addhosts - Pre-Tasks - Get info about user 'sapadm' + ansible.builtin.getent: + database: passwd + key: sapadm + failed_when: false + +# hana_exists already found existing database, this is additional check. +# getent_group['sapsys'][1] and getent_passwd['sapadm'][2] are Group ID. +- name: SAP HANA - Addhosts - Pre-Tasks - Assert that user 'sapadm' is present with group 'sapsys' + ansible.builtin.assert: + that: + - "'sapsys' in getent_group" + - "'sapadm' in getent_passwd" + # Ensure sapadm user is assigned to sapsys group + - getent_group['sapsys'][1] == getent_passwd['sapadm'][2] + fail_msg: >- + FAIL: User 'sapadm' with group 'sapsys' does not exist! + +- name: SAP HANA - Addhosts - Pre-Tasks - Generate password hash for 'sap_hana_install_sapadm_password' + ansible.builtin.shell: + cmd: "set -o pipefail && echo '{{ sap_hana_install_sapadm_password | d(sap_hana_install_master_password) }}' | openssl passwd -6 -stdin" + register: __sap_hana_install_register_sapadm_password_hash + no_log: true + changed_when: false + check_mode: false + +- name: SAP HANA - Addhosts - Pre-Tasks - Create user 'sapadm' with group 'sapsys' on new hosts + ansible.builtin.include_tasks: + file: pre_tasks/create_users_groups.yml + loop: "{{ __sap_hana_install_fact_addhosts_hosts_new }}" + loop_control: + loop_var: target_host + + +- name: SAP HANA - Addhosts - Pre-Tasks - Install and disable fapolicyd + ansible.builtin.include_tasks: + file: pre_tasks/fapolicyd.yml + loop: "{{ __sap_hana_install_fact_addhosts_hosts_new }}" + loop_control: + loop_var: target_host + when: + # Ensure fapolicyd is checked only on supported systems. + - ansible_os_family == "RedHat" + tags: sap_hana_install_use_fapolicyd + + +# Update HANA directory permissions +- name: SAP HANA - Addhosts - Pre-Tasks - Change ownership of HANA directories + ansible.builtin.include_tasks: + file: pre_tasks/hana_directory_permissions.yml + loop: "{{ __sap_hana_install_fact_addhosts_hosts_new }}" + loop_control: + loop_var: target_host + tags: sap_hana_install_chown_hana_directories + + +# Configure SElinux +- name: SAP HANA - Addhosts - Pre-Tasks - Configure SELinux file contexts for {{ sap_hana_install_root_path }} + ansible.builtin.include_tasks: + file: pre_tasks/selinux.yml + loop: "{{ __sap_hana_install_fact_addhosts_hosts_new }}" + loop_control: + loop_var: target_host + when: sap_hana_install_modify_selinux_labels + + +# Validate and prepare software directory +# For an addhosts operation, we first use the hdblcm command for creating a new configfile template, which +# we then process with the templating engine. The actual addhosts installation is done via the resident hdblcm. +# Non-resident hdblcm is used to avoid issues when attempting to generate configfile with resident hdblcm. + +# 'sap_hana_install_software_extract_directory' is required for configfile creation. +- name: SAP HANA - Addhosts - Pre-Tasks - Get status of the directory '{{ sap_hana_install_software_extract_directory }}' + ansible.builtin.stat: + path: "{{ sap_hana_install_software_extract_directory }}" + check_mode: false + register: __sap_hana_install_register_stat_extract_directory + failed_when: false + +- name: SAP HANA - Addhosts - Pre-Tasks - Fail if '{{ sap_hana_install_software_extract_directory }}' does not exist + ansible.builtin.fail: + msg: | + FAIL: The directory {{ sap_hana_install_software_extract_directory }} does not exist. + Path must be defined in the variable 'sap_hana_install_software_extract_directory'. + when: not __sap_hana_install_register_stat_extract_directory.stat.exists + +- name: SAP HANA - Addhosts - Pre-Tasks - Find directory 'SAP_HANA_DATABASE' in '{{ sap_hana_install_software_extract_directory }}' + ansible.builtin.find: + paths: "{{ sap_hana_install_software_extract_directory }}" + recurse: true + file_type: directory + patterns: 'SAP_HANA_DATABASE' + register: __sap_hana_install_register_find_directory_sap_hana_database_addhosts + +- name: SAP HANA - Addhosts - Pre-Tasks - Fail if directory 'SAP_HANA_DATABASE' does not exist in '{{ sap_hana_install_software_extract_directory }}' + ansible.builtin.fail: + msg: | + FAIL: The directory {{ sap_hana_install_software_extract_directory }} does not contain directory 'SAP_HANA_DATABASE'. + when: __sap_hana_install_register_find_directory_sap_hana_database_addhosts.files | length == 0 + +- name: SAP HANA - Addhosts - Pre-Tasks - Set fact for 'hdblcm' installer directory, addhosts + ansible.builtin.set_fact: + __sap_hana_install_fact_hdblcm_path: "{{ __sap_hana_install_register_find_directory_sap_hana_database_addhosts.files[0].path }}" + + +# Create temporary directory and hdblcm configuration file. +- name: SAP HANA - Addhosts - Pre-Tasks - Create temporary directory to store various files + ansible.builtin.tempfile: + state: directory + suffix: hanaconfig + register: __sap_hana_install_register_tmpdir + tags: + - sap_hana_install_hdblcm_commandline + - sap_hana_install_check_installation + +- name: SAP HANA - Addhosts - Pre-Tasks - Fill variable __sap_hana_install_register_tmpdir for check mode only + ansible.builtin.set_fact: + __sap_hana_install_register_tmpdir: + path: '/tmp' + when: ansible_check_mode + +- name: SAP HANA - Addhosts - Pre-Tasks - Process the hdblcm configfile + ansible.builtin.include_tasks: + file: pre_tasks/hdblcm_configfile.yml diff --git a/roles/sap_hana_install/tasks/pre_install.yml b/roles/sap_hana_install/tasks/pre_install.yml index c8f37f535..937ac30dd 100644 --- a/roles/sap_hana_install/tasks/pre_install.yml +++ b/roles/sap_hana_install/tasks/pre_install.yml @@ -1,257 +1,164 @@ # SPDX-License-Identifier: Apache-2.0 --- -################ -# Password Facts -################ -# - name: SAP HANA Pre Install - Set password facts when using master password -# ansible.builtin.set_fact: -# sap_hana_install_sapadm_password: "{{ sap_hana_install_master_password }}" -# sap_hana_install_sidadm_password: "{{ sap_hana_install_master_password }}" -# sap_hana_install_db_system_password: "{{ sap_hana_install_master_password }}" -# sap_hana_install_ase_user_password: "{{ sap_hana_install_master_password }}" -# sap_hana_install_xs_org_password: "{{ sap_hana_install_master_password }}" -# sap_hana_install_lss_user_password: "{{ sap_hana_install_master_password }}" -# sap_hana_install_lss_backup_password: "{{ sap_hana_install_master_password }}" -# when: sap_hana_install_use_master_password == 'y' - -################ -# Handle fapolicyd -################ - -- name: SAP HANA Pre Install, fapolicyd - Ensure the presence of fapolicyd - ansible.builtin.package: - name: fapolicyd - state: present - when: - - sap_hana_install_use_fapolicyd - # Ensure fapolicyd is installed only on supported systems. - - ansible_os_family == 'RedHat' - tags: sap_hana_install_use_fapolicyd - -################ -# We must ensure fapolicyd is disabled before installing SAP HANA in all cases -# Otherwise, the installation of SAP HANA will fail -################ - -- name: SAP HANA Pre Install, fapolicyd - Block to disable fapolicyd +- name: SAP HANA - Install - Pre-Tasks - Install and disable fapolicyd + ansible.builtin.include_tasks: + file: pre_tasks/fapolicyd.yml + loop: "{{ __sap_hana_install_fact_all_hosts }}" + loop_control: + loop_var: target_host when: - - sap_hana_install_new_system # Don't disable for existing installations during addhosts. # Ensure fapolicyd is checked only on supported systems. - ansible_os_family == "RedHat" tags: sap_hana_install_use_fapolicyd - block: - - name: SAP HANA Pre Install, fapolicyd - Gather package facts - ansible.builtin.package_facts: - - - name: SAP HANA Pre Install, fapolicyd - Disable fapolicyd - ansible.builtin.service: - name: fapolicyd - enabled: false - state: stopped - when: - - '"fapolicyd" in ansible_facts.packages' - -################ -# Prepare software path -################ - -- name: Prepare the HANA software for installation, new system - when: sap_hana_install_new_system - block: - - name: SAP HANA Pre Install - Normalize directory path - ansible.builtin.set_fact: - __sap_hana_install_fact_software_directory: "{{ sap_hana_install_software_directory | regex_replace('\\/$', '') }}" - - name: SAP HANA Pre Install - Check availability of software directory '{{ __sap_hana_install_fact_software_directory }}' - ansible.builtin.stat: - path: "{{ __sap_hana_install_fact_software_directory }}" - check_mode: false - register: __sap_hana_install_register_stat_software_directory - failed_when: false +# Update HANA directory permissions +- name: SAP HANA - Install - Pre-Tasks - Change ownership of HANA directories + ansible.builtin.include_tasks: + file: pre_tasks/hana_directory_permissions.yml + loop: "{{ __sap_hana_install_fact_all_hosts }}" + loop_control: + loop_var: target_host + tags: sap_hana_install_chown_hana_directories - - name: SAP HANA Pre Install - Assert that the software directory exists - ansible.builtin.assert: - that: __sap_hana_install_register_stat_software_directory.stat.exists - fail_msg: "FAIL: The software directory '{{ __sap_hana_install_fact_software_directory }}' does not exist!" - success_msg: "PASS: The software directory '{{ __sap_hana_install_fact_software_directory }}' exist." - - name: > - SAP HANA Pre Install - Assert directory permissions in case `sap_hana_install_software_extract_directory` - is below `sap_hana_install_software_extract_directory` - when: sap_hana_install_software_extract_directory is search(sap_hana_install_software_directory) - block: +# Configure SElinux +- name: SAP HANA - Install - Pre-Tasks - Configure SELinux file contexts for {{ sap_hana_install_root_path }} + ansible.builtin.include_tasks: + file: pre_tasks/selinux.yml + loop: "{{ __sap_hana_install_fact_all_hosts }}" + loop_control: + loop_var: target_host + when: sap_hana_install_modify_selinux_labels - - name: SAP HANA Pre Install - Set fact for number of directory levels of the software directory - ansible.builtin.set_fact: - __sap_hana_install_fact_software_directory_levels: "{{ __sap_hana_install_fact_software_directory | regex_findall('/') | length }}" - - name: SAP HANA Pre Install - Assert directory permissions - ansible.builtin.include_tasks: ./pre_install-loop-block.yml - loop: "{{ range(1, __sap_hana_install_fact_software_directory_levels | int + 1, 1) | list }}" - loop_control: - loop_var: line_item +# Validate and prepare software directory +- name: SAP HANA - Install - Pre-Tasks - Normalize directory path + ansible.builtin.set_fact: + __sap_hana_install_fact_software_directory: "{{ sap_hana_install_software_directory | regex_replace('\\/$', '') }}" + +- name: SAP HANA - Install - Pre-Tasks - Check availability of software directory '{{ __sap_hana_install_fact_software_directory }}' + ansible.builtin.stat: + path: "{{ __sap_hana_install_fact_software_directory }}" + check_mode: false + register: __sap_hana_install_register_stat_software_directory + failed_when: false + +- name: SAP HANA - Install - Pre-Tasks - Assert that the software directory exists + ansible.builtin.assert: + that: __sap_hana_install_register_stat_software_directory.stat.exists + fail_msg: "FAIL: The software directory '{{ __sap_hana_install_fact_software_directory }}' does not exist!" + success_msg: "PASS: The software directory '{{ __sap_hana_install_fact_software_directory }}' exist." + +- name: > + SAP HANA - Install - Pre-Tasks - Assert directory permissions in case `sap_hana_install_software_extract_directory` + is below `sap_hana_install_software_extract_directory` + when: sap_hana_install_software_extract_directory is search(sap_hana_install_software_directory) + block: - - name: SAP HANA Pre Install - Change ownership of HANA directories - ansible.builtin.file: - path: "{{ item }}" - state: directory - mode: '0755' - owner: root - group: root - loop: - - '{{ sap_hana_install_root_path }}' - - '{{ sap_hana_install_shared_path }}' - - '{{ sap_hana_install_root_path }}/log' - - '{{ sap_hana_install_root_path }}/data' - tags: sap_hana_install_chown_hana_directories + - name: SAP HANA - Install - Pre-Tasks - Set fact for number of directory levels of the software directory + ansible.builtin.set_fact: + __sap_hana_install_fact_software_directory_levels: "{{ __sap_hana_install_fact_software_directory | regex_findall('/') | length }}" + + - name: SAP HANA - Install - Pre-Tasks - Assert directory permissions + ansible.builtin.include_tasks: + file: pre_tasks/software_directory_permissions.yml + loop: "{{ range(1, __sap_hana_install_fact_software_directory_levels | int + 1, 1) | list }}" + loop_control: + loop_var: line_item + +- name: SAP HANA - Install - Pre-Tasks - Get info about software extract directory '{{ sap_hana_install_software_extract_directory }}' + ansible.builtin.stat: + path: "{{ sap_hana_install_software_extract_directory }}" + check_mode: false + register: __sap_hana_install_register_stat_software_extract_directory + failed_when: false + +- name: SAP HANA - Install - Pre-Tasks - Change ownership of software extract directory '{{ sap_hana_install_software_extract_directory }}' + ansible.builtin.file: + path: "{{ sap_hana_install_software_extract_directory }}" + state: directory + recurse: true + mode: '0755' + owner: root + group: root + when: __sap_hana_install_register_stat_software_extract_directory.stat.exists + +# In case more than one installation is ongoing and extracting to the same shared directory, wait until the extraction has completed: +- name: SAP HANA - Install - Pre-Tasks - Suspending if extraction status file '{{ sap_hana_install_software_extract_directory }}/__EXTRACTION_ONGOING__' exists + ansible.builtin.wait_for: + path: "{{ sap_hana_install_software_extract_directory }}/__EXTRACTION_ONGOING__" + state: absent + failed_when: false + +- name: SAP HANA - Install - Pre-Tasks - Find directory 'SAP_HANA_DATABASE' if '{{ sap_hana_install_software_extract_directory }}' exists + ansible.builtin.find: + paths: "{{ sap_hana_install_software_extract_directory }}" + recurse: true + file_type: directory + patterns: 'SAP_HANA_DATABASE' + register: __sap_hana_install_register_find_directory_sap_hana_database_initial + when: __sap_hana_install_register_stat_software_extract_directory.stat.exists + +# All SAPCAR and SAR files pre_tasks steps will be skipped if role `sap_install_media_detect` successfully extracts software. +- name: SAP HANA - Install - Pre-Tasks - Set directory of 'hdblcm' from successful find result + when: + - __sap_hana_install_register_stat_software_extract_directory.stat.exists + - __sap_hana_install_register_find_directory_sap_hana_database_initial.files[0] is defined + block: - - name: SAP HANA Pre Install - Configure 'sap_hana_install_root_path' SELinux file contexts - ansible.builtin.include_role: - name: '{{ sap_hana_install_system_roles_collection }}.selinux' - vars: - selinux_booleans: - - { name: 'selinuxuser_execmod', state: 'on' } - selinux_fcontexts: - - { target: '{{ sap_hana_install_root_path }}(/.*)?', setype: 'usr_t' } - selinux_restore_dirs: - - '{{ sap_hana_install_root_path }}' - when: sap_hana_install_modify_selinux_labels + - name: SAP HANA - Install - Pre-Tasks - Set fact for 'hdblcm' installer directory if found initially + ansible.builtin.set_fact: + __sap_hana_install_fact_hdblcm_path: "{{ __sap_hana_install_register_find_directory_sap_hana_database_initial.files[0].path }}" - - name: SAP HANA Pre Install - Get info about software extract directory '{{ sap_hana_install_software_extract_directory }}' + - name: SAP HANA - Install - Pre-Tasks - Get info about '{{ __sap_hana_install_fact_hdblcm_path }}/hdblcm' if found initially ansible.builtin.stat: - path: "{{ sap_hana_install_software_extract_directory }}" + path: "{{ __sap_hana_install_fact_hdblcm_path + '/hdblcm' }}" check_mode: false - register: __sap_hana_install_register_stat_software_extract_directory - failed_when: false - - - name: SAP HANA Pre Install - Change ownership of software extract directory '{{ sap_hana_install_software_extract_directory }}' - ansible.builtin.file: - path: "{{ sap_hana_install_software_extract_directory }}" - state: directory - recurse: true - mode: '0755' - owner: root - group: root - when: __sap_hana_install_register_stat_software_extract_directory.stat.exists - - # In case more than one installation is ongoing and extracting to the same shared directory, wait until the extraction has completed: - - name: SAP HANA Pre Install - Suspending if extraction status file '{{ sap_hana_install_software_extract_directory }}/__EXTRACTION_ONGOING__' exists - ansible.builtin.wait_for: - path: "{{ sap_hana_install_software_extract_directory }}/__EXTRACTION_ONGOING__" - state: absent + register: __sap_hana_install_register_stat_hdblcm_initial failed_when: false - - name: SAP HANA Pre Install - Find directory 'SAP_HANA_DATABASE' if '{{ sap_hana_install_software_extract_directory }}' exists - ansible.builtin.find: - paths: "{{ sap_hana_install_software_extract_directory }}" - recurse: true - file_type: directory - patterns: 'SAP_HANA_DATABASE' - register: __sap_hana_install_register_find_directory_sap_hana_database_initial - when: __sap_hana_install_register_stat_software_extract_directory.stat.exists - - # All SAPCAR and SAR files pre_install steps will be skipped if role `sap_install_media_detect` successfully extracts software. - - name: SAP HANA Pre Install - Set directory of 'hdblcm' from successful find result - when: - - __sap_hana_install_register_stat_software_extract_directory.stat.exists - - __sap_hana_install_register_find_directory_sap_hana_database_initial.files[0] is defined - block: - - - name: SAP HANA Pre Install - Set fact for 'hdblcm' installer directory if found initially - ansible.builtin.set_fact: - __sap_hana_install_fact_hdblcm_path: "{{ __sap_hana_install_register_find_directory_sap_hana_database_initial.files[0].path }}" - - - name: SAP HANA Pre Install - Get info about '{{ __sap_hana_install_fact_hdblcm_path }}/hdblcm' if found initially - ansible.builtin.stat: - path: "{{ __sap_hana_install_fact_hdblcm_path + '/hdblcm' }}" - check_mode: false - register: __sap_hana_install_register_stat_hdblcm_initial - failed_when: false - - - name: SAP HANA Pre Install - Assert that file 'hdblcm' is available if found initially - ansible.builtin.assert: - that: __sap_hana_install_register_stat_hdblcm_initial.stat.exists - fail_msg: "FAIL: File '{{ __sap_hana_install_fact_hdblcm_path + '/hdblcm' }}' could not be found. Installation of SAP HANA is not possible." - success_msg: "Using '{{ __sap_hana_install_fact_hdblcm_path + '/hdblcm' }}' for the installation of SAP HANA." - - - name: SAP HANA Pre Install - Extract SAR files if file 'hdblcm' was not found initially - when: __sap_hana_install_register_find_directory_sap_hana_database_initial.files[0] is not defined - block: - - - name: SAP HANA Pre Install - Run hdblcm prepare - ansible.builtin.include_tasks: pre_install/hdblcm_prepare.yml - - - name: SAP HANA Pre Install - Display 'hdblcm' installer directory - ansible.builtin.debug: - var: __sap_hana_install_fact_hdblcm_path - - - name: SAP HANA Pre Install - Set __sap_hana_install_fact_hdblcm_path in case of check mode - ansible.builtin.set_fact: - __sap_hana_install_fact_hdblcm_path: '/software/hana/extracted' - when: ansible_check_mode + - name: SAP HANA - Install - Pre-Tasks - Assert that file 'hdblcm' is available if found initially + ansible.builtin.assert: + that: __sap_hana_install_register_stat_hdblcm_initial.stat.exists + fail_msg: "FAIL: File '{{ __sap_hana_install_fact_hdblcm_path + '/hdblcm' }}' could not be found. Installation of SAP HANA is not possible." + success_msg: "Using '{{ __sap_hana_install_fact_hdblcm_path + '/hdblcm' }}' for the installation of SAP HANA." - - name: SAP HANA Pre Install - Get info about '{{ __sap_hana_install_fact_hdblcm_path }}/hdblcm' - ansible.builtin.stat: - path: "{{ __sap_hana_install_fact_hdblcm_path + '/hdblcm' }}" - check_mode: false - register: __sap_hana_install_register_stat_hdblcm - failed_when: false +- name: SAP HANA - Install - Pre-Tasks - Extract SAR files if file 'hdblcm' was not found initially + when: __sap_hana_install_register_find_directory_sap_hana_database_initial.files[0] is not defined + block: - - name: SAP HANA Pre Install - Assert that file 'hdblcm' is available - ansible.builtin.assert: - that: __sap_hana_install_register_stat_hdblcm.stat.exists - fail_msg: "FAIL: File 'hdblcm' could not be found. Installation of SAP HANA is not possible." - success_msg: "Using file '{{ __sap_hana_install_fact_hdblcm_path + '/hdblcm' }}' for the installation of SAP HANA." - when: not ansible_check_mode + - name: SAP HANA - Install - Pre-Tasks - Run hdblcm prepare + ansible.builtin.include_tasks: pre_tasks/hdblcm_prepare.yml + - name: SAP HANA - Install - Pre-Tasks - Display 'hdblcm' installer directory + ansible.builtin.debug: + msg: "{{ __sap_hana_install_fact_hdblcm_path }}" + when: __sap_hana_install_fact_hdblcm_path is defined -# For an addhosts operation, we first use the hdblcm command for creating a new configfile template, which -# we then process with the templating engine. The actual addhosts installation is done via the resident hdblcm. -# Non-resident hdblcm is used to avoid issues when attempting to generate configfile with resident hdblcm. -- name: Set the path to hdblcm, addhosts - when: not sap_hana_install_new_system - block: + - name: SAP HANA - Install - Pre-Tasks - Set __sap_hana_install_fact_hdblcm_path in case of check mode + ansible.builtin.set_fact: + __sap_hana_install_fact_hdblcm_path: '/software/hana/extracted' + when: ansible_check_mode - # 'sap_hana_install_software_extract_directory' is required for configfile creation. - - name: SAP HANA Pre Install - Addhosts - Get status of the directory '{{ sap_hana_install_software_extract_directory }}' + - name: SAP HANA - Install - Pre-Tasks - Get info about '{{ __sap_hana_install_fact_hdblcm_path }}/hdblcm' ansible.builtin.stat: - path: "{{ sap_hana_install_software_extract_directory }}" + path: "{{ __sap_hana_install_fact_hdblcm_path + '/hdblcm' }}" check_mode: false - register: __sap_hana_install_register_stat_extract_directory + register: __sap_hana_install_register_stat_hdblcm failed_when: false - - name: SAP HANA Pre Install - Addhosts - Fail if '{{ sap_hana_install_software_extract_directory }}' does not exist - ansible.builtin.fail: - msg: | - FAIL: The directory {{ sap_hana_install_software_extract_directory }} does not exist. - Path must be defined in the variable 'sap_hana_install_software_extract_directory'. - when: not __sap_hana_install_register_stat_extract_directory.stat.exists - - - name: SAP HANA Pre Install - Addhosts - Find directory 'SAP_HANA_DATABASE' in '{{ sap_hana_install_software_extract_directory }}' - ansible.builtin.find: - paths: "{{ sap_hana_install_software_extract_directory }}" - recurse: true - file_type: directory - patterns: 'SAP_HANA_DATABASE' - register: __sap_hana_install_register_find_directory_sap_hana_database_addhosts - - - name: SAP HANA Pre Install - Addhosts - Fail if directory 'SAP_HANA_DATABASE' does not exist in '{{ sap_hana_install_software_extract_directory }}' - ansible.builtin.fail: - msg: | - FAIL: The directory {{ sap_hana_install_software_extract_directory }} does not contain directory 'SAP_HANA_DATABASE'. - when: __sap_hana_install_register_find_directory_sap_hana_database_addhosts.files | length == 0 - - - name: SAP HANA Pre Install - Addhosts - Set fact for 'hdblcm' installer directory, addhosts - ansible.builtin.set_fact: - __sap_hana_install_fact_hdblcm_path: "{{ __sap_hana_install_register_find_directory_sap_hana_database_addhosts.files[0].path }}" + - name: SAP HANA - Install - Pre-Tasks - Assert that file 'hdblcm' is available + ansible.builtin.assert: + that: __sap_hana_install_register_stat_hdblcm.stat.exists + fail_msg: "FAIL: File 'hdblcm' could not be found. Installation of SAP HANA is not possible." + success_msg: "Using file '{{ __sap_hana_install_fact_hdblcm_path + '/hdblcm' }}' for the installation of SAP HANA." + when: not ansible_check_mode -################ -# Pre Install Steps -################ -- name: SAP HANA Pre Install - Create temporary directory to store various files +# Create temporary directory and hdblcm configuration file. +- name: SAP HANA - Install - Pre-Tasks - Create temporary directory to store various files ansible.builtin.tempfile: state: directory suffix: hanaconfig @@ -260,11 +167,12 @@ - sap_hana_install_hdblcm_commandline - sap_hana_install_check_installation -- name: SAP HANA Pre Install - Fill variable __sap_hana_install_register_tmpdir for check mode only +- name: SAP HANA - Install - Pre-Tasks - Fill variable __sap_hana_install_register_tmpdir for check mode only ansible.builtin.set_fact: __sap_hana_install_register_tmpdir: path: '/tmp' when: ansible_check_mode -- name: SAP HANA Pre Install - Process the hdblcm configfile - ansible.builtin.include_tasks: pre_install/hdblcm_configfile.yml +- name: SAP HANA - Install - Pre-Tasks - Process the hdblcm configfile + ansible.builtin.include_tasks: + file: pre_tasks/hdblcm_configfile.yml diff --git a/roles/sap_hana_install/tasks/assert_variables.yml b/roles/sap_hana_install/tasks/pre_tasks/assert_variables.yml similarity index 85% rename from roles/sap_hana_install/tasks/assert_variables.yml rename to roles/sap_hana_install/tasks/pre_tasks/assert_variables.yml index c5b9b1f44..b31e3af55 100644 --- a/roles/sap_hana_install/tasks/assert_variables.yml +++ b/roles/sap_hana_install/tasks/pre_tasks/assert_variables.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 --- -- name: Assert that the variable 'sap_hana_install_sid' is defined as String consisting of 3 characters +- name: SAP HANA - Pre-Tasks - Assert that the variable 'sap_hana_install_sid' is defined as String consisting of 3 characters ansible.builtin.assert: that: - sap_hana_install_sid is defined @@ -18,7 +18,7 @@ FAIL: The length of SAP HANA System ID '{{ sap_hana_install_sid }}' is not 3 characters! {% endif %} -- name: Assert that the variable 'sap_hana_install_sid' is not in the list of reserved SAP SIDs +- name: SAP HANA - Pre-Tasks - Assert that the variable 'sap_hana_install_sid' is not in the list of reserved SAP SIDs ansible.builtin.assert: that: sap_hana_install_sid not in __sap_hana_install_sid_prohibited success_msg: | @@ -44,7 +44,7 @@ FAIL: The SAP HANA Instance Number '{{ sap_hana_install_number }}' is not 2 digits! {% endif %} -- name: Assert that the variable 'sap_hana_install_master_password' is defined as String and not empty +- name: SAP HANA - Pre-Tasks - Assert that the variable 'sap_hana_install_master_password' is defined as String and not empty ansible.builtin.assert: that: - sap_hana_install_master_password is defined @@ -62,7 +62,7 @@ {% endif %} -- name: Assert that the variable 'sap_hana_install_addhosts' is defined as String and not empty +- name: SAP HANA - Pre-Tasks - Assert that the variable 'sap_hana_install_addhosts' is defined as String and not empty ansible.builtin.assert: that: - sap_hana_install_addhosts is defined @@ -78,5 +78,6 @@ {% else %} FAIL: The variable 'sap_hana_install_addhosts' is empty. {% endif %} + This variable is required when 'sap_hana_install_new_system' is set to false. when: - not sap_hana_install_new_system diff --git a/roles/sap_hana_install/tasks/pre_tasks/check_addhosts.yml b/roles/sap_hana_install/tasks/pre_tasks/check_addhosts.yml new file mode 100644 index 000000000..88d617048 --- /dev/null +++ b/roles/sap_hana_install/tasks/pre_tasks/check_addhosts.yml @@ -0,0 +1,87 @@ +# SPDX-License-Identifier: Apache-2.0 +--- + +### Addhosts variables: +# __sap_hana_install_fact_addhosts_hosts +# - The list of all valid hostnames in addhosts string. +# - Used only for setting '__sap_hana_install_fact_addhosts_hosts_new' and '__sap_hana_install_fact_all_hosts'. + +# __sap_hana_install_fact_addhosts_hosts_new +# - The list of all valid hostnames in addhosts string without host with existing profiles or directories. +# - Used for replacing addhosts string in hdblcm configfile. + +# __sap_hana_install_fact_all_hosts +# - The list of all valid hostnames in addhosts string including Managed node. +# - Used for running all configuration tasks for idempotency. + +- name: SAP HANA - Addhosts - Pre-Tasks - Set fact with list of additional hostnames + ansible.builtin.set_fact: + __sap_hana_install_fact_addhosts_hosts: + "{{ sap_hana_install_addhosts.split(',') | map('trim') | reject('equalto', '') | map('regex_replace', ':.*$', '') | list }}" + __sap_hana_install_fact_addhosts_hosts_new: [] + +- name: SAP HANA - Addhosts - Pre-Tasks - Assert that the variable 'sap_hana_install_addhosts' is valid addhosts string + ansible.builtin.assert: + that: + - __sap_hana_install_fact_addhosts_hosts | length > 0 + success_msg: | + PASS: The variable 'sap_hana_install_addhosts' contains valid addhosts string. + Additional hosts: {{ __sap_hana_install_fact_addhosts_hosts | join(', ') }} + fail_msg: | + FAIL: The variable 'sap_hana_install_addhosts' is not valid addhosts string. + Examples: + sap_hana_install_addhosts: "hanaworker1,hanaworker2" + sap_hana_install_addhosts: "hanaworker1:role=worker,hanaworker2:role=worker" + + +# Check for existing addhosts profiles and folders before removing them from list. +- name: SAP HANA - Addhosts - Pre-Tasks - Find existing instance profiles for all hosts + ansible.builtin.find: + paths: "{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}/profile/" + patterns: "{{ sap_hana_install_sid }}_HDB{{ sap_hana_install_number }}_*" + file_type: file + register: __sap_hana_install_register_existing_profiles + +- name: SAP HANA - Addhosts - Pre-Tasks - Set fact with list of existing hosts with instance profiles + ansible.builtin.set_fact: + __sap_hana_install_fact_existing_hosts_profile: + "{{ __sap_hana_install_register_existing_profiles.files | map(attribute='path') | map('basename') + | map('regex_replace', '^' + sap_hana_install_sid + '_HDB' + sap_hana_install_number + '_', '') | list }}" + +- name: SAP HANA - Addhosts - Pre-Tasks - Find existing instance directories for all hosts + ansible.builtin.find: + paths: "/usr/sap/{{ sap_hana_install_sid }}/HDB{{ sap_hana_install_number }}/" + patterns: "*" + file_type: directory + register: __sap_hana_install_register_existing_dirs + +- name: SAP HANA - Addhosts - Pre-Tasks - Set fact with list of existing hosts with instance directories + ansible.builtin.set_fact: + __sap_hana_install_fact_existing_hosts_dirs: + "{{ __sap_hana_install_register_existing_dirs.files | map(attribute='path') | map('basename') | list }}" + +- name: SAP HANA - Addhosts - Pre-Tasks - Set fact with list of new hosts without existing profiles or directories + ansible.builtin.set_fact: + __sap_hana_install_fact_addhosts_hosts_new: >- + {{ + __sap_hana_install_fact_addhosts_hosts | + difference( + __sap_hana_install_fact_existing_hosts_profile | union(__sap_hana_install_fact_existing_hosts_dirs) + ) + }} + +- name: SAP HANA - Addhosts - Pre-Tasks - Show lists of hosts to be added + ansible.builtin.debug: + msg: "New hosts will be added: {{ __sap_hana_install_fact_addhosts_hosts_new | join(', ') }}" + when: __sap_hana_install_fact_addhosts_hosts_new | length > 0 + + +# Test SSH connection from managed node to addhosts hosts is not implemented because +# all configuration tasks must come from Control node, not pass through Managed node to addhosts. +- name: SAP HANA - Addhosts - Pre-Tasks - Verify SSH connectivity from control node to each additional host + ansible.builtin.wait_for_connection: + timeout: 30 + loop: "{{ __sap_hana_install_fact_addhosts_hosts_new }}" + delegate_to: "{{ item }}" + run_once: true + when: __sap_hana_install_fact_addhosts_hosts_new | length > 0 diff --git a/roles/sap_hana_install/tasks/pre_tasks/create_users_groups.yml b/roles/sap_hana_install/tasks/pre_tasks/create_users_groups.yml new file mode 100644 index 000000000..16098d716 --- /dev/null +++ b/roles/sap_hana_install/tasks/pre_tasks/create_users_groups.yml @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: Apache-2.0 +--- + +# This task is required only for addhosts operation, because it requires +# user 'sapadm' to be present on addhosts with correct password. +# Addhosts operation does not use root SSH, but sapadm SSH instead. + +- name: SAP HANA - Addhosts - Pre-Tasks - Create 'sapsys' group on new host + ansible.builtin.group: + name: sapsys + gid: "{{ getent_group['sapsys'][1] }}" + state: present + delegate_to: "{{ target_host }}" + become: true + +# User 'sidadm' is not required for addhosts, only sapadm user. +- name: SAP HANA - Addhosts - Pre-Tasks - Create 'sapadm' user on new host + ansible.builtin.user: + name: sapadm + uid: "{{ getent_passwd['sapadm'][1] }}" + home: "{{ getent_passwd['sapadm'][4] }}" + shell: "{{ getent_passwd['sapadm'][5] }}" + groups: sapsys + append: true + state: present + password: "{{ __sap_hana_install_register_sapadm_password_hash.stdout }}" + delegate_to: "{{ target_host }}" + become: true diff --git a/roles/sap_hana_install/tasks/pre_install/extract_sarfile.yml b/roles/sap_hana_install/tasks/pre_tasks/extract_sarfile.yml similarity index 70% rename from roles/sap_hana_install/tasks/pre_install/extract_sarfile.yml rename to roles/sap_hana_install/tasks/pre_tasks/extract_sarfile.yml index 041fc08dd..137726b29 100644 --- a/roles/sap_hana_install/tasks/pre_install/extract_sarfile.yml +++ b/roles/sap_hana_install/tasks/pre_tasks/extract_sarfile.yml @@ -1,17 +1,17 @@ # SPDX-License-Identifier: Apache-2.0 --- -- name: SAP HANA hdblcm prepare - Set fact for temporary extraction directory, default +- name: SAP HANA - Pre-Tasks - Set fact for temporary extraction directory, default ansible.builtin.set_fact: __sap_hana_install_tmp_software_extract_directory: "{{ sap_hana_install_software_extract_directory }}/tmp" when: "'SAPHOST' not in __sap_hana_install_passed_sarfile" -- name: SAP HANA hdblcm prepare - Set fact for temporary extraction directory, SAP Host Agent +- name: SAP HANA - Pre-Tasks - Set fact for temporary extraction directory, SAP Host Agent ansible.builtin.set_fact: __sap_hana_install_tmp_software_extract_directory: "{{ sap_hana_install_software_extract_directory }}/tmp/SAP_HOST_AGENT" when: "'SAPHOST' in __sap_hana_install_passed_sarfile" -- name: SAP HANA hdblcm prepare - Create temporary extraction directory '{{ __sap_hana_install_tmp_software_extract_directory }}' +- name: SAP HANA - Pre-Tasks - Create temporary extraction directory '{{ __sap_hana_install_tmp_software_extract_directory }}' ansible.builtin.file: path: "{{ __sap_hana_install_tmp_software_extract_directory }}" state: directory @@ -19,7 +19,7 @@ owner: root group: root -- name: SAP HANA hdblcm prepare - Extract file '{{ __sap_hana_install_fact_sar_dir }}/{{ __sap_hana_install_passed_sarfile }}' +- name: SAP HANA - Pre-Tasks - Extract file '{{ __sap_hana_install_fact_sar_dir }}/{{ __sap_hana_install_passed_sarfile }}' ansible.builtin.command: >- {{ sap_hana_install_software_extract_directory }}/sapcar/{{ __sap_hana_install_fact_selected_sapcar_filename }} \ -R {{ __sap_hana_install_tmp_software_extract_directory }} \ @@ -30,7 +30,7 @@ chdir: "{{ sap_hana_install_software_extract_directory }}" changed_when: "'SAPCAR: processing archive' in __sap_hana_install_register_extract.stdout" -- name: SAP HANA hdblcm prepare - Move files into the correct place, default +- name: SAP HANA - Pre-Tasks - Move files into the correct place, default ansible.builtin.shell: | extracted_dir=$(ls -d */) mv SIGNATURE.SMF ${extracted_dir} @@ -40,14 +40,14 @@ changed_when: true when: "'SAPHOST' not in __sap_hana_install_passed_sarfile" -- name: SAP HANA hdblcm prepare - Move files into the correct place, SAP Host Agent +- name: SAP HANA - Pre-Tasks - Move files into the correct place, SAP Host Agent ansible.builtin.command: mv ./tmp/SAP_HOST_AGENT . args: chdir: "{{ sap_hana_install_software_extract_directory }}" changed_when: true when: "'SAPHOST' in __sap_hana_install_passed_sarfile" -- name: SAP HANA hdblcm prepare - Remove temporary extraction directory '{{ sap_hana_install_software_extract_directory }}/tmp' +- name: SAP HANA - Pre-Tasks - Remove temporary extraction directory '{{ sap_hana_install_software_extract_directory }}/tmp' ansible.builtin.file: path: "{{ sap_hana_install_software_extract_directory }}/tmp/" state: absent diff --git a/roles/sap_hana_install/tasks/pre_tasks/fapolicyd.yml b/roles/sap_hana_install/tasks/pre_tasks/fapolicyd.yml new file mode 100644 index 000000000..45d0ab931 --- /dev/null +++ b/roles/sap_hana_install/tasks/pre_tasks/fapolicyd.yml @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: Apache-2.0 +--- + +- name: SAP HANA - Pre-Tasks - Ensure the presence of fapolicyd + ansible.builtin.package: + name: fapolicyd + state: present + delegate_to: "{{ target_host }}" + when: sap_hana_install_use_fapolicyd + +# We must ensure fapolicyd is disabled before installing SAP HANA in all cases. +# Otherwise, the installation of SAP HANA will fail. + +- name: SAP HANA - Pre-Tasks - Disable fapolicyd if it exists + ansible.builtin.shell: # noqa command-instead-of-module + # This command only runs the second part if the first part succeeds + cmd: "rpm -q fapolicyd && systemctl disable --now fapolicyd" + delegate_to: "{{ target_host }}" + register: __sap_hana_install_register_disable_fapolicy + changed_when: >- + "Removed" in __sap_hana_install_register_disable_fapolicy.stderr or + "Stopping" in __sap_hana_install_register_disable_fapolicy.stdout + failed_when: >- + __sap_hana_install_register_disable_fapolicy.rc != 0 and + "package fapolicyd is not installed" not in __sap_hana_install_register_disable_fapolicy.stderr diff --git a/roles/sap_hana_install/tasks/pre_tasks/hana_directory_permissions.yml b/roles/sap_hana_install/tasks/pre_tasks/hana_directory_permissions.yml new file mode 100644 index 000000000..599705b6b --- /dev/null +++ b/roles/sap_hana_install/tasks/pre_tasks/hana_directory_permissions.yml @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: Apache-2.0 +--- + +- name: SAP HANA - Pre-Tasks - Change ownership of HANA directories + ansible.builtin.file: + path: "{{ item }}" + state: directory + mode: '0755' + owner: root + group: root + loop: + - '{{ sap_hana_install_root_path }}' + - '{{ sap_hana_install_shared_path }}' + - '{{ sap_hana_install_root_path }}/log' + - '{{ sap_hana_install_root_path }}/data' + delegate_to: "{{ target_host }}" diff --git a/roles/sap_hana_install/tasks/hana_exists.yml b/roles/sap_hana_install/tasks/pre_tasks/hana_exists.yml similarity index 66% rename from roles/sap_hana_install/tasks/hana_exists.yml rename to roles/sap_hana_install/tasks/pre_tasks/hana_exists.yml index 787859538..493bddf00 100644 --- a/roles/sap_hana_install/tasks/hana_exists.yml +++ b/roles/sap_hana_install/tasks/pre_tasks/hana_exists.yml @@ -2,12 +2,12 @@ --- # Required to reset status if the role is used multiple times in one playbook. -- name: SAP HANA Checks - Reset the status variable if defined from previous run +- name: SAP HANA - Pre-Tasks - Reset the status variable if defined from previous run ansible.builtin.set_fact: __sap_hana_install_fact_is_installed: false when: __sap_hana_install_fact_is_installed is defined -- name: SAP HANA Checks - Check if saphostctrl is installed +- name: SAP HANA - Pre-Tasks - Check if saphostctrl is installed ansible.builtin.stat: path: /usr/sap/hostctrl/exe/saphostctrl check_mode: false @@ -17,22 +17,23 @@ # Check 1: Use found sapcontrol to get list of SAP instances. # Only valid combination of SID and Instance Number will pass. -- name: SAP HANA Checks - Check if SAP instances are installed with saphostctrl +- name: SAP HANA - Pre-Tasks - Check if SAP instances are installed with saphostctrl when: __sap_hana_install_register_stat_saphostctrl.stat.exists block: - - name: SAP HANA Checks - Get list of installed SAP instances + - name: SAP HANA - Pre-Tasks - Get list of installed SAP instances ansible.builtin.shell: cmd: set -o pipefail && /usr/sap/hostctrl/exe/saphostctrl -function ListInstances | cut -d":" -f2- register: __sap_hana_install_register_instancelist changed_when: false - - name: SAP HANA Checks - Display instances + - name: SAP HANA - Pre-Tasks - Display instances ansible.builtin.debug: - var: __sap_hana_install_register_instancelist.stdout_lines + msg: "{{ __sap_hana_install_register_instancelist.stdout_lines }}" verbosity: 1 + when: __sap_hana_install_register_instancelist.stdout_lines is defined - - name: SAP HANA Checks - Desired SAP HANA is installed and running + - name: SAP HANA - Pre-Tasks - Desired SAP HANA is installed and running ansible.builtin.set_fact: __sap_hana_install_fact_is_installed: true when: @@ -43,7 +44,7 @@ loop_var: __sap_hana_install_loop_instance label: "{{ __sap_hana_install_loop_instance.split('-')[0] | trim }}" - - name: SAP HANA Checks - Fail if existing SAP HANA was detected with same instance number but different SID + - name: SAP HANA - Pre-Tasks - Fail if existing SAP HANA was detected with same instance number but different SID ansible.builtin.fail: msg: >- The instance number {{ sap_hana_install_number }} is already used by @@ -56,7 +57,7 @@ loop_var: __sap_hana_install_loop_instance label: "{{ __sap_hana_install_loop_instance.split('-')[0] | trim }}" - - name: SAP HANA Checks - Fail if existing SAP HANA was detected with same SID but different instance number + - name: SAP HANA - Pre-Tasks - Fail if existing SAP HANA was detected with same SID but different instance number ansible.builtin.fail: msg: >- The SAP HANA system {{ sap_hana_install_sid }} already exists with different instance number @@ -72,18 +73,18 @@ # Check 2: Check presence of directories if saphostctrl was not found. # These checks do not set '__sap_hana_install_fact_is_installed' as they pass only if directories are empty. -- name: SAP HANA Checks - Check directories if no saphostctrl is found +- name: SAP HANA - Pre-Tasks - Check directories if no saphostctrl is found when: not __sap_hana_install_register_stat_saphostctrl.stat.exists block: - - name: SAP HANA Checks - Get status of '{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}' + - name: SAP HANA - Pre-Tasks - Get status of '{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}' ansible.builtin.stat: path: "{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}" check_mode: false register: __sap_hana_install_register_stat_hana_shared_sid_assert failed_when: false - - name: SAP HANA Checks - Get contents of '{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}' + - name: SAP HANA - Pre-Tasks - Get contents of '{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}' ansible.builtin.find: paths: "{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}" patterns: '*' @@ -91,21 +92,21 @@ register: __sap_hana_install_register_files_in_hana_shared_sid_assert when: __sap_hana_install_register_stat_hana_shared_sid_assert.stat.exists - - name: SAP HANA Checks - Fail if the directory '{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}' exists and is not empty + - name: SAP HANA - Pre-Tasks - Fail if the directory '{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}' exists and is not empty ansible.builtin.fail: msg: "FAIL: The directory '{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}' exists and is not empty!" when: - __sap_hana_install_register_stat_hana_shared_sid_assert.stat.exists - __sap_hana_install_register_files_in_hana_shared_sid_assert.matched | int != 0 - - name: SAP HANA Checks - Get status of '/usr/sap/{{ sap_hana_install_sid }}' + - name: SAP HANA - Pre-Tasks - Get status of '/usr/sap/{{ sap_hana_install_sid }}' ansible.builtin.stat: path: "/usr/sap/{{ sap_hana_install_sid }}" check_mode: false register: __sap_hana_install_register_stat_usr_sap_sid_assert failed_when: false - - name: SAP HANA Checks - Get contents of '/usr/sap/{{ sap_hana_install_sid }}' + - name: SAP HANA - Pre-Tasks - Get contents of '/usr/sap/{{ sap_hana_install_sid }}' ansible.builtin.find: paths: "/usr/sap/{{ sap_hana_install_sid }}" patterns: '*' @@ -113,7 +114,7 @@ register: __sap_hana_install_register_files_in_usr_sap_sid_assert when: __sap_hana_install_register_stat_usr_sap_sid_assert.stat.exists - - name: SAP HANA Checks - Fail if the directory '/usr/sap/{{ sap_hana_install_sid }}' exists and is not empty + - name: SAP HANA - Pre-Tasks - Fail if the directory '/usr/sap/{{ sap_hana_install_sid }}' exists and is not empty ansible.builtin.fail: msg: "FAIL: The directory '/usr/sap/{{ sap_hana_install_sid }}' exists and is not empty!" when: @@ -124,7 +125,7 @@ # Check 3: Check if the group 'sapsys' exists with correct ID. # The role supports specifying the SAP HANA group id in variable `sap_hana_install_groupid`, which is the id of the sapsys group. # The SAP HANA installation will fail if there is already a group named sapsys but with a different ID. Let's better fail before. -- name: SAP HANA Checks - Check SAP HANA admin group +- name: SAP HANA - Pre-Tasks - Check SAP HANA admin group when: - sap_hana_install_groupid is defined - sap_hana_install_groupid is string @@ -136,13 +137,13 @@ # [0] - 'X' if the password is set. # [1] - Group ID. # [2] - Group members. - - name: SAP HANA Checks - Get details of the 'sapsys' group + - name: SAP HANA - Pre-Tasks - Get details of the 'sapsys' group ansible.builtin.getent: database: group key: sapsys failed_when: false - - name: SAP HANA Checks - In case there is a group 'sapsys', assert that its group ID is identical to 'sap_hana_install_groupid' + - name: SAP HANA - Pre-Tasks - In case there is a group 'sapsys', assert that its group ID is identical to 'sap_hana_install_groupid' ansible.builtin.assert: that: - getent_group['sapsys'][1] | int == sap_hana_install_groupid | int @@ -157,7 +158,7 @@ # Check 4: Check if the user 'sidadm' exists. -- name: SAP HANA Checks - SAP HANA admin user check +- name: SAP HANA - Pre-Tasks - SAP HANA admin user check when: - sap_hana_install_check_sidadm_user | d(true) - not __sap_hana_install_fact_is_installed | d(false) @@ -165,13 +166,13 @@ __sap_hana_install_sidadm: "{{ sap_hana_install_sid | lower }}adm" block: - - name: SAP HANA Checks - Get info about user '{{ __sap_hana_install_sidadm }}' + - name: SAP HANA - Pre-Tasks - Get info about user '{{ __sap_hana_install_sidadm }}' ansible.builtin.getent: database: passwd key: "{{ __sap_hana_install_sidadm }}" failed_when: false - - name: SAP HANA Checks - Fail if the user '{{ __sap_hana_install_sidadm }}' exists + - name: SAP HANA - Pre-Tasks - Fail if the user '{{ __sap_hana_install_sidadm }}' exists ansible.builtin.fail: msg: "FAIL: The user '{{ __sap_hana_install_sidadm }}' already exists!" when: @@ -179,7 +180,7 @@ - __sap_hana_install_sidadm in getent_passwd -- name: SAP HANA Checks - Fail if SAP HANA is not found when addhosts is used +- name: SAP HANA - Pre-Tasks - Fail if SAP HANA is not found when addhosts is used ansible.builtin.fail: msg: | FAIL: The existing SAP HANA System was not detected when adding new hosts! @@ -187,3 +188,35 @@ when: - not sap_hana_install_new_system - not __sap_hana_install_fact_is_installed | d(false) + +- name: SAP HANA - Pre-Tasks - Run 'hdblcm --list_systems' for existing database + ansible.builtin.shell: | + set -o pipefail && ./hdblcm --list_systems | awk '/\/hana\/shared\/{{ sap_hana_install_sid }}/{a=1} + /version:/{if (a==1){ + gsub ("^\\s*version: ", "");printf ("%s;", $NF)} + } + /hosts?:/{if (a==1){ + gsub ("^\\s*hosts?: ", ""); gsub (", ", ","); print; a=0} + }' + args: + chdir: "{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}/hdblcm" + register: __sap_hana_install_register_existing_systems + changed_when: false + when: + - __sap_hana_install_fact_is_installed + - not ansible_check_mode + +- name: SAP HANA - Pre-Tasks - Display details of existing SAP HANA + ansible.builtin.debug: + msg: | + SAP HANA database is installed and running: + HANA Version - {{ __sap_hana_install_fact_hana_version }} + Hosts - {{ __sap_hana_install_fact_hana_hosts }} + SID - {{ sap_hana_install_sid }} + NR - {{ sap_hana_install_number }} + vars: + __sap_hana_install_fact_hana_version: "{{ __sap_hana_install_register_existing_systems.stdout.split(';')[0] }}" + __sap_hana_install_fact_hana_hosts: "{{ __sap_hana_install_register_existing_systems.stdout.split(';')[1] }}" + when: + - __sap_hana_install_fact_is_installed + - not ansible_check_mode diff --git a/roles/sap_hana_install/tasks/hana_start.yml b/roles/sap_hana_install/tasks/pre_tasks/hana_start.yml similarity index 84% rename from roles/sap_hana_install/tasks/hana_start.yml rename to roles/sap_hana_install/tasks/pre_tasks/hana_start.yml index 49c4d2a5a..4716f0dee 100644 --- a/roles/sap_hana_install/tasks/hana_start.yml +++ b/roles/sap_hana_install/tasks/pre_tasks/hana_start.yml @@ -1,12 +1,12 @@ # SPDX-License-Identifier: Apache-2.0 --- -- name: Ensure SAP HANA is running - Set path to sapcontrol +- name: SAP HANA - Pre-Tasks - Start HANA - Set path to sapcontrol ansible.builtin.set_fact: __sap_hana_install_sapcontrol_path: "/usr/sap/{{ sap_hana_install_sid | upper }}/HDB{{ sap_hana_install_number }}/exe/sapcontrol" -- name: Ensure SAP HANA is running - Check for sapcontrol executable +- name: SAP HANA - Pre-Tasks - Start HANA - Check for sapcontrol executable ansible.builtin.stat: path: "{{ __sap_hana_install_sapcontrol_path }}" register: __sap_hana_install_stat_sapcontrol @@ -15,7 +15,7 @@ when: __sap_hana_install_stat_sapcontrol.stat.exists block: - - name: Ensure SAP HANA is running - Start instance + - name: SAP HANA - Pre-Tasks - Start HANA - Start instance ansible.builtin.command: cmd: "{{ __sap_hana_install_sapcontrol_path }} -nr {{ sap_hana_install_number }} -function StartSystem" become: true @@ -23,7 +23,7 @@ register: __sap_hana_install_register_start_hana changed_when: "'StartSystem OK' in __sap_hana_install_register_start_hana.stdout" - - name: Ensure SAP HANA is running - Wait for instance to be fully started + - name: SAP HANA - Pre-Tasks - Start HANA - Wait for instance to be fully started ansible.builtin.command: cmd: "{{ __sap_hana_install_sapcontrol_path }} -nr {{ sap_hana_install_number }} -function GetProcessList" become: true diff --git a/roles/sap_hana_install/tasks/pre_install/hdblcm_configfile.yml b/roles/sap_hana_install/tasks/pre_tasks/hdblcm_configfile.yml similarity index 87% rename from roles/sap_hana_install/tasks/pre_install/hdblcm_configfile.yml rename to roles/sap_hana_install/tasks/pre_tasks/hdblcm_configfile.yml index 8dfba5261..9b736fed0 100644 --- a/roles/sap_hana_install/tasks/pre_install/hdblcm_configfile.yml +++ b/roles/sap_hana_install/tasks/pre_tasks/hdblcm_configfile.yml @@ -1,24 +1,24 @@ # SPDX-License-Identifier: Apache-2.0 --- -- name: SAP HANA Pre Install - Create the hdblcm configfile directory '{{ sap_hana_install_configfile_directory }}' if it does not exist +- name: SAP HANA - Pre-Tasks - Create the hdblcm configfile directory '{{ sap_hana_install_configfile_directory }}' if it does not exist ansible.builtin.file: path: "{{ sap_hana_install_configfile_directory }}" state: directory mode: '0755' -- name: SAP HANA Pre Install - Check if file '{{ sap_hana_install_configfile_directory }}/configfile.cfg' exists +- name: SAP HANA - Pre-Tasks - Check if file '{{ sap_hana_install_configfile_directory }}/configfile.cfg' exists ansible.builtin.stat: path: "{{ sap_hana_install_configfile_directory }}/configfile.cfg" check_mode: false register: __sap_hana_install_register_stat_hdblcm_configfile -- name: SAP HANA Pre Install - Notify about existing hdblcm configfile +- name: SAP HANA - Pre-Tasks - Notify about existing hdblcm configfile ansible.builtin.debug: msg: "INFO: Using existing static hdblcm configfile '{{ sap_hana_install_configfile_directory }}/configfile.cfg'." when: __sap_hana_install_register_stat_hdblcm_configfile.stat.exists -- name: SAP HANA Pre Install - Make the existing static hdblcm configfile available for the SAP HANA installation +- name: SAP HANA - Pre-Tasks - Make the existing static hdblcm configfile available for the SAP HANA installation ansible.builtin.copy: src: "{{ sap_hana_install_configfile_directory }}/configfile.cfg" dest: "{{ __sap_hana_install_register_tmpdir.path }}/configfile.cfg" @@ -32,13 +32,13 @@ when: not __sap_hana_install_register_stat_hdblcm_configfile.stat.exists block: - - name: SAP HANA Pre Install - Create the hdblcm configfile template '{{ sap_hana_install_configfile_directory }}/{{ sap_hana_install_configfile_template_prefix }}.cfg' + - name: SAP HANA - Pre-Tasks - Create the hdblcm configfile template '{{ sap_hana_install_configfile_directory }}/{{ sap_hana_install_configfile_template_prefix }}.cfg' ansible.builtin.command: cmd: "{{ __sap_hana_install_fact_hdblcm_path }}/hdblcm --dump_configfile_template={{ sap_hana_install_configfile_directory }}/{{ sap_hana_install_configfile_template_prefix }}.cfg" register: __sap_hana_install_register_hdblcm_output changed_when: false - - name: SAP HANA Pre Install - Display the output of the hdblcm command + - name: SAP HANA - Pre-Tasks - Display the output of the hdblcm command ansible.builtin.debug: msg: "Output of hdblcm command: {{ __sap_hana_install_register_hdblcm_output.stdout_lines }}" @@ -57,7 +57,7 @@ # will be used to override the corresponding hdblcm configfile parameter (e.g. "max_mem"). # 2) If a role variable for the hdblcm configfile is not set in the playbook or inventory, either the default value which is set # in the hdblcm configfile template will be used, or an empty string. - - name: SAP HANA Pre Install - Create a Jinja2 template from the hdblcm configfile template + - name: SAP HANA - Pre-Tasks - Create a Jinja2 template from the hdblcm configfile template ansible.builtin.shell: | set -o pipefail && awk 'BEGIN{FS="="; printf ("\{\{ ansible_managed | comment \}\}\n# File created on: \{\{ template_host \}\}\n# Template file: \{\{ template_path \}\}\n#\n")} @@ -66,24 +66,24 @@ register: __sap_hana_install_create_jinja2_template changed_when: false - - name: SAP HANA Pre Install - Display the location of the remote Jinja2 template + - name: SAP HANA - Pre-Tasks - Display the location of the remote Jinja2 template ansible.builtin.debug: msg: | The Jinja2 template for creating the hdblcm configfile has been saved to '{{ sap_hana_install_configfile_directory }}/{{ sap_hana_install_configfile_template_prefix }}.j2'. - - name: SAP HANA Pre Install - Download the Jinja2 template + - name: SAP HANA - Pre-Tasks - Download the Jinja2 template ansible.builtin.fetch: src: "{{ sap_hana_install_configfile_directory }}/{{ sap_hana_install_configfile_template_prefix }}.j2" dest: "{{ sap_hana_install_local_configfile_directory }}" register: __sap_hana_install_register_fetch_hdblcm_configfile_jinja2_template - - name: SAP HANA Pre Install - Display the location of the local Jinja2 template + - name: SAP HANA - Pre-Tasks - Display the location of the local Jinja2 template ansible.builtin.debug: msg: "The Jinja2 template has been downloaded to '{{ __sap_hana_install_register_fetch_hdblcm_configfile_jinja2_template.dest }}'." when: not ansible_check_mode - - name: SAP HANA Pre Install - Process the Jinja2 template to create the hdblcm configfile + - name: SAP HANA - Pre-Tasks - Process the Jinja2 template to create the hdblcm configfile ansible.builtin.template: src: "{{ __sap_hana_install_register_fetch_hdblcm_configfile_jinja2_template.dest }}" dest: "{{ __sap_hana_install_register_tmpdir.path }}/configfile.cfg" @@ -91,6 +91,6 @@ register: __sap_hana_install_register_cftemplate when: not ansible_check_mode -- name: SAP HANA Pre Install - Display the path name of the hdblcm configfile +- name: SAP HANA - Pre-Tasks - Display the path name of the hdblcm configfile ansible.builtin.debug: msg: "The hdblcm configfile is: '{{ __sap_hana_install_register_tmpdir.path }}/configfile.cfg'" diff --git a/roles/sap_hana_install/tasks/pre_install/hdblcm_prepare.yml b/roles/sap_hana_install/tasks/pre_tasks/hdblcm_prepare.yml similarity index 67% rename from roles/sap_hana_install/tasks/pre_install/hdblcm_prepare.yml rename to roles/sap_hana_install/tasks/pre_tasks/hdblcm_prepare.yml index 0b0e0f165..969ab309b 100644 --- a/roles/sap_hana_install/tasks/pre_install/hdblcm_prepare.yml +++ b/roles/sap_hana_install/tasks/pre_tasks/hdblcm_prepare.yml @@ -5,7 +5,7 @@ # Create directory {{ sap_hana_install_software_extract_directory }} # This is where all extracted .SAR files will be stored -- name: SAP HANA hdblcm prepare - Remove directory '{{ sap_hana_install_software_extract_directory }}' +- name: SAP HANA - Pre-Tasks - Remove directory '{{ sap_hana_install_software_extract_directory }}' ansible.builtin.file: path: "{{ sap_hana_install_software_extract_directory }}" state: absent @@ -13,7 +13,7 @@ - sap_hana_install_prepare_sapcar - sap_hana_install_prepare_sarfiles -- name: SAP HANA hdblcm prepare - Create directory '{{ sap_hana_install_software_extract_directory }}' +- name: SAP HANA - Pre-Tasks - Create directory '{{ sap_hana_install_software_extract_directory }}' ansible.builtin.file: path: "{{ sap_hana_install_software_extract_directory }}" state: directory @@ -22,7 +22,7 @@ - sap_hana_install_prepare_sapcar - sap_hana_install_prepare_sarfiles -- name: SAP HANA hdblcm prepare - Create SAPCAR directory '{{ sap_hana_install_software_extract_directory }}/sapcar' +- name: SAP HANA - Pre-Tasks - Create SAPCAR directory '{{ sap_hana_install_software_extract_directory }}/sapcar' ansible.builtin.file: path: "{{ sap_hana_install_software_extract_directory }}/sapcar" state: directory @@ -31,7 +31,7 @@ - sap_hana_install_prepare_sapcar - sap_hana_install_prepare_sarfiles -- name: SAP HANA hdblcm prepare - Create status file '{{ sap_hana_install_software_extract_directory }}/__EXTRACTION_ONGOING__' +- name: SAP HANA - Pre-Tasks - Create status file '{{ sap_hana_install_software_extract_directory }}/__EXTRACTION_ONGOING__' ansible.builtin.file: path: "{{ sap_hana_install_software_extract_directory }}/__EXTRACTION_ONGOING__" state: touch @@ -40,34 +40,34 @@ # Ensure that temporary file __EXTRACTION_ONGOING__ is removed if fail occurs. - name: Rescue block for SAPCAR and SAR file preparation block: - - name: SAP HANA hdblcm prepare - Prepare SAPCAR + - name: SAP HANA - Pre-Tasks - Prepare SAPCAR ansible.builtin.include_tasks: prepare_sapcar.yml tags: - sap_hana_install_prepare_sapcar - sap_hana_install_prepare_sarfiles - - name: SAP HANA hdblcm prepare - Prepare SAR files + - name: SAP HANA - Pre-Tasks - Prepare SAR files ansible.builtin.include_tasks: prepare_sarfiles.yml tags: sap_hana_install_prepare_sarfiles rescue: - - name: SAP HANA hdblcm prepare - Remove status file '{{ sap_hana_install_software_extract_directory }}/__EXTRACTION_ONGOING__' + - name: SAP HANA - Pre-Tasks - Remove status file '{{ sap_hana_install_software_extract_directory }}/__EXTRACTION_ONGOING__' ansible.builtin.file: path: "{{ sap_hana_install_software_extract_directory }}/__EXTRACTION_ONGOING__" state: absent - - name: SAP HANA hdblcm prepare - Preparation tasks failed + - name: SAP HANA - Pre-Tasks - Preparation tasks failed ansible.builtin.fail: msg: | Preparation steps failed. Please see details of failed task above. Cleanup of temporary files was completed. -- name: SAP HANA hdblcm prepare - Remove status file '{{ sap_hana_install_software_extract_directory }}/__EXTRACTION_ONGOING__' +- name: SAP HANA - Pre-Tasks - Remove status file '{{ sap_hana_install_software_extract_directory }}/__EXTRACTION_ONGOING__' ansible.builtin.file: path: "{{ sap_hana_install_software_extract_directory }}/__EXTRACTION_ONGOING__" state: absent -- name: SAP HANA hdblcm prepare - Find 'SAP_HANA_DATABASE' in '{{ sap_hana_install_software_extract_directory }}' +- name: SAP HANA - Pre-Tasks - Find 'SAP_HANA_DATABASE' in '{{ sap_hana_install_software_extract_directory }}' ansible.builtin.find: paths: "{{ sap_hana_install_software_extract_directory }}" recurse: true @@ -75,7 +75,7 @@ patterns: 'SAP_HANA_DATABASE' register: __sap_hana_install_register_find_directory_sap_hana_database -- name: SAP HANA hdblcm prepare - Set fact for 'hdblcm' installer path +- name: SAP HANA - Pre-Tasks - Set fact for 'hdblcm' installer path ansible.builtin.set_fact: __sap_hana_install_fact_hdblcm_path: "{{ __sap_hana_install_register_find_directory_sap_hana_database.files[0].path }}" diff --git a/roles/sap_hana_install/tasks/pre_install/prepare_sapcar.yml b/roles/sap_hana_install/tasks/pre_tasks/prepare_sapcar.yml similarity index 92% rename from roles/sap_hana_install/tasks/pre_install/prepare_sapcar.yml rename to roles/sap_hana_install/tasks/pre_tasks/prepare_sapcar.yml index 32045bfb5..b8d3ea95a 100644 --- a/roles/sap_hana_install/tasks/pre_install/prepare_sapcar.yml +++ b/roles/sap_hana_install/tasks/pre_tasks/prepare_sapcar.yml @@ -2,16 +2,16 @@ --- # hdblcm prepare SAPCAR -- name: SAP HANA hdblcm prepare - SAPCAR defined - Prepare the SAPCAR executable if 'sap_hana_install_sapcar_filename' is defined +- name: SAP HANA - Pre-Tasks - Prepare the SAPCAR executable if 'sap_hana_install_sapcar_filename' is defined when: sap_hana_install_sapcar_filename is defined block: - - name: SAP HANA hdblcm prepare - SAPCAR defined - Check if the SAPCAR executable exists + - name: SAP HANA - Pre-Tasks - Check if the SAPCAR executable exists ansible.builtin.stat: path: "{{ __sap_hana_install_fact_software_directory }}/{{ sap_hana_install_sapcar_filename }}" register: __sap_hana_install_register_sapcar_stat - - name: SAP HANA hdblcm prepare - SAPCAR defined - Fail if the SAPCAR executable does not exist + - name: SAP HANA - Pre-Tasks - Fail if the SAPCAR executable does not exist ansible.builtin.fail: msg: "FAIL: The SAPCAR EXE file '{{ __sap_hana_install_fact_software_directory }}/{{ sap_hana_install_sapcar_filename }}' does not exist!" when: not __sap_hana_install_register_sapcar_stat.stat.exists @@ -19,7 +19,7 @@ # We cannot always use the SAPCAR executable in __sap_hana_install_fact_software_directory because there are # some configurations in which executing files in this directory is not possible. So we always copy SAPCAR # to directory 'sapcar' in sap_hana_install_software_extract_directory. We do not copy the SAPCAR checksum file. - - name: SAP HANA hdblcm prepare - SAPCAR defined - Copy the SAPCAR executable to '{{ sap_hana_install_software_extract_directory }}/sapcar' + - name: SAP HANA - Pre-Tasks - Copy the SAPCAR executable to '{{ sap_hana_install_software_extract_directory }}/sapcar' ansible.builtin.copy: src: "{{ __sap_hana_install_fact_software_directory }}/{{ sap_hana_install_sapcar_filename }}" dest: "{{ sap_hana_install_software_extract_directory }}/sapcar/{{ sap_hana_install_sapcar_filename }}" @@ -28,7 +28,7 @@ group: 'root' mode: '0755' - - name: SAP HANA hdblcm prepare - SAPCAR defined - Separate file from directory names and add the global checksum file path + - name: SAP HANA - Pre-Tasks - Separate file from directory names and add the global checksum file path ansible.builtin.set_fact: __sap_hana_install_fact_sapcar_dict_tmp: { dir: "{{ sap_hana_install_software_extract_directory }}/sapcar", @@ -37,7 +37,7 @@ } when: sap_hana_install_global_checksum_file is defined - - name: SAP HANA hdblcm prepare - SAPCAR defined - Separate file from directory names and add the specific checksum file path + - name: SAP HANA - Pre-Tasks - Separate file from directory names and add the specific checksum file path ansible.builtin.set_fact: __sap_hana_install_fact_sapcar_dict_tmp: { dir: "{{ sap_hana_install_software_extract_directory }}/sapcar", @@ -46,11 +46,11 @@ } when: sap_hana_install_global_checksum_file is not defined - - name: SAP HANA hdblcm prepare - SAPCAR defined - Create a list of one dict for checksum verification + - name: SAP HANA - Pre-Tasks - Create a list of one dict for checksum verification ansible.builtin.set_fact: __sap_hana_install_fact_sapcar_dict: "{{ __sap_hana_install_fact_sapcar_dict | d([]) + [__sap_hana_install_fact_sapcar_dict_tmp] }}" - - name: SAP HANA hdblcm prepare - SAPCAR defined - Verify checksum for the SAPCAR executable + - name: SAP HANA - Pre-Tasks - Verify checksum for the SAPCAR executable ansible.builtin.include_tasks: verify_checksum.yml loop: "{{ __sap_hana_install_fact_sapcar_dict }}" loop_control: @@ -59,7 +59,7 @@ - __sap_hana_install_fact_sapcar_dict | length > 0 - sap_hana_install_verify_checksums - - name: SAP HANA hdblcm prepare - SAPCAR defined - Set fact for the SAPCAR executable from variable + - name: SAP HANA - Pre-Tasks - Set fact for the SAPCAR executable from variable ansible.builtin.set_fact: __sap_hana_install_fact_selected_sapcar_filename: "{{ sap_hana_install_sapcar_filename }}" diff --git a/roles/sap_hana_install/tasks/pre_install/prepare_sarfiles.yml b/roles/sap_hana_install/tasks/pre_tasks/prepare_sarfiles.yml similarity index 72% rename from roles/sap_hana_install/tasks/pre_install/prepare_sarfiles.yml rename to roles/sap_hana_install/tasks/pre_tasks/prepare_sarfiles.yml index f9693d3a9..b41a33448 100644 --- a/roles/sap_hana_install/tasks/pre_install/prepare_sarfiles.yml +++ b/roles/sap_hana_install/tasks/pre_tasks/prepare_sarfiles.yml @@ -2,19 +2,19 @@ --- # hdblcm prepare sarfiles -- name: SAP HANA hdblcm prepare - Set fact for final location of SAR files, default +- name: SAP HANA - Pre-Tasks - Set fact for final location of SAR files, default ansible.builtin.set_fact: __sap_hana_install_fact_sar_dir: "{{ __sap_hana_install_fact_software_directory }}" -- name: SAP HANA hdblcm prepare - Set fact list of SAR files if 'sap_hana_install_sarfiles' is defined +- name: SAP HANA - Pre-Tasks - Set fact list of SAR files if 'sap_hana_install_sarfiles' is defined ansible.builtin.set_fact: __sap_hana_install_fact_sarfiles: "{{ sap_hana_install_sarfiles | d([]) }}" -- name: SAP HANA hdblcm prepare - Find all SAR files if 'sap_hana_install_sarfiles' is undefined +- name: SAP HANA - Pre-Tasks - Find all SAR files if 'sap_hana_install_sarfiles' is undefined when: sap_hana_install_sarfiles is not defined block: - - name: SAP HANA hdblcm prepare - Find all SAR files in '{{ __sap_hana_install_fact_software_directory }}' + - name: SAP HANA - Pre-Tasks - Find all SAR files in '{{ __sap_hana_install_fact_software_directory }}' ansible.builtin.find: paths: "{{ __sap_hana_install_fact_software_directory }}" recurse: false @@ -22,7 +22,7 @@ patterns: '*.SAR' register: __sap_hana_install_register_find_sarfiles - - name: SAP HANA hdblcm prepare - Create list of file names from the find result + - name: SAP HANA - Pre-Tasks - Create list of file names from the find result ansible.builtin.set_fact: __sap_hana_install_fact_sarfiles: "{{ __sap_hana_install_fact_sarfiles | d([]) + [item.path | basename] }}" loop: "{{ __sap_hana_install_register_find_sarfiles.files }}" @@ -31,13 +31,13 @@ when: sap_hana_install_copy_sarfiles block: - - name: SAP HANA hdblcm prepare - Create directory '{{ sap_hana_install_software_extract_directory }}/sarfiles' + - name: SAP HANA - Pre-Tasks - Create directory '{{ sap_hana_install_software_extract_directory }}/sarfiles' ansible.builtin.file: path: "{{ sap_hana_install_software_extract_directory }}/sarfiles" state: directory mode: '0755' - - name: SAP HANA hdblcm prepare - Copy SAR files to '{{ sap_hana_install_software_extract_directory }}/sarfiles' + - name: SAP HANA - Pre-Tasks - Copy SAR files to '{{ sap_hana_install_software_extract_directory }}/sarfiles' ansible.builtin.copy: src: "{{ __sap_hana_install_fact_software_directory }}/{{ item }}" dest: "{{ sap_hana_install_software_extract_directory }}/sarfiles/{{ item }}" @@ -47,11 +47,11 @@ group: root with_items: "{{ __sap_hana_install_fact_sarfiles }}" - - name: SAP HANA hdblcm prepare - Set fact for final location of SAR files, copy_sarfiles + - name: SAP HANA - Pre-Tasks - Set fact for final location of SAR files, copy_sarfiles ansible.builtin.set_fact: __sap_hana_install_fact_sar_dir: "{{ sap_hana_install_software_extract_directory }}/sarfiles" -- name: SAP HANA hdblcm prepare - Fail if no SAR files were found +- name: SAP HANA - Pre-Tasks - Fail if no SAR files were found ansible.builtin.fail: msg: | {% if sap_hana_install_sarfiles is defined -%} @@ -65,9 +65,10 @@ - name: Display the resulting list of SAR file names ansible.builtin.debug: - var: __sap_hana_install_fact_sarfiles + msg: "{{ __sap_hana_install_fact_sarfiles }}" + when: __sap_hana_install_fact_sarfiles is defined -- name: SAP HANA hdblcm prepare - Fill list of dicts containing dir, file, and global checksum file +- name: SAP HANA - Pre-Tasks - Fill list of dicts containing dir, file, and global checksum file ansible.builtin.set_fact: __sap_hana_install_fact_sarfiles_dict: "{{ __sap_hana_install_fact_sarfiles_dict | d([]) + [__sap_hana_install_tmp_sarfiles_dict] }}" with_items: "{{ __sap_hana_install_fact_sarfiles }}" @@ -78,7 +79,7 @@ checksum_file: "{{ sap_hana_install_global_checksum_file }}" when: sap_hana_install_global_checksum_file is defined -- name: SAP HANA hdblcm prepare - Fill list of dicts containing dir, file, and specific checksum file +- name: SAP HANA - Pre-Tasks - Fill list of dicts containing dir, file, and specific checksum file ansible.builtin.set_fact: __sap_hana_install_fact_sarfiles_dict: "{{ __sap_hana_install_fact_sarfiles_dict | d([]) + [__sap_hana_install_tmp_sarfiles_dict] }}" with_items: "{{ __sap_hana_install_fact_sarfiles }}" @@ -89,7 +90,7 @@ checksum_file: "{{ __sap_hana_install_fact_software_directory }}/{{ item }}.sha256" when: sap_hana_install_global_checksum_file is not defined -- name: SAP HANA hdblcm prepare - Verify checksums for all SAR files in folder '{{ __sap_hana_install_fact_sar_dir }}' +- name: SAP HANA - Pre-Tasks - Verify checksums for all SAR files in folder '{{ __sap_hana_install_fact_sar_dir }}' ansible.builtin.include_tasks: verify_checksum.yml loop: "{{ __sap_hana_install_fact_sarfiles_dict }}" loop_control: @@ -99,7 +100,7 @@ - not ansible_check_mode - sap_hana_install_verify_checksums -- name: SAP HANA hdblcm prepare - Extract all SAR files in folder '{{ __sap_hana_install_fact_software_directory }}' +- name: SAP HANA - Pre-Tasks - Extract all SAR files in folder '{{ __sap_hana_install_fact_software_directory }}' ansible.builtin.include_tasks: extract_sarfile.yml loop: "{{ __sap_hana_install_fact_sarfiles }}" loop_control: @@ -109,7 +110,7 @@ - not ansible_check_mode tags: sap_hana_install_extract_sarfiles -- name: SAP HANA hdblcm prepare - Remove temporary SAR file directory '{{ sap_hana_install_software_extract_directory }}/sarfiles' +- name: SAP HANA - Pre-Tasks - Remove temporary SAR file directory '{{ sap_hana_install_software_extract_directory }}/sarfiles' ansible.builtin.file: path: "{{ sap_hana_install_software_extract_directory }}/sarfiles/" state: absent diff --git a/roles/sap_hana_install/tasks/pre_tasks/selinux.yml b/roles/sap_hana_install/tasks/pre_tasks/selinux.yml new file mode 100644 index 000000000..0d1c3def6 --- /dev/null +++ b/roles/sap_hana_install/tasks/pre_tasks/selinux.yml @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 +--- + +- name: SAP HANA - Pre-Tasks - Configure 'sap_hana_install_root_path' SELinux file contexts + ansible.builtin.include_role: + name: '{{ sap_hana_install_system_roles_collection }}.selinux' + vars: + selinux_booleans: + - { name: 'selinuxuser_execmod', state: 'on' } + selinux_fcontexts: + - { target: '{{ sap_hana_install_root_path }}(/.*)?', setype: 'usr_t' } + selinux_restore_dirs: + - '{{ sap_hana_install_root_path }}' + delegate_to: "{{ target_host }}" diff --git a/roles/sap_hana_install/tasks/pre_install-loop-block.yml b/roles/sap_hana_install/tasks/pre_tasks/software_directory_permissions.yml similarity index 71% rename from roles/sap_hana_install/tasks/pre_install-loop-block.yml rename to roles/sap_hana_install/tasks/pre_tasks/software_directory_permissions.yml index c27dbdc57..dff53a946 100644 --- a/roles/sap_hana_install/tasks/pre_install-loop-block.yml +++ b/roles/sap_hana_install/tasks/pre_tasks/software_directory_permissions.yml @@ -1,27 +1,23 @@ # SPDX-License-Identifier: Apache-2.0 --- -- name: SAP HANA Pre Install - Set __sap_hana_install_fact_tmp_dirname +- name: SAP HANA - Pre-Tasks - Set the software directory name ansible.builtin.set_fact: __sap_hana_install_fact_tmp_dirname: "{{ (__sap_hana_install_fact_tmp_dirname + '/' + __sap_hana_install_fact_software_directory.split(\"/\")[line_item | int]) | string }}" -- name: SAP HANA Pre Install - Get directory info +- name: SAP HANA - Pre-Tasks - Get directory info ansible.builtin.stat: path: "{{ __sap_hana_install_fact_tmp_dirname }}" register: __sap_hana_install_register_stat_dirname -- name: SAP HANA Pre Install - Display all users permissions for the directory +- name: SAP HANA - Pre-Tasks - Display all users permissions for the directory ansible.builtin.debug: msg: "'{{ __sap_hana_install_fact_tmp_dirname }}' has all users permissions '{{ __sap_hana_install_register_stat_dirname.stat.mode[-1] }}'." -- name: SAP HANA Pre Install - Assert that the directory is world executable +- name: SAP HANA - Pre-Tasks - Assert that the directory is world executable ansible.builtin.assert: that: __sap_hana_install_register_stat_dirname.stat.mode[-1] == '1' or __sap_hana_install_register_stat_dirname.stat.mode[-1] == '5' or __sap_hana_install_register_stat_dirname.stat.mode[-1] == '7' fail_msg: "FAIL: The directory {{ __sap_hana_install_fact_tmp_dirname }} has all users permission '{{ __sap_hana_install_register_stat_dirname.stat.mode[-1] }}' but needs to be world executable! Either change the all users execute permissions or use a separate directory for 'sap_hana_install_software_extract_directory'." success_msg: "PASS: The directory {{ __sap_hana_install_fact_tmp_dirname }} is world executable." - -#- name: SAP HANA Pre Install - Set __sap_hana_install_fact_software_directories -# ansible.builtin.set_fact: -# __sap_hana_install_fact_software_directories: "{{ __sap_hana_install_fact_software_directories | d([]) + [__sap_hana_install_fact_tmp_dirname] }}" diff --git a/roles/sap_hana_install/tasks/pre_install/verify_checksum.yml b/roles/sap_hana_install/tasks/pre_tasks/verify_checksum.yml similarity index 80% rename from roles/sap_hana_install/tasks/pre_install/verify_checksum.yml rename to roles/sap_hana_install/tasks/pre_tasks/verify_checksum.yml index 125e25a65..7838a543d 100644 --- a/roles/sap_hana_install/tasks/pre_install/verify_checksum.yml +++ b/roles/sap_hana_install/tasks/pre_tasks/verify_checksum.yml @@ -1,12 +1,12 @@ # SPDX-License-Identifier: Apache-2.0 --- -- name: SAP HANA hdblcm prepare - Check if checksum file exists +- name: SAP HANA - Pre-Tasks - Check if checksum file exists ansible.builtin.stat: path: "{{ __sap_hana_install_passed_file_dict.checksum_file }}" register: __sap_hana_install_register_stat_checksum_file -- name: SAP HANA hdblcm prepare - Fail if the checksum file is missing +- name: SAP HANA - Pre-Tasks - Fail if the checksum file is missing ansible.builtin.fail: msg: "FAIL: Missing checksum file '{{ __sap_hana_install_passed_file_dict.checksum_file }}'!" when: not __sap_hana_install_register_stat_checksum_file.stat.exists @@ -18,25 +18,25 @@ # We are using awk to search for the file name in the checksum file. If there is no entry for the file, instead of # displaying the checksum for the file, we display the string 'Missing entry' on stdout. # Reason for noqa: A double brace might also occur in an awk command sequence. - - name: SAP HANA hdblcm prepare - Get expected checksum from file # noqa jinja[spacing] + - name: SAP HANA - Pre-Tasks - Get expected checksum from file # noqa jinja[spacing] ansible.builtin.command: "awk 'BEGIN{a=0}/{{ __sap_hana_install_passed_file_dict.file }}/{a++; print $1}END{if (a==0){print \"Missing entry\"}}' {{ __sap_hana_install_passed_file_dict.checksum_file }}" check_mode: false register: __sap_hana_install_register_checksum_from_file changed_when: false - - name: SAP HANA hdblcm prepare - Fail if an entry for file '{{ __sap_hana_install_passed_file_dict.file }}' is missing in '{{ __sap_hana_install_passed_file_dict.checksum_file }}' + - name: SAP HANA - Pre-Tasks - Fail if an entry for file '{{ __sap_hana_install_passed_file_dict.file }}' is missing in '{{ __sap_hana_install_passed_file_dict.checksum_file }}' ansible.builtin.fail: msg: "FAIL: Missing entry for file '{{ __sap_hana_install_passed_file_dict.file }}' in '{{ __sap_hana_install_passed_file_dict.checksum_file }}'!" when: __sap_hana_install_register_checksum_from_file.stdout == 'Missing entry' - - name: SAP HANA hdblcm prepare - Calculate checksum of '{{ __sap_hana_install_passed_file_dict.file }}' + - name: SAP HANA - Pre-Tasks - Calculate checksum of '{{ __sap_hana_install_passed_file_dict.file }}' ansible.builtin.stat: path: "{{ __sap_hana_install_passed_file_dict.dir }}/{{ __sap_hana_install_passed_file_dict.file }}" checksum_algorithm: "{{ sap_hana_install_checksum_algorithm }}" register: __sap_hana_install_register_stat_file when: __sap_hana_install_register_checksum_from_file.stdout != 'Missing entry' - - name: SAP HANA hdblcm prepare - Assert that the checksum of the SAR file is correct + - name: SAP HANA - Pre-Tasks - Assert that the checksum of the SAR file is correct ansible.builtin.assert: that: __sap_hana_install_register_stat_file.stat.checksum == __sap_hana_install_register_checksum_from_file.stdout.split(' ').0 From b727968c128bbbbde2c056e8dff9e93a229e8c98 Mon Sep 17 00:00:00 2001 From: Marcel Mamula Date: Tue, 30 Sep 2025 16:09:45 +0200 Subject: [PATCH 2/4] move selinux include_role into block for delegation --- .../tasks/post_tasks/selinux.yml | 26 ++++++++++--------- .../tasks/pre_tasks/selinux.yml | 22 +++++++++------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/roles/sap_hana_install/tasks/post_tasks/selinux.yml b/roles/sap_hana_install/tasks/post_tasks/selinux.yml index ecd9f45e5..35b395b67 100644 --- a/roles/sap_hana_install/tasks/post_tasks/selinux.yml +++ b/roles/sap_hana_install/tasks/post_tasks/selinux.yml @@ -2,16 +2,18 @@ --- # This configuration includes also Pre-Tasks content to ensure they are all set same. -- name: SAP HANA - Post-Tasks - Configure 'sap_hana_install_root_path' SELinux file contexts - ansible.builtin.include_role: - name: '{{ sap_hana_install_system_roles_collection }}.selinux' - vars: - selinux_booleans: - - { name: 'selinuxuser_execmod', state: 'on' } - selinux_fcontexts: - - { target: '{{ sap_hana_install_root_path }}(/.*)?', setype: 'usr_t' } - - { target: '/usr/sap(/.*)?', setype: 'usr_t' } - selinux_restore_dirs: - - '{{ sap_hana_install_root_path }}' - - /usr/sap +- name: Block for delegation delegate_to: "{{ target_host }}" + block: + - name: SAP HANA - Post-Tasks - Configure 'sap_hana_install_root_path' SELinux file contexts + ansible.builtin.include_role: + name: '{{ sap_hana_install_system_roles_collection }}.selinux' + vars: + selinux_booleans: + - { name: 'selinuxuser_execmod', state: 'on' } + selinux_fcontexts: + - { target: '{{ sap_hana_install_root_path }}(/.*)?', setype: 'usr_t' } + - { target: '/usr/sap(/.*)?', setype: 'usr_t' } + selinux_restore_dirs: + - '{{ sap_hana_install_root_path }}' + - /usr/sap diff --git a/roles/sap_hana_install/tasks/pre_tasks/selinux.yml b/roles/sap_hana_install/tasks/pre_tasks/selinux.yml index 0d1c3def6..f643b320b 100644 --- a/roles/sap_hana_install/tasks/pre_tasks/selinux.yml +++ b/roles/sap_hana_install/tasks/pre_tasks/selinux.yml @@ -1,14 +1,16 @@ # SPDX-License-Identifier: Apache-2.0 --- -- name: SAP HANA - Pre-Tasks - Configure 'sap_hana_install_root_path' SELinux file contexts - ansible.builtin.include_role: - name: '{{ sap_hana_install_system_roles_collection }}.selinux' - vars: - selinux_booleans: - - { name: 'selinuxuser_execmod', state: 'on' } - selinux_fcontexts: - - { target: '{{ sap_hana_install_root_path }}(/.*)?', setype: 'usr_t' } - selinux_restore_dirs: - - '{{ sap_hana_install_root_path }}' +- name: Block for delegation delegate_to: "{{ target_host }}" + block: + - name: SAP HANA - Pre-Tasks - Configure 'sap_hana_install_root_path' SELinux file contexts + ansible.builtin.include_role: + name: '{{ sap_hana_install_system_roles_collection }}.selinux' + vars: + selinux_booleans: + - { name: 'selinuxuser_execmod', state: 'on' } + selinux_fcontexts: + - { target: '{{ sap_hana_install_root_path }}(/.*)?', setype: 'usr_t' } + selinux_restore_dirs: + - '{{ sap_hana_install_root_path }}' From b0daf95195365624c79973bb465f0796218726ca Mon Sep 17 00:00:00 2001 From: Marcel Mamula Date: Wed, 1 Oct 2025 16:39:59 +0200 Subject: [PATCH 3/4] updated readme and fixed detected issues --- roles/sap_hana_install/README.md | 242 +++++++++++------- roles/sap_hana_install/defaults/main.yml | 2 +- .../sap_hana_install/tasks/hana_addhosts.yml | 67 ++--- roles/sap_hana_install/tasks/main.yml | 8 +- .../sap_hana_install/tasks/post_addhosts.yml | 10 + roles/sap_hana_install/tasks/post_install.yml | 7 +- .../tasks/post_tasks/hdbuserstore.yml | 41 +-- roles/sap_hana_install/tasks/pre_addhosts.yml | 1 + .../tasks/pre_tasks/assert_variables.yml | 42 +++ .../tasks/pre_tasks/check_addhosts.yml | 14 - .../tasks/pre_tasks/fapolicyd.yml | 2 +- .../tasks/pre_tasks/hana_exists.yml | 12 +- roles/sap_hana_install/vars/main.yml | 15 ++ 13 files changed, 269 insertions(+), 194 deletions(-) diff --git a/roles/sap_hana_install/README.md b/roles/sap_hana_install/README.md index 48fed18d6..ae8b38aac 100644 --- a/roles/sap_hana_install/README.md +++ b/roles/sap_hana_install/README.md @@ -143,6 +143,13 @@ of this file will not be reflected. ## Execution +This Ansible Role can be executed in following scenarios: +1. Install new SAP HANA System on one host + - `sap_hana_install_new_system: true` +2. Install new SAP HANA System on multiple hosts (Scale-Out) + - `sap_hana_install_new_system: true` and `sap_hana_install_addhosts` with valid addhosts String. +3. Install new hosts to existing SAP HANA System + - `sap_hana_install_new_system: false`, `sap_hana_install_addhosts` with valid addhosts String and `sap_hana_install_sapadm_password` defined. @@ -154,101 +161,135 @@ It is recommended to execute this role together with other roles in this collect 4. *`sap_hana_install`* -### Execution Flow -#### Perform Initial Checks - -These checks will be performed by default but can be skipped by setting `sap_hana_install_force` to `true`. -- If variable `sap_hana_install_check_sidadm_user` is undefined or set to `yes`: Check if user sidadm exists. If yes, - abort the role. -- Check if `/usr/sap/hostctrl/exe/saphostctrl` exists and get info on running HANA instances: - - If a conflicting instances exist, the role aborts with a failure - - If the desired instance is running, the role aborts with success -- If `/usr/sap/hostctrl/exe/saphostctrl` does not exist: - - Check if the directory `/hana/shared/` exists. If yes and not empty, abort the role. - - Check if the directory `/usr/sap/` exists. If yes and not empty, abort the role. - -#### Pre-Install - -- Set all passwords to follow master password if set to 'y'. - -- Prepare the software located in directory `sap_hana_install_software_directory`: - - - If file `hdblcm` is found, skip the next step and proceed with the `hdblcm` existence check. - - - If file `hdblcm` is not found, proceed with the next step. - -- Prepare SAR files for `hdblcm`: - - - Get a list of hardware matching SAPCAR executables from `sap_hana_install_software_directory` in case its file name is not - provided by role variable. - - - Select the most recent version of SAPCAR from the hardware matching SAPCAR executables identified before. - - - Get all SAR files from `sap_hana_install_software_directory` or use the SAR files provided by the corresponding role variable, if set. - - - Extract all SAR files into `sap_hana_install_software_extract_directory`. - -Note: For each SAPCAR or SAR file called or used by the role, if variable `sap_hana_install_verify_checksums` -is set to `yes`, the role will perform a checksum verification against a specific or global checksum file. - -- Check existence of `hdblcm` in `SAP_HANA_DATABASE` directory from the extracted SAR files. - -- Check the existence of file `configfile.cfg` in the directory `configfiles` below `sap_hana_install_software_extract_directory`. - -If this file exists, copy it to a temporary directory for use by the hdblcm command. Be aware that when using this file, -any modifications to role variables after creation of this file will not be reflected. - -If this file is not present, perform the following three steps: - -- Create a hdblcm configfile template directly from the hdblcm command, using option `dump_configfile_template`. - -- Convert the configfile template into a Jinja2 template and download it to the control node. - -- Process the Jinja2 template, using the configured role variables or default settings, to create a customized hdblm configfile -in a temporary directory for use by the hdblcm command in the next step. - -#### SAP HANA Install - -- Execute hdblcm, using the configfile mentioned above. - -#### Post-Install - -- Create and Store Connection Info in hdbuserstore. - -- Set Log Mode key to overwrite value and apply to system. - -- Apply SAP HANA license to the new deployed instance if set to `yes`. - -- Set expiry of Unix created users to `never`. - -- Update `/etc/hosts` (optional - `yes` by default). - -- Apply firewall rules (optional - `no` by default). - -- Generate input file for `sap_swpm`. - -- Print a short summary of the result of the installation. - -### Add hosts to an existing SAP HANA Installation - -#### Pre-Install - -- Process SAP HANA configfile based on input parameters. - -#### SAP HANA Add Hosts - -- For each host to be added, check if there is: - - an instance profile in `/hana/shared//profile/_HDB_` - - a directory `/usr/sap//HDB/` - - an entry in the output of `./hdblcm --list_systems` - If any of the above is true, abort the role. - -- Execute hdblcm. - -#### Post-Install - -- Print a short summary of the result of the installation. +### Execution Flow +#### Validate mandatory variables +- If the mandatory variables are undefined or invalid (e.g. empty string, wrong length, etc.), abort the role with failure. Variables that are mandatory: + - `sap_hana_install_sid` + - `sap_hana_install_number` + - `sap_hana_install_master_password` + - `sap_hana_install_addhosts` if the variable `sap_hana_install_new_system` is set to `false`. +- All other password variables are set to the value of `sap_hana_install_master_password` if `sap_hana_install_use_master_password` is set to `y`. +- If the variable `sap_hana_install_new_system` is undefined or invalid and `sap_hana_install_master_password` is not set to `true`, abort the role with failure. + + +#### Check existing installation +This part is performed when: +- Always, unless `sap_hana_install_force` is set to `true`. + +- If the file `/usr/sap/hostctrl/exe/saphostctrl` is present, get a list of instances with `saphostctrl -function ListInstances`: + - If an instance with the same SID and Instance Number is found, skip Pre-Tasks and Installation and proceed to either Addhosts or Post-Tasks. + - If an instance with the same SID but different Instance number is found, abort the role with failure. + - If an instance with the same Instance number but different SID is found, abort the role with failure. +- If the file `/usr/sap/hostctrl/exe/saphostctrl` is not present: + - If the directory `/hana/shared/` exists and contains files, abort the role with failure. + - If the directory `/usr/sap/` exists and contains files, abort the role with failure. + - If the variable `sap_hana_install_groupid` is defined, check if group `sapsys` already exists: + - If it already exists with a different group ID, abort the role with failure. + - If the variable `sap_hana_install_check_sidadm_user` is defined, check if user `` already exists: + - If it already exists, abort the role with failure. +- If the existing instance was not found when adding hosts, abort the role with failure. + + +#### Check Addhosts +This part is performed when: +- The variable `sap_hana_install_addhosts` is defined and not empty String. + +**Addhosts are relevant to both Installation and Addhosts operations, because we need to delegate Pre-Tasks and Post-Tasks to them.** + +Steps: +1. If the variable `sap_hana_install_addhosts` does not contain hosts, abort the role with failure. + - This list of the `all hosts` is used for all Post-Tasks steps for idempotency. +2. Gather list of all Instance profiles in `/hana/shared//profile/`. +3. Gather list of all directories in `/usr/sap//HDB/`. +4. If the existing instance profile or directory was found in hosts list, create separate list without them. + - This list of the `new hosts` is used for one-time tasks. + + +#### Pre-Tasks for Installation +This part is performed when: +- The variable `sap_hana_install_new_system` is set to `true`. +- Existing SAP HANA was not detected. + +Steps: +1. If the variable `sap_hana_install_use_fapolicyd` is set to `true` and operating system is `RedHat`, install and disable `fapolicyd` on all new hosts. +2. Configure permissions for the SAP HANA directories on all new hosts. +3. If the variable `sap_hana_install_modify_selinux_labels` is set to `true`, configure `SElinux` on all new hosts. +4. Prepare the directory defined in variable `sap_hana_install_software_directory`. +5. If the `hdblcm` was not found in the directory `sap_hana_install_software_directory`: + - Find latest `SAPCAR` executable in the directory `sap_hana_install_software_directory` and use latest one matching OS Architecture. + - Extract found `SAR` files using selected `SAPCAR` executable. + - If the variable `sap_hana_install_verify_checksums` is set to `true`, validate checksum. +6. If the file `configfiles/configfile.cfg` is found in the directory defined in `sap_hana_install_software_directory`, make copy of it and use it for installation. + - If the file was not found, create template using `hdblcm` command and fill it in with jinja2 template. + + +#### Pre-Tasks for Addhosts +This part is performed when: +- The variable `sap_hana_install_new_system` is set to `false`. +- Existing SAP HANA was detected. +- New hosts identified in the variable `sap_hana_install_addhosts`. + +Steps: +1. Gather details of user `adm` and group `sapsys` on managed node. + - If the user or group is not present, abort the role with failure. + - Generate password hash for `sapadm` user using the value of `sap_hana_install_sapadm_password` variable. +2. Create the user `adm` on all addhosts. + - This is not required during installation, because the `root` user is used instead. +3. If the variable `sap_hana_install_use_fapolicyd` is set to `true` and operating system is `RedHat`, install and disable `fapolicyd` on all new hosts. +4. Configure permissions for the SAP HANA directories on all new hosts. +5. If the variable `sap_hana_install_modify_selinux_labels` is set to `true`, configure `SElinux` on all new hosts. +6. If the file `configfiles/configfile.cfg` is found in the directory defined in `sap_hana_install_software_directory`, make copy of it and use it for installation. + - If the file was not found, create template using `hdblcm` command and fill it in with jinja2 template. + + +#### Installation +This part is performed when: +- The variable `sap_hana_install_new_system` is set to `true`. +- Existing SAP HANA was not detected. + +Steps: +1. Execute the `hdblcm` executable in the directory `sap_hana_install_software_directory` using the configfile prepared in pre-tasks. + + +#### Addhosts +This part is performed when: +- The variable `sap_hana_install_new_system` is set to `false`. +- Existing SAP HANA was detected. +- New hosts identified in the variable `sap_hana_install_addhosts`. + +Steps: +1. Prepare new addhosts string only with new hosts and update `configfile.cfg`. +2. Execute the `hdblcm` executable in the directory `/hana/shared//hdblcm/` using the configfile prepared in pre-tasks. + + +#### Post-Tasks for Installation +This part is performed when: +- The variable `sap_hana_install_new_system` is set to `true`. + +Steps: +1. Update Secure User Store configuration (`hdbuserstore`) for `adm` user, for new installations. +2. Set Log Mode key to overwrite value and apply to system, for new installations. +3. Apply SAP HANA license if the variable `sap_hana_install_apply_license` is set to `true`, for new installations. +4. Recreate the initial tenant database if the variable `sap_hana_install_recreate_tenant_database` is set to `true`, for new installations. +5. Set expiration of unix users to `never` if the variable `sap_hana_install_set_sidadm_noexpire` is set to `true`, for new installations. +6. Apply firewall rules if the variable `sap_hana_install_update_firewall` is set to `true`. +7. Apply SElinux policies if the variable `sap_hana_install_modify_selinux_labels` is set to `true`. +8. (Red Hat specific) Configure `fapolicyd` if the variable `sap_hana_install_use_fapolicyd` is set to `true`. +9. Output final status of installed system. + + +#### Post-Tasks for Addhosts +This part is performed when: +- The variable `sap_hana_install_new_system` is set to `false`. + +Steps: +1. Update Secure User Store configuration (`hdbuserstore`) for `adm` user, for new hosts. +5. Set expiration of unix users to `never` if the variable `sap_hana_install_set_sidadm_noexpire` is set to `true`, for new hosts. +6. Apply firewall rules if the variable `sap_hana_install_update_firewall` is set to `true`. +7. Apply SElinux policies if the variable `sap_hana_install_modify_selinux_labels` is set to `true`. +8. (Red Hat specific) Configure `fapolicyd` if the variable `sap_hana_install_use_fapolicyd` is set to `true`. +9. Output final status of installed system. ### Example @@ -325,7 +366,7 @@ With the following tags, the role can be called to perform certain activities on with `--skip-tags`, to skip modifying these directories. This can be useful when using tag `sap_hana_install_preinstall`. - tag `sap_hana_install_configure_firewall`: Use this flag to only configure the firewall ports for - SAP HANA. Note: The role variable `sap_hana_install_update_firewall` has to be set to `yes` as + SAP HANA. Note: The role variable `sap_hana_install_update_firewall` has to be set to `true` as well. - tag `sap_hana_install_extract_sarfiles`: Use this flag with `--skip-tags` to run the SAR file preparation steps of tag `sap_hana_install_prepare_sarfiles` without extracting the SAR files. @@ -442,7 +483,7 @@ Default is `True`, in which case the installation will not be performed if the ` - _Type:_ `bool` - _Default:_ `true` -Set to `true` to ensure the SAP system user `{{ sap_hana_install_sid | lower }}adm` is configured with a non-expiring password. +Set to `true` to ensure the SAP system user `{{ sap_hana_install_sid | lower }}adm` is configured with a non-expiring password.
Set to `false` to skip this step — typically done when the user is managed by a central identity provider (e.g. Active Directory or LDAP). ### sap_hana_install_new_system @@ -453,12 +494,19 @@ Set to `false` to skip this step — typically done when the user is managed by Set to `False` to use existing SAP HANA database and add more hosts using variable `sap_hana_install_addhosts`.
Default is `True`, in which case fresh SAP HANA installation will be performed. +### sap_hana_install_addhosts + +- _Type:_ `string` + +If the following variable is specified, the role will perform a scaleout installation or it will add additional hosts to an existing SAP HANA system.
+Example: `sap_hana_install_addhosts: 'host2:role=worker,host3:role=worker:group=g02,host4:role=standby:group=g02',host5`. + ### sap_hana_install_update_firewall - _Type:_ `bool` - _Default:_ `False` -The role can be configured to also set the required firewall ports for SAP HANA. If this is desired, set the variable `sap_hana_install_update_firewall` to `yes` (default is `no`).
+The role can be configured to also set the required firewall ports for SAP HANA. If this is desired, set the variable `sap_hana_install_update_firewall` to `true` (default is `false`).
The firewall ports are defined in a variable which is compatible with the variable structure used by Linux System Role `firewall`.
The firewall ports for SAP HANA are defined in member `port` of the first field of variable `sap_hana_install_firewall` (`sap_hana_install_firewall[0].port`), see file `defaults/main.yml`.
If the member `state` is set to `enabled`, the ports will be enabled. If the member `state` is set to `disabled`, the ports will be disabled, which might be useful for testing.
diff --git a/roles/sap_hana_install/defaults/main.yml b/roles/sap_hana_install/defaults/main.yml index ac9f49550..87ceea933 100644 --- a/roles/sap_hana_install/defaults/main.yml +++ b/roles/sap_hana_install/defaults/main.yml @@ -165,7 +165,7 @@ sap_hana_install_use_master_password: 'y' # sap_hana_install_lss_backup_password: # sap_hana_install_ase_user_password: # sap_hana_install_root_password: -# sap_hana_install_sapadm_password: +# sap_hana_install_sapadm_password: # This password is required when adding hosts with `sap_hana_install_new_system: false` # sap_hana_install_xs_org_password: # Optional steps diff --git a/roles/sap_hana_install/tasks/hana_addhosts.yml b/roles/sap_hana_install/tasks/hana_addhosts.yml index 1a70de892..86cb47670 100644 --- a/roles/sap_hana_install/tasks/hana_addhosts.yml +++ b/roles/sap_hana_install/tasks/hana_addhosts.yml @@ -1,36 +1,29 @@ # SPDX-License-Identifier: Apache-2.0 --- +# This file is executed only if we detected addhosts that are not present yet. +# We need to create new updated addhosts string after removing existing hosts. +# New addhosts string has to be injected into configfile, +# because we cannot override user set 'sap_hana_install_addhosts' due to precedence. -- name: SAP HANA - Addhosts - Make sure the additional hosts are not yet part of the exiting SAP HANA system - hdblcm checks - when: not ansible_check_mode - block: +- name: SAP HANA - Addhosts - Set fact for updated addhosts string + ansible.builtin.set_fact: + __sap_hana_install_addhosts: "{{ __sap_hana_install_addhosts | d([]) + [item] }}" + loop: "{{ sap_hana_install_addhosts.split(',') | map('trim') | reject('equalto', '') | list }}" + when: + - item.split(':')[0] in __sap_hana_install_fact_addhosts_hosts_new -# Reason for noqa: We can safely fail at the last command in the pipeline. - - name: SAP HANA - Addhosts - Run 'hdblcm --list_systems' # noqa risky-shell-pipe - ansible.builtin.shell: | - ./hdblcm --list_systems | awk '/\/hana\/shared\/{{ sap_hana_install_sid }}/{a=1} - /hosts:/{if (a==1){ - gsub ("^\\s*hosts: ", "");print;a=0} - }' - args: - chdir: "{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}/hdblcm" - register: __sap_hana_install_register_hdblcm_list_systems - changed_when: false +- name: Debug __sap_hana_install_addhosts + ansible.builtin.debug: + msg: | + old: {{ sap_hana_install_addhosts }} + new: {{ __sap_hana_install_addhosts }} - - name: SAP HANA - Addhosts - Show the output of hdblcm --list_systems - ansible.builtin.debug: - msg: "{{ __sap_hana_install_register_hdblcm_list_systems.stdout_lines }}" +- name: SAP HANA - Addhosts - Update configfile with new addhosts string + ansible.builtin.lineinfile: + path: "{{ __sap_hana_install_register_tmpdir.path }}/configfile.cfg" + regexp: '^addhosts\s*=\s*.*$' + line: "addhosts = {{ __sap_hana_install_addhosts | join(',') }}" - - name: SAP HANA - Addhosts - Assert that the additional hosts are not shown in hdblcm --list_systems - ansible.builtin.assert: - that: line_item not in __sap_hana_install_register_hdblcm_list_systems.stdout - fail_msg: >- - FAIL: The host '{{ line_item }}' is already part of system '{{ sap_hana_install_sid }}' - and addhosts operation will not be performed. - success_msg: "PASS: Host '{{ line_item }}' is not yet part of system '{{ sap_hana_install_sid }}'." - loop: "{{ __sap_hana_install_fact_addhosts_hosts }}" - loop_control: - loop_var: line_item - name: SAP HANA - Addhosts - Set fact for hdblcm command line ansible.builtin.set_fact: @@ -60,23 +53,3 @@ when: - not ansible_check_mode - __sap_hana_install_register_hdblcm_add_hosts.stdout is defined - -- name: SAP HANA - Addhosts - Run 'hdblcm --list_systems' after the installation - ansible.builtin.shell: | - set -o pipefail && ./hdblcm --list_systems | awk '/\/hana\/shared\/{{ sap_hana_install_sid }}/{a=1} - /version:/{if (a==1){ - gsub ("^\\s*version: ", "");printf ("version: %s; hosts: ", $NF)} - } - /hosts?:/{if (a==1){ - gsub ("^\\s*hosts?: ", ""); print; a=0} - }' - args: - chdir: "{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}/hdblcm" - register: __sap_hana_install_register_addhosts_result - changed_when: false - when: not ansible_check_mode - -- name: SAP HANA - Addhosts - Show the HANA version and hosts - ansible.builtin.debug: - msg: "HANA system '{{ sap_hana_install_sid }}': {{ __sap_hana_install_register_addhosts_result.stdout }}" - when: not ansible_check_mode diff --git a/roles/sap_hana_install/tasks/main.yml b/roles/sap_hana_install/tasks/main.yml index 7e9e586ac..3d6a9f297 100644 --- a/roles/sap_hana_install/tasks/main.yml +++ b/roles/sap_hana_install/tasks/main.yml @@ -72,7 +72,7 @@ - name: Ensure SAP HANA is running for existing systems or addhosts operations ansible.builtin.include_tasks: file: pre_tasks/hana_start.yml - when: __sap_hana_install_fact_is_installed | d(false) + when: __sap_hana_install_fact_is_installed - name: Validate connection to provided addhosts @@ -102,13 +102,13 @@ ansible.builtin.include_tasks: file: pre_install.yml tags: sap_hana_install_preinstall - when: not __sap_hana_install_fact_is_installed | d(false) + when: not __sap_hana_install_fact_is_installed - name: SAP HANA - Install ansible.builtin.include_tasks: file: hana_install.yml when: - - not __sap_hana_install_fact_is_installed | d(false) + - not __sap_hana_install_fact_is_installed - name: SAP HANA - Install - Post-tasks ansible.builtin.include_tasks: @@ -119,7 +119,7 @@ - name: Block for Addhosts tasks when: - not sap_hana_install_new_system - - __sap_hana_install_fact_is_installed | d(false) + - __sap_hana_install_fact_is_installed block: # Execute only if new hosts are to be added. - name: SAP HANA - Addhosts - Pre-Tasks diff --git a/roles/sap_hana_install/tasks/post_addhosts.yml b/roles/sap_hana_install/tasks/post_addhosts.yml index 1a34c6e63..cadad81d7 100644 --- a/roles/sap_hana_install/tasks/post_addhosts.yml +++ b/roles/sap_hana_install/tasks/post_addhosts.yml @@ -2,6 +2,16 @@ --- # Execute only on new addhosts, if present. +- name: SAP HANA - Addhosts - Post-Tasks - Store connection information + ansible.builtin.include_tasks: + file: post_tasks/hdbuserstore.yml + loop: "{{ __sap_hana_install_fact_addhosts_hosts_new }}" + loop_control: + loop_var: target_host + when: + - __sap_hana_install_fact_addhosts_hosts_new | length > 0 + tags: sap_hana_install_store_connection_information + - name: SAP HANA - Addhosts - Post-Tasks - Set user expiration ansible.builtin.include_tasks: file: post_tasks/user_expiration.yml diff --git a/roles/sap_hana_install/tasks/post_install.yml b/roles/sap_hana_install/tasks/post_install.yml index 4b524ecb7..ff3e8e033 100644 --- a/roles/sap_hana_install/tasks/post_install.yml +++ b/roles/sap_hana_install/tasks/post_install.yml @@ -4,12 +4,15 @@ # Installation tasks that can be destructive and should never be executed on existing database. - name: Block with tasks for new HANA Systems when: - - not __sap_hana_install_fact_is_installed | d(false) + - not __sap_hana_install_fact_is_installed block: - name: SAP HANA - Install - Post-Tasks - Store connection information ansible.builtin.include_tasks: file: post_tasks/hdbuserstore.yml + loop: "{{ __sap_hana_install_fact_all_hosts }}" + loop_control: + loop_var: target_host tags: sap_hana_install_store_connection_information - name: SAP HANA - Install - Post-Tasks - Set log_mode @@ -70,7 +73,7 @@ - name: SAP HANA - Install - Post-Tasks - Firewall ansible.builtin.include_tasks: file: post_tasks/firewall.yml - loop: "{{ __sap_hana_install_fact_all_hosts }}" + loop: "{{ __sap_hana_install_fact_all_hosts if not __sap_hana_install_fact_is_installed else [inventory_hostname_short] }}" loop_control: loop_var: target_host when: sap_hana_install_update_firewall diff --git a/roles/sap_hana_install/tasks/post_tasks/hdbuserstore.yml b/roles/sap_hana_install/tasks/post_tasks/hdbuserstore.yml index 5162b4a65..112a7286c 100644 --- a/roles/sap_hana_install/tasks/post_tasks/hdbuserstore.yml +++ b/roles/sap_hana_install/tasks/post_tasks/hdbuserstore.yml @@ -1,23 +1,26 @@ # SPDX-License-Identifier: Apache-2.0 --- -- name: SAP HANA - Post-Tasks - Create and Store Connection Info in hdbuserstore - ansible.builtin.shell: | - /usr/sap/{{ sap_hana_install_sid }}/SYS/exe/hdb/hdbuserstore \ - SET {{ sap_hana_install_hdbuserstore_key }} \ - {{ ansible_hostname }}:3{{ sap_hana_install_number }}13 \ - SYSTEM '{{ sap_hana_install_db_system_password | d(sap_hana_install_master_password) }}' - args: - executable: /bin/bash - become: true - become_user: "{{ sap_hana_install_sid | lower }}adm" - when: not ansible_check_mode - changed_when: false - register: __sap_hana_install_store_connection_information - tags: sap_hana_install_store_connection_information +- name: Block to delegate_to all tasks + delegate_to: "{{ target_host }}" + block: + - name: SAP HANA - Post-Tasks - Create and Store Connection Info in hdbuserstore + ansible.builtin.shell: | + /usr/sap/{{ sap_hana_install_sid }}/SYS/exe/hdb/hdbuserstore \ + SET {{ sap_hana_install_hdbuserstore_key }} \ + {{ ansible_hostname }}:3{{ sap_hana_install_number }}13 \ + SYSTEM '{{ sap_hana_install_db_system_password | d(sap_hana_install_master_password) }}' + args: + executable: /bin/bash + become: true + become_user: "{{ sap_hana_install_sid | lower }}adm" + when: not ansible_check_mode + changed_when: false + register: __sap_hana_install_store_connection_information + tags: sap_hana_install_store_connection_information -- name: SAP HANA - Post-Tasks - Display the output of hdbuserstore - ansible.builtin.debug: - msg: "{{ __sap_hana_install_store_connection_information.stdout_lines }}" - tags: sap_hana_install_store_connection_information - when: __sap_hana_install_store_connection_information.stdout_lines is defined + - name: SAP HANA - Post-Tasks - Display the output of hdbuserstore + ansible.builtin.debug: + msg: "{{ __sap_hana_install_store_connection_information.stdout_lines }}" + tags: sap_hana_install_store_connection_information + when: __sap_hana_install_store_connection_information.stdout_lines is defined diff --git a/roles/sap_hana_install/tasks/pre_addhosts.yml b/roles/sap_hana_install/tasks/pre_addhosts.yml index aa9fe18d8..c7f688bb1 100644 --- a/roles/sap_hana_install/tasks/pre_addhosts.yml +++ b/roles/sap_hana_install/tasks/pre_addhosts.yml @@ -30,6 +30,7 @@ fail_msg: >- FAIL: User 'sapadm' with group 'sapsys' does not exist! +# TODO: Issue#1123 Remove default to master - name: SAP HANA - Addhosts - Pre-Tasks - Generate password hash for 'sap_hana_install_sapadm_password' ansible.builtin.shell: cmd: "set -o pipefail && echo '{{ sap_hana_install_sapadm_password | d(sap_hana_install_master_password) }}' | openssl passwd -6 -stdin" diff --git a/roles/sap_hana_install/tasks/pre_tasks/assert_variables.yml b/roles/sap_hana_install/tasks/pre_tasks/assert_variables.yml index b31e3af55..1d606bdab 100644 --- a/roles/sap_hana_install/tasks/pre_tasks/assert_variables.yml +++ b/roles/sap_hana_install/tasks/pre_tasks/assert_variables.yml @@ -81,3 +81,45 @@ This variable is required when 'sap_hana_install_new_system' is set to false. when: - not sap_hana_install_new_system + +# TODO: Issue#1123 Uncomment and update when fixing issue with use_master_password +# Master Password cannot be used in combination with other initial passwords +# Mandatory parameter 'password' (Password) is missing or invalid + +# # This will not replace user defined variables due to variable precedence. +# - name: SAP HANA - Pre-Tasks - Set password facts when using master password +# ansible.builtin.set_fact: +# sap_hana_install_sapadm_password: "{{ sap_hana_install_master_password }}" +# sap_hana_install_sidadm_password: "{{ sap_hana_install_master_password }}" +# sap_hana_install_db_system_password: "{{ sap_hana_install_master_password }}" +# sap_hana_install_ase_user_password: "{{ sap_hana_install_master_password }}" +# sap_hana_install_xs_org_password: "{{ sap_hana_install_master_password }}" +# sap_hana_install_lss_user_password: "{{ sap_hana_install_master_password }}" +# sap_hana_install_lss_backup_password: "{{ sap_hana_install_master_password }}" +# no_log: true +# when: +# - sap_hana_install_use_master_password is defined +# - sap_hana_install_use_master_password == 'y' + + +# - name: SAP HANA - Pre-Tasks - Assert that the variable 'sap_hana_install_sapadm_password' is defined as String and not empty +# ansible.builtin.assert: +# that: +# - sap_hana_install_sapadm_password is defined +# - sap_hana_install_sapadm_password is string +# - sap_hana_install_sapadm_password | trim | length > 0 +# success_msg: | +# PASS: The variable 'sap_hana_install_sapadm_password' is defined as String and not empty. +# fail_msg: | +# {% if sap_hana_install_sapadm_password is not defined %} +# FAIL: The variable 'sap_hana_install_sapadm_password' is not defined. +# {% elif sap_hana_install_sapadm_password is not string %} +# FAIL: The variable 'sap_hana_install_sapadm_password' is not String. +# {% else %} +# FAIL: The variable 'sap_hana_install_sapadm_password' is empty. +# {% endif %} +# This variable is required when 'sap_hana_install_new_system' is set to false. +# when: +# - not sap_hana_install_new_system +# - sap_hana_install_use_master_password is undefined +# or sap_hana_install_use_master_password != 'y' diff --git a/roles/sap_hana_install/tasks/pre_tasks/check_addhosts.yml b/roles/sap_hana_install/tasks/pre_tasks/check_addhosts.yml index 88d617048..fafebfad5 100644 --- a/roles/sap_hana_install/tasks/pre_tasks/check_addhosts.yml +++ b/roles/sap_hana_install/tasks/pre_tasks/check_addhosts.yml @@ -1,24 +1,10 @@ # SPDX-License-Identifier: Apache-2.0 --- -### Addhosts variables: -# __sap_hana_install_fact_addhosts_hosts -# - The list of all valid hostnames in addhosts string. -# - Used only for setting '__sap_hana_install_fact_addhosts_hosts_new' and '__sap_hana_install_fact_all_hosts'. - -# __sap_hana_install_fact_addhosts_hosts_new -# - The list of all valid hostnames in addhosts string without host with existing profiles or directories. -# - Used for replacing addhosts string in hdblcm configfile. - -# __sap_hana_install_fact_all_hosts -# - The list of all valid hostnames in addhosts string including Managed node. -# - Used for running all configuration tasks for idempotency. - - name: SAP HANA - Addhosts - Pre-Tasks - Set fact with list of additional hostnames ansible.builtin.set_fact: __sap_hana_install_fact_addhosts_hosts: "{{ sap_hana_install_addhosts.split(',') | map('trim') | reject('equalto', '') | map('regex_replace', ':.*$', '') | list }}" - __sap_hana_install_fact_addhosts_hosts_new: [] - name: SAP HANA - Addhosts - Pre-Tasks - Assert that the variable 'sap_hana_install_addhosts' is valid addhosts string ansible.builtin.assert: diff --git a/roles/sap_hana_install/tasks/pre_tasks/fapolicyd.yml b/roles/sap_hana_install/tasks/pre_tasks/fapolicyd.yml index 45d0ab931..534eb8280 100644 --- a/roles/sap_hana_install/tasks/pre_tasks/fapolicyd.yml +++ b/roles/sap_hana_install/tasks/pre_tasks/fapolicyd.yml @@ -22,4 +22,4 @@ "Stopping" in __sap_hana_install_register_disable_fapolicy.stdout failed_when: >- __sap_hana_install_register_disable_fapolicy.rc != 0 and - "package fapolicyd is not installed" not in __sap_hana_install_register_disable_fapolicy.stderr + "package fapolicyd is not installed" not in __sap_hana_install_register_disable_fapolicy.stdout diff --git a/roles/sap_hana_install/tasks/pre_tasks/hana_exists.yml b/roles/sap_hana_install/tasks/pre_tasks/hana_exists.yml index 493bddf00..e521a0691 100644 --- a/roles/sap_hana_install/tasks/pre_tasks/hana_exists.yml +++ b/roles/sap_hana_install/tasks/pre_tasks/hana_exists.yml @@ -1,12 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 --- -# Required to reset status if the role is used multiple times in one playbook. -- name: SAP HANA - Pre-Tasks - Reset the status variable if defined from previous run - ansible.builtin.set_fact: - __sap_hana_install_fact_is_installed: false - when: __sap_hana_install_fact_is_installed is defined - - name: SAP HANA - Pre-Tasks - Check if saphostctrl is installed ansible.builtin.stat: path: /usr/sap/hostctrl/exe/saphostctrl @@ -130,7 +124,7 @@ - sap_hana_install_groupid is defined - sap_hana_install_groupid is string - sap_hana_install_groupid | trim | length > 0 - - not __sap_hana_install_fact_is_installed | d(false) + - not __sap_hana_install_fact_is_installed block: # getent_groups will be populated, with fields: @@ -161,7 +155,7 @@ - name: SAP HANA - Pre-Tasks - SAP HANA admin user check when: - sap_hana_install_check_sidadm_user | d(true) - - not __sap_hana_install_fact_is_installed | d(false) + - not __sap_hana_install_fact_is_installed vars: __sap_hana_install_sidadm: "{{ sap_hana_install_sid | lower }}adm" block: @@ -187,7 +181,7 @@ This is required when the variable 'sap_hana_install_new_system' is set to false. when: - not sap_hana_install_new_system - - not __sap_hana_install_fact_is_installed | d(false) + - not __sap_hana_install_fact_is_installed - name: SAP HANA - Pre-Tasks - Run 'hdblcm --list_systems' for existing database ansible.builtin.shell: | diff --git a/roles/sap_hana_install/vars/main.yml b/roles/sap_hana_install/vars/main.yml index e2173a862..62e0dbff7 100644 --- a/roles/sap_hana_install/vars/main.yml +++ b/roles/sap_hana_install/vars/main.yml @@ -38,3 +38,18 @@ __sap_hana_install_architecture_matrix: # Example: SAPCAR_1400-80008313.EXE: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (GNU/Linux), dynamically linked, # interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=f40042b59e928aacfff753e59686be4d6e242998, for GNU/Linux 3.7.0, not stripped - ['aarch64'] + +# Sets default value of HANA exists detection. +__sap_hana_install_fact_is_installed: false + +# The list of all valid hostnames in addhosts string including Managed node. +# - Used for running all configuration tasks for idempotency. +__sap_hana_install_fact_all_hosts: [] + +# The list of all valid hostnames in addhosts string. +# - Used only for setting '__sap_hana_install_fact_addhosts_hosts_new' and '__sap_hana_install_fact_all_hosts'. +__sap_hana_install_fact_addhosts_hosts: [] + +# The list of all valid hostnames in addhosts string without host with existing profiles or directories. +# - Used for replacing addhosts string in hdblcm configfile. +__sap_hana_install_fact_addhosts_hosts_new: [] From 761113edc441fc79f38ea9f611657809e13b2da0 Mon Sep 17 00:00:00 2001 From: Marcel Mamula Date: Thu, 2 Oct 2025 15:40:18 +0200 Subject: [PATCH 4/4] implement hdbuserstore delegate with sync --- .../sap_hana_install/tasks/hana_addhosts.yml | 6 - roles/sap_hana_install/tasks/main.yml | 47 ++++++- .../sap_hana_install/tasks/post_addhosts.yml | 60 +-------- roles/sap_hana_install/tasks/post_install.yml | 66 ++-------- .../tasks/post_tasks/hdbuserstore.yml | 115 +++++++++++++++--- .../tasks/post_tasks/hdbuserstore_sync.yml | 60 +++++++++ .../tasks/pre_tasks/check_addhosts.yml | 18 ++- 7 files changed, 229 insertions(+), 143 deletions(-) create mode 100644 roles/sap_hana_install/tasks/post_tasks/hdbuserstore_sync.yml diff --git a/roles/sap_hana_install/tasks/hana_addhosts.yml b/roles/sap_hana_install/tasks/hana_addhosts.yml index 86cb47670..7188f7331 100644 --- a/roles/sap_hana_install/tasks/hana_addhosts.yml +++ b/roles/sap_hana_install/tasks/hana_addhosts.yml @@ -12,12 +12,6 @@ when: - item.split(':')[0] in __sap_hana_install_fact_addhosts_hosts_new -- name: Debug __sap_hana_install_addhosts - ansible.builtin.debug: - msg: | - old: {{ sap_hana_install_addhosts }} - new: {{ __sap_hana_install_addhosts }} - - name: SAP HANA - Addhosts - Update configfile with new addhosts string ansible.builtin.lineinfile: path: "{{ __sap_hana_install_register_tmpdir.path }}/configfile.cfg" diff --git a/roles/sap_hana_install/tasks/main.yml b/roles/sap_hana_install/tasks/main.yml index 3d6a9f297..91f1318c0 100644 --- a/roles/sap_hana_install/tasks/main.yml +++ b/roles/sap_hana_install/tasks/main.yml @@ -137,4 +137,49 @@ ansible.builtin.include_tasks: file: post_addhosts.yml -# TODO: Check hosts in post_install and compare against addhosts string, then debug explanation! + +# Show final status of SAP HANA System +# Gather details about installed database for finished message +- name: SAP HANA - Run 'hdblcm --list_systems' after the completion + ansible.builtin.shell: | + set -o pipefail && ./hdblcm --list_systems | awk '/\/hana\/shared\/{{ sap_hana_install_sid }}/{a=1} + /version:/{if (a==1){ + gsub ("^\\s*version: ", "");printf ("%s;", $NF)} + } + /hosts?:/{if (a==1){ + gsub ("^\\s*hosts?: ", ""); gsub (", ", ","); print; a=0} + }' + args: + chdir: "{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}/hdblcm" + register: __sap_hana_install_register_completion_result + changed_when: false + when: not ansible_check_mode + +- name: SAP HANA - Display SAP HANA details and completed post tasks + ansible.builtin.debug: + msg: | + SAP HANA database is installed and running: + HANA Version - {{ __sap_hana_install_fact_hana_version }} + Hosts - {{ __sap_hana_install_fact_hana_hosts }} + SID - {{ sap_hana_install_sid }} + NR - {{ sap_hana_install_number }} + + {% if sap_hana_install_new_system and __sap_hana_install_fact_is_installed and __sap_hana_install_fact_addhosts_hosts_new | length > 0 %} + The new hosts defined in the variable 'sap_hana_install_addhosts' were not added: {{ __sap_hana_install_fact_addhosts_hosts_new | join(', ') }}. + Execute this role with the variable 'sap_hana_install_new_system' set to false to add new hosts. + {% endif %} + + {% if sap_hana_install_update_firewall %} + Firewall is enabled and SAP HANA ports are open. + {% endif %} + {% if sap_hana_install_modify_selinux_labels %} + SELinux file contexts are configured for SAP folders '{{ sap_hana_install_root_path }}' and '/usr/sap'. + {% endif %} + {% if ansible_os_family == "RedHat" and sap_hana_install_use_fapolicyd %} + Fapolicyd is configured for SAP folders '{{ sap_hana_install_root_path }}' and '/usr/sap'. + {% endif %} + vars: + __sap_hana_install_fact_hana_version: "{{ __sap_hana_install_register_completion_result.stdout.split(';')[0] }}" + __sap_hana_install_fact_hana_hosts: "{{ __sap_hana_install_register_completion_result.stdout.split(';')[1] }}" + when: + - not ansible_check_mode diff --git a/roles/sap_hana_install/tasks/post_addhosts.yml b/roles/sap_hana_install/tasks/post_addhosts.yml index cadad81d7..a3235b22a 100644 --- a/roles/sap_hana_install/tasks/post_addhosts.yml +++ b/roles/sap_hana_install/tasks/post_addhosts.yml @@ -2,16 +2,6 @@ --- # Execute only on new addhosts, if present. -- name: SAP HANA - Addhosts - Post-Tasks - Store connection information - ansible.builtin.include_tasks: - file: post_tasks/hdbuserstore.yml - loop: "{{ __sap_hana_install_fact_addhosts_hosts_new }}" - loop_control: - loop_var: target_host - when: - - __sap_hana_install_fact_addhosts_hosts_new | length > 0 - tags: sap_hana_install_store_connection_information - - name: SAP HANA - Addhosts - Post-Tasks - Set user expiration ansible.builtin.include_tasks: file: post_tasks/user_expiration.yml @@ -24,6 +14,11 @@ # Execute on all hosts in play to achieve idempotency. +- name: SAP HANA - Addhosts - Post-Tasks - Update hdbuserstore connection details + ansible.builtin.include_tasks: + file: post_tasks/hdbuserstore.yml + tags: sap_hana_install_store_connection_information + - name: SAP HANA - Addhosts - Post-Tasks - Firewall ansible.builtin.include_tasks: file: post_tasks/firewall.yml @@ -52,48 +47,3 @@ - ansible_os_family == "RedHat" - sap_hana_install_use_fapolicyd tags: sap_hana_install_use_fapolicyd - - -# Gather details about installed database for finished message -- name: SAP HANA - Addhosts - Post-Tasks - Run 'hdblcm --list_systems' after the installation - ansible.builtin.shell: | - set -o pipefail && ./hdblcm --list_systems | awk '/\/hana\/shared\/{{ sap_hana_install_sid }}/{a=1} - /version:/{if (a==1){ - gsub ("^\\s*version: ", "");printf ("%s;", $NF)} - } - /hosts?:/{if (a==1){ - gsub ("^\\s*hosts?: ", ""); gsub (", ", ","); print; a=0} - }' - args: - chdir: "{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}/hdblcm" - register: __sap_hana_install_register_install_result - changed_when: false - when: not ansible_check_mode - -- name: SAP HANA - Addhosts - Post-Tasks - Set facts with HANA version and hosts - ansible.builtin.set_fact: - __sap_hana_install_fact_hana_version: "{{ __sap_hana_install_register_install_result.stdout.split(';')[0] }}" - __sap_hana_install_fact_hana_hosts: "{{ __sap_hana_install_register_install_result.stdout.split(';')[1] }}" - when: not ansible_check_mode - - -- name: SAP HANA - Addhosts - Post-Tasks - Display SAP HANA details and completed post tasks - ansible.builtin.debug: - msg: | - SAP HANA database is installed and running: - HANA Version - {{ __sap_hana_install_fact_hana_version }} - Hosts - {{ __sap_hana_install_fact_hana_hosts }} - SID - {{ sap_hana_install_sid }} - NR - {{ sap_hana_install_number }} - - {% if sap_hana_install_update_firewall %} - Firewall is enabled and SAP HANA ports are open. - {% endif %} - {% if sap_hana_install_modify_selinux_labels %} - SELinux file contexts are configured for SAP folders '{{ sap_hana_install_root_path }}' and '/usr/sap'. - {% endif %} - {% if ansible_os_family == "RedHat" and sap_hana_install_use_fapolicyd %} - Fapolicyd is configured for SAP folders '{{ sap_hana_install_root_path }}' and '/usr/sap'. - {% endif %} - when: - - not ansible_check_mode diff --git a/roles/sap_hana_install/tasks/post_install.yml b/roles/sap_hana_install/tasks/post_install.yml index ff3e8e033..b5242521f 100644 --- a/roles/sap_hana_install/tasks/post_install.yml +++ b/roles/sap_hana_install/tasks/post_install.yml @@ -7,14 +7,6 @@ - not __sap_hana_install_fact_is_installed block: - - name: SAP HANA - Install - Post-Tasks - Store connection information - ansible.builtin.include_tasks: - file: post_tasks/hdbuserstore.yml - loop: "{{ __sap_hana_install_fact_all_hosts }}" - loop_control: - loop_var: target_host - tags: sap_hana_install_store_connection_information - - name: SAP HANA - Install - Post-Tasks - Set log_mode ansible.builtin.include_tasks: file: post_tasks/log_mode.yml @@ -70,10 +62,16 @@ when: sap_hana_install_cleanup_configfile_directory +# Execute on all hosts in play to achieve idempotency. +- name: SAP HANA - Install - Post-Tasks - Update hdbuserstore connection details + ansible.builtin.include_tasks: + file: post_tasks/hdbuserstore.yml + tags: sap_hana_install_store_connection_information + - name: SAP HANA - Install - Post-Tasks - Firewall ansible.builtin.include_tasks: file: post_tasks/firewall.yml - loop: "{{ __sap_hana_install_fact_all_hosts if not __sap_hana_install_fact_is_installed else [inventory_hostname_short] }}" + loop: "{{ __sap_hana_install_fact_all_hosts }}" loop_control: loop_var: target_host when: sap_hana_install_update_firewall @@ -98,53 +96,3 @@ - ansible_os_family == "RedHat" - sap_hana_install_use_fapolicyd tags: sap_hana_install_use_fapolicyd - - -# Gather details about installed database for finished message -- name: SAP HANA - Install - Post-Tasks - Run 'hdblcm --list_systems' after the installation - ansible.builtin.shell: | - set -o pipefail && ./hdblcm --list_systems | awk '/\/hana\/shared\/{{ sap_hana_install_sid }}/{a=1} - /version:/{if (a==1){ - gsub ("^\\s*version: ", "");printf ("%s;", $NF)} - } - /hosts?:/{if (a==1){ - gsub ("^\\s*hosts?: ", ""); gsub (", ", ","); print; a=0} - }' - args: - chdir: "{{ sap_hana_install_shared_path }}/{{ sap_hana_install_sid }}/hdblcm" - register: __sap_hana_install_register_install_result - changed_when: false - when: not ansible_check_mode - -- name: SAP HANA - Install - Post-Tasks - Set facts with HANA version and hosts - ansible.builtin.set_fact: - __sap_hana_install_fact_hana_version: "{{ __sap_hana_install_register_install_result.stdout.split(';')[0] }}" - __sap_hana_install_fact_hana_hosts: "{{ __sap_hana_install_register_install_result.stdout.split(';')[1] }}" - when: not ansible_check_mode - - -- name: SAP HANA - Install - Post-Tasks - Display SAP HANA details and completed post tasks - ansible.builtin.debug: - msg: | - SAP HANA database is installed and running: - HANA Version - {{ __sap_hana_install_fact_hana_version }} - Hosts - {{ __sap_hana_install_fact_hana_hosts }} - SID - {{ sap_hana_install_sid }} - NR - {{ sap_hana_install_number }} - - {% if sap_hana_install_new_system and __sap_hana_install_fact_is_installed and __sap_hana_install_fact_addhosts_hosts | length > 0 %} - The hosts defined in the variable 'sap_hana_install_addhosts' were not added. - Execute this role with the variable 'sap_hana_install_new_system' set to false to add new hosts. - {% endif %} - - {% if sap_hana_install_update_firewall %} - Firewall is enabled and SAP HANA ports are open. - {% endif %} - {% if sap_hana_install_modify_selinux_labels %} - SELinux file contexts are configured for SAP folders '{{ sap_hana_install_root_path }}' and '/usr/sap'. - {% endif %} - {% if ansible_os_family == "RedHat" and sap_hana_install_use_fapolicyd %} - Fapolicyd is configured for SAP folders '{{ sap_hana_install_root_path }}' and '/usr/sap'. - {% endif %} - when: - - not ansible_check_mode diff --git a/roles/sap_hana_install/tasks/post_tasks/hdbuserstore.yml b/roles/sap_hana_install/tasks/post_tasks/hdbuserstore.yml index 112a7286c..0f6388302 100644 --- a/roles/sap_hana_install/tasks/post_tasks/hdbuserstore.yml +++ b/roles/sap_hana_install/tasks/post_tasks/hdbuserstore.yml @@ -1,26 +1,101 @@ # SPDX-License-Identifier: Apache-2.0 --- -- name: Block to delegate_to all tasks - delegate_to: "{{ target_host }}" +# Executed only for new installations to avoid overwriting existing configuration. +- name: SAP HANA - Post-Tasks - hdbuserstore - Add key {{ sap_hana_install_hdbuserstore_key }} + ansible.builtin.shell: | + /usr/sap/{{ sap_hana_install_sid }}/SYS/exe/hdb/hdbuserstore \ + SET {{ sap_hana_install_hdbuserstore_key }} \ + {{ ansible_hostname }}:3{{ sap_hana_install_number }}13 \ + SYSTEM '{{ sap_hana_install_db_system_password | d(sap_hana_install_master_password) }}' + args: + executable: /bin/bash + become: true + become_user: "{{ sap_hana_install_sid | lower }}adm" + changed_when: true + when: + - not ansible_check_mode + - not __sap_hana_install_fact_is_installed + +- name: SAP HANA - Post-Tasks - hdbuserstore - Execute 'hdbuserstore list' command + ansible.builtin.shell: + cmd: "/usr/sap/{{ sap_hana_install_sid }}/SYS/exe/hdb/hdbuserstore list" + args: + executable: /bin/bash + become: true + become_user: "{{ sap_hana_install_sid | lower }}adm" + register: __sap_hana_install_register_hdbuserstore_list + changed_when: false + failed_when: false + +- name: SAP HANA - Post-Tasks - hdbuserstore - Inform if command 'hdbuserstore list' failed for existing installation + ansible.builtin.debug: + msg: | + Command '/usr/sap/{{ sap_hana_install_sid }}/SYS/exe/hdb/hdbuserstore list' was not successful! Proceeding with remaining tasks. + {{ __sap_hana_install_register_hdbuserstore_list.stdout_lines }} + when: + - __sap_hana_install_register_hdbuserstore_list.rc != 0 + - __sap_hana_install_fact_is_installed + - __sap_hana_install_fact_addhosts_hosts | length == 0 + +- name: SAP HANA - Post-Tasks - hdbuserstore - Fail if command 'hdbuserstore list' failed for new installation or addhosts + ansible.builtin.fail: + msg: | + FAIL: Command '/usr/sap/{{ sap_hana_install_sid }}/SYS/exe/hdb/hdbuserstore list' was not successful! + {% if __sap_hana_install_fact_addhosts_hosts | length > 0 %} + Synchronization to all hosts will not be performed until issues are resolved. + {% endif %} + {{ __sap_hana_install_register_hdbuserstore_list.stdout_lines }} + when: + - __sap_hana_install_register_hdbuserstore_list.rc != 0 + - (__sap_hana_install_fact_addhosts_hosts | length > 0 or not __sap_hana_install_fact_is_installed) + + +# Following steps are required only when adding hosts. +# We will use 'KEY FILE' and 'DATA FILE' from 'hdbuserstore list' to get real path of files without assuming. +- name: Block to get content of files + when: + - __sap_hana_install_register_hdbuserstore_list.rc == 0 + - __sap_hana_install_fact_addhosts_hosts | length > 0 block: - - name: SAP HANA - Post-Tasks - Create and Store Connection Info in hdbuserstore - ansible.builtin.shell: | - /usr/sap/{{ sap_hana_install_sid }}/SYS/exe/hdb/hdbuserstore \ - SET {{ sap_hana_install_hdbuserstore_key }} \ - {{ ansible_hostname }}:3{{ sap_hana_install_number }}13 \ - SYSTEM '{{ sap_hana_install_db_system_password | d(sap_hana_install_master_password) }}' - args: - executable: /bin/bash + - name: SAP HANA - Post-Tasks - hdbuserstore - Parse command 'hdbuserstore list' output to find file paths + ansible.builtin.set_fact: + __sap_hana_install_fact_hdbuserstore_key_path: + "{{ (__sap_hana_install_register_hdbuserstore_list.stdout_lines | select('search', '^KEY FILE') | first).split(':')[1] | trim }}" + __sap_hana_install_fact_hdbuserstore_data_path: + "{{ (__sap_hana_install_register_hdbuserstore_list.stdout_lines | select('search', '^DATA FILE') | first).split(':')[1] | trim }}" + + - name: SAP HANA - Post-Tasks - hdbuserstore - Fail if file paths were not parsed + ansible.builtin.fail: + msg: | + FAIL: Command 'hdbuserstore list' did not contain 'KEY FILE' or 'DATA FILE' paths. + Synchronization to all hosts will not be performed until issues are resolved. + when: + - __sap_hana_install_fact_hdbuserstore_key_path is not defined + or __sap_hana_install_fact_hdbuserstore_key_path | length == 0 + or __sap_hana_install_fact_hdbuserstore_data_path is not defined + or __sap_hana_install_fact_hdbuserstore_data_path | length == 0 + + - name: SAP HANA - Post-Tasks - hdbuserstore - Slurp contents of 'KEY FILE' + ansible.builtin.slurp: + src: "{{ __sap_hana_install_fact_hdbuserstore_key_path }}" + register: __sap_hana_install_register_hdbuserstore_key_slurp + become: true + become_user: "{{ sap_hana_install_sid | lower }}adm" + no_log: true + + - name: SAP HANA - Post-Tasks - hdbuserstore - Slurp contents of 'DATA FILE' + ansible.builtin.slurp: + src: "{{ __sap_hana_install_fact_hdbuserstore_data_path }}" + register: __sap_hana_install_register_hdbuserstore_data_slurp become: true become_user: "{{ sap_hana_install_sid | lower }}adm" - when: not ansible_check_mode - changed_when: false - register: __sap_hana_install_store_connection_information - tags: sap_hana_install_store_connection_information - - - name: SAP HANA - Post-Tasks - Display the output of hdbuserstore - ansible.builtin.debug: - msg: "{{ __sap_hana_install_store_connection_information.stdout_lines }}" - tags: sap_hana_install_store_connection_information - when: __sap_hana_install_store_connection_information.stdout_lines is defined + no_log: true + + + - name: SAP HANA - Post-Tasks - hdbuserstore - Start sync of hdbuserstore to hosts + ansible.builtin.include_tasks: + file: hdbuserstore_sync.yml + loop: "{{ __sap_hana_install_fact_addhosts_hosts }}" + loop_control: + loop_var: target_host diff --git a/roles/sap_hana_install/tasks/post_tasks/hdbuserstore_sync.yml b/roles/sap_hana_install/tasks/post_tasks/hdbuserstore_sync.yml new file mode 100644 index 000000000..be42c9a51 --- /dev/null +++ b/roles/sap_hana_install/tasks/post_tasks/hdbuserstore_sync.yml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: Apache-2.0 +--- + +# This file will synchronize hdbuserstore files from the managed node. +- name: Block to delegate_to all tasks + delegate_to: "{{ target_host }}" + become: true + vars: + __sap_hana_install_fact_hdbuserstore_key_path_target: + "{{ __sap_hana_install_fact_hdbuserstore_key_path | replace(ansible_hostname, target_host) }}" + __sap_hana_install_fact_hdbuserstore_data_path_target: + "{{ __sap_hana_install_fact_hdbuserstore_data_path | replace(ansible_hostname, target_host) }}" + block: + - name: SAP HANA - Post-Tasks - hdbuserstore - Check for if KEY file exists + ansible.builtin.stat: + path: "{{ __sap_hana_install_fact_hdbuserstore_key_path_target }}" + register: __sap_hana_install_register_hdbuserstore_key_stat_target + + - name: SAP HANA - Post-Tasks - hdbuserstore - Check for if DATA file exists + ansible.builtin.stat: + path: "{{ __sap_hana_install_fact_hdbuserstore_data_path_target }}" + register: __sap_hana_install_register_hdbuserstore_data_stat_target + + # We need to ensure that copy is started only if both files are absent. + - name: Block to copy files if they do not exist + when: + - not __sap_hana_install_register_hdbuserstore_key_stat_target.stat.exists + - not __sap_hana_install_register_hdbuserstore_data_stat_target.stat.exists + block: + - name: SAP HANA - Post-Tasks - hdbuserstore - Create directory for hdbuserstore files + ansible.builtin.file: + path: "{{ __sap_hana_install_fact_hdbuserstore_key_path_target | dirname }}" + state: directory + owner: "{{ sap_hana_install_sid | lower }}adm" + group: "sapsys" + mode: '0700' + + - name: SAP HANA - Post-Tasks - hdbuserstore - Create KEY file + ansible.builtin.copy: + content: "{{ __sap_hana_install_register_hdbuserstore_key_slurp.content | b64decode }}" + dest: "{{ __sap_hana_install_fact_hdbuserstore_key_path_target }}" + owner: "{{ sap_hana_install_sid | lower }}adm" + group: "sapsys" + mode: '0600' + + - name: SAP HANA - Post-Tasks - hdbuserstore - Create DATA file + ansible.builtin.copy: + content: "{{ __sap_hana_install_register_hdbuserstore_data_slurp.content | b64decode }}" + dest: "{{ __sap_hana_install_fact_hdbuserstore_data_path_target }}" + owner: "{{ sap_hana_install_sid | lower }}adm" + group: "sapsys" + mode: '0600' + + - name: SAP HANA - Post-Tasks - hdbuserstore - Inform that existing hdbuserstore key files were found + ansible.builtin.debug: + msg: | + Existing KEY or DATA files were found and synchronization was skipped. + when: + - __sap_hana_install_register_hdbuserstore_key_stat_target.stat.exists + or __sap_hana_install_register_hdbuserstore_data_stat_target.stat.exists diff --git a/roles/sap_hana_install/tasks/pre_tasks/check_addhosts.yml b/roles/sap_hana_install/tasks/pre_tasks/check_addhosts.yml index fafebfad5..0696570e1 100644 --- a/roles/sap_hana_install/tasks/pre_tasks/check_addhosts.yml +++ b/roles/sap_hana_install/tasks/pre_tasks/check_addhosts.yml @@ -1,10 +1,11 @@ # SPDX-License-Identifier: Apache-2.0 --- +# Difference ensures that our addhosts list does not contain Managed node. - name: SAP HANA - Addhosts - Pre-Tasks - Set fact with list of additional hostnames ansible.builtin.set_fact: __sap_hana_install_fact_addhosts_hosts: - "{{ sap_hana_install_addhosts.split(',') | map('trim') | reject('equalto', '') | map('regex_replace', ':.*$', '') | list }}" + "{{ sap_hana_install_addhosts.split(',') | map('trim') | reject('equalto', '') | map('regex_replace', ':.*$', '') | list | difference([inventory_hostname_short]) }}" - name: SAP HANA - Addhosts - Pre-Tasks - Assert that the variable 'sap_hana_install_addhosts' is valid addhosts string ansible.builtin.assert: @@ -56,10 +57,23 @@ ) }} +# We need to reset hosts list and remove new, if HANA is installed and 'sap_hana_install_new_system' is 'true'. +# This ensures that post-tasks are idempotent for those hosts that already exist, not new. +- name: SAP HANA - Addhosts - Pre-Tasks - Reset fact with list of new hosts if Add + ansible.builtin.set_fact: + __sap_hana_install_fact_addhosts_hosts: + "{{ __sap_hana_install_fact_addhosts_hosts | difference(__sap_hana_install_fact_addhosts_hosts_new) }}" + when: + - sap_hana_install_new_system + - __sap_hana_install_fact_is_installed + - __sap_hana_install_fact_addhosts_hosts_new | length > 0 + - name: SAP HANA - Addhosts - Pre-Tasks - Show lists of hosts to be added ansible.builtin.debug: msg: "New hosts will be added: {{ __sap_hana_install_fact_addhosts_hosts_new | join(', ') }}" - when: __sap_hana_install_fact_addhosts_hosts_new | length > 0 + when: + - __sap_hana_install_fact_addhosts_hosts_new | length > 0 + - not (sap_hana_install_new_system and __sap_hana_install_fact_is_installed) # Test SSH connection from managed node to addhosts hosts is not implemented because