Statistics
| Branch: | Tag: | Revision:

root / lib / uidpool.py @ 3e8dcc8a

History | View | Annotate | Download (11.8 kB)

1 6d127406 Balazs Lecz
#
2 6d127406 Balazs Lecz
#
3 6d127406 Balazs Lecz
4 2cfbc784 Iustin Pop
# Copyright (C) 2010, 2012 Google Inc.
5 6d127406 Balazs Lecz
#
6 6d127406 Balazs Lecz
# This program is free software; you can redistribute it and/or modify
7 6d127406 Balazs Lecz
# it under the terms of the GNU General Public License as published by
8 6d127406 Balazs Lecz
# the Free Software Foundation; either version 2 of the License, or
9 6d127406 Balazs Lecz
# (at your option) any later version.
10 6d127406 Balazs Lecz
#
11 6d127406 Balazs Lecz
# This program is distributed in the hope that it will be useful, but
12 6d127406 Balazs Lecz
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 6d127406 Balazs Lecz
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 6d127406 Balazs Lecz
# General Public License for more details.
15 6d127406 Balazs Lecz
#
16 6d127406 Balazs Lecz
# You should have received a copy of the GNU General Public License
17 6d127406 Balazs Lecz
# along with this program; if not, write to the Free Software
18 6d127406 Balazs Lecz
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 6d127406 Balazs Lecz
# 02110-1301, USA.
20 6d127406 Balazs Lecz
21 6d127406 Balazs Lecz
22 6d127406 Balazs Lecz
"""User-id pool related functions.
23 6d127406 Balazs Lecz

24 6d127406 Balazs Lecz
The user-id pool is cluster-wide configuration option.
25 6d127406 Balazs Lecz
It is stored as a list of user-id ranges.
26 6d127406 Balazs Lecz
This module contains functions used for manipulating the
27 6d127406 Balazs Lecz
user-id pool parameter and for requesting/returning user-ids
28 6d127406 Balazs Lecz
from the pool.
29 6d127406 Balazs Lecz

30 6d127406 Balazs Lecz
"""
31 6d127406 Balazs Lecz
32 649bcdd8 Balazs Lecz
import errno
33 649bcdd8 Balazs Lecz
import logging
34 649bcdd8 Balazs Lecz
import os
35 649bcdd8 Balazs Lecz
import random
36 649bcdd8 Balazs Lecz
37 6d127406 Balazs Lecz
from ganeti import errors
38 6d127406 Balazs Lecz
from ganeti import constants
39 196ec587 Guido Trotter
from ganeti import compat
40 852bbc95 Balazs Lecz
from ganeti import utils
41 3e8dcc8a Michael Hanselmann
from ganeti import pathutils
42 6d127406 Balazs Lecz
43 6d127406 Balazs Lecz
44 6d127406 Balazs Lecz
def ParseUidPool(value, separator=None):
45 6d127406 Balazs Lecz
  """Parse a user-id pool definition.
46 6d127406 Balazs Lecz

47 6d127406 Balazs Lecz
  @param value: string representation of the user-id pool.
48 6d127406 Balazs Lecz
                The accepted input format is a list of integer ranges.
49 6d127406 Balazs Lecz
                The boundaries are inclusive.
50 6d127406 Balazs Lecz
                Example: '1000-5000,8000,9000-9010'.
51 6d127406 Balazs Lecz
  @param separator: the separator character between the uids/uid-ranges.
52 6d127406 Balazs Lecz
                    Defaults to a comma.
53 6d127406 Balazs Lecz
  @return: a list of integer pairs (lower, higher range boundaries)
54 6d127406 Balazs Lecz

55 6d127406 Balazs Lecz
  """
56 6d127406 Balazs Lecz
  if separator is None:
57 6d127406 Balazs Lecz
    separator = ","
58 6d127406 Balazs Lecz
59 6d127406 Balazs Lecz
  ranges = []
60 6d127406 Balazs Lecz
  for range_def in value.split(separator):
61 6d127406 Balazs Lecz
    if not range_def:
62 6d127406 Balazs Lecz
      # Skip empty strings
