"""
PCSStatus - command ``pcs status``
==================================
This module provides the classs ``PCSStatus`` which processes
``/usr/sbin/pcs status`` command output. Typical output of the ``pcs status``
command looks like::
Cluster name: mycluster
Last updated: Thu Dec 1 02:33:50 2016 Last change: Wed Aug 3 03:47:11 2016 by root via cibadmin on nodea.example.com
Stack: corosync
Current DC: nodea.example.com (version 1.1.13-10.el7-44eb2dd) - partition WITHOUT quorum
3 nodes and 3 resources configured
Online: [ nodea.example.com ]
OFFLINE: [ nodeb.example.com nodec.example.com ]
Full list of resources:
myfence (stonith:fence_xvm): Stopped
Resource Group: myweb
webVIP (ocf::heartbeat:IPaddr2): Stopped
webserver (ocf::heartbeat:apache): Stopped
PCSD Status:
nodea.example.com: Online
nodeb.example.com: Offline
nodec.example.com: Offline
Daemon Status:
corosync: active/enabled
pacemaker: active/enabled
pcsd: active/enabled
The class ``PCSStatus`` has one attribute ``data`` which is a dict containing
the whole the output and one attribute ``nodes`` is a list containing all
node names that from ``PCSD Status`` section.
Examples:
>>> pcsstatus_content = '''
... Cluster name: openstack
... Last updated: Fri Oct 14 15:45:32 2016
... Last change: Thu Oct 13 20:02:27 2016
... Stack: corosync
... Current DC: myhost15 (1) - partition with quorum
... Version: 1.1.12-a14efad
... 3 Nodes configured
... 143 Resources configured
... online: [ myhost15 myhost16 myhost17 ]
... Full list of resources:
... stonith-ipmilan-10.24.221.172 (stonith:fence_ipmilan): Started myhost15
... stonith-ipmilan-10.24.221.171 (stonith:fence_ipmilan): Started myhost16
... stonith-ipmilan-10.24.221.173 (stonith:fence_ipmilan): Started myhost15
... PCSD Status:
... myhost15: Online
... myhost17: Online
... myhost16: Online
... Daemon Status:
... corosync: active/enabled
... pacemaker: active/enabled
... pcsd: active/enabled
... '''.strip()
>>> from insights.tests import context_wrap
>>> shared = {PCSStatus: PCSStatus(context_wrap(pcsstatus_content))}
>>> pcsstatus_info = shared[PCSStatus]
>>> pcsstatus_info.get("Cluster name")
'openstack'
>>> pcsstatus_info.get("Stack")
'corosync'
>>> pcsstatus_info.get("Nodes configured")
'3'
>>> pcsstatus_info.get("Resources configured")
'143'
>>> pcsstatus_info.nodes
['myhost15', 'myhost17', 'myhost16']
>>> len(pcsstatus_info.get("Full list of resources"))
3
"""
from .. import parser, CommandParser
from insights.specs import Specs
[docs]@parser(Specs.pcs_status)
class PCSStatus(CommandParser):
"""Class to process the output of ``pcs status`` command.
Attributes:
nodes (list): A list containing all node names according "PCSD Status" section
data (dict): A dict containing key, value for each line of the output in
the form::
{
"Resources configured": "143",
"PCSD Status": [
"myhost15: Online",
"myhost17: Online",
"myhost16: Online"
],
"Current DC": "myhost15 (1) - partition with quorum",
"Full list of resources": [
"stonith-ipmilan-10.24.221.172\t(stonith:fence_ipmilan):\tStarted myhost15",
"stonith-ipmilan-10.24.221.171\t(stonith:fence_ipmilan):\tStarted myhost16",
"stonith-ipmilan-10.24.221.173\t(stonith:fence_ipmilan):\tStarted myhost15",
],
"Daemon Status": [
"corosync: active/enabled",
"pacemaker: active/enabled",
"pcsd: active/enabled"
],
"Nodes configured": "3",
"Online": "[ myhost15 myhost16 myhost17 ]",
"Cluster name": "openstack",
"Stack": "corosync"
}
"""
[docs] def parse_content(self, content):
self.nodes = []
self.data = {}
self.bad_nodes = []
# according this file https://github.com/ClusterLabs/pacemaker/blob/d078ca4a9ac72fc96073a215da2eed48939536f5/tools/crm_mon.c
key_oneline = (
"Cluster name", "Stack", "Current DC", "Online", "RemoteOnline", "OFFLINE", "RemoteOFFLINE", "GuestOnline")
key_nextline = ("Full list of resources", "Failed Actions", "PCSD Status", "Daemon Status")
key_nextline_start = 0
multiple_lines = []
for line in content:
if line.startswith("WARNING:"):
if "WARNING" in self.data:
self.data["WARNING"].append(line.strip())
else:
self.data["WARNING"] = [line.strip()]
continue
if (line.startswith("RemoteNode") or line.startswith("GuestNode") or line.startswith("Node")):
linesplit = line.split()
bad_node = {}
bad_node['name'] = linesplit[1][0:-1]
bad_node['status'] = line.split(':')[1][1:]
self.bad_nodes.append(bad_node)
if line.startswith(key_nextline):
key_nextline_start = 1
multiple_lines = []
self.data[line.split(":")[0]] = multiple_lines
continue
if key_nextline_start == 0:
linesplit = line.split()
if line.startswith(key_oneline):
key, value = line.split(":", 1)
self.data[key.strip()] = value.strip()
elif "Nodes configured" in line:
self.data["Nodes configured"] = linesplit[0]
elif "Resources configured" in line:
self.data["Resources configured"] = linesplit[0]
elif "resources configured" in line:
if "and" in line: # 3 nodes and 3 resources configured
self.data['Nodes configured'] = linesplit[0]
self.data["Resources configured"] = linesplit[3]
else: # key_nextline_start > 0
if line.strip():
multiple_lines.append(line.strip())
pcsd_status = self.data.get("PCSD Status")
if pcsd_status:
# According "PCSD Status" to get node list
for line in pcsd_status:
self.nodes.append(line.split(":")[0].strip())
[docs] def get(self, i_key):
"""str/list: Returns the data associated with ``i_key`` or ``None`` if ``i_key`` is not present"""
return self.data.get(i_key)