Statistics
| Branch: | Tag: | Revision:

root / lib / uidpool.py @ bc57fa8d

History | View | Annotate | Download (11.7 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 852bbc95 Balazs Lecz
from ganeti import utils
40 3e8dcc8a Michael Hanselmann
from ganeti import pathutils
41 6d127406 Balazs Lecz
42 6d127406 Balazs Lecz
43 6d127406 Balazs Lecz
def ParseUidPool(value, separator=None):
44 6d127406 Balazs Lecz
  """Parse a user-id pool definition.
45 6d127406 Balazs Lecz

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

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

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

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

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

109 fdad8c4d Balazs Lecz
  """
110 fdad8c4d Balazs Lecz
  for uid_range in remove_uids:
111 fdad8c4d Balazs Lecz
    if uid_range not in uid_pool:
112 fdad8c4d Balazs Lecz
      raise errors.OpPrereqError(
113 fdad8c4d Balazs Lecz
          "User-id range to be removed is not found in the current"
114 32d74a90 Thomas Thrainer
          " user-id pool: %s" % str(uid_range), errors.ECODE_INVAL)
115 fdad8c4d Balazs Lecz
    uid_pool.remove(uid_range)
116 fdad8c4d Balazs Lecz
117 fdad8c4d Balazs Lecz
118 23f1bf29 Michael Hanselmann
def _FormatUidRange(lower, higher):
119 852bbc95 Balazs Lecz
  """Convert a user-id range definition into a string.
120 852bbc95 Balazs Lecz

121 852bbc95 Balazs Lecz
  """
122 852bbc95 Balazs Lecz
  if lower == higher:
123 23f1bf29 Michael Hanselmann
    return str(lower)
124 852bbc95 Balazs Lecz
125 23f1bf29 Michael Hanselmann
  return "%s-%s" % (lower, higher)
126 852bbc95 Balazs Lecz
127 23f1bf29 Michael Hanselmann
128 23f1bf29 Michael Hanselmann
def FormatUidPool(uid_pool, separator=None):
129 852bbc95 Balazs Lecz
  """Convert the internal representation of the user-id pool into a string.
130 852bbc95 Balazs Lecz

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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