Skip to Content
Author's profile photo Phani Kumar Arava

SAP-as-a-Service with OpenStack Cloud – Part 3: S/4HANA HEAT Template

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:

  1. Use a SUSE for SAP Image
  2. Take the inputs for the S/4HANA system (Instance Size: Small, Medium and Large)
  3. Create two servers: HANA System and S/4HANA Primary App Server
  4. Block Attachments from different Volume Types, size varies again based on the Instance Size to both the HANA System and the primary application server
  5. Create Mount Points for HANA Server based on the SID Inputs (HANA Server)
  6. Create Mount Points for S/4HANA App Server based on SID Inputs (HANA Server)
  7. Create mount point for HANA Installer (HANA server)
  8. Download the HANA Installer from a repo (This needs to be created prior) (HANA Server)
  9. Do an unattended installation of HANA Server
  10. Create a mount point for SAP Installation Dump (Primary S/4HANA server)
  11. Download the SWPM and inifile.params template from a repo (This needs to be created prior) (Primary S/4HANA Server)
  12. Do an S/4HANA Unattended Installation (Primary S/4HANA Server) SAP Note : 2230669

 

HEAT Stack Inputs

sapblog-part3-2

Once you launch the stack, the necessary operations start orchestrating. We have to wait till the Stack completely gets created.

sapblog-part3-4
sapblog-part3-5

The Complete Stack Operation should complete within 6-7 hours.

sapblog-part3-6

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] } 

Assigned Tags

      1 Comment
      You must be Logged on to comment or reply to a post.
      Author's profile photo Amaury VAN ESPEN
      Amaury VAN ESPEN

      Hello Phani Kumar Arava

      could you tell me how to set ip up to deploy a SAP Appliance available in CAL ?

      Thank you

      Amaury