Exemplo n.º 1
0
class CommunicatorLoggerTest(TestCase):
    def setUp(self):
        self.logger = mock.MagicMock(spec_set=logging.Logger)
        self.reporter = MockLibraryReportProcessor()
        self.com_logger = lib.LibCommunicatorLogger(self.logger, self.reporter)

    def test_log_request_start(self):
        request = fixture_request()
        self.com_logger.log_request_start(request)
        self.reporter.assert_reports(
            fixture_report_item_list_send(request.url, request.data)
        )
        self.assertEqual(
            [fixture_logger_call_send(request.url, request.data)],
            self.logger.mock_calls
        )

    def test_log_response_connected(self):
        expected_code = 200
        expected_data = "data"
        expected_debug_data = "* text\n>> data out\n"
        response = Response.connection_successful(
            MockCurlSimple(
                info={pycurl.RESPONSE_CODE: expected_code},
                output=expected_data.encode("utf-8"),
                debug_output=expected_debug_data.encode("utf-8"),
                request=fixture_request(),
            )
        )
        self.com_logger.log_response(response)
        self.reporter.assert_reports(
            fixture_report_item_list_on_success(
                response.request.url,
                expected_code,
                expected_data,
                expected_debug_data
            )
        )
        logger_calls = fixture_logger_calls_on_success(
            response.request.url,
            expected_code,
            expected_data,
            expected_debug_data
        )
        self.assertEqual(logger_calls, self.logger.mock_calls)

    @mock.patch("pcs.lib.node_communication.is_proxy_set")
    def test_log_response_not_connected(self, mock_proxy):
        mock_proxy.return_value = False
        expected_debug_data = "* text\n>> data out\n"
        error_msg = "error"
        response = Response.connection_failure(
            MockCurlSimple(
                debug_output=expected_debug_data.encode("utf-8"),
                request=fixture_request(),
            ),
            pycurl.E_HTTP_POST_ERROR,
            error_msg,
        )
        self.com_logger.log_response(response)
        self.reporter.assert_reports(
            fixture_report_item_list_not_connected(
                response.request.host_label, error_msg
            )
            +
            fixture_report_item_list_debug(
                response.request.url, expected_debug_data
            )
        )
        logger_calls = [
            fixture_logger_call_not_connected(
                response.request.host_label, error_msg
            ),
            fixture_logger_call_debug_data(
                response.request.url, expected_debug_data
            )
        ]
        self.assertEqual(logger_calls, self.logger.mock_calls)

    @mock.patch("pcs.lib.node_communication.is_proxy_set")
    def test_log_response_not_connected_with_proxy(self, mock_proxy):
        mock_proxy.return_value = True
        expected_debug_data = "* text\n>> data out\n"
        error_msg = "error"
        response = Response.connection_failure(
            MockCurlSimple(
                debug_output=expected_debug_data.encode("utf-8"),
                request=fixture_request(),
            ),
            pycurl.E_HTTP_POST_ERROR,
            error_msg,
        )
        self.com_logger.log_response(response)
        self.reporter.assert_reports(
            fixture_report_item_list_not_connected(
                response.request.host_label, error_msg
            )
            +
            fixture_report_item_list_proxy_set(
                response.request.host_label, response.request.host_label
            )
            +
            fixture_report_item_list_debug(
                response.request.url, expected_debug_data
            )
        )
        logger_calls = [
            fixture_logger_call_not_connected(
                response.request.host_label, error_msg
            ),
            fixture_logger_call_proxy_set(),
            fixture_logger_call_debug_data(
                response.request.url, expected_debug_data
            )
        ]
        self.assertEqual(logger_calls, self.logger.mock_calls)

    def test_log_retry(self):
        prev_addr = "addr"
        prev_port = 2225
        prev_host = Destination(prev_addr, prev_port)
        response = Response.connection_failure(
            MockCurlSimple(request=fixture_request()),
            pycurl.E_HTTP_POST_ERROR,
            "e",
        )
        self.com_logger.log_retry(response, prev_host)
        self.reporter.assert_reports([(
            severity.WARNING,
            report_codes.NODE_COMMUNICATION_RETRYING,
            {
                "node": response.request.host_label,
                "failed_address": prev_addr,
                "failed_port": prev_port,
                "next_address": response.request.dest.addr,
                "next_port": settings.pcsd_default_port,
                "request": response.request.url,
            },
            None
        )])
        logger_call = mock.call.warning(
            (
                "Unable to connect to '{label}' via address '{old_addr}' and "
                "port '{old_port}'. Retrying request '{req}' via address "
                "'{new_addr}' and port '{new_port}'"
            ).format(
                label=response.request.host_label,
                old_addr=prev_addr,
                old_port=prev_port,
                new_addr=response.request.dest.addr,
                new_port=settings.pcsd_default_port,
                req=response.request.url,
            )
        )
        self.assertEqual([logger_call], self.logger.mock_calls)

    def test_log_no_more_addresses(self):
        response = Response.connection_failure(
            MockCurlSimple(request=fixture_request()),
            pycurl.E_HTTP_POST_ERROR,
            "e"
        )
        self.com_logger.log_no_more_addresses(response)
        self.reporter.assert_reports([(
            severity.WARNING,
            report_codes.NODE_COMMUNICATION_NO_MORE_ADDRESSES,
            {
                "node": response.request.host_label,
                "request": response.request.url,
            },
            None
        )])
        logger_call = mock.call.warning(
            "No more addresses for node {label} to run '{req}'".format(
                label=response.request.host_label,
                req=response.request.url,
            )
        )
        self.assertEqual([logger_call], self.logger.mock_calls)
