|
|
bc4e95 |
From e56f42bf31ae0a52618fe8754fd0b2ae623e6a7a Mon Sep 17 00:00:00 2001
|
|
|
bc4e95 |
From: Tomas Jelinek <tojeline@redhat.com>
|
|
|
bc4e95 |
Date: Thu, 12 Dec 2019 14:46:44 +0100
|
|
|
bc4e95 |
Subject: [PATCH 1/7] squash bz1781303 fix safe-disabling clones, groups,
|
|
|
bc4e95 |
bundles
|
|
|
bc4e95 |
|
|
|
bc4e95 |
fix simulate_cib_error report
|
|
|
bc4e95 |
|
|
|
bc4e95 |
Putting only one CIB in the report is not enough info. Both original and
|
|
|
bc4e95 |
changed CIB as well as crm_simulate output would be needed. All that
|
|
|
bc4e95 |
info can be seen in debug messages. So there is no need to put it in the
|
|
|
bc4e95 |
report.
|
|
|
bc4e95 |
---
|
|
|
bc4e95 |
pcs/cli/common/console_report.py | 7 +-
|
|
|
bc4e95 |
pcs/lib/cib/resource/common.py | 21 +-
|
|
|
bc4e95 |
pcs/lib/commands/resource.py | 27 +-
|
|
|
bc4e95 |
pcs/lib/pacemaker/live.py | 8 +-
|
|
|
bc4e95 |
pcs/lib/reports.py | 4 +-
|
|
|
bc4e95 |
.../tier0/cli/common/test_console_report.py | 10 +-
|
|
|
bc4e95 |
.../tier0/lib/cib/test_resource_common.py | 60 ++++-
|
|
|
bc4e95 |
.../resource/test_resource_enable_disable.py | 242 +++++++++++++++++-
|
|
|
bc4e95 |
pcs_test/tier0/lib/pacemaker/test_live.py | 7 -
|
|
|
bc4e95 |
9 files changed, 350 insertions(+), 36 deletions(-)
|
|
|
bc4e95 |
|
|
|
bc4e95 |
diff --git a/pcs/cli/common/console_report.py b/pcs/cli/common/console_report.py
|
|
|
bc4e95 |
index d349c823..60dbb2a0 100644
|
|
|
bc4e95 |
--- a/pcs/cli/common/console_report.py
|
|
|
bc4e95 |
+++ b/pcs/cli/common/console_report.py
|
|
|
bc4e95 |
@@ -1269,8 +1269,11 @@ CODE_TO_MESSAGE_BUILDER_MAP = {
|
|
|
bc4e95 |
,
|
|
|
bc4e95 |
|
|
|
bc4e95 |
codes.CIB_SIMULATE_ERROR: lambda info:
|
|
|
bc4e95 |
- "Unable to simulate changes in CIB: {reason}\n{cib}"
|
|
|
bc4e95 |
- .format(**info)
|
|
|
bc4e95 |
+ "Unable to simulate changes in CIB{_reason}"
|
|
|
bc4e95 |
+ .format(
|
|
|
bc4e95 |
+ _reason=format_optional(info["reason"], ": {0}"),
|
|
|
bc4e95 |
+ **info
|
|
|
bc4e95 |
+ )
|
|
|
bc4e95 |
,
|
|
|
bc4e95 |
|
|
|
bc4e95 |
codes.CIB_PUSH_FORCED_FULL_DUE_TO_CRM_FEATURE_SET: lambda info:
|
|
|
bc4e95 |
diff --git a/pcs/lib/cib/resource/common.py b/pcs/lib/cib/resource/common.py
|
|
|
bc4e95 |
index f1891003..e30c5e69 100644
|
|
|
bc4e95 |
--- a/pcs/lib/cib/resource/common.py
|
|
|
bc4e95 |
+++ b/pcs/lib/cib/resource/common.py
|
|
|
bc4e95 |
@@ -1,8 +1,9 @@
|
|
|
bc4e95 |
from collections import namedtuple
|
|
|
bc4e95 |
from typing import (
|
|
|
bc4e95 |
cast,
|
|
|
bc4e95 |
+ List,
|
|
|
bc4e95 |
Optional,
|
|
|
bc4e95 |
- Sequence,
|
|
|
bc4e95 |
+ Set,
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
from xml.etree.ElementTree import Element
|
|
|
bc4e95 |
|
|
|
bc4e95 |
@@ -114,7 +115,23 @@ def find_primitives(resource_el):
|
|
|
bc4e95 |
return [resource_el]
|
|
|
bc4e95 |
return []
|
|
|
bc4e95 |
|
|
|
bc4e95 |
-def get_inner_resources(resource_el: Element) -> Sequence[Element]:
|
|
|
bc4e95 |
+def get_all_inner_resources(resource_el: Element) -> Set[Element]:
|
|
|
bc4e95 |
+ """
|
|
|
bc4e95 |
+ Return all inner resources (both direct and indirect) of a resource
|
|
|
bc4e95 |
+ Example: for a clone containing a group, this function will return both
|
|
|
bc4e95 |
+ the group and the resources inside the group
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ resource_el -- resource element to get its inner resources
|
|
|
bc4e95 |
+ """
|
|
|
bc4e95 |
+ all_inner: Set[Element] = set()
|
|
|
bc4e95 |
+ to_process = set([resource_el])
|
|
|
bc4e95 |
+ while to_process:
|
|
|
bc4e95 |
+ new_inner = get_inner_resources(to_process.pop())
|
|
|
bc4e95 |
+ to_process.update(set(new_inner) - all_inner)
|
|
|
bc4e95 |
+ all_inner.update(new_inner)
|
|
|
bc4e95 |
+ return all_inner
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+def get_inner_resources(resource_el: Element) -> List[Element]:
|
|
|
bc4e95 |
"""
|
|
|
bc4e95 |
Return list of inner resources (direct descendants) of a resource
|
|
|
bc4e95 |
specified as resource_el.
|
|
|
bc4e95 |
diff --git a/pcs/lib/commands/resource.py b/pcs/lib/commands/resource.py
|
|
|
bc4e95 |
index 1b652ea4..4f975c7f 100644
|
|
|
bc4e95 |
--- a/pcs/lib/commands/resource.py
|
|
|
bc4e95 |
+++ b/pcs/lib/commands/resource.py
|
|
|
bc4e95 |
@@ -802,7 +802,28 @@ def disable_safe(env, resource_ids, strict, wait):
|
|
|
bc4e95 |
with resource_environment(
|
|
|
bc4e95 |
env, wait, resource_ids, _ensure_disabled_after_wait(True)
|
|
|
bc4e95 |
) as resources_section:
|
|
|
bc4e95 |
- _disable_validate_and_edit_cib(env, resources_section, resource_ids)
|
|
|
bc4e95 |
+ id_provider = IdProvider(resources_section)
|
|
|
bc4e95 |
+ resource_el_list = _find_resources_or_raise(
|
|
|
bc4e95 |
+ resources_section,
|
|
|
bc4e95 |
+ resource_ids
|
|
|
bc4e95 |
+ )
|
|
|
bc4e95 |
+ env.report_processor.process_list(
|
|
|
bc4e95 |
+ _resource_list_enable_disable(
|
|
|
bc4e95 |
+ resource_el_list,
|
|
|
bc4e95 |
+ resource.common.disable,
|
|
|
bc4e95 |
+ id_provider,
|
|
|
bc4e95 |
+ env.get_cluster_state()
|
|
|
bc4e95 |
+ )
|
|
|
bc4e95 |
+ )
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ inner_resources_names_set = set()
|
|
|
bc4e95 |
+ for resource_el in resource_el_list:
|
|
|
bc4e95 |
+ inner_resources_names_set.update({
|
|
|
bc4e95 |
+ inner_resource_el.get("id")
|
|
|
bc4e95 |
+ for inner_resource_el
|
|
|
bc4e95 |
+ in resource.common.get_all_inner_resources(resource_el)
|
|
|
bc4e95 |
+ })
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
plaintext_status, transitions, dummy_cib = simulate_cib(
|
|
|
bc4e95 |
env.cmd_runner(),
|
|
|
bc4e95 |
get_root(resources_section)
|
|
|
bc4e95 |
@@ -830,6 +851,10 @@ def disable_safe(env, resource_ids, strict, wait):
|
|
|
bc4e95 |
exclude=resource_ids
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ # Stopping a clone stops all its inner resources. That should not block
|
|
|
bc4e95 |
+ # stopping the clone.
|
|
|
bc4e95 |
+ other_affected = other_affected - inner_resources_names_set
|
|
|
bc4e95 |
if other_affected:
|
|
|
bc4e95 |
raise LibraryError(
|
|
|
bc4e95 |
reports.resource_disable_affects_other_resources(
|
|
|
bc4e95 |
diff --git a/pcs/lib/pacemaker/live.py b/pcs/lib/pacemaker/live.py
|
|
|
bc4e95 |
index 83274af0..233f2e2d 100644
|
|
|
bc4e95 |
--- a/pcs/lib/pacemaker/live.py
|
|
|
bc4e95 |
+++ b/pcs/lib/pacemaker/live.py
|
|
|
bc4e95 |
@@ -271,7 +271,7 @@ def simulate_cib_xml(runner, cib_xml):
|
|
|
bc4e95 |
transitions_file = write_tmpfile(None)
|
|
|
bc4e95 |
except OSError as e:
|
|
|
bc4e95 |
raise LibraryError(
|
|
|
bc4e95 |
- reports.cib_simulate_error(format_os_error(e), cib_xml)
|
|
|
bc4e95 |
+ reports.cib_simulate_error(format_os_error(e))
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
|
|
|
bc4e95 |
cmd = [
|
|
|
bc4e95 |
@@ -284,7 +284,7 @@ def simulate_cib_xml(runner, cib_xml):
|
|
|
bc4e95 |
stdout, stderr, retval = runner.run(cmd, stdin_string=cib_xml)
|
|
|
bc4e95 |
if retval != 0:
|
|
|
bc4e95 |
raise LibraryError(
|
|
|
bc4e95 |
- reports.cib_simulate_error(stderr.strip(), cib_xml)
|
|
|
bc4e95 |
+ reports.cib_simulate_error(stderr.strip())
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
|
|
|
bc4e95 |
try:
|
|
|
bc4e95 |
@@ -297,7 +297,7 @@ def simulate_cib_xml(runner, cib_xml):
|
|
|
bc4e95 |
return stdout, transitions_xml, new_cib_xml
|
|
|
bc4e95 |
except OSError as e:
|
|
|
bc4e95 |
raise LibraryError(
|
|
|
bc4e95 |
- reports.cib_simulate_error(format_os_error(e), cib_xml)
|
|
|
bc4e95 |
+ reports.cib_simulate_error(format_os_error(e))
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
|
|
|
bc4e95 |
def simulate_cib(runner, cib):
|
|
|
bc4e95 |
@@ -319,7 +319,7 @@ def simulate_cib(runner, cib):
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
except (etree.XMLSyntaxError, etree.DocumentInvalid) as e:
|
|
|
bc4e95 |
raise LibraryError(
|
|
|
bc4e95 |
- reports.cib_simulate_error(str(e), cib_xml)
|
|
|
bc4e95 |
+ reports.cib_simulate_error(str(e))
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
|
|
|
bc4e95 |
### wait for idle
|
|
|
bc4e95 |
diff --git a/pcs/lib/reports.py b/pcs/lib/reports.py
|
|
|
bc4e95 |
index 1f081007..c9b4a25d 100644
|
|
|
bc4e95 |
--- a/pcs/lib/reports.py
|
|
|
bc4e95 |
+++ b/pcs/lib/reports.py
|
|
|
bc4e95 |
@@ -1935,18 +1935,16 @@ def cib_diff_error(reason, cib_old, cib_new):
|
|
|
bc4e95 |
}
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
|
|
|
bc4e95 |
-def cib_simulate_error(reason, cib):
|
|
|
bc4e95 |
+def cib_simulate_error(reason):
|
|
|
bc4e95 |
"""
|
|
|
bc4e95 |
cannot simulate effects a CIB would have on a live cluster
|
|
|
bc4e95 |
|
|
|
bc4e95 |
string reason -- error description
|
|
|
bc4e95 |
- string cib -- the CIB whose effects were to be simulated
|
|
|
bc4e95 |
"""
|
|
|
bc4e95 |
return ReportItem.error(
|
|
|
bc4e95 |
report_codes.CIB_SIMULATE_ERROR,
|
|
|
bc4e95 |
info={
|
|
|
bc4e95 |
"reason": reason,
|
|
|
bc4e95 |
- "cib": cib,
|
|
|
bc4e95 |
}
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
|
|
|
bc4e95 |
diff --git a/pcs_test/tier0/cli/common/test_console_report.py b/pcs_test/tier0/cli/common/test_console_report.py
|
|
|
bc4e95 |
index 0d0c2457..29e9614d 100644
|
|
|
bc4e95 |
--- a/pcs_test/tier0/cli/common/test_console_report.py
|
|
|
bc4e95 |
+++ b/pcs_test/tier0/cli/common/test_console_report.py
|
|
|
bc4e95 |
@@ -2238,8 +2238,14 @@ class CibDiffError(NameBuildTest):
|
|
|
bc4e95 |
class CibSimulateError(NameBuildTest):
|
|
|
bc4e95 |
def test_success(self):
|
|
|
bc4e95 |
self.assert_message_from_report(
|
|
|
bc4e95 |
- "Unable to simulate changes in CIB: error message\n<cib />",
|
|
|
bc4e95 |
- reports.cib_simulate_error("error message", "<cib />")
|
|
|
bc4e95 |
+ "Unable to simulate changes in CIB: error message",
|
|
|
bc4e95 |
+ reports.cib_simulate_error("error message")
|
|
|
bc4e95 |
+ )
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ def test_empty_reason(self):
|
|
|
bc4e95 |
+ self.assert_message_from_report(
|
|
|
bc4e95 |
+ "Unable to simulate changes in CIB",
|
|
|
bc4e95 |
+ reports.cib_simulate_error("")
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
|
|
|
bc4e95 |
|
|
|
bc4e95 |
diff --git a/pcs_test/tier0/lib/cib/test_resource_common.py b/pcs_test/tier0/lib/cib/test_resource_common.py
|
|
|
bc4e95 |
index ebba09da..cd716ba2 100644
|
|
|
bc4e95 |
--- a/pcs_test/tier0/lib/cib/test_resource_common.py
|
|
|
bc4e95 |
+++ b/pcs_test/tier0/lib/cib/test_resource_common.py
|
|
|
bc4e95 |
@@ -200,10 +200,12 @@ class FindOneOrMoreResources(TestCase):
|
|
|
bc4e95 |
|
|
|
bc4e95 |
|
|
|
bc4e95 |
class FindResourcesMixin:
|
|
|
bc4e95 |
+ _iterable_type = list
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
def assert_find_resources(self, input_resource_id, output_resource_ids):
|
|
|
bc4e95 |
self.assertEqual(
|
|
|
bc4e95 |
- output_resource_ids,
|
|
|
bc4e95 |
- [
|
|
|
bc4e95 |
+ self._iterable_type(output_resource_ids),
|
|
|
bc4e95 |
+ self._iterable_type([
|
|
|
bc4e95 |
element.get("id", "")
|
|
|
bc4e95 |
for element in
|
|
|
bc4e95 |
self._tested_fn(
|
|
|
bc4e95 |
@@ -211,7 +213,7 @@ class FindResourcesMixin:
|
|
|
bc4e95 |
'.//*[@id="{0}"]'.format(input_resource_id)
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
- ]
|
|
|
bc4e95 |
+ ])
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
|
|
|
bc4e95 |
def test_group(self):
|
|
|
bc4e95 |
@@ -235,6 +237,27 @@ class FindResourcesMixin:
|
|
|
bc4e95 |
def test_bundle_with_primitive(self):
|
|
|
bc4e95 |
self.assert_find_resources("H-bundle", ["H"])
|
|
|
bc4e95 |
|
|
|
bc4e95 |
+ def test_primitive(self):
|
|
|
bc4e95 |
+ raise NotImplementedError()
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ def test_primitive_in_clone(self):
|
|
|
bc4e95 |
+ raise NotImplementedError()
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ def test_primitive_in_master(self):
|
|
|
bc4e95 |
+ raise NotImplementedError()
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ def test_primitive_in_group(self):
|
|
|
bc4e95 |
+ raise NotImplementedError()
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ def test_primitive_in_bundle(self):
|
|
|
bc4e95 |
+ raise NotImplementedError()
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ def test_cloned_group(self):
|
|
|
bc4e95 |
+ raise NotImplementedError()
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ def test_mastered_group(self):
|
|
|
bc4e95 |
+ raise NotImplementedError()
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
|
|
|
bc4e95 |
class FindPrimitives(TestCase, FindResourcesMixin):
|
|
|
bc4e95 |
_tested_fn = staticmethod(common.find_primitives)
|
|
|
bc4e95 |
@@ -266,6 +289,37 @@ class FindPrimitives(TestCase, FindResourcesMixin):
|
|
|
bc4e95 |
self.assert_find_resources("F-master", ["F1", "F2"])
|
|
|
bc4e95 |
|
|
|
bc4e95 |
|
|
|
bc4e95 |
+class GetAllInnerResources(TestCase, FindResourcesMixin):
|
|
|
bc4e95 |
+ _iterable_type = set
|
|
|
bc4e95 |
+ _tested_fn = staticmethod(common.get_all_inner_resources)
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ def test_primitive(self):
|
|
|
bc4e95 |
+ self.assert_find_resources("A", set())
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ def test_primitive_in_clone(self):
|
|
|
bc4e95 |
+ self.assert_find_resources("B", set())
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ def test_primitive_in_master(self):
|
|
|
bc4e95 |
+ self.assert_find_resources("C", set())
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ def test_primitive_in_group(self):
|
|
|
bc4e95 |
+ self.assert_find_resources("D1", set())
|
|
|
bc4e95 |
+ self.assert_find_resources("D2", set())
|
|
|
bc4e95 |
+ self.assert_find_resources("E1", set())
|
|
|
bc4e95 |
+ self.assert_find_resources("E2", set())
|
|
|
bc4e95 |
+ self.assert_find_resources("F1", set())
|
|
|
bc4e95 |
+ self.assert_find_resources("F2", set())
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ def test_primitive_in_bundle(self):
|
|
|
bc4e95 |
+ self.assert_find_resources("H", set())
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ def test_cloned_group(self):
|
|
|
bc4e95 |
+ self.assert_find_resources("E-clone", {"E", "E1", "E2"})
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ def test_mastered_group(self):
|
|
|
bc4e95 |
+ self.assert_find_resources("F-master", {"F", "F1", "F2"})
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
class GetInnerResources(TestCase, FindResourcesMixin):
|
|
|
bc4e95 |
_tested_fn = staticmethod(common.get_inner_resources)
|
|
|
bc4e95 |
|
|
|
bc4e95 |
diff --git a/pcs_test/tier0/lib/commands/resource/test_resource_enable_disable.py b/pcs_test/tier0/lib/commands/resource/test_resource_enable_disable.py
|
|
|
bc4e95 |
index 634f0f33..62899940 100644
|
|
|
bc4e95 |
--- a/pcs_test/tier0/lib/commands/resource/test_resource_enable_disable.py
|
|
|
bc4e95 |
+++ b/pcs_test/tier0/lib/commands/resource/test_resource_enable_disable.py
|
|
|
bc4e95 |
@@ -1729,12 +1729,6 @@ class DisableSimulate(TestCase):
|
|
|
bc4e95 |
fixture.error(
|
|
|
bc4e95 |
report_codes.CIB_SIMULATE_ERROR,
|
|
|
bc4e95 |
reason="some stderr",
|
|
|
bc4e95 |
- # curently, there is no way to normalize xml with our lxml
|
|
|
bc4e95 |
- # version 4.2.3, so this never passes equality tests
|
|
|
bc4e95 |
- # cib=self.config.calls.get(
|
|
|
bc4e95 |
- # "runner.pcmk.simulate_cib"
|
|
|
bc4e95 |
- # ).check_stdin.expected_stdin
|
|
|
bc4e95 |
- # ,
|
|
|
bc4e95 |
),
|
|
|
bc4e95 |
],
|
|
|
bc4e95 |
expected_in_processor=False
|
|
|
bc4e95 |
@@ -1988,12 +1982,6 @@ class DisableSafeMixin():
|
|
|
bc4e95 |
fixture.error(
|
|
|
bc4e95 |
report_codes.CIB_SIMULATE_ERROR,
|
|
|
bc4e95 |
reason="some stderr",
|
|
|
bc4e95 |
- # curently, there is no way to normalize xml with our lxml
|
|
|
bc4e95 |
- # version 4.2.3, so this never passes equality tests
|
|
|
bc4e95 |
- # cib=self.config.calls.get(
|
|
|
bc4e95 |
- # "runner.pcmk.simulate_cib"
|
|
|
bc4e95 |
- # ).check_stdin.expected_stdin
|
|
|
bc4e95 |
- # ,
|
|
|
bc4e95 |
),
|
|
|
bc4e95 |
],
|
|
|
bc4e95 |
expected_in_processor=False
|
|
|
bc4e95 |
@@ -2118,6 +2106,236 @@ class DisableSafeMixin():
|
|
|
bc4e95 |
fixture.report_resource_not_running("B"),
|
|
|
bc4e95 |
])
|
|
|
bc4e95 |
|
|
|
bc4e95 |
+ def test_inner_resources(self, mock_write_tmpfile):
|
|
|
bc4e95 |
+ cib_xml = """
|
|
|
bc4e95 |
+ <resources>
|
|
|
bc4e95 |
+ <primitive id="A" />
|
|
|
bc4e95 |
+ <clone id="B-clone">
|
|
|
bc4e95 |
+ <primitive id="B" />
|
|
|
bc4e95 |
+ </clone>
|
|
|
bc4e95 |
+ <master id="C-master">
|
|
|
bc4e95 |
+ <primitive id="C" />
|
|
|
bc4e95 |
+ </master>
|
|
|
bc4e95 |
+ <group id="D">
|
|
|
bc4e95 |
+ <primitive id="D1" />
|
|
|
bc4e95 |
+ <primitive id="D2" />
|
|
|
bc4e95 |
+ </group>
|
|
|
bc4e95 |
+ <clone id="E-clone">
|
|
|
bc4e95 |
+ <group id="E">
|
|
|
bc4e95 |
+ <primitive id="E1" />
|
|
|
bc4e95 |
+ <primitive id="E2" />
|
|
|
bc4e95 |
+ </group>
|
|
|
bc4e95 |
+ </clone>
|
|
|
bc4e95 |
+ <master id="F-master">
|
|
|
bc4e95 |
+ <group id="F">
|
|
|
bc4e95 |
+ <primitive id="F1" />
|
|
|
bc4e95 |
+ <primitive id="F2" />
|
|
|
bc4e95 |
+ </group>
|
|
|
bc4e95 |
+ </master>
|
|
|
bc4e95 |
+ <bundle id="G-bundle" />
|
|
|
bc4e95 |
+ <bundle id="H-bundle">
|
|
|
bc4e95 |
+ <primitive id="H" />
|
|
|
bc4e95 |
+ </bundle>
|
|
|
bc4e95 |
+ </resources>
|
|
|
bc4e95 |
+ """
|
|
|
bc4e95 |
+ status_xml = """
|
|
|
bc4e95 |
+ <resources>
|
|
|
bc4e95 |
+ <resource id="A" managed="true" />
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ unique="false"
|
|
|
bc4e95 |
+ >
|
|
|
bc4e95 |
+ <resource id="B" managed="true" />
|
|
|
bc4e95 |
+ <resource id="B" managed="true" />
|
|
|
bc4e95 |
+ </clone>
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ unique="false"
|
|
|
bc4e95 |
+ >
|
|
|
bc4e95 |
+ <resource id="C" managed="true" />
|
|
|
bc4e95 |
+ <resource id="C" managed="true" />
|
|
|
bc4e95 |
+ </clone>
|
|
|
bc4e95 |
+ <group id="D" number_resources="2">
|
|
|
bc4e95 |
+ <resource id="D1" managed="true" />
|
|
|
bc4e95 |
+ <resource id="D2" managed="true" />
|
|
|
bc4e95 |
+ </group>
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ unique="false"
|
|
|
bc4e95 |
+ >
|
|
|
bc4e95 |
+ <group id="E:0" number_resources="2">
|
|
|
bc4e95 |
+ <resource id="E1" managed="true" />
|
|
|
bc4e95 |
+ <resource id="E2" managed="true" />
|
|
|
bc4e95 |
+ </group>
|
|
|
bc4e95 |
+ <group id="E:1" number_resources="2">
|
|
|
bc4e95 |
+ <resource id="E1" managed="true" />
|
|
|
bc4e95 |
+ <resource id="E2" managed="true" />
|
|
|
bc4e95 |
+ </group>
|
|
|
bc4e95 |
+ </clone>
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ unique="false"
|
|
|
bc4e95 |
+ >
|
|
|
bc4e95 |
+ <group id="F:0" number_resources="2">
|
|
|
bc4e95 |
+ <resource id="F1" managed="true" />
|
|
|
bc4e95 |
+ <resource id="F2" managed="true" />
|
|
|
bc4e95 |
+ </group>
|
|
|
bc4e95 |
+ <group id="F:1" number_resources="2">
|
|
|
bc4e95 |
+ <resource id="F1" managed="true" />
|
|
|
bc4e95 |
+ <resource id="F2" managed="true" />
|
|
|
bc4e95 |
+ </group>
|
|
|
bc4e95 |
+ </clone>
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ unique="false" managed="true" failed="false"
|
|
|
bc4e95 |
+ >
|
|
|
bc4e95 |
+ <replica id="0">
|
|
|
bc4e95 |
+ <resource id="H" />
|
|
|
bc4e95 |
+ </replica>
|
|
|
bc4e95 |
+ <replica id="1">
|
|
|
bc4e95 |
+ <resource id="H" />
|
|
|
bc4e95 |
+ </replica>
|
|
|
bc4e95 |
+ </bundle>
|
|
|
bc4e95 |
+ </resources>
|
|
|
bc4e95 |
+ """
|
|
|
bc4e95 |
+ synapses = []
|
|
|
bc4e95 |
+ index = 0
|
|
|
bc4e95 |
+ for res_name, is_clone in [
|
|
|
bc4e95 |
+ ("A", False),
|
|
|
bc4e95 |
+ ("B", True),
|
|
|
bc4e95 |
+ ("C", True),
|
|
|
bc4e95 |
+ ("D1", False),
|
|
|
bc4e95 |
+ ("D2", False),
|
|
|
bc4e95 |
+ ("E1", True),
|
|
|
bc4e95 |
+ ("E2", True),
|
|
|
bc4e95 |
+ ("F1", True),
|
|
|
bc4e95 |
+ ("F2", True),
|
|
|
bc4e95 |
+ ("H", False),
|
|
|
bc4e95 |
+ ]:
|
|
|
bc4e95 |
+ if is_clone:
|
|
|
bc4e95 |
+ synapses.append(f"""
|
|
|
bc4e95 |
+ <synapse>
|
|
|
bc4e95 |
+ <action_set>
|
|
|
bc4e95 |
+ <rsc_op id="{index}" operation="stop" on_node="node1">
|
|
|
bc4e95 |
+ <primitive id="{res_name}" long_id="{res_name}:0" />
|
|
|
bc4e95 |
+ </rsc_op>
|
|
|
bc4e95 |
+ </action_set>
|
|
|
bc4e95 |
+ </synapse>
|
|
|
bc4e95 |
+ <synapse>
|
|
|
bc4e95 |
+ <action_set>
|
|
|
bc4e95 |
+ <rsc_op id="{index + 1}" operation="stop" on_node="node2">
|
|
|
bc4e95 |
+ <primitive id="{res_name}" long_id="{res_name}:1" />
|
|
|
bc4e95 |
+ </rsc_op>
|
|
|
bc4e95 |
+ </action_set>
|
|
|
bc4e95 |
+ </synapse>
|
|
|
bc4e95 |
+ """)
|
|
|
bc4e95 |
+ index += 2
|
|
|
bc4e95 |
+ else:
|
|
|
bc4e95 |
+ synapses.append(f"""
|
|
|
bc4e95 |
+ <synapse>
|
|
|
bc4e95 |
+ <action_set>
|
|
|
bc4e95 |
+ <rsc_op id="{index}" operation="stop" on_node="node1">
|
|
|
bc4e95 |
+ <primitive id="{res_name}" />
|
|
|
bc4e95 |
+ </rsc_op>
|
|
|
bc4e95 |
+ </action_set>
|
|
|
bc4e95 |
+ </synapse>
|
|
|
bc4e95 |
+ """)
|
|
|
bc4e95 |
+ index += 1
|
|
|
bc4e95 |
+ transitions_xml = (
|
|
|
bc4e95 |
+ "<transition_graph>" + "\n".join(synapses) + "</transition_graph>"
|
|
|
bc4e95 |
+ )
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ self.tmpfile_transitions.read.return_value = transitions_xml
|
|
|
bc4e95 |
+ mock_write_tmpfile.side_effect = [
|
|
|
bc4e95 |
+ self.tmpfile_new_cib, self.tmpfile_transitions,
|
|
|
bc4e95 |
+ AssertionError("No other write_tmpfile call expected")
|
|
|
bc4e95 |
+ ]
|
|
|
bc4e95 |
+ (self.config
|
|
|
bc4e95 |
+ .runner.cib.load(resources=cib_xml)
|
|
|
bc4e95 |
+ .runner.pcmk.load_state(resources=status_xml)
|
|
|
bc4e95 |
+ )
|
|
|
bc4e95 |
+ self.config.runner.pcmk.simulate_cib(
|
|
|
bc4e95 |
+ self.tmpfile_new_cib.name,
|
|
|
bc4e95 |
+ self.tmpfile_transitions.name,
|
|
|
bc4e95 |
+ stdout="simulate output",
|
|
|
bc4e95 |
+ resources="""
|
|
|
bc4e95 |
+ <resources>
|
|
|
bc4e95 |
+ <primitive id="A" />
|
|
|
bc4e95 |
+ <clone id="B-clone">
|
|
|
bc4e95 |
+ <meta_attributes id="B-clone-meta_attributes">
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ id="B-clone-meta_attributes-target-role"
|
|
|
bc4e95 |
+ />
|
|
|
bc4e95 |
+ </meta_attributes>
|
|
|
bc4e95 |
+ <primitive id="B" />
|
|
|
bc4e95 |
+ </clone>
|
|
|
bc4e95 |
+ <master id="C-master">
|
|
|
bc4e95 |
+ <meta_attributes id="C-master-meta_attributes">
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ id="C-master-meta_attributes-target-role"
|
|
|
bc4e95 |
+ />
|
|
|
bc4e95 |
+ </meta_attributes>
|
|
|
bc4e95 |
+ <primitive id="C" />
|
|
|
bc4e95 |
+ </master>
|
|
|
bc4e95 |
+ <group id="D">
|
|
|
bc4e95 |
+ <meta_attributes id="D-meta_attributes">
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ id="D-meta_attributes-target-role"
|
|
|
bc4e95 |
+ />
|
|
|
bc4e95 |
+ </meta_attributes>
|
|
|
bc4e95 |
+ <primitive id="D1" />
|
|
|
bc4e95 |
+ <primitive id="D2" />
|
|
|
bc4e95 |
+ </group>
|
|
|
bc4e95 |
+ <clone id="E-clone">
|
|
|
bc4e95 |
+ <meta_attributes id="E-clone-meta_attributes">
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ id="E-clone-meta_attributes-target-role"
|
|
|
bc4e95 |
+ />
|
|
|
bc4e95 |
+ </meta_attributes>
|
|
|
bc4e95 |
+ <group id="E">
|
|
|
bc4e95 |
+ <primitive id="E1" />
|
|
|
bc4e95 |
+ <primitive id="E2" />
|
|
|
bc4e95 |
+ </group>
|
|
|
bc4e95 |
+ </clone>
|
|
|
bc4e95 |
+ <master id="F-master">
|
|
|
bc4e95 |
+ <meta_attributes id="F-master-meta_attributes">
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ id="F-master-meta_attributes-target-role"
|
|
|
bc4e95 |
+ />
|
|
|
bc4e95 |
+ </meta_attributes>
|
|
|
bc4e95 |
+ <group id="F">
|
|
|
bc4e95 |
+ <primitive id="F1" />
|
|
|
bc4e95 |
+ <primitive id="F2" />
|
|
|
bc4e95 |
+ </group>
|
|
|
bc4e95 |
+ </master>
|
|
|
bc4e95 |
+ <bundle id="G-bundle" />
|
|
|
bc4e95 |
+ <bundle id="H-bundle">
|
|
|
bc4e95 |
+ <meta_attributes id="H-bundle-meta_attributes">
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
+ id="H-bundle-meta_attributes-target-role"
|
|
|
bc4e95 |
+ />
|
|
|
bc4e95 |
+ </meta_attributes>
|
|
|
bc4e95 |
+ <primitive id="H" />
|
|
|
bc4e95 |
+ </bundle>
|
|
|
bc4e95 |
+ </resources>
|
|
|
bc4e95 |
+ """
|
|
|
bc4e95 |
+ )
|
|
|
bc4e95 |
+ self.env_assist.assert_raise_library_error(
|
|
|
bc4e95 |
+ lambda: resource.disable_safe(
|
|
|
bc4e95 |
+ self.env_assist.get_env(),
|
|
|
bc4e95 |
+ ["B-clone", "C-master", "D", "E-clone", "F-master", "H-bundle"],
|
|
|
bc4e95 |
+ self.strict,
|
|
|
bc4e95 |
+ False,
|
|
|
bc4e95 |
+ ),
|
|
|
bc4e95 |
+ [
|
|
|
bc4e95 |
+ fixture.error(
|
|
|
bc4e95 |
+ report_codes.RESOURCE_DISABLE_AFFECTS_OTHER_RESOURCES,
|
|
|
bc4e95 |
+ disabled_resource_list=[
|
|
|
bc4e95 |
+ "B-clone", "C-master", "D", "E-clone", "F-master",
|
|
|
bc4e95 |
+ "H-bundle"
|
|
|
bc4e95 |
+ ],
|
|
|
bc4e95 |
+ affected_resource_list=["A"],
|
|
|
bc4e95 |
+ crm_simulate_plaintext_output="simulate output",
|
|
|
bc4e95 |
+ ),
|
|
|
bc4e95 |
+ ],
|
|
|
bc4e95 |
+ expected_in_processor=False
|
|
|
bc4e95 |
+ )
|
|
|
bc4e95 |
+
|
|
|
bc4e95 |
@mock.patch("pcs.lib.pacemaker.live.write_tmpfile")
|
|
|
bc4e95 |
class DisableSafe(DisableSafeMixin, TestCase):
|
|
|
bc4e95 |
strict = False
|
|
|
bc4e95 |
diff --git a/pcs_test/tier0/lib/pacemaker/test_live.py b/pcs_test/tier0/lib/pacemaker/test_live.py
|
|
|
bc4e95 |
index dfebcb17..1ea5454e 100644
|
|
|
bc4e95 |
--- a/pcs_test/tier0/lib/pacemaker/test_live.py
|
|
|
bc4e95 |
+++ b/pcs_test/tier0/lib/pacemaker/test_live.py
|
|
|
bc4e95 |
@@ -686,7 +686,6 @@ class SimulateCibXml(LibraryPacemakerTest):
|
|
|
bc4e95 |
fixture.error(
|
|
|
bc4e95 |
report_codes.CIB_SIMULATE_ERROR,
|
|
|
bc4e95 |
reason="some error",
|
|
|
bc4e95 |
- cib="<cib />",
|
|
|
bc4e95 |
),
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
mock_runner.run.assert_not_called()
|
|
|
bc4e95 |
@@ -703,7 +702,6 @@ class SimulateCibXml(LibraryPacemakerTest):
|
|
|
bc4e95 |
fixture.error(
|
|
|
bc4e95 |
report_codes.CIB_SIMULATE_ERROR,
|
|
|
bc4e95 |
reason="some error",
|
|
|
bc4e95 |
- cib="<cib />",
|
|
|
bc4e95 |
),
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
mock_runner.run.assert_not_called()
|
|
|
bc4e95 |
@@ -729,7 +727,6 @@ class SimulateCibXml(LibraryPacemakerTest):
|
|
|
bc4e95 |
fixture.error(
|
|
|
bc4e95 |
report_codes.CIB_SIMULATE_ERROR,
|
|
|
bc4e95 |
reason="some error",
|
|
|
bc4e95 |
- cib="<cib />",
|
|
|
bc4e95 |
),
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
|
|
|
bc4e95 |
@@ -755,7 +752,6 @@ class SimulateCibXml(LibraryPacemakerTest):
|
|
|
bc4e95 |
fixture.error(
|
|
|
bc4e95 |
report_codes.CIB_SIMULATE_ERROR,
|
|
|
bc4e95 |
reason="some error",
|
|
|
bc4e95 |
- cib="<cib />",
|
|
|
bc4e95 |
),
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
|
|
|
bc4e95 |
@@ -782,7 +778,6 @@ class SimulateCibXml(LibraryPacemakerTest):
|
|
|
bc4e95 |
fixture.error(
|
|
|
bc4e95 |
report_codes.CIB_SIMULATE_ERROR,
|
|
|
bc4e95 |
reason="some error",
|
|
|
bc4e95 |
- cib="<cib />",
|
|
|
bc4e95 |
),
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
|
|
|
bc4e95 |
@@ -819,7 +814,6 @@ class SimulateCib(TestCase):
|
|
|
bc4e95 |
"Start tag expected, '<' not found, line 1, column 1 "
|
|
|
bc4e95 |
"(<string>, line 1)"
|
|
|
bc4e95 |
),
|
|
|
bc4e95 |
- cib=self.cib_xml,
|
|
|
bc4e95 |
),
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
|
|
|
bc4e95 |
@@ -835,7 +829,6 @@ class SimulateCib(TestCase):
|
|
|
bc4e95 |
"Start tag expected, '<' not found, line 1, column 1 "
|
|
|
bc4e95 |
"(<string>, line 1)"
|
|
|
bc4e95 |
),
|
|
|
bc4e95 |
- cib=self.cib_xml,
|
|
|
bc4e95 |
),
|
|
|
bc4e95 |
)
|
|
|
bc4e95 |
|
|
|
bc4e95 |
--
|
|
|
bc4e95 |
2.21.1
|
|
|
bc4e95 |
|