Exemple #1
0
def add_level(lib_env: LibraryEnvironment,
              level,
              target_type,
              target_value,
              devices,
              force_device=False,
              force_node=False):
    """
    Validate and add a new fencing level

    LibraryEnvironment lib_env -- environment
    int|string level -- level (index) of the new fencing level
    constant target_type -- the new fencing level target value type
    mixed target_value -- the new fencing level target value
    Iterable devices -- list of stonith devices for the new fencing level
    bool force_device -- continue even if a stonith device does not exist
    bool force_node -- continue even if a node (target) does not exist
    """
    version_check = None
    if target_type == TARGET_TYPE_REGEXP:
        version_check = Version(2, 3, 0)
    elif target_type == TARGET_TYPE_ATTRIBUTE:
        version_check = Version(2, 4, 0)

    cib = lib_env.get_cib(version_check)
    cib_fencing_topology.add_level(
        lib_env.report_processor, get_fencing_topology(cib),
        get_resources(cib), level, target_type, target_value, devices,
        ClusterState(get_cluster_status_xml(
            lib_env.cmd_runner())).node_section.nodes, force_device,
        force_node)
    if lib_env.report_processor.has_errors:
        raise LibraryError()
    lib_env.push_cib()
Exemple #2
0
    def push_cib(self, custom_cib=None, wait=False):
        """
        Push previously loaded instance of CIB or a custom CIB

        etree custom_cib -- push a custom CIB instead of a loaded instance
            (allows to push an externally provided CIB and replace the one in
            the cluster completely)
        mixed wait -- how many seconds to wait for pacemaker to process new CIB
            or False for not waiting at all
        """
        if custom_cib is not None:
            if self.__loaded_cib_diff_source is not None:
                raise AssertionError(
                    "CIB has been loaded, cannot push custom CIB"
                )
            return self.__push_cib_full(custom_cib, wait)
        if self.__loaded_cib_diff_source is None:
            raise AssertionError("CIB has not been loaded")
        # Push by diff works with crm_feature_set > 3.0.8, see
        # https://bugzilla.redhat.com/show_bug.cgi?id=1488044 for details. We
        # only check the version if a CIB has been loaded, otherwise the push
        # fails anyway. By my testing it seems that only the source CIB's
        # version matters.
        if self.__loaded_cib_diff_source_feature_set < Version(3, 0, 9):
            self.report_processor.process(
                reports.cib_push_forced_full_due_to_crm_feature_set(
                    Version(3, 0, 9),
                    self.__loaded_cib_diff_source_feature_set
                )
            )
            return self.__push_cib_full(self.__loaded_cib_to_modify, wait=wait)
        return self.__push_cib_diff(wait=wait)
Exemple #3
0
def _defaults_create(
    env: LibraryEnvironment,
    cib_section_name: str,
    validator_options: Mapping[str, Any],
    nvpairs: Mapping[str, str],
    nvset_options: Mapping[str, str],
    nvset_rule: Optional[str] = None,
    force_flags: Optional[Container] = None,
) -> None:
    if force_flags is None:
        force_flags = set()
    force = (reports.codes.FORCE
             in force_flags) or (reports.codes.FORCE_OPTIONS in force_flags)

    required_cib_version = None
    nice_to_have_cib_version = None
    if nvset_rule:
        # Parse the rule to see if we need to upgrade CIB schema. All errors
        # would be properly reported by a validator called bellow, so we can
        # safely ignore them here.
        try:
            rule_tree = parse_rule(nvset_rule)
            if has_rsc_or_op_expression(rule_tree):
                required_cib_version = Version(3, 4, 0)
            if has_node_attr_expr_with_type_integer(rule_tree):
                nice_to_have_cib_version = Version(3, 5, 0)
        except RuleParseError:
            pass

    cib = env.get_cib(
        minimal_version=required_cib_version,
        nice_to_have_version=nice_to_have_cib_version,
    )
    id_provider = IdProvider(cib)

    validator = nvpair_multi.ValidateNvsetAppendNew(
        id_provider,
        nvpairs,
        nvset_options,
        nvset_rule=nvset_rule,
        **validator_options,
    )
    if env.report_processor.report_list(
            validator.validate(force_options=force)).has_errors:
        raise LibraryError()

    nvpair_multi.nvset_append_new(
        sections.get(cib, cib_section_name),
        id_provider,
        get_pacemaker_version_by_which_cib_was_validated(cib),
        nvpair_multi.NVSET_META,
        nvpairs,
        nvset_options,
        nvset_rule=validator.get_parsed_rule(),
    )

    env.report_processor.report(
        ReportItem.warning(reports.messages.DefaultsCanBeOverriden()))
    env.push_cib()
Exemple #4
0
    def test_satisfied_nice_to_have_greater_than_required(self):
        (self.config.runner.cib.load(
            name="load_cib_old",
            filename="cib-empty-2.6.xml").runner.cib.upgrade().runner.cib.load(
                filename="cib-empty-2.8.xml"))
        env = self.env_assist.get_env()
        env.get_cib(Version(2, 7, 0), Version(2, 8, 0))

        self.env_assist.assert_reports(
            [fixture.info(report_codes.CIB_UPGRADE_SUCCESSFUL)])
Exemple #5
0
    def test_nice_to_have_equal_required(self):
        (self.config.runner.cib.load(
            name="load_cib_old",
            filename="cib-empty-3.1.xml").runner.cib.upgrade().runner.cib.load(
                filename="cib-empty-3.3.xml"))
        env = self.env_assist.get_env()
        env.get_cib(Version(3, 3, 0), Version(3, 3, 0))

        self.env_assist.assert_reports(
            [fixture.info(report_codes.CIB_UPGRADE_SUCCESSFUL)])
Exemple #6
0
def _get_required_cib_version_for_container(container_type, container_options):
    if container_type == "podman":
        return Version(3, 2, 0)

    if "promoted-max" in container_options:
        return Version(3, 0, 0)

    if container_type == "rkt":
        return Version(2, 10, 0)

    return Version(2, 8, 0)
Exemple #7
0
 def test_higher_version(self, mock_upgrade, mock_get_cib):
     actual_cib, was_upgraded = lib.ensure_cib_version(
         self.mock_runner, self.cib, Version(2, 3, 3))
     self.assertEqual(self.cib, actual_cib)
     self.assertFalse(was_upgraded)
     mock_upgrade.assert_not_called()
     mock_get_cib.assert_not_called()
Exemple #8
0
 def assert_cib(tree, expected_xml, schema_version=None):
     if schema_version is None:
         schema_version = Version(3, 5, 0)
     xml = etree.fromstring('<root id="X"/>')
     rule.rule_to_cib(xml, IdProvider(xml), schema_version, tree)
     assert_xml_equal('<root id="X">' + expected_xml + "</root>",
                      etree_to_str(xml))
Exemple #9
0
 def test_nvpairs(self):
     context_element = etree.fromstring("""<context id="a" />""")
     id_provider = IdProvider(context_element)
     nvpair_multi.nvset_append_new(
         context_element,
         id_provider,
         Version(3, 5, 0),
         nvpair_multi.NVSET_META,
         {"attr1": "value1", "attr-empty": "", "attr2": "value2"},
         {},
     )
     assert_xml_equal(
         """
             <context id="a">
                 <meta_attributes id="a-meta_attributes">
                     <nvpair id="a-meta_attributes-attr1"
                         name="attr1" value="value1"
                     />
                     <nvpair id="a-meta_attributes-attr2"
                         name="attr2" value="value2"
                     />
                 </meta_attributes>
             </context>
         """,
         etree_to_str(context_element),
     )
Exemple #10
0
 def test_success(self):
     self.assertEqual(
         Version(3, 0, 9),
         lib.get_cib_crm_feature_set(
             etree.XML('<cib crm_feature_set="3.0.9" />')
         )
     )
Exemple #11
0
 def test_with_revision(self):
     self.assertEqual(
         Version(1, 2, 3),
         lib.get_pacemaker_version_by_which_cib_was_validated(
             etree.XML('<cib validate-with="pacemaker-1.2.3"/>')
         )
     )
Exemple #12
0
 def get_cib(self, minimal_version=None):
     if self.__loaded_cib_diff_source is not None:
         raise AssertionError("CIB has already been loaded")
     self.__loaded_cib_diff_source = get_cib_xml(self.cmd_runner())
     self.__loaded_cib_to_modify = get_cib(self.__loaded_cib_diff_source)
     if minimal_version is not None:
         upgraded_cib = ensure_cib_version(
             self.cmd_runner(),
             self.__loaded_cib_to_modify,
             minimal_version
         )
         if upgraded_cib is not None:
             self.__loaded_cib_to_modify = upgraded_cib
             self.__loaded_cib_diff_source = etree_to_str(upgraded_cib)
             if not self._cib_upgrade_reported:
                 self.report_processor.process(
                     reports.cib_upgrade_successful()
                 )
             self._cib_upgrade_reported = True
     self.__loaded_cib_diff_source_feature_set = (
         get_cib_crm_feature_set(
             self.__loaded_cib_to_modify,
             none_if_missing=True
         )
         or
         Version(0, 0, 0)
     )
     return self.__loaded_cib_to_modify
Exemple #13
0
 def test_success_no_revision(self):
     self.assertEqual(
         Version(3, 1),
         lib.get_cib_crm_feature_set(
             etree.XML('<cib crm_feature_set="3.1" />')
         )
     )
Exemple #14
0
    def test_target_attribute_updates_cib(
        self, mock_get_cib, mock_status_xml, mock_status, mock_push_cib,
        mock_get_topology, mock_get_resources, mock_add_level
    ):
        self.prepare_mocks(
            mock_get_cib, mock_status_xml, mock_status, mock_get_topology,
            mock_get_resources
        )
        lib_env = create_lib_env()

        lib.add_level(
            lib_env, "level", TARGET_TYPE_ATTRIBUTE, "target value", "devices",
            "force device", "force node"
        )

        mock_add_level.assert_called_once_with(
            lib_env.report_processor,
            "topology el",
            "resources_el",
            "level",
            TARGET_TYPE_ATTRIBUTE,
            "target value",
            "devices",
            "nodes",
            "force device",
            "force node"
        )
        mock_get_cib.assert_called_once_with(Version(2, 4, 0))
        self.assert_mocks(
            mock_status_xml, mock_status, mock_get_topology, mock_get_resources,
            mock_push_cib
        )
Exemple #15
0
def _get_cib_version(
    cib: _ElementTree, attribute: str, regexp: Pattern
) -> Version:
    version = cib.getroot().get(attribute)
    if version is None:
        raise LibraryError(
            ReportItem.error(
                reports.messages.CibLoadErrorBadFormat(
                    f"the attribute '{attribute}' of the element 'cib' "
                    "is missing"
                )
            )
        )
    match = regexp.match(version)
    if not match:
        raise LibraryError(
            ReportItem.error(
                reports.messages.CibLoadErrorBadFormat(
                    f"the attribute '{attribute}' of the element 'cib' has "
                    f"an invalid value: '{version}'"
                )
            )
        )
    return Version(
        int(match.group("major")),
        int(match.group("minor")),
        int(match.group("rev")) if match.group("rev") else None,
    )
Exemple #16
0
 def build_expression(self, dom_element, syntactic_tree):
     dom_expression = self.add_element(
         dom_element, "expression", dom_element.getAttribute("id") + "-expr"
     )
     dom_expression.setAttribute("operation", syntactic_tree.symbol_id)
     dom_expression.setAttribute(
         "attribute", syntactic_tree.children[0].value
     )
     if not isinstance(syntactic_tree, SymbolPrefix):
         child = syntactic_tree.children[1]
         if isinstance(child, SymbolType):
             # rhbz#1869399
             # Pcs was always accepting 'integer', while CIB was only
             # supporting 'number' (and 'string' and 'version'). Pacemaker
             # was documenting it as 'integer' and was treating it as
             # integer (not float). With CIB schema 3.5.0, both 'integer'
             # and 'number' are accepted by CIB. For older schemas, we turn
             # 'integer' to 'number'.
             if (
                 self.cib_schema_version < Version(3, 5, 0)
                 and child.symbol_id == "integer"
             ):
                 dom_expression.setAttribute("type", "number")
             else:
                 dom_expression.setAttribute("type", child.symbol_id)
             child = child.children[0]
         dom_expression.setAttribute("value", child.value)
Exemple #17
0
 def _export_node_attr(self, parent_el: _Element,
                       expr: NodeAttrExpr) -> _Element:
     element = etree.SubElement(
         parent_el,
         "expression",
         {
             "id": create_subelement_id(parent_el, "expr",
                                        self.id_provider),
             "attribute": expr.attr_name,
             "operation": expr.operator.lower(),
         },
     )
     if expr.attr_value:
         element.attrib["value"] = expr.attr_value
     if expr.attr_type:
         # rhbz#1869399
         # Pcs was always accepting 'integer', while CIB was only supporting
         # 'number' (and 'string' and 'version'). Pacemaker was documenting
         # it as 'integer' and was treating it as integer (not float). With
         # CIB schema 3.5.0, both 'integer' and 'number' are accepted by
         # CIB. For older schemas, we turn 'integer' to 'number'.
         if (self.cib_schema_version < Version(3, 5, 0)
                 and expr.attr_type == NODE_ATTR_TYPE_INTEGER):
             element.attrib["type"] = "number"
         else:
             element.attrib["type"] = expr.attr_type.lower()
     return element
Exemple #18
0
 def test_higher_version(self, mock_upgrade, mock_get_cib):
     self.assertTrue(
         lib.ensure_cib_version(
             self.mock_runner, self.cib, Version(2, 3, 3)
         ) is None
     )
     mock_upgrade.assert_not_called()
     mock_get_cib.assert_not_called()
Exemple #19
0
 def test_upgraded_higher_version(self, mock_upgrade, mock_get_cib):
     expected_cib = '<cib validate-with="pacemaker-2.3.6"/>'
     mock_get_cib.return_value = expected_cib
     actual_cib, was_upgraded = lib.ensure_cib_version(
         self.mock_runner, self.cib, Version(2, 3, 5))
     assert_xml_equal(expected_cib, etree.tostring(actual_cib).decode())
     self.assertTrue(was_upgraded)
     mock_upgrade.assert_called_once_with(self.mock_runner)
     mock_get_cib.assert_called_once_with(self.mock_runner)
Exemple #20
0
 def test_upgraded_higher_version(self, mock_upgrade, mock_get_cib):
     upgraded_cib = '<cib validate-with="pacemaker-2.3.6"/>'
     mock_get_cib.return_value = upgraded_cib
     assert_xml_equal(
         upgraded_cib,
         etree.tostring(
             lib.ensure_cib_version(self.mock_runner, self.cib,
                                    Version(2, 3, 5))).decode())
     mock_upgrade.assert_called_once_with(self.mock_runner)
     mock_get_cib.assert_called_once_with(self.mock_runner)
Exemple #21
0
    def test_get_and_push_cib_version_upgrade_needed(self):
        (self.config.runner.cib.load(
            name="load_cib_old",
            filename="cib-empty-2.6.xml").runner.cib.upgrade().runner.cib.load(
                filename="cib-empty-2.8.xml"))
        env = self.env_assist.get_env()
        env.get_cib(Version(2, 8, 0))

        self.env_assist.assert_reports(
            [fixture.info(report_codes.CIB_UPGRADE_SUCCESSFUL)])
Exemple #22
0
 def test_cib_parse_error(self, mock_upgrade, mock_get_cib):
     mock_get_cib.return_value = "not xml"
     assert_raise_library_error(
         lambda: lib.ensure_cib_version(self.mock_runner, self.cib,
                                        Version(2, 3, 5)),
         (Severity.ERROR, report_codes.CIB_UPGRADE_FAILED, {
             "reason": start_tag_error_text(),
         }))
     mock_upgrade.assert_called_once_with(self.mock_runner)
     mock_get_cib.assert_called_once_with(self.mock_runner)
Exemple #23
0
 def test_type_number_old_schema(self):
     self.assert_cib(
         NodeAttrExpr(NODE_ATTR_OP_EQ, "#uname", "12345",
                      NODE_ATTR_TYPE_NUMBER),
         """
             <expression attribute="#uname" id="X-expr" operation="eq"
                 type="number" value="12345"
             />
         """,
         Version(3, 4, 0),
     )
Exemple #24
0
 def test_major(self):
     ver = Version(2)
     self.assert_asterisk((2, None, None), *ver)
     self.assertEqual(ver.major, 2)
     self.assertEqual(ver[0], 2)
     self.assertEqual(ver.minor, None)
     self.assertEqual(ver[1], None)
     self.assertEqual(ver.revision, None)
     self.assertEqual(ver[2], None)
     self.assertEqual(ver.as_full_tuple, (2, 0, 0))
     self.assertEqual(str(ver), "2")
     self.assertEqual(str(ver.normalize()), "2.0.0")
Exemple #25
0
 def test_major_minor_revision(self):
     ver = Version(2, 3, 4)
     self.assert_asterisk((2, 3, 4), *ver)
     self.assertEqual(ver.major, 2)
     self.assertEqual(ver[0], 2)
     self.assertEqual(ver.minor, 3)
     self.assertEqual(ver[1], 3)
     self.assertEqual(ver.revision, 4)
     self.assertEqual(ver[2], 4)
     self.assertEqual(ver.as_full_tuple, (2, 3, 4))
     self.assertEqual(str(ver), "2.3.4")
     self.assertEqual(str(ver.normalize()), "2.3.4")
Exemple #26
0
 def test_upgraded_lower_version(self, mock_upgrade, mock_get_cib):
     mock_get_cib.return_value = etree.tostring(self.cib).decode()
     assert_raise_library_error(
         lambda: lib.ensure_cib_version(self.mock_runner, self.cib,
                                        Version(2, 3, 5)),
         (Severity.ERROR,
          report_codes.CIB_UPGRADE_FAILED_TO_MINIMAL_REQUIRED_VERSION, {
              "required_version": "2.3.5",
              "current_version": "2.3.4"
          }))
     mock_upgrade.assert_called_once_with(self.mock_runner)
     mock_get_cib.assert_called_once_with(self.mock_runner)
Exemple #27
0
 def test_upgraded_lower_version_dont_fail(self, mock_upgrade, mock_get_cib):
     expected_cib = '<cib validate-with="pacemaker-2.3.4"/>'
     mock_get_cib.return_value = expected_cib
     actual_cib, was_upgraded = lib.ensure_cib_version(
         self.mock_runner,
         self.cib,
         Version(2, 3, 5),
         fail_if_version_not_met=False,
     )
     assert_xml_equal(expected_cib, etree.tostring(actual_cib).decode())
     self.assertFalse(was_upgraded)
     mock_upgrade.assert_called_once_with(self.mock_runner)
     mock_get_cib.assert_called_once_with(self.mock_runner)
Exemple #28
0
 def test_everything(self):
     context_element = etree.fromstring("""<context id="a" />""")
     id_provider = IdProvider(context_element)
     nvpair_multi.nvset_append_new(
         context_element,
         id_provider,
         Version(3, 5, 0),
         nvpair_multi.NVSET_META,
         {
             "attr1": "value1",
             "attr-empty": "",
             "attr2": "value2"
         },
         {
             "id": "custom-id",
             "score": "INFINITY",
             "empty-attr": ""
         },
         nvset_rule=BoolExpr(
             BOOL_AND,
             [RscExpr("ocf", "pacemaker", "Dummy"),
              OpExpr("start", None)],
         ),
     )
     assert_xml_equal(
         """
             <context id="a">
                 <meta_attributes id="custom-id" score="INFINITY">
                     <rule id="custom-id-rule"
                         boolean-op="and" score="INFINITY"
                     >
                         <rsc_expression id="custom-id-rule-rsc-ocf-pacemaker-Dummy"
                             class="ocf" provider="pacemaker" type="Dummy"
                         />
                         <op_expression id="custom-id-rule-op-start" 
                             name="start"
                         />
                     </rule>
                     <nvpair id="custom-id-attr1"
                         name="attr1" value="value1"
                     />
                     <nvpair id="custom-id-attr2"
                         name="attr2" value="value2"
                     />
                 </meta_attributes>
             </context>
         """,
         etree_to_str(context_element),
     )
Exemple #29
0
def _get_cib_version(cib, attribute, regexp, none_if_missing=False):
    version = cib.get(attribute)
    if version is None:
        if none_if_missing:
            return None
        raise LibraryError(
            reports.cib_load_error_invalid_format(
                "the attribute '{0}' of the element 'cib' is missing".format(
                    attribute)))
    match = regexp.match(version)
    if not match:
        raise LibraryError(
            reports.cib_load_error_invalid_format(
                ("the attribute '{0}' of the element 'cib' has an invalid"
                 " value: '{1}'").format(attribute, version)))
    return Version(int(match.group("major")), int(match.group("minor")),
                   int(match.group("rev")) if match.group("rev") else None)
Exemple #30
0
    def get_cib(
        self,
        minimal_version: Optional[Version] = None,
        nice_to_have_version: Optional[Version] = None,
    ) -> _Element:
        if self.__loaded_cib_diff_source is not None:
            raise AssertionError("CIB has already been loaded")

        self.__loaded_cib_diff_source = get_cib_xml(self.cmd_runner())
        self.__loaded_cib_to_modify = get_cib(self.__loaded_cib_diff_source)

        if (
            nice_to_have_version is not None
            and minimal_version is not None
            and minimal_version >= nice_to_have_version
        ):
            nice_to_have_version = None

        for version, mandatory in (
            (nice_to_have_version, False),
            (minimal_version, True),
        ):
            if version is not None:
                upgraded_cib, was_upgraded = ensure_cib_version(
                    self.cmd_runner(),
                    self.__loaded_cib_to_modify,
                    version,
                    fail_if_version_not_met=mandatory,
                )
                if was_upgraded:
                    self.__loaded_cib_to_modify = upgraded_cib
                    self.__loaded_cib_diff_source = etree_to_str(upgraded_cib)
                    if not self._cib_upgrade_reported:
                        self.report_processor.report(
                            ReportItem.info(
                                reports.messages.CibUpgradeSuccessful()
                            )
                        )
                    self._cib_upgrade_reported = True

        self.__loaded_cib_diff_source_feature_set = get_cib_crm_feature_set(
            self.__loaded_cib_to_modify, none_if_missing=True
        ) or Version(0, 0, 0)
        return self.__loaded_cib_to_modify