Exemplo n.º 2
0
class PrepareOptionsPlainTest(TestCase):
    def setUp(self):
        self.cib = "cib"
        self.report_processor = MockLibraryReportProcessor(debug=False)
        self.prepare = partial(ticket.prepare_options_plain, self.cib,
                               self.report_processor)

    @mock.patch("pcs.lib.cib.constraint.ticket._create_id")
    def test_prepare_correct_options(self, mock_create_id, _):
        mock_create_id.return_value = "generated_id"
        role = str(const.PCMK_ROLE_PROMOTED_LEGACY).lower()
        self.assertEqual(
            {
                "id": "generated_id",
                "loss-policy": "fence",
                "rsc": "resourceA",
                "rsc-role": const.PCMK_ROLE_PROMOTED_PRIMARY,
                "ticket": "ticket_key",
            },
            self.prepare(
                {
                    "loss-policy": "fence",
                    "rsc-role": role
                },
                "ticket_key",
                "resourceA",
            ),
        )
        self.report_processor.assert_reports([
            fixture.warn(
                report_codes.DEPRECATED_OPTION_VALUE,
                option_name="role",
                deprecated_value=role,
                replaced_by=const.PCMK_ROLE_PROMOTED,
            )
        ])

    @mock.patch("pcs.lib.cib.constraint.ticket._create_id")
    def test_does_not_include_role_if_not_presented(self, mock_create_id, _):
        mock_create_id.return_value = "generated_id"
        self.assertEqual(
            {
                "id": "generated_id",
                "loss-policy": "fence",
                "rsc": "resourceA",
                "ticket": "ticket_key",
            },
            self.prepare(
                {
                    "loss-policy": "fence",
                    "rsc-role": ""
                },
                "ticket_key",
                "resourceA",
            ),
        )
        self.report_processor.assert_reports([])

    def test_refuse_unknown_attributes(self, _):
        assert_raise_library_error(
            lambda: self.prepare(
                {
                    "unknown": "nonsense",
                    "rsc-role": "master"
                },
                "ticket_key",
                "resourceA",
            ),
            (
                severities.ERROR,
                report_codes.INVALID_OPTIONS,
                {
                    "option_names": ["unknown"],
                    "option_type": None,
                    "allowed": [
                        "id",
                        "loss-policy",
                        "rsc",
                        "rsc-role",
                        "ticket",
                    ],
                    "allowed_patterns": [],
                },
            ),
        )

    def test_refuse_bad_role(self, _):
        assert_raise_library_error(
            lambda: self.prepare({
                "id": "id",
                "rsc-role": "bad_role"
            }, "ticket_key", "resourceA"), )
        self.report_processor.assert_reports([
            fixture.error(
                report_codes.INVALID_OPTION_VALUE,
                allowed_values=const.PCMK_ROLES,
                option_value="bad_role",
                option_name="role",
                cannot_be_empty=False,
                forbidden_characters=None,
            ),
        ])

    def test_refuse_missing_ticket(self, _):
        role = str(const.PCMK_ROLE_UNPROMOTED_LEGACY).lower()
        assert_raise_library_error(
            lambda: self.prepare({
                "id": "id",
                "rsc-role": role
            }, "", "resourceA"), )
        self.report_processor.assert_reports([
            fixture.error(
                report_codes.REQUIRED_OPTIONS_ARE_MISSING,
                option_names=["ticket"],
                option_type=None,
            ),
            fixture.warn(
                report_codes.DEPRECATED_OPTION_VALUE,
                option_name="role",
                deprecated_value=role,
                replaced_by=const.PCMK_ROLE_UNPROMOTED,
            ),
        ])

    def test_refuse_missing_resource_id(self, _):
        assert_raise_library_error(
            lambda: self.prepare(
                {
                    "id": "id",
                    "rsc-role": const.PCMK_ROLE_PROMOTED
                },
                "ticket_key",
                "",
            ), )
        self.report_processor.assert_reports([
            fixture.error(
                report_codes.REQUIRED_OPTIONS_ARE_MISSING,
                option_names=["rsc"],
                option_type=None,
            ),
        ])

    def test_refuse_unknown_lost_policy(self, mock_check_new_id_applicable):
        # pylint: disable=unused-argument
        assert_raise_library_error(
            lambda: self.prepare(
                {
                    "loss-policy": "unknown",
                    "ticket": "T",
                    "id": "id"
                },
                "ticket_key",
                "resourceA",
            ), )
        self.report_processor.assert_reports([
            fixture.error(
                report_codes.INVALID_OPTION_VALUE,
                allowed_values=("fence", "stop", "freeze", "demote"),
                option_value="unknown",
                option_name="loss-policy",
                cannot_be_empty=False,
                forbidden_characters=None,
            ),
        ])

    @mock.patch("pcs.lib.cib.constraint.ticket._create_id")
    def test_complete_id(self, mock_create_id, _):
        mock_create_id.return_value = "generated_id"
        options = {
            "loss-policy": "freeze",
            "ticket": "T",
            "rsc-role": const.PCMK_ROLE_PROMOTED,
        }
        ticket_key = "ticket_key"
        resource_id = "resourceA"
        expected_options = options.copy()
        expected_options.update({
            "id": "generated_id",
            "rsc": resource_id,
            "rsc-role": const.PCMK_ROLE_PROMOTED_PRIMARY,
            "ticket": ticket_key,
        })
        self.assertEqual(
            expected_options,
            self.prepare(
                options,
                ticket_key,
                resource_id,
            ),
        )
        mock_create_id.assert_called_once_with(
            self.cib,
            ticket_key,
            resource_id,
            const.PCMK_ROLE_PROMOTED_PRIMARY,
        )
Exemplo n.º 3
0
class NodeTargetLibFactory(TestCase):
    def setUp(self):
        self.known_hosts = {
            "host{}".format(i): PcsKnownHost(
                "host{}".format(i),
                "token{}".format(i),
                [
                    Destination(
                        "addr{}{}".format(i, j), "port{}{}".format(i, j)
                    ) for j in range(2)
                ]
            ) for i in range(2)
        }
        self.report_processor = MockLibraryReportProcessor()
        self.factory = lib.NodeTargetLibFactory(
            self.known_hosts, self.report_processor
        )

    def assert_equal_known_host_target(self, known_host, target):
        self.assertEqual(known_host.name, target.label)
        self.assertEqual(known_host.token, target.token)
        self.assertEqual(known_host.dest_list, target.dest_list)

    def test_one_host(self):
        host = "host0"
        self.assert_equal_known_host_target(
            self.known_hosts[host],
            self.factory.get_target_list([host])[0]
        )
        self.report_processor.assert_reports([])

    def test_multiple_hosts(self):
        host_list = ["host0", "host1"]
        target_list = self.factory.get_target_list(host_list)
        for i, host in enumerate(host_list):
            self.assert_equal_known_host_target(
                self.known_hosts[host], target_list[i]
            )
        self.report_processor.assert_reports([])

    def test_multiple_not_found(self):
        host = "host0"
        unknown_hosts = ["node0", "node1"]
        report = fixture.error(
            report_codes.HOST_NOT_FOUND,
            force_code=report_codes.SKIP_OFFLINE_NODES,
            host_list=unknown_hosts
        )
        assert_raise_library_error(
            lambda: self.factory.get_target_list([host] + unknown_hosts),
            report
        )
        self.report_processor.assert_reports([report])

    def test_multiple_skip_not_allowed(self):
        host = "host0"
        unknown_hosts = ["node0", "node1"]
        report = fixture.error(
            report_codes.HOST_NOT_FOUND,
            host_list=unknown_hosts
        )
        assert_raise_library_error(
            lambda: self.factory.get_target_list(
                [host] + unknown_hosts, allow_skip=False,
            ),
            report
        )
        self.report_processor.assert_reports([report])

    def test_multiple_not_found_skip_offline(self):
        host = "host0"
        unknown_hosts = ["node0", "node1"]
        target_list = self.factory.get_target_list(
            [host] + unknown_hosts, skip_non_existing=True
        )
        self.assert_equal_known_host_target(
            self.known_hosts[host], target_list[0]
        )
        self.report_processor.assert_reports([
            fixture.warn(report_codes.HOST_NOT_FOUND, host_list=unknown_hosts)
        ])

    def test_no_host_found(self):
        unknown_hosts = ["node0", "node1"]
        report_list = [
            fixture.error(
                report_codes.HOST_NOT_FOUND,
                force_code=report_codes.SKIP_OFFLINE_NODES,
                host_list=unknown_hosts
            ),
            fixture.error(report_codes.NONE_HOST_FOUND)
        ]
        assert_raise_library_error(
            lambda: self.factory.get_target_list(unknown_hosts),
            *report_list
        )
        self.report_processor.assert_reports(report_list)

    def test_no_host_found_skip_offline(self):
        unknown_hosts = ["node0", "node1"]
        report_list = [
            fixture.warn(report_codes.HOST_NOT_FOUND, host_list=unknown_hosts),
            fixture.error(report_codes.NONE_HOST_FOUND)
        ]
        assert_raise_library_error(
            lambda: self.factory.get_target_list(
                unknown_hosts, skip_non_existing=True
            ),
            report_list[1]
        )
        self.report_processor.assert_reports(report_list)

    def test_empty_host_list(self):
        self.assertEqual([], self.factory.get_target_list([]))
        self.report_processor.assert_reports([])
Exemplo n.º 4
0
class PrepareSetTest(TestCase):
    def setUp(self):
        self.report_processor = MockLibraryReportProcessor(debug=False)

    def test_return_corrected_resource_set(self):
        find_valid_id = mock.Mock()
        find_valid_id.side_effect = lambda id: {"A": "AA", "B": "BB"}[id]
        self.assertEqual(
            {
                "ids": ["AA", "BB"],
                "options": {
                    "sequential": "true"
                }
            },
            resource_set.prepare_set(
                find_valid_id,
                {
                    "ids": ["A", "B"],
                    "options": {
                        "sequential": "true"
                    }
                },
                self.report_processor,
            ),
        )
        self.report_processor.assert_reports([])

    def test_refuse_invalid_attribute_name(self):
        assert_raise_library_error(
            lambda: resource_set.prepare_set(
                mock.Mock(),
                {
                    "ids": ["A", "B"],
                    "options": {
                        "invalid_name": "true"
                    }
                },
                self.report_processor,
            ), )
        self.report_processor.assert_reports([
            fixture.error(
                reports.codes.INVALID_OPTIONS,
                option_names=["invalid_name"],
                option_type="set",
                allowed=["action", "require-all", "role", "sequential"],
                allowed_patterns=[],
            ),
        ])

    def test_refuse_invalid_attribute_value(self):
        assert_raise_library_error(
            lambda: resource_set.prepare_set(
                mock.Mock(),
                {
                    "ids": ["A", "B"],
                    "options": {
                        "role": "invalid"
                    }
                },
                self.report_processor,
            ), )
        self.report_processor.assert_reports([
            fixture.error(
                reports.codes.INVALID_OPTION_VALUE,
                option_name="role",
                allowed_values=const.PCMK_ROLES,
                option_value="invalid",
                cannot_be_empty=False,
                forbidden_characters=None,
            ),
        ])