1from __future__ import print_function
2from __future__ import unicode_literals
3# Copyright (C) 2014 Kristoffer Gronlund <kgronlund@suse.com>
4# See COPYING for license information.
5
6
7from crmsh import cibconfig
8from lxml import etree
9from crmsh import xmlutil
10
11factory = cibconfig.cib_factory
12
13
14def setup_function():
15    "set up test fixtures"
16    from crmsh import idmgmt
17    idmgmt.clear()
18    factory._push_state()
19
20
21def teardown_function():
22    factory._pop_state()
23
24
25def test_bug41660_1():
26    xml = """<primitive id="bug41660" class="ocf" provider="pacemaker" type="Dummy"> \
27    <meta_attributes id="bug41660-meta"> \
28    <nvpair id="bug41660-meta-target-role" name="target-role" value="Stopped"/> \
29    </meta_attributes> \
30    </primitive>
31"""
32    data = etree.fromstring(xml)
33    obj = factory.create_from_node(data)
34    print(etree.tostring(obj.node))
35    data = obj.repr_cli(format_mode=-1)
36    print(data)
37    exp = 'primitive bug41660 ocf:pacemaker:Dummy meta target-role=Stopped'
38    assert data == exp
39    assert obj.cli_use_validate()
40
41    commit_holder = factory.commit
42    try:
43        factory.commit = lambda *args: True
44        from crmsh.ui_resource import set_deep_meta_attr
45        set_deep_meta_attr("bug41660", "target-role", "Started")
46        assert ['Started'] == obj.node.xpath('.//nvpair[@name="target-role"]/@value')
47    finally:
48        factory.commit = commit_holder
49
50
51def test_bug41660_2():
52    xml = """
53<clone id="libvirtd-clone">
54 <primitive class="lsb" id="libvirtd" type="libvirtd">
55  <operations>
56   <op id="libvirtd-monitor-interval-15" interval="15" name="monitor" start-delay="15" timeout="15"/>
57   <op id="libvirtd-start-interval-0" interval="0" name="start" on-fail="restart" timeout="15"/>
58   <op id="libvirtd-stop-interval-0" interval="0" name="stop" on-fail="ignore" timeout="15"/>
59  </operations>
60  <meta_attributes id="libvirtd-meta_attributes"/>
61 </primitive>
62 <meta_attributes id="libvirtd-clone-meta">
63  <nvpair id="libvirtd-interleave" name="interleave" value="true"/>
64  <nvpair id="libvirtd-ordered" name="ordered" value="true"/>
65  <nvpair id="libvirtd-clone-meta-target-role" name="target-role" value="Stopped"/>
66 </meta_attributes>
67</clone>
68"""
69    data = etree.fromstring(xml)
70    obj = factory.create_from_node(data)
71    assert obj is not None
72    #data = obj.repr_cli(format_mode=-1)
73    #print data
74    #exp = 'clone libvirtd-clone libvirtd meta interleave=true ordered=true target-role=Stopped'
75    #assert data == exp
76    #assert obj.cli_use_validate()
77
78    print(etree.tostring(obj.node))
79
80    commit_holder = factory.commit
81    try:
82        factory.commit = lambda *args: True
83        from crmsh.ui_resource import set_deep_meta_attr
84        print("PRE", etree.tostring(obj.node))
85        set_deep_meta_attr("libvirtd-clone", "target-role", "Started")
86        print("POST", etree.tostring(obj.node))
87        assert ['Started'] == obj.node.xpath('.//nvpair[@name="target-role"]/@value')
88    finally:
89        factory.commit = commit_holder
90
91
92def test_bug41660_3():
93    xml = """
94<clone id="libvirtd-clone">
95 <primitive class="lsb" id="libvirtd" type="libvirtd">
96  <operations>
97   <op id="libvirtd-monitor-interval-15" interval="15" name="monitor" start-delay="15" timeout="15"/>
98   <op id="libvirtd-start-interval-0" interval="0" name="start" on-fail="restart" timeout="15"/>
99   <op id="libvirtd-stop-interval-0" interval="0" name="stop" on-fail="ignore" timeout="15"/>
100  </operations>
101  <meta_attributes id="libvirtd-meta_attributes"/>
102 </primitive>
103 <meta_attributes id="libvirtd-clone-meta_attributes">
104 <nvpair id="libvirtd-clone-meta_attributes-target-role" name="target-role" value="Stopped"/>
105 </meta_attributes>
106</clone>
107"""
108    data = etree.fromstring(xml)
109    obj = factory.create_from_node(data)
110    assert obj is not None
111    data = obj.repr_cli(format_mode=-1)
112    print(data)
113    exp = 'clone libvirtd-clone libvirtd meta target-role=Stopped'
114    assert data == exp
115    assert obj.cli_use_validate()
116
117    commit_holder = factory.commit
118    try:
119        factory.commit = lambda *args: True
120        from crmsh.ui_resource import set_deep_meta_attr
121        set_deep_meta_attr("libvirtd-clone", "target-role", "Started")
122        assert ['Started'] == obj.node.xpath('.//nvpair[@name="target-role"]/@value')
123    finally:
124        factory.commit = commit_holder
125
126
127def test_comments():
128    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">
129  <configuration>
130    <crm_config>
131      <cluster_property_set id="cib-bootstrap-options">
132        <nvpair id="cib-bootstrap-options-dc-version" name="dc-version" value="1.1.11-3.3-3ca8c3b"/>
133        <nvpair id="cib-bootstrap-options-cluster-infrastructure" name="cluster-infrastructure" value="corosync"/>
134        <!--# COMMENT TEXT 1 -->
135      </cluster_property_set>
136    </crm_config>
137    <nodes>
138      <node uname="beta1" id="1">
139        <!--# COMMENT TEXT 2 -->
140      </node>
141    </nodes>
142    <resources/>
143    <constraints/>
144    <rsc_defaults>
145      <meta_attributes id="rsc-options">
146        <nvpair name="resource-stickiness" value="1" id="rsc-options-resource-stickiness"/>
147        <!--# COMMENT TEXT 3 -->
148      </meta_attributes>
149    </rsc_defaults>
150  </configuration>
151  <status>
152    <node_state id="1" uname="beta1" in_ccm="true" crmd="online" crm-debug-origin="do_state_transition" join="member" expected="member">
153      <lrm id="1">
154        <lrm_resources/>
155      </lrm>
156      <transient_attributes id="1">
157        <instance_attributes id="status-1">
158          <nvpair id="status-1-shutdown" name="shutdown" value="0"/>
159          <nvpair id="status-1-probe_complete" name="probe_complete" value="true"/>
160        </instance_attributes>
161      </transient_attributes>
162    </node_state>
163  </status>
164</cib>"""
165    elems = etree.fromstring(xml)
166    xmlutil.sanitize_cib(elems)
167    assert xmlutil.xml_tostring(elems).count("COMMENT TEXT") == 3
168
169
170def test_eq1():
171    xml1 = """<cluster_property_set id="cib-bootstrap-options">
172    <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"></nvpair>
173    <nvpair id="cib-bootstrap-options-stonith-timeout" name="stonith-timeout" value="180"></nvpair>
174    <nvpair id="cib-bootstrap-options-symmetric-cluster" name="symmetric-cluster" value="false"></nvpair>
175    <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="freeze"></nvpair>
176    <nvpair id="cib-bootstrap-options-batch-limit" name="batch-limit" value="20"></nvpair>
177    <nvpair id="cib-bootstrap-options-dc-version" name="dc-version" value="1.1.10-c1a326d"></nvpair>
178    <nvpair id="cib-bootstrap-options-cluster-infrastructure" name="cluster-infrastructure" value="corosync"></nvpair>
179    <nvpair id="cib-bootstrap-options-last-lrm-refresh" name="last-lrm-refresh" value="1391433789"></nvpair>
180    <nvpair id="cib-bootstrap-options-is-managed-default" name="is-managed-default" value="true"></nvpair>
181  </cluster_property_set>
182  """
183    xml2 = """<cluster_property_set id="cib-bootstrap-options">
184    <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"></nvpair>
185    <nvpair id="cib-bootstrap-options-stonith-timeout" name="stonith-timeout" value="180"></nvpair>
186    <nvpair id="cib-bootstrap-options-symmetric-cluster" name="symmetric-cluster" value="false"></nvpair>
187    <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="freeze"></nvpair>
188    <nvpair id="cib-bootstrap-options-batch-limit" name="batch-limit" value="20"></nvpair>
189    <nvpair id="cib-bootstrap-options-dc-version" name="dc-version" value="1.1.10-c1a326d"></nvpair>
190    <nvpair id="cib-bootstrap-options-cluster-infrastructure" name="cluster-infrastructure" value="corosync"></nvpair>
191    <nvpair id="cib-bootstrap-options-last-lrm-refresh" name="last-lrm-refresh" value="1391433789"></nvpair>
192    <nvpair id="cib-bootstrap-options-is-managed-default" name="is-managed-default" value="true"></nvpair>
193  </cluster_property_set>
194    """
195    e1 = etree.fromstring(xml1)
196    e2 = etree.fromstring(xml2)
197    assert xmlutil.xml_equals(e1, e2, show=True)
198
199
200def test_pcs_interop_1():
201    """
202    pcs<>crmsh interop bug
203    """
204
205    xml = """<clone id="dummies">
206        <meta_attributes id="dummies-meta">
207          <nvpair name="globally-unique" value="false" id="dummies-meta-globally-unique"/>
208        </meta_attributes>
209        <meta_attributes id="dummies-meta_attributes">
210          <nvpair id="dummies-meta_attributes-target-role" name="target-role" value="Stopped"/>
211        </meta_attributes>
212        <primitive id="dummy-1" class="ocf" provider="heartbeat" type="Dummy"/>
213      </clone>"""
214    elem = etree.fromstring(xml)
215    from crmsh.ui_resource import set_deep_meta_attr_node
216
217    assert len(elem.xpath(".//meta_attributes/nvpair[@name='target-role']")) == 1
218
219    print("BEFORE:", etree.tostring(elem))
220
221    set_deep_meta_attr_node(elem, 'target-role', 'Stopped')
222
223    print("AFTER:", etree.tostring(elem))
224
225    assert len(elem.xpath(".//meta_attributes/nvpair[@name='target-role']")) == 1
226
227
228def test_bnc878128():
229    """
230    L3: "crm configure show" displays XML information instead of typical crm output.
231    """
232    xml = """<rsc_location id="cli-prefer-dummy-resource" rsc="dummy-resource"
233role="Started">
234  <rule id="cli-prefer-rule-dummy-resource" score="INFINITY">
235    <expression id="cli-prefer-expr-dummy-resource" attribute="#uname"
236operation="eq" value="x64-4"/>
237    <date_expression id="cli-prefer-lifetime-end-dummy-resource" operation="lt"
238end="2014-05-17 17:56:11Z"/>
239  </rule>
240</rsc_location>"""
241    data = etree.fromstring(xml)
242    obj = factory.create_from_node(data)
243    assert obj is not None
244    data = obj.repr_cli(format_mode=-1)
245    print("OUTPUT:", data)
246    exp = 'location cli-prefer-dummy-resource dummy-resource role=Started rule #uname eq x64-4 and date lt "2014-05-17 17:56:11Z"'
247    assert data == exp
248    assert obj.cli_use_validate()
249
250
251def test_order_without_score_kind():
252    """
253    Spec says order doesn't require score or kind to be set
254    """
255    xml = '<rsc_order first="a" first-action="promote" id="order-a-b" then="b" then-action="start"/>'
256    data = etree.fromstring(xml)
257    obj = factory.create_from_node(data)
258    assert obj is not None
259    data = obj.repr_cli(format_mode=-1)
260    print("OUTPUT:", data)
261    exp = 'order order-a-b a:promote b:start'
262    assert data == exp
263    assert obj.cli_use_validate()
264
265
266
267def test_bnc878112():
268    """
269    crm configure group can hijack a cloned primitive (and then crash)
270    """
271    obj1 = factory.create_object('primitive', 'p1', 'Dummy')
272    assert obj1 is True
273    obj2 = factory.create_object('group', 'g1', 'p1')
274    assert obj2 is True
275    obj3 = factory.create_object('group', 'g2', 'p1')
276    print(obj3)
277    assert obj3 is False
278
279
280def test_copy_nvpairs():
281    from crmsh.cibconfig import copy_nvpairs
282
283    to = etree.fromstring('''
284    <node>
285    <nvpair name="stonith-enabled" value="true"/>
286    </node>
287    ''')
288    copy_nvpairs(to, etree.fromstring('''
289    <node>
290    <nvpair name="stonith-enabled" value="false"/>
291    </node>
292    '''))
293
294    assert ['stonith-enabled'] == to.xpath('./nvpair/@name')
295    assert ['false'] == to.xpath('./nvpair/@value')
296
297    copy_nvpairs(to, etree.fromstring('''
298    <node>
299    <nvpair name="stonith-enabled" value="true"/>
300    </node>
301    '''))
302
303    assert ['stonith-enabled'] == to.xpath('./nvpair/@name')
304    assert ['true'] == to.xpath('./nvpair/@value')
305
306
307def test_pengine_test():
308    xml = '''<primitive class="ocf" id="rsc1" provider="pacemaker" type="Dummy">
309        <instance_attributes id="rsc1-instance_attributes-1">
310          <nvpair id="rsc1-instance_attributes-1-state" name="state" value="/var/run/Dummy-rsc1-clusterA"/>
311          <rule id="rsc1-instance_attributes-1-rule-1" score="0">
312            <expression id="rsc1-instance_attributes-1-rule-1-expr-1" attribute="#cluster-name" operation="eq" value="clusterA"/>
313          </rule>
314        </instance_attributes>
315        <instance_attributes id="rsc1-instance_attributes-2">
316          <nvpair id="rsc1-instance_attributes-2-state" name="state" value="/var/run/Dummy-rsc1-clusterB"/>
317          <rule id="rsc1-instance_attributes-2-rule-1" score="0">
318            <expression id="rsc1-instance_attributes-2-rule-1-expr-1" attribute="#cluster-name" operation="eq" value="clusterB"/>
319          </rule>
320        </instance_attributes>
321        <operations>
322          <op id="rsc1-monitor-10" interval="10" name="monitor"/>
323        </operations>
324      </primitive>'''
325    data = etree.fromstring(xml)
326    obj = factory.create_from_node(data)
327    assert obj is not None
328    data = obj.repr_cli(format_mode=-1)
329    print("OUTPUT:", data)
330    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'
331    assert data == exp
332    assert obj.cli_use_validate()
333
334
335def test_tagset():
336    xml = '''<primitive class="ocf" id="%s" provider="pacemaker" type="Dummy"/>'''
337    tag = '''<tag id="t0"><obj_ref id="r1"/><obj_ref id="r2"/></tag>'''
338    factory.create_from_node(etree.fromstring(xml % ('r1')))
339    factory.create_from_node(etree.fromstring(xml % ('r2')))
340    factory.create_from_node(etree.fromstring(xml % ('r3')))
341    factory.create_from_node(etree.fromstring(tag))
342    elems = factory.get_elems_on_tag("tag:t0")
343    assert set(x.obj_id for x in elems) == set(['r1', 'r2'])
344
345
346def test_ratrace():
347    xml = '''<primitive class="ocf" id="%s" provider="pacemaker" type="Dummy"/>'''
348    factory.create_from_node(etree.fromstring(xml % ('r1')))
349    factory.create_from_node(etree.fromstring(xml % ('r2')))
350    factory.create_from_node(etree.fromstring(xml % ('r3')))
351
352    context = object()
353
354    from crmsh.ui_resource import RscMgmt
355    obj = factory.find_object('r1')
356    RscMgmt()._trace_resource(context, 'r1', obj)
357
358    obj = factory.find_object('r1')
359    ops = obj.node.xpath('./operations/op')
360    for op in ops:
361        assert op.xpath('./instance_attributes/nvpair[@name="trace_ra"]/@value') == ["1"]
362    assert set(obj.node.xpath('./operations/op/@name')) == set(['start', 'stop'])
363
364
365def test_op_role():
366    xml = '''<primitive class="ocf" id="rsc2" provider="pacemaker" type="Dummy">
367        <operations>
368          <op id="rsc2-monitor-10" interval="10" name="monitor" role="Stopped"/>
369        </operations>
370      </primitive>'''
371    data = etree.fromstring(xml)
372    obj = factory.create_from_node(data)
373    assert obj is not None
374    data = obj.repr_cli(format_mode=-1)
375    print("OUTPUT:", data)
376    exp = 'primitive rsc2 ocf:pacemaker:Dummy op monitor interval=10 role=Stopped'
377    assert data == exp
378    assert obj.cli_use_validate()
379
380
381def test_nvpair_no_value():
382    xml = '''<primitive class="ocf" id="rsc3" provider="heartbeat" type="Dummy">
383        <instance_attributes id="rsc3-instance_attributes-1">
384          <nvpair id="rsc3-instance_attributes-1-verbose" name="verbose"/>
385          <nvpair id="rsc3-instance_attributes-1-verbase" name="verbase" value=""/>
386          <nvpair id="rsc3-instance_attributes-1-verbese" name="verbese" value=" "/>
387        </instance_attributes>
388      </primitive>'''
389    data = etree.fromstring(xml)
390    obj = factory.create_from_node(data)
391    assert obj is not None
392    data = obj.repr_cli(format_mode=-1)
393    print("OUTPUT:", data)
394    exp = 'primitive rsc3 Dummy params verbose verbase="" verbese=" "'
395    assert data == exp
396    assert obj.cli_use_validate()
397
398
399def test_delete_ticket():
400    xml0 = '<primitive id="daa0" class="ocf" provider="heartbeat" type="Dummy"/>'
401    xml1 = '<primitive id="daa1" class="ocf" provider="heartbeat" type="Dummy"/>'
402    xml2 = '''<rsc_ticket id="taa0" ticket="taaA">
403        <resource_set id="taa0-0">
404          <resource_ref id="daa0"/>
405          <resource_ref id="daa1"/>
406        </resource_set>
407      </rsc_ticket>'''
408    for x in (xml0, xml1, xml2):
409        data = etree.fromstring(x)
410        obj = factory.create_from_node(data)
411        assert obj is not None
412        data = obj.repr_cli(format_mode=-1)
413
414    factory.delete('daa0')
415    assert factory.find_object('daa0') is None
416    assert factory.find_object('taa0') is not None
417
418
419def test_quotes():
420    """
421    Parsing escaped quotes
422    """
423    xml = '''<primitive class="ocf" id="q1" provider="pacemaker" type="Dummy">
424        <instance_attributes id="q1-instance_attributes-1">
425          <nvpair id="q1-instance_attributes-1-state" name="state" value="foo&quot;foo&quot;"/>
426        </instance_attributes>
427    </primitive>
428    '''
429    data = etree.fromstring(xml)
430    obj = factory.create_from_node(data)
431    assert obj is not None
432    data = obj.repr_cli(format_mode=-1)
433    print("OUTPUT:", data)
434    exp = 'primitive q1 ocf:pacemaker:Dummy params state="foo\\"foo\\""'
435    assert data == exp
436    assert obj.cli_use_validate()
437
438
439def test_nodeattrs():
440    """
441    bug with parsing node attrs
442    """
443    xml = '''<node id="1" uname="dell71"> \
444  <instance_attributes id="dell71-instance_attributes"> \
445    <nvpair name="staging-0-0-placement" value="true" id="dell71-instance_attributes-staging-0-0-placement"/> \
446    <nvpair name="meta-0-0-placement" value="true" id="dell71-instance_attributes-meta-0-0-placement"/> \
447  </instance_attributes> \
448  <instance_attributes id="nodes-1"> \
449    <nvpair id="nodes-1-standby" name="standby" value="off"/> \
450  </instance_attributes> \
451</node>'''
452
453    data = etree.fromstring(xml)
454    obj = factory.create_from_node(data)
455    assert obj is not None
456    data = obj.repr_cli(format_mode=-1)
457    exp = 'node 1: dell71 attributes staging-0-0-placement=true meta-0-0-placement=true attributes standby=off'
458    assert data == exp
459    assert obj.cli_use_validate()
460
461
462def test_nodeattrs2():
463    xml = """<node id="h04" uname="h04"> \
464 <utilization id="h04-utilization"> \
465   <nvpair id="h04-utilization-utl_ram" name="utl_ram" value="1200"/> \
466   <nvpair id="h04-utilization-utl_cpu" name="utl_cpu" value="200"/> \
467 </utilization> \
468 <instance_attributes id="nodes-h04"> \
469   <nvpair id="nodes-h04-standby" name="standby" value="off"/> \
470 </instance_attributes> \
471</node>"""
472    data = etree.fromstring(xml)
473    obj = factory.create_from_node(data)
474    assert obj is not None
475    data = obj.repr_cli(format_mode=-1)
476    exp = 'node h04 utilization utl_ram=1200 utl_cpu=200 attributes standby=off'
477    assert data == exp
478    assert obj.cli_use_validate()
479
480
481def test_group_constraint_location():
482    """
483    configuring a location constraint on a grouped resource is OK
484    """
485    factory.create_object('node', 'node1')
486    factory.create_object('primitive', 'p1', 'Dummy')
487    factory.create_object('primitive', 'p2', 'Dummy')
488    factory.create_object('group', 'g1', 'p1', 'p2')
489    factory.create_object('location', 'loc-p1', 'p1', 'inf:', 'node1')
490    c = factory.find_object('loc-p1')
491    assert c and c.check_sanity() == 0
492
493
494def test_group_constraint_colocation():
495    """
496    configuring a colocation constraint on a grouped resource is bad
497    """
498    factory.create_object('primitive', 'p1', 'Dummy')
499    factory.create_object('primitive', 'p2', 'Dummy')
500    factory.create_object('group', 'g1', 'p1', 'p2')
501    factory.create_object('colocation', 'coloc-p1-p2', 'inf:', 'p1', 'p2')
502    c = factory.find_object('coloc-p1-p2')
503    assert c and c.check_sanity() > 0
504
505
506def test_group_constraint_colocation_rscset():
507    """
508    configuring a constraint on a grouped resource is bad
509    """
510    factory.create_object('primitive', 'p1', 'Dummy')
511    factory.create_object('primitive', 'p2', 'Dummy')
512    factory.create_object('primitive', 'p3', 'Dummy')
513    factory.create_object('group', 'g1', 'p1', 'p2')
514    factory.create_object('colocation', 'coloc-p1-p2-p3', 'inf:', 'p1', 'p2', 'p3')
515    c = factory.find_object('coloc-p1-p2-p3')
516    assert c and c.check_sanity() > 0
517
518
519def test_clone_constraint_colocation_rscset():
520    """
521    configuring a constraint on a cloned resource is bad
522    """
523    factory.create_object('primitive', 'p1', 'Dummy')
524    factory.create_object('primitive', 'p2', 'Dummy')
525    factory.create_object('primitive', 'p3', 'Dummy')
526    factory.create_object('clone', 'c1', 'p1')
527    factory.create_object('colocation', 'coloc-p1-p2-p3', 'inf:', 'p1', 'p2', 'p3')
528    c = factory.find_object('coloc-p1-p2-p3')
529    assert c and c.check_sanity() > 0
530
531
532def test_existing_node_resource():
533    factory.create_object('primitive', 'ha-one', 'Dummy')
534
535    n = factory.find_node('ha-one')
536    assert factory.test_element(n)
537
538    r = factory.find_resource('ha-one')
539    assert factory.test_element(r)
540
541    assert n != r
542
543    assert factory.check_structure()
544    factory.cli_use_validate_all()
545
546    ok, s = factory.mkobj_set('ha-one')
547    assert ok
548
549
550def test_existing_node_resource_2():
551    obj = cibconfig.mkset_obj()
552    assert obj is not None
553
554    from crmsh import clidisplay
555    with clidisplay.nopretty():
556        text = obj.repr()
557    text += "\nprimitive ha-one Dummy"
558    ok = obj.save(text)
559    assert ok
560
561    obj = cibconfig.mkset_obj()
562    assert obj is not None
563    with clidisplay.nopretty():
564        text2 = obj.repr()
565
566    assert sorted(text.split('\n')) == sorted(text2.split('\n'))
567
568
569def test_id_collision_breakage_1():
570    from crmsh import clidisplay
571
572    obj = cibconfig.mkset_obj()
573    assert obj is not None
574    with clidisplay.nopretty():
575        original_cib = obj.repr()
576    print(original_cib)
577
578    obj = cibconfig.mkset_obj()
579    assert obj is not None
580
581    ok = obj.save("""node node1
582primitive p0 ocf:pacemaker:Dummy
583primitive p1 ocf:pacemaker:Dummy
584primitive p2 ocf:heartbeat:Delay \
585    params startdelay=2 mondelay=2 stopdelay=2
586primitive p3 ocf:pacemaker:Dummy
587primitive st stonith:null params hostlist=node1
588clone c1 p1
589ms m1 p2
590op_defaults timeout=60s
591""")
592    assert ok
593
594    obj = cibconfig.mkset_obj()
595    assert obj is not None
596    ok = obj.save("""op_defaults timeout=2m
597node node1 \
598    attributes mem=16G
599primitive st stonith:null \
600    params hostlist='node1' \
601    meta description="some description here" requires=nothing \
602    op monitor interval=60m
603primitive p1 ocf:heartbeat:Dummy \
604    op monitor interval=60m \
605    op monitor interval=120m OCF_CHECK_LEVEL=10
606""")
607    assert ok
608
609    obj = cibconfig.mkset_obj()
610    with clidisplay.nopretty():
611        text = obj.repr()
612    text = text + "\nprimitive p2 ocf:heartbeat:Dummy"
613    ok = obj.save(text)
614    assert ok
615
616    obj = cibconfig.mkset_obj()
617    with clidisplay.nopretty():
618        text = obj.repr()
619    text = text + "\ngroup g1 p1 p2"
620    ok = obj.save(text)
621    assert ok
622
623    obj = cibconfig.mkset_obj("g1")
624    with clidisplay.nopretty():
625        text = obj.repr()
626    text = text.replace("group g1 p1 p2", "group g1 p1 p3")
627    text = text + "\nprimitive p3 ocf:heartbeat:Dummy"
628    ok = obj.save(text)
629    assert ok
630
631    obj = cibconfig.mkset_obj("g1")
632    with clidisplay.nopretty():
633        print(obj.repr().strip())
634        assert obj.repr().strip() == "group g1 p1 p3"
635
636    obj = cibconfig.mkset_obj()
637    assert obj is not None
638    ok = obj.save(original_cib)
639    assert ok
640    obj = cibconfig.mkset_obj()
641    with clidisplay.nopretty():
642        print("*** ORIGINAL")
643        print(original_cib)
644        print("*** NOW")
645        print(obj.repr())
646        assert original_cib == obj.repr()
647
648
649def test_id_collision_breakage_3():
650    from crmsh import clidisplay
651
652    obj = cibconfig.mkset_obj()
653    assert obj is not None
654    with clidisplay.nopretty():
655        original_cib = obj.repr()
656    print(original_cib)
657
658    obj = cibconfig.mkset_obj()
659    assert obj is not None
660    ok = obj.save("""node node1
661primitive node1 Dummy params fake=something
662    """)
663    assert ok
664
665    print("** baseline")
666    obj = cibconfig.mkset_obj()
667    assert obj is not None
668    with clidisplay.nopretty():
669        print(obj.repr())
670
671    obj = cibconfig.mkset_obj()
672    assert obj is not None
673    ok = obj.save("""primitive node1 Dummy params fake=something-else
674    """, remove=False, method='update')
675    assert ok
676
677    print("** end")
678
679    obj = cibconfig.mkset_obj()
680    assert obj is not None
681    ok = obj.save(original_cib, remove=True, method='replace')
682    assert ok
683    obj = cibconfig.mkset_obj()
684    with clidisplay.nopretty():
685        print("*** ORIGINAL")
686        print(original_cib)
687        print("*** NOW")
688        print(obj.repr())
689        assert original_cib == obj.repr()
690
691
692def test_id_collision_breakage_2():
693    from crmsh import clidisplay
694
695    obj = cibconfig.mkset_obj()
696    assert obj is not None
697    with clidisplay.nopretty():
698        original_cib = obj.repr()
699    print(original_cib)
700
701    obj = cibconfig.mkset_obj()
702    assert obj is not None
703
704    ok = obj.save("""node 168633610: webui
705node 168633611: node1
706rsc_template web-server apache \
707	params port=8000 \
708	op monitor interval=10s
709primitive d0 Dummy \
710	meta target-role=Started
711primitive d1 Dummy
712primitive d2 Dummy
713# Never use this STONITH agent in production!
714primitive development-stonith stonith:null \
715	params hostlist="webui node1 node2 node3"
716primitive proxy systemd:haproxy \
717	op monitor interval=10s
718primitive proxy-vip IPaddr2 \
719	params ip=10.13.37.20
720primitive srv1 @web-server
721primitive srv2 @web-server
722primitive vip1 IPaddr2 \
723	params ip=10.13.37.21 \
724	op monitor interval=20s
725primitive vip2 IPaddr2 \
726	params ip=10.13.37.22 \
727	op monitor interval=20s
728primitive virtual-ip IPaddr2 \
729	params ip=10.13.37.77 lvs_support=false \
730	op start timeout=20 interval=0 \
731	op stop timeout=20 interval=0 \
732	op monitor interval=10 timeout=20
733primitive yet-another-virtual-ip IPaddr2 \
734	params ip=10.13.37.72 cidr_netmask=24 \
735	op start interval=0 timeout=20 \
736	op stop interval=0 timeout=20 \
737	op monitor interval=10 timeout=20 \
738	meta target-role=Started
739group dovip d0 virtual-ip \
740	meta target-role=Stopped
741group g-proxy proxy-vip proxy
742group g-serv1 vip1 srv1
743group g-serv2 vip2 srv2
744clone d2-clone d2 \
745	meta target-role=Started
746tag dummytag d0 d1 d1-on-node1 d2 d2-clone
747# Never put the two web servers on the same node
748colocation co-serv -inf: g-serv1 g-serv2
749location d1-on-node1 d1 inf: node1
750# Never put any web server or haproxy on webui
751location l-avoid-webui { g-proxy g-serv1 g-serv2 } -inf: webui
752# Prever to spread groups across nodes
753location l-proxy g-proxy 200: node1
754location l-serv1 g-serv1 200: node2
755location l-serv2 g-serv2 200: node3
756property cib-bootstrap-options: \
757	have-watchdog=false \
758	dc-version="1.1.13+git20150917.20c2178-224.2-1.1.13+git20150917.20c2178" \
759	cluster-infrastructure=corosync \
760	cluster-name=hacluster \
761	stonith-enabled=true \
762	no-quorum-policy=ignore
763rsc_defaults rsc-options: \
764	resource-stickiness=1 \
765	migration-threshold=3
766op_defaults op-options: \
767	timeout=600 \
768	record-pending=true
769""")
770    assert ok
771
772    obj = cibconfig.mkset_obj()
773    assert obj is not None
774    ok = obj.save(original_cib)
775    assert ok
776    obj = cibconfig.mkset_obj()
777    with clidisplay.nopretty():
778        print("*** ORIGINAL")
779        print(original_cib)
780        print("*** NOW")
781        print(obj.repr())
782        assert original_cib == obj.repr()
783
784
785def test_bug_110():
786    """
787    configuring attribute-based fencing-topology
788    """
789    factory.create_object(*"primitive stonith-libvirt stonith:null".split())
790    factory.create_object(*"primitive fence-nova stonith:null".split())
791    cmd = "fencing_topology attr:OpenStack-role=compute stonith-libvirt,fence-nova".split()
792    ok = factory.create_object(*cmd)
793    assert ok
794    obj = cibconfig.mkset_obj()
795    assert obj is not None
796
797    for o in obj.obj_set:
798        if o.node.tag == 'fencing-topology':
799            assert o.check_sanity() == 0
800
801
802def test_reordering_resource_sets():
803    """
804    Can we reorder resource sets?
805    """
806    from crmsh import clidisplay
807    obj1 = factory.create_object('primitive', 'p1', 'Dummy')
808    assert obj1 is True
809    obj2 = factory.create_object('primitive', 'p2', 'Dummy')
810    assert obj2 is True
811    obj3 = factory.create_object('primitive', 'p3', 'Dummy')
812    assert obj3 is True
813    obj4 = factory.create_object('primitive', 'p4', 'Dummy')
814    assert obj4 is True
815    o1 = factory.create_object('order', 'o1', 'p1', 'p2', 'p3', 'p4')
816    assert o1 is True
817
818    obj = cibconfig.mkset_obj('o1')
819    assert obj is not None
820    rc = obj.save('order o1 p4 p3 p2 p1')
821    assert rc == True
822
823    obj2 = cibconfig.mkset_obj('o1')
824    with clidisplay.nopretty():
825        assert "order o1 p4 p3 p2 p1" == obj2.repr().strip()
826
827
828def test_bug959895():
829    """
830    Allow importing XML with cloned groups
831    """
832    xml = """<clone id="c-bug959895">
833    <group id="g-bug959895">
834    <primitive id="p-bug959895-a" class="ocf" provider="pacemaker" type="Dummy" />
835    <primitive id="p-bug959895-b" class="ocf" provider="pacemaker" type="Dummy" />
836    </group>
837</clone>
838"""
839    data = etree.fromstring(xml)
840    obj = factory.create_from_node(data)
841    print(etree.tostring(obj.node))
842    data = obj.repr_cli(format_mode=-1)
843    print(data)
844    exp = 'clone c-bug959895 g-bug959895'
845    assert data == exp
846    assert obj.cli_use_validate()
847
848    commit_holder = factory.commit
849    try:
850        factory.commit = lambda *args: True
851        from crmsh.ui_resource import set_deep_meta_attr
852        set_deep_meta_attr("c-bug959895", "target-role", "Started")
853        assert ['Started'] == obj.node.xpath('.//nvpair[@name="target-role"]/@value')
854    finally:
855        factory.commit = commit_holder
856
857
858def test_node_util_attr():
859    """
860    Handle node with utitilization before attributes correctly
861    """
862    xml = """<node id="aberfeldy" uname="aberfeldy">
863  <utilization id="nodes-aberfeldy-utilization">
864    <nvpair id="nodes-aberfeldy-utilization-cpu" name="cpu" value="2"/>
865    <nvpair id="nodes-aberfeldy-utilization-memory" name="memory" value="500"/>
866  </utilization>
867  <instance_attributes id="nodes-aberfeldy">
868    <nvpair id="nodes-aberfeldy-standby" name="standby" value="on"/>
869  </instance_attributes>
870</node>"""
871
872    data = etree.fromstring(xml)
873    obj = factory.create_from_node(data)
874    print(etree.tostring(obj.node))
875    data = obj.repr_cli(format_mode=-1)
876    print(data)
877    exp = 'node aberfeldy utilization cpu=2 memory=500 attributes standby=on'
878    assert data == exp
879    assert obj.cli_use_validate()
880
881
882def test_dup_create_same_name():
883    """
884    Creating two objects with the same name
885    """
886    ok = factory.create_object(*"primitive dup1 Dummy".split())
887    assert ok
888    ok = factory.create_object(*"primitive dup1 Dummy".split())
889    assert not ok
890
891
892def test_dup_create():
893    """
894    Creating property sets with unknown properties
895    """
896    ok = factory.create_object(*"property hana_test1: hana_attribute_1=5 hana_attribute_2=mohican".split())
897    assert ok
898    ok = factory.create_object(*"property hana_test2: hana_attribute_1=5s a-b-c-d=e-f-g".split())
899    assert ok
900