SAP-as-a-Service with OpenStack Cloud – Part 1: Creating a HEAT Template for SAP Services
SAP Provides Cloud Appliance Library http://cal.sap.com. But here are the issues with it.
- Fixed SID. Cannot be used in Production. Most of the landscapes have to register their SIDs in the Solution manager to identify the machine. If it’s a SAP Service Provider, having the same SID for all customers would be a challenge.
- Appliances are available for AWS / Azure, but not for OpenStack.
- Appliances are not customized with databases of your choice. (Most of the time it’s SYBASE / HANA.)
We will look at the problem from a different perspective and try to create a HEAT template for automating the installation of SAP Systems (Unattended Installation). Though this approach is time-intensive, it gives a lot more flexibility and dependability.
The input requirements of the HEAT Template would be the following:
- Give a facility to select the SAP Instance Type (ECCEHP7, ECCEHP6, NW7.5, NW7.4 etc.)
- Give a facility to select the Database (SAPDB, SYBASE, DB2, Oracle, HANA etc.)
- Place to Enter the SID
The HEAT template should accomplish the following:
- Create a nova instance.
- Attach two block storages. The sizes of which will depend on the SAP Instance Type choosen. For ex: NW7.4, block sizes of 40G and 75GB are attached. The intention is to have separate disks for sapdata (/usr/sap, /sapmnt) and dbdata (Depends on the DB Selected. If its SYBASE, mount point will be /sybase)
- Create LVM Volume Groups of sapdata and dbdata.
- Create LVM Logical Volumes, Format and mount them.
Assumptions in using the HEAT Template.
- You have first created a SUSE for SAP OpenStack Cloud Image with cloud-init. If you haven’t, please use: https://www.suse.com/communities/blog/building-suse-sap-cloud-image-using-kiwi/to create one.
- You have installed OpenStack HEAT Services.
- You are running OpenStack with libvirt based virtualization platforms (Tested on KVM).
The HEAT file:
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:
sapinstance_type:
type: string
label: SAP Instance Type
description: SAP Instance Type Ex ECCEHP7, ECCEHP6, NW74
constraints:
- allowed_values: [ ECCEHP6, NW74, S4HANA ]
sapinstance_db_type:
type: string
label: SAP DB Type
description: SAP Database Type Ex SAPDB, SYB, DB2, HANA, ORA
constraints:
- allowed_values: [ SAPDB, SYB, DB2, HANA, ORA ]
sapinstance_sid:
type: string
label: SAP Instance SID
description: SAP 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]"
resources:
floating_ip:
type: OS::Nova::FloatingIP
properties:
pool: floating
nova_instance:
type: OS::Nova::Server
properties:
image: 'SUSEforSAP'
flavor: 'm1.sapsmall'
key_name: 'cloud'
name: 'sapserver'
networks:
- network: 'fixed'
user_data_format: RAW
user_data:
str_replace:
template: |
#!/bin/bash
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 ))
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)"
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
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 sapdata ${voldata1_dev}-part1
vgcreate dbdata ${voldata2_dev}-part1
#The creation of Logical Volumes sapdata. Right now very simple. We will make it complex as we go.
lvcreate -L+5G -n usrsap sapdata
lvcreate -L+5G -n sapmnt sapdata
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/sapdata/usrsap
mkfs.ext4 /dev/sapdata/sapmnt
mkfs.ext4 /dev/sapdata/sapdump
mkfs.ext4 /dev/dbdata/${db_mount_point}
mkdir -p /usr/sap
mkdir -p /sapmnt
mkdir -p /sapdump
mkdir -p /${db_mount_point}
mount /dev/sapdata/usrsap /usr/sap
mount /dev/sapdata/sapmnt /sapmnt
mount /dev/sapdata/sapdump /sapdump
mount /dev/dbdata/${db_mount_point} ${db_mount_point}
params:
"%voldata1_id%": { get_resource: cinder_volume1 }
"%voldata2_id%": { get_resource: cinder_volume2 }
"%voldata1_size%": { "Fn::Select" : [ {get_param: sapinstance_type} , { "ECCEHP7" : 50, "ECCEHP6" : 50, "NW74" : 40 } ] }
"%voldata2_size%": { "Fn::Select" : [ {get_param: sapinstance_type} , { "ECCEHP7" : 200, "ECCEHP6" : 200, "NW74" : 75 } ] }
"%dbmountpoint%": { "Fn::Select" : [ {get_param: sapinstance_db_type} , { "DB2" : "db2", "SYB" : "sybase", "SAPDB" : "sapdb" } ] }
cinder_volume1:
type: OS::Cinder::Volume
properties:
size: { "Fn::Select" : [ {get_param: sapinstance_type} , { "ECCEHP7" : 50, "ECCEHP6" : 50, "NW74" : 40 } ] }
cinder_volume2:
type: OS::Cinder::Volume
properties:
size: { "Fn::Select" : [ {get_param: sapinstance_type} , { "ECCEHP7" : 200, "ECCEHP6" : 200, "NW74" : 75 } ] }
volume_attachment1:
type: OS::Cinder::VolumeAttachment
properties:
volume_id: { get_resource: cinder_volume1 }
instance_uuid: { get_resource: nova_instance }
mountpoint: /dev/vdc
volume_attachment2:
type: OS::Cinder::VolumeAttachment
properties:
volume_id: { get_resource: cinder_volume2 }
instance_uuid: { get_resource: nova_instance }
mountpoint: /dev/vdd
association:
type: OS::Nova::FloatingIPAssociation
properties:
floating_ip: { get_resource: floating_ip }
server_id: { get_resource: nova_instance }
outputs:
instance_ip:
description: Public IP address of the newly created Nova instance.
value: { get_attr: [nova_instance, first_address] }
Be the first to leave a comment
You must be Logged on to comment or reply to a post.