diff --git a/requirements.yml b/requirements.yml index abeb348..53a4981 100644 --- a/requirements.yml +++ b/requirements.yml @@ -12,7 +12,7 @@ collections: version: 5.4.0 - name: azure.azcollection type: galaxy - version: 1.15.0 + version: 2.2.0 - name: google.cloud type: galaxy version: 1.1.3 diff --git a/roles/sap_vm_provision/README.md b/roles/sap_vm_provision/README.md index 3d9871d..4103dc4 100644 --- a/roles/sap_vm_provision/README.md +++ b/roles/sap_vm_provision/README.md @@ -162,6 +162,12 @@ This required structure will: var: groups ``` +### Design assumptions with execution impact + +- For Hyperscaler Cloud Service Providers that use Resource Groups (IBM Cloud, Microsoft Azure): + - Virtual Machine and associated resources (Disks, Network Interfaces, Load Balancer etc.) will be provisioned to the same Resource Group as the targeted network/subnet. + - Optional: Private DNS may be allocated to another Resource Group, and an optional variable is provided for this. + ### Tags to control execution There are no tags used to control the execution of this Ansible Role diff --git a/roles/sap_vm_provision/defaults/main.yml b/roles/sap_vm_provision/defaults/main.yml index b5b633c..2def3d1 100644 --- a/roles/sap_vm_provision/defaults/main.yml +++ b/roles/sap_vm_provision/defaults/main.yml @@ -23,7 +23,7 @@ sap_vm_provision_bastion_user: "" sap_vm_provision_ssh_bastion_private_key_file_path: "" sap_vm_provision_ssh_host_private_key_file_path: "" -sap_vm_provision_ssh_host_public_key_file_path: "{{ sap_vm_provision_ssh_host_private_key_file_path + '.pub' }}" +sap_vm_provision_ssh_host_public_key_file_path: "{{ sap_vm_provision_ssh_host_private_key_file_path + '.pub' }}" # used for gcp_ce_vm, ibmpowervm_vm, kubevirt_vm, vmware_vm #### @@ -137,6 +137,7 @@ sap_vm_provision_ibmcloud_resource_group_name: "" sap_vm_provision_ibmcloud_region: "{{ sap_vm_provision_ibmcloud_availability_zone | regex_replace('-[0-9]', '') }}" sap_vm_provision_ibmcloud_availability_zone: "" sap_vm_provision_ibmcloud_private_dns_instance_name: "" +# sap_vm_provision_ibmcloud_private_dns_resource_group_name: "" # optional, default use of sap_vm_provision_ibmcloud_resource_group_name sap_vm_provision_ibmcloud_vpc_name: "" sap_vm_provision_ibmcloud_vpc_subnet_name: "" sap_vm_provision_ibmcloud_vpc_sg_names: "" # comma-separated, if ansible_to_terraform then ignore this variable @@ -156,8 +157,10 @@ sap_vm_provision_msazure_app_client_secret: "" sap_vm_provision_msazure_resource_group_name: "" sap_vm_provision_msazure_location_region: "" sap_vm_provision_msazure_location_availability_zone_no: 1 +# sap_vm_provision_msazure_private_dns_resource_group_name: "" # optional, default use of sap_vm_provision_msazure_resource_group_name sap_vm_provision_msazure_vnet_name: "" sap_vm_provision_msazure_vnet_subnet_name: "" +sap_vm_provision_msazure_key_pair_name_ssh_host_public_key: "" #### diff --git a/roles/sap_vm_provision/tasks/common/set_ansible_vars.yml b/roles/sap_vm_provision/tasks/common/set_ansible_vars.yml index 6f06655..67c3228 100644 --- a/roles/sap_vm_provision/tasks/common/set_ansible_vars.yml +++ b/roles/sap_vm_provision/tasks/common/set_ansible_vars.yml @@ -11,11 +11,10 @@ sap_software_download_directory: "{{ sap_software_download_directory | default('/software') }}" sap_install_media_detect_source_directory: "{{ sap_software_download_directory | default('/software') }}" -- name: Set facts for all hosts - use facts from localhost - Ansible only - ansible.builtin.set_fact: - sap_vm_provision_ssh_host_private_key_file_path: "{{ sap_vm_provision_ssh_host_private_key_file_path }}" - when: - - sap_vm_provision_iac_type == "ansible" +# - name: Set facts for all hosts - use facts from localhost - Ansible only +# ansible.builtin.set_fact: +# when: +# - sap_vm_provision_iac_type == "ansible" - name: Set facts for all hosts - use facts from localhost - SAP HANA ansible.builtin.set_fact: diff --git a/roles/sap_vm_provision/tasks/platform_ansible/ibmcloud_powervs/execute_main.yml b/roles/sap_vm_provision/tasks/platform_ansible/ibmcloud_powervs/execute_main.yml index f24a27b..40a11cb 100644 --- a/roles/sap_vm_provision/tasks/platform_ansible/ibmcloud_powervs/execute_main.yml +++ b/roles/sap_vm_provision/tasks/platform_ansible/ibmcloud_powervs/execute_main.yml @@ -55,6 +55,14 @@ ibm.cloudcollection.ibm_resource_group_info: name: "{{ sap_vm_provision_ibmcloud_resource_group_name }}" + # DNS may exist in separate Resource Group + # Use empty string var (or default false if undefined) to evaluate to false boolean + - name: Identify Resource Group info for Private DNS + register: register_ibmcloud_resource_group_dns + ibm.cloudcollection.ibm_resource_group_info: + name: "{{ sap_vm_provision_ibmcloud_private_dns_resource_group_name }}" + when: (sap_vm_provision_ibmcloud_private_dns_resource_group_name | default(false)) + - name: Identify IBM Power Infrastructure Workspace register: register_ibmcloud_power_iaas_workspace_service_instance ibm.cloudcollection.ibm_resource_instance_info: @@ -86,10 +94,12 @@ ibm.cloudcollection.ibm_pi_catalog_images_info: pi_cloud_instance_id: "{{ register_ibmcloud_power_iaas_workspace_service_instance.resource.guid }}" # must be GUID, not CRN + # DNS may exist in separate Resource Group + # If previous identification task is skipped, use resource group else use the resource group defined for the Private DNS - name: Identify Private DNS instance register: register_ibmcloud_pdns_service_instance ibm.cloudcollection.ibm_resource_instance_info: - resource_group_id: "{{ register_ibmcloud_resource_group.resource.id }}" + resource_group_id: "{{ register_ibmcloud_resource_group.resource.id if register_ibmcloud_resource_group_dns is skipped else register_ibmcloud_resource_group_dns.resource.id }}" location: global service: dns-svcs name: "{{ sap_vm_provision_ibmcloud_private_dns_instance_name }}" diff --git a/roles/sap_vm_provision/tasks/platform_ansible/ibmcloud_vs/execute_main.yml b/roles/sap_vm_provision/tasks/platform_ansible/ibmcloud_vs/execute_main.yml index c947801..fe97d5f 100644 --- a/roles/sap_vm_provision/tasks/platform_ansible/ibmcloud_vs/execute_main.yml +++ b/roles/sap_vm_provision/tasks/platform_ansible/ibmcloud_vs/execute_main.yml @@ -11,6 +11,14 @@ ibm.cloudcollection.ibm_resource_group_info: name: "{{ sap_vm_provision_ibmcloud_resource_group_name }}" + # DNS may exist in separate Resource Group + # Use empty string var (or default false if undefined) to evaluate to false boolean + - name: Identify Resource Group info for Private DNS + register: register_ibmcloud_resource_group_dns + ibm.cloudcollection.ibm_resource_group_info: + name: "{{ sap_vm_provision_ibmcloud_private_dns_resource_group_name }}" + when: (sap_vm_provision_ibmcloud_private_dns_resource_group_name | default(false)) + - name: Identify pre-loaded SSH Public Key info register: register_ibmcloud_ssh_public_key ibm.cloudcollection.ibm_is_ssh_key_info: @@ -27,10 +35,12 @@ name: "{{ item }}" loop: "{{ sap_vm_provision_ibmcloud_vpc_sg_names | split(',') }}" + # DNS may exist in separate Resource Group + # If previous identification task is skipped, use resource group else use the resource group defined for the Private DNS - name: Identify Private DNS instance register: register_ibmcloud_pdns_service_instance ibm.cloudcollection.ibm_resource_instance_info: - resource_group_id: "{{ register_ibmcloud_resource_group.resource.id }}" + resource_group_id: "{{ register_ibmcloud_resource_group.resource.id if register_ibmcloud_resource_group_dns is skipped else register_ibmcloud_resource_group_dns.resource.id }}" location: global service: dns-svcs name: "{{ sap_vm_provision_ibmcloud_private_dns_instance_name }}" diff --git a/roles/sap_vm_provision/tasks/platform_ansible/msazure_vm/execute_main.yml b/roles/sap_vm_provision/tasks/platform_ansible/msazure_vm/execute_main.yml index fd6bca6..7e906b8 100644 --- a/roles/sap_vm_provision/tasks/platform_ansible/msazure_vm/execute_main.yml +++ b/roles/sap_vm_provision/tasks/platform_ansible/msazure_vm/execute_main.yml @@ -13,6 +13,28 @@ ansible.builtin.set_fact: register_provisioned_host_all: [] + # Ansible Module name parameter, requires resource_group parameter + # We cannot assume Resource Group if the SSH Public Key is managed by Administrators + # Therefore use without any parameter to retrieve list of all SSH Public Keys and filter in Ansible + - name: Get all SSH Public Keys in MS Azure + azure.azcollection.azure_rm_sshpublickey_info: + register: __sap_vm_provision_msazure_key_pair_name_ssh_host_public_keys + + - name: Set fact for selected SSH Public Key in MS Azure + ansible.builtin.set_fact: + __sap_vm_provision_msazure_key_pair_name_ssh_host_public_key_value: "{{ (__sap_vm_provision_msazure_key_pair_name_ssh_host_public_keys.ssh_keys | selectattr('name', '==', sap_vm_provision_msazure_key_pair_name_ssh_host_public_key))[0].public_key }}" + + - name: Get Private DNS Zone Virtual Network Links + azure.azcollection.azure_rm_privatednszonelink_info: + # DNS may exist in separate Resource Group. Use empty string var (or default false if undefined) to evaluate to false boolean, and use Python or logic operator + resource_group: "{{ (sap_vm_provision_msazure_private_dns_resource_group_name | default(false)) or sap_vm_provision_msazure_resource_group_name }}" + zone_name: "{{ sap_vm_provision_dns_root_domain }}" + register: __sap_vm_provision_msazure_private_dns_virtual_network_links + + - name: Set boolean fact for Auto Registration of DNS Records from Private DNS Zone Virtual Network Link + ansible.builtin.set_fact: + __sap_vm_provision_msazure_private_dns_auto_register_records: "{{ (__sap_vm_provision_msazure_private_dns_virtual_network_links.virtualnetworklinks | selectattr('virtual_network.id', 'search', sap_vm_provision_msazure_vnet_name))[0].registration_enabled }}" + - name: Provision hosts to MS Azure register: register_provisioned_hosts ansible.builtin.include_tasks: @@ -30,7 +52,7 @@ ansible.builtin.add_host: name: "{{ add_item[0].host_node }}" groups: "{{ add_item[0].sap_system_type + '_' if (add_item[0].sap_system_type != '') }}{{ add_item[0].sap_host_type }}" - ansible_host: "{{ add_item[0].ansible_facts.azure_vm.properties.networkProfile.networkInterfaces[0].properties.ipConfigurations[0].properties.privateIPAddress }}" + ansible_host: "{{ add_item[0].ansible_facts.azure_vm.network_profile.network_interfaces[0].properties.ip_configurations[0].private_ip_address }}" ansible_user: "root" ansible_ssh_private_key_file: "{{ sap_vm_provision_ssh_host_private_key_file_path }}" ansible_ssh_common_args: -o ConnectTimeout=180 -o ControlMaster=auto -o ControlPersist=3600s -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ForwardX11=no -o ProxyCommand='ssh -W %h:%p {{ sap_vm_provision_bastion_user }}@{{ sap_vm_provision_bastion_public_ip }} -p {{ sap_vm_provision_bastion_ssh_port }} -i {{ sap_vm_provision_ssh_bastion_private_key_file_path }} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' @@ -55,12 +77,14 @@ # Create "A" (IPv4 Address) Resource Record to map IPv4 address as hostname / subdomain of the root domain name - name: Ansible MS Azure Private DNS Records for hosts azure.azcollection.azure_rm_privatednsrecordset: - resource_group: "{{ sap_vm_provision_msazure_resource_group_name }}" + # DNS may exist in separate Resource Group. Use empty string var (or default false if undefined) to evaluate to false boolean, and use Python or logic operator + resource_group: "{{ (sap_vm_provision_msazure_private_dns_resource_group_name | default(false)) or sap_vm_provision_msazure_resource_group_name }}" zone_name: "{{ hostvars[inventory_hostname].sap_vm_provision_dns_root_domain }}" relative_name: "{{ inventory_hostname }}" record_type: A records: - entry: "{{ hostvars[inventory_hostname].ansible_host }}" + when: not __sap_vm_provision_msazure_private_dns_auto_register_records # - ansible.builtin.debug: # var: register_add_hosts.results diff --git a/roles/sap_vm_provision/tasks/platform_ansible/msazure_vm/execute_provision.yml b/roles/sap_vm_provision/tasks/platform_ansible/msazure_vm/execute_provision.yml index d932641..7eab37b 100644 --- a/roles/sap_vm_provision/tasks/platform_ansible/msazure_vm/execute_provision.yml +++ b/roles/sap_vm_provision/tasks/platform_ansible/msazure_vm/execute_provision.yml @@ -47,7 +47,7 @@ ssh_password_enabled: false ssh_public_keys: - path: /home/azureadmin/.ssh/authorized_keys - key_data: "{{ lookup('ansible.builtin.file', sap_vm_provision_ssh_host_public_key_file_path ) }}" # Replace with import/lookup via Ansible Module azure_rm_ssh_public_key/azure_rm_sshpublickey_info + key_data: "{{ __sap_vm_provision_msazure_key_pair_name_ssh_host_public_key_value }}" vm_size: "{{ lookup('ansible.builtin.vars', 'sap_vm_provision_' + sap_vm_provision_iac_platform + '_host_specifications_dictionary')[sap_vm_provision_host_specification_plan][scaleout_origin_host_spec | default(inventory_hostname)].virtual_machine_profile }}" image: publisher: "{{ lookup('ansible.builtin.vars', 'sap_vm_provision_' + sap_vm_provision_iac_platform + '_host_os_image_dictionary')[sap_vm_provision_msazure_vm_host_os_image].publisher }}" @@ -58,7 +58,8 @@ public_ip_allocation_method: "Disabled" managed_disk_type: StandardSSD_LRS remove_on_absent: ["all"] - vm_identity: "SystemAssigned" + vm_identity: + type: SystemAssigned state: "present" started: true @@ -77,7 +78,7 @@ - name: Create fact for delegate host IP ansible.builtin.set_fact: - provisioned_private_ip: "{{ register_provisioned_host_single.ansible_facts.azure_vm.properties.networkProfile.networkInterfaces[0].properties.ipConfigurations[0].properties.privateIPAddress }}" + provisioned_private_ip: "{{ register_provisioned_host_single.ansible_facts.azure_vm.network_profile.network_interfaces[0].properties.ip_configurations[0].private_ip_address }}" - name: Copy facts to delegate host @@ -201,7 +202,7 @@ - name: Create fact for delegate host IP ansible.builtin.set_fact: - provisioned_private_ip: "{{ register_provisioned_host_single.ansible_facts.azure_vm.properties.networkProfile.networkInterfaces[0].properties.ipConfigurations[0].properties.privateIPAddress }}" + provisioned_private_ip: "{{ register_provisioned_host_single.ansible_facts.azure_vm.network_profile.network_interfaces[0].properties.ip_configurations[0].private_ip_address }}" - name: Copy facts to delegate host delegate_to: "{{ provisioned_private_ip }}" @@ -212,10 +213,9 @@ delegate_sap_vm_provision_bastion_ssh_port: "{{ sap_vm_provision_bastion_ssh_port }}" delegate_sap_vm_provision_ssh_bastion_private_key_file_path: "{{ sap_vm_provision_ssh_bastion_private_key_file_path }}" delegate_sap_vm_provision_ssh_host_private_key_file_path: "{{ sap_vm_provision_ssh_host_private_key_file_path }}" - delegate_private_ip: "{{ register_provisioned_host_single.ansible_facts.azure_vm.properties.networkProfile.networkInterfaces[0].properties.ipConfigurations[0].properties.privateIPAddress }}" + delegate_private_ip: "{{ register_provisioned_host_single.ansible_facts.azure_vm.network_profile.network_interfaces[0].properties.ip_configurations[0].private_ip_address }}" delegate_hostname: "{{ inventory_hostname }}" delegate_sap_vm_provision_dns_root_domain_name: "{{ sap_vm_provision_dns_root_domain }}" - delegate_sap_vm_provision_ssh_host_public_key_file_path: "{{ lookup('ansible.builtin.file', sap_vm_provision_ssh_host_public_key_file_path ) }}" # Replace with import/lookup via Ansible Module azure_rm_ssh_public_key/azure_rm_sshpublickey_info ### begin block, parameters will be applied to each task within the block diff --git a/roles/sap_vm_provision/tasks/platform_ansible/msazure_vm/execute_setup_ha.yml b/roles/sap_vm_provision/tasks/platform_ansible/msazure_vm/execute_setup_ha.yml index bc48e5f..67a2bf6 100644 --- a/roles/sap_vm_provision/tasks/platform_ansible/msazure_vm/execute_setup_ha.yml +++ b/roles/sap_vm_provision/tasks/platform_ansible/msazure_vm/execute_setup_ha.yml @@ -23,7 +23,8 @@ - name: Ansible MS Azure Private DNS Records for SAP HANA HA Virtual Hostname azure.azcollection.azure_rm_privatednsrecordset: - resource_group: "{{ sap_vm_provision_msazure_resource_group_name }}" + # DNS may exist in separate Resource Group. Use empty string var (or default false if undefined) to evaluate to false boolean, and use Python or logic operator + resource_group: "{{ (sap_vm_provision_msazure_private_dns_resource_group_name | default(false)) or sap_vm_provision_msazure_resource_group_name }}" zone_name: "{{ hostvars[host_node].sap_vm_provision_dns_root_domain }}" relative_name: "{{ sap_swpm_db_host }}" record_type: A @@ -53,7 +54,8 @@ - name: Ansible MS Azure Private DNS Records for SAP NetWeaver ASCS HA Virtual Hostname azure.azcollection.azure_rm_privatednsrecordset: - resource_group: "{{ sap_vm_provision_msazure_resource_group_name }}" + # DNS may exist in separate Resource Group. Use empty string var (or default false if undefined) to evaluate to false boolean, and use Python or logic operator + resource_group: "{{ (sap_vm_provision_msazure_private_dns_resource_group_name | default(false)) or sap_vm_provision_msazure_resource_group_name }}" zone_name: "{{ hostvars[host_node].sap_vm_provision_dns_root_domain }}" relative_name: "{{ sap_swpm_ascs_instance_hostname }}" record_type: A @@ -83,7 +85,8 @@ - name: Ansible MS Azure Private DNS Records for SAP NetWeaver ERS HA Virtual Hostname azure.azcollection.azure_rm_privatednsrecordset: - resource_group: "{{ sap_vm_provision_msazure_resource_group_name }}" + # DNS may exist in separate Resource Group. Use empty string var (or default false if undefined) to evaluate to false boolean, and use Python or logic operator + resource_group: "{{ (sap_vm_provision_msazure_private_dns_resource_group_name | default(false)) or sap_vm_provision_msazure_resource_group_name }}" zone_name: "{{ hostvars[host_node].sap_vm_provision_dns_root_domain }}" relative_name: "{{ sap_swpm_ers_instance_hostname }}" record_type: A @@ -115,7 +118,8 @@ # - name: Ansible MS Azure Private DNS Records for SAP NetWeaver PAS HA Virtual Hostname # azure.azcollection.azure_rm_privatednsrecordset: -# resource_group: "{{ sap_vm_provision_msazure_resource_group_name }}" +# # DNS may exist in separate Resource Group. Use empty string var (or default false if undefined) to evaluate to false boolean, and use Python or logic operator +# resource_group: "{{ (sap_vm_provision_msazure_private_dns_resource_group_name | default(false)) or sap_vm_provision_msazure_resource_group_name }}" # zone_name: "{{ hostvars[host_node].sap_vm_provision_dns_root_domain }}" # relative_name: "{{ sap_swpm_pas_instance_hostname }}" # record_type: A @@ -145,7 +149,8 @@ # - name: Ansible MS Azure Private DNS Records for SAP NetWeaver AAS HA Virtual Hostname # azure.azcollection.azure_rm_privatednsrecordset: -# resource_group: "{{ sap_vm_provision_msazure_resource_group_name }}" +# # DNS may exist in separate Resource Group. Use empty string var (or default false if undefined) to evaluate to false boolean, and use Python or logic operator +# resource_group: "{{ (sap_vm_provision_msazure_private_dns_resource_group_name | default(false)) or sap_vm_provision_msazure_resource_group_name }}" # zone_name: "{{ hostvars[host_node].sap_vm_provision_dns_root_domain }}" # relative_name: "{{ sap_swpm_aas_instance_hostname }}" # record_type: A