| Branch: | Tag: | Revision:

root / lib / utils / @ adc523ab

History | View | Annotate | Download (21 kB)

1 2f31098c Iustin Pop
2 a8083063 Iustin Pop
3 a8083063 Iustin Pop
4 4fd029cf Michael Hanselmann
# Copyright (C) 2006, 2007, 2010, 2011 Google Inc.
5 a8083063 Iustin Pop
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 a8083063 Iustin Pop
22 58885d79 Iustin Pop
"""Ganeti utility module.
23 58885d79 Iustin Pop

24 58885d79 Iustin Pop
This module holds functions that can be used in both daemons (all) and
25 58885d79 Iustin Pop
the command line scripts.
26 899d2a81 Michael Hanselmann

27 a8083063 Iustin Pop
28 a8083063 Iustin Pop
29 63fc4229 Michael Hanselmann
# Allow wildcard import in pylint: disable-msg=W0401
30 a8083063 Iustin Pop
31 a8083063 Iustin Pop
import os
32 a8083063 Iustin Pop
import re
33 4ca1b175 Alexander Schreiber
import errno
34 2f8b60b3 Iustin Pop
import pwd
35 78feb6fb Guido Trotter
import itertools
36 9c233417 Iustin Pop
import select
37 bb698c1f Iustin Pop
import logging
38 de499029 Michael Hanselmann
import signal
39 a8083063 Iustin Pop
40 a8083063 Iustin Pop
from ganeti import errors
41 3aecd2c7 Iustin Pop
from ganeti import constants
42 716a32cb Guido Trotter
from ganeti import compat
43 a8083063 Iustin Pop
44 63fc4229 Michael Hanselmann
from ganeti.utils.algo import *
45 63fc4229 Michael Hanselmann
from ganeti.utils.filelock import *
46 63fc4229 Michael Hanselmann
from ganeti.utils.hash import *
47 63fc4229 Michael Hanselmann
from import *
48 63fc4229 Michael Hanselmann
from ganeti.utils.log import *
49 63fc4229 Michael Hanselmann
from ganeti.utils.mlock import *
50 63fc4229 Michael Hanselmann
from ganeti.utils.nodesetup import *
51 63fc4229 Michael Hanselmann
from ganeti.utils.process import *
52 63fc4229 Michael Hanselmann
from ganeti.utils.retry import *
53 63fc4229 Michael Hanselmann
from ganeti.utils.text import *
54 63fc4229 Michael Hanselmann
from ganeti.utils.wrapper import *
55 63fc4229 Michael Hanselmann
from ganeti.utils.x509 import *
56 16abfbc2 Alexander Schreiber
57 58885d79 Iustin Pop
58 28f34048 Michael Hanselmann
_VALID_SERVICE_NAME_RE = re.compile("^[-_.a-zA-Z0-9]{1,128}$")
59 28f34048 Michael Hanselmann
60 05636402 Guido Trotter
UUID_RE = re.compile('^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-'
61 05636402 Guido Trotter
62 05636402 Guido Trotter
63 7c0d6283 Michael Hanselmann
64 a5728081 Guido Trotter
def ForceDictType(target, key_types, allowed_values=None):
65 a5728081 Guido Trotter
  """Force the values of a dict to have certain types.
66 a5728081 Guido Trotter

67 a5728081 Guido Trotter
  @type target: dict
68 a5728081 Guido Trotter
  @param target: the dict to update
69 a5728081 Guido Trotter
  @type key_types: dict
70 a5728081 Guido Trotter
  @param key_types: dict mapping target dict keys to types
71 a5728081 Guido Trotter
                    in constants.ENFORCEABLE_TYPES
72 a5728081 Guido Trotter
  @type allowed_values: list
73 a5728081 Guido Trotter
  @keyword allowed_values: list of specially allowed values
74 a5728081 Guido Trotter

75 a5728081 Guido Trotter
76 a5728081 Guido Trotter
  if allowed_values is None:
77 a5728081 Guido Trotter
    allowed_values = []
78 a5728081 Guido Trotter
79 8b46606c Guido Trotter
  if not isinstance(target, dict):
80 8b46606c Guido Trotter
    msg = "Expected dictionary, got '%s'" % target
81 8b46606c Guido Trotter
    raise errors.TypeEnforcementError(msg)
82 8b46606c Guido Trotter
83 a5728081 Guido Trotter
  for key in target:
84 a5728081 Guido Trotter
    if key not in key_types:
85 58a59652 Iustin Pop
      msg = "Unknown parameter '%s'" % key
86 a5728081 Guido Trotter
      raise errors.TypeEnforcementError(msg)
87 a5728081 Guido Trotter
88 a5728081 Guido Trotter
    if target[key] in allowed_values:
89 a5728081 Guido Trotter
90 a5728081 Guido Trotter
91 29921401 Iustin Pop
    ktype = key_types[key]
92 29921401 Iustin Pop
    if ktype not in constants.ENFORCEABLE_TYPES:
93 29921401 Iustin Pop
      msg = "'%s' has non-enforceable type %s" % (key, ktype)
94 a5728081 Guido Trotter
      raise errors.ProgrammerError(msg)
95 a5728081 Guido Trotter
96 59525e1f Michael Hanselmann
    if ktype in (constants.VTYPE_STRING, constants.VTYPE_MAYBE_STRING):
97 59525e1f Michael Hanselmann
      if target[key] is None and ktype == constants.VTYPE_MAYBE_STRING:
98 59525e1f Michael Hanselmann
99 59525e1f Michael Hanselmann
      elif not isinstance(target[key], basestring):
100 a5728081 Guido Trotter
        if isinstance(target[key], bool) and not target[key]:
101 a5728081 Guido Trotter
          target[key] = ''
102 a5728081 Guido Trotter
103 a5728081 Guido Trotter
          msg = "'%s' (value %s) is not a valid string" % (key, target[key])
104 a5728081 Guido Trotter
          raise errors.TypeEnforcementError(msg)
105 29921401 Iustin Pop
    elif ktype == constants.VTYPE_BOOL:
106 a5728081 Guido Trotter
      if isinstance(target[key], basestring) and target[key]:
