# R0904: Too many public methods
import os
-import socket
import logging
import zlib
import base64
@ivar data: the data payload, for successful results, or None
@type failed: boolean
- @ivar failed: whether the operation failed at RPC level (not
+ @ivar failed: whether the operation failed at transport level (not
application level on the remote node)
@ivar call: the name of the RPC call
@ivar node: the name of the node to which we made the call
offline, as opposed to actual failure; offline=True will always
imply failed=True, in order to allow simpler checking if
the user doesn't care about the exact failure mode
+ @ivar fail_msg: the error message if the call failed
"""
def __init__(self, data=None, failed=False, offline=False,
self.node = node
if offline:
self.failed = True
- self.error = "Node is marked offline"
+ self.fail_msg = "Node is marked offline"
self.data = self.payload = None
elif failed:
- self.error = data
+ self.fail_msg = self._EnsureErr(data)
self.data = self.payload = None
else:
self.data = data
- self.error = None
- if isinstance(data, (tuple, list)) and len(data) == 2:
- self.payload = data[1]
+ if not isinstance(self.data, (tuple, list)):
+ self.fail_msg = ("RPC layer error: invalid result type (%s)" %
+ type(self.data))
+ elif len(data) != 2:
+ self.fail_msg = ("RPC layer error: invalid result length (%d), "
+ "expected 2" % len(self.data))
+ elif not self.data[0]:
+ self.fail_msg = self._EnsureErr(self.data[1])
else:
- self.payload = None
+ # finally success
+ self.fail_msg = None
+ self.payload = data[1]
+
+ @staticmethod
+ def _EnsureErr(val):
+ """Helper to ensure we return a 'True' value for error."""
+ if val:
+ return val
+ else:
+ return "No error information"
- def Raise(self):
+ def Raise(self, msg, prereq=False):
"""If the result has failed, raise an OpExecError.
This is used so that LU code doesn't have to check for each
result, but instead can call this function.
"""
- if self.failed:
- raise errors.OpExecError("Call '%s' to node '%s' has failed: %s" %
- (self.call, self.node, self.error))
+ if not self.fail_msg:
+ return
+
+ if not msg: # one could pass None for default message
+ msg = ("Call '%s' to node '%s' has failed: %s" %
+ (self.call, self.node, self.fail_msg))
+ else:
+ msg = "%s: %s" % (msg, self.fail_msg)
+ if prereq:
+ ec = errors.OpPrereqError
+ else:
+ ec = errors.OpExecError
+ raise ec(msg)
def RemoteFailMsg(self):
"""Check if the remote procedure failed.
- This is valid only for RPC calls which return result of the form
- (status, data | error_msg).
-
- @return: empty string for succcess, otherwise an error message
+ @return: the fail_msg attribute
"""
- def _EnsureErr(val):
- """Helper to ensure we return a 'True' value for error."""
- if val:
- return val
- else:
- return "No error information"
-
- if self.failed:
- return _EnsureErr(self.error)
- if not isinstance(self.data, (tuple, list)):
- return "Invalid result type (%s)" % type(self.data)
- if len(self.data) != 2:
- return "Invalid result length (%d), expected 2" % len(self.data)
- if not self.data[0]:
- return _EnsureErr(self.data[1])
- return ""
+ return self.fail_msg
class Client:
idict["beparams"] = cluster.FillBE(instance)
if bep is not None:
idict["beparams"].update(bep)
+ for nic in idict["nics"]:
+ nic['nicparams'] = objects.FillDict(
+ cluster.nicparams[constants.PP_DEFAULT],
+ nic['nicparams'])
return idict
def _ConnectList(self, client, node_list, call):
"""Helper for computing node addresses.
- @type client: L{Client}
+ @type client: L{ganeti.rpc.Client}
@param client: a C{Client} instance
@type node_list: list
@param node_list: the node list we should connect
def _ConnectNode(self, client, node, call):
"""Helper for computing one node's address.
- @type client: L{Client}
+ @type client: L{ganeti.rpc.Client}
@param client: a C{Client} instance
@type node: str
@param node: the node we should connect
# Begin RPC calls
#
- def call_volume_list(self, node_list, vg_name):
+ def call_lv_list(self, node_list, vg_name):
"""Gets the logical volumes present in a given volume group.
This is a multi-node call.
"""
- return self._MultiNodeCall(node_list, "volume_list", [vg_name])
+ return self._MultiNodeCall(node_list, "lv_list", [vg_name])
def call_vg_list(self, node_list):
"""Gets the volume group list.
return self._SingleNodeCall(node, "instance_reboot",
[self._InstDict(instance), reboot_type])
- def call_instance_os_add(self, node, inst):
+ def call_instance_os_add(self, node, inst, reinstall):
"""Installs an OS on the given instance.
This is a single-node call.
"""
return self._SingleNodeCall(node, "instance_os_add",
- [self._InstDict(inst)])
+ [self._InstDict(inst), reinstall])
def call_instance_run_rename(self, node, inst, old_name):
"""Run the OS rename script for an instance.
memory information
"""
- retux = self._MultiNodeCall(node_list, "node_info",
- [vg_name, hypervisor_type])
-
- for result in retux.itervalues():
- if result.failed or not isinstance(result.data, dict):
- result.data = {}
- if result.offline:
- log_name = None
- else:
- log_name = "call_node_info"
-
- utils.CheckDict(result.data, {
- 'memory_total' : '-',
- 'memory_dom0' : '-',
- 'memory_free' : '-',
- 'vg_size' : 'node_unreachable',
- 'vg_free' : '-',
- }, log_name)
- return retux
+ return self._MultiNodeCall(node_list, "node_info",
+ [vg_name, hypervisor_type])
def call_node_add(self, node, dsa, dsapub, rsa, rsapub, ssh, sshpub):
"""Add a node to the cluster.
[checkdict, cluster_name])
@classmethod
- def call_node_start_master(cls, node, start_daemons):
+ def call_node_start_master(cls, node, start_daemons, no_voting):
"""Tells a node to activate itself as a master.
This is a single-node call.
"""
return cls._StaticSingleNodeCall(node, "node_start_master",
- [start_daemons])
+ [start_daemons, no_voting])
@classmethod
def call_node_stop_master(cls, node, stop_daemons):
This is a multi-node call.
"""
- result = self._MultiNodeCall(node_list, "os_diagnose", [])
-
- for node_result in result.values():
- if not node_result.failed and node_result.data:
- node_result.data = [objects.OS.FromDict(oss)
- for oss in node_result.data]
- return result
+ return self._MultiNodeCall(node_list, "os_diagnose", [])
def call_os_get(self, node, name):
"""Returns an OS definition.
This is a single-node call.
"""
- result = self._SingleNodeCall(node, "export_info", [path])
- if not result.failed and result.data:
- result.data = objects.SerializableConfigParser.Loads(str(result.data))
- return result
+ return self._SingleNodeCall(node, "export_info", [path])
def call_instance_os_import(self, node, inst, src_node, src_images,
cluster_name):
"""
return self._SingleNodeCall(node, "node_demote_from_mc", [])
+
+ def call_node_powercycle(self, node, hypervisor):
+ """Tries to powercycle a node.
+
+ This is a single-node call.
+
+ """
+ return self._SingleNodeCall(node, "node_powercycle", [hypervisor])
+
+
def call_test_delay(self, node_list, duration):
"""Sleep for a fixed time on given node(s).
"""
cluster = self._cfg.GetClusterInfo()
- hv_full = cluster.FillDict(cluster.hvparams.get(hvname, {}), hvparams)
+ hv_full = objects.FillDict(cluster.hvparams.get(hvname, {}), hvparams)
return self._MultiNodeCall(node_list, "hypervisor_validate_params",
[hvname, hv_full])