def test_empty_property_sets(self): out = self._parse('rsc_defaults defaults:') self.assertEqual('<rsc_defaults><meta_attributes id="defaults"/></rsc_defaults>', xml_tostring(out)) out = self._parse('op_defaults defaults:') self.assertEqual('<op_defaults><meta_attributes id="defaults"/></op_defaults>', xml_tostring(out))
def test_resources(self, mock_error): out = self._parse('primitive www ocf:heartbeat:apache op monitor timeout=10s') self.assertEqual(out.get('id'), 'www') self.assertEqual(out.get('class'), 'ocf') self.assertEqual(['monitor'], out.xpath('//op/@name')) out = self._parse('rsc_template public_vm ocf:heartbeat:Xen op start timeout=300s op stop timeout=300s op monitor interval=30s timeout=60s op migrate_from timeout=600s op migrate_to timeout=600s') self.assertEqual(out.get('id'), 'public_vm') self.assertEqual(out.get('class'), 'ocf') #print out out = self._parse('primitive st stonith:ssh params hostlist=node1 meta target-role=Started requires=nothing op start timeout=60s op monitor interval=60m timeout=60s') self.assertEqual(out.get('id'), 'st') out2 = self._parse('primitive st stonith:ssh hostlist=node1 meta target-role=Started requires=nothing op start timeout=60s op monitor interval=60m timeout=60s') self.assertEqual(out2.get('id'), 'st') self.assertEqual(xml_tostring(out), xml_tostring(out2)) out = self._parse('primitive st stonith:ssh params hostlist= meta') self.assertEqual(out.get('id'), 'st') out = self._parse('primitive st stonith:null params hostlist=node1 meta requires=nothing description="some description here" op start op monitor interval=60m') self.assertEqual(out.get('id'), 'st') out = self._parse('ms m0 resource params a=b') self.assertEqual(out.get('id'), 'm0') print(xml_tostring(out)) self.assertEqual(['resource'], out.xpath('./crmsh-ref/@id')) self.assertEqual(['b'], out.xpath('instance_attributes/nvpair[@name="a"]/@value')) out2 = self._parse('ms m0 resource a=b') self.assertEqual(out.get('id'), 'm0') self.assertEqual(xml_tostring(out), xml_tostring(out2)) out = self._parse('master ma resource meta a=b') self.assertEqual(out.get('id'), 'ma') self.assertEqual(['resource'], out.xpath('./crmsh-ref/@id')) self.assertEqual(['b'], out.xpath('meta_attributes/nvpair[@name="a"]/@value')) out = self._parse('clone clone-1 resource meta a=b') self.assertEqual(out.get('id'), 'clone-1') self.assertEqual(['resource'], out.xpath('./crmsh-ref/@id')) self.assertEqual(['b'], out.xpath('meta_attributes/nvpair[@name="a"]/@value')) out = self._parse('group group-1 a') self.assertEqual(out.get('id'), 'group-1') self.assertEqual(len(out), 1) out = self._parse('group group-1 a b c') self.assertEqual(len(out), 3) out = self._parse('group group-1') self.assertFalse(out) out = self._parse('group group-1 params a=b') self.assertEqual(len(out), 1) self.assertEqual(['b'], out.xpath('/group/instance_attributes/nvpair[@name="a"]/@value'))
def test_resources(self): out = self._parse('primitive www ocf:heartbeat:apache op monitor timeout=10s') self.assertEqual(out.get('id'), 'www') self.assertEqual(out.get('class'), 'ocf') self.assertEqual(['monitor'], out.xpath('//op/@name')) out = self._parse('rsc_template public_vm ocf:heartbeat:Xen op start timeout=300s op stop timeout=300s op monitor interval=30s timeout=60s op migrate_from timeout=600s op migrate_to timeout=600s') self.assertEqual(out.get('id'), 'public_vm') self.assertEqual(out.get('class'), 'ocf') #print out out = self._parse('primitive st stonith:ssh params hostlist=node1 meta target-role=Started requires=nothing op start timeout=60s op monitor interval=60m timeout=60s') self.assertEqual(out.get('id'), 'st') out2 = self._parse('primitive st stonith:ssh hostlist=node1 meta target-role=Started requires=nothing op start timeout=60s op monitor interval=60m timeout=60s') self.assertEqual(out2.get('id'), 'st') self.assertEqual(xml_tostring(out), xml_tostring(out2)) out = self._parse('primitive st stonith:ssh params hostlist= meta') self.assertEqual(out.get('id'), 'st') out = self._parse('primitive st stonith:null params hostlist=node1 meta requires=nothing description="some description here" op start op monitor interval=60m') self.assertEqual(out.get('id'), 'st') out = self._parse('ms m0 resource params a=b') self.assertEqual(out.get('id'), 'm0') print(xml_tostring(out)) self.assertEqual(['resource'], out.xpath('./crmsh-ref/@id')) self.assertEqual(['b'], out.xpath('instance_attributes/nvpair[@name="a"]/@value')) out2 = self._parse('ms m0 resource a=b') self.assertEqual(out.get('id'), 'm0') self.assertEqual(xml_tostring(out), xml_tostring(out2)) out = self._parse('master ma resource meta a=b') self.assertEqual(out.get('id'), 'ma') self.assertEqual(['resource'], out.xpath('./crmsh-ref/@id')) self.assertEqual(['b'], out.xpath('meta_attributes/nvpair[@name="a"]/@value')) out = self._parse('clone clone-1 resource meta a=b') self.assertEqual(out.get('id'), 'clone-1') self.assertEqual(['resource'], out.xpath('./crmsh-ref/@id')) self.assertEqual(['b'], out.xpath('meta_attributes/nvpair[@name="a"]/@value')) out = self._parse('group group-1 a') self.assertEqual(out.get('id'), 'group-1') self.assertEqual(len(out), 1) out = self._parse('group group-1 a b c') self.assertEqual(len(out), 3) out = self._parse('group group-1') self.assertFalse(out) out = self._parse('group group-1 params a=b') self.assertEqual(len(out), 1) self.assertEqual(['b'], out.xpath('/group/instance_attributes/nvpair[@name="a"]/@value'))
def test_fencing_1114(self): """ Test node attribute fence target assignment """ out = self._parse('fencing_topology attr:rack=1 poison-pill power') expect = """<fencing-topology><fencing-level devices="poison-pill" index="1" target-attribute="rack" target-value="1"/><fencing-level devices="power" index="2" target-attribute="rack" target-value="1"/></fencing-topology>""" self.assertEqual(expect, xml_tostring(out)) out = self._parse('fencing_topology attr:rack=1 poison-pill,power') expect = '<fencing-topology><fencing-level devices="poison-pill,power" index="1" target-attribute="rack" target-value="1"/></fencing-topology>' self.assertEqual(expect, xml_tostring(out))
def test_fencing(self): # num test nodes are 3 out = self._parse('fencing_topology') expect = '<fencing-topology/>' self.assertEqual(expect, xml_tostring(out)) out = self._parse('fencing_topology poison-pill power') expect = '<fencing-topology><fencing-level target="ha-one" index="1" devices="poison-pill"/><fencing-level target="ha-one" index="2" devices="power"/><fencing-level target="ha-three" index="1" devices="poison-pill"/><fencing-level target="ha-three" index="2" devices="power"/><fencing-level target="ha-two" index="1" devices="poison-pill"/><fencing-level target="ha-two" index="2" devices="power"/></fencing-topology>' self.assertEqual(expect, xml_tostring(out)) out = self._parse('fencing_topology node-a: poison-pill power node-b: ipmi serial') self.assertEqual(4, len(out)) devs = ['stonith-vbox3-1-off', 'stonith-vbox3-2-off', 'stonith-vbox3-1-on', 'stonith-vbox3-2-on'] out = self._parse('fencing_topology vbox4: %s' % ','.join(devs)) print(xml_tostring(out)) self.assertEqual(1, len(out))
def test_fencing(self): # num test nodes are 3 out = self._parse('fencing_topology') expect = '<fencing-topology/>' self.assertEqual(expect, xml_tostring(out)) out = self._parse('fencing_topology poison-pill power') expect = '<fencing-topology><fencing-level devices="poison-pill" index="1" target="ha-one"/><fencing-level devices="power" index="2" target="ha-one"/><fencing-level devices="poison-pill" index="1" target="ha-three"/><fencing-level devices="power" index="2" target="ha-three"/><fencing-level devices="poison-pill" index="1" target="ha-two"/><fencing-level devices="power" index="2" target="ha-two"/></fencing-topology>' self.assertEqual(expect, xml_tostring(out)) out = self._parse('fencing_topology node-a: poison-pill power node-b: ipmi serial') self.assertEqual(4, len(out)) devs = ['stonith-vbox3-1-off', 'stonith-vbox3-2-off', 'stonith-vbox3-1-on', 'stonith-vbox3-2-on'] out = self._parse('fencing_topology vbox4: %s' % ','.join(devs)) print(xml_tostring(out)) self.assertEqual(1, len(out))
def test_comments(): xml = """<cib epoch="25" num_updates="1" admin_epoch="0" validate-with="pacemaker-1.2" cib-last-written="Thu Mar 6 15:53:49 2014" update-origin="beta1" update-client="cibadmin" update-user="******" crm_feature_set="3.0.8" have-quorum="1" dc-uuid="1"> <configuration> <crm_config> <cluster_property_set id="cib-bootstrap-options"> <nvpair id="cib-bootstrap-options-dc-version" name="dc-version" value="1.1.11-3.3-3ca8c3b"/> <nvpair id="cib-bootstrap-options-cluster-infrastructure" name="cluster-infrastructure" value="corosync"/> <!--# COMMENT TEXT 1 --> </cluster_property_set> </crm_config> <nodes> <node uname="beta1" id="1"> <!--# COMMENT TEXT 2 --> </node> </nodes> <resources/> <constraints/> <rsc_defaults> <meta_attributes id="rsc-options"> <nvpair name="resource-stickiness" value="1" id="rsc-options-resource-stickiness"/> <!--# COMMENT TEXT 3 --> </meta_attributes> </rsc_defaults> </configuration> <status> <node_state id="1" uname="beta1" in_ccm="true" crmd="online" crm-debug-origin="do_state_transition" join="member" expected="member"> <lrm id="1"> <lrm_resources/> </lrm> <transient_attributes id="1"> <instance_attributes id="status-1"> <nvpair id="status-1-shutdown" name="shutdown" value="0"/> <nvpair id="status-1-probe_complete" name="probe_complete" value="true"/> </instance_attributes> </transient_attributes> </node_state> </status> </cib>""" elems = etree.fromstring(xml) xmlutil.sanitize_cib(elems) assert xmlutil.xml_tostring(elems).count("COMMENT TEXT") == 3
def test_configs(self): outp = self._parse_lines(''' primitive rsc_dummy ocf:heartbeat:Dummy monitor rsc_dummy 30 ''') #print outp self.assertEqual(2, len(outp)) outp = self._parse_lines(''' primitive testfs ocf:heartbeat:Filesystem \ params directory="/mnt" fstype="ocfs2" device="/dev/sda1" clone testfs-clone testfs \ meta ordered="true" interleave="true" ''') #print outp self.assertEqual(2, len(outp)) inp = [ """node node1 attributes mem=16G""", """node node2 utilization cpu=4""", """primitive st stonith:ssh \ params hostlist='node1 node2' \ meta target-role="Started" requires="nothing" \ op start timeout=60s \ op monitor interval=60m timeout=60s""", """primitive st2 stonith:ssh \ params hostlist='node1 node2'""", """primitive d1 ocf:pacemaker:Dummy \ operations $id=d1-ops \ op monitor interval=60m \ op monitor interval=120m OCF_CHECK_LEVEL=10""", """monitor d1 60s:30s""", """primitive d2 ocf:heartbeat:Delay \ params mondelay=60 \ op start timeout=60s \ op stop timeout=60s""", """monitor d2:Started 60s:30s""", """group g1 d1 d2""", """primitive d3 ocf:pacemaker:Dummy""", """clone c d3 \ meta clone-max=1""", """primitive d4 ocf:pacemaker:Dummy""", """ms m d4""", """primitive s5 ocf:pacemaker:Stateful \ operations $id-ref=d1-ops""", """primitive s6 ocf:pacemaker:Stateful \ operations $id-ref=d1""", """ms m5 s5""", """ms m6 s6""", """location l1 g1 100: node1""", """location l2 c \ rule $id=l2-rule1 100: #uname eq node1""", """location l3 m5 \ rule inf: #uname eq node1 and pingd gt 0""", """location l4 m5 \ rule -inf: not_defined pingd or pingd lte 0""", """location l5 m5 \ rule -inf: not_defined pingd or pingd lte 0 \ rule inf: #uname eq node1 and pingd gt 0 \ rule inf: date lt "2009-05-26" and \ date in start="2009-05-26" end="2009-07-26" and \ date in start="2009-05-26" years="2009" and \ date date_spec years="2009" hours=09-17""", """location l6 m5 \ rule $id-ref=l2-rule1""", """location l7 m5 \ rule $id-ref=l2""", """collocation c1 inf: m6 m5""", """collocation c2 inf: m5:Master d1:Started""", """order o1 Mandatory: m5 m6""", """order o2 Optional: d1:start m5:promote""", """order o3 Serialize: m5 m6""", """order o4 inf: m5 m6""", """rsc_ticket ticket-A_m6 ticket-A: m6""", """rsc_ticket ticket-B_m6_m5 ticket-B: m6 m5 loss-policy=fence""", """rsc_ticket ticket-C_master ticket-C: m6 m5:Master loss-policy=fence""", """fencing_topology st st2""", """property stonith-enabled=true""", """property $id=cpset2 maintenance-mode=true""", """rsc_defaults failure-timeout=10m""", """op_defaults $id=opsdef2 record-pending=true""" ] outp = self._parse_lines('\n'.join(inp)) a = [xml_tostring(x) for x in outp] b = [ '<node uname="node1"><instance_attributes><nvpair name="mem" value="16G"/></instance_attributes></node>', '<node uname="node2"><utilization><nvpair name="cpu" value="4"/></utilization></node>', '<primitive id="st" class="stonith" type="ssh"><instance_attributes><nvpair name="hostlist" value="node1 node2"/></instance_attributes><meta_attributes><nvpair name="target-role" value="Started"/><nvpair name="requires" value="nothing"/></meta_attributes><operations><op name="start" timeout="60s" interval="0"/><op name="monitor" interval="60m" timeout="60s"/></operations></primitive>', '<primitive id="st2" class="stonith" type="ssh"><instance_attributes><nvpair name="hostlist" value="node1 node2"/></instance_attributes></primitive>', '<primitive id="d1" class="ocf" provider="pacemaker" type="Dummy"><operations id="d1-ops"><op name="monitor" interval="60m"/><op name="monitor" interval="120m"><instance_attributes><nvpair name="OCF_CHECK_LEVEL" value="10"/></instance_attributes></op></operations></primitive>', '<op name="monitor" rsc="d1" interval="60s" timeout="30s"/>', '<primitive id="d2" class="ocf" provider="heartbeat" type="Delay"><instance_attributes><nvpair name="mondelay" value="60"/></instance_attributes><operations><op name="start" timeout="60s" interval="0"/><op name="stop" timeout="60s" interval="0"/></operations></primitive>', '<op name="monitor" role="Started" rsc="d2" interval="60s" timeout="30s"/>', '<group id="g1"><crmsh-ref id="d1"/><crmsh-ref id="d2"/></group>', '<primitive id="d3" class="ocf" provider="pacemaker" type="Dummy"/>', '<clone id="c"><meta_attributes><nvpair name="clone-max" value="1"/></meta_attributes><crmsh-ref id="d3"/></clone>', '<primitive id="d4" class="ocf" provider="pacemaker" type="Dummy"/>', '<master id="m"><crmsh-ref id="d4"/></master>', '<primitive id="s5" class="ocf" provider="pacemaker" type="Stateful"><operations id-ref="d1-ops"/></primitive>', '<primitive id="s6" class="ocf" provider="pacemaker" type="Stateful"><operations id-ref="d1"/></primitive>', '<master id="m5"><crmsh-ref id="s5"/></master>', '<master id="m6"><crmsh-ref id="s6"/></master>', '<rsc_location id="l1" rsc="g1" score="100" node="node1"/>', '<rsc_location id="l2" rsc="c"><rule id="l2-rule1" score="100"><expression attribute="#uname" operation="eq" value="node1"/></rule></rsc_location>', '<rsc_location id="l3" rsc="m5"><rule score="INFINITY"><expression attribute="#uname" operation="eq" value="node1"/><expression attribute="pingd" operation="gt" value="0"/></rule></rsc_location>', '<rsc_location id="l4" rsc="m5"><rule score="-INFINITY" boolean-op="or"><expression attribute="pingd" operation="not_defined"/><expression attribute="pingd" operation="lte" value="0"/></rule></rsc_location>', '<rsc_location id="l5" rsc="m5"><rule score="-INFINITY" boolean-op="or"><expression attribute="pingd" operation="not_defined"/><expression attribute="pingd" operation="lte" value="0"/></rule><rule score="INFINITY"><expression attribute="#uname" operation="eq" value="node1"/><expression attribute="pingd" operation="gt" value="0"/></rule><rule score="INFINITY"><date_expression operation="lt" end="2009-05-26"/><date_expression operation="in_range" start="2009-05-26" end="2009-07-26"/><date_expression operation="in_range" start="2009-05-26"><duration years="2009"/></date_expression><date_expression operation="date_spec"><date_spec years="2009" hours="09-17"/></date_expression></rule></rsc_location>', '<rsc_location id="l6" rsc="m5"><rule id-ref="l2-rule1"/></rsc_location>', '<rsc_location id="l7" rsc="m5"><rule id-ref="l2"/></rsc_location>', '<rsc_colocation id="c1" score="INFINITY" rsc="m6" with-rsc="m5"/>', '<rsc_colocation id="c2" score="INFINITY" rsc="m5" rsc-role="Master" with-rsc="d1" with-rsc-role="Started"/>', '<rsc_order id="o1" kind="Mandatory" first="m5" then="m6"/>', '<rsc_order id="o2" kind="Optional" first="d1" first-action="start" then="m5" then-action="promote"/>', '<rsc_order id="o3" kind="Serialize" first="m5" then="m6"/>', '<rsc_order id="o4" score="INFINITY" first="m5" then="m6"/>', '<rsc_ticket id="ticket-A_m6" ticket="ticket-A" rsc="m6"/>', '<rsc_ticket id="ticket-B_m6_m5" ticket="ticket-B" loss-policy="fence"><resource_set><resource_ref id="m6"/><resource_ref id="m5"/></resource_set></rsc_ticket>', '<rsc_ticket id="ticket-C_master" ticket="ticket-C" loss-policy="fence"><resource_set><resource_ref id="m6"/></resource_set><resource_set role="Master"><resource_ref id="m5"/></resource_set></rsc_ticket>', '<fencing-topology><fencing-level devices="st" index="1" target="ha-one"/><fencing-level devices="st2" index="2" target="ha-one"/><fencing-level devices="st" index="1" target="ha-three"/><fencing-level devices="st2" index="2" target="ha-three"/><fencing-level devices="st" index="1" target="ha-two"/><fencing-level devices="st2" index="2" target="ha-two"/></fencing-topology>', '<cluster_property_set><nvpair name="stonith-enabled" value="true"/></cluster_property_set>', '<cluster_property_set id="cpset2"><nvpair name="maintenance-mode" value="true"/></cluster_property_set>', '<rsc_defaults><meta_attributes><nvpair name="failure-timeout" value="10m"/></meta_attributes></rsc_defaults>', '<op_defaults><meta_attributes id="opsdef2"><nvpair name="record-pending" value="true"/></meta_attributes></op_defaults>', ] for result, expected in zip(a, b): self.assertEqual(expected, result)
def test_comments(self): outp = self._parse_lines(''' # comment node n1 ''') self.assertNotEqual(-1, xml_tostring(outp[0]).find('# comment'))
def test_order(self): out = self._parse('order o1 Mandatory: [ A B sequential=true ] C') print(xml_tostring(out)) self.assertEqual(['Mandatory'], out.xpath('/rsc_order/@kind')) self.assertEqual(2, len(out.xpath('/rsc_order/resource_set'))) self.assertEqual(['false'], out.xpath('/rsc_order/resource_set/@require-all')) self.assertEqual(['A', 'B', 'C'], out.xpath('//resource_ref/@id')) out = self._parse('order o1 Mandatory: [ A B sequential=false ] C') self.assertEqual(2, len(out.xpath('/rsc_order/resource_set'))) #self.assertTrue(['require-all', 'false'] in out.resources[0][1]) #self.assertTrue(['sequential', 'false'] in out.resources[0][1]) self.assertEqual(out.get('id'), 'o1') out = self._parse('order o1 Mandatory: A B C sequential=false') self.assertEqual(1, len(out.xpath('/rsc_order/resource_set'))) #self.assertTrue(['sequential', 'false'] in out.resources[0][1]) self.assertEqual(out.get('id'), 'o1') out = self._parse('order o1 Mandatory: A B C sequential=true') self.assertEqual(1, len(out.xpath('/rsc_order/resource_set'))) #self.assertTrue(['sequential', 'true'] not in out.resources[0][1]) self.assertEqual(out.get('id'), 'o1') out = self._parse('order c_apache_1 Mandatory: apache:start ip_1') self.assertEqual(out.get('id'), 'c_apache_1') out = self._parse( 'order c_apache_2 Mandatory: apache:start ip_1 ip_2 ip_3') self.assertEqual(2, len(out.xpath('/rsc_order/resource_set'))) self.assertEqual(out.get('id'), 'c_apache_2') out = self._parse('order o1 Serialize: A ( B C )') self.assertEqual(2, len(out.xpath('/rsc_order/resource_set'))) self.assertEqual(out.get('id'), 'o1') out = self._parse('order o1 Serialize: A ( B C ) symmetrical=false') self.assertEqual(2, len(out.xpath('/rsc_order/resource_set'))) self.assertEqual(out.get('id'), 'o1') self.assertEqual(['false'], out.xpath('//@symmetrical')) out = self._parse('order o1 Serialize: A ( B C ) symmetrical=true') self.assertEqual(2, len(out.xpath('/rsc_order/resource_set'))) self.assertEqual(out.get('id'), 'o1') self.assertEqual(['true'], out.xpath('//@symmetrical')) inp = 'colocation rsc_colocation-master INFINITY: [ vip-master vip-rep sequential=true ] [ msPostgresql:Master sequential=true ]' out = self._parse(inp) self.assertEqual(2, len(out.xpath('/rsc_colocation/resource_set'))) self.assertEqual(out.get('id'), 'rsc_colocation-master') out = self._parse('order order_2 Mandatory: [ A B ] C') self.assertEqual(2, len(out.xpath('/rsc_order/resource_set'))) self.assertEqual(out.get('id'), 'order_2') self.assertEqual(['Mandatory'], out.xpath('/rsc_order/@kind')) self.assertEqual(['false'], out.xpath('//resource_set/@sequential')) out = self._parse('order order-1 Optional: group1:stop group2:start') self.assertEqual(out.get('id'), 'order-1') self.assertEqual(['Optional'], out.xpath('/rsc_order/@kind')) self.assertEqual(['group1'], out.xpath('/rsc_order/@first')) self.assertEqual(['stop'], out.xpath('/rsc_order/@first-action')) self.assertEqual(['group2'], out.xpath('/rsc_order/@then')) self.assertEqual(['start'], out.xpath('/rsc_order/@then-action'))
def test_configs(self): outp = self._parse_lines(''' primitive rsc_dummy ocf:heartbeat:Dummy monitor rsc_dummy 30 ''') #print outp self.assertEqual(2, len(outp)) outp = self._parse_lines(''' primitive testfs ocf:heartbeat:Filesystem \ params directory="/mnt" fstype="ocfs2" device="/dev/sda1" clone testfs-clone testfs \ meta ordered="true" interleave="true" ''') #print outp self.assertEqual(2, len(outp)) inp = [ """node node1 attributes mem=16G""", """node node2 utilization cpu=4""", """primitive st stonith:ssh \ params hostlist='node1 node2' \ meta target-role="Started" requires="nothing" \ op start timeout=60s \ op monitor interval=60m timeout=60s""", """primitive st2 stonith:ssh \ params hostlist='node1 node2'""", """primitive d1 ocf:pacemaker:Dummy \ operations $id=d1-ops \ op monitor interval=60m \ op monitor interval=120m OCF_CHECK_LEVEL=10""", """monitor d1 60s:30s""", """primitive d2 ocf:heartbeat:Delay \ params mondelay=60 \ op start timeout=60s \ op stop timeout=60s""", """monitor d2:Started 60s:30s""", """group g1 d1 d2""", """primitive d3 ocf:pacemaker:Dummy""", """clone c d3 \ meta clone-max=1""", """primitive d4 ocf:pacemaker:Dummy""", """ms m d4""", """primitive s5 ocf:pacemaker:Stateful \ operations $id-ref=d1-ops""", """primitive s6 ocf:pacemaker:Stateful \ operations $id-ref=d1""", """ms m5 s5""", """ms m6 s6""", """location l1 g1 100: node1""", """location l2 c \ rule $id=l2-rule1 100: #uname eq node1""", """location l3 m5 \ rule inf: #uname eq node1 and pingd gt 0""", """location l4 m5 \ rule -inf: not_defined pingd or pingd lte 0""", """location l5 m5 \ rule -inf: not_defined pingd or pingd lte 0 \ rule inf: #uname eq node1 and pingd gt 0 \ rule inf: date lt "2009-05-26" and \ date in start="2009-05-26" end="2009-07-26" and \ date in start="2009-05-26" years="2009" and \ date date_spec years="2009" hours=09-17""", """location l6 m5 \ rule $id-ref=l2-rule1""", """location l7 m5 \ rule $id-ref=l2""", """collocation c1 inf: m6 m5""", """collocation c2 inf: m5:Master d1:Started""", """order o1 Mandatory: m5 m6""", """order o2 Optional: d1:start m5:promote""", """order o3 Serialize: m5 m6""", """order o4 inf: m5 m6""", """rsc_ticket ticket-A_m6 ticket-A: m6""", """rsc_ticket ticket-B_m6_m5 ticket-B: m6 m5 loss-policy=fence""", """rsc_ticket ticket-C_master ticket-C: m6 m5:Master loss-policy=fence""", """fencing_topology st st2""", """property stonith-enabled=true""", """property $id=cpset2 maintenance-mode=true""", """rsc_defaults failure-timeout=10m""", """op_defaults $id=opsdef2 record-pending=true"""] outp = self._parse_lines('\n'.join(inp)) a = [xml_tostring(x) for x in outp] b = [ '<node uname="node1"><instance_attributes><nvpair name="mem" value="16G"/></instance_attributes></node>', '<node uname="node2"><utilization><nvpair name="cpu" value="4"/></utilization></node>', '<primitive id="st" class="stonith" type="ssh"><instance_attributes><nvpair name="hostlist" value="node1 node2"/></instance_attributes><meta_attributes><nvpair name="target-role" value="Started"/><nvpair name="requires" value="nothing"/></meta_attributes><operations><op name="start" timeout="60s" interval="0"/><op name="monitor" interval="60m" timeout="60s"/></operations></primitive>', '<primitive id="st2" class="stonith" type="ssh"><instance_attributes><nvpair name="hostlist" value="node1 node2"/></instance_attributes></primitive>', '<primitive id="d1" class="ocf" provider="pacemaker" type="Dummy"><operations id="d1-ops"><op name="monitor" interval="60m"/><op name="monitor" interval="120m"><instance_attributes><nvpair name="OCF_CHECK_LEVEL" value="10"/></instance_attributes></op></operations></primitive>', '<op name="monitor" rsc="d1" interval="60s" timeout="30s"/>', '<primitive id="d2" class="ocf" provider="heartbeat" type="Delay"><instance_attributes><nvpair name="mondelay" value="60"/></instance_attributes><operations><op name="start" timeout="60s" interval="0"/><op name="stop" timeout="60s" interval="0"/></operations></primitive>', '<op name="monitor" role="Started" rsc="d2" interval="60s" timeout="30s"/>', '<group id="g1"><crmsh-ref id="d1"/><crmsh-ref id="d2"/></group>', '<primitive id="d3" class="ocf" provider="pacemaker" type="Dummy"/>', '<clone id="c"><meta_attributes><nvpair name="clone-max" value="1"/></meta_attributes><crmsh-ref id="d3"/></clone>', '<primitive id="d4" class="ocf" provider="pacemaker" type="Dummy"/>', '<master id="m"><crmsh-ref id="d4"/></master>', '<primitive id="s5" class="ocf" provider="pacemaker" type="Stateful"><operations id-ref="d1-ops"/></primitive>', '<primitive id="s6" class="ocf" provider="pacemaker" type="Stateful"><operations id-ref="d1"/></primitive>', '<master id="m5"><crmsh-ref id="s5"/></master>', '<master id="m6"><crmsh-ref id="s6"/></master>', '<rsc_location id="l1" rsc="g1" score="100" node="node1"/>', '<rsc_location id="l2" rsc="c"><rule id="l2-rule1" score="100"><expression attribute="#uname" operation="eq" value="node1"/></rule></rsc_location>', '<rsc_location id="l3" rsc="m5"><rule score="INFINITY"><expression attribute="#uname" operation="eq" value="node1"/><expression attribute="pingd" operation="gt" value="0"/></rule></rsc_location>', '<rsc_location id="l4" rsc="m5"><rule score="-INFINITY" boolean-op="or"><expression attribute="pingd" operation="not_defined"/><expression attribute="pingd" operation="lte" value="0"/></rule></rsc_location>', '<rsc_location id="l5" rsc="m5"><rule score="-INFINITY" boolean-op="or"><expression attribute="pingd" operation="not_defined"/><expression attribute="pingd" operation="lte" value="0"/></rule><rule score="INFINITY"><expression attribute="#uname" operation="eq" value="node1"/><expression attribute="pingd" operation="gt" value="0"/></rule><rule score="INFINITY"><date_expression operation="lt" end="2009-05-26"/><date_expression operation="in_range" start="2009-05-26" end="2009-07-26"/><date_expression operation="in_range" start="2009-05-26"><duration years="2009"/></date_expression><date_expression operation="date_spec"><date_spec years="2009" hours="09-17"/></date_expression></rule></rsc_location>', '<rsc_location id="l6" rsc="m5"><rule id-ref="l2-rule1"/></rsc_location>', '<rsc_location id="l7" rsc="m5"><rule id-ref="l2"/></rsc_location>', '<rsc_colocation id="c1" score="INFINITY" rsc="m6" with-rsc="m5"/>', '<rsc_colocation id="c2" score="INFINITY" rsc="m5" rsc-role="Master" with-rsc="d1" with-rsc-role="Started"/>', '<rsc_order id="o1" kind="Mandatory" first="m5" then="m6"/>', '<rsc_order id="o2" kind="Optional" first="d1" first-action="start" then="m5" then-action="promote"/>', '<rsc_order id="o3" kind="Serialize" first="m5" then="m6"/>', '<rsc_order id="o4" score="INFINITY" first="m5" then="m6"/>', '<rsc_ticket id="ticket-A_m6" ticket="ticket-A" rsc="m6"/>', '<rsc_ticket id="ticket-B_m6_m5" ticket="ticket-B" loss-policy="fence"><resource_set><resource_ref id="m6"/><resource_ref id="m5"/></resource_set></rsc_ticket>', '<rsc_ticket id="ticket-C_master" ticket="ticket-C" loss-policy="fence"><resource_set><resource_ref id="m6"/></resource_set><resource_set role="Master"><resource_ref id="m5"/></resource_set></rsc_ticket>', '<fencing-topology><fencing-level devices="st" index="1" target="ha-one"/><fencing-level devices="st2" index="2" target="ha-one"/><fencing-level devices="st" index="1" target="ha-three"/><fencing-level devices="st2" index="2" target="ha-three"/><fencing-level devices="st" index="1" target="ha-two"/><fencing-level devices="st2" index="2" target="ha-two"/></fencing-topology>', '<cluster_property_set><nvpair name="stonith-enabled" value="true"/></cluster_property_set>', '<cluster_property_set id="cpset2"><nvpair name="maintenance-mode" value="true"/></cluster_property_set>', '<rsc_defaults><meta_attributes><nvpair name="failure-timeout" value="10m"/></meta_attributes></rsc_defaults>', '<op_defaults><meta_attributes id="opsdef2"><nvpair name="record-pending" value="true"/></meta_attributes></op_defaults>', ] for result, expected in zip(a, b): self.assertEqual(expected, result)
def test_order(self): out = self._parse('order o1 Mandatory: [ A B sequential=true ] C') print(xml_tostring(out)) self.assertEqual(['Mandatory'], out.xpath('/rsc_order/@kind')) self.assertEqual(2, len(out.xpath('/rsc_order/resource_set'))) self.assertEqual(['false'], out.xpath('/rsc_order/resource_set/@require-all')) self.assertEqual(['A', 'B', 'C'], out.xpath('//resource_ref/@id')) out = self._parse('order o1 Mandatory: [ A B sequential=false ] C') self.assertEqual(2, len(out.xpath('/rsc_order/resource_set'))) #self.assertTrue(['require-all', 'false'] in out.resources[0][1]) #self.assertTrue(['sequential', 'false'] in out.resources[0][1]) self.assertEqual(out.get('id'), 'o1') out = self._parse('order o1 Mandatory: A B C sequential=false') self.assertEqual(1, len(out.xpath('/rsc_order/resource_set'))) #self.assertTrue(['sequential', 'false'] in out.resources[0][1]) self.assertEqual(out.get('id'), 'o1') out = self._parse('order o1 Mandatory: A B C sequential=true') self.assertEqual(1, len(out.xpath('/rsc_order/resource_set'))) #self.assertTrue(['sequential', 'true'] not in out.resources[0][1]) self.assertEqual(out.get('id'), 'o1') out = self._parse('order c_apache_1 Mandatory: apache:start ip_1') self.assertEqual(out.get('id'), 'c_apache_1') out = self._parse('order c_apache_2 Mandatory: apache:start ip_1 ip_2 ip_3') self.assertEqual(2, len(out.xpath('/rsc_order/resource_set'))) self.assertEqual(out.get('id'), 'c_apache_2') out = self._parse('order o1 Serialize: A ( B C )') self.assertEqual(2, len(out.xpath('/rsc_order/resource_set'))) self.assertEqual(out.get('id'), 'o1') out = self._parse('order o1 Serialize: A ( B C ) symmetrical=false') self.assertEqual(2, len(out.xpath('/rsc_order/resource_set'))) self.assertEqual(out.get('id'), 'o1') self.assertEqual(['false'], out.xpath('//@symmetrical')) out = self._parse('order o1 Serialize: A ( B C ) symmetrical=true') self.assertEqual(2, len(out.xpath('/rsc_order/resource_set'))) self.assertEqual(out.get('id'), 'o1') self.assertEqual(['true'], out.xpath('//@symmetrical')) inp = 'colocation rsc_colocation-master INFINITY: [ vip-master vip-rep sequential=true ] [ msPostgresql:Master sequential=true ]' out = self._parse(inp) self.assertEqual(2, len(out.xpath('/rsc_colocation/resource_set'))) self.assertEqual(out.get('id'), 'rsc_colocation-master') out = self._parse('order order_2 Mandatory: [ A B ] C') self.assertEqual(2, len(out.xpath('/rsc_order/resource_set'))) self.assertEqual(out.get('id'), 'order_2') self.assertEqual(['Mandatory'], out.xpath('/rsc_order/@kind')) self.assertEqual(['false'], out.xpath('//resource_set/@sequential')) out = self._parse('order order-1 Optional: group1:stop group2:start') self.assertEqual(out.get('id'), 'order-1') self.assertEqual(['Optional'], out.xpath('/rsc_order/@kind')) self.assertEqual(['group1'], out.xpath('/rsc_order/@first')) self.assertEqual(['stop'], out.xpath('/rsc_order/@first-action')) self.assertEqual(['group2'], out.xpath('/rsc_order/@then')) self.assertEqual(['start'], out.xpath('/rsc_order/@then-action'))