deploy/ansible/playbook_00_validate_parameters.yaml (641 lines of code) (raw):
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
---
# /*---------------------------------------------------------------------------8
# | |
# | Validate the parameters |
# | |
# +------------------------------------4--------------------------------------*/
- hosts: localhost
name: "0.0 Validations"
gather_facts: true
vars_files:
- vars/ansible-input-api.yaml # API Input template with defaults
# -------------------------------------+---------------------------------------8
#
# Build the list of tasks to be executed in order here.
#
# -------------------------------------+---------------------------------------8
tasks:
- name: "0.0 Validations - Show SDAF Version"
ansible.builtin.debug:
msg:
- "SDAF Version: {{ SDAF_Version }}"
tags:
- always
- name: "0.0 Validations - Ensure jmespath is installed on the controller"
ansible.builtin.pip:
name: jmespath
state: present
tags:
- always
- name: "0.0 Validations - Ensure netaddr is installed in the controller"
ansible.builtin.pip:
name: netaddr
state: present
tags:
- always
# - name: "0.0 Validations - ensure credssp is installed in the controller"
# ansible.builtin.pip:
# name: 'pywinrm[credssp]'
# state: present
# failed_when: false
- name: "0.0 Validations - Create Progress folder"
ansible.builtin.file:
path: "{{ _workspace_directory }}/.progress"
state: directory
mode: 0755
tags:
- always
- name: "0.0 Validations - Remove os-install-done flag"
ansible.builtin.file:
path: "{{ _workspace_directory }}/.progress/validation-done"
state: absent
tags:
- always
# -------------------------------------+---------------------------------------8
#
# Ensure cluster determining parameters are present
#
# -------------------------------------+---------------------------------------8
- name: "Backward Compatibility - Check required Database HA variables "
ansible.builtin.set_fact:
database_high_availability: "{{ db_high_availability | default(false) }}"
when:
- db_high_availability is defined
- database_high_availability is not defined
tags:
- always
- name: "0.0 Validations - Check required variables are present and not empty"
ansible.builtin.assert:
that:
- item_to_check.parameter is defined # Has the variable been defined
- item_to_check.parameter | type_debug != 'NoneType' # Is the variable not empty"
- item_to_check.parameter | trim | length > 1
fail_msg: "{{ item_to_check.error }}"
loop:
- { parameter: "database_high_availability", error: "database_high_availability has no value assigned" }
- { parameter: "database_cluster_type", error: "database_cluster_type has no value assigned" }
- { parameter: "scs_high_availability", error: "scs_high_availability has no value assigned" }
- { parameter: "scs_cluster_type", error: "scs_cluster_type has no value assigned" }
- { parameter: "use_msi_for_clusters", error: "use_msi_for_clusters has no value assigned" }
- { parameter: "platform", error: "platform has no value assigned" }
loop_control:
loop_var: item_to_check
tags:
- always
# -------------------------------------+---------------------------------------8
#
# Show parameters used for cluster aware coding
#
# -------------------------------------+---------------------------------------8
- name: "Cluster aware code..."
ansible.builtin.debug:
msg: # Best method for formatting output with Azure Devops Logs
- "database_high_availability: {{ database_high_availability }}"
- "database_cluster_type: {{ database_cluster_type }}"
- "scs_high_availability: {{ scs_high_availability }}"
- "scs_cluster_type: {{ scs_cluster_type }}"
- "use_msi_for_clusters: {{ use_msi_for_clusters }}"
- "platform: {{ platform | upper }}"
verbosity: 2
tags:
- always
# -------------------------------------+
# Fencing support is only needed when:
# database_high_availability is true AND database_cluster_type is AFA (Azure Fencing Agent)
# OR
# scs_high_availability is true AND scs_cluster_type is AFA (Azure Fencing Agent)
#
# - name: fencing
# block:
# # - name: "0.0 Validations - Initialize tier"
# # ansible.builtin.set_fact:
# # tier: fencing
# - name: "0.0 Validations - Retrieve the Fencing SPN details"
# ansible.builtin.include_role:
# name: roles-misc/0.2-kv-secrets
# when: platform != "ORACLE"
# tags:
# - kv-secrets
# when: (database_high_availability and database_cluster_type == "AFA") or
# (scs_high_availability and scs_cluster_type == "AFA")
- name: "0.0 Validations - Retrieve the Fencing SPN details"
ansible.builtin.include_role:
name: roles-misc/0.2-kv-secrets
vars:
operation: fencing
when:
- (database_high_availability and database_cluster_type == "AFA") or
(scs_high_availability and scs_cluster_type == "AFA")
- platform != "ORACLE"
tags:
- always
- kv-secrets
# -------------------------------------+
- name: "0.0 Validations - Retrieve the domain passwords"
ansible.builtin.include_role:
name: roles-misc/0.1-passwords
tasks_from: windows.yaml
public: true
tags:
- always
- 0.1-win-passwords
when:
- platform == "SQLSERVER"
- name: "0.0 Validations - Retrieve the storage account details"
ansible.builtin.include_role:
name: roles-misc/0.3.sap-installation-media-storage-details
public: true
tags:
- always
- kv-sap-installation-media-storage-details
- name: "0.0 Validations - Check required variables are present and not empty"
ansible.builtin.assert:
that:
- item_to_check.parameter is defined # Has the variable been defined
- item_to_check.parameter | type_debug != 'NoneType' # Is the variable not empty"
- item_to_check.parameter | trim | length > 1
fail_msg: "{{ item_to_check.error }}"
loop:
- {
parameter: "bom_base_name",
error: "Please provide the Bill of materials name in bom_base_name parameter",
}
- {
parameter: "kv_name",
error: "Please provide the workload zone key vault name in kv_name parameter",
}
- {
parameter: "sap_fqdn",
error: "Please provide the SAP fqdn in in sap_fqdn parameter",
}
- {
parameter: "sap_sid",
error: "Please provide the SAP SID in sap_sid parameter",
}
- {
parameter: "secret_prefix",
error: "Please provide the Key Vault secret prefix in secret_prefix parameter",
}
- {
parameter: "sapbits_location_base_path",
error: "Please provide the sapbits_location_base_path in the deployer key vault",
}
loop_control:
loop_var: item_to_check
tags:
- always
- name: "0.0 Validations - Check required SCS HA variables are present and not empty"
ansible.builtin.assert:
that:
- item_to_check.parameter is defined # Has the variable been defined
- item_to_check.parameter | type_debug != 'NoneType' # Is the variable not empty"
- item_to_check.parameter | trim | length > 1
fail_msg: "{{ item_to_check.error }}"
loop:
- {
parameter: "NFS_provider",
error: "A highly available SCS deployment requires that NFS_Provider provided",
}
- {
parameter: "sap_mnt",
error: "A highly available SCS deployment requires a shared sap_mnt is provided",
}
- {
parameter: "scs_lb_ip",
error: "A highly available SCS deployment requires that scs_lb_ip is provided",
}
- {
parameter: "ecs_lb_ip",
error: "A highly available SCS deployment requires that ers_lb_ip is provided",
}
loop_control:
loop_var: item_to_check
when:
- scs_high_availability
- platform != "SQLSERVER"
tags:
- always
- name: "0.0 Validations - Check required SCS HA fencing variables are present and not empty"
ansible.builtin.assert:
that:
- item_to_check.parameter is defined # Has the variable been defined
- item_to_check.parameter | type_debug != 'NoneType' # Is the variable not empty"
- item_to_check.parameter | trim | length > 1
fail_msg: "{{ item_to_check.error }}"
loop:
- {
parameter: "fencing_spn_client_id",
error: "A highly available SCS deployment requires that an SPN is defined for the fencing agent",
}
- {
parameter: "fencing_spn_client_pwd",
error: "A highly available SCS deployment requires that an SPN is defined for the fencing agent",
}
- {
parameter: "fencing_spn_subscription_id",
error: "A highly available SCS deployment requires that an SPN is defined for the fencing agent",
}
- {
parameter: "fencing_spn_tenant_id",
error: "A highly available SCS deployment requires that an SPN is defined for the fencing agent",
}
loop_control:
loop_var: item_to_check
when:
# - scs_high_availability
- (scs_high_availability and scs_cluster_type == "AFA")
- not use_msi_for_clusters
tags:
- always
- name: "0.0 Validations - Check required Database HA variables are present and not empty"
ansible.builtin.assert:
that:
- item_to_check.parameter is defined # Has the variable been defined
- item_to_check.parameter | type_debug != 'NoneType' # Is the variable not empty"
- item_to_check.parameter | trim | length > 1
fail_msg: "{{ item_to_check.error }}"
loop:
- {
parameter: "database_loadbalancer_ip",
error: "A highly available SCS deployment requires that scs_lb_ip is provided",
}
- {
parameter: "fencing_spn_client_id",
error: "A highly available SCS deployment requires that an SPN is defined for the fencing agent",
}
- {
parameter: "fencing_spn_client_pwd",
error: "A highly available SCS deployment requires that an SPN is defined for the fencing agent",
}
- {
parameter: "fencing_spn_subscription_id",
error: "A highly available SCS deployment requires that an SPN is defined for the fencing agent",
}
- {
parameter: "fencing_spn_tenant_id",
error: "A highly available SCS deployment requires that an SPN is defined for the fencing agent",
}
loop_control:
loop_var: item_to_check
when:
# - db_high_availability
- (database_high_availability and database_cluster_type == "AFA")
- platform in ["HANA", "DB2"]
tags:
- always
- name: "0.0 Validations - sharedHome variables"
ansible.builtin.debug:
var: sid_to_be_deployed
when: MULTI_SIDS is defined
loop: "{{ MULTI_SIDS }}"
loop_control:
loop_var: sid_to_be_deployed
tags:
- always
- name: "0.0 Validations - Validate ORACLE parameters (ora_release and ora_version)"
when:
- platform in ['ORACLE', 'ORACLE-ASM']
ansible.builtin.assert:
that:
- ora_release is version(ora_supported_version,'>=')
- ora_version is version(ora_supported_version,'>=')
fail_msg: "Oracle deployments requires that ora_release and ora_version are provided"
tags:
- always
- name: "0.0 Validations - Validate ORACLE parameters (oracle_sbp_patch)"
when:
- platform in ['ORACLE', 'ORACLE-ASM']
ansible.builtin.assert:
that:
- oracle_sbp_patch is defined
- oracle_sbp_patch | default('') | trim | length > 1
fail_msg: "Oracle deployments requires that oracle_sbp_patch is provided"
tags:
- always
- name: "0.0 Validations - Show ORACLE parameters"
when:
- platform in ['ORACLE', 'ORACLE-ASM']
ansible.builtin.debug:
msg:
- "ora_release: {{ ora_release }}"
- "ora_version: {{ ora_version }}"
- "oracle_sbp_patch: {{ oracle_sbp_patch }}"
tags:
- always
- name: "0.0 Validations - Validate SQL Server parameters"
when:
- platform == 'SQLSERVER'
ansible.builtin.assert:
that:
- domain_name is defined # Has the variable been defined
- domain_name | type_debug != 'NoneType' # Does it have a value
- domain_name | trim | length > 1
fail_msg: 'SQL Server deployments require that domain is specified'
tags:
- always
- name: "0.0 Validations - Get Access Token"
ansible.builtin.command: >-
az account get-access-token --query accessToken -o tsv
changed_when: false
register: access_token_data
no_log: true
tags:
- always
- name: "0.0 Validations - Save the access token"
ansible.builtin.set_fact:
access_token: "{{ access_token_data.stdout }}"
no_log: true
tags:
- always
- name: "0.0 Validations - Retrieve Subscription ID and Resource Group Name"
ansible.builtin.uri:
url: http://169.254.169.254/metadata/instance?api-version=2021-02-01
use_proxy: false
headers:
Metadata: true
register: azure_metadata
tags:
- always
- name: "0.0 Validations - Show IMDS results (JSON)"
ansible.builtin.debug:
var: azure_metadata.json
verbosity: 2
- name: "0.0 Validations - Extract details"
ansible.builtin.set_fact:
subscription_id: "{{ azure_metadata.json.compute.subscriptionId }}"
resource_group_name: "{{ azure_metadata.json.compute.resourceGroupName }}"
mnt_free_diskspace: "{{ ansible_mounts | json_query('[?mount == `/mnt`].size_available') }}"
tags:
- always
- name: "0.0 Validations - Show IMDS results"
ansible.builtin.debug:
var: mnt_free_diskspace
tags:
- always
- name: "0.0 Validations - Deployer disk space requirements"
ansible.builtin.set_fact:
deployer_free_temp_disk_space: 40
when:
- deployer_free_temp_disk_space is not defined
tags:
- always
- name: "0.0 Validations - Check for free disk space on deployer"
ansible.builtin.assert:
that: (mnt_free_diskspace | first | int / (1024 * 1024 * 1024) | int) > ( deployer_free_temp_disk_space )
fail_msg: "The deployer needs at least {{ deployer_free_temp_disk_space }} GB of free disk space in /mnt"
when:
- mnt_free_diskspace | length > 0
tags:
- 0.0-agent-diskspace
- name: "0.0 Validations - Check SAP CAL variables are present and not empty"
when: enable_sap_cal is defined and enable_sap_cal
ansible.builtin.assert:
that:
- calapi_kv is defined
- calapi_kv | type_debug != 'NoneType'
- calapi_kv | trim | length > 1
fail_msg: "Please provide the SAP CAL API key vault name in calapi_kv parameter"
tags:
- always
# /*---------------------------------------------------------------------------8
# | |
# | Validate the server side parameters |
# | |
# +------------------------------------4--------------------------------------*/
- hosts: "{{ sap_sid | upper }}_DB :
{{ sap_sid | upper }}_SCS :
{{ sap_sid | upper }}_ERS :
{{ sap_sid | upper }}_PAS :
{{ sap_sid | upper }}_APP :
{{ sap_sid | upper }}_WEB :
{{ sap_sid | upper }}_OBSERVER_DB"
name: "0.0 Validations - Validate SAP-Parameters"
gather_facts: false
vars_files:
- vars/ansible-input-api.yaml # API Input template with defaults
tasks:
- name: "0.0 Validations: - Wait for system to become reachable"
ansible.builtin.wait_for_connection:
timeout: 120
register: wait_for_connection_results
tags:
- always
- name: "0.0 Validations: - Gather facts for first time"
ansible.builtin.setup:
tags:
- always
- name: "0.0 Validations: - Set distro"
ansible.builtin.set_fact:
distro_family: "{{ ansible_os_family | upper }}"
distribution_id: "{{ ansible_distribution | lower ~ ansible_distribution_major_version }}"
distribution_full_id: "{{ ansible_distribution | lower ~ ansible_distribution_version }}"
tags:
- always
- name: "0.0 Validations: - Show distro"
ansible.builtin.debug:
msg:
- "Distro family: {{ distro_family }}"
- "Distribution id: {{ distribution_id }}"
- "Distribution full id: {{ distribution_full_id }}"
tags:
- always
- name: "0.0 Validations: - Set Python version {{ distribution_id }}"
when: (ansible_distribution | lower ~ ansible_distribution_major_version) in ['sles_sap12']
ansible.builtin.set_fact:
python_version: "python2"
tags:
- always
- name: "0.0 Validations - Get details from local host"
ansible.builtin.set_fact:
subscription_id: "{{ hostvars.localhost.subscription_id }}"
resource_group_name: "{{ hostvars.localhost.resource_group_name }}"
access_token: "{{ hostvars.localhost.access_token }}"
no_log: true
tags:
- always
- name: "0.0 Validations - Variables"
ansible.builtin.debug:
var: hostvars
verbosity: 4
- name: "0.0 Validations - groupsnames"
ansible.builtin.debug:
var: group_names
verbosity: 4
- name: "0.0 Validations - Variables"
ansible.builtin.debug:
msg:
- "Virtual Host Name: {{ virtual_host }}"
- "DNS: {{ ansible_domain }}"
- name: "0.0 Validations - Validate SCS and HDB instance numbers"
ansible.builtin.assert:
that:
- "scs_instance_number != db_instance_number"
fail_msg: "Please ensure that the scs_instance_number is different from the db_instance_number when performing a standalone installation"
when:
- single_server
- platform == "HANA"
tags:
- always
- 0.0-scs-db-instance-single
- name: "0.0 Validations - Validate SCS and HDB SIDs"
when:
- single_server
- platform != "ORACLE"
ansible.builtin.assert:
that:
- "sap_sid != db_sid"
fail_msg: "Please ensure that the sap_sid is different from the db_sid when performing a standalone installation"
tags:
- always
- name: Validate SCS and PAS instance numbers
ansible.builtin.assert:
that:
- scs_instance_number != pas_instance_number
fail_msg: "Please ensure that the pas_instance_number is different from the scs_instance_number when installing PAS on ASCS"
when: (ansible_play_hosts_all | length) == 2
tags:
- always
- 0.0-scs-pas
- name: "0.0 Validations - Validate SCS and PAS instance numbers"
ansible.builtin.assert:
that:
- scs_instance_number != pas_instance_number
fail_msg: "Please ensure that the pas_instance_number is different from the scs_instance_number on standalone installation"
when: single_server
tags:
- always
- 0.0-scs-pas-single
- name: "0.0 Validations - Validate DB and PAS instance numbers"
ansible.builtin.assert:
that:
- db_instance_number != pas_instance_number
fail_msg: "Please ensure that the pas_instance_number is different from the db_instance_number on standalone installation"
when: single_server
tags:
- always
- 0.0-scs-pas-db-single
# url: "https://management.azure.com/subscriptions/{{ subscription_id }}/providers/Microsoft.Web/sites?api-version=2022-03-01"
# url: "https://azure.status.microsoft/en-us/status"
- name: "0.0 Validations - Check internet connectivity"
ansible.builtin.uri:
url: "{{ url_internet }}"
# headers:
# Authorization: "Bearer {{ access_token }}"
# Content-Type: application/json
# Accept: application/json
status_code:
- 200
- 403
register: internet_check
vars:
ansible_python_interpreter: "{{ python_version }}"
when:
- (ansible_distribution | lower ~ ansible_distribution_major_version) in ['suse15', 'redhat8', 'redhat9', 'sles_sap15' ]
- ansible_os_family != "Windows"
- check_outbound | bool
tags:
- always
- 0.0-internet
- name: "0.0 Validations - Check internet connectivity"
ansible.builtin.uri:
url: "https://management.azure.com/subscriptions/{{ subscription_id }}/providers/Microsoft.Web/sites?api-version=2022-03-01"
headers:
Authorization: "Bearer {{ access_token }}"
Content-Type: application/json
Accept: application/json
status_code:
- 200
- 403
when:
- (ansible_distribution | lower ~ ansible_distribution_major_version) in ['suse15', 'redhat8', 'redhat9', 'sles_sap15' ]
- ansible_os_family != "Windows"
- check_outbound | bool
tags:
- always
- 0.0-internet
- name: "0.0 Validations - Show Mounts"
ansible.builtin.debug:
msg:
- "Mount: {{ item.mount }}"
- "Device: {{ item.device }}"
- "Filesystem: {{ item.fstype }}"
with_items:
- "{{ ansible_mounts }}"
when:
- ansible_os_family != "Windows"
- name: "0.0 Validations - Create directories"
become: true
ansible.builtin.file:
path: '/etc/sap_deployment_automation/{{ sap_sid | upper }}'
state: directory
mode: '0755'
when:
- ansible_os_family != "Windows"
tags:
- always
- name: "0.0 Validations - Show Hosts"
when:
- ansible_os_family != "Windows"
ansible.builtin.shell: set -o pipefail && cat /etc/hosts | grep -v -e "^#" | grep -v -e '^[[:space:]]*$'
register: hosts
tags:
- always
- 0.0-hosts
- name: "0.0 Validations - Show Hosts"
ansible.builtin.debug:
var: hosts.stdout_lines
when:
- hosts is defined
- ansible_os_family != "Windows"
- name: "0.0 Validations - Create validation-done flag"
delegate_to: localhost
become: false
ansible.builtin.file:
path: "{{ _workspace_directory }}/.progress/validation-done"
state: touch
mode: 0755
tags:
- always
- name: "0.0 Validations - Netmask"
when:
- ansible_os_family != "Windows"
ansible.builtin.debug:
msg:
- "Netmask: {{ hostvars[ansible_hostname]['ansible_default_ipv4']['netmask'] }}"
- "CIDR: {{ ((hostvars[ansible_hostname]['ansible_default_ipv4']['address'] | string) + '/' +
(hostvars[ansible_hostname]['ansible_default_ipv4']['netmask'] | string)) | ansible.utils.ipaddr('prefix') }}"
- "IPV4: {{ hostvars[ansible_hostname]['ansible_default_ipv4']['address'] }}"
- name: Check if /usr/sap is already mounted
when:
- ansible_os_family != "Windows"
block:
- name: Check if /usr/sap is already mounted
ansible.builtin.set_fact:
usr_sap_mounted: true
with_items: "{{ ansible_mounts }}"
when:
- item.mount == "/usr/sap"
- "'scs' in supported_tiers"
tags:
- always
- name: "0.0 Validations - Disk space details"
when:
- "'scs' in supported_tiers"
- usr_sap_mounted is defined
- ansible_os_family != "Windows"
block:
- name: "0.0 Validations - Disk space details"
ansible.builtin.set_fact:
free_diskspace: "{{ ansible_mounts | json_query('[?mount == `/usr/sap`].size_available') }}"
tags:
- always
- name: "0.0 Validations - SCS /usr/sap disk space requirements"
ansible.builtin.set_fact:
scs_free_diskspace: 10
when:
- scs_free_diskspace is not defined
tags:
- always
- name: "0.0 Validations - Show SCS disk space"
ansible.builtin.debug:
msg:
- "Free disk space: {{ free_diskspace | first | int / (1024 * 1024 * 1024) | int }}"
verbosity: 2
- name: "0.0 Validations - Show SCS disk space required"
ansible.builtin.debug:
msg:
- "Free disk space required: {{ scs_free_diskspace }}"
verbosity: 2
- name: "0.0 Validations - Check for free disk space on SCS"
ansible.builtin.assert:
that:
- (free_diskspace | first | int / (1024 * 1024 * 1024) | int) > (scs_free_diskspace | int)
fail_msg: "The SCS server needs at least {{ scs_free_diskspace }} GB of free disk space in /mnt"
tags:
- 0.0-scs-diskspace
tags:
- always
# /*---------------------------------------------------------------------------8
# | |
# | Validate the server side parameters - Oracle |
# | |
# +------------------------------------4--------------------------------------*/
- hosts: "{{ sap_sid | upper }}_DB :
{{ sap_sid | upper }}_PAS :
{{ sap_sid | upper }}_APP"
name: "0.0 Validations - Validate SAP-Parameters for Oracle"
gather_facts: true
vars_files:
- vars/ansible-input-api.yaml # API Input template with defaults
tasks:
- name: "0.0 Validations - Validate that the correct distribution is used"
ansible.builtin.assert:
that:
- "distribution_id == 'oraclelinux8'"
fail_msg: "For Oracle deployments DB, PAS and APP needs to run on OracleLinux"
when:
- platform in ['ORACLE', 'ORACLE-ASM']
- hosts: "{{ sap_sid | upper }}_DB"
name: "0.0 Validations - Validate SAP-Parameters for Oracle"
gather_facts: true
vars_files:
- vars/ansible-input-api.yaml # API Input template with defaults
tasks:
- name: "0.0 Validations - Validate that MULTISID is provided"
ansible.builtin.assert:
that:
- MULTI_SIDS is defined # Has the variable been defined
- MULTI_SIDS | length > 0
fail_msg: "Please specify MULTI_SIDS if you are deploying a shared home installation"
when: node_tier == 'oracle-multi-sid'
- hosts: "{{ sap_sid | upper }}_WEB"
name: "0.0 Validations - Validate SAP-Parameters for Web Dispatchers"
gather_facts: true
vars_files:
- vars/ansible-input-api.yaml # API Input template with defaults
tasks:
- name: "0.0 Validations - VAlidate web_sid presence of Web Dispatchers are deployed"
ansible.builtin.assert:
that:
- web_sid is defined # Has the variable been defined
- web_sid | type_debug != 'NoneType' # and given a value
- web_sid | trim | length > 1
fail_msg: "Please specify web_sid if you are deploying web dispatchers"
when: (ansible_play_hosts_all | length) > 0
# /*---------------------------------------------------------------------------8
# | END |
# +------------------------------------4--------------------------------------*/