def test_success(self, mock_func): mock_com = mock.MagicMock(spec_set=NodeCommunicator) mock_rep = MockLibraryReportProcessor() watchdog_dict = dict([ (NodeAddresses("node" + str(i)), "/dev/watchdog" + str(i)) for i in range(5) ]) device_dict = dict([ (NodeAddresses("node" + str(i)), ["/dev/sdb" + str(i)]) for i in range(5) ]) node_list = list(watchdog_dict.keys()) config = { "opt1": "val1", "opt2": "val2" } lib_sbd.set_sbd_config_on_all_nodes( mock_rep, mock_com, node_list, config, watchdog_dict, device_dict ) mock_func.assert_called_once_with( lib_sbd.set_sbd_config_on_node, [ ( [ mock_rep, mock_com, node, config, watchdog_dict[node], device_dict[node] ], {} ) for node in node_list ] )
def test_some_not_ok(self): watchdog_dict = { NodeAddresses("node1"): "", NodeAddresses("node2"): None, NodeAddresses("node3"): "/dev/watchdog", NodeAddresses("node4"): "../dev/watchdog", } assert_report_item_list_equal( cmd_sbd._validate_watchdog_dict(watchdog_dict), [(Severities.ERROR, report_codes.WATCHDOG_INVALID, { "watchdog": watchdog }) for watchdog in ["", None, "../dev/watchdog"]])
def setUp(self): self.env_assistant, self.config = get_env_tools(self) self.corosync_conf_facade = mock.MagicMock(CorosyncConfigFacade) self.corosync_conf_text = "corosync conf" self.corosync_conf_facade.config.export.return_value = ( self.corosync_conf_text ) self.corosync_conf_facade.get_nodes.return_value = NodeAddressesList([ NodeAddresses("node-1"), NodeAddresses("node-2"), ]) self.corosync_conf_facade.need_stopped_cluster = False self.corosync_conf_facade.need_qdevice_reload = False self.node_labels = ["node-1", "node-2"]
def test_success(self): mock_communicator = mock.MagicMock(spec_set=NodeCommunicator) node = NodeAddresses("node1") lib_sbd.remove_stonith_watchdog_timeout(mock_communicator, node) mock_communicator.call_node.assert_called_once_with( node, "remote/remove_stonith_watchdog_timeout", None )
def test_success(self, mock_func): mock_com = mock.MagicMock(spec_set=NodeCommunicator) mock_rep = MockLibraryReportProcessor() node_list = [NodeAddresses("node" + str(i)) for i in range(2)] data = { node_list[0]: { "watchdog": "/dev/watchdog1", "device_list": ["/dev/sdb", "/dev/vda1"], }, node_list[1]: { "watchdog": "/dev/watchdog2", "device_list": ["/dev/sda2"], } } lib_sbd.check_sbd_on_all_nodes(mock_rep, mock_com, data) items = sorted(data.items()) mock_func.assert_called_once_with( lib_sbd.check_sbd_on_node, [ ( [ mock_rep, mock_com, node, data["watchdog"], data["device_list"] ], {} ) for node, data in items ] )
def test_ring0_with_label(self): ring0 = "ring0" label = "label" target = lib.RequestTarget.from_node_addresses( NodeAddresses(ring0, name=label)) self.assertEqual(label, target.label) self.assertEqual([ring0], target.address_list)
def test_ring1(self): ring0 = "ring0" ring1 = "ring1" target = lib.RequestTarget.from_node_addresses( NodeAddresses(ring0, ring1)) self.assertEqual(ring0, target.label) self.assertEqual([ring0, ring1], target.address_list)
def test_success(self): mock_communicator = mock.MagicMock(spec_set=NodeCommunicator) node = NodeAddresses("node1") lib_sbd.get_sbd_config(mock_communicator, node) mock_communicator.call_node.assert_called_once_with( node, "remote/get_sbd_config", None )
def test_success(self, mock_corosync_live): conf_text = "test conf text" nodes = ["node1", "node2"] node_addrs_list = NodeAddressesList( [NodeAddresses(addr) for addr in nodes]) mock_corosync_live.set_remote_corosync_conf = mock.MagicMock() lib.distribute_corosync_conf(self.mock_communicator, self.mock_reporter, node_addrs_list, conf_text) corosync_live_calls = [ mock.call.set_remote_corosync_conf("mock node communicator", node_addrs_list[0], conf_text), mock.call.set_remote_corosync_conf("mock node communicator", node_addrs_list[1], conf_text), ] self.assertEqual(len(corosync_live_calls), len(mock_corosync_live.mock_calls)) mock_corosync_live.set_remote_corosync_conf.assert_has_calls( corosync_live_calls, any_order=True) assert_report_item_list_equal(self.mock_reporter.report_item_list, [ (severity.INFO, report_codes.COROSYNC_CONFIG_DISTRIBUTION_STARTED, {}), (severity.INFO, report_codes.COROSYNC_CONFIG_ACCEPTED_BY_NODE, { "node": nodes[0] }), (severity.INFO, report_codes.COROSYNC_CONFIG_ACCEPTED_BY_NODE, { "node": nodes[1] }), ])
def test_without_authfile(self, mock_pull): mock_pull.return_value = { "config": { "name": "name.conf", "data": "config" }, "authfile": { "name": None, "data": None } } commands.pull_config(self.mock_env, "node", "name") mock_pull.assert_called_once_with(self.mock_com, NodeAddresses("node"), "name") self.mock_env.booth.create_config.called_once_with("config", True) self.assertEqual(0, self.mock_env.booth.set_key_path.call_count) self.assertEqual(0, self.mock_env.booth.create_key.call_count) assert_report_item_list_equal( self.mock_rep.report_item_list, [(Severities.INFO, report_codes.BOOTH_FETCHING_CONFIG_FROM_NODE, { "node": "node", "config": "name" }), (Severities.INFO, report_codes.BOOTH_CONFIG_ACCEPTED_BY_NODE, { "node": None, "name_list": ["name"] })])
def test_with_authfile(self, mock_pull): mock_pull.return_value = { "config": { "name": "name.conf", "data": "config" }, "authfile": { "name": "name.key", "data": base64.b64encode("key".encode("utf-8")).decode("utf-8") } } commands.pull_config(self.mock_env, "node", "name") mock_pull.assert_called_once_with(self.mock_com, NodeAddresses("node"), "name") self.mock_env.booth.create_config.called_once_with("config", True) self.mock_env.booth.set_key_path.called_once_with( os.path.join(settings.booth_config_dir, "name.key")) self.mock_env.booth.create_key.called_once_with( "key".encode("utf-8"), True) assert_report_item_list_equal( self.mock_rep.report_item_list, [(Severities.INFO, report_codes.BOOTH_FETCHING_CONFIG_FROM_NODE, { "node": "node", "config": "name" }), (Severities.INFO, report_codes.BOOTH_CONFIG_ACCEPTED_BY_NODE, { "node": None, "name_list": ["name"] })])
def test_fail_doesnt_prevent_start(self, mock_remote_start, mock_remote_stop): nodes = ["node1", "node2"] node_addrs_list = NodeAddressesList( [NodeAddresses(addr) for addr in nodes]) def raiser(reporter, communicator, node): if node.ring0 == nodes[1]: raise NodeAuthenticationException(node.label, "command", "HTTP error: 401") mock_remote_stop.side_effect = raiser assert_raise_library_error( lambda: lib.qdevice_reload_on_nodes( self.mock_communicator, self.mock_reporter, node_addrs_list), (severity.ERROR, report_codes.NODE_COMMUNICATION_ERROR_NOT_AUTHORIZED, { "node": nodes[1], "command": "command", "reason": "HTTP error: 401", }, report_codes.SKIP_OFFLINE_NODES)) node_calls = [ mock.call(self.mock_reporter, self.mock_communicator, node_addrs_list[0]), mock.call(self.mock_reporter, self.mock_communicator, node_addrs_list[1]), ] self.assertEqual(len(node_calls), len(mock_remote_stop.mock_calls)) self.assertEqual(len(node_calls), len(mock_remote_start.mock_calls)) mock_remote_stop.assert_has_calls(node_calls, any_order=True) mock_remote_start.assert_has_calls(node_calls, any_order=True) assert_report_item_list_equal( self.mock_reporter.report_item_list, [ (severity.INFO, report_codes.QDEVICE_CLIENT_RELOAD_STARTED, {}), # why the same error twice? # 1. Tested piece of code calls a function which puts an error # into the reporter. The reporter raises an exception. The # exception is caught in the tested piece of code, stored, and # later put to reporter again. # 2. Mock reporter remembers everything that goes through it # and by the machanism described in 1 the error goes througt it # twice. (severity.ERROR, report_codes.NODE_COMMUNICATION_ERROR_NOT_AUTHORIZED, { "node": nodes[1], "command": "command", "reason": "HTTP error: 401", }, report_codes.SKIP_OFFLINE_NODES), (severity.ERROR, report_codes.NODE_COMMUNICATION_ERROR_NOT_AUTHORIZED, { "node": nodes[1], "command": "command", "reason": "HTTP error: 401", }, report_codes.SKIP_OFFLINE_NODES), ])
def test_one_node_running(self): node_responses = { "node1": '{"corosync": false}', "node2": '{"corosync": true}', } node_addrs_list = NodeAddressesList( [NodeAddresses(addr) for addr in node_responses.keys()] ) self.mock_communicator.call_node.side_effect = ( lambda node, request, data: node_responses[node.label] ) assert_raise_library_error( lambda: lib.check_corosync_offline_on_nodes( self.mock_communicator, self.mock_reporter, node_addrs_list ), ( severity.ERROR, report_codes.COROSYNC_RUNNING_ON_NODE, { "node": "node2", } ) )
def test_node_down(self): nodes = ["node1", "node2"] node_addrs_list = NodeAddressesList( [NodeAddresses(addr) for addr in nodes]) def side_effect(node, request, data): if node.ring0 == nodes[1]: raise NodeAuthenticationException(nodes[1], "command", "HTTP error: 401") return '{"corosync": false}' self.mock_communicator.call_node.side_effect = side_effect assert_raise_library_error( lambda: lib.check_corosync_offline_on_nodes( self.mock_communicator, self.mock_reporter, node_addrs_list), (severity.ERROR, report_codes.NODE_COMMUNICATION_ERROR_NOT_AUTHORIZED, { "node": nodes[1], "command": "command", "reason": "HTTP error: 401", }, report_codes.SKIP_OFFLINE_NODES), (severity.ERROR, report_codes.COROSYNC_NOT_RUNNING_CHECK_NODE_ERROR, { "node": nodes[1], }, report_codes.SKIP_OFFLINE_NODES))
def test_success(self, mock_remote_start, mock_remote_stop): nodes = ["node1", "node2"] node_addrs_list = NodeAddressesList( [NodeAddresses(addr) for addr in nodes] ) lib.qdevice_reload_on_nodes( self.mock_communicator, self.mock_reporter, node_addrs_list ) node_calls = [ mock.call( self.mock_reporter, self.mock_communicator, node_addrs_list[0] ), mock.call( self.mock_reporter, self.mock_communicator, node_addrs_list[1] ), ] self.assertEqual(len(node_calls), len(mock_remote_stop.mock_calls)) self.assertEqual(len(node_calls), len(mock_remote_start.mock_calls)) mock_remote_stop.assert_has_calls(node_calls, any_order=True) mock_remote_start.assert_has_calls(node_calls, any_order=True) assert_report_item_list_equal( self.mock_reporter.report_item_list, [ ( severity.INFO, report_codes.QDEVICE_CLIENT_RELOAD_STARTED, {} ), ] )
def test_success(self): mock_communicator = mock.MagicMock(spec_set=NodeCommunicator) node = NodeAddresses("node1") lib.node_check_auth(mock_communicator, node) mock_communicator.call_node.assert_called_once_with( node, "remote/check_auth", "check_auth_only=1" )
def test_json_error(self): nodes = ["node1", "node2"] node_addrs_list = NodeAddressesList( [NodeAddresses(addr) for addr in nodes] ) self.mock_communicator.call_node.side_effect = [ '{}', # missing key '{', # not valid json ] assert_raise_library_error( lambda: lib.check_corosync_offline_on_nodes( self.mock_communicator, self.mock_reporter, node_addrs_list ), ( severity.ERROR, report_codes.COROSYNC_NOT_RUNNING_CHECK_NODE_ERROR, { "node": nodes[0], }, report_codes.SKIP_OFFLINE_NODES ), ( severity.ERROR, report_codes.COROSYNC_NOT_RUNNING_CHECK_NODE_ERROR, { "node": nodes[1], }, report_codes.SKIP_OFFLINE_NODES ) )
def test_success(self): nodes = ["node1", "node2"] node_addrs_list = NodeAddressesList( [NodeAddresses(addr) for addr in nodes] ) self.mock_communicator.call_node.return_value = '{"corosync": false}' lib.check_corosync_offline_on_nodes( self.mock_communicator, self.mock_reporter, node_addrs_list ) assert_report_item_list_equal( self.mock_reporter.report_item_list, [ ( severity.INFO, report_codes.COROSYNC_NOT_RUNNING_CHECK_STARTED, {} ), ( severity.INFO, report_codes.COROSYNC_NOT_RUNNING_ON_NODE, {"node": nodes[0]} ), ( severity.INFO, report_codes.COROSYNC_NOT_RUNNING_ON_NODE, {"node": nodes[1]} ), ] )
def pull_config(env, node_name, name): """ Get config from specified node and save it on local system. It will rewrite existing files. env -- LibraryEnvironment node_name -- string, name of node from which config should be fetched name -- string, name of booth instance of which config should be fetched """ env.report_processor.process( booth_reports.booth_fetching_config_from_node_started(node_name, name)) output = sync.pull_config_from_node(env.node_communicator(), NodeAddresses(node_name), name) try: env.booth.create_config(output["config"]["data"], True) if (output["authfile"]["name"] is not None and output["authfile"]["data"]): env.booth.set_key_path( os.path.join(settings.booth_config_dir, output["authfile"]["name"])) env.booth.create_key( base64.b64decode(output["authfile"]["data"].encode("utf-8")), True) env.report_processor.process( booth_reports.booth_config_accepted_by_node(name_list=[name])) except KeyError: raise LibraryError(reports.invalid_response_format(node_name))
def test_success(self, mock_func): mock_com = mock.MagicMock(spec_set=NodeCommunicator) mock_rep = MockLibraryReportProcessor() node_list = [NodeAddresses("node" + str(i)) for i in range(5)] lib_sbd.disable_sbd_service_on_all_nodes(mock_rep, mock_com, node_list) mock_func.assert_called_once_with(lib_sbd.disable_sbd_service_on_node, [([mock_rep, mock_com, node], {}) for node in node_list])
def test_url_multiaddr(self): hosts = ["ring0", "ring1"] action = "action" request = self._get_request( lib.RequestTarget.from_node_addresses(NodeAddresses(*hosts))) self.assert_url(request.url, hosts[0], action) request.next_host() self.assert_url(request.url, hosts[1], action)
def test_success(self): mock_communicator = mock.MagicMock(spec_set=NodeCommunicator) node = NodeAddresses("node1") lib_sbd.check_sbd(mock_communicator, node, "/dev/watchdog", ["/dev/sdb1", "/dev/sdc"]) mock_communicator.call_node.assert_called_once_with( node, "remote/check_sbd", "watchdog=%2Fdev%2Fwatchdog&" +\ "device_list=%5B%22%2Fdev%2Fsdb1%22%2C+%22%2Fdev%2Fsdc%22%5D" )
def test_success(self): config = "test {\nconfig: data\n}\n" node = NodeAddresses("node1") mock_communicator = mock.MagicMock(spec_set=NodeCommunicator) mock_communicator.call_node.return_value = "dummy return" lib.set_remote_corosync_conf(mock_communicator, node, config) mock_communicator.call_node.assert_called_once_with( node, "remote/set_corosync_conf", "corosync_conf=test+%7B%0Aconfig%3A+data%0A%7D%0A")
def test_one_node_down_forced(self, mock_corosync_live): conf_text = "test conf text" nodes = ["node1", "node2"] node_addrs_list = NodeAddressesList( [NodeAddresses(addr) for addr in nodes]) mock_corosync_live.set_remote_corosync_conf = mock.MagicMock() def raiser(comm, node, conf): if node.ring0 == nodes[1]: raise NodeAuthenticationException(nodes[1], "command", "HTTP error: 401") mock_corosync_live.set_remote_corosync_conf.side_effect = raiser lib.distribute_corosync_conf(self.mock_communicator, self.mock_reporter, node_addrs_list, conf_text, skip_offline_nodes=True) corosync_live_calls = [ mock.call.set_remote_corosync_conf("mock node communicator", nodes[0], conf_text), mock.call.set_remote_corosync_conf("mock node communicator", nodes[1], conf_text), ] self.assertEqual(len(corosync_live_calls), len(mock_corosync_live.mock_calls)) mock_corosync_live.set_remote_corosync_conf.assert_has_calls( [ mock.call("mock node communicator", node_addrs_list[0], conf_text), mock.call("mock node communicator", node_addrs_list[1], conf_text), ], any_order=True) assert_report_item_list_equal(self.mock_reporter.report_item_list, [ (severity.INFO, report_codes.COROSYNC_CONFIG_DISTRIBUTION_STARTED, {}), (severity.INFO, report_codes.COROSYNC_CONFIG_ACCEPTED_BY_NODE, { "node": nodes[0] }), (severity.WARNING, report_codes.NODE_COMMUNICATION_ERROR_NOT_AUTHORIZED, { "node": nodes[1], "command": "command", "reason": "HTTP error: 401", }), (severity.WARNING, report_codes.COROSYNC_CONFIG_DISTRIBUTION_NODE_ERROR, { "node": nodes[1], }), ])
def test_errors_forced(self): nodes = ["node1", "node2"] node_addrs_list = NodeAddressesList( [NodeAddresses(addr) for addr in nodes] ) def side_effect(node, request, data): if node.ring0 == nodes[1]: raise NodeAuthenticationException( nodes[1], "command", "HTTP error: 401" ) return '{' # invalid json self.mock_communicator.call_node.side_effect = side_effect lib.check_corosync_offline_on_nodes( self.mock_communicator, self.mock_reporter, node_addrs_list, skip_offline_nodes=True ) assert_report_item_list_equal( self.mock_reporter.report_item_list, [ ( severity.INFO, report_codes.COROSYNC_NOT_RUNNING_CHECK_STARTED, {} ), ( severity.WARNING, report_codes.COROSYNC_NOT_RUNNING_CHECK_NODE_ERROR, { "node": nodes[0], } ), ( severity.WARNING, report_codes.NODE_COMMUNICATION_ERROR_NOT_AUTHORIZED, { "node": nodes[1], "command": "command", "reason" : "HTTP error: 401", } ), ( severity.WARNING, report_codes.COROSYNC_NOT_RUNNING_CHECK_NODE_ERROR, { "node": nodes[1], } ) ] )
def find_node_list(resources_section): node_list = [ NodeAddresses(nvpair.attrib["value"], name=nvpair.getparent().getparent().attrib["id"]) for nvpair in resources_section.xpath( ".//primitive[{is_remote}]/{has_server}".format( is_remote=_IS_REMOTE_AGENT_XPATH_SNIPPET, has_server=_HAS_SERVER_XPATH_SNIPPET, )) ] node_list.extend([ NodeAddresses(primitive.attrib["id"], name=primitive.attrib["id"]) for primitive in resources_section.xpath( ".//primitive[{is_remote} and not({has_server})]".format( is_remote=_IS_REMOTE_AGENT_XPATH_SNIPPET, has_server=_HAS_SERVER_XPATH_SNIPPET, )) ]) return node_list
def validate(self, node_name, options): tree = etree.fromstring(""" <cib> <configuration> <resources> <primitive id="CONFLICT"/> <primitive id="A"> <meta_attributes> <nvpair name="remote-node" value="GUEST_CONFLICT" /> </meta_attributes> </primitive> <primitive id="B" class="ocf" provider="pacemaker" type="remote" > <instance_attributes> <nvpair name="server" value="REMOTE_CONFLICT"/> </instance_attributes> </primitive> <primitive id="C"> <meta_attributes> <nvpair name="remote-node" value="some"/> <nvpair name="remote-addr" value="GUEST_ADDR_CONFLICT" /> </meta_attributes> </primitive> </resources> </configuration> </cib> """) nodes = [ NodeAddresses("RING0", "RING1", name="R1"), NodeAddresses("REMOTE_CONFLICT", name="B"), NodeAddresses("GUEST_CONFLICT", name="GUEST_CONFLICT"), NodeAddresses("GUEST_ADDR_CONFLICT", name="some"), ] return guest_node.validate_conflicts(tree, nodes, node_name, options)
def setUp(self): self.mock_env = mock.MagicMock(spec_set=LibraryEnvironment) self.mock_log = mock.MagicMock(spec_set=logging.Logger) self.mock_env.logger = self.mock_log self.mock_com = mock.MagicMock(spec_set=NodeCommunicator) self.mock_env.node_communicator.return_value = self.mock_com self.mock_run = mock.MagicMock(spec_set=CommandRunner) self.mock_env.cmd_runner.return_value = self.mock_run self.mock_rep = MockLibraryReportProcessor() self.mock_env.report_processor = self.mock_rep self.node_list = NodeAddressesList( [NodeAddresses("node" + str(i)) for i in range(3)])
def get_nodes(self): """ Get all defined nodes """ result = NodeAddressesList() for node in self.config.findall("./clusternodes/clusternode"): altname = node.find("altname") result.append(NodeAddresses( ring0=node.get("name"), ring1=altname.get("name") if altname is not None else None, name=None, id=node.get("nodeid") )) return result
def validate( self, instance_attributes=None, node_name="NODE-NAME", host="node-host" ): nodes = [ NodeAddresses("RING0", "RING1", name="R"), ] resource_agent = mock.MagicMock() return remote_node.validate_create( nodes, resource_agent, host, node_name, instance_attributes if instance_attributes else {}, )