63 6d127406 Balazs Lecz
      continue
64 6d127406 Balazs Lecz
    boundaries = range_def.split("-")
65 6d127406 Balazs Lecz
    n_elements = len(boundaries)
66 6d127406 Balazs Lecz
    if n_elements > 2:
67 6d127406 Balazs Lecz
      raise errors.OpPrereqError(
68 6d127406 Balazs Lecz
          "Invalid user-id range definition. Only one hyphen allowed: %s"
69 2cfbc784 Iustin Pop
          % boundaries, errors.ECODE_INVAL)
70 6d127406 Balazs Lecz
    try:
71 6d127406 Balazs Lecz
      lower = int(boundaries[0])
72 6d127406 Balazs Lecz
    except (ValueError, TypeError), err:
73 6d127406 Balazs Lecz
      raise errors.OpPrereqError("Invalid user-id value for lower boundary of"
74 6d127406 Balazs Lecz
                                 " user-id range: %s"
75 6d127406 Balazs Lecz
                                 % str(err), errors.ECODE_INVAL)
76 6d127406 Balazs Lecz
    try:
77 6d127406 Balazs Lecz
      higher = int(boundaries[n_elements - 1])
78 6d127406 Balazs Lecz
    except (ValueError, TypeError), err:
79 6d127406 Balazs Lecz
      raise errors.OpPrereqError("Invalid user-id value for higher boundary of"
80 6d127406 Balazs Lecz
                                 " user-id range: %s"
81 6d127406 Balazs Lecz
                                 % str(err), errors.ECODE_INVAL)
82 6d127406 Balazs Lecz
83 6d127406 Balazs Lecz
    ranges.append((lower, higher))
84 6d127406 Balazs Lecz
85 6d127406 Balazs Lecz
  ranges.sort()
86 6d127406 Balazs Lecz
  return ranges
87 6d127406 Balazs Lecz
88 6d127406 Balazs Lecz
89 fdad8c4d Balazs Lecz
def AddToUidPool(uid_pool, add_uids):
90 fdad8c4d Balazs Lecz
  """Add a list of user-ids/user-id ranges to a user-id pool.
91 fdad8c4d Balazs Lecz

92 fdad8c4d Balazs Lecz
  @param uid_pool: a user-id pool (list of integer tuples)
93 fdad8c4d Balazs Lecz
  @param add_uids: user-id ranges to be added to the pool
94 fdad8c4d Balazs Lecz
                   (list of integer tuples)
95 fdad8c4d Balazs Lecz

96 fdad8c4d Balazs Lecz
  """
97 fdad8c4d Balazs Lecz
  for uid_range in add_uids:
98 fdad8c4d Balazs Lecz
    if uid_range not in uid_pool:
99 fdad8c4d Balazs Lecz
      uid_pool.append(uid_range)
100 fdad8c4d Balazs Lecz
  uid_pool.sort()
101 fdad8c4d Balazs Lecz
102 fdad8c4d Balazs Lecz
103 fdad8c4d Balazs Lecz
def RemoveFromUidPool(uid_pool, remove_uids):
104 fdad8c4d Balazs Lecz
  """Remove a list of user-ids/user-id ranges from a user-id pool.
105 fdad8c4d Balazs Lecz

106 fdad8c4d Balazs Lecz
  @param uid_pool: a user-id pool (list of integer tuples)
107 fdad8c4d Balazs Lecz
  @param remove_uids: user-id ranges to be removed from the pool
108 fdad8c4d Balazs Lecz
                      (list of integer tuples)
109 fdad8c4d Balazs Lecz

110 fdad8c4d Balazs Lecz
  """
111 fdad8c4d Balazs Lecz
  for uid_range in remove_uids:
112 fdad8c4d Balazs Lecz
    if uid_range not in uid_pool:
113 fdad8c4d Balazs Lecz
      raise errors.OpPrereqError(
114 fdad8c4d Balazs Lecz
          "User-id range to be removed is not found in the current"
115 fdad8c4d Balazs Lecz
          " user-id pool: %s" % uid_range, errors.ECODE_INVAL)
116 fdad8c4d Balazs Lecz
    uid_pool.remove(uid_range)
117 fdad8c4d Balazs Lecz
118 fdad8c4d Balazs Lecz
119 196ec587 Guido Trotter
def _FormatUidRange(lower, higher, roman=False):
120 852bbc95 Balazs Lecz
  """Convert a user-id range definition into a string.
121 852bbc95 Balazs Lecz

122 852bbc95 Balazs Lecz
  """
123 852bbc95 Balazs Lecz
  if lower == higher:
124 196ec587 Guido Trotter
    return str(compat.TryToRoman(lower, convert=roman))
125 196ec587 Guido Trotter
  return "%s-%s" % (compat.TryToRoman(lower, convert=roman),
126 196ec587 Guido Trotter
                    compat.TryToRoman(higher, convert=roman))
127 852bbc95 Balazs Lecz
128 852bbc95 Balazs Lecz
129 196ec587 Guido Trotter
def FormatUidPool(uid_pool, separator=None, roman=False):
130 852bbc95 Balazs Lecz
  """Convert the internal representation of the user-id pool into a string.
131 852bbc95 Balazs Lecz

132 852bbc95 Balazs Lecz
  The output format is also accepted by ParseUidPool()
133 852bbc95 Balazs Lecz

134 852bbc95 Balazs Lecz
  @param uid_pool: a list of integer pairs representing UID ranges
135 0fbae49a Balazs Lecz
  @param separator: the separator character between the uids/uid-ranges.
136 0fbae49a Balazs Lecz
                    Defaults to ", ".
137 852bbc95 Balazs Lecz
  @return: a string with the formatted results
138 852bbc95 Balazs Lecz

139 852bbc95 Balazs Lecz
  """
140 0fbae49a Balazs Lecz
  if separator is None:
141 0fbae49a Balazs Lecz
    separator = ", "
142 196ec587 Guido Trotter
  return separator.join([_FormatUidRange(lower, higher, roman=roman)
143 0fbae49a Balazs Lecz
                         for lower, higher in uid_pool])
144 852bbc95 Balazs Lecz
145 852bbc95 Balazs Lecz
146 6d127406 Balazs Lecz
def CheckUidPool(uid_pool):
147 6d127406 Balazs Lecz
  """Sanity check user-id pool range definition values.
148 6d127406 Balazs Lecz

149 6d127406 Balazs Lecz
  @param uid_pool: a list of integer pairs (lower, higher range boundaries)
150 6d127406 Balazs Lecz

151 6d127406 Balazs Lecz
  """
152 6d127406 Balazs Lecz
  for lower, higher in uid_pool:
153 6d127406 Balazs Lecz
    if lower > higher:
154 6d127406 Balazs Lecz
      raise errors.OpPrereqError(
155 6d127406 Balazs Lecz
          "Lower user-id range boundary value (%s)"
156 6d127406 Balazs Lecz
          " is larger than higher boundary value (%s)" %
157 6d127406 Balazs Lecz
          (lower, higher), errors.ECODE_INVAL)
158 6d127406 Balazs Lecz
    if lower < constants.UIDPOOL_UID_MIN:
159 6d127406 Balazs Lecz
      raise errors.OpPrereqError(
160 6d127406 Balazs Lecz
          "Lower user-id range boundary value (%s)"
161 6d127406 Balazs Lecz
          " is smaller than UIDPOOL_UID_MIN (%s)." %
162 6d127406 Balazs Lecz
          (lower, constants.UIDPOOL_UID_MIN),
163 6d127406 Balazs Lecz
          errors.ECODE_INVAL)
164 6d127406 Balazs Lecz
    if higher > constants.UIDPOOL_UID_MAX:
165 6d127406 Balazs Lecz
      raise errors.OpPrereqError(
166 6d127406 Balazs Lecz
          "Higher user-id boundary value (%s)"
167 6d127406 Balazs Lecz
          " is larger than UIDPOOL_UID_MAX (%s)." %
168 6d127406 Balazs Lecz
          (higher, constants.UIDPOOL_UID_MAX),
169 6d127406 Balazs Lecz
          errors.ECODE_INVAL)
