From d755483c2b861e42a876669ab5d49ea12a22c56c Mon Sep 17 00:00:00 2001
From: Michael Hanselmann <hansmi@google.com>
Date: Mon, 7 Nov 2011 20:42:31 +0100
Subject: [PATCH] Fail if node/group evacuation can't evacuate instances

If an instance can't be evacuated, only a message would be printed. With
this change the operation always aborts. Newly added unittests check for
this behaviour.

Signed-off-by: Michael Hanselmann <hansmi@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>
---
 lib/cmdlib.py                  |  7 ++--
 test/ganeti.cmdlib_unittest.py | 67 ++++++++++++++++++++++++++++++++++
 2 files changed, 71 insertions(+), 3 deletions(-)

diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index 2f3f7b65e..f5876f26e 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -10285,9 +10285,10 @@ def _LoadNodeEvacResult(lu, alloc_result, early_release, use_nodes):
   (moved, failed, jobs) = alloc_result
 
   if failed:
-    lu.LogWarning("Unable to evacuate instances %s",
-                  utils.CommaJoin("%s (%s)" % (name, reason)
-                                  for (name, reason) in failed))
+    failreason = utils.CommaJoin("%s (%s)" % (name, reason)
+                                 for (name, reason) in failed)
+    lu.LogWarning("Unable to evacuate instances %s", failreason)
+    raise errors.OpExecError("Unable to evacuate instances %s" % failreason)
 
   if moved:
     lu.LogInfo("Instances to be moved: %s",
diff --git a/test/ganeti.cmdlib_unittest.py b/test/ganeti.cmdlib_unittest.py
index 40eebe0aa..08cbc6138 100755
--- a/test/ganeti.cmdlib_unittest.py
+++ b/test/ganeti.cmdlib_unittest.py
@@ -28,6 +28,7 @@ import time
 import tempfile
 import shutil
 import operator
+import itertools
 
 from ganeti import constants
 from ganeti import mcpu
@@ -363,5 +364,71 @@ class TestClusterVerifyFiles(unittest.TestCase):
       ]))
 
 
+class _FakeLU:
+  def __init__(self):
+    self.warning_log = []
+    self.info_log = []
+
+  def LogWarning(self, text, *args):
+    self.warning_log.append((text, args))
+
+  def LogInfo(self, text, *args):
+    self.info_log.append((text, args))
+
+
+class TestLoadNodeEvacResult(unittest.TestCase):
+  def testSuccess(self):
+    for moved in [[], [
+      ("inst20153.example.com", "grp2", ["nodeA4509", "nodeB2912"]),
+      ]]:
+      for early_release in [False, True]:
+        for use_nodes in [False, True]:
+          jobs = [
+            [opcodes.OpInstanceReplaceDisks().__getstate__()],
+            [opcodes.OpInstanceMigrate().__getstate__()],
+            ]
+
+          alloc_result = (moved, [], jobs)
+          assert cmdlib.IAllocator._NEVAC_RESULT(alloc_result)
+
+          lu = _FakeLU()
+          result = cmdlib._LoadNodeEvacResult(lu, alloc_result,
+                                              early_release, use_nodes)
+
+          if moved:
+            (_, (info_args, )) = lu.info_log.pop(0)
+            for (instname, instgroup, instnodes) in moved:
+              self.assertTrue(instname in info_args)
+              if use_nodes:
+                for i in instnodes:
+                  self.assertTrue(i in info_args)
+              else:
+                self.assertTrue(instgroup in info_args)
+
+          self.assertFalse(lu.info_log)
+          self.assertFalse(lu.warning_log)
+
+          for op in itertools.chain(*result):
+            if hasattr(op.__class__, "early_release"):
+              self.assertEqual(op.early_release, early_release)
+            else:
+              self.assertFalse(hasattr(op, "early_release"))
+
+  def testFailed(self):
+    alloc_result = ([], [
+      ("inst5191.example.com", "errormsg21178"),
+      ], [])
+    assert cmdlib.IAllocator._NEVAC_RESULT(alloc_result)
+
+    lu = _FakeLU()
+    self.assertRaises(errors.OpExecError, cmdlib._LoadNodeEvacResult,
+                      lu, alloc_result, False, False)
+    self.assertFalse(lu.info_log)
+    (_, (args, )) = lu.warning_log.pop(0)
+    self.assertTrue("inst5191.example.com" in args)
+    self.assertTrue("errormsg21178" in args)
+    self.assertFalse(lu.warning_log)
+
+
 if __name__ == "__main__":
   testutils.GanetiTestProgram()
-- 
GitLab