diff --git a/lib/utils.py b/lib/utils.py
index a9b71b5fbb3c0161d298dc0ead40a5f0027b8588..6744358222ce075825914cd0ac502a82d3f02c46 100644
--- a/lib/utils.py
+++ b/lib/utils.py
@@ -1092,6 +1092,35 @@ def RemovePidFile(name):
     pass
 
 
+def KillProcess(pid, signal=signal.SIGTERM, timeout=30):
+  """Kill a process given by its pid.
+
+  @type pid: int
+  @param pid: The PID to terminate.
+  @type signal: int
+  @param signal: The signal to send, by default SIGTERM
+  @type timeout: int
+  @param timeout: The timeout after which, if the process is still alive,
+                  a SIGKILL will be sent. If not positive, no such checking
+                  will be done
+
+  """
+  if pid <= 0:
+    # kill with pid=0 == suicide
+    raise errors.ProgrammerError("Invalid pid given '%s'" % pid)
+
+  if not IsProcessAlive(pid):
+    return
+  os.kill(pid, signal)
+  if timeout <= 0:
+    return
+  end = time.time() + timeout
+  while time.time() < end and IsProcessAlive(pid):
+    time.sleep(0.1)
+  if IsProcessAlive(pid):
+    os.kill(pid, signal.SIGKILL)
+
+
 def FindFile(name, search_path, test=os.path.exists):
   """Look for a filesystem object in a given path.
 
diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py
index 23a8b6b75fb52f27e31bf70b18895131d66a80b0..9a9eed94880bc5cbfbb519e78605f25134e863de 100755
--- a/test/ganeti.utils_unittest.py
+++ b/test/ganeti.utils_unittest.py
@@ -43,7 +43,8 @@ from ganeti.utils import IsProcessAlive, RunCmd, \
      ParseUnit, AddAuthorizedKey, RemoveAuthorizedKey, \
      ShellQuote, ShellQuoteArgs, TcpPing, ListVisibleFiles, \
      SetEtcHostsEntry, RemoveEtcHostsEntry, FirstFree
-from ganeti.errors import LockError, UnitParseError, GenericError
+from ganeti.errors import LockError, UnitParseError, GenericError, \
+     ProgrammerError
 
 def _ChildHandler(signal, stack):
   global _ChildFlag
@@ -132,6 +133,27 @@ class TestPidFileFunctions(unittest.TestCase):
     self.failIf(os.path.exists(pid_file),
                 "PID file should not exist anymore")
 
+  def testKill(self):
+    pid_file = self.f_dpn('child')
+    r_fd, w_fd = os.pipe()
+    new_pid = os.fork()
+    if new_pid == 0: #child
+      utils.WritePidFile('child')
+      os.write(w_fd, 'a')
+      signal.pause()
+      os._exit(0)
+      return
+    # else we are in the parent
+    # wait until the child has written the pid file
+    os.read(r_fd, 1)
+    read_pid = utils.ReadPidFile(pid_file)
+    self.failUnlessEqual(read_pid, new_pid)
+    self.failUnless(utils.IsProcessAlive(new_pid))
+    utils.KillProcess(new_pid)
+    self.failIf(utils.IsProcessAlive(new_pid))
+    utils.RemovePidFile('child')
+    self.failUnlessRaises(ProgrammerError, utils.KillProcess, 0)
+
   def tearDown(self):
     for name in os.listdir(self.dir):
       os.unlink(os.path.join(self.dir, name))