Add utils.IsNormAbsPath function
[ganeti-local] / lib / mcpu.py
index 2f60fd7..2512762 100644 (file)
@@ -28,13 +28,13 @@ are two kinds of classes defined:
 
 """
 
 
 """
 
+import logging
 
 from ganeti import opcodes
 from ganeti import constants
 from ganeti import errors
 from ganeti import rpc
 from ganeti import cmdlib
 
 from ganeti import opcodes
 from ganeti import constants
 from ganeti import errors
 from ganeti import rpc
 from ganeti import cmdlib
-from ganeti import logger
 from ganeti import locking
 
 
 from ganeti import locking
 
 
@@ -49,11 +49,13 @@ class Processor(object):
     opcodes.OpRenameCluster: cmdlib.LURenameCluster,
     opcodes.OpVerifyDisks: cmdlib.LUVerifyDisks,
     opcodes.OpSetClusterParams: cmdlib.LUSetClusterParams,
     opcodes.OpRenameCluster: cmdlib.LURenameCluster,
     opcodes.OpVerifyDisks: cmdlib.LUVerifyDisks,
     opcodes.OpSetClusterParams: cmdlib.LUSetClusterParams,
+    opcodes.OpRedistributeConfig: cmdlib.LURedistributeConfig,
     # node lu
     opcodes.OpAddNode: cmdlib.LUAddNode,
     opcodes.OpQueryNodes: cmdlib.LUQueryNodes,
     opcodes.OpQueryNodeVolumes: cmdlib.LUQueryNodeVolumes,
     opcodes.OpRemoveNode: cmdlib.LURemoveNode,
     # node lu
     opcodes.OpAddNode: cmdlib.LUAddNode,
     opcodes.OpQueryNodes: cmdlib.LUQueryNodes,
     opcodes.OpQueryNodeVolumes: cmdlib.LUQueryNodeVolumes,
     opcodes.OpRemoveNode: cmdlib.LURemoveNode,
+    opcodes.OpSetNodeParams: cmdlib.LUSetNodeParams,
     # instance lu
     opcodes.OpCreateInstance: cmdlib.LUCreateInstance,
     opcodes.OpReinstallInstance: cmdlib.LUReinstallInstance,
     # instance lu
     opcodes.OpCreateInstance: cmdlib.LUCreateInstance,
     opcodes.OpReinstallInstance: cmdlib.LUReinstallInstance,
@@ -66,6 +68,7 @@ class Processor(object):
     opcodes.OpDeactivateInstanceDisks: cmdlib.LUDeactivateInstanceDisks,
     opcodes.OpReplaceDisks: cmdlib.LUReplaceDisks,
     opcodes.OpFailoverInstance: cmdlib.LUFailoverInstance,
     opcodes.OpDeactivateInstanceDisks: cmdlib.LUDeactivateInstanceDisks,
     opcodes.OpReplaceDisks: cmdlib.LUReplaceDisks,
     opcodes.OpFailoverInstance: cmdlib.LUFailoverInstance,
+    opcodes.OpMigrateInstance: cmdlib.LUMigrateInstance,
     opcodes.OpConnectConsole: cmdlib.LUConnectConsole,
     opcodes.OpQueryInstances: cmdlib.LUQueryInstances,
     opcodes.OpQueryInstanceData: cmdlib.LUQueryInstanceData,
     opcodes.OpConnectConsole: cmdlib.LUConnectConsole,
     opcodes.OpQueryInstances: cmdlib.LUQueryInstances,
     opcodes.OpQueryInstanceData: cmdlib.LUQueryInstanceData,
@@ -97,6 +100,7 @@ class Processor(object):
     self.context = context
     self._feedback_fn = None
     self.exclusive_BGL = False
     self.context = context
     self._feedback_fn = None
     self.exclusive_BGL = False
+    self.rpc = rpc.RpcRunner(context.cfg)
 
   def _ExecLU(self, lu):
     """Logical Unit execution sequence.
 
   def _ExecLU(self, lu):
     """Logical Unit execution sequence.
@@ -104,7 +108,7 @@ class Processor(object):
     """
     write_count = self.context.cfg.write_count
     lu.CheckPrereq()
     """
     write_count = self.context.cfg.write_count
     lu.CheckPrereq()
-    hm = HooksMaster(rpc.call_hooks_runner, self, lu)
+    hm = HooksMaster(self.rpc.call_hooks_runner, self, lu)
     h_results = hm.RunPhase(constants.HOOKS_PHASE_PRE)
     lu.HooksCallBack(constants.HOOKS_PHASE_PRE, h_results,
                      self._feedback_fn, None)
     h_results = hm.RunPhase(constants.HOOKS_PHASE_PRE)
     lu.HooksCallBack(constants.HOOKS_PHASE_PRE, h_results,
                      self._feedback_fn, None)
@@ -131,6 +135,8 @@ class Processor(object):
     adding_locks = level in lu.add_locks
     acquiring_locks = level in lu.needed_locks
     if level not in locking.LEVELS:
     adding_locks = level in lu.add_locks
     acquiring_locks = level in lu.needed_locks
     if level not in locking.LEVELS:
+      if callable(self._run_notifier):
+        self._run_notifier()
       result = self._ExecLU(lu)
     elif adding_locks and acquiring_locks:
       # We could both acquire and add locks at the same level, but for now we
       result = self._ExecLU(lu)
     elif adding_locks and acquiring_locks:
       # We could both acquire and add locks at the same level, but for now we
@@ -170,11 +176,18 @@ class Processor(object):
 
     return result
 
 
     return result
 
