-
Notifications
You must be signed in to change notification settings - Fork 0
/
pacemaker.py
228 lines (182 loc) · 6.42 KB
/
pacemaker.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# -*- coding: utf-8 -*-
'''
Module for managing the Pacemaker clusters
Copyright (C) 2017 Davide Madrisan <davide.madrisan.gmail.com>
'''
# Import python libs
from xml.dom.minidom import parseString
try:
from pcs import utils
from pcs.lib import pacemaker as lib_pacemaker
HAS_PCS_LIBS = True
except ImportError:
HAS_PCS_LIBS = False
# Import salt libs
from salt.exceptions import CommandExecutionError
# Define the module's virtual name
__virtualname__ = 'pacemaker'
def __virtual__():
'''
Confine this execution module on Red Hat systems with the pcs library
'''
if __grains__.get('os_family') == 'RedHat':
if not HAS_PCS_LIBS:
return (False, 'The pcs python library cannot be loaded')
return True
return (False,
'The {0} module cannot be loaded: '
'unsupported OS family'.format(__virtualname__))
def cluster_local_node():
'''
Return the name of the local cluster member.
CLI Example:
.. code-block:: bash
salt '*' pacemaker.cluster_local_node
'''
node_status = cluster_local_node_status()
return node_status.get('name', '')
def cluster_local_node_status():
'''
Return the status of the local cluster member.
CLI Example:
.. code-block:: bash
salt '*' pacemaker.cluster_local_node_status
'''
try:
node_status = lib_pacemaker.get_local_node_status(
utils.cmd_runner()
)
except LibraryError as e:
raise CommandExecutionError('Unable to get node status: {0}'.format(
'\n'.join([item.message for item in e.args]))
)
return node_status
def cluster_name():
'''
Return the cluster name.
CLI Example:
.. code-block:: bash
salt '*' pacemaker.cluster_name
'''
return utils.getClusterName()
_get_node_attr = lambda node, attr: node.getAttribute(attr)
def _get_all_nodes():
info_dom = utils.getClusterState()
nodes = info_dom.getElementsByTagName('nodes')
if nodes.length == 0:
raise CommandExecutionError('No nodes section found')
all_nodes = nodes[0].getElementsByTagName('node')
return all_nodes
def cluster_nodes():
'''
Return the list of cluster nodes.
CLI Example:
.. code-block:: bash
salt '*' pacemaker.cluster_nodes
'''
all_nodes = _get_all_nodes()
name = lambda node: _get_node_attr(node, 'name')
return list(name(node) for node in all_nodes)
def cluster_nodes_status():
name = lambda node: _get_node_attr(node, 'name')
maintenance = lambda node: _get_node_attr(node, 'maintenance') == 'true'
online = lambda node: _get_node_attr(node, 'online') == 'true'
# FIXME: remote nodes are not supported (see: pcs/status.py):
#remote = lambda node: _get_node_attr(node, 'type') == 'remote'
standby = lambda node: _get_node_attr(node, 'standby') == 'true'
all_nodes = _get_all_nodes()
maintenancenodes = list(
name(node) for node in all_nodes if maintenance(node))
onlinenodes = list(name(node) for node in all_nodes if online(node))
offlinenodes = list(
name(node) for node in all_nodes if name(node) not in onlinenodes)
standbynodes = list(name(node) for node in all_nodes if standby(node))
return dict(
maintenancenodes = maintenancenodes,
offlinenodes = offlinenodes,
onlinenodes = onlinenodes,
standbynodes = standbynodes)
def cluster_resource_group_list():
groups = list()
group_xpath = '//group'
group_xml = utils.get_cib_xpath(group_xpath)
# If no groups exist, we silently return
if not group_xml:
return groups
element = parseString(group_xml).documentElement
# If there is more than one group returned it's wrapped in an xpath-query
# element
elements = (element.getElementsByTagName('group')
if element.tagName == 'xpath-query' else list(element))
return dict((e.getAttribute("id"),
list(e.getAttribute("id") for e in
e.getElementsByTagName("primitive"))) for e in elements)
def cluster_resources():
'''
Return the cluster status resources.
CLI Example:
.. code-block:: bash
salt '*' pacemaker.cluster_resources
'''
info_dom = utils.getClusterState()
resources = info_dom.getElementsByTagName('resources')
if resources.length == 0:
raise CommandExecutionError('No resources section found')
def _pack_data(resource):
nodes = resource.getElementsByTagName('node')
node = list(node.getAttribute('name')
for node in nodes if nodes.length > 0)
resource_agent = resource.getAttribute('resource_agent')
resource_id = resource.getAttribute('id')
role = resource.getAttribute('role')
return (resource_id, dict(
resource_agent = resource_agent,
role = role,
node = node[0] if len(node) == 1 else node))
return dict(_pack_data(resource)
for resource in resources[0].getElementsByTagName('resource'))
def cluster_service_status():
'''
Return the status (enable/running) of the cluster services?
CLI Example:
.. code-block:: bash
salt '*' pacemaker.cluster_service_status
'''
services = [
'corosync',
'pacemaker',
'pacemaker_remote',
'pcsd',
'sbd',
]
enabled_services = __salt__['service.get_enabled']()
def _pack_data(service):
enabled = service in enabled_services
running = __salt__['service.status'](service)
return dict(
enabled = enabled,
running = running,
)
return dict((service, _pack_data(service)) for service in services)
def cluster_stonith_configured():
'''
Check whether stonith is configured or not.
Return False if no stonith devices are detected and
stonith-enabled is not false.
CLI Example:
.. code-block:: bash
salt '*' pacemaker.cluster_stonith_configured
'''
return not utils.stonithCheck()
def is_cluster_member():
'''
Check if a system cluster is running on this node.
CLI Example:
.. code-block:: bash
salt '*' pacemaker.is_cluster_member
'''
monitor_command = ['crm_mon', '--one-shot']
output, retval = utils.run(monitor_command)
if retval != 0:
return (False, 'Cluster is not currently running on this node')
return (True)