X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/ff20190d1f950cd66e2187a5b3bea41d7bf7c679..f44c88c743f8254677142c510d6e2031da4c7f71:/lib/uidpool.py diff --git a/lib/uidpool.py b/lib/uidpool.py index 80e7807..59401a4 100644 --- a/lib/uidpool.py +++ b/lib/uidpool.py @@ -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) @@ -218,7 +223,7 @@ class LockedUid(object): def GetUid(self): return self._uid - def __str__(self): + def AsStr(self): return "%s" % self._uid @@ -255,6 +260,7 @@ def RequestUnusedUid(all_uids): 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 @@ -263,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: @@ -292,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" @@ -330,12 +344,16 @@ def ReleaseUid(uid): 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): @@ -344,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: