diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 06:48:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 06:48:59 +0000 |
commit | d835b2cae8abc71958b69362162e6a70c3d7ef63 (patch) | |
tree | 81052e3d2ce3e1bcda085f73d925e9d6257dec15 /test/unittests/test_bugs.py | |
parent | Initial commit. (diff) | |
download | crmsh-upstream.tar.xz crmsh-upstream.zip |
Adding upstream version 4.6.0.upstream/4.6.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'test/unittests/test_bugs.py')
-rw-r--r-- | test/unittests/test_bugs.py | 893 |
1 files changed, 893 insertions, 0 deletions
diff --git a/test/unittests/test_bugs.py b/test/unittests/test_bugs.py new file mode 100644 index 0000000..725b020 --- /dev/null +++ b/test/unittests/test_bugs.py @@ -0,0 +1,893 @@ +from __future__ import print_function +from __future__ import unicode_literals +# Copyright (C) 2014 Kristoffer Gronlund <kgronlund@suse.com> +# See COPYING for license information. +try: + from unittest import mock +except ImportError: + import mock + +from crmsh import cibconfig +from lxml import etree +from crmsh import xmlutil + +factory = cibconfig.cib_factory + + +def setup_function(): + "set up test fixtures" + from crmsh import idmgmt + idmgmt.clear() + factory._push_state() + + +def teardown_function(): + factory._pop_state() + + +def test_bug41660_1(): + xml = """<primitive id="bug41660" class="ocf" provider="pacemaker" type="Dummy"> \ + <meta_attributes id="bug41660-meta"> \ + <nvpair id="bug41660-meta-target-role" name="target-role" value="Stopped"/> \ + </meta_attributes> \ + </primitive> +""" + data = etree.fromstring(xml) + obj = factory.create_from_node(data) + print(etree.tostring(obj.node)) + data = obj.repr_cli(format_mode=-1) + print(data) + exp = 'primitive bug41660 ocf:pacemaker:Dummy meta target-role=Stopped' + assert data == exp + assert obj.cli_use_validate() + + commit_holder = factory.commit + try: + factory.commit = lambda *args: True + from crmsh.ui_resource import set_deep_meta_attr + set_deep_meta_attr("bug41660", "target-role", "Started") + assert ['Started'] == obj.node.xpath('.//nvpair[@name="target-role"]/@value') + finally: + factory.commit = commit_holder + + +def test_bug41660_2(): + xml = """ +<clone id="libvirtd-clone"> + <primitive class="lsb" id="libvirtd" type="libvirtd"> + <operations> + <op id="libvirtd-monitor-interval-15" interval="15" name="monitor" start-delay="15" timeout="15"/> + <op id="libvirtd-start-interval-0" interval="0" name="start" on-fail="restart" timeout="15"/> + <op id="libvirtd-stop-interval-0" interval="0" name="stop" on-fail="ignore" timeout="15"/> + </operations> + <meta_attributes id="libvirtd-meta_attributes"/> + </primitive> + <meta_attributes id="libvirtd-clone-meta"> + <nvpair id="libvirtd-interleave" name="interleave" value="true"/> + <nvpair id="libvirtd-ordered" name="ordered" value="true"/> + <nvpair id="libvirtd-clone-meta-target-role" name="target-role" value="Stopped"/> + </meta_attributes> +</clone> +""" + data = etree.fromstring(xml) + obj = factory.create_from_node(data) + assert obj is not None + #data = obj.repr_cli(format_mode=-1) + #print data + #exp = 'clone libvirtd-clone libvirtd meta interleave=true ordered=true target-role=Stopped' + #assert data == exp + #assert obj.cli_use_validate() + + print(etree.tostring(obj.node)) + + commit_holder = factory.commit + try: + factory.commit = lambda *args: True + from crmsh.ui_resource import set_deep_meta_attr + print("PRE", etree.tostring(obj.node)) + set_deep_meta_attr("libvirtd-clone", "target-role", "Started") + print("POST", etree.tostring(obj.node)) + assert ['Started'] == obj.node.xpath('.//nvpair[@name="target-role"]/@value') + finally: + factory.commit = commit_holder + + +def test_bug41660_3(): + xml = """ +<clone id="libvirtd-clone"> + <primitive class="lsb" id="libvirtd" type="libvirtd"> + <operations> + <op id="libvirtd-monitor-interval-15" interval="15" name="monitor" start-delay="15" timeout="15"/> + <op id="libvirtd-start-interval-0" interval="0" name="start" on-fail="restart" timeout="15"/> + <op id="libvirtd-stop-interval-0" interval="0" name="stop" on-fail="ignore" timeout="15"/> + </operations> + <meta_attributes id="libvirtd-meta_attributes"/> + </primitive> + <meta_attributes id="libvirtd-clone-meta_attributes"> + <nvpair id="libvirtd-clone-meta_attributes-target-role" name="target-role" value="Stopped"/> + </meta_attributes> +</clone> +""" + data = etree.fromstring(xml) + obj = factory.create_from_node(data) + assert obj is not None + data = obj.repr_cli(format_mode=-1) + print(data) + exp = 'clone libvirtd-clone libvirtd meta target-role=Stopped' + assert data == exp + assert obj.cli_use_validate() + + commit_holder = factory.commit + try: + factory.commit = lambda *args: True + from crmsh.ui_resource import set_deep_meta_attr + set_deep_meta_attr("libvirtd-clone", "target-role", "Started") + assert ['Started'] == obj.node.xpath('.//nvpair[@name="target-role"]/@value') + finally: + factory.commit = commit_holder + + +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="root" 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_eq1(): + xml1 = """<cluster_property_set id="cib-bootstrap-options"> + <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"></nvpair> + <nvpair id="cib-bootstrap-options-stonith-timeout" name="stonith-timeout" value="180"></nvpair> + <nvpair id="cib-bootstrap-options-symmetric-cluster" name="symmetric-cluster" value="false"></nvpair> + <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="freeze"></nvpair> + <nvpair id="cib-bootstrap-options-batch-limit" name="batch-limit" value="20"></nvpair> + <nvpair id="cib-bootstrap-options-dc-version" name="dc-version" value="1.1.10-c1a326d"></nvpair> + <nvpair id="cib-bootstrap-options-cluster-infrastructure" name="cluster-infrastructure" value="corosync"></nvpair> + <nvpair id="cib-bootstrap-options-last-lrm-refresh" name="last-lrm-refresh" value="1391433789"></nvpair> + <nvpair id="cib-bootstrap-options-is-managed-default" name="is-managed-default" value="true"></nvpair> + </cluster_property_set> + """ + xml2 = """<cluster_property_set id="cib-bootstrap-options"> + <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"></nvpair> + <nvpair id="cib-bootstrap-options-stonith-timeout" name="stonith-timeout" value="180"></nvpair> + <nvpair id="cib-bootstrap-options-symmetric-cluster" name="symmetric-cluster" value="false"></nvpair> + <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="freeze"></nvpair> + <nvpair id="cib-bootstrap-options-batch-limit" name="batch-limit" value="20"></nvpair> + <nvpair id="cib-bootstrap-options-dc-version" name="dc-version" value="1.1.10-c1a326d"></nvpair> + <nvpair id="cib-bootstrap-options-cluster-infrastructure" name="cluster-infrastructure" value="corosync"></nvpair> + <nvpair id="cib-bootstrap-options-last-lrm-refresh" name="last-lrm-refresh" value="1391433789"></nvpair> + <nvpair id="cib-bootstrap-options-is-managed-default" name="is-managed-default" value="true"></nvpair> + </cluster_property_set> + """ + e1 = etree.fromstring(xml1) + e2 = etree.fromstring(xml2) + assert xmlutil.xml_equals(e1, e2, show=True) + + +def test_pcs_interop_1(): + """ + pcs<>crmsh interop bug + """ + + xml = """<clone id="dummies"> + <meta_attributes id="dummies-meta"> + <nvpair name="globally-unique" value="false" id="dummies-meta-globally-unique"/> + </meta_attributes> + <meta_attributes id="dummies-meta_attributes"> + <nvpair id="dummies-meta_attributes-target-role" name="target-role" value="Stopped"/> + </meta_attributes> + <primitive id="dummy-1" class="ocf" provider="heartbeat" type="Dummy"/> + </clone>""" + elem = etree.fromstring(xml) + from crmsh.ui_resource import set_deep_meta_attr_node + + assert len(elem.xpath(".//meta_attributes/nvpair[@name='target-role']")) == 1 + + print("BEFORE:", etree.tostring(elem)) + + set_deep_meta_attr_node(elem, 'target-role', 'Stopped') + + print("AFTER:", etree.tostring(elem)) + + assert len(elem.xpath(".//meta_attributes/nvpair[@name='target-role']")) == 1 + + +def test_bnc878128(): + """ + L3: "crm configure show" displays XML information instead of typical crm output. + """ + xml = """<rsc_location id="cli-prefer-dummy-resource" rsc="dummy-resource" +role="Started"> + <rule id="cli-prefer-rule-dummy-resource" score="INFINITY"> + <expression id="cli-prefer-expr-dummy-resource" attribute="#uname" +operation="eq" value="x64-4"/> + <date_expression id="cli-prefer-lifetime-end-dummy-resource" operation="lt" +end="2014-05-17 17:56:11Z"/> + </rule> +</rsc_location>""" + data = etree.fromstring(xml) + obj = factory.create_from_node(data) + assert obj is not None + data = obj.repr_cli(format_mode=-1) + print("OUTPUT:", data) + exp = 'location cli-prefer-dummy-resource dummy-resource role=Started rule #uname eq x64-4 and date lt "2014-05-17 17:56:11Z"' + assert data == exp + assert obj.cli_use_validate() + + +def test_order_without_score_kind(): + """ + Spec says order doesn't require score or kind to be set + """ + xml = '<rsc_order first="a" first-action="promote" id="order-a-b" then="b" then-action="start"/>' + data = etree.fromstring(xml) + obj = factory.create_from_node(data) + assert obj is not None + data = obj.repr_cli(format_mode=-1) + print("OUTPUT:", data) + exp = 'order order-a-b a:promote b:start' + assert data == exp + assert obj.cli_use_validate() + + + +def test_bnc878112(): + """ + crm configure group can hijack a cloned primitive (and then crash) + """ + obj1 = factory.create_object('primitive', 'p1', 'Dummy') + assert obj1 is True + obj2 = factory.create_object('group', 'g1', 'p1') + assert obj2 is True + obj3 = factory.create_object('group', 'g2', 'p1') + print(obj3) + assert obj3 is False + + +def test_copy_nvpairs(): + from crmsh.cibconfig import copy_nvpairs + + to = etree.fromstring(''' + <node> + <nvpair name="stonith-enabled" value="true"/> + </node> + ''') + copy_nvpairs(to, etree.fromstring(''' + <node> + <nvpair name="stonith-enabled" value="false"/> + </node> + ''')) + + assert ['stonith-enabled'] == to.xpath('./nvpair/@name') + assert ['false'] == to.xpath('./nvpair/@value') + + copy_nvpairs(to, etree.fromstring(''' + <node> + <nvpair name="stonith-enabled" value="true"/> + </node> + ''')) + + assert ['stonith-enabled'] == to.xpath('./nvpair/@name') + assert ['true'] == to.xpath('./nvpair/@value') + + +def test_pengine_test(): + xml = '''<primitive class="ocf" id="rsc1" provider="pacemaker" type="Dummy"> + <instance_attributes id="rsc1-instance_attributes-1"> + <nvpair id="rsc1-instance_attributes-1-state" name="state" value="/var/run/Dummy-rsc1-clusterA"/> + <rule id="rsc1-instance_attributes-1-rule-1" score="0"> + <expression id="rsc1-instance_attributes-1-rule-1-expr-1" attribute="#cluster-name" operation="eq" value="clusterA"/> + </rule> + </instance_attributes> + <instance_attributes id="rsc1-instance_attributes-2"> + <nvpair id="rsc1-instance_attributes-2-state" name="state" value="/var/run/Dummy-rsc1-clusterB"/> + <rule id="rsc1-instance_attributes-2-rule-1" score="0"> + <expression id="rsc1-instance_attributes-2-rule-1-expr-1" attribute="#cluster-name" operation="eq" value="clusterB"/> + </rule> + </instance_attributes> + <operations> + <op id="rsc1-monitor-10" interval="10" name="monitor"/> + </operations> + </primitive>''' + data = etree.fromstring(xml) + obj = factory.create_from_node(data) + assert obj is not None + data = obj.repr_cli(format_mode=-1) + print("OUTPUT:", data) + exp = 'primitive rsc1 ocf:pacemaker:Dummy params rule 0: #cluster-name eq clusterA state="/var/run/Dummy-rsc1-clusterA" params rule 0: #cluster-name eq clusterB state="/var/run/Dummy-rsc1-clusterB" op monitor interval=10' + assert data == exp + assert obj.cli_use_validate() + + +def test_tagset(): + xml = '''<primitive class="ocf" id="%s" provider="pacemaker" type="Dummy"/>''' + tag = '''<tag id="t0"><obj_ref id="r1"/><obj_ref id="r2"/></tag>''' + factory.create_from_node(etree.fromstring(xml % ('r1'))) + factory.create_from_node(etree.fromstring(xml % ('r2'))) + factory.create_from_node(etree.fromstring(xml % ('r3'))) + factory.create_from_node(etree.fromstring(tag)) + elems = factory.get_elems_on_tag("tag:t0") + assert set(x.obj_id for x in elems) == set(['r1', 'r2']) + + +def test_op_role(): + xml = '''<primitive class="ocf" id="rsc2" provider="pacemaker" type="Dummy"> + <operations> + <op id="rsc2-monitor-10" interval="10" name="monitor" role="Stopped"/> + </operations> + </primitive>''' + data = etree.fromstring(xml) + obj = factory.create_from_node(data) + assert obj is not None + data = obj.repr_cli(format_mode=-1) + print("OUTPUT:", data) + exp = 'primitive rsc2 ocf:pacemaker:Dummy op monitor interval=10 role=Stopped' + assert data == exp + assert obj.cli_use_validate() + + +def test_nvpair_no_value(): + xml = '''<primitive class="ocf" id="rsc3" provider="heartbeat" type="Dummy"> + <instance_attributes id="rsc3-instance_attributes-1"> + <nvpair id="rsc3-instance_attributes-1-verbose" name="verbose"/> + <nvpair id="rsc3-instance_attributes-1-verbase" name="verbase" value=""/> + <nvpair id="rsc3-instance_attributes-1-verbese" name="verbese" value=" "/> + </instance_attributes> + </primitive>''' + data = etree.fromstring(xml) + obj = factory.create_from_node(data) + assert obj is not None + data = obj.repr_cli(format_mode=-1) + print("OUTPUT:", data) + exp = 'primitive rsc3 Dummy params verbose verbase="" verbese=" "' + assert data == exp + assert obj.cli_use_validate() + + +def test_delete_ticket(): + xml0 = '<primitive id="daa0" class="ocf" provider="heartbeat" type="Dummy"/>' + xml1 = '<primitive id="daa1" class="ocf" provider="heartbeat" type="Dummy"/>' + xml2 = '''<rsc_ticket id="taa0" ticket="taaA"> + <resource_set id="taa0-0"> + <resource_ref id="daa0"/> + <resource_ref id="daa1"/> + </resource_set> + </rsc_ticket>''' + for x in (xml0, xml1, xml2): + data = etree.fromstring(x) + obj = factory.create_from_node(data) + assert obj is not None + data = obj.repr_cli(format_mode=-1) + + factory.delete('daa0') + assert factory.find_object('daa0') is None + assert factory.find_object('taa0') is not None + + +def test_quotes(): + """ + Parsing escaped quotes + """ + xml = '''<primitive class="ocf" id="q1" provider="pacemaker" type="Dummy"> + <instance_attributes id="q1-instance_attributes-1"> + <nvpair id="q1-instance_attributes-1-state" name="state" value="foo"foo""/> + </instance_attributes> + </primitive> + ''' + data = etree.fromstring(xml) + obj = factory.create_from_node(data) + assert obj is not None + data = obj.repr_cli(format_mode=-1) + print("OUTPUT:", data) + exp = 'primitive q1 ocf:pacemaker:Dummy params state="foo\\"foo\\""' + assert data == exp + assert obj.cli_use_validate() + + +def test_nodeattrs(): + """ + bug with parsing node attrs + """ + xml = '''<node id="1" uname="dell71"> \ + <instance_attributes id="dell71-instance_attributes"> \ + <nvpair name="staging-0-0-placement" value="true" id="dell71-instance_attributes-staging-0-0-placement"/> \ + <nvpair name="meta-0-0-placement" value="true" id="dell71-instance_attributes-meta-0-0-placement"/> \ + </instance_attributes> \ + <instance_attributes id="nodes-1"> \ + <nvpair id="nodes-1-standby" name="standby" value="off"/> \ + </instance_attributes> \ +</node>''' + + data = etree.fromstring(xml) + obj = factory.create_from_node(data) + assert obj is not None + data = obj.repr_cli(format_mode=-1) + exp = 'node 1: dell71 attributes staging-0-0-placement=true meta-0-0-placement=true attributes standby=off' + assert data == exp + assert obj.cli_use_validate() + + +def test_nodeattrs2(): + xml = """<node id="h04" uname="h04"> \ + <utilization id="h04-utilization"> \ + <nvpair id="h04-utilization-utl_ram" name="utl_ram" value="1200"/> \ + <nvpair id="h04-utilization-utl_cpu" name="utl_cpu" value="200"/> \ + </utilization> \ + <instance_attributes id="nodes-h04"> \ + <nvpair id="nodes-h04-standby" name="standby" value="off"/> \ + </instance_attributes> \ +</node>""" + data = etree.fromstring(xml) + obj = factory.create_from_node(data) + assert obj is not None + data = obj.repr_cli(format_mode=-1) + exp = 'node h04 utilization utl_ram=1200 utl_cpu=200 attributes standby=off' + assert data == exp + assert obj.cli_use_validate() + + +def test_group_constraint_location(): + """ + configuring a location constraint on a grouped resource is OK + """ + factory.create_object('node', 'node1') + factory.create_object('primitive', 'p1', 'Dummy') + factory.create_object('primitive', 'p2', 'Dummy') + factory.create_object('group', 'g1', 'p1', 'p2') + factory.create_object('location', 'loc-p1', 'p1', 'inf:', 'node1') + c = factory.find_object('loc-p1') + assert c and c.check_sanity() == 0 + + +def test_group_constraint_colocation(): + """ + configuring a colocation constraint on a grouped resource is bad + """ + factory.create_object('primitive', 'p1', 'Dummy') + factory.create_object('primitive', 'p2', 'Dummy') + factory.create_object('group', 'g1', 'p1', 'p2') + factory.create_object('colocation', 'coloc-p1-p2', 'inf:', 'p1', 'p2') + c = factory.find_object('coloc-p1-p2') + assert c and c.check_sanity() > 0 + + +def test_group_constraint_colocation_rscset(): + """ + configuring a constraint on a grouped resource is bad + """ + factory.create_object('primitive', 'p1', 'Dummy') + factory.create_object('primitive', 'p2', 'Dummy') + factory.create_object('primitive', 'p3', 'Dummy') + factory.create_object('group', 'g1', 'p1', 'p2') + factory.create_object('colocation', 'coloc-p1-p2-p3', 'inf:', 'p1', 'p2', 'p3') + c = factory.find_object('coloc-p1-p2-p3') + assert c and c.check_sanity() > 0 + + +def test_clone_constraint_colocation_rscset(): + """ + configuring a constraint on a cloned resource is bad + """ + factory.create_object('primitive', 'p1', 'Dummy') + factory.create_object('primitive', 'p2', 'Dummy') + factory.create_object('primitive', 'p3', 'Dummy') + factory.create_object('clone', 'c1', 'p1') + factory.create_object('colocation', 'coloc-p1-p2-p3', 'inf:', 'p1', 'p2', 'p3') + c = factory.find_object('coloc-p1-p2-p3') + assert c and c.check_sanity() > 0 + + +def test_existing_node_resource(): + factory.create_object('primitive', 'ha-one', 'Dummy') + + n = factory.find_node('ha-one') + assert factory.test_element(n) + + r = factory.find_resource('ha-one') + assert factory.test_element(r) + + assert n != r + + assert factory.check_structure() + factory.cli_use_validate_all() + + ok, s = factory.mkobj_set('ha-one') + assert ok + + +@mock.patch("crmsh.log.LoggerUtils.line_number") +@mock.patch("crmsh.log.LoggerUtils.incr_lineno") +def test_existing_node_resource_2(mock_incr, mock_line_num): + obj = cibconfig.mkset_obj() + assert obj is not None + + from crmsh import clidisplay + with clidisplay.nopretty(): + text = obj.repr() + text += "\nprimitive ha-one Dummy" + ok = obj.save(text) + assert ok + + obj = cibconfig.mkset_obj() + assert obj is not None + with clidisplay.nopretty(): + text2 = obj.repr() + + assert sorted(text.split('\n')) == sorted(text2.split('\n')) + + +@mock.patch("crmsh.log.LoggerUtils.line_number") +@mock.patch("crmsh.log.LoggerUtils.incr_lineno") +def test_id_collision_breakage_1(mock_incr, mock_line_num): + from crmsh import clidisplay + + obj = cibconfig.mkset_obj() + assert obj is not None + with clidisplay.nopretty(): + original_cib = obj.repr() + print(original_cib) + + obj = cibconfig.mkset_obj() + assert obj is not None + + ok = obj.save("""node node1 +primitive p0 ocf:pacemaker:Dummy +primitive p1 ocf:pacemaker:Dummy +primitive p2 ocf:heartbeat:Delay \ + params startdelay=2 mondelay=2 stopdelay=2 +primitive p3 ocf:pacemaker:Dummy +primitive st stonith:null params hostlist=node1 +clone c1 p1 +ms m1 p2 +op_defaults timeout=60s +""") + assert ok + + obj = cibconfig.mkset_obj() + assert obj is not None + ok = obj.save("""op_defaults timeout=2m +node node1 \ + attributes mem=16G +primitive st stonith:null \ + params hostlist='node1' \ + meta description="some description here" requires=nothing \ + op monitor interval=60m +primitive p1 ocf:heartbeat:Dummy \ + op monitor interval=60m \ + op monitor interval=120m OCF_CHECK_LEVEL=10 +""") + assert ok + + obj = cibconfig.mkset_obj() + with clidisplay.nopretty(): + text = obj.repr() + text = text + "\nprimitive p2 ocf:heartbeat:Dummy" + ok = obj.save(text) + assert ok + + obj = cibconfig.mkset_obj() + with clidisplay.nopretty(): + text = obj.repr() + text = text + "\ngroup g1 p1 p2" + ok = obj.save(text) + assert ok + + obj = cibconfig.mkset_obj("g1") + with clidisplay.nopretty(): + text = obj.repr() + text = text.replace("group g1 p1 p2", "group g1 p1 p3") + text = text + "\nprimitive p3 ocf:heartbeat:Dummy" + ok = obj.save(text) + assert ok + + obj = cibconfig.mkset_obj("g1") + with clidisplay.nopretty(): + print(obj.repr().strip()) + assert obj.repr().strip() == "group g1 p1 p3" + + obj = cibconfig.mkset_obj() + assert obj is not None + ok = obj.save(original_cib) + assert ok + obj = cibconfig.mkset_obj() + with clidisplay.nopretty(): + print("*** ORIGINAL") + print(original_cib) + print("*** NOW") + print(obj.repr()) + assert original_cib == obj.repr() + + +@mock.patch("crmsh.log.LoggerUtils.line_number") +@mock.patch("crmsh.log.LoggerUtils.incr_lineno") +def test_id_collision_breakage_3(mock_incr, mock_line_num): + from crmsh import clidisplay + + obj = cibconfig.mkset_obj() + assert obj is not None + with clidisplay.nopretty(): + original_cib = obj.repr() + print(original_cib) + + obj = cibconfig.mkset_obj() + assert obj is not None + ok = obj.save("""node node1 +primitive node1 Dummy params fake=something + """) + assert ok + + print("** baseline") + obj = cibconfig.mkset_obj() + assert obj is not None + with clidisplay.nopretty(): + print(obj.repr()) + + obj = cibconfig.mkset_obj() + assert obj is not None + ok = obj.save("""primitive node1 Dummy params fake=something-else + """, remove=False, method='update') + assert ok + + print("** end") + + obj = cibconfig.mkset_obj() + assert obj is not None + ok = obj.save(original_cib, remove=True, method='replace') + assert ok + obj = cibconfig.mkset_obj() + with clidisplay.nopretty(): + print("*** ORIGINAL") + print(original_cib) + print("*** NOW") + print(obj.repr()) + assert original_cib == obj.repr() + + +@mock.patch("crmsh.log.LoggerUtils.line_number") +@mock.patch("crmsh.log.LoggerUtils.incr_lineno") +def test_id_collision_breakage_2(mock_incr, mock_line_num): + from crmsh import clidisplay + + obj = cibconfig.mkset_obj() + assert obj is not None + with clidisplay.nopretty(): + original_cib = obj.repr() + print(original_cib) + + obj = cibconfig.mkset_obj() + assert obj is not None + + ok = obj.save("""node 168633610: webui +node 168633611: node1 +rsc_template web-server apache \ + params port=8000 \ + op monitor interval=10s +primitive d0 Dummy \ + meta target-role=Started +primitive d1 Dummy +primitive d2 Dummy +# Never use this STONITH agent in production! +primitive development-stonith stonith:null \ + params hostlist="webui node1 node2 node3" +primitive proxy systemd:haproxy \ + op monitor interval=10s +primitive proxy-vip IPaddr2 \ + params ip=10.13.37.20 +primitive srv1 @web-server +primitive srv2 @web-server +primitive vip1 IPaddr2 \ + params ip=10.13.37.21 \ + op monitor interval=20s +primitive vip2 IPaddr2 \ + params ip=10.13.37.22 \ + op monitor interval=20s +primitive virtual-ip IPaddr2 \ + params ip=10.13.37.77 lvs_support=false \ + op start timeout=20 interval=0 \ + op stop timeout=20 interval=0 \ + op monitor interval=10 timeout=20 +primitive yet-another-virtual-ip IPaddr2 \ + params ip=10.13.37.72 cidr_netmask=24 \ + op start interval=0 timeout=20 \ + op stop interval=0 timeout=20 \ + op monitor interval=10 timeout=20 \ + meta target-role=Started +group dovip d0 virtual-ip \ + meta target-role=Stopped +group g-proxy proxy-vip proxy +group g-serv1 vip1 srv1 +group g-serv2 vip2 srv2 +clone d2-clone d2 \ + meta target-role=Started +tag dummytag d0 d1 d1-on-node1 d2 d2-clone +# Never put the two web servers on the same node +colocation co-serv -inf: g-serv1 g-serv2 +location d1-on-node1 d1 inf: node1 +# Never put any web server or haproxy on webui +location l-avoid-webui { g-proxy g-serv1 g-serv2 } -inf: webui +# Prever to spread groups across nodes +location l-proxy g-proxy 200: node1 +location l-serv1 g-serv1 200: node2 +location l-serv2 g-serv2 200: node3 +property cib-bootstrap-options: \ + have-watchdog=false \ + dc-version="1.1.13+git20150917.20c2178-224.2-1.1.13+git20150917.20c2178" \ + cluster-infrastructure=corosync \ + cluster-name=hacluster \ + stonith-enabled=true \ + no-quorum-policy=ignore +rsc_defaults rsc-options: \ + resource-stickiness=1 \ + migration-threshold=3 +op_defaults op-options: \ + timeout=600 \ + record-pending=true +""") + assert ok + + obj = cibconfig.mkset_obj() + assert obj is not None + ok = obj.save(original_cib) + assert ok + obj = cibconfig.mkset_obj() + with clidisplay.nopretty(): + print("*** ORIGINAL") + print(original_cib) + print("*** NOW") + print(obj.repr()) + assert original_cib == obj.repr() + + +def test_bug_110(): + """ + configuring attribute-based fencing-topology + """ + factory.create_object(*"primitive stonith-libvirt stonith:null".split()) + factory.create_object(*"primitive fence-nova stonith:null".split()) + cmd = "fencing_topology attr:OpenStack-role=compute stonith-libvirt,fence-nova".split() + ok = factory.create_object(*cmd) + assert ok + obj = cibconfig.mkset_obj() + assert obj is not None + + for o in obj.obj_set: + if o.node.tag == 'fencing-topology': + assert o.check_sanity() == 0 + + +@mock.patch("crmsh.log.LoggerUtils.line_number") +@mock.patch("crmsh.log.LoggerUtils.incr_lineno") +def test_reordering_resource_sets(mock_incr, mock_line_num): + """ + Can we reorder resource sets? + """ + from crmsh import clidisplay + obj1 = factory.create_object('primitive', 'p1', 'Dummy') + assert obj1 is True + obj2 = factory.create_object('primitive', 'p2', 'Dummy') + assert obj2 is True + obj3 = factory.create_object('primitive', 'p3', 'Dummy') + assert obj3 is True + obj4 = factory.create_object('primitive', 'p4', 'Dummy') + assert obj4 is True + o1 = factory.create_object('order', 'o1', 'p1', 'p2', 'p3', 'p4') + assert o1 is True + + obj = cibconfig.mkset_obj('o1') + assert obj is not None + rc = obj.save('order o1 p4 p3 p2 p1') + assert rc == True + + obj2 = cibconfig.mkset_obj('o1') + with clidisplay.nopretty(): + assert "order o1 p4 p3 p2 p1" == obj2.repr().strip() + + +def test_bug959895(): + """ + Allow importing XML with cloned groups + """ + xml = """<clone id="c-bug959895"> + <group id="g-bug959895"> + <primitive id="p-bug959895-a" class="ocf" provider="pacemaker" type="Dummy" /> + <primitive id="p-bug959895-b" class="ocf" provider="pacemaker" type="Dummy" /> + </group> +</clone> +""" + data = etree.fromstring(xml) + obj = factory.create_from_node(data) + print(etree.tostring(obj.node)) + data = obj.repr_cli(format_mode=-1) + print(data) + exp = 'clone c-bug959895 g-bug959895' + assert data == exp + assert obj.cli_use_validate() + + commit_holder = factory.commit + try: + factory.commit = lambda *args: True + from crmsh.ui_resource import set_deep_meta_attr + set_deep_meta_attr("c-bug959895", "target-role", "Started") + assert ['Started'] == obj.node.xpath('.//nvpair[@name="target-role"]/@value') + finally: + factory.commit = commit_holder + + +def test_node_util_attr(): + """ + Handle node with utitilization before attributes correctly + """ + xml = """<node id="aberfeldy" uname="aberfeldy"> + <utilization id="nodes-aberfeldy-utilization"> + <nvpair id="nodes-aberfeldy-utilization-cpu" name="cpu" value="2"/> + <nvpair id="nodes-aberfeldy-utilization-memory" name="memory" value="500"/> + </utilization> + <instance_attributes id="nodes-aberfeldy"> + <nvpair id="nodes-aberfeldy-standby" name="standby" value="on"/> + </instance_attributes> +</node>""" + + data = etree.fromstring(xml) + obj = factory.create_from_node(data) + print(etree.tostring(obj.node)) + data = obj.repr_cli(format_mode=-1) + print(data) + exp = 'node aberfeldy utilization cpu=2 memory=500 attributes standby=on' + assert data == exp + assert obj.cli_use_validate() + + +def test_dup_create_same_name(): + """ + Creating two objects with the same name + """ + ok = factory.create_object(*"primitive dup1 Dummy".split()) + assert ok + ok = factory.create_object(*"primitive dup1 Dummy".split()) + assert not ok + + +def test_dup_create(): + """ + Creating property sets with unknown properties + """ + ok = factory.create_object(*"property hana_test1: hana_attribute_1=5 hana_attribute_2=mohican".split()) + assert ok + ok = factory.create_object(*"property hana_test2: hana_attribute_1=5s a-b-c-d=e-f-g".split()) + assert ok |