+from ganeti import serializer
+from ganeti import constants
+from ganeti import errors
+
+import ganeti.http.client
+
+
+# Module level variable
+_http_manager = None
+
+
+def Init():
+ """Initializes the module-global HTTP client manager.
+
+ Must be called before using any RPC function.
+
+ """
+ global _http_manager
+
+ assert not _http_manager, "RPC module initialized more than once"
+
+ _http_manager = http.client.HttpClientManager()
+
+
+def Shutdown():
+ """Stops the module-global HTTP client manager.
+
+ Must be called before quitting the program.
+
+ """
+ global _http_manager
+
+ if _http_manager:
+ _http_manager.Shutdown()
+ _http_manager = None
+
+
+class RpcResult(object):
+ """RPC Result class.
+
+ This class holds an RPC result. It is needed since in multi-node
+ calls we can't raise an exception just because one one out of many
+ failed, and therefore we use this class to encapsulate the result.
+
+ @ivar data: the data payload, for successfull results, or None
+ @type failed: boolean
+ @ivar failed: whether the operation failed at RPC 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
+ @ivar offline: whether the operation failed because the node was
+ 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
+
+ """
+ def __init__(self, data=None, failed=False, offline=False,
+ call=None, node=None):
+ self.failed = failed
+ self.offline = offline
+ self.call = call
+ self.node = node
+ if offline:
+ self.failed = True
+ self.error = "Node is marked offline"
+ self.data = self.payload = None
+ elif failed:
+ self.error = 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]
+ else:
+ self.payload = None
+
+ def Raise(self):
+ """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))
+
+ 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
+
+ """
+ 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 ""