First pass at STONITH support.

This commit is contained in:
Adam Gandelman
2013-01-24 13:24:09 -08:00
parent ec0748635a
commit cba1d3c816
4 changed files with 149 additions and 0 deletions

View File

@@ -23,3 +23,16 @@ options:
.
This configuration element is mandatory and the service will fail on
install if it is not provided.
stonith_enabled:
type: string
default: 'False'
description: |
Enable resource fencing (aka STONITH) for every node in the cluster.
This requires MAAS credentials be provided and each node's power
parameters are properly configured in its invenvory.
maas_url:
type: string
description: MAAS API endpoint.
maas_credentials:
type: string
description: MAAS credentials.

View File

@@ -293,6 +293,37 @@ def configure_cluster():
cmd = 'crm resource cleanup %s' % res_name
pcmk.commit(cmd)
if utils.config_get('stonith_enabled') in ['true', 'True']:
utils.juju_log('INFO', 'Configuring STONITH for all nodes in cluster.')
# configure stontih resources for all nodes in cluster.
# note: this is totally provider dependent and requires
# access to the MAAS API endpoint, using endpoint and credentials
# set in config.
url = utils.config_get('maas_url')
creds = utils.config_get('maas_credentials')
if None in [url, creds]:
utils.juju_log('ERROR', 'maas_url and maas_credentials must be set'\
' in config to enable STONITH.')
maas = maas.MAASHelper(url, creds)
nodes = maas.list_nodes()
if not nodes:
utils.juju_log('ERROR', 'Could not obtain node inventory from '\
'MAAS @ %s.' % url)
sys.exit(1)
hosts = get_cluster_nodes()
for host in hosts:
rsc, constraint = pcmk.maas_stonith_primitive(nodes, host)
if not rsc:
utils.juju_log('ERROR',
'Failed to determine STONITH primitive for node'\
' %s' % host)
cmd = 'crm -F configure %s' % rsc
pcmk.commit(cmd)
if constraint:
cmd = 'crm -F configure %s' % constraint
pcmk.commit(cmd)
for rel_id in utils.relation_ids('ha'):
utils.relation_set(rid=rel_id,
clustered="yes")

64
hooks/maas.py Normal file
View File

@@ -0,0 +1,64 @@
import apt_pkg as apt
import json
import sys
import subprocess
import utils
MAAS_STABLE_PPA = 'ppa:maas-maintainers/stable '
MAAS_PROFILE_NAME = 'maas-juju-hacluster'
class MAASHelper(object):
def __init__(url, creds):
self.url = url
self.creds = creds
self.install_maas_cli()
def install_maas_cli(self):
'''
Ensure maas-cli is installed. Fallback to MAAS stable PPA when
needed.
'''
apt.init()
cache = apt.Cache()
try:
pkg = cache['maas-cli']
except KeyError:
cmd = ['add-apt-repository', '-y', MAAS_STABLE_PPA]
subprocess.check_call(cmd)
cmd = ['apt-get', 'update']
subprocess.check_call(cmd)
install_maas_cli()
return
if not pkg.current_ver:
utils.install('maas-cli')
def login(self):
cmd = ['maas-cli', 'login', MAAS_PROFILE_NAME, self.url, self.creds]
try:
subprocess.check_call(cmd)
except subprocess.CalledProcessError:
utils.juju_log('ERROR', 'Could not login to MAAS @ %s.' % url)
return False
def logout(self):
cmd = ['maas-cli', 'logout', MAAS_PROFILE_NAME]
subprocess.check_call(cmd)
def list_nodes():
self.login()
try:
cmd = ['maas-cli', MAAS_PROFILE_NAME, 'nodes', 'list']
out = subprocess.check_output(cmd)
except subprocess.CalledProcessError:
utils.juju_log('ERROR', 'Could not get node inventory from MAAS.')
return False
self.logout()
return json.loads(out)

View File

@@ -52,3 +52,44 @@ def crm_opt_exists(opt_name):
if opt:
return True
return False
def _maas_ipmi_stonith_resource(host, power_params):
crm_node = crm_node_name(host)
rsc_name = '%s_res_stonith' % crm_node
rsc = 'primitive %s stonith:external/ipmi' % rsc_name
rsc += ' params hostname=%s ipaddr=%s user=%s passwd=%s interface=lan' %\
(crm_node, power_params['power_address'],
power_params['power_user'], power_params['power_pass'])
# ensure ipmi stonith agents are not running on the hosts that
# they manage.
constraint = 'location const_loc_stonith_avoid_%s %s -inf: %s' %\
(crm_node, rsc_name, crm_node)
return rsc, constraint
def maas_stonith_primitive(maas_nodes, host):
power_type = power_params = None
for node in maas_nodes:
if node['hostname'] == host:
power_type = node['power_type']
power_params = node['power_parameters']
if not power_type or not power_params:
return False, False
rsc = constraint = None
# we can extend to support other power flavors in the future?
if power_type == 'ipmi':
rsc, constraint = _maas_ipmi_stonith_resource(host, power_params)
else:
utils.juju_log('ERROR',
'Unsupported STONITH power_type: %s' % power_type)
return False, False
if not rsc or not constraint:
return False, False
return rsc, constraint