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:
- 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] }
Hello Phani Kumar Arava
could you tell me how to set ip up to deploy a SAP Appliance available in CAL ?
Thank you
Amaury