Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F3871574
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
22 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/cts/CIB.py b/cts/CIB.py
index 40e536b547..6c7ecce5df 100644
--- a/cts/CIB.py
+++ b/cts/CIB.py
@@ -1,562 +1,562 @@
'''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
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 CIB06(CibBase):
version = "transitional-0.6"
coloc_template = """<rsc_colocation id="%s" from="%s" to="%s" to_role="%s" score="%s"/>"""
cib_template ='''
<cib admin_epoch="1" epoch="0" num_updates="0" remote_access_port="9898">
<configuration>
<crm_config> %s
</crm_config>
<nodes/>
<resources> %s
</resources>
<constraints> %s
</constraints>
</configuration>
<status/>
</cib> '''
cib_option_template = '''
<cluster_property_set id="cib-bootstrap-options"><attributes>
<nvpair id="cib-bootstrap-1" name="start-failure-is-fatal" value="false"/>
<nvpair id="cib-bootstrap-2" name="stonith-enabled" value="%d"/>
<nvpair id="cib-bootstrap-3" name="pe-input-series-max" value="30000"/>
<nvpair id="cib-bootstrap-4" name="shutdown-escalation" value="5min"/>
<nvpair id="cib-bootstrap-5" name="startup-fencing" value="false"/>
<nvpair id="cib-bootstrap-6" name="batch-limit" value="10"/>
<nvpair id="cib-bootstrap-7" name="no-quorum-policy" value="%s"/>
</attributes></cluster_property_set>'''
lsb_resource = '''
<primitive id="lsb_dummy" class="lsb" type="''' +CTSvars.CTS_home+ '''/LSBDummy">
<operations>
<op id="ocf_lsb_monitor" name="monitor" interval="5s"/>
</operations>
</primitive> '''
clustermon_location_constraint = '''
<rsc_location id="run_cluster_mon" rsc="cluster_mon">
<rule id="cant_run_cluster_mon" score="-INFINITY" boolean_op="and">
<expression id="mon_expr" attribute="#is_dc" operation="eq" value="false"/>
</rule>
</rsc_location> '''
resource_group_template = '''<group id="group-1">%s %s %s</group>'''
per_node_constraint_template = '''
<rsc_location id="preferred-%s" rsc="%s" node="%s" score="100"/>'''
pingd_constraint_template = '''
<rsc_location id="%s-is-connected" rsc="%s">
<rule id="%s-connected-rule" role="%s" score="-INFINITY">
<expression id="%s-connected-expr" attribute="connected" operation="lt" value="%d"/>
</rule>
</rsc_location>'''
dummy_resource_template = '''
<primitive id="%s" class="ocf" type="Dummy" provider="heartbeat">
<operations>
<op id="mon-%s" name="monitor" interval="P10S"/>
</operations>
<instance_attributes id="%s-attrs"><attributes>
<nvpair id="migrate-%s" name="allow_migrate" value="1"/>
</attributes></instance_attributes>
</primitive> '''
clustermon_resource_template = '''
<primitive id="cluster_mon" class="ocf" type="ClusterMon" provider="heartbeat">
<operations>
<op id="cluster_mon-1" name="monitor" interval="5s" prereq="nothing"/>
<op id="cluster_mon-2" name="start" prereq="nothing"/>
</operations>
<instance_attributes id="cluster_mon-attrs">
<attributes>
<nvpair id="cluster_mon-1" name="htmlfile" value="/suse/abeekhof/Export/cluster.html"/>
<nvpair id="cluster_mon-2" name="update" value="10"/>
<nvpair id="cluster_mon-3" name="extra_options" value="-n -r"/>
<nvpair id="cluster_mon-4" name="user" value="abeekhof"/>
</attributes>
</instance_attributes>
</primitive> '''
master_slave_resource = '''
<master_slave id="master-1">
<instance_attributes id="master_rsc">
<attributes>
<nvpair id="clone_max_1" name="clone_max" value="%d"/>
<nvpair id="clone_node_max_2" name="clone_node_max" value="%d"/>
<nvpair id="master_max_3" name="master_max" value="%d"/>
<nvpair id="master_node_max_4" name="master_node_max" value="%d"/>
</attributes>
</instance_attributes>
<primitive id="ocf_msdummy" class="ocf" type="Stateful" provider="heartbeat">
<operations>
<op id="ocf_msdummy_monitor" name="monitor" interval="15s"/>
<op id="ocf_msdummy_monitor_master" name="monitor" interval="16s" role="Master"/>
</operations>
</primitive>
</master_slave>'''
pingd_resource_template = """
<clone id="Connectivity">
<meta_attributes id="pingd-opts">
<attributes>
<nvpair id="pingd-opt-1" name="globally_unique" value="false"/>
</attributes>
</meta_attributes>
<primitive id="pingd" class="ocf" provider="pacemaker" type="pingd">
<operations>
<op id="pingd-op-1" name="monitor" interval="120s"/>
</operations>
<instance_attributes id="pingd-attrs">
<attributes>
<nvpair id="pingd-attr-1" name="host_list" value="%s"/>
<nvpair id="pingd-attr-2" name="name" value="connected"/>
</attributes>
</instance_attributes>
</primitive>
</clone>"""
stonith_resource_template = """
<clone id="DoFencing">
<meta_attributes id="fencing">
<attributes>
<nvpair id="DoFencing-attr-1" name="resource_failure_stickiness" value="-1"/>
<nvpair id="DoFencing-attr-2" name="globally_unique" value="false"/>
</attributes>
</meta_attributes>
<primitive id="child_DoFencing" class="stonith" type="%s">
<operations>
<op id="DoFencing-op-1" name="monitor" interval="120s" prereq="nothing" timeout="300s"/>
<op id="DoFencing-op-2" name="start" prereq="nothing" timeout="180s"/>
<op id="DoFencing-op-3" name="stop" timeout="180s"/>
</operations>
<instance_attributes id="fencing-child">
<attributes>
<nvpair id="child_DoFencing-1" name="%s" value="%s"/>
<nvpair id="child_DoFencing-2" name="livedangerously" value="yes"/>
</attributes>
</instance_attributes>
</primitive>
</clone>"""
bsc_template = '''
<cluster_property_set id="bsc-options">
<attributes>
<nvpair id="bsc-options-ident-string" name="ident-string" value="Linux-HA TEST configuration file - REMOVEME!!"/>
</attributes>
</cluster_property_set>'''
def NewIP(self, name=None):
template = '''
<primitive id="%s" class="ocf" type="IPaddr" provider="heartbeat">
<operations>
<op id="mon-%s" name="monitor" interval="5s"/>
</operations>
<instance_attributes id="attrs-%s"><attributes>
<nvpair id="netmask-%s" name="cidr_netmask" value="32"/>
<nvpair id="ip-%s" name="ip" value="%s"/>
</attributes></instance_attributes>
</primitive> '''
ip = self.NextIP()
if not name:
name = "r"+ip
return template % (name, name, name, name, name, ip)
def NewHBIP(self, name=None):
template = '''
<primitive id="%s" class="heartbeat" type="IPaddr">
<operations>
<op id="mon-%s" name="monitor" interval="5s"/>
</operations>
<instance_attributes id="attrs-%s"><attributes>
<nvpair id="ip-%s" name="1" value="%s/32"/>
</attributes></instance_attributes>
</primitive> '''
ip = self.NextIP()
if not name:
name = "r"+ip
return template % (name, name, name, name, ip)
def NewDummy(self, name):
return self.dummy_resource_template % (name, name, name, name)
def install(self, target):
self.CM.rsh("localhost", "echo \'" + self.contents(target) + "\' > " + self.cib_tmpfile)
rc = self.CM.rsh.cp(cib_file, "root@%s:%s/cib.xml" + (target, CTSvars.CRM_CONFIG_DIR))
if rc != 0:
raise ValueError("Can not copy %s to %s (%d)"%(self.cib_tmpfile, target, rc))
self.CM.rsh(target, "chown "+CTSvars.CRM_DAEMON_USER+" "+CTSvars.CRM_CONFIG_DIR+"/cib.xml")
self.CM.rsh("localhost", "rm -f "+self.cib_tmpfile)
def contents(self, target=None):
# fencing resource
if self.cts_cib:
return self.cts_cib
nodelist = ""
num_nodes = 0
for node in self.CM.Env["nodes"]:
nodelist += node + " "
num_nodes = num_nodes + 1
no_quorum = "stop"
if num_nodes < 3:
no_quorum = "ignore"
self.CM.debug("Cluster only has %d nodes, ignoring quorum" % num_nodes)
#make up crm config
cib_options = self.cib_option_template % (self.CM.Env["DoFencing"], no_quorum)
#create resources and their constraints
resources = ""
constraints = ""
if self.CM.Env["DoBSC"] == 1:
cib_options = cib_options + self.bsc_template
if self.CM.Env["CIBResource"] != 1:
# generate cib
self.cts_cib = self.cib_template % (cib_options, resources, constraints)
return self.cts_cib
if self.CM.cluster_monitor == 1:
resources += self.clustermon_resource_template
constraints += self.clustermon_location_constraint
ip1_rsc = self.NewIP()
ip2_rsc = self.NewHBIP()
ip3_rsc = self.NewIP()
resources += self.resource_group_template % (ip1_rsc, ip2_rsc, ip3_rsc)
# lsb resource
resources += self.lsb_resource
# Migrator
resources += self.NewDummy("migrator")
constraints += self.coloc_template % ("group-with-master", "group-1", "master-1", "Master", "INFINITY")
constraints += self.coloc_template % ("lsb-with-group", "lsb_dummy", "group-1", "Started", "INFINITY")
# per node resource
for node in self.CM.Env["nodes"]:
per_node_resources = self.NewIP("rsc_"+node)
per_node_constraint = self.per_node_constraint_template % (node, "rsc_"+node, node)
resources += per_node_resources
constraints += per_node_constraint
# Ping the test master
resources += self.pingd_resource_template % os.uname()[1]
# Require conectivity to run
constraints += self.pingd_constraint_template % ("master-1", "master-1", "m", "Started", "m", 1)
if self.CM.Env["DoFencing"]:
p_name = None
p_value = None
entries = string.split(self.CM.Env["stonith-params"], ',')
for entry in entries:
(p_name, p_value) = string.split(entry, '=')
if p_name == "hostlist" and p_value == "all":
p_value = string.join(self.CM.Env["nodes"], " ")
stonith_resource = self.stonith_resource_template % (self.CM.Env["stonith-type"], p_name, p_value)
resources += stonith_resource
#master slave resource
resources += self.master_slave_resource % (num_nodes, 1, 1, 1)
# generate cib
self.cts_cib = self.cib_template % (cib_options, resources, constraints)
return self.cts_cib
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.debug("Cluster only has %d nodes, ignoring quorum" % 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")
# Now stop the shell from rejecting every update because we've not defined stonith resources yet
self._create('''property stonith-enabled=false''')
self._create('''property start-failure-is-fatal=false pe-input-series-max=5000''')
self._create('''property shutdown-escalation=5min startup-fencing=false 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()
# Fencing resource
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 = ""
self._create('''primitive FencingChild stonith::%s %s op monitor interval=120s timeout=300 op start interval=0 timeout=180s op stop interval=0 timeout=180s''' % (self.CM.Env["stonith-type"], params))
# Set a threshold for unreliable stonith devices such as the vmware one
self._create('''clone Fencing FencingChild meta globally-unique=false migration-threshold=5''')
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''')
self._create('''property stonith-enabled=%s''' % (self.CM.Env["DoFencing"]))
# 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
self._create('''primitive migrator ocf:pacemaker:Dummy meta 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=120s''' % os.uname()[1])
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 op monitor interval=16s role=Master''')
+ 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("pacemaker06", CIB06, 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-0.6":
name = "pacemaker06";
elif name == "pacemaker-1.0":
name = "pacemaker10";
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()
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, May 12, 5:07 PM (22 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1753937
Default Alt Text
(22 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment