Add RPC for setting watcher pause
authorMichael Hanselmann <hansmi@google.com>
Tue, 11 Dec 2012 16:17:20 +0000 (17:17 +0100)
committerMichael Hanselmann <hansmi@google.com>
Thu, 13 Dec 2012 11:29:13 +0000 (12:29 +0100)
The watcher pause file should be set/unset on all nodes at once, not
only the master node. For that a new RPC is needed.

Signed-off-by: Michael Hanselmann <hansmi@google.com>
Reviewed-by: Guido Trotter <ultrotter@google.com>

lib/backend.py
lib/rpc_defs.py
lib/server/noded.py
test/ganeti.backend_unittest.py

index 179e9f5..ccb6a17 100644 (file)
@@ -64,6 +64,7 @@ from ganeti import mcpu
 from ganeti import compat
 from ganeti import pathutils
 from ganeti import vcluster
+from ganeti import ht
 
 
 _BOOT_ID_PATH = "/proc/sys/kernel/random/boot_id"
@@ -3768,6 +3769,25 @@ def RunRestrictedCmd(cmd,
       lock = None
 
 
+def SetWatcherPause(until, _filename=pathutils.WATCHER_PAUSEFILE):
+  """Creates or removes the watcher pause file.
+
+  @type until: None or number
+  @param until: Unix timestamp saying until when the watcher shouldn't run
+
+  """
+  if until is None:
+    logging.info("Received request to no longer pause watcher")
+    utils.RemoveFile(_filename)
+  else:
+    logging.info("Received request to pause watcher until %s", until)
+
+    if not ht.TNumber(until):
+      _Fail("Duration must be numeric")
+
+    utils.WriteFile(_filename, data="%d\n" % (until, ), mode=0644)
+
+
 class HooksRunner(object):
   """Hook runner.
 
index ecea054..449b50a 100644 (file)
@@ -505,6 +505,9 @@ _MISC_CALLS = [
     ("hvname", None, "Hypervisor name"),
     ("hvfull", None, "Parameters to be validated"),
     ], None, None, "Validate hypervisor params"),
+  ("set_watcher_pause", MULTI, None, constants.RPC_TMO_URGENT, [
+    ("until", None, None),
+    ], None, None, "Set watcher pause end"),
   ]
 
 CALLS = {
index 91ce4ce..0a1d0d6 100644 (file)
@@ -827,6 +827,14 @@ class NodeRequestHandler(http.server.HttpServerHandler):
     (values,) = params
     return ssconf.WriteSsconfFiles(values)
 
+  @staticmethod
+  def perspective_set_watcher_pause(params):
+    """Set watcher pause.
+
+    """
+    (until, ) = params
+    return backend.SetWatcherPause(until)
+
   # os -----------------------
 
   @staticmethod
index f551ac2..4a85242 100755 (executable)
@@ -482,5 +482,40 @@ class TestRunRestrictedCmd(unittest.TestCase):
       self.fail("Did not raise exception")
 
 
+class TestSetWatcherPause(unittest.TestCase):
+  def setUp(self):
+    self.tmpdir = tempfile.mkdtemp()
+    self.filename = utils.PathJoin(self.tmpdir, "pause")
+
+  def tearDown(self):
+    shutil.rmtree(self.tmpdir)
+
+  def testUnsetNonExisting(self):
+    self.assertFalse(os.path.exists(self.filename))
+    backend.SetWatcherPause(None, _filename=self.filename)
+    self.assertFalse(os.path.exists(self.filename))
+
+  def testSetNonNumeric(self):
+    for i in ["", [], {}, "Hello World", "0", "1.0"]:
+      self.assertFalse(os.path.exists(self.filename))
+
+      try:
+        backend.SetWatcherPause(i, _filename=self.filename)
+      except backend.RPCFail, err:
+        self.assertEqual(str(err), "Duration must be numeric")
+      else:
+        self.fail("Did not raise exception")
+
+      self.assertFalse(os.path.exists(self.filename))
+
+  def testSet(self):
+    self.assertFalse(os.path.exists(self.filename))
+
+    for i in range(10):
+      backend.SetWatcherPause(i, _filename=self.filename)
+      self.assertEqual(utils.ReadFile(self.filename), "%s\n" % i)
+      self.assertEqual(os.stat(self.filename).st_mode & 0777, 0644)
+
+
 if __name__ == "__main__":
   testutils.GanetiTestProgram()