170 6d127406 Balazs Lecz
171 6d127406 Balazs Lecz
172 6d127406 Balazs Lecz
def ExpandUidPool(uid_pool):
173 6d127406 Balazs Lecz
  """Expands a uid-pool definition to a list of uids.
174 6d127406 Balazs Lecz

175 6d127406 Balazs Lecz
  @param uid_pool: a list of integer pairs (lower, higher range boundaries)
176 6d127406 Balazs Lecz
  @return: a list of integers
177 6d127406 Balazs Lecz

178 6d127406 Balazs Lecz
  """
179 6d127406 Balazs Lecz
  uids = set()
180 6d127406 Balazs Lecz
  for lower, higher in uid_pool:
181 6d127406 Balazs Lecz
    uids.update(range(lower, higher + 1))
182 6d127406 Balazs Lecz
  return list(uids)
183 649bcdd8 Balazs Lecz
184 649bcdd8 Balazs Lecz
185 649bcdd8 Balazs Lecz
def _IsUidUsed(uid):
186 649bcdd8 Balazs Lecz
  """Check if there is any process in the system running with the given user-id
187 649bcdd8 Balazs Lecz

188 c7e4b037 Balazs Lecz
  @type uid: integer
189 c7e4b037 Balazs Lecz
  @param uid: the user-id to be checked.
190 c7e4b037 Balazs Lecz

191 649bcdd8 Balazs Lecz
  """
192 649bcdd8 Balazs Lecz
  pgrep_command = [constants.PGREP, "-u", uid]
193 649bcdd8 Balazs Lecz
  result = utils.RunCmd(pgrep_command)
194 649bcdd8 Balazs Lecz
195 649bcdd8 Balazs Lecz
  if result.exit_code == 0:
196 649bcdd8 Balazs Lecz
    return True
197 649bcdd8 Balazs Lecz
  elif result.exit_code == 1:
198 649bcdd8 Balazs Lecz
    return False
199 649bcdd8 Balazs Lecz
  else:
200 649bcdd8 Balazs Lecz
    raise errors.CommandError("Running pgrep failed. exit code: %s"
201 649bcdd8 Balazs Lecz
                              % result.exit_code)
202 649bcdd8 Balazs Lecz
203 649bcdd8 Balazs Lecz
204 649bcdd8 Balazs Lecz
class LockedUid(object):
205 649bcdd8 Balazs Lecz
  """Class representing a locked user-id in the uid-pool.
206 649bcdd8 Balazs Lecz

207 649bcdd8 Balazs Lecz
  This binds together a userid and a lock.
208 649bcdd8 Balazs Lecz

209 649bcdd8 Balazs Lecz
  """
210 649bcdd8 Balazs Lecz
  def __init__(self, uid, lock):
211 649bcdd8 Balazs Lecz
    """Constructor
212 649bcdd8 Balazs Lecz

213 649bcdd8 Balazs Lecz
    @param uid: a user-id
214 649bcdd8 Balazs Lecz
    @param lock: a utils.FileLock object
215 649bcdd8 Balazs Lecz

216 649bcdd8 Balazs Lecz
    """
217 649bcdd8 Balazs Lecz
    self._uid = uid
218 649bcdd8 Balazs Lecz
    self._lock = lock
219 649bcdd8 Balazs Lecz
220 649bcdd8 Balazs Lecz
  def Unlock(self):
221 649bcdd8 Balazs Lecz
    # Release the exclusive lock and close the filedescriptor
222 649bcdd8 Balazs Lecz
    self._lock.Close()
223 649bcdd8 Balazs Lecz
224 14850c5e Guido Trotter
  def GetUid(self):
225 14850c5e Guido Trotter
    return self._uid
226 14850c5e Guido Trotter
227 c7e4b037 Balazs Lecz
  def AsStr(self):
228 649bcdd8 Balazs Lecz
    return "%s" % self._uid
229 649bcdd8 Balazs Lecz
230 649bcdd8 Balazs Lecz
231 649bcdd8 Balazs Lecz
def RequestUnusedUid(all_uids):
232 649bcdd8 Balazs Lecz
  """Tries to find an unused uid from the uid-pool, locks it and returns it.
233 649bcdd8 Balazs Lecz

234 d3b790bb Balazs Lecz
  Usage pattern
235 d3b790bb Balazs Lecz
  =============
236 649bcdd8 Balazs Lecz

237 d3b790bb Balazs Lecz
  1. When starting a process::
238 649bcdd8 Balazs Lecz

239 649bcdd8 Balazs Lecz
      from ganeti import ssconf
240 649bcdd8 Balazs Lecz
      from ganeti import uidpool
241 649bcdd8 Balazs Lecz

242 649bcdd8 Balazs Lecz
      # Get list of all user-ids in the uid-pool from ssconf
243 649bcdd8 Balazs Lecz
      ss = ssconf.SimpleStore()
244 d3b790bb Balazs Lecz
      uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\\n")
245 649bcdd8 Balazs Lecz
      all_uids = set(uidpool.ExpandUidPool(uid_pool))
246 649bcdd8 Balazs Lecz

247 649bcdd8 Balazs Lecz
      uid = uidpool.RequestUnusedUid(all_uids)
248 649bcdd8 Balazs Lecz
      try:
249 649bcdd8 Balazs Lecz
        <start a process with the UID>
250 649bcdd8 Balazs Lecz
        # Once the process is started, we can release the file lock
251 649bcdd8 Balazs Lecz
        uid.Unlock()
252 649bcdd8 Balazs Lecz
      except ..., err:
253 649bcdd8 Balazs Lecz
        # Return the UID to the pool
254 649bcdd8 Balazs Lecz
        uidpool.ReleaseUid(uid)
255 649bcdd8 Balazs Lecz

256 d3b790bb Balazs Lecz
  2. Stopping a process::
257 649bcdd8 Balazs Lecz

258 649bcdd8 Balazs Lecz
      from ganeti import uidpool
259 649bcdd8 Balazs Lecz

260 649bcdd8 Balazs Lecz
      uid = <get the UID the process is running under>
261 649bcdd8 Balazs Lecz
      <stop the process>
262 649bcdd8 Balazs Lecz
      uidpool.ReleaseUid(uid)
263 649bcdd8 Balazs Lecz

264 c7e4b037 Balazs Lecz
  @type all_uids: set of integers
265 649bcdd8 Balazs Lecz
  @param all_uids: a set containing all the user-ids in the user-id pool
266 649bcdd8 Balazs Lecz
  @return: a LockedUid object representing the unused uid. It's the caller's
267 649bcdd8 Balazs Lecz
           responsibility to unlock the uid once an instance is started with
268 649bcdd8 Balazs Lecz
           this uid.
269 649bcdd8 Balazs Lecz

270 649bcdd8 Balazs Lecz
  """
271 649bcdd8 Balazs Lecz
  # Create the lock dir if it's not yet present
272 649bcdd8 Balazs Lecz
  try:
273 3e8dcc8a Michael Hanselmann
    utils.EnsureDirs([(pathutils.UIDPOOL_LOCKDIR, 0755)])
274 649bcdd8 Balazs Lecz
  except errors.GenericError, err:
275 649bcdd8 Balazs Lecz
    raise errors.LockError("Failed to create user-id pool lock dir: %s" % err)
276 649bcdd8 Balazs Lecz
277 649bcdd8 Balazs Lecz
  # Get list of currently used uids from the filesystem
278 649bcdd8 Balazs Lecz
  try:
279 c7e4b037 Balazs Lecz
    taken_uids = set()
280 3e8dcc8a Michael Hanselmann
    for taken_uid in os.listdir(pathutils.UIDPOOL_LOCKDIR):
281 c7e4b037 Balazs Lecz
      try:
282 c7e4b037 Balazs Lecz
        taken_uid = int(taken_uid)
283 c7e4b037 Balazs Lecz
      except ValueError, err:
284 c7e4b037 Balazs Lecz
        # Skip directory entries that can't be converted into an integer
285 c7e4b037 Balazs Lecz
        continue
286 c7e4b037 Balazs Lecz
      taken_uids.add(taken_uid)
287 649bcdd8 Balazs Lecz
  except OSError, err:
288 649bcdd8 Balazs Lecz
    raise errors.LockError("Failed to get list of used user-ids: %s" % err)
289 649bcdd8 Balazs Lecz
290 c7e4b037 Balazs Lecz
  # Filter out spurious entries from the directory listing
291 c7e4b037 Balazs Lecz
  taken_uids = all_uids.intersection(taken_uids)
292 c7e4b037 Balazs Lecz
293 649bcdd8 Balazs Lecz
  # Remove the list of used uids from the list of all uids
294 649bcdd8 Balazs Lecz
  unused_uids = list(all_uids - taken_uids)
295 649bcdd8 Balazs Lecz
  if not unused_uids:
296 649bcdd8 Balazs Lecz
    logging.info("All user-ids in the uid-pool are marked 'taken'")
297 649bcdd8 Balazs Lecz
298 649bcdd8 Balazs Lecz
  # Randomize the order of the unused user-id list
299 649bcdd8 Balazs Lecz
  random.shuffle(unused_uids)
300 649bcdd8 Balazs Lecz
301 649bcdd8 Balazs Lecz
  # Randomize the order of the unused user-id list
302 649bcdd8 Balazs Lecz
  taken_uids = list(taken_uids)
303 649bcdd8 Balazs Lecz
  random.shuffle(taken_uids)
304 649bcdd8 Balazs Lecz
305 649bcdd8 Balazs Lecz
  for uid in (unused_uids + taken_uids):
306 649bcdd8 Balazs Lecz
    try:
307 649bcdd8 Balazs Lecz
      # Create the lock file
308 649bcdd8 Balazs Lecz
      # Note: we don't care if it exists. Only the fact that we can
309 649bcdd8 Balazs Lecz
      # (or can't) lock it later is what matters.
310 3e8dcc8a Michael Hanselmann
      uid_path = utils.PathJoin(pathutils.UIDPOOL_LOCKDIR, str(uid))
311 649bcdd8 Balazs Lecz
      lock = utils.FileLock.Open(uid_path)
312 649bcdd8 Balazs Lecz
    except OSError, err:
313 649bcdd8 Balazs Lecz
      raise errors.LockError("Failed to create lockfile for user-id %s: %s"
314 649bcdd8 Balazs Lecz
                             % (uid, err))
315 649bcdd8 Balazs Lecz
    try:
316 649bcdd8 Balazs Lecz
      # Try acquiring an exclusive lock on the lock file
317 649bcdd8 Balazs Lecz
      lock.Exclusive()
318 649bcdd8 Balazs Lecz
      # Check if there is any process running with this user-id
319 649bcdd8 Balazs Lecz
      if _IsUidUsed(uid):
320 649bcdd8 Balazs Lecz
        logging.debug("There is already a process running under"
321 649bcdd8 Balazs Lecz
                      " user-id %s", uid)
322 649bcdd8 Balazs Lecz
        lock.Unlock()
323 649bcdd8 Balazs Lecz
        continue
324 649bcdd8 Balazs Lecz
      return LockedUid(uid, lock)
325 649bcdd8 Balazs Lecz
    except IOError, err:
326 649bcdd8 Balazs Lecz
      if err.errno == errno.EAGAIN:
327 649bcdd8 Balazs Lecz
        # The file is already locked, let's skip it and try another unused uid
328 649bcdd8 Balazs Lecz
        logging.debug("Lockfile for user-id is already locked %s: %s", uid, err)
329 649bcdd8 Balazs Lecz
        continue
330 649bcdd8 Balazs Lecz
    except errors.LockError, err:
331 649bcdd8 Balazs Lecz
      # There was an unexpected error while trying to lock the file
332 649bcdd8 Balazs Lecz
      logging.error("Failed to lock the lockfile for user-id %s: %s", uid, err)
333 649bcdd8 Balazs Lecz
      raise
334 649bcdd8 Balazs Lecz
335 649bcdd8 Balazs Lecz
  raise errors.LockError("Failed to find an unused user-id")
336 649bcdd8 Balazs Lecz
337 649bcdd8 Balazs Lecz
338 649bcdd8 Balazs Lecz
def ReleaseUid(uid):
339 649bcdd8 Balazs Lecz
  """This should be called when the given user-id is no longer in use.
340 649bcdd8 Balazs Lecz

341 ff20190d Guido Trotter
  @type uid: LockedUid or integer
342 ff20190d Guido Trotter
  @param uid: the uid to release back to the pool
343 ff20190d Guido Trotter

344 649bcdd8 Balazs Lecz
  """
345 ff20190d Guido Trotter
  if isinstance(uid, LockedUid):
346 ff20190d Guido Trotter
    # Make sure we release the exclusive lock, if there is any
347 ff20190d Guido Trotter
    uid.Unlock()
348 c7e4b037 Balazs Lecz
    uid_filename = uid.AsStr()
349 c7e4b037 Balazs Lecz
  else:
350 c7e4b037 Balazs Lecz
    uid_filename = str(uid)
351 c7e4b037 Balazs Lecz
352 649bcdd8 Balazs Lecz
  try:
353 3e8dcc8a Michael Hanselmann
    uid_path = utils.PathJoin(pathutils.UIDPOOL_LOCKDIR, uid_filename)
354 649bcdd8 Balazs Lecz
    os.remove(uid_path)
355 649bcdd8 Balazs Lecz
  except OSError, err:
356 649bcdd8 Balazs Lecz
    raise errors.LockError("Failed to remove user-id lockfile"
357 c7e4b037 Balazs Lecz
                           " for user-id %s: %s" % (uid_filename, err))
358 5833b7e6 Balazs Lecz
359 5833b7e6 Balazs Lecz
360 5833b7e6 Balazs Lecz
def ExecWithUnusedUid(fn, all_uids, *args, **kwargs):
361 5833b7e6 Balazs Lecz
  """Execute a callable and provide an unused user-id in its kwargs.
362 5833b7e6 Balazs Lecz

363 5833b7e6 Balazs Lecz
  This wrapper function provides a simple way to handle the requesting,
364 5833b7e6 Balazs Lecz
  unlocking and releasing a user-id.
365 5833b7e6 Balazs Lecz
  "fn" is called by passing a "uid" keyword argument that
366 c7e4b037 Balazs Lecz
  contains an unused user-id (as an integer) selected from the set of user-ids
367 5833b7e6 Balazs Lecz
  passed in all_uids.
368 5833b7e6 Balazs Lecz
  If there is an error while executing "fn", the user-id is returned
369 5833b7e6 Balazs Lecz
  to the pool.
370 5833b7e6 Balazs Lecz

371 c7e4b037 Balazs Lecz
  @param fn: a callable that accepts a keyword argument called "uid"
372 c7e4b037 Balazs Lecz
  @type all_uids: a set of integers
373 5833b7e6 Balazs Lecz
  @param all_uids: a set containing all user-ids in the user-id pool
374 5833b7e6 Balazs Lecz

375 5833b7e6 Balazs Lecz
  """
376 5833b7e6 Balazs Lecz
  uid = RequestUnusedUid(all_uids)
377 c7e4b037 Balazs Lecz
  kwargs["uid"] = uid.GetUid()
378 5833b7e6 Balazs Lecz
  try:
379 5833b7e6 Balazs Lecz
    return_value = fn(*args, **kwargs)
380 5833b7e6 Balazs Lecz
  except:
381 5833b7e6 Balazs Lecz
    # The failure of "callabe" means that starting a process with the uid
382 5833b7e6 Balazs Lecz
    # failed, so let's put the uid back into the pool.
383 5833b7e6 Balazs Lecz
    ReleaseUid(uid)
384 5833b7e6 Balazs Lecz
    raise
385 5833b7e6 Balazs Lecz
  uid.Unlock()
386 5833b7e6 Balazs Lecz
  return return_value