107 a5728081 Guido Trotter
        if target[key].lower() == constants.VALUE_FALSE:
108 a5728081 Guido Trotter
          target[key] = False
109 a5728081 Guido Trotter
        elif target[key].lower() == constants.VALUE_TRUE:
110 a5728081 Guido Trotter
          target[key] = True
111 a5728081 Guido Trotter
112 a5728081 Guido Trotter
          msg = "'%s' (value %s) is not a valid boolean" % (key, target[key])
113 a5728081 Guido Trotter
          raise errors.TypeEnforcementError(msg)
114 a5728081 Guido Trotter
      elif target[key]:
115 a5728081 Guido Trotter
        target[key] = True
116 a5728081 Guido Trotter
117 a5728081 Guido Trotter
        target[key] = False
118 29921401 Iustin Pop
    elif ktype == constants.VTYPE_SIZE:
119 a5728081 Guido Trotter
120 a5728081 Guido Trotter
        target[key] = ParseUnit(target[key])
121 a5728081 Guido Trotter
      except errors.UnitParseError, err:
122 a5728081 Guido Trotter
        msg = "'%s' (value %s) is not a valid size. error: %s" % \
123 a5728081 Guido Trotter
              (key, target[key], err)
124 a5728081 Guido Trotter
        raise errors.TypeEnforcementError(msg)
125 29921401 Iustin Pop
    elif ktype == constants.VTYPE_INT:
126 a5728081 Guido Trotter
127 a5728081 Guido Trotter
        target[key] = int(target[key])
128 a5728081 Guido Trotter
      except (ValueError, TypeError):
129 a5728081 Guido Trotter
        msg = "'%s' (value %s) is not a valid integer" % (key, target[key])
130 a5728081 Guido Trotter
        raise errors.TypeEnforcementError(msg)
131 a5728081 Guido Trotter
132 a5728081 Guido Trotter
133 28f34048 Michael Hanselmann
def ValidateServiceName(name):
134 28f34048 Michael Hanselmann
  """Validate the given service name.
135 28f34048 Michael Hanselmann

136 28f34048 Michael Hanselmann
  @type name: number or string
137 28f34048 Michael Hanselmann
  @param name: Service name or port specification
138 28f34048 Michael Hanselmann

139 28f34048 Michael Hanselmann
140 28f34048 Michael Hanselmann
141 28f34048 Michael Hanselmann
    numport = int(name)
142 28f34048 Michael Hanselmann
  except (ValueError, TypeError):
143 28f34048 Michael Hanselmann
    # Non-numeric service name
144 28f34048 Michael Hanselmann
    valid = _VALID_SERVICE_NAME_RE.match(name)
145 28f34048 Michael Hanselmann
146 28f34048 Michael Hanselmann
    # Numeric port (protocols other than TCP or UDP might need adjustments
147 28f34048 Michael Hanselmann
    # here)
148 28f34048 Michael Hanselmann
    valid = (numport >= 0 and numport < (1 << 16))
149 28f34048 Michael Hanselmann
150 28f34048 Michael Hanselmann
  if not valid:
151 28f34048 Michael Hanselmann
    raise errors.OpPrereqError("Invalid service name '%s'" % name,
152 28f34048 Michael Hanselmann
153 28f34048 Michael Hanselmann
154 28f34048 Michael Hanselmann
  return name
155 28f34048 Michael Hanselmann
156 28f34048 Michael Hanselmann
157 a8083063 Iustin Pop
def ListVolumeGroups():
158 a8083063 Iustin Pop
  """List volume groups and their size
159 a8083063 Iustin Pop

160 58885d79 Iustin Pop
  @rtype: dict
161 58885d79 Iustin Pop
162 58885d79 Iustin Pop
       Dictionary with keys volume name and values
163 58885d79 Iustin Pop
       the size of the volume
164 a8083063 Iustin Pop

165 a8083063 Iustin Pop
166 a8083063 Iustin Pop
  command = "vgs --noheadings --units m --nosuffix -o name,size"
167 a8083063 Iustin Pop
  result = RunCmd(command)
168 a8083063 Iustin Pop
  retval = {}
169 a8083063 Iustin Pop
  if result.failed:
170 a8083063 Iustin Pop
    return retval
171 a8083063 Iustin Pop
172 a8083063 Iustin Pop
  for line in result.stdout.splitlines():
173 a8083063 Iustin Pop
174 a8083063 Iustin Pop
      name, size = line.split()
175 a8083063 Iustin Pop
      size = int(float(size))
176 a8083063 Iustin Pop
    except (IndexError, ValueError), err:
177 bb698c1f Iustin Pop
      logging.error("Invalid output from vgs (%s): %s", err, line)
178 a8083063 Iustin Pop
179 a8083063 Iustin Pop
180 a8083063 Iustin Pop
    retval[name] = size
181 a8083063 Iustin Pop
182 a8083063 Iustin Pop
  return retval
183 a8083063 Iustin Pop
184 a8083063 Iustin Pop
185 a8083063 Iustin Pop
def BridgeExists(bridge):
186 a8083063 Iustin Pop
  """Check whether the given bridge exists in the system
187 a8083063 Iustin Pop

188 58885d79 Iustin Pop
  @type bridge: str
189 58885d79 Iustin Pop
  @param bridge: the bridge name to check
190 58885d79 Iustin Pop
  @rtype: boolean
191 58885d79 Iustin Pop
  @return: True if it does
192 a8083063 Iustin Pop

193 a8083063 Iustin Pop
194 a8083063 Iustin Pop
  return os.path.isdir("/sys/class/net/%s/bridge" % bridge)
195 a8083063 Iustin Pop
196 a8083063 Iustin Pop
197 a8083063 Iustin Pop
def TryConvert(fn, val):
198 a8083063 Iustin Pop
  """Try to convert a value ignoring errors.
199 a8083063 Iustin Pop

200 58885d79 Iustin Pop
  This function tries to apply function I{fn} to I{val}. If no
201 58885d79 Iustin Pop
  C{ValueError} or C{TypeError} exceptions are raised, it will return
202 58885d79 Iustin Pop
  the result, else it will return the original value. Any other
203 58885d79 Iustin Pop
  exceptions are propagated to the caller.
204 58885d79 Iustin Pop

205 58885d79 Iustin Pop
  @type fn: callable
206 58885d79 Iustin Pop
  @param fn: function to apply to the value
207 58885d79 Iustin Pop
  @param val: the value to be converted
208 58885d79 Iustin Pop
  @return: The converted value if the conversion was successful,
209 58885d79 Iustin Pop
      otherwise the original value.
210 a8083063 Iustin Pop

211 a8083063 Iustin Pop
212 a8083063 Iustin Pop
213 a8083063 Iustin Pop
    nv = fn(val)
214 7c4d6c7b Michael Hanselmann
  except (ValueError, TypeError):
215 a8083063 Iustin Pop
    nv = val
216 a8083063 Iustin Pop
  return nv
217 a8083063 Iustin Pop
218 a8083063 Iustin Pop
219 31155d60 Balazs Lecz
def ParseCpuMask(cpu_mask):
220 31155d60 Balazs Lecz
  """Parse a CPU mask definition and return the list of CPU IDs.
221 31155d60 Balazs Lecz

222 31155d60 Balazs Lecz
  CPU mask format: comma-separated list of CPU IDs
223 31155d60 Balazs Lecz
  or dash-separated ID ranges
224 31155d60 Balazs Lecz
  Example: "0-2,5" -> "0,1,2,5"
225 31155d60 Balazs Lecz

226 31155d60 Balazs Lecz
  @type cpu_mask: str
227 31155d60 Balazs Lecz
  @param cpu_mask: CPU mask definition
228 31155d60 Balazs Lecz
  @rtype: list of int
229 31155d60 Balazs Lecz
  @return: list of CPU IDs
230 31155d60 Balazs Lecz

231 31155d60 Balazs Lecz
232 31155d60 Balazs Lecz
  if not cpu_mask:
233 31155d60 Balazs Lecz
    return []
234 31155d60 Balazs Lecz
  cpu_list = []
235 31155d60 Balazs Lecz
  for range_def in cpu_mask.split(","):
236 31155d60 Balazs Lecz
    boundaries = range_def.split("-")
237 31155d60 Balazs Lecz
    n_elements = len(boundaries)
238 31155d60 Balazs Lecz
    if n_elements > 2:
239 31155d60 Balazs Lecz
      raise errors.ParseError("Invalid CPU ID range definition"
240 31155d60 Balazs Lecz
                              " (only one hyphen allowed): %s" % range_def)
241 31155d60 Balazs Lecz
242 31155d60 Balazs Lecz
      lower = int(boundaries[0])
243 31155d60 Balazs Lecz
    except (ValueError, TypeError), err:
244 31155d60 Balazs Lecz
      raise errors.ParseError("Invalid CPU ID value for lower boundary of"
245 31155d60 Balazs Lecz
                              " CPU ID range: %s" % str(err))
246 31155d60 Balazs Lecz
247 31155d60 Balazs Lecz
      higher = int(boundaries[-1])
248 31155d60 Balazs Lecz
    except (ValueError, TypeError), err:
249 31155d60 Balazs Lecz
      raise errors.ParseError("Invalid CPU ID value for higher boundary of"
250 31155d60 Balazs Lecz
                              " CPU ID range: %s" % str(err))
251 31155d60 Balazs Lecz
    if lower > higher:
252 31155d60 Balazs Lecz
      raise errors.ParseError("Invalid CPU ID range definition"
253 31155d60 Balazs Lecz
                              " (%d > %d): %s" % (lower, higher, range_def))
254 31155d60 Balazs Lecz
    cpu_list.extend(range(lower, higher + 1))
255 31155d60 Balazs Lecz
  return cpu_list
256 31155d60 Balazs Lecz
257 31155d60 Balazs Lecz
258 257f4c0a Iustin Pop
def GetHomeDir(user, default=None):
259 257f4c0a Iustin Pop
  """Try to get the homedir of the given user.
260 257f4c0a Iustin Pop

261 257f4c0a Iustin Pop
  The user can be passed either as a string (denoting the name) or as
262 257f4c0a Iustin Pop
  an integer (denoting the user id). If the user is not found, the
263 257f4c0a Iustin Pop
  'default' argument is returned, which defaults to None.
264 2f8b60b3 Iustin Pop

265 2f8b60b3 Iustin Pop
266 2f8b60b3 Iustin Pop
267 257f4c0a Iustin Pop
    if isinstance(user, basestring):
268 257f4c0a Iustin Pop
      result = pwd.getpwnam(user)
269 257f4c0a Iustin Pop
    elif isinstance(user, (int, long)):
270 257f4c0a Iustin Pop
      result = pwd.getpwuid(user)
271 257f4c0a Iustin Pop
272 257f4c0a Iustin Pop
      raise errors.ProgrammerError("Invalid type passed to GetHomeDir (%s)" %
273 257f4c0a Iustin Pop
274 2f8b60b3 Iustin Pop
  except KeyError:
275 2f8b60b3 Iustin Pop
    return default
276 2f8b60b3 Iustin Pop
  return result.pw_dir
277 59072e7e Michael Hanselmann
278 59072e7e Michael Hanselmann
279 7b4126b7 Iustin Pop
def FirstFree(seq, base=0):
280 7b4126b7 Iustin Pop
  """Returns the first non-existing integer from seq.
281 7b4126b7 Iustin Pop

282 7b4126b7 Iustin Pop
  The seq argument should be a sorted list of positive integers. The
283 7b4126b7 Iustin Pop
  first time the index of an element is smaller than the element
284 7b4126b7 Iustin Pop
  value, the index will be returned.
285 7b4126b7 Iustin Pop

286 7b4126b7 Iustin Pop
  The base argument is used to start at a different offset,
287 58885d79 Iustin Pop
  i.e. C{[3, 4, 6]} with I{offset=3} will return 5.
288 58885d79 Iustin Pop

289 58885d79 Iustin Pop
  Example: C{[0, 1, 3]} will return I{2}.
290 7b4126b7 Iustin Pop

291 58885d79 Iustin Pop
  @type seq: sequence
292 58885d79 Iustin Pop
  @param seq: the sequence to be analyzed.
293 58885d79 Iustin Pop
  @type base: int
294 58885d79 Iustin Pop
  @param base: use this value as the base index of the sequence
295 58885d79 Iustin Pop
  @rtype: int
296 58885d79 Iustin Pop
  @return: the first non-used index in the sequence
297 7b4126b7 Iustin Pop

298 7b4126b7 Iustin Pop
299 7b4126b7 Iustin Pop
  for idx, elem in enumerate(seq):
300 7b4126b7 Iustin Pop
    assert elem >= base, "Passed element is higher than base offset"
301 7b4126b7 Iustin Pop
    if elem > idx + base:
302 7b4126b7 Iustin Pop
      # idx is not used
303 7b4126b7 Iustin Pop
      return idx + base
304 7b4126b7 Iustin Pop
  return None
305 7b4126b7 Iustin Pop
306 7b4126b7 Iustin Pop
307 dfdc4060 Guido Trotter
def SingleWaitForFdCondition(fdobj, event, timeout):
308 dcd511c8 Guido Trotter
  """Waits for a condition to occur on the socket.
309 dcd511c8 Guido Trotter

310 dfdc4060 Guido Trotter
  Immediately returns at the first interruption.
311 dfdc4060 Guido Trotter

312 dfdc4060 Guido Trotter
  @type fdobj: integer or object supporting a fileno() method
313 dfdc4060 Guido Trotter
  @param fdobj: entity to wait for events on
314 dfdc4060 Guido Trotter
  @type event: integer
315 dcd511c8 Guido Trotter
  @param event: ORed condition (see select module)
316 dcd511c8 Guido Trotter
  @type timeout: float or None
317 dcd511c8 Guido Trotter
  @param timeout: Timeout in seconds
318 dcd511c8 Guido Trotter
  @rtype: int or None
319 dcd511c8 Guido Trotter
  @return: None for timeout, otherwise occured conditions
320 dcd511c8 Guido Trotter

321 dcd511c8 Guido Trotter
322 dcd511c8 Guido Trotter
  check = (event | select.POLLPRI |
323 dcd511c8 Guido Trotter
           select.POLLNVAL | select.POLLHUP | select.POLLERR)
324 dcd511c8 Guido Trotter
325 dcd511c8 Guido Trotter
  if timeout is not None:
326 dcd511c8 Guido Trotter
    # Poller object expects milliseconds
327 dcd511c8 Guido Trotter
    timeout *= 1000
328 dcd511c8 Guido Trotter
329 dcd511c8 Guido Trotter
  poller = select.poll()
330 dfdc4060 Guido Trotter
  poller.register(fdobj, event)
331 dcd511c8 Guido Trotter
332 dfdc4060 Guido Trotter
    # TODO: If the main thread receives a signal and we have no timeout, we
333 dfdc4060 Guido Trotter
    # could wait forever. This should check a global "quit" flag or something
334 dfdc4060 Guido Trotter
    # every so often.
335 dfdc4060 Guido Trotter
    io_events = poller.poll(timeout)
336 dfdc4060 Guido Trotter
  except select.error, err:
337 dfdc4060 Guido Trotter
    if err[0] != errno.EINTR:
338 dfdc4060 Guido Trotter
339 dfdc4060 Guido Trotter
    io_events = []
340 dfdc4060 Guido Trotter
  if io_events and io_events[0][1] & check:
341 dfdc4060 Guido Trotter
    return io_events[0][1]
342 dfdc4060 Guido Trotter
343 dfdc4060 Guido Trotter
    return None
344 dfdc4060 Guido Trotter
345 dfdc4060 Guido Trotter
346 dfdc4060 Guido Trotter
class FdConditionWaiterHelper(object):
347 dfdc4060 Guido Trotter
  """Retry helper for WaitForFdCondition.
348 dfdc4060 Guido Trotter

349 dfdc4060 Guido Trotter
  This class contains the retried and wait functions that make sure
350 dfdc4060 Guido Trotter
  WaitForFdCondition can continue waiting until the timeout is actually
351 dfdc4060 Guido Trotter
352 dfdc4060 Guido Trotter

353 dfdc4060 Guido Trotter
354 dfdc4060 Guido Trotter
355 dfdc4060 Guido Trotter
  def __init__(self, timeout):
356 dfdc4060 Guido Trotter
    self.timeout = timeout
357 dfdc4060 Guido Trotter
358 dfdc4060 Guido Trotter
  def Poll(self, fdobj, event):
359 dfdc4060 Guido Trotter
    result = SingleWaitForFdCondition(fdobj, event, self.timeout)
360 dfdc4060 Guido Trotter
    if result is None:
361 dfdc4060 Guido Trotter
      raise RetryAgain()
362 dfdc4060 Guido Trotter
363 dfdc4060 Guido Trotter
      return result
364 dfdc4060 Guido Trotter
365 dfdc4060 Guido Trotter
  def UpdateTimeout(self, timeout):
366 dfdc4060 Guido Trotter
    self.timeout = timeout
367 dfdc4060 Guido Trotter
368 dfdc4060 Guido Trotter
369 dfdc4060 Guido Trotter
def WaitForFdCondition(fdobj, event, timeout):
370 dfdc4060 Guido Trotter
  """Waits for a condition to occur on the socket.
371 dfdc4060 Guido Trotter

372 dfdc4060 Guido Trotter
  Retries until the timeout is expired, even if interrupted.
373 dfdc4060 Guido Trotter

374 dfdc4060 Guido Trotter
  @type fdobj: integer or object supporting a fileno() method
375 dfdc4060 Guido Trotter
  @param fdobj: entity to wait for events on
376 dfdc4060 Guido Trotter
  @type event: integer
377 dfdc4060 Guido Trotter
  @param event: ORed condition (see select module)
378 dfdc4060 Guido Trotter
  @type timeout: float or None
379 dfdc4060 Guido Trotter
  @param timeout: Timeout in seconds
380 dfdc4060 Guido Trotter
  @rtype: int or None
381 dfdc4060 Guido Trotter
  @return: None for timeout, otherwise occured conditions
382 dfdc4060 Guido Trotter

383 dfdc4060 Guido Trotter
384 dfdc4060 Guido Trotter
  if timeout is not None:
385 dfdc4060 Guido Trotter
    retrywaiter = FdConditionWaiterHelper(timeout)
386 1b429e2a Iustin Pop
387 1b429e2a Iustin Pop
      result = Retry(retrywaiter.Poll, RETRY_REMAINING_TIME, timeout,
388 1b429e2a Iustin Pop
                     args=(fdobj, event), wait_fn=retrywaiter.UpdateTimeout)
389 1b429e2a Iustin Pop
    except RetryTimeout:
390 1b429e2a Iustin Pop
      result = None
391 dfdc4060 Guido Trotter
392 dfdc4060 Guido Trotter
    result = None
393 dfdc4060 Guido Trotter
    while result is None:
394 dfdc4060 Guido Trotter
      result = SingleWaitForFdCondition(fdobj, event, timeout)
395 dfdc4060 Guido Trotter
  return result
396 2de64672 Iustin Pop
397 2de64672 Iustin Pop
398 2826b361 Guido Trotter
def EnsureDaemon(name):
399 2826b361 Guido Trotter
  """Check for and start daemon if not alive.
400 2826b361 Guido Trotter

401 2826b361 Guido Trotter
402 2826b361 Guido Trotter
  result = RunCmd([constants.DAEMON_UTIL, "check-and-start", name])
403 2826b361 Guido Trotter
  if result.failed:
404 2826b361 Guido Trotter
    logging.error("Can't start daemon '%s', failure %s, output: %s",
405 2826b361 Guido Trotter
                  name, result.fail_reason, result.output)
406 2826b361 Guido Trotter
    return False
407 2826b361 Guido Trotter
408 2826b361 Guido Trotter
  return True
409 b330ac0b Guido Trotter
410 b330ac0b Guido Trotter
411 db147305 Tom Limoncelli
def StopDaemon(name):
412 db147305 Tom Limoncelli
  """Stop daemon
413 db147305 Tom Limoncelli

414 db147305 Tom Limoncelli
415 db147305 Tom Limoncelli
  result = RunCmd([constants.DAEMON_UTIL, "stop", name])
416 db147305 Tom Limoncelli
  if result.failed:
417 db147305 Tom Limoncelli
    logging.error("Can't stop daemon '%s', failure %s, output: %s",
418 db147305 Tom Limoncelli
                  name, result.fail_reason, result.output)
419 db147305 Tom Limoncelli
    return False
420 db147305 Tom Limoncelli
421 db147305 Tom Limoncelli
  return True
422 db147305 Tom Limoncelli
423 db147305 Tom Limoncelli
424 8d1a2a64 Michael Hanselmann
def CheckVolumeGroupSize(vglist, vgname, minsize):
425 8d1a2a64 Michael Hanselmann
  """Checks if the volume group list is valid.
426 8d1a2a64 Michael Hanselmann

427 58885d79 Iustin Pop
  The function will check if a given volume group is in the list of
428 58885d79 Iustin Pop
  volume groups and has a minimum size.
429 58885d79 Iustin Pop

430 58885d79 Iustin Pop
  @type vglist: dict
431 58885d79 Iustin Pop
  @param vglist: dictionary of volume group names and their size
432 58885d79 Iustin Pop
  @type vgname: str
433 58885d79 Iustin Pop
  @param vgname: the volume group we should check
434 58885d79 Iustin Pop
  @type minsize: int
435 58885d79 Iustin Pop
  @param minsize: the minimum size we accept
436 58885d79 Iustin Pop
  @rtype: None or str
437 58885d79 Iustin Pop
  @return: None for success, otherwise the error message
438 8d1a2a64 Michael Hanselmann

439 8d1a2a64 Michael Hanselmann
440 8d1a2a64 Michael Hanselmann
  vgsize = vglist.get(vgname, None)
441 8d1a2a64 Michael Hanselmann
  if vgsize is None:
442 8d1a2a64 Michael Hanselmann
    return "volume group '%s' missing" % vgname
443 8d1a2a64 Michael Hanselmann
  elif vgsize < minsize:
444 8d1a2a64 Michael Hanselmann
    return ("volume group '%s' too small (%s MiB required, %d MiB found)" %
445 8d1a2a64 Michael Hanselmann
            (vgname, minsize, vgsize))
446 8d1a2a64 Michael Hanselmann
  return None
447 7996a135 Iustin Pop
448 7996a135 Iustin Pop
449 45bc5e4a Michael Hanselmann
def SplitTime(value):
450 739be818 Michael Hanselmann
  """Splits time as floating point number into a tuple.
451 739be818 Michael Hanselmann

452 45bc5e4a Michael Hanselmann
  @param value: Time in seconds
453 45bc5e4a Michael Hanselmann
  @type value: int or float
454 45bc5e4a Michael Hanselmann
  @return: Tuple containing (seconds, microseconds)
455 739be818 Michael Hanselmann

456 739be818 Michael Hanselmann
457 45bc5e4a Michael Hanselmann
  (seconds, microseconds) = divmod(int(value * 1000000), 1000000)
458 45bc5e4a Michael Hanselmann
459 45bc5e4a Michael Hanselmann
  assert 0 <= seconds, \
460 45bc5e4a Michael Hanselmann
    "Seconds must be larger than or equal to 0, but are %s" % seconds
461 45bc5e4a Michael Hanselmann
  assert 0 <= microseconds <= 999999, \
462 45bc5e4a Michael Hanselmann
    "Microseconds must be 0-999999, but are %s" % microseconds
463 45bc5e4a Michael Hanselmann
464 45bc5e4a Michael Hanselmann
  return (int(seconds), int(microseconds))
465 739be818 Michael Hanselmann
466 739be818 Michael Hanselmann
467 739be818 Michael Hanselmann
def MergeTime(timetuple):
468 739be818 Michael Hanselmann
  """Merges a tuple into time as a floating point number.
469 739be818 Michael Hanselmann

470 45bc5e4a Michael Hanselmann
  @param timetuple: Time as tuple, (seconds, microseconds)
471 739be818 Michael Hanselmann
  @type timetuple: tuple
472 739be818 Michael Hanselmann
  @return: Time as a floating point number expressed in seconds
473 739be818 Michael Hanselmann

474 739be818 Michael Hanselmann
475 45bc5e4a Michael Hanselmann
  (seconds, microseconds) = timetuple
476 739be818 Michael Hanselmann
477 45bc5e4a Michael Hanselmann
  assert 0 <= seconds, \
478 45bc5e4a Michael Hanselmann
    "Seconds must be larger than or equal to 0, but are %s" % seconds
479 45bc5e4a Michael Hanselmann
  assert 0 <= microseconds <= 999999, \
480 45bc5e4a Michael Hanselmann
    "Microseconds must be 0-999999, but are %s" % microseconds
481 739be818 Michael Hanselmann
482 45bc5e4a Michael Hanselmann
  return float(seconds) + (float(microseconds) * 0.000001)
483 739be818 Michael Hanselmann
484 739be818 Michael Hanselmann
485 691c81b7 Michael Hanselmann
def FindMatch(data, name):
486 691c81b7 Michael Hanselmann
  """Tries to find an item in a dictionary matching a name.
487 691c81b7 Michael Hanselmann

488 691c81b7 Michael Hanselmann
  Callers have to ensure the data names aren't contradictory (e.g. a regexp
489 691c81b7 Michael Hanselmann
  that matches a string). If the name isn't a direct key, all regular
490 691c81b7 Michael Hanselmann
  expression objects in the dictionary are matched against it.
491 691c81b7 Michael Hanselmann

492 691c81b7 Michael Hanselmann
  @type data: dict
493 691c81b7 Michael Hanselmann
  @param data: Dictionary containing data
494 691c81b7 Michael Hanselmann
  @type name: string
495 691c81b7 Michael Hanselmann
  @param name: Name to look for
496 691c81b7 Michael Hanselmann
  @rtype: tuple; (value in dictionary, matched groups as list)
497 691c81b7 Michael Hanselmann

498 691c81b7 Michael Hanselmann
499 691c81b7 Michael Hanselmann
  if name in data:
500 691c81b7 Michael Hanselmann
    return (data[name], [])
501 691c81b7 Michael Hanselmann
502 691c81b7 Michael Hanselmann
  for key, value in data.items():
503 691c81b7 Michael Hanselmann
    # Regex objects
504 691c81b7 Michael Hanselmann
    if hasattr(key, "match"):
505 691c81b7 Michael Hanselmann
      m = key.match(name)
506 691c81b7 Michael Hanselmann
      if m:
507 691c81b7 Michael Hanselmann
        return (value, list(m.groups()))
508 691c81b7 Michael Hanselmann
509 691c81b7 Michael Hanselmann
  return None
510 691c81b7 Michael Hanselmann
511 691c81b7 Michael Hanselmann
512 1b045f5d Balazs Lecz
def GetMounts(filename=constants.PROC_MOUNTS):
513 1b045f5d Balazs Lecz
  """Returns the list of mounted filesystems.
514 1b045f5d Balazs Lecz

515 1b045f5d Balazs Lecz
  This function is Linux-specific.
516 1b045f5d Balazs Lecz

517 1b045f5d Balazs Lecz
  @param filename: path of mounts file (/proc/mounts by default)
518 1b045f5d Balazs Lecz
  @rtype: list of tuples
519 1b045f5d Balazs Lecz
  @return: list of mount entries (device, mountpoint, fstype, options)
520 1b045f5d Balazs Lecz

521 1b045f5d Balazs Lecz
522 1b045f5d Balazs Lecz
  # TODO(iustin): investigate non-Linux options (e.g. via mount output)
523 1b045f5d Balazs Lecz
  data = []
524 1b045f5d Balazs Lecz
  mountlines = ReadFile(filename).splitlines()
525 1b045f5d Balazs Lecz
  for line in mountlines:
526 1b045f5d Balazs Lecz
    device, mountpoint, fstype, options, _ = line.split(None, 4)
527 1b045f5d Balazs Lecz
    data.append((device, mountpoint, fstype, options))
528 1b045f5d Balazs Lecz
529 1b045f5d Balazs Lecz
  return data
530 1b045f5d Balazs Lecz
531 1b045f5d Balazs Lecz
532 451575de Guido Trotter
def SignalHandled(signums):
533 451575de Guido Trotter
  """Signal Handled decoration.
534 451575de Guido Trotter

535 451575de Guido Trotter
  This special decorator installs a signal handler and then calls the target
536 451575de Guido Trotter
  function. The function must accept a 'signal_handlers' keyword argument,
537 451575de Guido Trotter
  which will contain a dict indexed by signal number, with SignalHandler
538 451575de Guido Trotter
  objects as values.
539 451575de Guido Trotter

540 451575de Guido Trotter
  The decorator can be safely stacked with iself, to handle multiple signals
541 451575de Guido Trotter
  with different handlers.
542 451575de Guido Trotter

543 451575de Guido Trotter
  @type signums: list
544 451575de Guido Trotter
  @param signums: signals to intercept
545 451575de Guido Trotter

546 451575de Guido Trotter
547 451575de Guido Trotter
  def wrap(fn):
548 451575de Guido Trotter
    def sig_function(*args, **kwargs):
549 451575de Guido Trotter
      assert 'signal_handlers' not in kwargs or \
550 451575de Guido Trotter
             kwargs['signal_handlers'] is None or \
551 451575de Guido Trotter
             isinstance(kwargs['signal_handlers'], dict), \
552 451575de Guido Trotter
             "Wrong signal_handlers parameter in original function call"
553 451575de Guido Trotter
      if 'signal_handlers' in kwargs and kwargs['signal_handlers'] is not None:
554 451575de Guido Trotter
        signal_handlers = kwargs['signal_handlers']
555 451575de Guido Trotter
556 451575de Guido Trotter
        signal_handlers = {}
557 451575de Guido Trotter
        kwargs['signal_handlers'] = signal_handlers
558 451575de Guido Trotter
      sighandler = SignalHandler(signums)
559 451575de Guido Trotter
560 451575de Guido Trotter
        for sig in signums:
561 451575de Guido Trotter
          signal_handlers[sig] = sighandler
562 451575de Guido Trotter
        return fn(*args, **kwargs)
563 451575de Guido Trotter
564 451575de Guido Trotter
565 451575de Guido Trotter
    return sig_function
566 451575de Guido Trotter
  return wrap
567 451575de Guido Trotter
568 451575de Guido Trotter
569 b9768937 Michael Hanselmann
class SignalWakeupFd(object):
570 b9768937 Michael Hanselmann
571 b9768937 Michael Hanselmann
    # This is only supported in Python 2.5 and above (some distributions
572 b9768937 Michael Hanselmann
    # backported it to Python 2.4)
573 b9768937 Michael Hanselmann
    _set_wakeup_fd_fn = signal.set_wakeup_fd
574 b9768937 Michael Hanselmann
  except AttributeError:
575 b9768937 Michael Hanselmann
    # Not supported
576 b9768937 Michael Hanselmann
    def _SetWakeupFd(self, _): # pylint: disable-msg=R0201
577 b9768937 Michael Hanselmann
      return -1
578 b9768937 Michael Hanselmann
579 b9768937 Michael Hanselmann
    def _SetWakeupFd(self, fd):
580 b9768937 Michael Hanselmann
      return self._set_wakeup_fd_fn(fd)
581 b9768937 Michael Hanselmann
582 b9768937 Michael Hanselmann
  def __init__(self):
583 b9768937 Michael Hanselmann
    """Initializes this class.
584 b9768937 Michael Hanselmann

585 b9768937 Michael Hanselmann
586 b9768937 Michael Hanselmann
    (read_fd, write_fd) = os.pipe()
587 b9768937 Michael Hanselmann
588 b9768937 Michael Hanselmann
    # Once these succeeded, the file descriptors will be closed automatically.
589 b9768937 Michael Hanselmann
    # Buffer size 0 is important, otherwise .read() with a specified length
590 b9768937 Michael Hanselmann
    # might buffer data and the file descriptors won't be marked readable.
591 b9768937 Michael Hanselmann
    self._read_fh = os.fdopen(read_fd, "r", 0)
592 b9768937 Michael Hanselmann
    self._write_fh = os.fdopen(write_fd, "w", 0)
593 b9768937 Michael Hanselmann
594 b9768937 Michael Hanselmann
    self._previous = self._SetWakeupFd(self._write_fh.fileno())
595 b9768937 Michael Hanselmann
596 b9768937 Michael Hanselmann
    # Utility functions
597 b9768937 Michael Hanselmann
    self.fileno = self._read_fh.fileno
598 b9768937 Michael Hanselmann =
599 b9768937 Michael Hanselmann
600 b9768937 Michael Hanselmann
  def Reset(self):
601 b9768937 Michael Hanselmann
    """Restores the previous wakeup file descriptor.
602 b9768937 Michael Hanselmann

603 b9768937 Michael Hanselmann
604 b9768937 Michael Hanselmann
    if hasattr(self, "_previous") and self._previous is not None:
605 b9768937 Michael Hanselmann
606 b9768937 Michael Hanselmann
      self._previous = None
607 b9768937 Michael Hanselmann
608 b9768937 Michael Hanselmann
  def Notify(self):
609 b9768937 Michael Hanselmann
    """Notifies the wakeup file descriptor.
610 b9768937 Michael Hanselmann

611 b9768937 Michael Hanselmann
612 b9768937 Michael Hanselmann
613 b9768937 Michael Hanselmann
614 b9768937 Michael Hanselmann
  def __del__(self):
615 b9768937 Michael Hanselmann
    """Called before object deletion.
616 b9768937 Michael Hanselmann

617 b9768937 Michael Hanselmann
618 b9768937 Michael Hanselmann
619 b9768937 Michael Hanselmann
620 b9768937 Michael Hanselmann
621 de499029 Michael Hanselmann
class SignalHandler(object):
622 de499029 Michael Hanselmann
  """Generic signal handler class.
623 de499029 Michael Hanselmann

624 58885d79 Iustin Pop
  It automatically restores the original handler when deconstructed or
625 58885d79 Iustin Pop
  when L{Reset} is called. You can either pass your own handler
626 58885d79 Iustin Pop
  function in or query the L{called} attribute to detect whether the
627 58885d79 Iustin Pop
  signal was sent.
628 58885d79 Iustin Pop

629 58885d79 Iustin Pop
  @type signum: list
630 58885d79 Iustin Pop
  @ivar signum: the signals we handle
631 58885d79 Iustin Pop
  @type called: boolean
632 58885d79 Iustin Pop
  @ivar called: tracks whether any of the signals have been raised
633 de499029 Michael Hanselmann

634 de499029 Michael Hanselmann
635 b9768937 Michael Hanselmann
  def __init__(self, signum, handler_fn=None, wakeup=None):
636 de499029 Michael Hanselmann
    """Constructs a new SignalHandler instance.
637 de499029 Michael Hanselmann

638 58885d79 Iustin Pop
    @type signum: int or list of ints
639 de499029 Michael Hanselmann
    @param signum: Single signal number or set of signal numbers
640 92b61ec7 Michael Hanselmann
    @type handler_fn: callable
641 92b61ec7 Michael Hanselmann
    @param handler_fn: Signal handling function
642 de499029 Michael Hanselmann

643 de499029 Michael Hanselmann
644 92b61ec7 Michael Hanselmann
    assert handler_fn is None or callable(handler_fn)
645 92b61ec7 Michael Hanselmann
646 6c52849e Guido Trotter
    self.signum = set(signum)
647 de499029 Michael Hanselmann
    self.called = False
648 de499029 Michael Hanselmann
649 92b61ec7 Michael Hanselmann
    self._handler_fn = handler_fn
650 b9768937 Michael Hanselmann
    self._wakeup = wakeup
651 92b61ec7 Michael Hanselmann
652 de499029 Michael Hanselmann
    self._previous = {}
653 de499029 Michael Hanselmann
654 de499029 Michael Hanselmann
      for signum in self.signum:
655 de499029 Michael Hanselmann
        # Setup handler
656 de499029 Michael Hanselmann
        prev_handler = signal.signal(signum, self._HandleSignal)
657 de499029 Michael Hanselmann
658 de499029 Michael Hanselmann
          self._previous[signum] = prev_handler
659 de499029 Michael Hanselmann
660 de499029 Michael Hanselmann
          # Restore previous handler
661 de499029 Michael Hanselmann
          signal.signal(signum, prev_handler)
662 de499029 Michael Hanselmann
663 de499029 Michael Hanselmann
664 de499029 Michael Hanselmann
      # Reset all handlers
665 de499029 Michael Hanselmann
666 de499029 Michael Hanselmann
      # Here we have a race condition: a handler may have already been called,
667 de499029 Michael Hanselmann
      # but there's not much we can do about it at this point.
668 de499029 Michael Hanselmann
669 de499029 Michael Hanselmann
670 de499029 Michael Hanselmann
  def __del__(self):
671 de499029 Michael Hanselmann
672 de499029 Michael Hanselmann
673 de499029 Michael Hanselmann
  def Reset(self):
674 de499029 Michael Hanselmann
    """Restore previous handler.
675 de499029 Michael Hanselmann

676 58885d79 Iustin Pop
    This will reset all the signals to their previous handlers.
677 58885d79 Iustin Pop

678 de499029 Michael Hanselmann
679 de499029 Michael Hanselmann
    for signum, prev_handler in self._previous.items():
680 de499029 Michael Hanselmann
      signal.signal(signum, prev_handler)
681 de499029 Michael Hanselmann
      # If successful, remove from dict
682 de499029 Michael Hanselmann
      del self._previous[signum]
683 de499029 Michael Hanselmann
684 de499029 Michael Hanselmann
  def Clear(self):
685 58885d79 Iustin Pop
    """Unsets the L{called} flag.
686 de499029 Michael Hanselmann

687 de499029 Michael Hanselmann
    This function can be used in case a signal may arrive several times.
688 de499029 Michael Hanselmann

689 de499029 Michael Hanselmann
690 de499029 Michael Hanselmann
    self.called = False
691 de499029 Michael Hanselmann
692 92b61ec7 Michael Hanselmann
  def _HandleSignal(self, signum, frame):
693 de499029 Michael Hanselmann
    """Actual signal handling function.
694 de499029 Michael Hanselmann

695 de499029 Michael Hanselmann
696 de499029 Michael Hanselmann
    # This is not nice and not absolutely atomic, but it appears to be the only
697 de499029 Michael Hanselmann
    # solution in Python -- there are no atomic types.
698 de499029 Michael Hanselmann
    self.called = True
699 a2d2e1a7 Iustin Pop
700 b9768937 Michael Hanselmann
    if self._wakeup:
701 b9768937 Michael Hanselmann
      # Notify whoever is interested in signals
702 b9768937 Michael Hanselmann
703 b9768937 Michael Hanselmann
704 92b61ec7 Michael Hanselmann
    if self._handler_fn:
705 92b61ec7 Michael Hanselmann
      self._handler_fn(signum, frame)
706 92b61ec7 Michael Hanselmann
707 a2d2e1a7 Iustin Pop
708 a2d2e1a7 Iustin Pop
class FieldSet(object):
709 a2d2e1a7 Iustin Pop
  """A simple field set.
710 a2d2e1a7 Iustin Pop

711 a2d2e1a7 Iustin Pop
  Among the features are:
712 a2d2e1a7 Iustin Pop
    - checking if a string is among a list of static string or regex objects
713 a2d2e1a7 Iustin Pop
    - checking if a whole list of string matches
714 a2d2e1a7 Iustin Pop
    - returning the matching groups from a regex match
715 a2d2e1a7 Iustin Pop

716 a2d2e1a7 Iustin Pop
  Internally, all fields are held as regular expression objects.
717 a2d2e1a7 Iustin Pop

718 a2d2e1a7 Iustin Pop
719 a2d2e1a7 Iustin Pop
  def __init__(self, *items):
720 a2d2e1a7 Iustin Pop
    self.items = [re.compile("^%s$" % value) for value in items]
721 a2d2e1a7 Iustin Pop
722 a2d2e1a7 Iustin Pop
  def Extend(self, other_set):
723 a2d2e1a7 Iustin Pop
    """Extend the field set with the items from another one"""
724 a2d2e1a7 Iustin Pop
725 a2d2e1a7 Iustin Pop
726 a2d2e1a7 Iustin Pop
  def Matches(self, field):
727 a2d2e1a7 Iustin Pop
    """Checks if a field matches the current set
728 a2d2e1a7 Iustin Pop

729 a2d2e1a7 Iustin Pop
    @type field: str
730 a2d2e1a7 Iustin Pop
    @param field: the string to match
731 6c881c52 Iustin Pop
    @return: either None or a regular expression match object
732 a2d2e1a7 Iustin Pop

733 a2d2e1a7 Iustin Pop
734 a2d2e1a7 Iustin Pop
    for m in itertools.ifilter(None, (val.match(field) for val in self.items)):
735 a2d2e1a7 Iustin Pop
      return m
736 6c881c52 Iustin Pop
    return None
737 a2d2e1a7 Iustin Pop
738 a2d2e1a7 Iustin Pop
  def NonMatching(self, items):
739 a2d2e1a7 Iustin Pop
    """Returns the list of fields not matching the current set
740 a2d2e1a7 Iustin Pop

741 a2d2e1a7 Iustin Pop
    @type items: list
742 a2d2e1a7 Iustin Pop
    @param items: the list of fields to check
743 a2d2e1a7 Iustin Pop
    @rtype: list
744 a2d2e1a7 Iustin Pop
    @return: list of non-matching fields
745 a2d2e1a7 Iustin Pop

746 a2d2e1a7 Iustin Pop
747 a2d2e1a7 Iustin Pop
    return [val for val in items if not self.Matches(val)]