config/sysinv/sysinv/sysinv/sysinv/cluster/pacemaker.py

223 lines
6.6 KiB
Python

#
# Copyright (c) 2014 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
"""
PaceMaker
"""
import os
import sys
import uuid
import logging
from lxml import etree
LOG = logging.getLogger(__name__)
NODE_STATE_NOT_SET = ''
NODE_STATE_OFFLINE = 'offline'
NODE_STATE_ONLINE = 'online'
RESOURCE_STATE_NOT_SET = ''
RESOURCE_STATE_UNKNOWN = 'unknown'
RESOURCE_STATE_ENABLED = 'enabled'
RESOURCE_STATE_DISABLED = 'disabled'
RESOURCE_STATE_FAILED = 'failed'
class PaceMakerNode(object):
""" Pacemaker Node information about a node making up the cluster
"""
def __init__(self, node_name):
self.name = node_name
self.state = NODE_STATE_NOT_SET
class PaceMakerResource(object):
""" Pacemaker Resource information on a resource running on a node
in the cluster
"""
def __init__(self, node_name, resource_name):
self.name = resource_name
self.node_name = node_name
self.last_operation = ""
self.state = RESOURCE_STATE_NOT_SET
class Pacemaker(object):
""" Pacemaker
"""
def __init__(self):
self._xmldoc = None
def load(self):
""" Ask for the latest information on the cluster
"""
pacemaker_xml_filename = ('/tmp/pacemaker_%s.xml'
% str(uuid.uuid4()))
try:
if not os.path.exists('/usr/sbin/cibadmin'):
return
os.system("/usr/sbin/cibadmin --query > %s"
% pacemaker_xml_filename)
if not os.path.exists(pacemaker_xml_filename):
return
self._xmldoc = etree.parse(pacemaker_xml_filename)
if self._xmldoc is None:
os.remove(pacemaker_xml_filename)
return
if not etree.iselement(self._xmldoc.getroot()):
self._xmldoc = None
os.remove(pacemaker_xml_filename)
return
if len(self._xmldoc.getroot()) == 0:
self._xmldoc = None
os.remove(pacemaker_xml_filename)
return
os.remove(pacemaker_xml_filename)
except Exception:
if os.path.exists(pacemaker_xml_filename):
os.remove(pacemaker_xml_filename)
LOG.error("error:", sys.exc_info()[0])
def get_resource(self, node_name, resource_name):
""" Get a resource's information and state
"""
if self._xmldoc is None:
return None
xmlroot = self._xmldoc.getroot()
xmlresource = xmlroot.find(".//status/node_state[@id='%s']/"
"lrm[@id='%s']/lrm_resources/"
"lrm_resource[@id='%s']/lrm_rsc_op"
% (node_name, node_name, resource_name))
if not etree.iselement(xmlresource):
return None
resource = PaceMakerResource(node_name, resource_name)
resource.last_operation = xmlresource.attrib["operation"]
if (xmlresource.attrib["operation"] == "start" or
xmlresource.attrib["operation"] == "promote"):
if xmlresource.attrib["rc-code"] == "0":
resource.state = RESOURCE_STATE_ENABLED
else:
resource.state = RESOURCE_STATE_FAILED
elif (xmlresource.attrib["operation"] == "stop" or
xmlresource.attrib["operation"] == "demote"):
if xmlresource.attrib["rc-code"] == "0":
resource.state = RESOURCE_STATE_DISABLED
else:
resource.state = RESOURCE_STATE_FAILED
elif xmlresource.attrib["operation"] == "monitor":
if xmlresource.attrib["rc-code"] == "0":
resource.state = RESOURCE_STATE_ENABLED
elif xmlresource.attrib["rc-code"] == "7":
resource.state = RESOURCE_STATE_DISABLED
else:
resource.state = RESOURCE_STATE_FAILED
else:
resource.state = RESOURCE_STATE_UNKNOWN
return resource
def get_node(self, node_name):
""" Get a node's information and state
"""
if self._xmldoc is None:
return None
node = PaceMakerNode(node_name)
xmlroot = self._xmldoc.getroot()
# Check the static configuration for state.
xmlnode = xmlroot.find((".//nodes/node[@id='%s']"
"/instance_attributes[@id='nodes-%s']"
"/nvpair[@id='nodes-%s-standby']"
% (node_name, node_name, node_name)))
if etree.iselement(xmlnode):
if xmlnode.attrib["name"] == "standby":
if xmlnode.attrib["value"] == "on":
node.state = NODE_STATE_OFFLINE
return node
# Now check the running status for state.
xmlnode = xmlroot.find(".//status/node_state[@id='%s']"
% node_name)
if not etree.iselement(xmlnode):
return None
if xmlnode.attrib["in_ccm"] == "true":
if xmlnode.attrib["crmd"] == "online":
node.state = NODE_STATE_ONLINE
else:
node.state = NODE_STATE_OFFLINE
else:
node.state = NODE_STATE_OFFLINE
return node
def set_node_state(self, node_name, node_state):
""" Set the state of a node in the cluster
"""
try:
if not os.path.exists('/usr/sbin/crm'):
return False
if node_state == NODE_STATE_OFFLINE:
action = "standby"
elif node_state == NODE_STATE_ONLINE:
action = "online"
else:
LOG.warning("Unsupported state (%s) requested for %s."
% (node_state, node_name))
return False
os.system("/usr/sbin/crm node %s %s" % (action, node_name))
return True
except Exception:
LOG.error("error:", sys.exc_info()[0])
return False
def migrate_resource_to_node(self, resource_name, node_name, lifetime):
""" Migrate resource to a node in the cluster.
"""
try:
if not os.path.exists('/usr/sbin/crm'):
return False
# Lifetime follows the duration format specified in ISO_8601
os.system("/usr/sbin/crm resource migrate %s %s P%sS"
% (resource_name, node_name, lifetime))
return True
except Exception:
os.system("/usr/sbin/crm resource unmigrate %s" % resource_name)
LOG.error("error:", sys.exc_info()[0])
return False