build_chroot: hard-code the version of blaze-builder
[ganeti-local] / lib / uidpool.py
index 21c9113..59401a4 100644 (file)
@@ -1,7 +1,7 @@
 #
 #
 
-# Copyright (C) 2010 Google Inc.
+# Copyright (C) 2010, 2012 Google Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -37,6 +37,7 @@ import random
 from ganeti import errors
 from ganeti import constants
 from ganeti import utils
+from ganeti import pathutils
 
 
 def ParseUidPool(value, separator=None):
@@ -64,7 +65,7 @@ def ParseUidPool(value, separator=None):
     if n_elements > 2:
       raise errors.OpPrereqError(
           "Invalid user-id range definition. Only one hyphen allowed: %s"
-          % boundaries)
+          % boundaries, errors.ECODE_INVAL)
     try:
       lower = int(boundaries[0])
     except (ValueError, TypeError), err:
@@ -110,7 +111,7 @@ def RemoveFromUidPool(uid_pool, remove_uids):
     if uid_range not in uid_pool:
       raise errors.OpPrereqError(
           "User-id range to be removed is not found in the current"
-          " user-id pool: %s" % uid_range, errors.ECODE_INVAL)
+          " user-id pool: %s" % str(uid_range), errors.ECODE_INVAL)
     uid_pool.remove(uid_range)
 
 
@@ -120,6 +121,7 @@ def _FormatUidRange(lower, higher):
   """
   if lower == higher:
     return str(lower)
+
   return "%s-%s" % (lower, higher)
 
 
@@ -182,6 +184,9 @@ def ExpandUidPool(uid_pool):
 def _IsUidUsed(uid):
   """Check if there is any process in the system running with the given user-id
 
+  @type uid: integer
+  @param uid: the user-id to be checked.
+
   """
   pgrep_command = [constants.PGREP, "-u", uid]
   result = utils.RunCmd(pgrep_command)
@@ -215,23 +220,27 @@ class LockedUid(object):
     # Release the exclusive lock and close the filedescriptor
     self._lock.Close()
 
-  def __str__(self):
+  def GetUid(self):
+    return self._uid
+
+  def AsStr(self):
     return "%s" % self._uid
 
 
 def RequestUnusedUid(all_uids):
   """Tries to find an unused uid from the uid-pool, locks it and returns it.
 
-  Usage pattern:
+  Usage pattern
+  =============
 
-    1) When starting a process
+  1. When starting a process::
 
       from ganeti import ssconf
       from ganeti import uidpool
 
       # Get list of all user-ids in the uid-pool from ssconf
       ss = ssconf.SimpleStore()
-      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
+      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\\n")
       all_uids = set(uidpool.ExpandUidPool(uid_pool))
 
       uid = uidpool.RequestUnusedUid(all_uids)
@@ -243,7 +252,7 @@ def RequestUnusedUid(all_uids):
         # Return the UID to the pool
         uidpool.ReleaseUid(uid)
 
-    2) Stopping a process
+  2. Stopping a process::
 
       from ganeti import uidpool
 
@@ -251,6 +260,7 @@ def RequestUnusedUid(all_uids):
       <stop the process>
       uidpool.ReleaseUid(uid)
 
+  @type all_uids: set of integers
   @param all_uids: a set containing all the user-ids in the user-id pool
   @return: a LockedUid object representing the unused uid. It's the caller's
            responsibility to unlock the uid once an instance is started with
@@ -259,18 +269,26 @@ def RequestUnusedUid(all_uids):
   """
   # Create the lock dir if it's not yet present
   try:
-    utils.EnsureDirs([(constants.UIDPOOL_LOCKDIR, 0755)])
+    utils.EnsureDirs([(pathutils.UIDPOOL_LOCKDIR, 0755)])
   except errors.GenericError, err:
     raise errors.LockError("Failed to create user-id pool lock dir: %s" % err)
 
   # Get list of currently used uids from the filesystem
   try:
-    taken_uids = set(os.listdir(constants.UIDPOOL_LOCKDIR))
-    # Filter out spurious entries from the directory listing
-    taken_uids = all_uids.intersection(taken_uids)
+    taken_uids = set()
+    for taken_uid in os.listdir(pathutils.UIDPOOL_LOCKDIR):
+      try:
+        taken_uid = int(taken_uid)
+      except ValueError, err:
+        # Skip directory entries that can't be converted into an integer
+        continue
+      taken_uids.add(taken_uid)
   except OSError, err:
     raise errors.LockError("Failed to get list of used user-ids: %s" % err)
 
+  # Filter out spurious entries from the directory listing
+  taken_uids = all_uids.intersection(taken_uids)
+
   # Remove the list of used uids from the list of all uids
   unused_uids = list(all_uids - taken_uids)
   if not unused_uids:
@@ -288,7 +306,7 @@ def RequestUnusedUid(all_uids):
       # Create the lock file
       # Note: we don't care if it exists. Only the fact that we can
       # (or can't) lock it later is what matters.
-      uid_path = utils.PathJoin(constants.UIDPOOL_LOCKDIR, str(uid))
+      uid_path = utils.PathJoin(pathutils.UIDPOOL_LOCKDIR, str(uid))
       lock = utils.FileLock.Open(uid_path)
     except OSError, err:
       raise errors.LockError("Failed to create lockfile for user-id %s: %s"
@@ -319,15 +337,23 @@ def RequestUnusedUid(all_uids):
 def ReleaseUid(uid):
   """This should be called when the given user-id is no longer in use.
 
+  @type uid: LockedUid or integer
+  @param uid: the uid to release back to the pool
+
   """
-  # Make sure we release the exclusive lock, if there is any
-  uid.Unlock()
+  if isinstance(uid, LockedUid):
+    # Make sure we release the exclusive lock, if there is any
+    uid.Unlock()
+    uid_filename = uid.AsStr()
+  else:
+    uid_filename = str(uid)
+
   try:
-    uid_path = utils.PathJoin(constants.UIDPOOL_LOCKDIR, str(uid))
+    uid_path = utils.PathJoin(pathutils.UIDPOOL_LOCKDIR, uid_filename)
     os.remove(uid_path)
   except OSError, err:
     raise errors.LockError("Failed to remove user-id lockfile"
-                           " for user-id %s: %s" % (uid, err))
+                           " for user-id %s: %s" % (uid_filename, err))
 
 
 def ExecWithUnusedUid(fn, all_uids, *args, **kwargs):
@@ -336,17 +362,18 @@ def ExecWithUnusedUid(fn, all_uids, *args, **kwargs):
   This wrapper function provides a simple way to handle the requesting,
   unlocking and releasing a user-id.
   "fn" is called by passing a "uid" keyword argument that
-  contains an unused user-id (as a string) selected from the set of user-ids
+  contains an unused user-id (as an integer) selected from the set of user-ids
   passed in all_uids.
   If there is an error while executing "fn", the user-id is returned
   to the pool.
 
-  @param fn: a callable
+  @param fn: a callable that accepts a keyword argument called "uid"
+  @type all_uids: a set of integers
   @param all_uids: a set containing all user-ids in the user-id pool
 
   """
   uid = RequestUnusedUid(all_uids)
-  kwargs["uid"] = str(uid)
+  kwargs["uid"] = uid.GetUid()
   try:
     return_value = fn(*args, **kwargs)
   except: