Exemplo n.º 1
0
class TestTagMixin(
        get_assert_pcs_effect_mixin(lambda cib: etree.tostring(
            # pylint:disable=undefined-variable
            etree.parse(cib).findall(".//tags")[0]))):
    def setUp(self):
        # pylint: disable=invalid-name
        self.temp_cib = get_tmp_file("tier1_tag")
        write_file_to_tmpfile(tags_cib, self.temp_cib)
        self.pcs_runner = PcsRunner(self.temp_cib.name)

    def tearDown(self):
        # pylint: disable=invalid-name
        self.temp_cib.close()

    @staticmethod
    def fixture_tags_xml(tag1=None, append=""):
        tag1_default = """
            <tag id="tag1">
                <obj_ref id="x1"/>
                <obj_ref id="x2"/>
                <obj_ref id="x3"/>
            </tag>
        """
        if tag1 is None:
            tag1 = tag1_default
        return f"""
Exemplo n.º 2
0
class RscDefaultsSetCreate(
        get_assert_pcs_effect_mixin(lambda cib: etree.tostring(
            # pylint:disable=undefined-variable
            etree.parse(cib).findall(".//rsc_defaults")[0])),
        DefaultsSetCreateMixin,
        TestCase,
):
    cli_command = ["resource", "defaults"]
    cib_tag = "rsc_defaults"

    @skip_unless_pacemaker_supports_rsc_and_op_rules()
    def test_success_rules_rsc_op(self):
        self.assert_effect(
            self.cli_command +
            "set create id=X meta nam1=val1 rule resource ::Dummy".split(),
            f"""\
            <{self.cib_tag}>
                <meta_attributes id="X">
                    <rule id="X-rule" boolean-op="and" score="INFINITY">
                        <rsc_expression id="X-rule-rsc-Dummy" type="Dummy"/>
                    </rule>
                    <nvpair id="X-nam1" name="nam1" value="val1"/>
                </meta_attributes>
            </{self.cib_tag}>
            """,
            output=(
                "CIB has been upgraded to the latest schema version.\n"
                "Warning: Defaults do not apply to resources which override "
                "them with their own defined values\n"),
        )
Exemplo n.º 3
0
class PropertyUnset(
        TestCase,
        get_assert_pcs_effect_mixin(lambda cib: etree.tostring(
            # pylint:disable=undefined-variable
            etree.parse(cib).findall(".//crm_config")[0])),
):
    def setUp(self):
        self.temp_cib = get_tmp_file("tier1_properties_unset")
        write_file_to_tmpfile(empty_cib, self.temp_cib)
        self.pcs_runner = PcsRunner(self.temp_cib.name)

    def tearDown(self):
        self.temp_cib.close()

    @staticmethod
    def fixture_xml_no_props():
        # must match empty_cib
        return """
            <crm_config />
        """

    @staticmethod
    def fixture_xml_empty_props():
        # must match empty_cib
        return """
            <crm_config>
                <cluster_property_set id="cib-bootstrap-options" />
            </crm_config>
        """

    @staticmethod
    def fixture_xml_with_props():
        # must match empty_cib
        return """
            <crm_config>
                <cluster_property_set id="cib-bootstrap-options">
                    <nvpair id="cib-bootstrap-options-batch-limit"
                        name="batch-limit" value="100"
                    />
                </cluster_property_set>
            </crm_config>
        """

    def test_keep_empty_nvset(self):
        self.assert_effect(
            "property set batch-limit=100".split(),
            self.fixture_xml_with_props(),
        )
        self.assert_effect("property unset batch-limit".split(),
                           self.fixture_xml_empty_props())

    def test_dont_create_nvset_on_removal(self):
        # pcs mimics crm_attribute. So this behaves differently than the rest
        # of pcs - instead of doing nothing it returns an error.
        # Should be changed to be consistent with the rest of pcs.
        self.assert_pcs_fail(
            "property unset batch-limit".split(),
            "Error: can't remove property: 'batch-limit' that doesn't exist\n",
        )
Exemplo n.º 4
0
class OpDefaultsUpdate(
        get_assert_pcs_effect_mixin(lambda cib: etree.tostring(
            # pylint:disable=undefined-variable
            etree.parse(cib).findall(".//op_defaults")[0])),
        DefaultsUpdateMixin,
        TestCase,
):
    cli_command = ["resource", "op", "defaults"]
    prefix = "op"
    cib_tag = "op_defaults"
Exemplo n.º 5
0
class ResourceTest(
    TestCase,
    get_assert_pcs_effect_mixin(get_cib_resources)
):
    empty_cib = rc("cib-empty.xml")
    temp_cib = rc("temp-cib.xml")

    def setUp(self):
        shutil.copy(self.empty_cib, self.temp_cib)
        self.pcs_runner = PcsRunner(self.temp_cib)
Exemplo n.º 6
0
class ResourceTest(TestCase, get_assert_pcs_effect_mixin(get_cib_resources)):
    empty_cib = rc("cib-empty.xml")

    def setUp(self):
        self.temp_cib = get_tmp_file("tier1_test_resource_common")
        write_file_to_tmpfile(self.empty_cib, self.temp_cib)
        self.pcs_runner = PcsRunner(self.temp_cib.name)

    def tearDown(self):
        self.temp_cib.close()
Exemplo n.º 7
0
class RscDefaultsSetUpdate(
        get_assert_pcs_effect_mixin(lambda cib: etree.tostring(
            # pylint:disable=undefined-variable
            etree.parse(cib).findall(".//rsc_defaults")[0])),
        DefaultsSetUpdateMixin,
        TestCase,
):
    cli_command = "resource defaults"
    prefix = "rsc"
    cib_tag = "rsc_defaults"
Exemplo n.º 8
0
class BundleCreateCommon(
        TestCase,
        get_assert_pcs_effect_mixin(lambda cib: etree.tostring(
            # pylint:disable=undefined-variable
            etree.parse(cib).findall(".//resources")[0]))):
    temp_cib = rc("temp-cib.xml")
    empty_cib = None

    def setUp(self):
        shutil.copy(self.empty_cib, self.temp_cib)
        self.pcs_runner = PcsRunner(self.temp_cib)
        self.pcs_runner.mock_settings = get_mock_settings(
            "crm_resource_binary")
Exemplo n.º 9
0
class BundleCreateCommon(
        TestCase,
        get_assert_pcs_effect_mixin(lambda cib: etree.tostring(
            # pylint:disable=undefined-variable
            etree.parse(cib).findall(".//resources")[0])),
):
    empty_cib = rc("cib-empty.xml")

    def setUp(self):
        self.temp_cib = get_tmp_file("tier1_bundle_create")
        write_file_to_tmpfile(self.empty_cib, self.temp_cib)
        self.pcs_runner = PcsRunner(self.temp_cib.name)
        self.pcs_runner.mock_settings = get_mock_settings(
            "crm_resource_binary")

    def tearDown(self):
        self.temp_cib.close()
Exemplo n.º 10
0
class TestGroupMixin(
        get_assert_pcs_effect_mixin(lambda cib: etree.tostring(
            # pylint:disable=undefined-variable
            etree.parse(cib).findall(".//resources")[0])), ):
    empty_cib = rc("cib-empty.xml")

    def setUp(self):
        # pylint: disable=invalid-name
        self.temp_cib = get_tmp_file("tier1_cib_resource_group_ungroup")
        self.pcs_runner = PcsRunner(self.temp_cib.name)
        xml_manip = XmlManipulation.from_file(self.empty_cib)
        xml_manip.append_to_first_tag_name("resources", FIXTURE_AGROUP_XML)
        xml_manip.append_to_first_tag_name(
            "configuration",
            """
            <tags>
                <tag id="T1">
                    <obj_ref id="AGroup"/>
                </tag>
                <tag id="T2">
                    <obj_ref id="AGroup"/>
                </tag>
            </tags>
            """,
        )
        xml_manip.append_to_first_tag_name(
            "constraints",
            """
            <rsc_location id="location-AGroup-rh7-1-INFINITY" node="rh7-1"
                rsc="AGroup" score="INFINITY"/>
            """,
            """
            <rsc_location id="location-T1-rh7-1-INFINITY" node="rh7-1" rsc="T1"
                score="INFINITY"/>
            """,
        )
        write_data_to_tmpfile(str(xml_manip), self.temp_cib)

    def tearDown(self):
        # pylint: disable=invalid-name
        self.temp_cib.close()
Exemplo n.º 11
0
class RscDefaultsSetCreate(
        get_assert_pcs_effect_mixin(lambda cib: etree.tostring(
            # pylint:disable=undefined-variable
            etree.parse(cib).findall(".//rsc_defaults")[0])),
        DefaultsSetCreateMixin,
        TestCase,
):
    cli_command = ["resource", "defaults"]
    cib_tag = "rsc_defaults"

    @skip_unless_pacemaker_supports_rsc_and_op_rules()
    def test_success_rules_rsc_op(self):
        self.assert_effect(
            self.cli_command +
            "set create id=X meta nam1=val1 rule resource ::Dummy".split(),
            f"""\
            <{self.cib_tag}>
                <meta_attributes id="X">
                    <rule id="X-rule" boolean-op="and" score="INFINITY">
                        <rsc_expression id="X-rule-rsc-Dummy" type="Dummy"/>
                    </rule>
                    <nvpair id="X-nam1" name="nam1" value="val1"/>
                </meta_attributes>
            </{self.cib_tag}>
            """,
            output=(
                "CIB has been upgraded to the latest schema version.\n"
                "Warning: Defaults do not apply to resources which override "
                "them with their own defined values\n"),
        )

    def test_node_attr_expressions(self):
        self.assert_pcs_fail(
            self.cli_command + ("set create rule defined attr").split(),
            ("Error: Keywords 'defined', 'not_defined', 'eq', 'ne', 'gte', "
             "'gt', 'lte' and 'lt' cannot be used in a rule in this command\n"
             "Error: Errors have occurred, therefore pcs is unable to continue\n"
             ),
        )
Exemplo n.º 12
0
class NodeAttributeTest(
        TestCase,
        get_assert_pcs_effect_mixin(lambda cib: etree.tostring(
            # pylint:disable=undefined-variable
            etree.parse(cib).findall(".//nodes")[0])),
):
    # pylint: disable=too-many-public-methods
    def setUp(self):
        self.temp_cib = get_tmp_file("tier1_node_attribute")
        write_file_to_tmpfile(empty_cib, self.temp_cib)
        self.pcs_runner = PcsRunner(self.temp_cib.name)

    def tearDown(self):
        self.temp_cib.close()

    def fixture_attrs(self, nodes, attrs=None):
        attrs = {} if attrs is None else attrs
        xml_lines = ["<nodes>"]
        for node_id, node_name in enumerate(nodes, 1):
            xml_lines.extend([
                '<node id="{0}" uname="{1}">'.format(node_id, node_name),
                '<instance_attributes id="nodes-{0}">'.format(node_id),
            ])
            nv = '<nvpair id="nodes-{id}-{name}" name="{name}" value="{val}"/>'
            for name, value in attrs.get(node_name, {}).items():
                xml_lines.append(nv.format(id=node_id, name=name, val=value))
            xml_lines.extend(["</instance_attributes>", "</node>"])
        xml_lines.append("</nodes>")

        utils_usefile_original = utils.usefile
        utils_filename_original = utils.filename
        utils.usefile = True
        utils.filename = self.temp_cib.name
        output, retval = utils.run(
            ["cibadmin", "--modify", "--xml-text", "\n".join(xml_lines)])
        utils.usefile = utils_usefile_original
        utils.filename = utils_filename_original
        assert output == ""
        assert retval == 0

    @staticmethod
    def fixture_xml_no_attrs():
        # must match empty_cib
        return """
            <nodes>
                <node id="1" uname="rh7-1" />
                <node id="2" uname="rh7-2" />
            </nodes>
        """

    @staticmethod
    def fixture_xml_empty_attrs():
        # must match empty_cib
        return """
            <nodes>
                <node id="1" uname="rh7-1">
                    <instance_attributes id="nodes-1" />
                </node>
                <node id="2" uname="rh7-2" />
            </nodes>
        """

    @staticmethod
    def fixture_xml_with_attrs():
        # must match empty_cib
        return """
            <nodes>
                <node id="1" uname="rh7-1">
                    <instance_attributes id="nodes-1">
                        <nvpair id="nodes-1-test" name="test" value="100" />
                    </instance_attributes>
                </node>
                <node id="2" uname="rh7-2" />
            </nodes>
        """

    def test_show_empty(self):
        self.fixture_attrs(["rh7-1", "rh7-2"])
        self.assert_pcs_success("node attribute".split(), "Node Attributes:\n")

    def test_show_nonempty(self):
        self.fixture_attrs(
            ["rh7-1", "rh7-2"],
            {
                "rh7-1": {
                    "IP": "192.168.1.1",
                },
                "rh7-2": {
                    "IP": "192.168.1.2",
                },
            },
        )
        self.assert_pcs_success(
            "node attribute".split(),
            """\
Node Attributes:
 rh7-1: IP=192.168.1.1
 rh7-2: IP=192.168.1.2
""",
        )

    def test_show_multiple_per_node(self):
        self.fixture_attrs(
            ["rh7-1", "rh7-2"],
            {
                "rh7-1": {
                    "IP": "192.168.1.1",
                    "alias": "node1",
                },
                "rh7-2": {
                    "IP": "192.168.1.2",
                    "alias": "node2",
                },
            },
        )
        self.assert_pcs_success(
            "node attribute".split(),
            """\
Node Attributes:
 rh7-1: IP=192.168.1.1 alias=node1
 rh7-2: IP=192.168.1.2 alias=node2
""",
        )

    def test_show_one_node(self):
        self.fixture_attrs(
            ["rh7-1", "rh7-2"],
            {
                "rh7-1": {
                    "IP": "192.168.1.1",
                    "alias": "node1",
                },
                "rh7-2": {
                    "IP": "192.168.1.2",
                    "alias": "node2",
                },
            },
        )
        self.assert_pcs_success(
            "node attribute rh7-1".split(),
            """\
Node Attributes:
 rh7-1: IP=192.168.1.1 alias=node1
""",
        )

    def test_show_missing_node(self):
        self.fixture_attrs(
            ["rh7-1", "rh7-2"],
            {
                "rh7-1": {
                    "IP": "192.168.1.1",
                    "alias": "node1",
                },
                "rh7-2": {
                    "IP": "192.168.1.2",
                    "alias": "node2",
                },
            },
        )
        self.assert_pcs_success(
            "node attribute rh7-3".split(),
            """\
Node Attributes:
""",
        )

    def test_show_name(self):
        self.fixture_attrs(
            ["rh7-1", "rh7-2"],
            {
                "rh7-1": {
                    "IP": "192.168.1.1",
                    "alias": "node1",
                },
                "rh7-2": {
                    "IP": "192.168.1.2",
                    "alias": "node2",
                },
            },
        )
        self.assert_pcs_success(
            "node attribute --name alias".split(),
            """\
Node Attributes:
 rh7-1: alias=node1
 rh7-2: alias=node2
""",
        )

    def test_show_missing_name(self):
        self.fixture_attrs(
            ["rh7-1", "rh7-2"],
            {
                "rh7-1": {
                    "IP": "192.168.1.1",
                    "alias": "node1",
                },
                "rh7-2": {
                    "IP": "192.168.1.2",
                    "alias": "node2",
                },
            },
        )
        self.assert_pcs_success(
            "node attribute --name missing".split(),
            """\
Node Attributes:
""",
        )

    def test_show_node_and_name(self):
        self.fixture_attrs(
            ["rh7-1", "rh7-2"],
            {
                "rh7-1": {
                    "IP": "192.168.1.1",
                    "alias": "node1",
                },
                "rh7-2": {
                    "IP": "192.168.1.2",
                    "alias": "node2",
                },
            },
        )
        self.assert_pcs_success(
            "node attribute --name alias rh7-1".split(),
            """\
Node Attributes:
 rh7-1: alias=node1
""",
        )

    def test_set_new(self):
        self.fixture_attrs(["rh7-1", "rh7-2"])
        self.assert_pcs_success("node attribute rh7-1 IP=192.168.1.1".split())
        self.assert_pcs_success(
            "node attribute".split(),
            """\
Node Attributes:
 rh7-1: IP=192.168.1.1
""",
        )
        self.assert_pcs_success("node attribute rh7-2 IP=192.168.1.2".split())
        self.assert_pcs_success(
            "node attribute".split(),
            """\
Node Attributes:
 rh7-1: IP=192.168.1.1
 rh7-2: IP=192.168.1.2
""",
        )

    def test_set_existing(self):
        self.fixture_attrs(
            ["rh7-1", "rh7-2"],
            {
                "rh7-1": {
                    "IP": "192.168.1.1",
                },
                "rh7-2": {
                    "IP": "192.168.1.2",
                },
            },
        )
        self.assert_pcs_success("node attribute rh7-2 IP=192.168.2.2".split())
        self.assert_pcs_success(
            "node attribute".split(),
            """\
Node Attributes:
 rh7-1: IP=192.168.1.1
 rh7-2: IP=192.168.2.2
""",
        )

    def test_unset(self):
        self.fixture_attrs(
            ["rh7-1", "rh7-2"],
            {
                "rh7-1": {
                    "IP": "192.168.1.1",
                },
                "rh7-2": {
                    "IP": "192.168.1.2",
                },
            },
        )
        self.assert_pcs_success("node attribute rh7-2 IP=".split())
        self.assert_pcs_success(
            "node attribute".split(),
            """\
Node Attributes:
 rh7-1: IP=192.168.1.1
""",
        )

    def test_unset_nonexisting(self):
        self.fixture_attrs(
            ["rh7-1", "rh7-2"],
            {
                "rh7-1": {
                    "IP": "192.168.1.1",
                },
                "rh7-2": {
                    "IP": "192.168.1.2",
                },
            },
        )
        self.assert_pcs_result(
            "node attribute rh7-1 missing=".split(),
            "Error: attribute: 'missing' doesn't exist for node: 'rh7-1'\n",
            returncode=2,
        )

    def test_unset_nonexisting_forced(self):
        self.fixture_attrs(
            ["rh7-1", "rh7-2"],
            {
                "rh7-1": {
                    "IP": "192.168.1.1",
                },
                "rh7-2": {
                    "IP": "192.168.1.2",
                },
            },
        )
        self.assert_pcs_success(
            "node attribute rh7-1 missing= --force".split(), "")

    def test_keep_empty_nvset(self):
        self.assert_effect(
            "node attribute rh7-1 test=100".split(),
            self.fixture_xml_with_attrs(),
        )
        self.assert_effect(
            "node attribute rh7-1 test=".split(),
            self.fixture_xml_empty_attrs(),
        )

    def test_dont_create_nvset_on_removal(self):
        # pcs does not actually do cib editing, it passes it to crm_node. So
        # this behaves differently than the rest of pcs - instead of doing
        # nothing it returns an error.
        # Should be changed to be consistent with the rest of pcs.
        output, retval = pcs(self.temp_cib.name,
                             "node attribute rh7-1 test=".split())
        self.assertEqual(
            output,
            "Error: attribute: 'test' doesn't exist for node: 'rh7-1'\n")
        self.assertEqual(retval, 2)
Exemplo n.º 13
0
class OperationAdd(TestCase, get_assert_pcs_effect_mixin(get_cib_resources)):
    empty_cib = rc("cib-empty.xml")

    def setUp(self):
        self.temp_cib = get_tmp_file("tier1_cib_resource_operation_add")
        self.pcs_runner = PcsRunner(self.temp_cib.name)
        write_data_to_tmpfile(self.fixture_cib_cache(), self.temp_cib)

    def tearDown(self):
        self.temp_cib.close()

    def fixture_cib_cache(self):
        if not hasattr(self.__class__, "cib_cache"):
            self.__class__.cib_cache = self.fixture_cib()
        return self.__class__.cib_cache

    def fixture_cib(self):
        write_file_to_tmpfile(self.empty_cib, self.temp_cib)
        self.assert_pcs_success(
            "resource create --no-default-ops R ocf:heartbeat:Dummy".split())
        # add to cib:
        # <primitive class="ocf" id="R" provider="heartbeat" type="Dummy">
        #   <operations>
        #     <op id="R-monitor-interval-60s" interval="60s"
        #       name="monitor"
        #     />
        #   </operations>
        # </primitive>
        self.temp_cib.seek(0)
        return self.temp_cib.read()

    def test_base_add(self):
        self.assert_effect(
            "resource op add R start interval=20s".split(),
            """<resources>
                <primitive class="ocf" id="R" provider="heartbeat" type="Dummy">
                    <operations>
                        <op id="R-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                        <op id="R-start-interval-20s" interval="20s"
                            name="start"
                        />
                    </operations>
                </primitive>
            </resources>""",
        )

    def test_add_with_OCF_CHECK_LEVEL(self):
        # pylint: disable=invalid-name
        self.assert_effect(
            ("resource op add R start interval=20s OCF_CHECK_LEVEL=1 "
             "description=test-description").split(),
            """<resources>
                <primitive class="ocf" id="R" provider="heartbeat" type="Dummy">
                    <operations>
                        <op id="R-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                        <op description="test-description" name="start"
                            id="R-start-interval-20s" interval="20s"
                        >
                            <instance_attributes
                                id="params-R-start-interval-20s"
                            >
                                <nvpair
                                    id="R-start-interval-20s-OCF_CHECK_LEVEL-1"
                                    name="OCF_CHECK_LEVEL" value="1"
                                />
                            </instance_attributes>
                        </op>
                    </operations>
                </primitive>
            </resources>""",
        )

    def test_can_multiple_operation_add(self):
        self.assert_effect(
            "resource op add R start interval=20s".split(),
            """<resources>
                <primitive class="ocf" id="R" provider="heartbeat" type="Dummy">
                    <operations>
                        <op id="R-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                        <op id="R-start-interval-20s" interval="20s"
                            name="start"
                        />
                    </operations>
                </primitive>
            </resources>""",
        )
        self.assert_effect(
            "resource op add R stop interval=30s".split(),
            """<resources>
                <primitive class="ocf" id="R" provider="heartbeat" type="Dummy">
                    <operations>
                        <op id="R-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                        <op id="R-start-interval-20s" interval="20s"
                            name="start"
                        />
                        <op id="R-stop-interval-30s" interval="30s"
                            name="stop"
                        />
                    </operations>
                </primitive>
            </resources>""",
        )

    def test_id_specified(self):
        self.assert_effect(
            "resource op add R start timeout=30 id=abcd".split(),
            """<resources>
                <primitive class="ocf" id="R" provider="heartbeat" type="Dummy">
                    <operations>
                        <op id="R-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                        <op id="abcd" interval="0s" name="start" timeout="30" />
                    </operations>
                </primitive>
            </resources>""",
        )

    def test_invalid_id(self):
        self.assert_pcs_fail_regardless_of_force(
            "resource op add R start timeout=30 id=ab#cd".split(),
            "Error: invalid operation id 'ab#cd', '#' is not a valid"
            " character for a operation id\n",
        )

    def test_duplicate_id(self):
        self.assert_pcs_fail_regardless_of_force(
            "resource op add R start timeout=30 id=R".split(),
            "Error: id 'R' is already in use, please specify another one\n",
        )

    def test_unknown_option(self):
        self.assert_pcs_fail(
            "resource op add R start timeout=30 requires=quorum".split(),
            ("Error: requires is not a valid op option (use --force to "
             "override)\n"),
        )
Exemplo n.º 14
0
class ManageUnmanage(
        TestCase,
        get_assert_pcs_effect_mixin(lambda cib: etree.tostring(
            # pylint:disable=undefined-variable
            etree.parse(cib).findall(".//resources")[0])),
):
    empty_cib = rc("cib-empty.xml")

    @staticmethod
    def fixture_cib_unmanaged_a(add_empty_meta_b=False):
        empty_meta_b = '<meta_attributes id="B-meta_attributes" />'
        return """
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <meta_attributes id="A-meta_attributes">
                        <nvpair id="A-meta_attributes-is-managed"
                            name="is-managed" value="false"
                        />
                    </meta_attributes>
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
                <primitive class="ocf" id="B" provider="heartbeat" type="Dummy">
                    {empty_meta_b}<operations>
                        <op id="B-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
            </resources>
        """.format(empty_meta_b=(empty_meta_b if add_empty_meta_b else ""))

    def setUp(self):
        self.temp_cib = get_tmp_file("tier1_cib_resource_manage_unmanage")
        write_file_to_tmpfile(self.empty_cib, self.temp_cib)
        self.pcs_runner = PcsRunner(self.temp_cib.name)

    def tearDown(self):
        self.temp_cib.close()

    def fixture_resource(self, name, managed=True, with_monitors=False):
        self.assert_pcs_success([
            "resource",
            "create",
            name,
            "ocf:heartbeat:Dummy",
            "--no-default-ops",
        ])
        if not managed:
            cmd = ["resource", "unmanage", name]
            if with_monitors:
                cmd.append("--monitor")
            self.assert_pcs_success(cmd)

    def fixture_tag(self, name, ids):
        self.assert_pcs_success(["tag", "create", name] + ids)

    def test_unmanage_none(self):
        self.assert_pcs_fail(
            "resource unmanage".split(),
            "Error: You must specify resource(s) to unmanage\n",
        )

    def test_manage_none(self):
        self.assert_pcs_fail(
            "resource manage".split(),
            "Error: You must specify resource(s) to manage\n",
        )

    def test_unmanage_one(self):
        self.fixture_resource("A")
        self.fixture_resource("B")
        self.assert_effect("resource unmanage A".split(),
                           self.fixture_cib_unmanaged_a())

    def test_manage_one(self):
        self.fixture_resource("A", managed=False)
        self.fixture_resource("B", managed=False)
        self.assert_effect(
            "resource manage B".split(),
            self.fixture_cib_unmanaged_a(add_empty_meta_b=True),
        )

    def test_unmanage_monitor(self):
        self.fixture_resource("A")
        self.assert_effect(
            "resource unmanage A --monitor".split(),
            """
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <meta_attributes id="A-meta_attributes">
                        <nvpair id="A-meta_attributes-is-managed"
                            name="is-managed" value="false"
                        />
                    </meta_attributes>
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s" enabled="false"
                        />
                    </operations>
                </primitive>
            </resources>
            """,
        )

    def test_unmanage_monitor_enabled(self):
        self.fixture_resource("A")
        self.assert_effect(
            "resource unmanage A".split(),
            """
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <meta_attributes id="A-meta_attributes">
                        <nvpair id="A-meta_attributes-is-managed"
                            name="is-managed" value="false"
                        />
                    </meta_attributes>
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
            </resources>
            """,
        )

    def test_manage_monitor(self):
        self.fixture_resource("A", managed=True, with_monitors=True)
        self.assert_effect(
            "resource manage A --monitor".split(),
            """
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
            </resources>
            """,
        )

    def test_manage_monitor_disabled(self):
        self.fixture_resource("A", managed=False, with_monitors=True)
        self.assert_effect(
            "resource manage A".split(),
            """
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <meta_attributes id="A-meta_attributes" />
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s" enabled="false"
                        />
                    </operations>
                </primitive>
            </resources>
            """,
            "Warning: Resource 'A' has no enabled monitor operations."
            " Re-run with '--monitor' to enable them.\n",
        )

    def test_unmanage_more(self):
        self.fixture_resource("A")
        self.fixture_resource("B")
        self.fixture_tag("TA", ["A"])
        self.assert_effect(
            "resource unmanage TA B".split(),
            """
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <meta_attributes id="A-meta_attributes">
                        <nvpair id="A-meta_attributes-is-managed"
                            name="is-managed" value="false"
                        />
                    </meta_attributes>
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
                <primitive class="ocf" id="B" provider="heartbeat" type="Dummy">
                    <meta_attributes id="B-meta_attributes">
                        <nvpair id="B-meta_attributes-is-managed"
                            name="is-managed" value="false"
                        />
                    </meta_attributes>
                    <operations>
                        <op id="B-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
            </resources>
            """,
        )

    def test_manage_more(self):
        self.fixture_resource("A", managed=False)
        self.fixture_resource("B", managed=False)
        self.fixture_tag("TA", ["A"])
        self.assert_effect(
            "resource manage TA B".split(),
            """
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <meta_attributes id="A-meta_attributes" />
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
                <primitive class="ocf" id="B" provider="heartbeat" type="Dummy">
                    <meta_attributes id="B-meta_attributes" />
                    <operations>
                        <op id="B-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
            </resources>
            """,
        )

    def test_unmanage_nonexistent(self):
        self.fixture_resource("A")

        self.assert_pcs_fail(
            "resource unmanage A B".split(),
            ("Error: bundle/clone/group/resource/tag 'B' does not exist\n"
             "Error: Errors have occurred, therefore pcs is unable to continue\n"
             ),
        )
        self.assert_resources_xml_in_cib("""
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
            </resources>
            """)

    def test_manage_nonexistent(self):
        self.fixture_resource("A", managed=False)

        self.assert_pcs_fail(
            "resource manage A B".split(),
            ("Error: bundle/clone/group/resource/tag 'B' does not exist\n"
             "Error: Errors have occurred, therefore pcs is unable to continue\n"
             ),
        )
        self.assert_resources_xml_in_cib("""
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <meta_attributes id="A-meta_attributes">
                        <nvpair id="A-meta_attributes-is-managed"
                            name="is-managed" value="false"
                        />
                    </meta_attributes>
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
            </resources>
            """)
Exemplo n.º 15
0
class Clone(
    TestCase,
    get_assert_pcs_effect_mixin(
        lambda cib: etree.tostring(
            # pylint:disable=undefined-variable
            etree.parse(cib).findall(".//resources")[0]
        )
    ),
):
    # pylint: disable=too-many-public-methods
    empty_cib = rc("cib-empty.xml")

    def setUp(self):
        self.temp_cib = get_tmp_file("tier1_cib_resource_clone_unclone_clone")
        self.pcs_runner = PcsRunner(self.temp_cib.name)
        self.set_cib_file(FIXTURE_PRIMITIVE_FOR_CLONE)
        self.stonith_deprecation_warning = (
            "Deprecation Warning: Ability of this command to accept stonith "
            "resources is deprecated and will be removed in a future release.\n"
        )

    def tearDown(self):
        self.temp_cib.close()

    def set_cib_file(self, *xml_string_list):
        xml_manip = XmlManipulation.from_file(self.empty_cib)
        xml_manip.append_to_first_tag_name("resources", *xml_string_list)
        write_data_to_tmpfile(str(xml_manip), self.temp_cib)

    def test_clone(self):
        self.assert_effect(
            "resource clone C".split(),
            fixture_resources_xml(fixture_clone("C-clone", "C")),
        )

    def test_clone_custom_id(self):
        self.assert_effect(
            "resource clone C CustomCloneId".split(),
            fixture_resources_xml(fixture_clone("CustomCloneId", "C")),
        )

    def test_clone_id_increment(self):
        self.set_cib_file(
            fixture_clone("C-clone", "Dummy"),
            FIXTURE_PRIMITIVE_FOR_CLONE,
        )
        self.assert_effect(
            "resource clone C".split(),
            fixture_resources_xml(
                fixture_clone("C-clone", "Dummy"),
                fixture_clone("C-clone-1", "C"),
            ),
        )

    def test_clone_id_is_stonith(self):
        self.set_cib_file(FIXTURE_STONITH_FOR_CLONE)
        self.assert_pcs_fail(
            "resource clone fence-device".split(),
            self.stonith_deprecation_warning + fixture_clone_stonith_msg(),
        )
        self.assert_resources_xml_in_cib(
            fixture_resources_xml(FIXTURE_STONITH_FOR_CLONE)
        )

    def test_clone_id_is_stonith_forced(self):
        self.set_cib_file(FIXTURE_STONITH_FOR_CLONE)
        self.assert_effect(
            "resource clone fence-device --force".split(),
            fixture_resources_xml(FIXTURE_STONITH_CLONE),
            output=self.stonith_deprecation_warning
            + fixture_clone_stonith_msg(forced=True),
        )

    def test_clone_group_with_stonith(self):
        self.set_cib_file(FIXTURE_GROUP_WITH_STONITH)
        self.assert_effect(
            "resource clone Group".split(),
            fixture_resources_xml(FIXTURE_CLONED_GROUP_WITH_STONITH),
        )

    def test_clone_group_with_stonith_forced(self):
        self.set_cib_file(FIXTURE_GROUP_WITH_STONITH)
        self.assert_effect(
            "resource clone Group --force".split(),
            fixture_resources_xml(FIXTURE_CLONED_GROUP_WITH_STONITH),
        )

    def test_promotable_clone(self):
        self.assert_effect(
            "resource promotable C".split(),
            fixture_resources_xml(
                fixture_clone("C-clone", "C", promotable=True)
            ),
        )

    def test_promotable_clone_custom_id(self):
        self.assert_effect(
            "resource promotable C CustomPromotableId".split(),
            fixture_resources_xml(
                fixture_clone("CustomPromotableId", "C", promotable=True)
            ),
        )

    def test_promotable_clone_id_is_stonith(self):
        self.set_cib_file(FIXTURE_STONITH_FOR_CLONE)
        self.assert_pcs_fail(
            "resource promotable fence-device".split(),
            self.stonith_deprecation_warning + fixture_clone_stonith_msg(),
        )
        self.assert_resources_xml_in_cib(
            fixture_resources_xml(FIXTURE_STONITH_FOR_CLONE)
        )

    def test_promotable_clone_id_is_stonith_forced(self):
        self.set_cib_file(FIXTURE_STONITH_FOR_CLONE)
        self.assert_effect(
            "resource promotable fence-device --force".split(),
            fixture_resources_xml(FIXTURE_STONITH_PROMOTABLE),
            output=self.stonith_deprecation_warning
            + fixture_clone_stonith_msg(forced=True),
        )

    def test_promotable_keyword_and_option(self):
        self.assert_pcs_fail(
            "resource promotable C CustomCloneId promotable=false".split(),
            (
                "Error: you cannot specify both promotable option and "
                "promotable keyword\n"
            ),
        )
        self.assert_resources_xml_in_cib(
            fixture_resources_xml(FIXTURE_PRIMITIVE_FOR_CLONE)
        )

    def test_clone_with_options(self):
        self.assert_effect(
            (
                "resource clone C CustomCloneId globally-unique=true meta a=b "
                "c=d"
            ).split(),
            fixture_resources_xml(FIXTURE_CLONE_WITH_OPTIONS),
        )

    def test_group_last_member(self):
        self.set_cib_file(FIXTURE_GROUP_LAST_MEMBER)
        self.assert_effect(
            "resource clone C".split(),
            fixture_resources_xml(fixture_clone("C-clone", "C")),
        )

    def test_nonexistent_resource(self):
        self.assert_pcs_fail(
            "resource clone NonExistentClone".split(),
            "Error: unable to find group or resource: NonExistentClone\n",
        )
        self.assert_resources_xml_in_cib(
            fixture_resources_xml(FIXTURE_PRIMITIVE_FOR_CLONE)
        )

    def test_invalid_clone_id(self):
        self.assert_pcs_fail(
            "resource clone C 1invalid".split(),
            "Error: invalid id '1invalid'\n",
        )
        self.assert_resources_xml_in_cib(
            fixture_resources_xml(FIXTURE_PRIMITIVE_FOR_CLONE)
        )

    def test_clone_id_already_exist(self):
        self.assert_pcs_fail(
            "resource clone C C".split(),
            "Error: id 'C' already exists\n",
        )
        self.assert_resources_xml_in_cib(
            fixture_resources_xml(FIXTURE_PRIMITIVE_FOR_CLONE)
        )

    def test_group_already_cloned(self):
        self.set_cib_file(FIXTURE_CLONED_GROUP)
        self.assert_pcs_fail(
            "resource clone Group".split(),
            "Error: cannot clone a group that has already been cloned\n",
        )
        self.assert_resources_xml_in_cib(
            fixture_resources_xml(FIXTURE_CLONED_GROUP)
        )

    def test_already_a_clone_resource(self):
        self.set_cib_file(FIXTURE_CLONED_GROUP)
        self.assert_pcs_fail(
            "resource clone G1".split(),
            "Error: G1 is already a clone resource\n",
        )
        self.assert_resources_xml_in_cib(
            fixture_resources_xml(FIXTURE_CLONED_GROUP)
        )

    def test_bundle_resource(self):
        self.set_cib_file(FIXTURE_BUNDLE_RESOURCE)
        self.assert_pcs_fail(
            "resource clone Dummy".split(),
            "Error: cannot clone bundle resource\n",
        )
        self.assert_resources_xml_in_cib(
            fixture_resources_xml(FIXTURE_BUNDLE_RESOURCE)
        )
Exemplo n.º 16
0
class Unclone(
    TestCase,
    get_assert_pcs_effect_mixin(
        lambda cib: etree.tostring(
            # pylint:disable=undefined-variable
            etree.parse(cib).findall(".//resources")[0]
        )
    ),
):
    empty_cib = rc("cib-empty.xml")

    def assert_tags_xml(self, expected_xml):
        self.assert_resources_xml_in_cib(
            expected_xml,
            get_cib_part_func=lambda cib: etree.tostring(
                etree.parse(cib).findall(".//tags")[0],
            ),
        )

    def assert_constraint_xml(self, expected_xml):
        self.assert_resources_xml_in_cib(
            expected_xml,
            get_cib_part_func=lambda cib: etree.tostring(
                etree.parse(cib).findall(".//constraints")[0],
            ),
        )

    def setUp(self):
        # pylint: disable=invalid-name
        self.temp_cib = get_tmp_file("tier1_cib_resource_group_ungroup")
        self.pcs_runner = PcsRunner(self.temp_cib.name)
        xml_manip = XmlManipulation.from_file(self.empty_cib)
        xml_manip.append_to_first_tag_name(
            "resources",
            FIXTURE_CLONE,
            FIXTURE_DUMMY,
        )
        xml_manip.append_to_first_tag_name(
            "configuration",
            FIXTURE_TAGS_CONFIG_XML,
        )
        xml_manip.append_to_first_tag_name(
            "constraints",
            """
            <rsc_location id="location-C-clone-rh7-1-INFINITY" node="rh7-1"
                rsc="C-clone" score="INFINITY"/>
            """,
            """
            <rsc_location id="location-TagCloneOnly-rh7-1-INFINITY"
                node="rh7-1" rsc="TagCloneOnly" score="INFINITY"/>
            """,
        )
        write_data_to_tmpfile(str(xml_manip), self.temp_cib)

    def tearDown(self):
        # pylint: disable=invalid-name
        self.temp_cib.close()

    def test_nonexistent_clone(self):
        self.assert_pcs_fail(
            "resource unclone NonExistentClone".split(),
            "Error: could not find resource: NonExistentClone\n",
        )
        self.assert_resources_xml_in_cib(FIXTURE_CLONE_AND_RESOURCE)
        self.assert_tags_xml(FIXTURE_TAGS_CONFIG_XML)
        self.assert_constraint_xml(FIXTURE_CONSTRAINTS_CONFIG_XML)

    def test_not_clone_resource(self):
        self.assert_pcs_fail(
            "resource unclone Dummy".split(),
            "Error: 'Dummy' is not a clone resource\n",
        )
        self.assert_resources_xml_in_cib(FIXTURE_CLONE_AND_RESOURCE)
        self.assert_tags_xml(FIXTURE_TAGS_CONFIG_XML)
        self.assert_constraint_xml(FIXTURE_CONSTRAINTS_CONFIG_XML)

    def test_unclone_clone_id(self):
        self.assert_effect(
            "resource unclone C-clone".split(), FIXTURE_RESOURCES
        )
        self.assert_tags_xml(FIXTURE_TAGS_RESULT_XML)
        self.assert_constraint_xml("<constraints/>")

    def test_unclone_resoruce_id(self):
        self.assert_effect("resource unclone C".split(), FIXTURE_RESOURCES)
        self.assert_tags_xml(FIXTURE_TAGS_RESULT_XML)
        self.assert_constraint_xml("<constraints/>")
Exemplo n.º 17
0
class OpDefaultsSetCreate(
        get_assert_pcs_effect_mixin(lambda cib: etree.tostring(
            # pylint:disable=undefined-variable
            etree.parse(cib).findall(".//op_defaults")[0])),
        DefaultsSetCreateMixin,
        TestCase,
):
    cli_command = ["resource", "op", "defaults"]
    cib_tag = "op_defaults"

    def test_rule_error_messages(self):
        self.assert_pcs_fail(
            self.cli_command +
            ("set create rule defined attr1 or attr2 gte number 12a or "
             "attr3 lt version 3.2.1a or attr4 ne string test or attr5 lt 3 "
             ).split(),
            ("Error: '12a' is not a valid number attribute value, use a "
             "floating-point number\n"
             "Error: '3.2.1a' is not a valid version attribute value, use "
             "a version number (e.g. 1, 1.2, 1.23.45, ...)\n"
             "Error: Errors have occurred, therefore pcs is unable to continue\n"
             ),
        )

    @skip_unless_pacemaker_supports_rsc_and_op_rules()
    def test_success_rules_rsc_op(self):
        self.assert_effect(
            self.cli_command +
            ("-- set create id=X meta nam1=val1 "
             "rule resource ::Dummy and (op start or op stop) and "
             "(defined attr1 or attr2 gte number -1.2 or "
             "attr3 lt version 3.2.1 or attr4 ne string test or attr5 lt 3) "
             ).split(),
            f"""\
            <{self.cib_tag}>
                <meta_attributes id="X">
                    <rule id="X-rule" boolean-op="and" score="INFINITY">
                        <rsc_expression id="X-rule-rsc-Dummy" type="Dummy"/>
                        <rule id="X-rule-rule" boolean-op="or" score="0">
                            <op_expression id="X-rule-rule-op-start"
                                name="start"
                            />
                            <op_expression id="X-rule-rule-op-stop"
                                name="stop"
                            />
                        </rule>
                        <rule id="X-rule-rule-1" boolean-op="or" score="0">
                            <expression id="X-rule-rule-1-expr"
                                operation="defined" attribute="attr1"
                            />
                            <expression id="X-rule-rule-1-expr-1"
                                attribute="attr2" operation="gte"
                                type="number" value="-1.2"
                            />
                            <expression id="X-rule-rule-1-expr-2"
                                attribute="attr3" operation="lt"
                                type="version" value="3.2.1"
                            />
                            <expression id="X-rule-rule-1-expr-3"
                                attribute="attr4" operation="ne"
                                type="string" value="test"
                            />
                            <expression id="X-rule-rule-1-expr-4"
                                attribute="attr5" operation="lt" value="3"
                            />
                        </rule>
                    </rule>
                    <nvpair id="X-nam1" name="nam1" value="val1"/>
                </meta_attributes>
            </{self.cib_tag}>
            """,
            output=(
                "CIB has been upgraded to the latest schema version.\n"
                "Warning: Defaults do not apply to resources which override "
                "them with their own defined values\n"),
        )
Exemplo n.º 18
0
class EnableDisable(
        TestCase,
        get_assert_pcs_effect_mixin(lambda cib: etree.tostring(
            # pylint:disable=undefined-variable
            etree.parse(cib).findall(".//resources")[0])),
):
    empty_cib = rc("cib-empty.xml")

    def setUp(self):
        self.temp_cib = get_tmp_file("tier1_cib_resource_enable_disable")
        write_file_to_tmpfile(self.empty_cib, self.temp_cib)
        self.pcs_runner = PcsRunner(self.temp_cib.name)

    def tearDown(self):
        self.temp_cib.close()

    def fixture_resource(self, name, disabled=False):
        cmd = [
            "resource",
            "create",
            name,
            "ocf:heartbeat:Dummy",
            "--no-default-ops",
        ]
        if disabled:
            cmd.append("--disabled")
        self.assert_pcs_success(cmd)

    def fixture_tag(self, name, ids):
        self.assert_pcs_success(["tag", "create", name] + ids)

    def test_enable_none(self):
        self.assert_pcs_fail(
            "resource enable".split(),
            "Error: You must specify resource(s) to enable\n",
        )

    def test_disable_none(self):
        self.assert_pcs_fail(
            "resource disable".split(),
            "Error: You must specify resource(s) to disable\n",
        )

    def test_enable(self):
        self.fixture_resource("A", disabled=True)
        self.fixture_resource("B", disabled=True)
        self.fixture_tag("TA", ["A"])
        self.assert_effect(
            "resource enable TA B".split(),
            """
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <meta_attributes id="A-meta_attributes"/>
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
                <primitive class="ocf" id="B" provider="heartbeat" type="Dummy">
                    <meta_attributes id="B-meta_attributes"/>
                    <operations>
                        <op id="B-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
            </resources>
            """,
        )

    def test_disable(self):
        self.fixture_resource("A", disabled=False)
        self.fixture_resource("B", disabled=False)
        self.fixture_tag("TA", ["A"])

        self.assert_effect(
            "resource disable B TA".split(),
            """
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <meta_attributes id="A-meta_attributes">
                        <nvpair id="A-meta_attributes-target-role"
                            name="target-role" value="Stopped"
                        />
                    </meta_attributes>
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
                <primitive class="ocf" id="B" provider="heartbeat" type="Dummy">
                    <meta_attributes id="B-meta_attributes">
                        <nvpair id="B-meta_attributes-target-role"
                            name="target-role" value="Stopped"
                        />
                    </meta_attributes>
                    <operations>
                        <op id="B-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
            </resources>
            """,
        )

    def test_enable_nonexistent(self):
        self.fixture_resource("A", disabled=True)

        self.assert_pcs_fail(
            "resource enable A B".split(),
            ("Error: bundle/clone/group/resource/tag 'B' does not exist\n"
             "Error: Errors have occurred, therefore pcs is unable to continue\n"
             ),
        )
        self.assert_resources_xml_in_cib("""
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <meta_attributes id="A-meta_attributes">
                        <nvpair id="A-meta_attributes-target-role"
                            name="target-role" value="Stopped"
                        />
                    </meta_attributes>
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
            </resources>
            """)

    def test_disable_nonexistent(self):
        self.fixture_resource("A", disabled=False)

        self.assert_pcs_fail(
            "resource disable A B".split(),
            ("Error: bundle/clone/group/resource/tag 'B' does not exist\n"
             "Error: Errors have occurred, therefore pcs is unable to continue\n"
             ),
        )
        self.assert_resources_xml_in_cib("""
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
            </resources>
            """)

    def test_resource_disable_non_existing_with_failed_action(self):
        xml = """
            <cib epoch="557" num_updates="122" admin_epoch="0" crm_feature_set="3.0.14" validate-with="pacemaker-2.10" update-origin="rh7-3" update-client="crmd" cib-last-written="Thu Aug 23 16:49:17 2012" have-quorum="0" dc-uuid="2">
              <configuration>
                <crm_config/>
                <nodes>
                </nodes>
                <resources/>
                <constraints/>
              </configuration>
              <status>
                <node_state id="1" uname="rh7-1" in_ccm="true" crmd="online" crm-debug-origin="do_update_resource" join="member" expected="member">
                  <lrm id="1">
                    <lrm_resources>
                      <lrm_resource id="A" type="apache" class="ocf" provider="heartbeat">
                        <lrm_rsc_op id="A_last_0" operation_key="A_monitor_0" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.0.14" transition-key="1:1104:7:817ee250-d179-483a-819e-9be9cb0e06df" transition-magic="0:7;1:1104:7:817ee250-d179-483a-819e-9be9cb0e06df" exit-reason="" on_node="rh7-1" call-id="1079" rc-code="7" op-status="0" interval="0" last-run="1591791198" last-rc-change="1591791198" exec-time="275" queue-time="0" op-digest="f2317cad3d54cec5d7d7aa7d0bf35cf8"/>
                      </lrm_resource>
                    </lrm_resources>
                  </lrm>
                </node_state>
              </status>
            </cib>
            """
        write_data_to_tmpfile(xml, self.temp_cib)
        self.assert_pcs_fail(
            "resource disable A".split(),
            ("Error: bundle/clone/group/resource/tag 'A' does not exist\n"
             "Error: Errors have occurred, therefore pcs is unable to continue\n"
             ),
        )
Exemplo n.º 19
0
class GroupDeleteRemoveUngroupBase(
        get_assert_pcs_effect_mixin(lambda cib: etree.tostring(
            # pylint:disable=undefined-variable
            etree.parse(cib).findall(".//resources")[0])),
        TestGroupMixin,
):
    command = None

    def assert_tags_xml(self, expected_xml):
        self.assert_resources_xml_in_cib(
            expected_xml,
            get_cib_part_func=lambda cib: etree.tostring(
                etree.parse(cib).findall(".//tags")[0], ),
        )

    def assert_constraint_xml(self, expected_xml):
        self.assert_resources_xml_in_cib(
            expected_xml,
            get_cib_part_func=lambda cib: etree.tostring(
                etree.parse(cib).findall(".//constraints")[0], ),
        )

    def test_nonexistent_group(self):
        self.assert_pcs_fail(
            ["resource"] + self.command + ["NonExistentGroup"],
            "Error: Group 'NonExistentGroup' does not exist\n",
        )
        self.assert_resources_xml_in_cib(
            fixture_resources_xml([FIXTURE_AGROUP_XML]), )
        self.assert_tags_xml(FIXTURE_TAGS_CONFIG_XML)
        self.assert_constraint_xml(FIXTURE_CONSTRAINTS_CONFIG_XML)

    def test_not_a_group_id(self):
        self.assert_pcs_fail(
            ["resource"] + self.command + ["A1"],
            "Error: Group 'A1' does not exist\n",
        )
        self.assert_resources_xml_in_cib(
            fixture_resources_xml([FIXTURE_AGROUP_XML]), )
        self.assert_tags_xml(FIXTURE_TAGS_CONFIG_XML)
        self.assert_constraint_xml(FIXTURE_CONSTRAINTS_CONFIG_XML)

    def test_whole_group(self):
        self.assert_effect(
            ["resource"] + self.command + ["AGroup"],
            fixture_resources_xml([
                fixture_primitive_xml("A1"),
                fixture_primitive_xml("A2"),
                fixture_primitive_xml("A3"),
            ], ),
            output=(
                "Removing Constraint - location-TagGroupOnly-rh7-1-INFINITY\n"
                "Removing Constraint - location-AGroup-rh7-1-INFINITY\n"),
        )
        self.assert_tags_xml(FIXTURE_TAGS_RESULT_XML)
        self.assert_constraint_xml("<constraints/>")

    def test_specified_resources(self):
        self.assert_effect(
            ["resource"] + self.command + ["AGroup", "A1", "A3"],
            fixture_resources_xml([
                fixture_group_xml(
                    "AGroup",
                    [
                        fixture_primitive_xml("A2"),
                    ],
                ),
                fixture_primitive_xml("A1"),
                fixture_primitive_xml("A3"),
            ], ),
        )
        self.assert_tags_xml(FIXTURE_TAGS_CONFIG_XML)
        self.assert_constraint_xml(FIXTURE_CONSTRAINTS_CONFIG_XML)

    def test_all_resources(self):
        self.assert_effect(
            ["resource"] + self.command + ["AGroup", "A1", "A2", "A3"],
            fixture_resources_xml([
                fixture_primitive_xml("A1"),
                fixture_primitive_xml("A2"),
                fixture_primitive_xml("A3"),
            ], ),
            output=(
                "Removing Constraint - location-TagGroupOnly-rh7-1-INFINITY\n"
                "Removing Constraint - location-AGroup-rh7-1-INFINITY\n"),
        )
        self.assert_tags_xml(FIXTURE_TAGS_RESULT_XML)
        self.assert_constraint_xml("<constraints/>")

    def test_cloned_group(self):
        self.assert_pcs_success("resource clone AGroup".split())
        self.assert_pcs_fail(
            ["resource"] + self.command + ["AGroup"],
            "Error: Cannot remove all resources from a cloned group\n",
        )
        self.assert_resources_xml_in_cib(
            fixture_resources_xml(
                [fixture_clone_xml("AGroup-clone", FIXTURE_AGROUP_XML)], ))
        self.assert_tags_xml(FIXTURE_TAGS_CONFIG_XML)
        self.assert_constraint_xml(FIXTURE_CLONE_TAG_CONSTRAINTS)

    def test_cloned_group_all_resorces_specified(self):
        self.assert_pcs_success("resource clone AGroup".split())
        self.assert_pcs_fail(
            ["resource"] + self.command + ["AGroup", "A1", "A2", "A3"],
            "Error: Cannot remove all resources from a cloned group\n",
        )
        self.assert_resources_xml_in_cib(
            fixture_resources_xml(
                [fixture_clone_xml("AGroup-clone", FIXTURE_AGROUP_XML)], ))
        self.assert_tags_xml(FIXTURE_TAGS_CONFIG_XML)
        self.assert_constraint_xml(FIXTURE_CLONE_TAG_CONSTRAINTS)

    def test_cloned_group_with_one_resource(self):
        self.assert_pcs_success("resource clone AGroup".split())
        self.assert_pcs_success("resource ungroup AGroup A1 A2".split())
        self.assert_effect(
            ["resource"] + self.command + ["AGroup"],
            fixture_resources_xml([
                fixture_clone_xml(
                    "AGroup-clone",
                    fixture_primitive_xml("A3"),
                ),
                fixture_primitive_xml("A1"),
                fixture_primitive_xml("A2"),
            ], ),
            output=
            "Removing Constraint - location-TagGroupOnly-rh7-1-INFINITY\n",
        )
        self.assert_tags_xml(FIXTURE_TAGS_RESULT_XML)
        self.assert_constraint_xml(FIXTURE_CLONE_CONSTRAINT)
Exemplo n.º 20
0
class Unclone(
        TestCase,
        get_assert_pcs_effect_mixin(lambda cib: etree.tostring(
            # pylint:disable=undefined-variable
            etree.parse(cib).findall(".//resources")[0])),
):
    empty_cib = rc("cib-empty.xml")

    def setUp(self):
        # pylint: disable=invalid-name
        self.temp_cib = get_tmp_file("tier1_cib_resource_group_ungroup")
        self.pcs_runner = PcsRunner(self.temp_cib.name)
        xml_manip = XmlManipulation.from_file(self.empty_cib)
        xml_manip.append_to_first_tag_name(
            "resources",
            FIXTURE_CLONE,
            FIXTURE_DUMMY,
        )
        xml_manip.append_to_first_tag_name(
            "configuration",
            """
            <tags>
                <tag id="T1">
                    <obj_ref id="C-clone"/>
                    <obj_ref id="Dummy"/>
                </tag>
                <tag id="T2">
                    <obj_ref id="C-clone"/>
                </tag>
            </tags>
            """,
        )
        xml_manip.append_to_first_tag_name(
            "constraints",
            """
            <rsc_location id="location-C-clone-rh7-1-INFINITY" node="rh7-1"
                rsc="C-clone" score="INFINITY"/>
            """,
            """
            <rsc_location id="location-T1-rh7-1-INFINITY" node="rh7-1" rsc="T1"
                score="INFINITY"/>
            """,
        )
        write_data_to_tmpfile(str(xml_manip), self.temp_cib)

    def tearDown(self):
        # pylint: disable=invalid-name
        self.temp_cib.close()

    def test_nonexistent_clone(self):
        self.assert_pcs_fail(
            "resource unclone NonExistentClone",
            "Error: could not find resource: NonExistentClone\n",
        )
        self.assert_resources_xml_in_cib(FIXTURE_CLONE_AND_RESOURCE)

    def test_not_clone_resource(self):
        self.assert_pcs_fail(
            "resource unclone Dummy",
            "Error: 'Dummy' is not a clone resource\n",
        )
        self.assert_resources_xml_in_cib(FIXTURE_CLONE_AND_RESOURCE)

    def test_unclone_clone_id(self):
        self.assert_effect("resource unclone C-clone", FIXTURE_RESOURCES)

    def test_unclone_resoruce_id(self):
        self.assert_effect("resource unclone C", FIXTURE_RESOURCES)
Exemplo n.º 21
0
class Move(
        TestCase,
        get_assert_pcs_effect_mixin(lambda cib: etree.tostring(
            # pylint:disable=undefined-variable
            etree.parse(cib).findall(".//resources")[0])),
):
    empty_cib = rc("cib-empty.xml")

    def setUp(self):
        # pylint: disable=invalid-name
        self.temp_cib = get_tmp_file("tier1_cib_resource_move")
        self.pcs_runner = PcsRunner(self.temp_cib.name)
        xml_manip = XmlManipulation.from_file(self.empty_cib)
        xml_manip.append_to_first_tag_name("resources", fixture_primitive)
        xml_manip.append_to_first_tag_name(
            "constraints",
            *fixture_constraints,
        )
        xml_manip.append_to_first_tag_name(
            "nodes",
            *fixture_nodes,
        )
        write_data_to_tmpfile(str(xml_manip), self.temp_cib)

    def tearDown(self):
        # pylint: disable=invalid-name
        self.temp_cib.close()

    def test_move_to_node_with_existing_ban_constraints(self):
        self.assert_effect(
            "resource move-with-constraint A node1".split(),
            f"<resources>{fixture_primitive}</resources>",
            output=(
                "Warning: A move constraint has been created and the resource "
                "'A' may or may not move depending on other configuration\n"),
        )
        self.assert_resources_xml_in_cib(
            """
            <constraints>
                <rsc_location id="location-A-node1--INFINITY" rsc="A"
                    node="node1" score="-INFINITY"
                />
                <rsc_location id="cli-prefer-A" rsc="A" role="Started"
                    node="node1" score="INFINITY"
                />
            </constraints>
            """,
            get_cib_part_func=lambda cib: etree.tostring(
                etree.parse(cib).findall(".//constraints")[0]),
        )

    def test_move_stopped_with_existing_constraints(self):
        self.assert_pcs_fail(
            "resource move-with-constraint A".split(),
            ("Error: You must specify a node when moving/banning a stopped "
             "resource\n"),
        )

    def test_nonexistent_resource(self):
        self.assert_pcs_fail(
            "resource move-with-constraint NonExistent".split(),
            ("Error: bundle/clone/group/resource 'NonExistent' does not "
             "exist\n"
             "Error: Errors have occurred, therefore pcs is unable to "
             "continue\n"),
        )

    def test_wait_not_supported_with_file(self):
        self.assert_pcs_fail(
            "resource move-with-constraint A --wait".split(),
            "Error: Cannot use '-f' together with '--wait'\n",
        )

    def test_move_autoclean_not_supported_with_file(self):
        self.assert_pcs_fail(
            "resource move A".split(),
            "Error: Specified option '-f' is not supported in this command\n",
        )
Exemplo n.º 22
0
class NodeUtilizationSet(
        TestCase,
        get_assert_pcs_effect_mixin(lambda cib: etree.tostring(
            # pylint:disable=undefined-variable
            etree.parse(cib).findall(".//nodes")[0])),
):
    def setUp(self):
        self.temp_cib = get_tmp_file("tier1_node_utilization_set")
        write_file_to_tmpfile(empty_cib, self.temp_cib)
        self.pcs_runner = PcsRunner(self.temp_cib.name)

    def tearDown(self):
        self.temp_cib.close()

    @staticmethod
    def fixture_xml_no_utilization():
        # must match empty_cib
        return """
            <nodes>
                <node id="1" uname="rh7-1" />
                <node id="2" uname="rh7-2" />
            </nodes>
        """

    @staticmethod
    def fixture_xml_empty_utilization():
        # must match empty_cib
        return """
            <nodes>
                <node id="1" uname="rh7-1">
                    <utilization id="nodes-1-utilization" />
                </node>
                <node id="2" uname="rh7-2" />
            </nodes>
        """

    @staticmethod
    def fixture_xml_with_utilization():
        # must match empty_cib
        return """
            <nodes>
                <node id="1" uname="rh7-1">
                    <utilization id="nodes-1-utilization">
                        <nvpair id="nodes-1-utilization-test" name="test"
                            value="100"
                        />
                    </utilization>
                </node>
                <node id="2" uname="rh7-2" />
            </nodes>
        """

    def test_node_utilization_set(self):
        output, returnVal = pcs(self.temp_cib.name,
                                "node utilization rh7-1 test1=10".split())
        ac("", output)
        self.assertEqual(0, returnVal)

        output, returnVal = pcs(self.temp_cib.name,
                                "node utilization rh7-2".split())
        expected_out = """\
Node Utilization:
"""
        ac(expected_out, output)
        self.assertEqual(0, returnVal)

        output, returnVal = pcs(self.temp_cib.name,
                                "node utilization rh7-1".split())
        expected_out = """\
Node Utilization:
 rh7-1: test1=10
"""
        ac(expected_out, output)
        self.assertEqual(0, returnVal)

        output, returnVal = pcs(
            self.temp_cib.name,
            "node utilization rh7-1 test1=-10 test4=1234".split(),
        )
        ac("", output)
        self.assertEqual(0, returnVal)
        output, returnVal = pcs(self.temp_cib.name,
                                "node utilization rh7-1".split())
        expected_out = """\
Node Utilization:
 rh7-1: test1=-10 test4=1234
"""
        ac(expected_out, output)
        self.assertEqual(0, returnVal)

        output, returnVal = pcs(
            self.temp_cib.name,
            "node utilization rh7-2 test2=321 empty=".split(),
        )
        ac("", output)
        self.assertEqual(0, returnVal)
        output, returnVal = pcs(self.temp_cib.name,
                                "node utilization rh7-2".split())
        expected_out = """\
Node Utilization:
 rh7-2: test2=321
"""
        ac(expected_out, output)
        self.assertEqual(0, returnVal)

        output, returnVal = pcs(self.temp_cib.name, "node utilization".split())
        expected_out = """\
Node Utilization:
 rh7-1: test1=-10 test4=1234
 rh7-2: test2=321
"""
        ac(expected_out, output)
        self.assertEqual(0, returnVal)

        output, returnVal = pcs(self.temp_cib.name,
                                "node utilization rh7-2 test1=-20".split())
        ac("", output)
        self.assertEqual(0, returnVal)

        output, returnVal = pcs(self.temp_cib.name,
                                "node utilization --name test1".split())
        expected_out = """\
Node Utilization:
 rh7-1: test1=-10
 rh7-2: test1=-20
"""
        ac(expected_out, output)
        self.assertEqual(0, returnVal)

        output, returnVal = pcs(
            self.temp_cib.name,
            "node utilization --name test1 rh7-2".split(),
        )
        expected_out = """\
Node Utilization:
 rh7-2: test1=-20
"""
        ac(expected_out, output)
        self.assertEqual(0, returnVal)

    def test_refuse_non_option_attribute_parameter_among_options(self):
        self.assert_pcs_fail(
            "node utilization rh7-1 net".split(),
            "Error: missing value of 'net' option\n",
        )

    def test_refuse_option_without_key(self):
        self.assert_pcs_fail(
            "node utilization rh7-1 =1".split(),
            "Error: missing key in '=1' option\n",
        )

    def test_refuse_unknown_node(self):
        self.assert_pcs_fail(
            "node utilization rh7-0 test=10".split(),
            "Error: Unable to find a node: rh7-0\n",
        )

    def test_refuse_value_not_int(self):
        self.assert_pcs_fail(
            "node utilization rh7-1 test1=10 test=int".split(),
            "Error: Value of utilization attribute must be integer: "
            "'test=int'\n",
        )

    def test_keep_empty_nvset(self):
        self.assert_effect(
            "node utilization rh7-1 test=100".split(),
            self.fixture_xml_with_utilization(),
        )
        self.assert_effect(
            "node utilization rh7-1 test=".split(),
            self.fixture_xml_empty_utilization(),
        )

    def test_dont_create_nvset_on_removal(self):
        self.assert_effect(
            "node utilization rh7-1 test=".split(),
            self.fixture_xml_no_utilization(),
        )
Exemplo n.º 23
0
class ManageUnmanage(
        TestCase,
        get_assert_pcs_effect_mixin(lambda cib: etree.tostring(
            # pylint:disable=undefined-variable
            etree.parse(cib).findall(".//resources")[0]))):
    empty_cib = rc("cib-empty.xml")
    temp_cib = rc("temp-cib.xml")

    @staticmethod
    def fixture_cib_unmanaged_a(add_empty_meta_b=False):
        empty_meta_b = '<meta_attributes id="B-meta_attributes" />'
        return """
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <meta_attributes id="A-meta_attributes">
                        <nvpair id="A-meta_attributes-is-managed"
                            name="is-managed" value="false"
                        />
                    </meta_attributes>
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
                <primitive class="ocf" id="B" provider="heartbeat" type="Dummy">
                    {empty_meta_b}<operations>
                        <op id="B-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
            </resources>
        """.format(empty_meta_b=(empty_meta_b if add_empty_meta_b else ""))

    def setUp(self):
        shutil.copy(self.empty_cib, self.temp_cib)
        self.pcs_runner = PcsRunner(self.temp_cib)

    def fixture_resource(self, name, managed=True, with_monitors=False):
        self.assert_pcs_success(
            "resource create {0} ocf:heartbeat:Dummy --no-default-ops".format(
                name))
        if not managed:
            self.assert_pcs_success("resource unmanage {0} {1}".format(
                name, "--monitor" if with_monitors else ""))

    def test_unmanage_none(self):
        self.assert_pcs_fail(
            "resource unmanage",
            "Error: You must specify resource(s) to unmanage\n")

    def test_manage_none(self):
        self.assert_pcs_fail(
            "resource manage",
            "Error: You must specify resource(s) to manage\n")

    def test_unmanage_one(self):
        self.fixture_resource("A")
        self.fixture_resource("B")
        self.assert_effect("resource unmanage A",
                           self.fixture_cib_unmanaged_a())

    def test_manage_one(self):
        self.fixture_resource("A", managed=False)
        self.fixture_resource("B", managed=False)
        self.assert_effect("resource manage B",
                           self.fixture_cib_unmanaged_a(add_empty_meta_b=True))

    def test_unmanage_monitor(self):
        self.fixture_resource("A")
        self.assert_effect(
            "resource unmanage A --monitor", """
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <meta_attributes id="A-meta_attributes">
                        <nvpair id="A-meta_attributes-is-managed"
                            name="is-managed" value="false"
                        />
                    </meta_attributes>
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s" enabled="false"
                        />
                    </operations>
                </primitive>
            </resources>
            """)

    def test_unmanage_monitor_enabled(self):
        self.fixture_resource("A")
        self.assert_effect(
            "resource unmanage A", """
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <meta_attributes id="A-meta_attributes">
                        <nvpair id="A-meta_attributes-is-managed"
                            name="is-managed" value="false"
                        />
                    </meta_attributes>
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
            </resources>
            """)

    def test_manage_monitor(self):
        self.fixture_resource("A", managed=True, with_monitors=True)
        self.assert_effect(
            "resource manage A --monitor", """
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
            </resources>
            """)

    def test_manage_monitor_disabled(self):
        self.fixture_resource("A", managed=False, with_monitors=True)
        self.assert_effect(
            "resource manage A", """
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <meta_attributes id="A-meta_attributes" />
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s" enabled="false"
                        />
                    </operations>
                </primitive>
            </resources>
            """, "Warning: Resource 'A' has no enabled monitor operations."
            " Re-run with '--monitor' to enable them.\n")

    def test_unmanage_more(self):
        self.fixture_resource("A")
        self.fixture_resource("B")
        self.assert_effect(
            "resource unmanage A B", """
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <meta_attributes id="A-meta_attributes">
                        <nvpair id="A-meta_attributes-is-managed"
                            name="is-managed" value="false"
                        />
                    </meta_attributes>
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
                <primitive class="ocf" id="B" provider="heartbeat" type="Dummy">
                    <meta_attributes id="B-meta_attributes">
                        <nvpair id="B-meta_attributes-is-managed"
                            name="is-managed" value="false"
                        />
                    </meta_attributes>
                    <operations>
                        <op id="B-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
            </resources>
            """)

    def test_manage_more(self):
        self.fixture_resource("A", managed=False)
        self.fixture_resource("B", managed=False)
        self.assert_effect(
            "resource manage A B", """
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <meta_attributes id="A-meta_attributes" />
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
                <primitive class="ocf" id="B" provider="heartbeat" type="Dummy">
                    <meta_attributes id="B-meta_attributes" />
                    <operations>
                        <op id="B-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
            </resources>
            """)

    def test_unmanage_nonexistent(self):
        self.fixture_resource("A")

        self.assert_pcs_fail(
            "resource unmanage A B",
            "Error: bundle/clone/group/resource 'B' does not exist\n")
        self.assert_resources_xml_in_cib("""
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
            </resources>
            """)

    def test_manage_nonexistent(self):
        self.fixture_resource("A", managed=False)

        self.assert_pcs_fail(
            "resource manage A B",
            "Error: bundle/clone/group/resource 'B' does not exist\n")
        self.assert_resources_xml_in_cib("""
            <resources>
                <primitive class="ocf" id="A" provider="heartbeat" type="Dummy">
                    <meta_attributes id="A-meta_attributes">
                        <nvpair id="A-meta_attributes-is-managed"
                            name="is-managed" value="false"
                        />
                    </meta_attributes>
                    <operations>
                        <op id="A-monitor-interval-10s" interval="10s"
                            name="monitor" timeout="20s"
                        />
                    </operations>
                </primitive>
            </resources>
            """)