Revision b6522276

b/lib/errors.py
82 82
  pass
83 83

  
84 84

  
85
class PidFileLockError(LockError):
86
  """PID file is already locked by another process.
87

  
88
  """
89

  
90

  
85 91
class HypervisorError(GenericError):
86 92
  """Hypervisor-related exception.
87 93

  
b/lib/utils/io.py
701 701
      logging.exception("Can't read pid file")
702 702
    return 0
703 703

  
704
  return _ParsePidFileContents(raw_data)
705

  
706

  
707
def _ParsePidFileContents(data):
708
  """Tries to extract a process ID from a PID file's content.
709

  
710
  @type data: string
711
  @rtype: int
712
  @return: Zero if nothing could be read, PID otherwise
713

  
714
  """
704 715
  try:
705
    pid = int(raw_data)
706
  except (TypeError, ValueError), err:
716
    pid = int(data)
717
  except (TypeError, ValueError):
707 718
    logging.info("Can't parse pid file contents", exc_info=True)
708 719
    return 0
709

  
710
  return pid
720
  else:
721
    return pid
711 722

  
712 723

  
713 724
def ReadLockedPidFile(path):
......
834 845
  """
835 846
  # We don't rename nor truncate the file to not drop locks under
836 847
  # existing processes
837
  fd_pidfile = os.open(pidfile, os.O_WRONLY | os.O_CREAT, 0600)
848
  fd_pidfile = os.open(pidfile, os.O_RDWR | os.O_CREAT, 0600)
838 849

  
839 850
  # Lock the PID file (and fail if not possible to do so). Any code
840 851
  # wanting to send a signal to the daemon should try to lock the PID
841 852
  # file before reading it. If acquiring the lock succeeds, the daemon is
842 853
  # no longer running and the signal should not be sent.
843
  filelock.LockFile(fd_pidfile)
854
  try:
855
    filelock.LockFile(fd_pidfile)
856
  except errors.LockError:
857
    msg = ["PID file '%s' is already locked by another process" % pidfile]
858
    # Try to read PID file
859
    pid = _ParsePidFileContents(os.read(fd_pidfile, 100))
860
    if pid > 0:
861
      msg.append(", PID read from file is %s" % pid)
862
    raise errors.PidFileLockError("".join(msg))
844 863

  
845 864
  os.write(fd_pidfile, "%d\n" % os.getpid())
846 865

  
b/test/ganeti.utils.io_unittest.py
711 711
    read_pid = utils.ReadPidFile(pid_file)
712 712
    self.failUnlessEqual(read_pid, os.getpid())
713 713
    self.failUnless(utils.IsProcessAlive(read_pid))
714
    self.failUnlessRaises(errors.LockError, utils.WritePidFile,
714
    self.failUnlessRaises(errors.PidFileLockError, utils.WritePidFile,
715 715
                          self.f_dpn('test'))
716 716
    os.close(fd)
717 717
    utils.RemoveFile(self.f_dpn("test"))
......
747 747
    read_pid = utils.ReadPidFile(pid_file)
748 748
    self.failUnlessEqual(read_pid, new_pid)
749 749
    self.failUnless(utils.IsProcessAlive(new_pid))
750

  
751
    # Try writing to locked file
752
    try:
753
      utils.WritePidFile(pid_file)
754
    except errors.PidFileLockError, err:
755
      errmsg = str(err)
756
      self.assertTrue(errmsg.endswith(" %s" % new_pid),
757
                      msg=("Error message ('%s') didn't contain correct"
758
                           " PID (%s)" % (errmsg, new_pid)))
759
    else:
760
      self.fail("Writing to locked file didn't fail")
761

  
750 762
    utils.KillProcess(new_pid, waitpid=True)
751 763
    self.failIf(utils.IsProcessAlive(new_pid))
752 764
    utils.RemoveFile(self.f_dpn('child'))
753 765
    self.failUnlessRaises(errors.ProgrammerError, utils.KillProcess, 0)
754 766

  
767
  def testExceptionType(self):
768
    # Make sure the PID lock error is a subclass of LockError in case some code
769
    # depends on it
770
    self.assertTrue(issubclass(errors.PidFileLockError, errors.LockError))
771

  
755 772
  def tearDown(self):
756 773
    shutil.rmtree(self.dir)
757 774

  

Also available in: Unified diff