diff --git a/lib/bootstrap.py b/lib/bootstrap.py index 2f720a26f2bcb218453609553c751a19e7914db3..2c73bca44fb85094e109689e6a11cbae8ce45890 100644 --- a/lib/bootstrap.py +++ b/lib/bootstrap.py @@ -222,7 +222,7 @@ def _WaitForNodeDaemon(node_name): """ def _CheckNodeDaemon(): - result = rpc.RpcRunner.call_version([node_name])[node_name] + result = rpc.BootstrapRunner().call_version([node_name])[node_name] if result.fail_msg: raise utils.RetryAgain() @@ -565,11 +565,12 @@ def FinalizeClusterDestroy(master): """ cfg = config.ConfigWriter() modify_ssh_setup = cfg.GetClusterInfo().modify_ssh_setup - result = rpc.RpcRunner.call_node_stop_master(master) + result = rpc.BootstrapRunner().call_node_stop_master(master) msg = result.fail_msg if msg: logging.warning("Could not disable the master role: %s", msg) - result = rpc.RpcRunner.call_node_leave_cluster(master, modify_ssh_setup) + result = rpc.BootstrapRunner().call_node_leave_cluster(master, + modify_ssh_setup) msg = result.fail_msg if msg: logging.warning("Could not shutdown the node daemon and cleanup" @@ -697,7 +698,7 @@ def MasterFailover(no_voting=False): logging.info("Stopping the master daemon on node %s", old_master) - result = rpc.RpcRunner.call_node_stop_master(old_master) + result = rpc.BootstrapRunner().call_node_stop_master(old_master) msg = result.fail_msg if msg: logging.error("Could not disable the master role on the old master" @@ -726,7 +727,8 @@ def MasterFailover(no_voting=False): logging.info("Starting the master daemons on the new master") - result = rpc.RpcRunner.call_node_start_master_daemons(new_master, no_voting) + result = rpc.BootstrapRunner().call_node_start_master_daemons(new_master, + no_voting) msg = result.fail_msg if msg: logging.error("Could not start the master role on the new master" @@ -782,7 +784,7 @@ def GatherMasterVotes(node_list): if not node_list: # no nodes left (eventually after removing myself) return [] - results = rpc.RpcRunner.call_master_info(node_list) + results = rpc.BootstrapRunner().call_master_info(node_list) if not isinstance(results, dict): # this should not happen (unless internal error in rpc) logging.critical("Can't complete rpc call, aborting master startup") diff --git a/lib/build/rpc_definitions.py b/lib/build/rpc_definitions.py index 930200b9857c552bb62a7e83f420678597ed6420..b4bb39e1a98097c76e150d568803f30485113022 100644 --- a/lib/build/rpc_definitions.py +++ b/lib/build/rpc_definitions.py @@ -371,4 +371,23 @@ CALLS = { ("rename", None, None), ], None, "Rename job queue file"), ], + "RpcClientBootstrap": [ + ("node_start_master_daemons", SINGLE, TMO_FAST, [ + ("no_voting", None, None), + ], None, "Starts master daemons on a node"), + ("node_activate_master_ip", SINGLE, TMO_FAST, [], None, + "Activates master IP on a node"), + ("node_stop_master", SINGLE, TMO_FAST, [], None, + "Deactivates master IP and stops master daemons on a node"), + ("node_deactivate_master_ip", SINGLE, TMO_FAST, [], None, + "Deactivates master IP on a node"), + ("node_change_master_netmask", SINGLE, TMO_FAST, [ + ("netmask", None, None), + ], None, "Change master IP netmask"), + ("node_leave_cluster", SINGLE, TMO_NORMAL, [ + ("modify_ssh_setup", None, None), + ], None, "Requests a node to clean the cluster information it has"), + ("master_info", MULTI, TMO_URGENT, [], None, "Query master info"), + ("version", MULTI, TMO_URGENT, [], None, "Query node version"), + ], } diff --git a/lib/rpc.py b/lib/rpc.py index bffd0d9ac8959ac160953fbbec8a6214a859780c..03b57c09a4a9d76038a1f1dd733f08d7110e9ad7 100644 --- a/lib/rpc.py +++ b/lib/rpc.py @@ -437,7 +437,8 @@ class _RpcProcessor: return self._CombineResults(results, requests, procedure) -class RpcRunner(_generated_rpc.RpcClientDefault): +class RpcRunner(_generated_rpc.RpcClientDefault, + _generated_rpc.RpcClientBootstrap): """RPC runner class. """ @@ -448,6 +449,11 @@ class RpcRunner(_generated_rpc.RpcClientDefault): @param context: Ganeti context """ + # Pylint doesn't recognize multiple inheritance properly, see + # <http://www.logilab.org/ticket/36586> and + # <http://www.logilab.org/ticket/35642> + # pylint: disable=W0233 + _generated_rpc.RpcClientBootstrap.__init__(self) _generated_rpc.RpcClientDefault.__init__(self) self._cfg = context.cfg @@ -646,79 +652,6 @@ class RpcRunner(_generated_rpc.RpcClientDefault): [self._InstDict(inst, osp=osparams), reinstall, debug]) - @classmethod - @_RpcTimeout(_TMO_FAST) - def call_node_start_master_daemons(cls, node, no_voting): - """Starts master daemons on a node. - - This is a single-node call. - - """ - return cls._StaticSingleNodeCall(node, "node_start_master_daemons", - [no_voting]) - - @classmethod - @_RpcTimeout(_TMO_FAST) - def call_node_activate_master_ip(cls, node): - """Activates master IP on a node. - - This is a single-node call. - - """ - return cls._StaticSingleNodeCall(node, "node_activate_master_ip", []) - - @classmethod - @_RpcTimeout(_TMO_FAST) - def call_node_stop_master(cls, node): - """Deactivates master IP and stops master daemons on a node. - - This is a single-node call. - - """ - return cls._StaticSingleNodeCall(node, "node_stop_master", []) - - @classmethod - @_RpcTimeout(_TMO_FAST) - def call_node_deactivate_master_ip(cls, node): - """Deactivates master IP on a node. - - This is a single-node call. - - """ - return cls._StaticSingleNodeCall(node, "node_deactivate_master_ip", []) - - @classmethod - @_RpcTimeout(_TMO_FAST) - def call_node_change_master_netmask(cls, node, netmask): - """Change master IP netmask. - - This is a single-node call. - - """ - return cls._StaticSingleNodeCall(node, "node_change_master_netmask", - [netmask]) - - @classmethod - @_RpcTimeout(_TMO_URGENT) - def call_master_info(cls, node_list): - """Query master info. - - This is a multi-node call. - - """ - # TODO: should this method query down nodes? - return cls._StaticMultiNodeCall(node_list, "master_info", []) - - @classmethod - @_RpcTimeout(_TMO_URGENT) - def call_version(cls, node_list): - """Query node version. - - This is a multi-node call. - - """ - return cls._StaticMultiNodeCall(node_list, "version", []) - @classmethod @_RpcTimeout(_TMO_NORMAL) def call_upload_file(cls, node_list, file_name, address_list=None): @@ -757,20 +690,6 @@ class RpcRunner(_generated_rpc.RpcClientDefault): """ return cls._StaticMultiNodeCall(node_list, "write_ssconf_files", [values]) - @classmethod - @_RpcTimeout(_TMO_NORMAL) - def call_node_leave_cluster(cls, node, modify_ssh_setup): - """Requests a node to clean the cluster information it has. - - This will remove the configuration information from the ganeti data - dir. - - This is a single-node call. - - """ - return cls._StaticSingleNodeCall(node, "node_leave_cluster", - [modify_ssh_setup]) - def call_test_delay(self, node_list, duration, read_timeout=None): """Sleep for a fixed time on given node(s). @@ -830,3 +749,25 @@ class JobQueueRunner(_generated_rpc.RpcClientJobQueue): body = serializer.DumpJson(args, indent=False) return self._proc(node_list, procedure, body, read_timeout=timeout) + + +class BootstrapRunner(_generated_rpc.RpcClientBootstrap): + """RPC wrappers for bootstrapping. + + """ + def __init__(self): + """Initializes this class. + + """ + _generated_rpc.RpcClientBootstrap.__init__(self) + + self._proc = _RpcProcessor(_SsconfResolver, + netutils.GetDaemonPort(constants.NODED)) + + def _Call(self, node_list, procedure, timeout, args): + """Entry point for automatically generated RPC wrappers. + + """ + body = serializer.DumpJson(args, indent=False) + + return self._proc(node_list, procedure, body, read_timeout=timeout) diff --git a/lib/server/masterd.py b/lib/server/masterd.py index a7b73cc86a6a911efed41feda4b602bd55f81d38..cc86d8a13f2d8cdd1292da42bf2521300ca3a2ac 100644 --- a/lib/server/masterd.py +++ b/lib/server/masterd.py @@ -532,7 +532,7 @@ def CheckAgreement(): def ActivateMasterIP(): # activate ip master_node = ssconf.SimpleStore().GetMasterNode() - result = rpc.RpcRunner.call_node_activate_master_ip(master_node) + result = rpc.BootstrapRunner().call_node_activate_master_ip(master_node) msg = result.fail_msg if msg: logging.error("Can't activate master IP address: %s", msg) diff --git a/test/ganeti.rpc_unittest.py b/test/ganeti.rpc_unittest.py index 21f536d209d8843da2a7716afae34fe2b379e911..657c013568e8c75bba7c7b87ee196f8acdde2ff9 100755 --- a/test/ganeti.rpc_unittest.py +++ b/test/ganeti.rpc_unittest.py @@ -73,7 +73,8 @@ class TestRpcProcessor(unittest.TestCase): resolver = rpc._StaticResolver(["127.0.0.1"]) http_proc = _FakeRequestProcessor(self._GetVersionResponse) proc = rpc._RpcProcessor(resolver, 24094) - result = proc(["localhost"], "version", None, _req_process_fn=http_proc) + result = proc(["localhost"], "version", None, _req_process_fn=http_proc, + read_timeout=60) self.assertEqual(result.keys(), ["localhost"]) lhresp = result["localhost"] self.assertFalse(lhresp.offline) @@ -113,7 +114,8 @@ class TestRpcProcessor(unittest.TestCase): resolver = rpc._StaticResolver([rpc._OFFLINE]) http_proc = _FakeRequestProcessor(NotImplemented) proc = rpc._RpcProcessor(resolver, 30668) - result = proc(["n17296"], "version", None, _req_process_fn=http_proc) + result = proc(["n17296"], "version", None, _req_process_fn=http_proc, + read_timeout=60) self.assertEqual(result.keys(), ["n17296"]) lhresp = result["n17296"] self.assertTrue(lhresp.offline) @@ -143,7 +145,8 @@ class TestRpcProcessor(unittest.TestCase): resolver = rpc._StaticResolver(nodes) http_proc = _FakeRequestProcessor(self._GetMultiVersionResponse) proc = rpc._RpcProcessor(resolver, 23245) - result = proc(nodes, "version", None, _req_process_fn=http_proc) + result = proc(nodes, "version", None, _req_process_fn=http_proc, + read_timeout=60) self.assertEqual(sorted(result.keys()), sorted(nodes)) for name in nodes: @@ -171,7 +174,7 @@ class TestRpcProcessor(unittest.TestCase): _FakeRequestProcessor(compat.partial(self._GetVersionResponseFail, errinfo)) result = proc(["aef9ur4i.example.com"], "version", None, - _req_process_fn=http_proc) + _req_process_fn=http_proc, read_timeout=60) self.assertEqual(result.keys(), ["aef9ur4i.example.com"]) lhresp = result["aef9ur4i.example.com"] self.assertFalse(lhresp.offline) @@ -263,7 +266,7 @@ class TestRpcProcessor(unittest.TestCase): for fn in [self._GetInvalidResponseA, self._GetInvalidResponseB]: http_proc = _FakeRequestProcessor(fn) result = proc(["oqo7lanhly.example.com"], "version", None, - _req_process_fn=http_proc) + _req_process_fn=http_proc, read_timeout=60) self.assertEqual(result.keys(), ["oqo7lanhly.example.com"]) lhresp = result["oqo7lanhly.example.com"] self.assertFalse(lhresp.offline)