Home > Workload Solutions > SAP > Guides > SAP HANA TDI Guides > Dell Validated Design for SAP HANA TDI with Dell PowerStore Storage > Implementing STONITH with the HA/DR provider for SAP HANA
For PowerEdge servers, configure IPMI over LAN for iDRAC to enable IPMI commands over LAN channels to any external systems:
The /etc/hosts file maintains a mapping of hostnames to IPMI IP addresses in STONITH using a standard naming convention:
# #
# IPMI mapping
#
10.230.79.85 hana01-ipmi
10.230.79.86 hana02-ipmi
10.230.79.87 hana03-ipmi
ipmitool power status –H hana01-ipmi -U root -P xxxx
If IPMI is working successfully, Chassis Power is on is returned.
chmod u+s /usr/bin/ipmitool
Create a custom HA/DR STONITH provider
To create your own HA/DR provider, perform the following steps and then add the hook method that you want to use. For more information, see the SAP HANA Administration Guide. The example here uses STONITH, which was written, tested, and validated for use with certified PowerEdge servers in SAP HANA scale-out scenarios.
To create the Dell recommended custom HA/DR STONITH provider:
The directory must be inside the /hana/shared storage of the SAP HANA installation but outside the <SID> directory structure. The example in this guide uses /hana/shared/HANA_Hooks as the location.
Sample for a HA/DR hook provider.
When using your own code in here, please copy this file to location on /hana/shared outside the HANA installation.
This file will be overwritten with each hdbupd call! To configure your own changed version of this file, please add
to your global.ini lines similar to this:
[ha_dr_provider_<HA_STONITH_Hook>]
provider = <HA_STONITH_Hook>
path = /hana/shared/HANA_Hooks
execution_order = 1
For all hooks, 0 must be returned in case of success.
"""
from hdb_ha_dr.client import HADRBase, Helper
import os, time
class HA_STONITH_Hook(HADRBase):
def __init__(self, *args, **kwargs):
# delegate construction to base class
super(HA_STONITH_Hook, self).__init__(*args, **kwargs)
def about(self):
return {"provider_company" : "Dell",
"provider_name" : "HA_STONITH_Hook", # provider name = class name
"provider_description" : "Dell STONITH HOOK for SAP HANA",
"provider_version" : "2.0"}
def startup(self, hostname, storage_partition, system_replication_mode, **kwargs):
self.tracer.debug("enter startup hook; %s" % locals())
self.tracer.debug(self.config.toString())
self.tracer.info("leave startup hook")
return 0
def shutdown(self, hostname, storage_partition, system_replication_mode, **kwargs):
self.tracer.debug("enter shutdown hook; %s" % locals())
self.tracer.debug(self.config.toString())
self.tracer.info("leave shutdown hook")
return 0
def failover(self, hostname, storage_partition, system_replication_mode, **kwargs):
self.tracer.debug("enter failover hook; %s" % locals())
self.tracer.debug(self.config.toString())
self.tracer.info("leave failover hook")
return 0
def stonith(self, failingHost, **kwargs):
self.tracer.debug("enter HANA HA stonith hook; %s" % locals())
self.tracer.debug(self.config.toString())
self.tracer.info( "Stonith - rebooting failing host %s" % failingHost)
ipmi_host = "%s-ipmi" % failingHost
power_cycle = "ipmitool power cycle -I lanplus -H %s -U root -P Xxxxxxxx " % ipmi_host
power_on = "ipmitool power on -I lanplus -H %s -U root -P Xxxxxxxxx " % ipmi_host
rc = os.system(power_cycle)
time.sleep(10)
if rc == 0:
msg = "Power cycle successfully executed to the failed host %s" % failingHost
self.tracer.info(msg)
rc = 0
elif rc !=0:
msg = "failed to power cycle %s, will try again" % failingHost
self.tracer.info(msg)
rc = os.system(power_on)
time.sleep(10)
if rc == 0:
msg = "Successfully powered on %s" % failingHost
self.tracer.info(msg)
rc = 0
elif rc !=0:
msg = "unable to power cycle %s - Please CHECK" % failingHost
self.tracer.info(msg)
return 1
self.tracer.info("leaving HANA HA stonith hook")
return rc
def preTakeover(self, isForce, **kwargs):
"""Pre takeover hook."""
self.tracer.info("%s.preTakeover method called with isForce=%s" % (self.__class__.__name__, isForce))
if not isForce:
# run pre takeover code
# run pre-check, return != 0 in case of error => will abort takeover
return 0
else:
# possible force-takeover only code
# usually nothing to do here
return 0
def postTakeover(self, rc, **kwargs):
"""Post takeover hook."""
self.tracer.info("%s.postTakeover method called with rc=%s" % (self.__class__.__name__, rc))
if rc == 0:
# normal takeover succeeded
return 0
elif rc == 1:
# waiting for force takeover
return 0
elif rc == 2:
# error, something went wrong
return 0
def srConnectionChanged(self, parameters, **kwargs):
self.tracer.debug("enter srConnectionChanged hook; %s" % locals())
# Access to parameters dictionary
hostname = parameters['hostname']
port = parameters['port']
volume = parameters['volume']
serviceName = parameters['service_name']
database = parameters['database']
status = parameters['status']
databaseStatus = parameters['database_status']
systemStatus = parameters['system_status']
timestamp = parameters['timestamp']
isInSync = parameters['is_in_sync']
reason = parameters['reason']
siteName = parameters['siteName']
self.tracer.info("leave srConnectionChanged hook")
return 0
def srReadAccessInitialized(self, parameters, **kwargs):
self.tracer.debug("enter srReadAccessInitialized hook; %s" % locals())
# Access to parameters dictionary
database = parameters['last_initialized_database']
databasesNoReadAccess = parameters['databases_without_read_access_initialized']
databasesReadAccess = parameters['databases_with_read_access_initialized']
timestamp = parameters['timestamp']
allDatabasesInitialized = parameters['all_databases_initialized']
self.tracer.info("leave srReadAccessInitialized hook")
return 0
def srServiceStateChanged(self, parameters, **kwargs):
self.tracer.debug("enter srServiceStateChanged hook; %s" % locals())
# Access to parameters dictionary
hostname = parameters['hostname']
service = parameters['service_name']
port = parameters['service_port']
status = parameters['service_status']
previousStatus = parameters['service_previous_status']
timestamp = parameters['timestamp']
daemonStatus = parameters['daemon_status']
databaseId = parameters['database_id']
databaseName = parameters['database_name']
databaseStatus = parameters['database_status']
self.tracer.info("leave srServiceStateChanged hook")
return 0
def srSecondaryUnregistered(self, parameters, **kwargs):
self.tracer.debug("enter srSecondaryUnregistered hook; %s" % locals())
# Access to parameters dictionary
siteName = parameters['site_name']
siteId = parameters['site_id']
reason = parameters['reason']
self.tracer.info("leave srSecondaryUnregistered hook")
return 0