-  def ExecOpCode(self, op, feedback_fn):
+  def ExecOpCode(self, op, feedback_fn, run_notifier):
     """Execute an opcode.
 
     """Execute an opcode.
 
-    Args:
-      op: the opcode to be executed
+    @type op: an OpCode instance
+    @param op: the opcode to be executed
+    @type feedback_fn: a function that takes a single argument
+    @param feedback_fn: this function will be used as feedback from the LU
+                        code to the end-user
+    @type run_notifier: callable (no arguments) or None
+    @param run_notifier:  this function (if callable) will be called when
+                          we are about to call the lu's Exec() method, that
+                          is, after we have aquired all locks
 
     """
     if not isinstance(op, opcodes.OpCode):
 
     """
     if not isinstance(op, opcodes.OpCode):
@@ -182,6 +195,7 @@ class Processor(object):
                                    " to ExecOpcode")
 
     self._feedback_fn = feedback_fn
                                    " to ExecOpcode")
 
     self._feedback_fn = feedback_fn
+    self._run_notifier = run_notifier
     lu_class = self.DISPATCH_TABLE.get(op.__class__, None)
     if lu_class is None:
       raise errors.OpCodeUnknown("Unknown opcode")
     lu_class = self.DISPATCH_TABLE.get(op.__class__, None)
     if lu_class is None:
       raise errors.OpCodeUnknown("Unknown opcode")
@@ -192,7 +206,7 @@ class Processor(object):
                              shared=not lu_class.REQ_BGL)
     try:
       self.exclusive_BGL = lu_class.REQ_BGL
                              shared=not lu_class.REQ_BGL)
     try:
       self.exclusive_BGL = lu_class.REQ_BGL
-      lu = lu_class(self, op, self.context)
+      lu = lu_class(self, op, self.context, self.rpc)
       lu.ExpandNames()
       assert lu.needed_locks is not None, "needed_locks not set by LU"
       result = self._LockAndExecLU(lu, locking.LEVEL_INSTANCE)
       lu.ExpandNames()
       assert lu.needed_locks is not None, "needed_locks not set by LU"
       result = self._LockAndExecLU(lu, locking.LEVEL_INSTANCE)
@@ -206,23 +220,35 @@ class Processor(object):
     """Log a change in LU execution progress.
 
     """
     """Log a change in LU execution progress.
 
     """
-    logger.Debug("Step %d/%d %s" % (current, total, message))
+    logging.debug("Step %d/%d %s", current, total, message)
     self._feedback_fn("STEP %d/%d %s" % (current, total, message))
 
     self._feedback_fn("STEP %d/%d %s" % (current, total, message))
 
-  def LogWarning(self, message, hint=None):
+  def LogWarning(self, message, *args, **kwargs):
     """Log a warning to the logs and the user.
 
     """Log a warning to the logs and the user.
 
-    """
-    logger.Error(message)
-    self._feedback_fn(" - WARNING: %s" % message)
-    if hint:
-      self._feedback_fn("      Hint: %s" % hint)
+    The optional keyword argument is 'hint' and can be used to show a
+    hint to the user (presumably related to the warning). If the
+    message is empty, it will not be printed at all, allowing one to
+    show only a hint.
 
 
-  def LogInfo(self, message):
+    """
+    assert not kwargs or (len(kwargs) == 1 and "hint" in kwargs), \
+           "Invalid keyword arguments for LogWarning (%s)" % str(kwargs)
+    if args:
+      message = message % tuple(args)
+    if message:
+      logging.warning(message)
+      self._feedback_fn(" - WARNING: %s" % message)
+    if "hint" in kwargs:
+      self._feedback_fn("      Hint: %s" % kwargs["hint"])
+
+  def LogInfo(self, message, *args):
     """Log an informational message to the logs and the user.
 
     """
     """Log an informational message to the logs and the user.
 
     """
-    logger.Info(message)
+    if args:
+      message = message % tuple(args)
+    logging.info(message)
     self._feedback_fn(" - INFO: %s" % message)
 
 
     self._feedback_fn(" - INFO: %s" % message)
 
 
@@ -294,11 +320,10 @@ class HooksMaster(object):
 
     This is the main function of the HookMaster.
 
 
     This is the main function of the HookMaster.
 
-    Args:
-      phase: the hooks phase to run
-
-    Returns:
-      the result of the hooks multi-node rpc call
+    @param phase: one of L{constants.HOOKS_PHASE_POST} or
+        L{constants.HOOKS_PHASE_PRE}; it denotes the hooks phase
+    @return: the processed results of the hooks multi-node rpc call
+    @raise errors.HooksFailure: on communication failure to the nodes
 
     """
     if not self.node_list[phase]:
 
     """
     if not self.node_list[phase]:
@@ -314,12 +339,13 @@ class HooksMaster(object):
         raise errors.HooksFailure("Communication failure")
       for node_name in results:
         res = results[node_name]
         raise errors.HooksFailure("Communication failure")
       for node_name in results:
         res = results[node_name]
-        if res is False or not isinstance(res, list):
-          self.proc.LogWarning("Communication failure to node %s" % node_name)
+        if res.failed or res.data is False or not isinstance(res.data, list):
+          if not res.offline:
+            self.proc.LogWarning("Communication failure to node %s" %
+                                 node_name)
           continue
           continue
-        for script, hkr, output in res:
+        for script, hkr, output in res.data:
           if hkr == constants.HKR_FAIL:
           if hkr == constants.HKR_FAIL:
-            output = output.strip().encode("string_escape")
             errs.append((node_name, script, output))
       if errs:
         raise errors.HooksAbort(errs)
             errs.append((node_name, script, output))
       if errs:
         raise errors.HooksAbort(errs)