/usr/share/pyshared/cts/CIB.py is in pacemaker 1.1.7-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | '''CTS: Cluster Testing System: CIB generator
'''
__copyright__='''
Author: Andrew Beekhof <abeekhof@suse.de>
Copyright (C) 2008 Andrew Beekhof
'''
from UserDict import UserDict
import sys, time, types, syslog, os, struct, string, signal, traceback, warnings, socket
from cts.CTSvars import *
from cts.CTS import ClusterManager
class CibBase:
cts_cib = None
cib_tmpfile = None
version = "unknown"
feature_set = "unknown"
target = None
def __init__(self, CM, tmpfile=None):
self.CM = CM
#self.target = self.CM.Env["nodes"][0]
if not tmpfile:
warnings.filterwarnings("ignore")
self.cib_tmpfile=os.tmpnam()
warnings.resetwarnings()
else:
self.cib_tmpfile = tmpfile
def version(self):
return self.version
def NextIP(self):
fields = string.split(self.CM.Env["IPBase"], '.')
fields[3] = str(int(fields[3])+1)
ip = string.join(fields, '.')
self.CM.Env["IPBase"] = ip
return ip
class CIB10(CibBase):
feature_set = "3.0"
version = "pacemaker-1.0"
cib_template = '''
<cib crm_feature_set='%s' admin_epoch='1' epoch='0' num_updates='0' validate-with='%s' %s>
<configuration>
<crm_config/>
<nodes/>
<resources/>
<constraints/>
</configuration>
<status/>
</cib>'''
def _create(self, command):
fixed = "HOME=/root CIB_file="+self.cib_tmpfile+" crm --force configure " + command
rc = self.CM.rsh(self.target, fixed)
if rc != 0:
self.CM.log("Configure call failed: "+fixed)
sys.exit(1)
def _show(self, command=""):
output = ""
(rc, result) = self.CM.rsh(self.target, "HOME=/root CIB_file="+self.cib_tmpfile+" crm configure show "+command, None, )
for line in result:
output += line
self.CM.debug("Generated Config: "+line)
return output
def NewIP(self, name=None, standard="ocf:heartbeat"):
ip = self.NextIP()
if not name:
name = "r"+ip
if not standard:
standard = ""
else:
standard += ":"
self._create('''primitive %s %sIPaddr params ip=%s cidr_netmask=32 op monitor interval=5s'''
% (name, standard, ip))
return name
def install(self, target):
old = self.cib_tmpfile
# Force a rebuild
self.cts_cib = None
self.cib_tmpfile = CTSvars.CRM_CONFIG_DIR+"/cib.xml"
self.contents(target)
self.CM.rsh(self.target, "chown "+CTSvars.CRM_DAEMON_USER+" "+self.cib_tmpfile)
self.cib_tmpfile = old
def contents(self, target=None):
# fencing resource
if self.cts_cib:
return self.cts_cib
if not target:
self.target = self.CM.Env["nodes"][0]
else:
self.target = target
cib_base = self.cib_template % (self.feature_set, self.version, ''' remote-tls-port='9898' remote-clear-port='9999' ''')
self.CM.rsh(self.target, '''echo "%s" > %s''' % (cib_base, self.cib_tmpfile))
#self.CM.rsh.cp(self.cib_tmpfile, "root@%s:%s" % (self.target, self.cib_tmpfile))
nodelist = ""
self.num_nodes = 0
for node in self.CM.Env["nodes"]:
nodelist += node + " "
self.num_nodes = self.num_nodes + 1
no_quorum = "stop"
if self.num_nodes < 3:
no_quorum = "ignore"
self.CM.log("Cluster only has %d nodes, configuring: no-quroum-policy=ignore" % self.num_nodes)
# The shell no longer functions when the lrmd isn't running, how wonderful
# Start one here and let the cluster clean it up when the full stack starts
# Just hope target has the same location for lrmd
self.CM.rsh(self.target, CTSvars.CRM_DAEMON_DIR+"/lrmd", synchronous=0)
# Tell the shell to mind its own business, we know what we're doing
self.CM.rsh(self.target, "crm options check-mode relaxed")
# Fencing resource
# Define first so that the shell doesn't reject every update
if self.CM.Env["DoFencing"]:
params = None
entries = string.split(self.CM.Env["stonith-params"], ',')
for entry in entries:
(name, value) = string.split(entry, '=')
if name == "hostlist" and value == "all":
value = string.join(self.CM.Env["nodes"], " ")
if params:
params = ("""%s '%s="%s"' """ % (params, name, value))
else:
params = ("""'%s="%s"' """ % (name, value))
if params:
params = "params %s" % params
else:
params = ""
# Set a threshold for unreliable stonith devices such as the vmware one
self._create('''primitive Fencing stonith::%s %s meta migration-threshold=5 op monitor interval=120s timeout=300 op start interval=0 timeout=180s op stop interval=0 timeout=180s''' % (self.CM.Env["stonith-type"], params))
self._create('''property stonith-enabled=%s''' % (self.CM.Env["DoFencing"]))
self._create('''property start-failure-is-fatal=false pe-input-series-max=5000 default-action-timeout=60s''')
self._create('''property shutdown-escalation=5min batch-limit=10 dc-deadtime=5s''')
self._create('''property no-quorum-policy=%s expected-quorum-votes=%d''' % (no_quorum, self.num_nodes))
if self.CM.Env["DoBSC"] == 1:
self._create('''property ident-string="Linux-HA TEST configuration file - REMOVEME!!"''')
# Add resources?
if self.CM.Env["CIBResource"] == 1:
self.add_resources()
if self.CM.cluster_monitor == 1:
self._create('''primitive cluster_mon ocf:pacemaker:ClusterMon params update=10 extra_options="-r -n" user=abeekhof htmlfile=/suse/abeekhof/Export/cluster.html op start interval=0 requires=nothing op monitor interval=5s requires=nothing''')
self._create('''location prefer-dc cluster_mon rule -INFINITY: \#is_dc eq false''')
# generate cib
self.cts_cib = self._show("xml")
if self.cib_tmpfile != CTSvars.CRM_CONFIG_DIR+"/cib.xml":
self.CM.rsh(self.target, "rm -f "+self.cib_tmpfile)
return self.cts_cib
def add_resources(self):
# Group Resource
r1 = self.NewIP()
#ip = self.NextIP()
#r2 = "r"+ip
#self._create('''primitive %s heartbeat::IPaddr params 1=%s/32 op monitor interval=5s''' % (r2, ip))
r2 = self.NewIP()
r3 = self.NewIP()
self._create('''group group-1 %s %s %s''' % (r1, r2, r3))
# Per-node resources
for node in self.CM.Env["nodes"]:
r = self.NewIP("rsc_"+node)
self._create('''location prefer-%s %s rule 100: \#uname eq %s''' % (node, r, node))
# LSB resource
lsb_agent = self.CM.install_helper("LSBDummy")
self._create('''primitive lsb-dummy lsb::''' +lsb_agent+ ''' op monitor interval=5s''')
self._create('''colocation lsb-with-group INFINITY: lsb-dummy group-1''')
self._create('''order lsb-after-group mandatory: group-1 lsb-dummy symmetrical=true''')
# Migrator
# Make this slightly sticky (since we have no other location constraints) to avoid relocation during Reattach
self._create('''primitive migrator ocf:pacemaker:Dummy meta resource-stickiness=1 allow-migrate=1 op monitor interval=P10S''')
# Ping the test master
self._create('''primitive ping-1 ocf:pacemaker:ping params host_list=%s name=connected debug=true op monitor interval=60s''' % self.CM.Env["cts-master"])
self._create('''clone Connectivity ping-1 meta globally-unique=false''')
#master slave resource
self._create('''primitive stateful-1 ocf:pacemaker:Stateful op monitor interval=15s timeout=60s op monitor interval=16s role=Master timeout=60s ''')
self._create('''ms master-1 stateful-1 meta clone-max=%d clone-node-max=%d master-max=%d master-node-max=%d'''
% (self.num_nodes, 1, 1, 1))
# Require conectivity to run the master
self._create('''location %s-is-connected %s rule -INFINITY: connected lt %d or not_defined connected''' % ("m1", "master-1", 1))
# Group with the master
self._create('''colocation group-with-master INFINITY: group-1 master-1:Master''')
self._create('''order group-after-master mandatory: master-1:promote group-1:start symmetrical=true''')
class HASI(CIB10):
def add_resources(self):
# DLM resource
self._create('''primitive dlm ocf:pacemaker:controld op monitor interval=120s''')
self._create('''clone dlm-clone dlm meta globally-unique=false interleave=true''')
# O2CB resource
self._create('''primitive o2cb ocf:ocfs2:o2cb op monitor interval=120s''')
self._create('''clone o2cb-clone o2cb meta globally-unique=false interleave=true''')
self._create('''colocation o2cb-with-dlm INFINITY: o2cb-clone dlm-clone''')
self._create('''order start-o2cb-after-dlm mandatory: dlm-clone o2cb-clone''')
class ConfigFactory:
def __init__(self, CM):
self.CM = CM
self.register("pacemaker10", CIB10, CM)
self.register("hae", HASI, CM)
def register(self, methodName, constructor, *args, **kargs):
"""register a constructor"""
_args = [constructor]
_args.extend(args)
setattr(self, methodName, apply(ConfigFactoryItem,_args, kargs))
def unregister(self, methodName):
"""unregister a constructor"""
delattr(self, methodName)
def createConfig(self, name="pacemaker-1.0"):
if name == "pacemaker-1.0":
name = "pacemaker10";
elif name == "pacemaker-1.1":
name = "pacemaker11";
elif name == "pacemaker-1.2":
name = "pacemaker12";
elif name == "hasi":
name = "hae";
if hasattr(self, name):
return getattr(self, name)()
else:
self.CM.log("Configuration variant '%s' is unknown. Defaulting to latest config" % name)
return self.pacemaker10()
class ConfigFactoryItem:
def __init__(self, function, *args, **kargs):
assert callable(function), "function should be a callable obj"
self._function = function
self._args = args
self._kargs = kargs
def __call__(self, *args, **kargs):
"""call function"""
_args = list(self._args)
_args.extend(args)
_kargs = self._kargs.copy()
_kargs.update(kargs)
return apply(self._function,_args,_kargs)
#CibFactory = ConfigFactory()
|