repair_command takes two strings as input cmd, and inp.
This patch generalizes RunRestrictedCmd to RunCmd. RunCmd
can now pass a string as stdin input to the command that
will rull.

Signed-off-by: Bhimanavajjula Aditya <[email protected]>
---
 lib/backend.py                     | 41 ++++++++++++++++++++++----------
 lib/pathutils.py                   |  4 ++++
 lib/rpc_defs.py                    |  4 ++++
 lib/server/noded.py                | 18 +++++++++++++-
 test/py/ganeti.backend_unittest.py | 48 +++++++++++++++++++-------------------
 5 files changed, 78 insertions(+), 37 deletions(-)

diff --git a/lib/backend.py b/lib/backend.py
index cc96689..6ed07e6 100644
--- a/lib/backend.py
+++ b/lib/backend.py
@@ -5473,18 +5473,25 @@ def _PrepareRestrictedCmd(path, cmd,
   return _verify_cmd(path, cmd)
 
 
-def RunRestrictedCmd(cmd,
-                     _lock_timeout=_RCMD_LOCK_TIMEOUT,
-                     _lock_file=pathutils.RESTRICTED_COMMANDS_LOCK_FILE,
-                     _path=pathutils.RESTRICTED_COMMANDS_DIR,
-                     _sleep_fn=time.sleep,
-                     _prepare_fn=_PrepareRestrictedCmd,
-                     _runcmd_fn=utils.RunCmd,
-                     _enabled=constants.ENABLE_RESTRICTED_COMMANDS):
-  """Executes a restricted command after performing strict tests.
+def RunCmd(cmd,
+           lock_file,
+           path,
+           inp=None,
+           _lock_timeout=_RCMD_LOCK_TIMEOUT,
+           _sleep_fn=time.sleep,
+           _prepare_fn=_PrepareRestrictedCmd,
+           _runcmd_fn=utils.RunCmd,
+           _enabled=constants.ENABLE_RESTRICTED_COMMANDS):
+  """Executes a command after performing strict tests.
 
   @type cmd: string
   @param cmd: Command name
+  @type lock_file: string
+  @param lock_file: path to the lock file
+  @type path: string
+  @param path: path to the directory in which the command is present
+  @type inp: string
+  @param inp: Input to be passed to the command
   @rtype: string
   @return: Command output
   @raise RPCFail: In case of an error
@@ -5499,14 +5506,24 @@ def RunRestrictedCmd(cmd,
   try:
     cmdresult = None
     try:
-      lock = utils.FileLock.Open(_lock_file)
+      lock = utils.FileLock.Open(lock_file)
       lock.Exclusive(blocking=True, timeout=_lock_timeout)
 
-      (status, value) = _prepare_fn(_path, cmd)
+      (status, value) = _prepare_fn(path, cmd)
 
       if status:
+        if inp:
+          input_fd = tempfile.TemporaryFile()
+          input_fd.write(inp)
+          input_fd.flush()
+          input_fd.seek(0)
+        else:
+          input_fd = None
         cmdresult = _runcmd_fn([value], env={}, reset_env=True,
-                               postfork_fn=lambda _: lock.Unlock())
+                               postfork_fn=lambda _: lock.Unlock(),
+                               input_fd=input_fd)
+        if input_fd:
+          input_fd.close()
       else:
         logging.error(value)
     except Exception: # pylint: disable=W0703
diff --git a/lib/pathutils.py b/lib/pathutils.py
index d9c3440..81ebb1f 100644
--- a/lib/pathutils.py
+++ b/lib/pathutils.py
@@ -122,6 +122,7 @@ VNC_PASSWORD_FILE = CONF_DIR + "/vnc-cluster-password"
 HOOKS_BASE_DIR = CONF_DIR + "/hooks"
 FILE_STORAGE_PATHS_FILE = CONF_DIR + "/file-storage-paths"
 RESTRICTED_COMMANDS_DIR = CONF_DIR + "/restricted-commands"
+REPAIR_COMMANDS_DIR = CONF_DIR + "/node-repair-commands"
 
 #: Node daemon certificate path
 NODED_CERT_FILE = DATA_DIR + "/server.pem"
@@ -133,6 +134,9 @@ NODED_CERT_MODE = 0440
 #: Locked in exclusive mode while noded verifies a remote command
 RESTRICTED_COMMANDS_LOCK_FILE = LOCK_DIR + "/ganeti-restricted-commands.lock"
 
+#: Locked in exclusive mode while noded verifies a remote command
+REPAIR_COMMANDS_LOCK_FILE = LOCK_DIR + "/ganeti-repair-commands.lock"
+
 #: Lock file for watcher, locked in shared mode by watcher; lock in exclusive
 # mode to block watcher (see L{cli._RunWhileDaemonsStoppedHelper.Call}
 WATCHER_LOCK_FILE = LOCK_DIR + "/ganeti-watcher.lock"
diff --git a/lib/rpc_defs.py b/lib/rpc_defs.py
index e386ec2..c958eda 100644
--- a/lib/rpc_defs.py
+++ b/lib/rpc_defs.py
@@ -591,6 +591,10 @@ _MISC_CALLS = [
   ("restricted_command", MULTI, None, constants.RPC_TMO_SLOW, [
     ("cmd", None, "Command name"),
     ], None, None, "Runs restricted command"),
+  ("repair_command", SINGLE, None, constants.RPC_TMO_SLOW, [
+    ("cmd", None, "Command name"),
+    ("inp", None, "Input to be passed as stdin"),
+    ], None, None, "Runs repair command"),
   ("run_oob", SINGLE, None, constants.RPC_TMO_NORMAL, [
     ("oob_program", None, None),
     ("command", None, None),
diff --git a/lib/server/noded.py b/lib/server/noded.py
index bd876b3..14d70b8 100644
--- a/lib/server/noded.py
+++ b/lib/server/noded.py
@@ -1023,7 +1023,23 @@ class NodeRequestHandler(http.server.HttpServerHandler):
     """
     (cmd, ) = params
 
-    return backend.RunRestrictedCmd(cmd)
+    return backend.RunCmd(
+      cmd,
+      lock_file=pathutils.RESTRICTED_COMMANDS_LOCK_FILE,
+      path=pathutils.RESTRICTED_COMMANDS_DIR)
+
+  @staticmethod
+  def perspective_repair_command(params):
+    """ Run a repair command.
+
+    """
+    (cmd, inp, ) = params
+
+    return backend.RunCmd(
+      cmd,
+      lock_file=pathutils.REPAIR_COMMANDS_LOCK_FILE,
+      path=pathutils.REPAIR_COMMANDS_DIR,
+      inp=inp)
 
   @staticmethod
   def perspective_write_ssconf_files(params):
diff --git a/test/py/ganeti.backend_unittest.py 
b/test/py/ganeti.backend_unittest.py
index 5453c30..0ec3eba 100755
--- a/test/py/ganeti.backend_unittest.py
+++ b/test/py/ganeti.backend_unittest.py
@@ -376,7 +376,7 @@ def _GenericRestrictedCmdError(cmd):
   return "Executing command '%s' failed" % cmd
 
 
-class TestRunRestrictedCmd(unittest.TestCase):
+class TestRunCmd(unittest.TestCase):
   def setUp(self):
     self.tmpdir = tempfile.mkdtemp()
 
@@ -388,10 +388,10 @@ class TestRunRestrictedCmd(unittest.TestCase):
     sleep_fn = testutils.CallCounter(_SleepForRestrictedCmd)
     self.assertFalse(os.path.exists(lockfile))
     self.assertRaises(backend.RPCFail,
-                      backend.RunRestrictedCmd, "test",
+                      backend.RunCmd, "test",
                       _lock_timeout=NotImplemented,
-                      _lock_file=lockfile,
-                      _path=NotImplemented,
+                      lock_file=lockfile,
+                      path=NotImplemented,
                       _sleep_fn=sleep_fn,
                       _prepare_fn=NotImplemented,
                       _runcmd_fn=NotImplemented,
@@ -404,10 +404,10 @@ class TestRunRestrictedCmd(unittest.TestCase):
 
     result = False
     try:
-      backend.RunRestrictedCmd("test22717",
+      backend.RunCmd("test22717",
                                _lock_timeout=0.1,
-                               _lock_file=lockfile,
-                               _path=NotImplemented,
+                               lock_file=lockfile,
+                               path=NotImplemented,
                                _sleep_fn=sleep_fn,
                                _prepare_fn=NotImplemented,
                                _runcmd_fn=NotImplemented,
@@ -443,9 +443,9 @@ class TestRunRestrictedCmd(unittest.TestCase):
     prepare_fn = testutils.CallCounter(self._PrepareRaisingException)
 
     try:
-      backend.RunRestrictedCmd("test23122",
-                               _lock_timeout=1.0, _lock_file=lockfile,
-                               _path=NotImplemented, _runcmd_fn=NotImplemented,
+      backend.RunCmd("test23122",
+                               _lock_timeout=1.0, lock_file=lockfile,
+                               path=NotImplemented, _runcmd_fn=NotImplemented,
                                _sleep_fn=sleep_fn, _prepare_fn=prepare_fn,
                                _enabled=True)
     except backend.RPCFail, err:
@@ -468,9 +468,9 @@ class TestRunRestrictedCmd(unittest.TestCase):
     prepare_fn = testutils.CallCounter(self._PrepareFails)
 
     try:
-      backend.RunRestrictedCmd("test29327",
-                               _lock_timeout=1.0, _lock_file=lockfile,
-                               _path=NotImplemented, _runcmd_fn=NotImplemented,
+      backend.RunCmd("test29327",
+                               _lock_timeout=1.0, lock_file=lockfile,
+                               path=NotImplemented, _runcmd_fn=NotImplemented,
                                _sleep_fn=sleep_fn, _prepare_fn=prepare_fn,
                                _enabled=True)
     except backend.RPCFail, err:
@@ -489,7 +489,7 @@ class TestRunRestrictedCmd(unittest.TestCase):
     lockfile = utils.PathJoin(self.tmpdir, "lock")
 
     def fn(args, env=NotImplemented, reset_env=NotImplemented,
-           postfork_fn=NotImplemented):
+           postfork_fn=NotImplemented, input_fd=NotImplemented):
       self.assertEqual(args, [utils.PathJoin(self.tmpdir, "test3079")])
       self.assertEqual(env, {})
       self.assertTrue(reset_env)
@@ -519,9 +519,9 @@ class TestRunRestrictedCmd(unittest.TestCase):
     runcmd_fn = testutils.CallCounter(fn)
 
     try:
-      backend.RunRestrictedCmd("test3079",
-                               _lock_timeout=1.0, _lock_file=lockfile,
-                               _path=self.tmpdir, _runcmd_fn=runcmd_fn,
+      backend.RunCmd("test3079",
+                               _lock_timeout=1.0, lock_file=lockfile,
+                               path=self.tmpdir, _runcmd_fn=runcmd_fn,
                                _sleep_fn=sleep_fn, _prepare_fn=prepare_fn,
                                _enabled=True)
     except backend.RPCFail, err:
@@ -540,7 +540,7 @@ class TestRunRestrictedCmd(unittest.TestCase):
     lockfile = utils.PathJoin(self.tmpdir, "lock")
 
     def fn(args, env=NotImplemented, reset_env=NotImplemented,
-           postfork_fn=NotImplemented):
+           postfork_fn=NotImplemented, input_fd=NotImplemented):
       self.assertEqual(args, [utils.PathJoin(self.tmpdir, "test5667")])
       self.assertEqual(env, {})
       self.assertTrue(reset_env)
@@ -557,9 +557,9 @@ class TestRunRestrictedCmd(unittest.TestCase):
     prepare_fn = testutils.CallCounter(self._SuccessfulPrepare)
     runcmd_fn = testutils.CallCounter(fn)
 
-    result = backend.RunRestrictedCmd("test5667",
-                                      _lock_timeout=1.0, _lock_file=lockfile,
-                                      _path=self.tmpdir, _runcmd_fn=runcmd_fn,
+    result = backend.RunCmd("test5667",
+                                      _lock_timeout=1.0, lock_file=lockfile,
+                                      path=self.tmpdir, _runcmd_fn=runcmd_fn,
                                       _sleep_fn=sleep_fn,
                                       _prepare_fn=prepare_fn,
                                       _enabled=True)
@@ -571,10 +571,10 @@ class TestRunRestrictedCmd(unittest.TestCase):
 
   def testCommandsDisabled(self):
     try:
-      backend.RunRestrictedCmd("test",
+      backend.RunCmd("test",
                                _lock_timeout=NotImplemented,
-                               _lock_file=NotImplemented,
-                               _path=NotImplemented,
+                               lock_file=NotImplemented,
+                               path=NotImplemented,
                                _sleep_fn=NotImplemented,
                                _prepare_fn=NotImplemented,
                                _runcmd_fn=NotImplemented,
-- 
2.5.0.457.gab17608

Reply via email to