SAP-as-a-Service with OpenStack Cloud – Part 3: S/4HANA HEAT Template
This content was based on work originally carried out by Phani Arava from SAT Infotech.
In the previous blog entry, we looked into building a HEAT template for HANA Instances.
In this part of the series SAP-as-a-Service with OpenStack Cloud, we will build-up on the previous HEAT template to create a S/4HANA Instance (S/4HANA 1511 SR1)
The S/4HANA HEAT Template should automate the following:
- Use a SUSE for SAP Image
- Take the inputs for the S/4HANA system (Instance Size: Small, Medium and Large)
- Create two servers: HANA System and S/4HANA Primary App Server
- Block Attachments from different Volume Types, size varies again based on the Instance Size to both the HANA System and the primary application server
- Create Mount Points for HANA Server based on the SID Inputs (HANA Server)
- Create Mount Points for S/4HANA App Server based on SID Inputs (HANA Server)
- Create mount point for HANA Installer (HANA server)
- Download the HANA Installer from a repo (This needs to be created prior) (HANA Server)
- Do an unattended installation of HANA Server
- Create a mount point for SAP Installation Dump (Primary S/4HANA server)
- Download the SWPM and inifile.params template from a repo (This needs to be created prior) (Primary S/4HANA Server)
- Do an S/4HANA Unattended Installation (Primary S/4HANA Server) SAP Note : 2230669
HEAT Stack Inputs
Once you launch the stack, the necessary operations start orchestrating. We have to wait till the Stack completely gets created.
The Complete Stack Operation should complete within 6-7 hours.
The HEAT Stack automates setting up of Volumes, the connection between the S4HANA server and completely sets up S4HANA.
The following HEAT template was used to achieve this:
heat_template_version: 2015-04-30 description: > A template showing how to create a Nova instance, a Cinder volume and attach the volume to the instance. The template uses only Heat OpenStack native resource types. parameters: s4hanainstance_type: type: string label: S4HANA Instance Type description: S4HANA Instance Type Small - 32GB HANA + 4GB App, Medium - 48GB + 6GB App, Large - 64GB + 8GB App constraints: - allowed_values: [ 'Small', 'Medium', 'Large' ] s4hanainstance_sid: type: string label: S4HANA Instance SID description: S4HANA Instance SID constraints: - length: {min: 3, max: 3} description: SID should be of 3 Characters - allowed_pattern: "[A-Z][A-Z0-9][A-Z0-9]" s4hanasystem_password: type: string label: S4HANA Master Password description: The Master Password for S4HANA constraints: - length: {min: 8} description: Password should be minimum of 8 Characters resources: floating_ip: type: OS::Nova::FloatingIP properties: pool: floating wait_condition: type: OS::Heat::WaitCondition properties: handle: {get_resource: wait_handle} count: 2 #Timeout of 8 hours for the complete build timeout: 28800 wait_handle: type: OS::Heat::WaitConditionHandle sap_nova_instance: type: OS::Nova::Server properties: image: 'SuseforSAP12SP1' flavor: { "Fn::Select" : [ {get_param: s4hanainstance_type} , { "Small" : 's1.small', "Medium" : 's1.medium', "Large" : 's1.large' } ] } key_name: 'phani-laptop' name: 'sapserver' networks: - network: 'fixed' security_groups: - {get_resource: sap_security_group } user_data_format: RAW user_data: str_replace: template: | #!/bin/bash s4hanasystem_pwd='%s4hanasystem_password%' hanaip='%hanasystem_ip%' s4hanasid='%s4hanainst_sid%' disk1_id='%voldata1_id%' disk2_id='%voldata2_id%' disk1_size='%voldata1_size%' disk2_size='%voldata2_size%' disk1_size_mb=$(( $disk1_size * 1024 )) disk2_size_mb=$(( $disk2_size * 1024 )) voldata1_dev="/dev/disk/by-id/virtio-$(echo ${disk1_id} | cut -c -20)" voldata2_dev="/dev/disk/by-id/virtio-$(echo ${disk2_id} | cut -c -20)" while [ ! -e ${voldata1_dev} ]; do echo Waiting for volume to attach; sleep 1; done while [ ! -e ${voldata2_dev} ]; do echo Waiting for volume to attach; sleep 1; done mkswap /dev/vdb swapon /dev/vdb parted -s ${voldata1_dev} mklabel msdos parted -s ${voldata1_dev} mkpart primary ext3 1 ${disk1_size_mb} parted -s ${voldata1_dev} set 1 lvm on parted -s ${voldata2_dev} mklabel msdos parted -s ${voldata2_dev} mkpart primary ext3 1 ${disk2_size_mb} parted -s ${voldata2_dev} set 1 lvm on partprobe vgcreate sapsoft ${voldata1_dev}-part1 vgcreate sapdata ${voldata2_dev}-part1 lvcreate -l +100%FREE -n dump sapsoft lvcreate -l +50%FREE -n usrsap sapdata lvcreate -l +50%FREE -n sapmnt sapdata mkfs.ext4 /dev/sapsoft/dump mkfs.ext4 /dev/sapdata/usrsap mkfs.ext4 /dev/sapdata/sapmnt mkdir -p /usr/sap mkdir -p /sapmnt mkdir -p /sapdump echo "/dev/sapsoft/dump /sapdump ext4 defaults 0 0" >> /etc/fstab echo "/dev/sapdata/usrsap /usr/sap ext4 defaults 0 0" >> /etc/fstab echo "/dev/sapdata/sapmnt /sapmnt ext4 defaults 0 0" >> /etc/fstab mount -av IPADDR=$(ifconfig | awk -F" +|:" '/inet addr/ && $4 != "127.0.0.1" {print $4}') echo "$IPADDR $HOSTNAME" >>/etc/hosts cd /sapdump wget http://w.x.y.z/saprepo/S4HANA/51051105.tar.gz tar -zxvf 51051105.tar.gz rm 51051105.tar.gz mkdir SWPM cd SWPM wget http://w.x.y.z/saprepo/SWPM/SAPCAR -O /usr/bin/SAPCAR chmod 755 /usr/bin/SAPCAR wget http://w.x.y.z/saprepo/SWPM/SWPM10SP17_6-20009701.SAR SAPCAR -xvf SWPM10SP17_6-20009701.SAR rm SWPM10SP17_6-20009701.SAR wget http://w.x.y.z/saprepo/SWPM/inifile.tgz tar -zxvf inifile.tgz sed -e "s;%PASSWORD%;${s4hanasystem_pwd};g" -e "s;%DOMAINNAME%;cloud.geeko.land;g" -e "s;%SID%;${s4hanasid};g" inifile.params.template -e "s;%HANAHOST%;${hanaip};g" > inifile.params rm inifile.params.template rm inifile.tgz cd .. mkdir SAPKERNEL cd SAPKERNEL wget http://w.x.y.z/saprepo/SAPKERNEL/51050826_3.ZIP unzip 51050826_3.ZIP rm 51050826_3.ZIP wget http://w.x.y.z/saprepo/SAPKERNEL/SAPEXE.SAR -O /sapdump/SAPKERNEL/DATA_UNITS/K_745_U_LINUX_X86_64/DBINDEP/SAPEXE.SAR wget http://w.x.y.z/saprepo/SAPKERNEL/SAPEXEDB.SAR -O //sapdump/SAPKERNEL/DATA_UNITS/K_745_U_LINUX_X86_64/DBINDEP/SAPEXEDB.SAR cd .. mkdir HDBCLIENT cd HDBCLIENT wget http://w.x.y.z/saprepo/HANAPLATFORM/51051106.ZIP unzip 51051106.ZIP rm 51051106.ZIP IPADDR=$(ifconfig | awk -F" +|:" '/inet addr/ && $4 != "127.0.0.1" {print $4}') echo "$IPADDR $HOSTNAME.cloud.geeko.land" >>/etc/hosts cd ../SWPM export SAPINST_EXECUTE_PRODUCT_ID=NW_ABAP_OneHost:S4HANAONPREM1511SR1.CORE.HDB.ABAP export SAPINST_SKIP_DIALOGS=true export SAPINST_INPUT_PARAMETERS_URL=/sapdump/SWPM/inifile.params ./sapinst -nogui -noguiserver wc_notify --data-binary '{"status": "SUCCESS"}' params: "%voldata1_id%": { get_resource: sap_cinder_volume1 } "%voldata2_id%": { get_resource: sap_cinder_volume2 } "%voldata1_size%": 40 "%voldata2_size%": { "Fn::Select" : [ {get_param: s4hanainstance_type} , { "Small" : 20, "Medium" : 30, "Large" : 40 } ] } "%s4hanasystem_password%" : { get_param: s4hanasystem_password } "%hanasystem_ip%" : { get_attr: [hana_nova_instance, first_address] } "%s4hanainst_sid%": { get_param: s4hanainstance_sid } wc_notify: { get_attr: ['wait_handle', 'curl_cli'] } hana_nova_instance: type: OS::Nova::Server properties: image: 'SuseforSAP12SP1' flavor: { "Fn::Select" : [ {get_param: s4hanainstance_type} , { "Small" : 'h1.medium', "Medium" : 'h1.large', "Large" : 'h1.xlarge' } ] } key_name: 'phani-laptop' name: 'hanaserver' networks: - network: 'fixed' security_groups: - {get_resource: hana_security_group } user_data_format: RAW user_data: str_replace: template: | #!/bin/bash disk1_id='%voldata1_id%' disk2_id='%voldata2_id%' disk3_id='%voldata3_id%' disk1_size='%voldata1_size%' disk2_size='%voldata2_size%' disk3_size='%voldata3_size%' hanasystem_pwd='%hanasystem_password%' hanasapadm_pwd='%hanasystem_password%' hanasidadm_pwd='%hanasystem_password%' disk1_size_mb=$(( $disk1_size * 1024 )) disk2_size_mb=$(( $disk2_size * 1024 )) disk3_size_mb=$(( $disk3_size * 1024 )) db_mount_point='%dbmountpoint%' voldata1_dev="/dev/disk/by-id/virtio-$(echo ${disk1_id} | cut -c -20)" voldata2_dev="/dev/disk/by-id/virtio-$(echo ${disk2_id} | cut -c -20)" voldata3_dev="/dev/disk/by-id/virtio-$(echo ${disk3_id} | cut -c -20)" hanainstance_sid='%hanainst_sid%' while [ ! -e ${voldata1_dev} ]; do echo Waiting for volume to attach; sleep 1; done while [ ! -e ${voldata2_dev} ]; do echo Waiting for volume to attach; sleep 1; done while [ ! -e ${voldata3_dev} ]; do echo Waiting for volume to attach; sleep 1; done parted -s ${voldata1_dev} mklabel msdos parted -s ${voldata1_dev} mkpart primary ext3 1 ${disk1_size_mb} parted -s ${voldata1_dev} set 1 lvm on parted -s ${voldata2_dev} mklabel msdos parted -s ${voldata2_dev} mkpart primary ext3 1 ${disk2_size_mb} parted -s ${voldata2_dev} set 1 lvm on parted -s ${voldata3_dev} mklabel msdos parted -s ${voldata3_dev} mkpart primary ext3 1 ${disk3_size_mb} parted -s ${voldata3_dev} set 1 lvm on partprobe vgcreate hanasoft ${voldata1_dev}-part1 vgcreate hanadata ${voldata2_dev}-part1 vgcreate hanalog ${voldata3_dev}-part1 #The creation of Logical Volumes sapdata. Right now very simple. We will make it complex as we go. lvcreate -l +100%FREE -n dump hanasoft lvcreate -l +100%FREE -n data hanadata lvcreate -l +100%FREE -n log hanalog #lvcreate -L+20G -n sapdump sapdata #The creation of Logical Volumes dbdata. We will just minus 5G from disk2 size (to counter LVM extenrs). Again need to make some proper calculations. #lvcreate -L+$(( $disk2_size - 5 ))G -n ${db_mount_point} dbdata mkfs.ext4 /dev/hanasoft/dump mkfs.ext4 /dev/hanadata/data mkfs.ext4 /dev/hanalog/log mkdir -p /hana/$( echo ${hanainstance_sid} )/global/hdb/data mkdir -p /hana/$( echo ${hanainstance_sid} )/global/hdb/log #mkdir -p /sapmnt mkdir -p /sapdump #mkdir -p /${db_mount_point} echo "/dev/hanasoft/dump /sapdump ext4 defaults 0 0" >> /etc/fstab echo "/dev/hanadata/data /hana/$( echo ${hanainstance_sid} )/global/hdb/data ext4 defaults 0 0" >> /etc/fstab echo "/dev/hanalog/log /hana/$( echo ${hanainstance_sid} )/global/hdb/log ext4 defaults 0 0" >> /etc/fstab mount -av IPADDR=$(ifconfig | awk -F" +|:" '/inet addr/ && $4 != "127.0.0.1" {print $4}') echo "$IPADDR $HOSTNAME" >>/etc/hosts cd /sapdump wget http://w.x.y.z/saprepo/HANAPLATFORM/HDB_SERVER_LINUX_X86_64.tar.gz tar -zxvf HDB_SERVER_LINUX_X86_64.tar.gz cd HDB_SERVER_LINUX_X86_64 cat << EOF > hdb_pwd.xml EOF cat hdb_pwd.xml |./hdbinst -b --number=00 --hostname=hanaserver --sapmnt=/hana -s $( echo ${hanainstance_sid} ) --db_mode=single_container --system_usage=custom --read_password_from_stdin=xml > hdb_inst.log wc_notify --data-binary '{"status": "SUCCESS"}' params: "%voldata1_id%": { get_resource: cinder_volume1 } "%voldata2_id%": { get_resource: cinder_volume2 } "%voldata3_id%": { get_resource: cinder_volume3 } "%voldata1_size%": 20 "%voldata2_size%": { "Fn::Select" : [ {get_param: s4hanainstance_type} , { "Small" : 64, "Medium" : 96, "Large" : 128 } ] } "%voldata3_size%": { "Fn::Select" : [ {get_param: s4hanainstance_type} , { "Small" : 32, "Medium" : 48, "Large" : 64} ] } "%hanainst_sid%": { get_param: s4hanainstance_sid } "%hanasystem_password%" : { get_param: s4hanasystem_password } wc_notify: { get_attr: ['wait_handle', 'curl_cli'] } cinder_volume1: type: OS::Cinder::Volume properties: size: 20 volume_type: 'SUSE-Enterprise-Storage' cinder_volume2: type: OS::Cinder::Volume properties: size: { "Fn::Select" : [ {get_param: s4hanainstance_type} , { "Small" : 64, "Medium" : 96, "Large" : 128 } ] } volume_type: 'NetApp' cinder_volume3: type: OS::Cinder::Volume properties: size: { "Fn::Select" : [ {get_param: s4hanainstance_type} , { "Small" : 32, "Medium" : 48, "Large" : 64 } ] } volume_type: 'NetApp' volume_attachment1: type: OS::Cinder::VolumeAttachment properties: volume_id: { get_resource: cinder_volume1 } instance_uuid: { get_resource: hana_nova_instance } mountpoint: /dev/vdc volume_attachment2: type: OS::Cinder::VolumeAttachment properties: volume_id: { get_resource: cinder_volume2 } instance_uuid: { get_resource: hana_nova_instance } mountpoint: /dev/vdd volume_attachment3: type: OS::Cinder::VolumeAttachment properties: volume_id: { get_resource: cinder_volume3 } instance_uuid: { get_resource: hana_nova_instance } mountpoint: /dev/vde sap_cinder_volume1: type: OS::Cinder::Volume properties: size: 40 volume_type: 'SUSE-Enterprise-Storage' sap_cinder_volume2: type: OS::Cinder::Volume properties: size: { "Fn::Select" : [ {get_param: s4hanainstance_type} , { "Small" : 20, "Medium" : 30, "Large" : 40 } ] } volume_type: 'NetApp' sap_volume_attachment1: type: OS::Cinder::VolumeAttachment properties: volume_id: { get_resource: sap_cinder_volume1 } instance_uuid: { get_resource: sap_nova_instance } mountpoint: /dev/vdc sap_volume_attachment2: type: OS::Cinder::VolumeAttachment properties: volume_id: { get_resource: sap_cinder_volume2 } instance_uuid: { get_resource: sap_nova_instance } mountpoint: /dev/vdd association: type: OS::Nova::FloatingIPAssociation properties: floating_ip: { get_resource: floating_ip } server_id: { get_resource: sap_nova_instance } hana_security_group: type: OS::Neutron::SecurityGroup properties: name: hanasg description: Ping and SSH rules: - protocol: icmp - protocol: tcp port_range_min: 22 port_range_max: 22 - protocol: tcp port_range_min: 30015 port_range_max: 30015 - protocol: tcp port_range_min: 50013 port_range_max: 50013 sap_security_group: type: OS::Neutron::SecurityGroup properties: name: sapsg description: Ping and SSH rules: - protocol: icmp - protocol: tcp port_range_min: 22 port_range_max: 22 - protocol: tcp port_range_min: 3200 port_range_max: 3200 outputs: hana_instance_ip: description: Intenal IP address of the HANA instance. value: { get_attr: [hana_nova_instance, first_address] } floating_ip_out: description: Public IP of the HANA Instance. value: { get_attr: [floating_ip, ip] }
No comments yet