1
1
# Copyright (C) 2008-2011 Dejan Muhamedagic <dmuhamedagic@suse.de>
3
3
# This program is free software; you can redistribute it and/or
4
4
# modify it under the terms of the GNU General Public
5
5
# License as published by the Free Software Foundation; either
6
6
# version 2.1 of the License, or (at your option) any later version.
8
8
# This software is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
11
# General Public License for more details.
13
13
# You should have received a copy of the GNU General Public
14
14
# License along with this library; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
24
from cache import WCache
25
25
from vars import Vars, getpwdent
26
from utils import stdout2list, is_program, is_process, add_sudo
27
from utils import os_types_list, get_stdout, find_value
28
from utils import crm_msec, crm_time_cmp
29
from msg import common_debug, common_err, common_warn, common_info
30
from msg import user_prefs
30
33
# Resource Agents interface (meta-data, parameters, etc)
32
35
lrmadmin_prog = "lrmadmin"
33
38
class RaLrmd(object):
35
40
Getting information from the resource agents.
37
42
def __init__(self):
38
43
self.good = self.is_lrmd_accessible()
39
45
def lrmadmin(self, opts, xml=False):
41
47
Get information directly from lrmd using lrmadmin.
43
49
rc, l = stdout2list("%s %s" % (lrmadmin_prog, opts))
45
l = l[1:] # skip the first line
51
l = l[1:] # skip the first line
47
54
def is_lrmd_accessible(self):
48
55
if not (is_program(lrmadmin_prog) and is_process("lrmd")):
50
return subprocess.call(\
51
add_sudo(">/dev/null 2>&1 %s -C" % lrmadmin_prog), \
57
return subprocess.call(
58
add_sudo(">/dev/null 2>&1 %s -C" % lrmadmin_prog),
53
61
def meta(self, ra_class, ra_type, ra_provider):
54
return self.lrmadmin("-M %s %s %s"%(ra_class, ra_type, ra_provider), True)
62
return self.lrmadmin("-M %s %s %s" % (ra_class, ra_type, ra_provider), True)
55
64
def providers(self, ra_type, ra_class="ocf"):
56
65
'List of providers for a class:type.'
57
66
return self.lrmadmin("-P %s %s" % (ra_class, ra_type), True)
60
70
return self.lrmadmin("-C")
61
72
def types(self, ra_class="ocf", ra_provider=""):
62
73
'List of types for a class.'
63
74
return self.lrmadmin("-T %s" % ra_class)
65
77
class RaOS(object):
67
79
Getting information from the resource agents (direct).
69
81
def __init__(self):
71
84
def meta(self, ra_class, ra_type, ra_provider):
73
86
if ra_class == "ocf":
74
rc, l = stdout2list("%s/resource.d/%s/%s meta-data" % \
75
(os.environ["OCF_ROOT"], ra_provider, ra_type))
87
rc, l = stdout2list("%s/resource.d/%s/%s meta-data" %
88
(os.environ["OCF_ROOT"], ra_provider, ra_type))
76
89
elif ra_class == "stonith":
77
if ra_type.startswith("fence_") and os.path.exists("/usr/sbin/%s" % ra_type):
90
if ra_type.startswith("fence_") and os.path.exists("/usr/sbin/%s" % ra_type):
78
91
rc, l = stdout2list("/usr/sbin/%s -o metadata" % ra_type)
80
93
rc, l = stdout2list("stonith -m -t %s" % ra_type)
81
94
elif ra_class == "nagios":
82
rc, l = stdout2list("%s/check_%s --metadata" % \
83
(vars.nagios_dir, ra_type))
95
rc, l = stdout2list("%s/check_%s --metadata" %
96
(vars.nagios_dir, ra_type))
85
99
def providers(self, ra_type, ra_class="ocf"):
86
100
'List of providers for a class:type.'
134
152
# not clear when/why crm_resource exits with non-zero
137
common_debug("crm_resource %s exited with code %d" % \
155
common_debug("crm_resource %s exited with code %d" %
140
159
def meta(self, ra_class, ra_type, ra_provider):
141
return self.crm_resource("--show-metadata %s:%s:%s"%(ra_class, ra_provider, ra_type))
160
return self.crm_resource("--show-metadata %s:%s:%s" % (ra_class, ra_provider, ra_type))
142
162
def providers(self, ra_type, ra_class="ocf"):
143
163
'List of providers for OCF:type.'
144
164
if ra_class != "ocf":
145
165
common_err("no providers for class %s" % ra_class)
147
167
return self.crm_resource("--list-ocf-alternatives %s" % ra_type)
148
169
def classes(self):
149
170
'List of classes.'
150
171
l = self.crm_resource("--list-standards")
152
174
def types(self, ra_class="ocf", ra_provider=""):
153
175
'List of types for a class.'
157
179
return self.crm_resource("--list-agents %s" % ra_class)
159
182
def can_use_lrmadmin():
160
183
from distutils import version
161
184
# after this glue release all users can get meta-data and
162
185
# similar from lrmd
163
186
minimum_glue = "1.0.10"
164
rc, glue_ver = get_stdout("%s -v" % lrmadmin_prog, stderr_on = False)
165
if not glue_ver: #lrmadmin probably not found
187
rc, glue_ver = get_stdout("%s -v" % lrmadmin_prog, stderr_on=False)
188
if not glue_ver: # lrmadmin probably not found
167
190
v_min = version.LooseVersion(minimum_glue)
168
191
v_this = version.LooseVersion(glue_ver)
169
192
return v_this >= v_min or \
170
193
(getpwdent()[0] in ("root", vars.crm_daemon_user))
171
196
def crm_resource_support():
172
rc, s = get_stdout("crm_resource --list-standards", stderr_on = False)
197
rc, s = get_stdout("crm_resource --list-standards", stderr_on=False)
176
203
return vars.ra_if
224
258
return wcache.retrieve(id)
226
260
for ra in ra_if().types(ra_class):
227
if (not ra_provider or \
261
if (not ra_provider or
228
262
ra_provider in ra_providers(ra, ra_class)) \
229
263
and ra not in list:
232
266
return wcache.store(id, list)
234
269
def get_pe_meta():
235
270
if not vars.pe_metadata:
236
vars.pe_metadata = RAInfo("pengine","metadata")
271
vars.pe_metadata = RAInfo("pengine", "metadata")
237
272
return vars.pe_metadata
238
275
def get_crmd_meta():
239
276
if not vars.crmd_metadata:
240
vars.crmd_metadata = RAInfo("crmd","metadata")
277
vars.crmd_metadata = RAInfo("crmd", "metadata")
241
278
vars.crmd_metadata.set_advanced_params(vars.crmd_advanced)
242
279
return vars.crmd_metadata
243
282
def get_stonithd_meta():
244
283
if not vars.stonithd_metadata:
245
vars.stonithd_metadata = RAInfo("stonithd","metadata")
284
vars.stonithd_metadata = RAInfo("stonithd", "metadata")
246
285
return vars.stonithd_metadata
247
288
def get_cib_meta():
248
289
if not vars.cib_metadata:
249
vars.cib_metadata = RAInfo("cib","metadata")
290
vars.cib_metadata = RAInfo("cib", "metadata")
250
291
return vars.cib_metadata
251
294
def get_properties_meta():
252
295
if not vars.crm_properties_metadata:
274
320
common_debug("%s metadata exited with code %d" % (prog, rc))
277
325
def get_nodes_text(n, tag):
278
try: return n.findtext(tag).strip()
327
return n.findtext(tag).strip()
281
332
def mk_monitor_name(role, depth):
282
333
depth = depth != "0" and ("_%s" % depth) or ""
283
334
return role and role != "Started" and \
284
335
"monitor_%s%s" % (role, depth) or \
285
336
"monitor%s" % depth
286
339
def monitor_name_node(node):
287
340
depth = node.get("depth") or '0'
288
341
role = node.get("role")
289
342
return mk_monitor_name(role, depth)
290
345
def monitor_name_pl(pl):
291
346
depth = find_value(pl, "depth") or '0'
292
347
role = find_value(pl, "role")
293
348
return mk_monitor_name(role, depth)
295
351
class RAInfo(object):
297
353
A resource agent and whatever's useful about it.
308
365
if not self.ra_provider:
309
366
self.ra_provider = "heartbeat"
310
367
self.ra_elem = None
311
369
def ra_string(self):
312
370
return self.ra_class == "ocf" and \
313
371
"%s:%s:%s" % (self.ra_class, self.ra_provider, self.ra_type) or \
314
372
"%s:%s" % (self.ra_class, self.ra_type)
315
374
def error(self, s):
316
375
common_err("%s: %s" % (self.ra_string(), s))
317
377
def warn(self, s):
318
378
common_warn("%s: %s" % (self.ra_string(), s))
319
380
def info(self, s):
320
381
common_info("%s: %s" % (self.ra_string(), s))
321
383
def debug(self, s):
322
384
common_debug("%s: %s" % (self.ra_string(), s))
323
386
def set_advanced_params(self, l):
324
387
self.advanced_params = l
325
389
def filter_crmd_attributes(self):
326
390
for p in self.ra_elem.xpath("//parameters/parameter"):
327
391
if not p.get("name") in vars.crmd_user_attributes:
328
392
self.ra_elem.remove(p)
329
394
def add_ra_params(self, ra):
331
396
Add parameters from another RAInfo instance.
438
507
d2[norole_op] = d[op]
440
509
return wcache.store(id, d)
441
511
def reqd_params_list(self):
443
513
List of required parameters.
445
515
d = self.params()
447
518
return [x for x in d if d[x]["required"] == '1']
448
520
def param_default(self, pname):
450
522
Parameter's default.
452
524
d = self.params()
453
try: return d[pname]["default"]
526
return d[pname]["default"]
455
530
def unreq_param(self, p):
457
532
Allow for some exceptions.
459
534
- the rhcs stonith agents sometimes require "action" (in
460
535
the meta-data) and "port", but they're automatically
461
536
supplied by stonithd
463
538
if self.ra_class == "stonith" and \
464
(self.ra_type.startswith("rhcs/") or \
465
self.ra_type.startswith("fence_")):
539
(self.ra_type.startswith("rhcs/") or
540
self.ra_type.startswith("fence_")):
466
541
if p in ("action", "port"):
469
545
def sanity_check_params(self, id, pl, existence_only=False):
471
547
pl is a list of (attribute, value) pairs.
589
669
l.append(actions)
590
670
return '\n\n'.join(l)
591
672
def get_shortdesc(self, n):
592
673
name = n.get("name")
593
shortdesc = get_nodes_text(n,"shortdesc")
594
longdesc = get_nodes_text(n,"longdesc")
674
shortdesc = get_nodes_text(n, "shortdesc")
675
longdesc = get_nodes_text(n, "longdesc")
595
676
if shortdesc and shortdesc not in (name, longdesc, self.ra_type):
598
680
def meta_title(self):
599
681
s = self.ra_string()
600
682
shortdesc = self.get_shortdesc(self.ra_elem)
602
684
s = "%s (%s)" % (shortdesc, s)
604
687
def meta_param_head(self, n):
605
688
name = n.get("name")
623
707
self.error("no name attribute for parameter")
626
longdesc = get_nodes_text(n,"longdesc")
710
longdesc = get_nodes_text(n, "longdesc")
628
longdesc = self.ra_tab + longdesc.replace("\n", "\n"+self.ra_tab) + '\n'
712
longdesc = self.ra_tab + longdesc.replace("\n", "\n" + self.ra_tab) + '\n'
629
713
l.append(longdesc)
630
714
return '\n'.join(l)
631
716
def meta_parameter(self, param):
632
717
if self.mk_ra_node() is None:
634
719
for c in self.ra_elem.xpath("//parameters/parameter"):
635
720
if c.get("name") == param:
636
721
return self.format_parameter(c)
637
723
def meta_parameters(self):
638
724
if self.mk_ra_node() is None: