+from ganeti import serializer
+from ganeti import constants
+from ganeti import errors
+
+# pylint has a bug here, doesn't see this import
+import ganeti.http.client # pylint: disable-msg=W0611
+
+
+# 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 # pylint: disable-msg=W0603
+
+ assert not _http_manager, "RPC module initialized more than once"
+
+ http.InitSsl()
+
+ _http_manager = http.client.HttpClientManager()
+
+
+def Shutdown():
+ """Stops the module-global HTTP client manager.
+
+ Must be called before quitting the program.
+
+ """
+ global _http_manager # pylint: disable-msg=W0603
+
+ 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 successful results, or None
+ @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
+ @ivar fail_msg: the error message if the call failed
+
+ """
+ def __init__(self, data=None, failed=False, offline=False,
+ call=None, node=None):
+ self.offline = offline
+ self.call = call
+ self.node = node
+
+ if offline:
+ self.fail_msg = "Node is marked offline"
+ self.data = self.payload = None
+ elif failed:
+ self.fail_msg = self._EnsureErr(data)
+ self.data = self.payload = None
+ else:
+ self.data = data
+ if not isinstance(self.data, (tuple, list)):
+ self.fail_msg = ("RPC layer error: invalid result type (%s)" %
+ type(self.data))
+ self.payload = None
+ elif len(data) != 2:
+ self.fail_msg = ("RPC layer error: invalid result length (%d), "
+ "expected 2" % len(self.data))
+ self.payload = None
+ elif not self.data[0]:
+ self.fail_msg = self._EnsureErr(self.data[1])
+ self.payload = None
+ else:
+ # finally success
+ self.fail_msg = None
+ self.payload = data[1]
+
+ assert hasattr(self, "call")
+ assert hasattr(self, "data")
+ assert hasattr(self, "fail_msg")
+ assert hasattr(self, "node")
+ assert hasattr(self, "offline")
+ assert hasattr(self, "payload")
+
+ @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, msg, prereq=False, ecode=None):
+ """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 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
+ if ecode is not None:
+ args = (msg, prereq)
+ else:
+ args = (msg, )
+ raise ec(*args) # pylint: disable-msg=W0142