Statistics
| Branch: | Tag: | Revision:

root / lib / utils.py @ 7b4126b7

History | View | Annotate | Download (30.2 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 a8083063 Iustin Pop
# Copyright (C) 2006, 2007 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
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
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 a8083063 Iustin Pop
"""Ganeti small utilities
23 899d2a81 Michael Hanselmann

24 a8083063 Iustin Pop
"""
25 a8083063 Iustin Pop
26 a8083063 Iustin Pop
27 a8083063 Iustin Pop
import sys
28 a8083063 Iustin Pop
import os
29 a8083063 Iustin Pop
import sha
30 a8083063 Iustin Pop
import time
31 113b55aa Iustin Pop
import subprocess
32 a8083063 Iustin Pop
import re
33 a8083063 Iustin Pop
import socket
34 a8083063 Iustin Pop
import tempfile
35 a8083063 Iustin Pop
import shutil
36 4ca1b175 Alexander Schreiber
import errno
37 2f8b60b3 Iustin Pop
import pwd
38 78feb6fb Guido Trotter
import itertools
39 9c233417 Iustin Pop
import select
40 9c233417 Iustin Pop
import fcntl
41 8f765069 Iustin Pop
import resource
42 9c233417 Iustin Pop
43 9c233417 Iustin Pop
from cStringIO import StringIO
44 a8083063 Iustin Pop
45 a8083063 Iustin Pop
from ganeti import logger
46 a8083063 Iustin Pop
from ganeti import errors
47 3aecd2c7 Iustin Pop
from ganeti import constants
48 a8083063 Iustin Pop
49 16abfbc2 Alexander Schreiber
50 a8083063 Iustin Pop
_locksheld = []
51 a8083063 Iustin Pop
_re_shell_unquoted = re.compile('^[-.,=:/_+@A-Za-z0-9]+$')
52 a8083063 Iustin Pop
53 f362096f Iustin Pop
debug = False
54 b74159ee Iustin Pop
no_fork = False
55 f362096f Iustin Pop
56 7c0d6283 Michael Hanselmann
57 a8083063 Iustin Pop
class RunResult(object):
58 a8083063 Iustin Pop
  """Simple class for holding the result of running external programs.
59 a8083063 Iustin Pop

60 a8083063 Iustin Pop
  Instance variables:
61 a8083063 Iustin Pop
    exit_code: the exit code of the program, or None (if the program
62 a8083063 Iustin Pop
               didn't exit())
63 a8083063 Iustin Pop
    signal: numeric signal that caused the program to finish, or None
64 a8083063 Iustin Pop
            (if the program wasn't terminated by a signal)
65 a8083063 Iustin Pop
    stdout: the standard output of the program
66 a8083063 Iustin Pop
    stderr: the standard error of the program
67 a8083063 Iustin Pop
    failed: a Boolean value which is True in case the program was
68 a8083063 Iustin Pop
            terminated by a signal or exited with a non-zero exit code
69 a8083063 Iustin Pop
    fail_reason: a string detailing the termination reason
70 a8083063 Iustin Pop

71 a8083063 Iustin Pop
  """
72 a8083063 Iustin Pop
  __slots__ = ["exit_code", "signal", "stdout", "stderr",
73 a8083063 Iustin Pop
               "failed", "fail_reason", "cmd"]
74 a8083063 Iustin Pop
75 a8083063 Iustin Pop
76 a8083063 Iustin Pop
  def __init__(self, exit_code, signal, stdout, stderr, cmd):
77 a8083063 Iustin Pop
    self.cmd = cmd
78 a8083063 Iustin Pop
    self.exit_code = exit_code
79 a8083063 Iustin Pop
    self.signal = signal
80 a8083063 Iustin Pop
    self.stdout = stdout
81 a8083063 Iustin Pop
    self.stderr = stderr
82 a8083063 Iustin Pop
    self.failed = (signal is not None or exit_code != 0)
83 a8083063 Iustin Pop
84 a8083063 Iustin Pop
    if self.signal is not None:
85 a8083063 Iustin Pop
      self.fail_reason = "terminated by signal %s" % self.signal
86 a8083063 Iustin Pop
    elif self.exit_code is not None:
87 a8083063 Iustin Pop
      self.fail_reason = "exited with exit code %s" % self.exit_code
88 a8083063 Iustin Pop
    else:
89 a8083063 Iustin Pop
      self.fail_reason = "unable to determine termination reason"
90 a8083063 Iustin Pop
91 f362096f Iustin Pop
    if debug and self.failed:
92 f362096f Iustin Pop
      logger.Debug("Command '%s' failed (%s); output: %s" %
93 f362096f Iustin Pop
                   (self.cmd, self.fail_reason, self.output))
94 f362096f Iustin Pop
95 a8083063 Iustin Pop
  def _GetOutput(self):
96 a8083063 Iustin Pop
    """Returns the combined stdout and stderr for easier usage.
97 a8083063 Iustin Pop

98 a8083063 Iustin Pop
    """
99 a8083063 Iustin Pop
    return self.stdout + self.stderr
100 a8083063 Iustin Pop
101 a8083063 Iustin Pop
  output = property(_GetOutput, None, None, "Return full output")
102 a8083063 Iustin Pop
103 a8083063 Iustin Pop
104 a8083063 Iustin Pop
def _GetLockFile(subsystem):
105 a8083063 Iustin Pop
  """Compute the file name for a given lock name."""
106 3aecd2c7 Iustin Pop
  return "%s/ganeti_lock_%s" % (constants.LOCK_DIR, subsystem)
107 a8083063 Iustin Pop
108 a8083063 Iustin Pop
109 a8083063 Iustin Pop
def Lock(name, max_retries=None, debug=False):
110 a8083063 Iustin Pop
  """Lock a given subsystem.
111 a8083063 Iustin Pop

112 a8083063 Iustin Pop
  In case the lock is already held by an alive process, the function
113 a8083063 Iustin Pop
  will sleep indefintely and poll with a one second interval.
114 a8083063 Iustin Pop

115 a8083063 Iustin Pop
  When the optional integer argument 'max_retries' is passed with a
116 a8083063 Iustin Pop
  non-zero value, the function will sleep only for this number of
117 a8083063 Iustin Pop
  times, and then it will will raise a LockError if the lock can't be
118 a8083063 Iustin Pop
  acquired. Passing in a negative number will cause only one try to
119 a8083063 Iustin Pop
  get the lock. Passing a positive number will make the function retry
120 a8083063 Iustin Pop
  for approximately that number of seconds.
121 a8083063 Iustin Pop

122 a8083063 Iustin Pop
  """
123 a8083063 Iustin Pop
  lockfile = _GetLockFile(name)
124 a8083063 Iustin Pop
125 a8083063 Iustin Pop
  if name in _locksheld:
126 a8083063 Iustin Pop
    raise errors.LockError('Lock "%s" already held!' % (name,))
127 a8083063 Iustin Pop
128 a8083063 Iustin Pop
  errcount = 0
129 a8083063 Iustin Pop
130 a8083063 Iustin Pop
  retries = 0
131 a8083063 Iustin Pop
  while True:
132 a8083063 Iustin Pop
    try:
133 a8083063 Iustin Pop
      fd = os.open(lockfile, os.O_CREAT | os.O_EXCL | os.O_RDWR | os.O_SYNC)
134 a8083063 Iustin Pop
      break
135 a8083063 Iustin Pop
    except OSError, creat_err:
136 4ca1b175 Alexander Schreiber
      if creat_err.errno != errno.EEXIST:
137 3ecf6786 Iustin Pop
        raise errors.LockError("Can't create the lock file. Error '%s'." %
138 3ecf6786 Iustin Pop
                               str(creat_err))
139 a8083063 Iustin Pop
140 a8083063 Iustin Pop
      try:
141 a8083063 Iustin Pop
        pf = open(lockfile, 'r')
142 a8083063 Iustin Pop
      except IOError, open_err:
143 a8083063 Iustin Pop
        errcount += 1
144 a8083063 Iustin Pop
        if errcount >= 5:
145 3ecf6786 Iustin Pop
          raise errors.LockError("Lock file exists but cannot be opened."
146 3ecf6786 Iustin Pop
                                 " Error: '%s'." % str(open_err))
147 a8083063 Iustin Pop
        time.sleep(1)
148 a8083063 Iustin Pop
        continue
149 a8083063 Iustin Pop
150 a8083063 Iustin Pop
      try:
151 a8083063 Iustin Pop
        pid = int(pf.read())
152 a8083063 Iustin Pop
      except ValueError:
153 3ecf6786 Iustin Pop
        raise errors.LockError("Invalid pid string in %s" %
154 a8083063 Iustin Pop
                               (lockfile,))
155 a8083063 Iustin Pop
156 a8083063 Iustin Pop
      if not IsProcessAlive(pid):
157 3ecf6786 Iustin Pop
        raise errors.LockError("Stale lockfile %s for pid %d?" %
158 3ecf6786 Iustin Pop
                               (lockfile, pid))
159 a8083063 Iustin Pop
160 a8083063 Iustin Pop
      if max_retries and max_retries <= retries:
161 3ecf6786 Iustin Pop
        raise errors.LockError("Can't acquire lock during the specified"
162 3ecf6786 Iustin Pop
                               " time, aborting.")
163 a8083063 Iustin Pop
      if retries == 5 and (debug or sys.stdin.isatty()):
164 a8083063 Iustin Pop
        logger.ToStderr("Waiting for '%s' lock from pid %d..." % (name, pid))
165 a8083063 Iustin Pop
166 a8083063 Iustin Pop
      time.sleep(1)
167 a8083063 Iustin Pop
      retries += 1
168 a8083063 Iustin Pop
      continue
169 a8083063 Iustin Pop
170 a8083063 Iustin Pop
  os.write(fd, '%d\n' % (os.getpid(),))
171 a8083063 Iustin Pop
  os.close(fd)
172 a8083063 Iustin Pop
173 a8083063 Iustin Pop
  _locksheld.append(name)
174 a8083063 Iustin Pop
175 a8083063 Iustin Pop
176 a8083063 Iustin Pop
def Unlock(name):
177 098c0958 Michael Hanselmann
  """Unlock a given subsystem.
178 a8083063 Iustin Pop

179 098c0958 Michael Hanselmann
  """
180 a8083063 Iustin Pop
  lockfile = _GetLockFile(name)
181 a8083063 Iustin Pop
182 a8083063 Iustin Pop
  try:
183 a8083063 Iustin Pop
    fd = os.open(lockfile, os.O_RDONLY)
184 a8083063 Iustin Pop
  except OSError:
185 a8083063 Iustin Pop
    raise errors.LockError('Lock "%s" not held.' % (name,))
186 a8083063 Iustin Pop
187 a8083063 Iustin Pop
  f = os.fdopen(fd, 'r')
188 a8083063 Iustin Pop
  pid_str = f.read()
189 a8083063 Iustin Pop
190 a8083063 Iustin Pop
  try:
191 a8083063 Iustin Pop
    pid = int(pid_str)
192 a8083063 Iustin Pop
  except ValueError:
193 a8083063 Iustin Pop
    raise errors.LockError('Unable to determine PID of locking process.')
194 a8083063 Iustin Pop
195 a8083063 Iustin Pop
  if pid != os.getpid():
196 a8083063 Iustin Pop
    raise errors.LockError('Lock not held by me (%d != %d)' %
197 a8083063 Iustin Pop
                           (os.getpid(), pid,))
198 a8083063 Iustin Pop
199 a8083063 Iustin Pop
  os.unlink(lockfile)
200 a8083063 Iustin Pop
  _locksheld.remove(name)
201 a8083063 Iustin Pop
202 a8083063 Iustin Pop
203 a8083063 Iustin Pop
def LockCleanup():
204 098c0958 Michael Hanselmann
  """Remove all locks.
205 a8083063 Iustin Pop

206 098c0958 Michael Hanselmann
  """
207 a8083063 Iustin Pop
  for lock in _locksheld:
208 a8083063 Iustin Pop
    Unlock(lock)
209 a8083063 Iustin Pop
210 a8083063 Iustin Pop
211 a8083063 Iustin Pop
def RunCmd(cmd):
212 a8083063 Iustin Pop
  """Execute a (shell) command.
213 a8083063 Iustin Pop

214 a8083063 Iustin Pop
  The command should not read from its standard input, as it will be
215 a8083063 Iustin Pop
  closed.
216 a8083063 Iustin Pop

217 a8083063 Iustin Pop
  Args:
218 a8083063 Iustin Pop
    cmd: command to run. (str)
219 a8083063 Iustin Pop

220 a8083063 Iustin Pop
  Returns: `RunResult` instance
221 a8083063 Iustin Pop

222 a8083063 Iustin Pop
  """
223 b74159ee Iustin Pop
  if no_fork:
224 b74159ee Iustin Pop
    raise errors.ProgrammerError("utils.RunCmd() called with fork() disabled")
225 b74159ee Iustin Pop
226 a8083063 Iustin Pop
  if isinstance(cmd, list):
227 a8083063 Iustin Pop
    cmd = [str(val) for val in cmd]
228 113b55aa Iustin Pop
    strcmd = " ".join(cmd)
229 113b55aa Iustin Pop
    shell = False
230 113b55aa Iustin Pop
  else:
231 113b55aa Iustin Pop
    strcmd = cmd
232 113b55aa Iustin Pop
    shell = True
233 23f41a3e Michael Hanselmann
  env = os.environ.copy()
234 23f41a3e Michael Hanselmann
  env["LC_ALL"] = "C"
235 9c233417 Iustin Pop
  poller = select.poll()
236 113b55aa Iustin Pop
  child = subprocess.Popen(cmd, shell=shell,
237 113b55aa Iustin Pop
                           stderr=subprocess.PIPE,
238 113b55aa Iustin Pop
                           stdout=subprocess.PIPE,
239 113b55aa Iustin Pop
                           stdin=subprocess.PIPE,
240 23f41a3e Michael Hanselmann
                           close_fds=True, env=env)
241 113b55aa Iustin Pop
242 113b55aa Iustin Pop
  child.stdin.close()
243 9c233417 Iustin Pop
  poller.register(child.stdout, select.POLLIN)
244 9c233417 Iustin Pop
  poller.register(child.stderr, select.POLLIN)
245 9c233417 Iustin Pop
  out = StringIO()
246 9c233417 Iustin Pop
  err = StringIO()
247 9c233417 Iustin Pop
  fdmap = {
248 9c233417 Iustin Pop
    child.stdout.fileno(): (out, child.stdout),
249 9c233417 Iustin Pop
    child.stderr.fileno(): (err, child.stderr),
250 9c233417 Iustin Pop
    }
251 9c233417 Iustin Pop
  for fd in fdmap:
252 9c233417 Iustin Pop
    status = fcntl.fcntl(fd, fcntl.F_GETFL)
253 9c233417 Iustin Pop
    fcntl.fcntl(fd, fcntl.F_SETFL, status | os.O_NONBLOCK)
254 9c233417 Iustin Pop
255 9c233417 Iustin Pop
  while fdmap:
256 9c233417 Iustin Pop
    for fd, event in poller.poll():
257 9c233417 Iustin Pop
      if event & select.POLLIN or event & select.POLLPRI:
258 9c233417 Iustin Pop
        data = fdmap[fd][1].read()
259 9c233417 Iustin Pop
        # no data from read signifies EOF (the same as POLLHUP)
260 9c233417 Iustin Pop
        if not data:
261 9c233417 Iustin Pop
          poller.unregister(fd)
262 9c233417 Iustin Pop
          del fdmap[fd]
263 9c233417 Iustin Pop
          continue
264 9c233417 Iustin Pop
        fdmap[fd][0].write(data)
265 9c233417 Iustin Pop
      if (event & select.POLLNVAL or event & select.POLLHUP or
266 9c233417 Iustin Pop
          event & select.POLLERR):
267 9c233417 Iustin Pop
        poller.unregister(fd)
268 9c233417 Iustin Pop
        del fdmap[fd]
269 9c233417 Iustin Pop
270 9c233417 Iustin Pop
  out = out.getvalue()
271 9c233417 Iustin Pop
  err = err.getvalue()
272 a8083063 Iustin Pop
273 a8083063 Iustin Pop
  status = child.wait()
274 113b55aa Iustin Pop
  if status >= 0:
275 113b55aa Iustin Pop
    exitcode = status
276 a8083063 Iustin Pop
    signal = None
277 a8083063 Iustin Pop
  else:
278 a8083063 Iustin Pop
    exitcode = None
279 113b55aa Iustin Pop
    signal = -status
280 a8083063 Iustin Pop
281 a8083063 Iustin Pop
  return RunResult(exitcode, signal, out, err, strcmd)
282 a8083063 Iustin Pop
283 a8083063 Iustin Pop
284 a8083063 Iustin Pop
def RunCmdUnlocked(cmd):
285 a8083063 Iustin Pop
  """Execute a shell command without the 'cmd' lock.
286 a8083063 Iustin Pop

287 a8083063 Iustin Pop
  This variant of `RunCmd()` drops the 'cmd' lock before running the
288 a8083063 Iustin Pop
  command and re-aquires it afterwards, thus it can be used to call
289 a8083063 Iustin Pop
  other ganeti commands.
290 a8083063 Iustin Pop

291 a8083063 Iustin Pop
  The argument and return values are the same as for the `RunCmd()`
292 a8083063 Iustin Pop
  function.
293 a8083063 Iustin Pop

294 a8083063 Iustin Pop
  Args:
295 a8083063 Iustin Pop
    cmd - command to run. (str)
296 a8083063 Iustin Pop

297 a8083063 Iustin Pop
  Returns:
298 a8083063 Iustin Pop
    `RunResult`
299 a8083063 Iustin Pop

300 a8083063 Iustin Pop
  """
301 a8083063 Iustin Pop
  Unlock('cmd')
302 a8083063 Iustin Pop
  ret = RunCmd(cmd)
303 a8083063 Iustin Pop
  Lock('cmd')
304 a8083063 Iustin Pop
305 a8083063 Iustin Pop
  return ret
306 a8083063 Iustin Pop
307 a8083063 Iustin Pop
308 a8083063 Iustin Pop
def RemoveFile(filename):
309 a8083063 Iustin Pop
  """Remove a file ignoring some errors.
310 a8083063 Iustin Pop

311 a8083063 Iustin Pop
  Remove a file, ignoring non-existing ones or directories. Other
312 a8083063 Iustin Pop
  errors are passed.
313 a8083063 Iustin Pop

314 a8083063 Iustin Pop
  """
315 a8083063 Iustin Pop
  try:
316 a8083063 Iustin Pop
    os.unlink(filename)
317 a8083063 Iustin Pop
  except OSError, err:
318 4ca1b175 Alexander Schreiber
    if err.errno not in (errno.ENOENT, errno.EISDIR):
319 a8083063 Iustin Pop
      raise
320 a8083063 Iustin Pop
321 a8083063 Iustin Pop
322 a8083063 Iustin Pop
def _FingerprintFile(filename):
323 a8083063 Iustin Pop
  """Compute the fingerprint of a file.
324 a8083063 Iustin Pop

325 a8083063 Iustin Pop
  If the file does not exist, a None will be returned
326 a8083063 Iustin Pop
  instead.
327 a8083063 Iustin Pop

328 a8083063 Iustin Pop
  Args:
329 a8083063 Iustin Pop
    filename - Filename (str)
330 a8083063 Iustin Pop

331 a8083063 Iustin Pop
  """
332 a8083063 Iustin Pop
  if not (os.path.exists(filename) and os.path.isfile(filename)):
333 a8083063 Iustin Pop
    return None
334 a8083063 Iustin Pop
335 a8083063 Iustin Pop
  f = open(filename)
336 a8083063 Iustin Pop
337 a8083063 Iustin Pop
  fp = sha.sha()
338 a8083063 Iustin Pop
  while True:
339 a8083063 Iustin Pop
    data = f.read(4096)
340 a8083063 Iustin Pop
    if not data:
341 a8083063 Iustin Pop
      break
342 a8083063 Iustin Pop
343 a8083063 Iustin Pop
    fp.update(data)
344 a8083063 Iustin Pop
345 a8083063 Iustin Pop
  return fp.hexdigest()
346 a8083063 Iustin Pop
347 a8083063 Iustin Pop
348 a8083063 Iustin Pop
def FingerprintFiles(files):
349 a8083063 Iustin Pop
  """Compute fingerprints for a list of files.
350 a8083063 Iustin Pop

351 a8083063 Iustin Pop
  Args:
352 a8083063 Iustin Pop
    files - array of filenames.  ( [str, ...] )
353 a8083063 Iustin Pop

354 a8083063 Iustin Pop
  Return value:
355 a8083063 Iustin Pop
    dictionary of filename: fingerprint for the files that exist
356 a8083063 Iustin Pop

357 a8083063 Iustin Pop
  """
358 a8083063 Iustin Pop
  ret = {}
359 a8083063 Iustin Pop
360 a8083063 Iustin Pop
  for filename in files:
361 a8083063 Iustin Pop
    cksum = _FingerprintFile(filename)
362 a8083063 Iustin Pop
    if cksum:
363 a8083063 Iustin Pop
      ret[filename] = cksum
364 a8083063 Iustin Pop
365 a8083063 Iustin Pop
  return ret
366 a8083063 Iustin Pop
367 a8083063 Iustin Pop
368 a8083063 Iustin Pop
def CheckDict(target, template, logname=None):
369 a8083063 Iustin Pop
  """Ensure a dictionary has a required set of keys.
370 a8083063 Iustin Pop

371 a8083063 Iustin Pop
  For the given dictionaries `target` and `template`, ensure target
372 a8083063 Iustin Pop
  has all the keys from template. Missing keys are added with values
373 a8083063 Iustin Pop
  from template.
374 a8083063 Iustin Pop

375 a8083063 Iustin Pop
  Args:
376 a8083063 Iustin Pop
    target   - the dictionary to check
377 a8083063 Iustin Pop
    template - template dictionary
378 a8083063 Iustin Pop
    logname  - a caller-chosen string to identify the debug log
379 a8083063 Iustin Pop
               entry; if None, no logging will be done
380 a8083063 Iustin Pop

381 a8083063 Iustin Pop
  Returns value:
382 a8083063 Iustin Pop
    None
383 a8083063 Iustin Pop

384 a8083063 Iustin Pop
  """
385 a8083063 Iustin Pop
  missing = []
386 a8083063 Iustin Pop
  for k in template:
387 a8083063 Iustin Pop
    if k not in target:
388 a8083063 Iustin Pop
      missing.append(k)
389 a8083063 Iustin Pop
      target[k] = template[k]
390 a8083063 Iustin Pop
391 a8083063 Iustin Pop
  if missing and logname:
392 a8083063 Iustin Pop
    logger.Debug('%s missing keys %s' %
393 a8083063 Iustin Pop
                 (logname, ', '.join(missing)))
394 a8083063 Iustin Pop
395 a8083063 Iustin Pop
396 a8083063 Iustin Pop
def IsProcessAlive(pid):
397 a8083063 Iustin Pop
  """Check if a given pid exists on the system.
398 a8083063 Iustin Pop

399 a8083063 Iustin Pop
  Returns: true or false, depending on if the pid exists or not
400 a8083063 Iustin Pop

401 a8083063 Iustin Pop
  Remarks: zombie processes treated as not alive
402 a8083063 Iustin Pop

403 a8083063 Iustin Pop
  """
404 a8083063 Iustin Pop
  try:
405 a8083063 Iustin Pop
    f = open("/proc/%d/status" % pid)
406 a8083063 Iustin Pop
  except IOError, err:
407 4ca1b175 Alexander Schreiber
    if err.errno in (errno.ENOENT, errno.ENOTDIR):
408 a8083063 Iustin Pop
      return False
409 a8083063 Iustin Pop
410 a8083063 Iustin Pop
  alive = True
411 a8083063 Iustin Pop
  try:
412 a8083063 Iustin Pop
    data = f.readlines()
413 a8083063 Iustin Pop
    if len(data) > 1:
414 a8083063 Iustin Pop
      state = data[1].split()
415 a8083063 Iustin Pop
      if len(state) > 1 and state[1] == "Z":
416 a8083063 Iustin Pop
        alive = False
417 a8083063 Iustin Pop
  finally:
418 a8083063 Iustin Pop
    f.close()
419 a8083063 Iustin Pop
420 a8083063 Iustin Pop
  return alive
421 a8083063 Iustin Pop
422 a8083063 Iustin Pop
423 a8083063 Iustin Pop
def MatchNameComponent(key, name_list):
424 a8083063 Iustin Pop
  """Try to match a name against a list.
425 a8083063 Iustin Pop

426 a8083063 Iustin Pop
  This function will try to match a name like test1 against a list
427 a8083063 Iustin Pop
  like ['test1.example.com', 'test2.example.com', ...]. Against this
428 a8083063 Iustin Pop
  list, 'test1' as well as 'test1.example' will match, but not
429 a8083063 Iustin Pop
  'test1.ex'. A multiple match will be considered as no match at all
430 a8083063 Iustin Pop
  (e.g. 'test1' against ['test1.example.com', 'test1.example.org']).
431 a8083063 Iustin Pop

432 a8083063 Iustin Pop
  Args:
433 a8083063 Iustin Pop
    key: the name to be searched
434 a8083063 Iustin Pop
    name_list: the list of strings against which to search the key
435 a8083063 Iustin Pop

436 a8083063 Iustin Pop
  Returns:
437 a8083063 Iustin Pop
    None if there is no match *or* if there are multiple matches
438 a8083063 Iustin Pop
    otherwise the element from the list which matches
439 a8083063 Iustin Pop

440 a8083063 Iustin Pop
  """
441 a8083063 Iustin Pop
  mo = re.compile("^%s(\..*)?$" % re.escape(key))
442 a8083063 Iustin Pop
  names_filtered = [name for name in name_list if mo.match(name) is not None]
443 a8083063 Iustin Pop
  if len(names_filtered) != 1:
444 a8083063 Iustin Pop
    return None
445 a8083063 Iustin Pop
  return names_filtered[0]
446 a8083063 Iustin Pop
447 a8083063 Iustin Pop
448 bcf043c9 Iustin Pop
class HostInfo:
449 89e1fc26 Iustin Pop
  """Class implementing resolver and hostname functionality
450 bcf043c9 Iustin Pop

451 bcf043c9 Iustin Pop
  """
452 89e1fc26 Iustin Pop
  def __init__(self, name=None):
453 bcf043c9 Iustin Pop
    """Initialize the host name object.
454 bcf043c9 Iustin Pop

455 89e1fc26 Iustin Pop
    If the name argument is not passed, it will use this system's
456 89e1fc26 Iustin Pop
    name.
457 bcf043c9 Iustin Pop

458 bcf043c9 Iustin Pop
    """
459 89e1fc26 Iustin Pop
    if name is None:
460 89e1fc26 Iustin Pop
      name = self.SysName()
461 89e1fc26 Iustin Pop
462 89e1fc26 Iustin Pop
    self.query = name
463 89e1fc26 Iustin Pop
    self.name, self.aliases, self.ipaddrs = self.LookupHostname(name)
464 bcf043c9 Iustin Pop
    self.ip = self.ipaddrs[0]
465 bcf043c9 Iustin Pop
466 c8a0948f Michael Hanselmann
  def ShortName(self):
467 c8a0948f Michael Hanselmann
    """Returns the hostname without domain.
468 c8a0948f Michael Hanselmann

469 c8a0948f Michael Hanselmann
    """
470 c8a0948f Michael Hanselmann
    return self.name.split('.')[0]
471 c8a0948f Michael Hanselmann
472 89e1fc26 Iustin Pop
  @staticmethod
473 89e1fc26 Iustin Pop
  def SysName():
474 89e1fc26 Iustin Pop
    """Return the current system's name.
475 bcf043c9 Iustin Pop

476 89e1fc26 Iustin Pop
    This is simply a wrapper over socket.gethostname()
477 a8083063 Iustin Pop

478 89e1fc26 Iustin Pop
    """
479 89e1fc26 Iustin Pop
    return socket.gethostname()
480 a8083063 Iustin Pop
481 89e1fc26 Iustin Pop
  @staticmethod
482 89e1fc26 Iustin Pop
  def LookupHostname(hostname):
483 89e1fc26 Iustin Pop
    """Look up hostname
484 a8083063 Iustin Pop

485 89e1fc26 Iustin Pop
    Args:
486 89e1fc26 Iustin Pop
      hostname: hostname to look up
487 89e1fc26 Iustin Pop

488 89e1fc26 Iustin Pop
    Returns:
489 89e1fc26 Iustin Pop
      a tuple (name, aliases, ipaddrs) as returned by socket.gethostbyname_ex
490 89e1fc26 Iustin Pop
      in case of errors in resolving, we raise a ResolverError
491 89e1fc26 Iustin Pop

492 89e1fc26 Iustin Pop
    """
493 89e1fc26 Iustin Pop
    try:
494 89e1fc26 Iustin Pop
      result = socket.gethostbyname_ex(hostname)
495 89e1fc26 Iustin Pop
    except socket.gaierror, err:
496 89e1fc26 Iustin Pop
      # hostname not found in DNS
497 89e1fc26 Iustin Pop
      raise errors.ResolverError(hostname, err.args[0], err.args[1])
498 a8083063 Iustin Pop
499 89e1fc26 Iustin Pop
    return result
500 a8083063 Iustin Pop
501 a8083063 Iustin Pop
502 a8083063 Iustin Pop
def ListVolumeGroups():
503 a8083063 Iustin Pop
  """List volume groups and their size
504 a8083063 Iustin Pop

505 a8083063 Iustin Pop
  Returns:
506 a8083063 Iustin Pop
     Dictionary with keys volume name and values the size of the volume
507 a8083063 Iustin Pop

508 a8083063 Iustin Pop
  """
509 a8083063 Iustin Pop
  command = "vgs --noheadings --units m --nosuffix -o name,size"
510 a8083063 Iustin Pop
  result = RunCmd(command)
511 a8083063 Iustin Pop
  retval = {}
512 a8083063 Iustin Pop
  if result.failed:
513 a8083063 Iustin Pop
    return retval
514 a8083063 Iustin Pop
515 a8083063 Iustin Pop
  for line in result.stdout.splitlines():
516 a8083063 Iustin Pop
    try:
517 a8083063 Iustin Pop
      name, size = line.split()
518 a8083063 Iustin Pop
      size = int(float(size))
519 a8083063 Iustin Pop
    except (IndexError, ValueError), err:
520 a8083063 Iustin Pop
      logger.Error("Invalid output from vgs (%s): %s" % (err, line))
521 a8083063 Iustin Pop
      continue
522 a8083063 Iustin Pop
523 a8083063 Iustin Pop
    retval[name] = size
524 a8083063 Iustin Pop
525 a8083063 Iustin Pop
  return retval
526 a8083063 Iustin Pop
527 a8083063 Iustin Pop
528 a8083063 Iustin Pop
def BridgeExists(bridge):
529 a8083063 Iustin Pop
  """Check whether the given bridge exists in the system
530 a8083063 Iustin Pop

531 a8083063 Iustin Pop
  Returns:
532 a8083063 Iustin Pop
     True if it does, false otherwise.
533 a8083063 Iustin Pop

534 a8083063 Iustin Pop
  """
535 a8083063 Iustin Pop
  return os.path.isdir("/sys/class/net/%s/bridge" % bridge)
536 a8083063 Iustin Pop
537 a8083063 Iustin Pop
538 a8083063 Iustin Pop
def NiceSort(name_list):
539 a8083063 Iustin Pop
  """Sort a list of strings based on digit and non-digit groupings.
540 a8083063 Iustin Pop

541 a8083063 Iustin Pop
  Given a list of names ['a1', 'a10', 'a11', 'a2'] this function will
542 a8083063 Iustin Pop
  sort the list in the logical order ['a1', 'a2', 'a10', 'a11'].
543 a8083063 Iustin Pop

544 a8083063 Iustin Pop
  The sort algorithm breaks each name in groups of either only-digits
545 a8083063 Iustin Pop
  or no-digits. Only the first eight such groups are considered, and
546 a8083063 Iustin Pop
  after that we just use what's left of the string.
547 a8083063 Iustin Pop

548 a8083063 Iustin Pop
  Return value
549 a8083063 Iustin Pop
    - a copy of the list sorted according to our algorithm
550 a8083063 Iustin Pop

551 a8083063 Iustin Pop
  """
552 a8083063 Iustin Pop
  _SORTER_BASE = "(\D+|\d+)"
553 a8083063 Iustin Pop
  _SORTER_FULL = "^%s%s?%s?%s?%s?%s?%s?%s?.*$" % (_SORTER_BASE, _SORTER_BASE,
554 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE,
555 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE,
556 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE)
557 a8083063 Iustin Pop
  _SORTER_RE = re.compile(_SORTER_FULL)
558 a8083063 Iustin Pop
  _SORTER_NODIGIT = re.compile("^\D*$")
559 a8083063 Iustin Pop
  def _TryInt(val):
560 a8083063 Iustin Pop
    """Attempts to convert a variable to integer."""
561 a8083063 Iustin Pop
    if val is None or _SORTER_NODIGIT.match(val):
562 a8083063 Iustin Pop
      return val
563 a8083063 Iustin Pop
    rval = int(val)
564 a8083063 Iustin Pop
    return rval
565 a8083063 Iustin Pop
566 a8083063 Iustin Pop
  to_sort = [([_TryInt(grp) for grp in _SORTER_RE.match(name).groups()], name)
567 a8083063 Iustin Pop
             for name in name_list]
568 a8083063 Iustin Pop
  to_sort.sort()
569 a8083063 Iustin Pop
  return [tup[1] for tup in to_sort]
570 a8083063 Iustin Pop
571 a8083063 Iustin Pop
572 a8083063 Iustin Pop
def TryConvert(fn, val):
573 a8083063 Iustin Pop
  """Try to convert a value ignoring errors.
574 a8083063 Iustin Pop

575 a8083063 Iustin Pop
  This function tries to apply function `fn` to `val`. If no
576 a8083063 Iustin Pop
  ValueError or TypeError exceptions are raised, it will return the
577 a8083063 Iustin Pop
  result, else it will return the original value. Any other exceptions
578 a8083063 Iustin Pop
  are propagated to the caller.
579 a8083063 Iustin Pop

580 a8083063 Iustin Pop
  """
581 a8083063 Iustin Pop
  try:
582 a8083063 Iustin Pop
    nv = fn(val)
583 a8083063 Iustin Pop
  except (ValueError, TypeError), err:
584 a8083063 Iustin Pop
    nv = val
585 a8083063 Iustin Pop
  return nv
586 a8083063 Iustin Pop
587 a8083063 Iustin Pop
588 a8083063 Iustin Pop
def IsValidIP(ip):
589 a8083063 Iustin Pop
  """Verifies the syntax of an IP address.
590 a8083063 Iustin Pop

591 a8083063 Iustin Pop
  This function checks if the ip address passes is valid or not based
592 a8083063 Iustin Pop
  on syntax (not ip range, class calculations or anything).
593 a8083063 Iustin Pop

594 a8083063 Iustin Pop
  """
595 a8083063 Iustin Pop
  unit = "(0|[1-9]\d{0,2})"
596 a8083063 Iustin Pop
  return re.match("^%s\.%s\.%s\.%s$" % (unit, unit, unit, unit), ip)
597 a8083063 Iustin Pop
598 a8083063 Iustin Pop
599 a8083063 Iustin Pop
def IsValidShellParam(word):
600 a8083063 Iustin Pop
  """Verifies is the given word is safe from the shell's p.o.v.
601 a8083063 Iustin Pop

602 a8083063 Iustin Pop
  This means that we can pass this to a command via the shell and be
603 a8083063 Iustin Pop
  sure that it doesn't alter the command line and is passed as such to
604 a8083063 Iustin Pop
  the actual command.
605 a8083063 Iustin Pop

606 a8083063 Iustin Pop
  Note that we are overly restrictive here, in order to be on the safe
607 a8083063 Iustin Pop
  side.
608 a8083063 Iustin Pop

609 a8083063 Iustin Pop
  """
610 a8083063 Iustin Pop
  return bool(re.match("^[-a-zA-Z0-9._+/:%@]+$", word))
611 a8083063 Iustin Pop
612 a8083063 Iustin Pop
613 a8083063 Iustin Pop
def BuildShellCmd(template, *args):
614 a8083063 Iustin Pop
  """Build a safe shell command line from the given arguments.
615 a8083063 Iustin Pop

616 a8083063 Iustin Pop
  This function will check all arguments in the args list so that they
617 a8083063 Iustin Pop
  are valid shell parameters (i.e. they don't contain shell
618 a8083063 Iustin Pop
  metacharaters). If everything is ok, it will return the result of
619 a8083063 Iustin Pop
  template % args.
620 a8083063 Iustin Pop

621 a8083063 Iustin Pop
  """
622 a8083063 Iustin Pop
  for word in args:
623 a8083063 Iustin Pop
    if not IsValidShellParam(word):
624 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Shell argument '%s' contains"
625 3ecf6786 Iustin Pop
                                   " invalid characters" % word)
626 a8083063 Iustin Pop
  return template % args
627 a8083063 Iustin Pop
628 a8083063 Iustin Pop
629 a8083063 Iustin Pop
def FormatUnit(value):
630 a8083063 Iustin Pop
  """Formats an incoming number of MiB with the appropriate unit.
631 a8083063 Iustin Pop

632 a8083063 Iustin Pop
  Value needs to be passed as a numeric type. Return value is always a string.
633 a8083063 Iustin Pop

634 a8083063 Iustin Pop
  """
635 a8083063 Iustin Pop
  if value < 1024:
636 a8083063 Iustin Pop
    return "%dM" % round(value, 0)
637 a8083063 Iustin Pop
638 a8083063 Iustin Pop
  elif value < (1024 * 1024):
639 a8083063 Iustin Pop
    return "%0.1fG" % round(float(value) / 1024, 1)
640 a8083063 Iustin Pop
641 a8083063 Iustin Pop
  else:
642 a8083063 Iustin Pop
    return "%0.1fT" % round(float(value) / 1024 / 1024, 1)
643 a8083063 Iustin Pop
644 a8083063 Iustin Pop
645 a8083063 Iustin Pop
def ParseUnit(input_string):
646 a8083063 Iustin Pop
  """Tries to extract number and scale from the given string.
647 a8083063 Iustin Pop

648 a8083063 Iustin Pop
  Input must be in the format NUMBER+ [DOT NUMBER+] SPACE* [UNIT]. If no unit
649 a8083063 Iustin Pop
  is specified, it defaults to MiB. Return value is always an int in MiB.
650 a8083063 Iustin Pop

651 a8083063 Iustin Pop
  """
652 a8083063 Iustin Pop
  m = re.match('^([.\d]+)\s*([a-zA-Z]+)?$', input_string)
653 a8083063 Iustin Pop
  if not m:
654 3ecf6786 Iustin Pop
    raise errors.UnitParseError("Invalid format")
655 a8083063 Iustin Pop
656 a8083063 Iustin Pop
  value = float(m.groups()[0])
657 a8083063 Iustin Pop
658 a8083063 Iustin Pop
  unit = m.groups()[1]
659 a8083063 Iustin Pop
  if unit:
660 a8083063 Iustin Pop
    lcunit = unit.lower()
661 a8083063 Iustin Pop
  else:
662 a8083063 Iustin Pop
    lcunit = 'm'
663 a8083063 Iustin Pop
664 a8083063 Iustin Pop
  if lcunit in ('m', 'mb', 'mib'):
665 a8083063 Iustin Pop
    # Value already in MiB
666 a8083063 Iustin Pop
    pass
667 a8083063 Iustin Pop
668 a8083063 Iustin Pop
  elif lcunit in ('g', 'gb', 'gib'):
669 a8083063 Iustin Pop
    value *= 1024
670 a8083063 Iustin Pop
671 a8083063 Iustin Pop
  elif lcunit in ('t', 'tb', 'tib'):
672 a8083063 Iustin Pop
    value *= 1024 * 1024
673 a8083063 Iustin Pop
674 a8083063 Iustin Pop
  else:
675 3ecf6786 Iustin Pop
    raise errors.UnitParseError("Unknown unit: %s" % unit)
676 a8083063 Iustin Pop
677 a8083063 Iustin Pop
  # Make sure we round up
678 a8083063 Iustin Pop
  if int(value) < value:
679 a8083063 Iustin Pop
    value += 1
680 a8083063 Iustin Pop
681 a8083063 Iustin Pop
  # Round up to the next multiple of 4
682 a8083063 Iustin Pop
  value = int(value)
683 a8083063 Iustin Pop
  if value % 4:
684 a8083063 Iustin Pop
    value += 4 - value % 4
685 a8083063 Iustin Pop
686 a8083063 Iustin Pop
  return value
687 a8083063 Iustin Pop
688 a8083063 Iustin Pop
689 a8083063 Iustin Pop
def AddAuthorizedKey(file_name, key):
690 a8083063 Iustin Pop
  """Adds an SSH public key to an authorized_keys file.
691 a8083063 Iustin Pop

692 a8083063 Iustin Pop
  Args:
693 a8083063 Iustin Pop
    file_name: Path to authorized_keys file
694 a8083063 Iustin Pop
    key: String containing key
695 a8083063 Iustin Pop
  """
696 a8083063 Iustin Pop
  key_fields = key.split()
697 a8083063 Iustin Pop
698 a8083063 Iustin Pop
  f = open(file_name, 'a+')
699 a8083063 Iustin Pop
  try:
700 a8083063 Iustin Pop
    nl = True
701 a8083063 Iustin Pop
    for line in f:
702 a8083063 Iustin Pop
      # Ignore whitespace changes
703 a8083063 Iustin Pop
      if line.split() == key_fields:
704 a8083063 Iustin Pop
        break
705 a8083063 Iustin Pop
      nl = line.endswith('\n')
706 a8083063 Iustin Pop
    else:
707 a8083063 Iustin Pop
      if not nl:
708 a8083063 Iustin Pop
        f.write("\n")
709 a8083063 Iustin Pop
      f.write(key.rstrip('\r\n'))
710 a8083063 Iustin Pop
      f.write("\n")
711 a8083063 Iustin Pop
      f.flush()
712 a8083063 Iustin Pop
  finally:
713 a8083063 Iustin Pop
    f.close()
714 a8083063 Iustin Pop
715 a8083063 Iustin Pop
716 a8083063 Iustin Pop
def RemoveAuthorizedKey(file_name, key):
717 a8083063 Iustin Pop
  """Removes an SSH public key from an authorized_keys file.
718 a8083063 Iustin Pop

719 a8083063 Iustin Pop
  Args:
720 a8083063 Iustin Pop
    file_name: Path to authorized_keys file
721 a8083063 Iustin Pop
    key: String containing key
722 a8083063 Iustin Pop
  """
723 a8083063 Iustin Pop
  key_fields = key.split()
724 a8083063 Iustin Pop
725 a8083063 Iustin Pop
  fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name))
726 a8083063 Iustin Pop
  try:
727 59f82e3f Michael Hanselmann
    out = os.fdopen(fd, 'w')
728 a8083063 Iustin Pop
    try:
729 59f82e3f Michael Hanselmann
      f = open(file_name, 'r')
730 59f82e3f Michael Hanselmann
      try:
731 59f82e3f Michael Hanselmann
        for line in f:
732 59f82e3f Michael Hanselmann
          # Ignore whitespace changes while comparing lines
733 59f82e3f Michael Hanselmann
          if line.split() != key_fields:
734 59f82e3f Michael Hanselmann
            out.write(line)
735 899d2a81 Michael Hanselmann
736 899d2a81 Michael Hanselmann
        out.flush()
737 899d2a81 Michael Hanselmann
        os.rename(tmpname, file_name)
738 899d2a81 Michael Hanselmann
      finally:
739 899d2a81 Michael Hanselmann
        f.close()
740 899d2a81 Michael Hanselmann
    finally:
741 899d2a81 Michael Hanselmann
      out.close()
742 899d2a81 Michael Hanselmann
  except:
743 899d2a81 Michael Hanselmann
    RemoveFile(tmpname)
744 899d2a81 Michael Hanselmann
    raise
745 899d2a81 Michael Hanselmann
746 899d2a81 Michael Hanselmann
747 9440aeab Michael Hanselmann
def SetEtcHostsEntry(file_name, ip, hostname, aliases):
748 9440aeab Michael Hanselmann
  """Sets the name of an IP address and hostname in /etc/hosts.
749 899d2a81 Michael Hanselmann

750 899d2a81 Michael Hanselmann
  """
751 7fbb1f65 Michael Hanselmann
  # Ensure aliases are unique
752 7fbb1f65 Michael Hanselmann
  aliases = UniqueSequence([hostname] + aliases)[1:]
753 7fbb1f65 Michael Hanselmann
754 9440aeab Michael Hanselmann
  fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name))
755 899d2a81 Michael Hanselmann
  try:
756 9440aeab Michael Hanselmann
    out = os.fdopen(fd, 'w')
757 9440aeab Michael Hanselmann
    try:
758 9440aeab Michael Hanselmann
      f = open(file_name, 'r')
759 9440aeab Michael Hanselmann
      try:
760 9440aeab Michael Hanselmann
        written = False
761 9440aeab Michael Hanselmann
        for line in f:
762 9440aeab Michael Hanselmann
          fields = line.split()
763 7e3dbb94 Iustin Pop
          if fields and not fields[0].startswith('#') and ip == fields[0]:
764 9440aeab Michael Hanselmann
            continue
765 9440aeab Michael Hanselmann
          out.write(line)
766 9440aeab Michael Hanselmann
767 7e3dbb94 Iustin Pop
        out.write("%s\t%s" % (ip, hostname))
768 9440aeab Michael Hanselmann
        if aliases:
769 9440aeab Michael Hanselmann
          out.write(" %s" % ' '.join(aliases))
770 9440aeab Michael Hanselmann
        out.write('\n')
771 9440aeab Michael Hanselmann
772 9440aeab Michael Hanselmann
        out.flush()
773 2e3e75b7 Michael Hanselmann
        os.fsync(out)
774 9440aeab Michael Hanselmann
        os.rename(tmpname, file_name)
775 9440aeab Michael Hanselmann
      finally:
776 9440aeab Michael Hanselmann
        f.close()
777 9440aeab Michael Hanselmann
    finally:
778 9440aeab Michael Hanselmann
      out.close()
779 9440aeab Michael Hanselmann
  except:
780 9440aeab Michael Hanselmann
    RemoveFile(tmpname)
781 9440aeab Michael Hanselmann
    raise
782 899d2a81 Michael Hanselmann
783 899d2a81 Michael Hanselmann
784 d9c02ca6 Michael Hanselmann
def AddHostToEtcHosts(hostname):
785 d9c02ca6 Michael Hanselmann
  """Wrapper around SetEtcHostsEntry.
786 d9c02ca6 Michael Hanselmann

787 d9c02ca6 Michael Hanselmann
  """
788 d9c02ca6 Michael Hanselmann
  hi = HostInfo(name=hostname)
789 d9c02ca6 Michael Hanselmann
  SetEtcHostsEntry(constants.ETC_HOSTS, hi.ip, hi.name, [hi.ShortName()])
790 d9c02ca6 Michael Hanselmann
791 d9c02ca6 Michael Hanselmann
792 899d2a81 Michael Hanselmann
def RemoveEtcHostsEntry(file_name, hostname):
793 3e1cdf9f Michael Hanselmann
  """Removes a hostname from /etc/hosts.
794 899d2a81 Michael Hanselmann

795 9440aeab Michael Hanselmann
  IP addresses without names are removed from the file.
796 899d2a81 Michael Hanselmann
  """
797 899d2a81 Michael Hanselmann
  fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name))
798 899d2a81 Michael Hanselmann
  try:
799 899d2a81 Michael Hanselmann
    out = os.fdopen(fd, 'w')
800 899d2a81 Michael Hanselmann
    try:
801 899d2a81 Michael Hanselmann
      f = open(file_name, 'r')
802 899d2a81 Michael Hanselmann
      try:
803 899d2a81 Michael Hanselmann
        for line in f:
804 899d2a81 Michael Hanselmann
          fields = line.split()
805 899d2a81 Michael Hanselmann
          if len(fields) > 1 and not fields[0].startswith('#'):
806 899d2a81 Michael Hanselmann
            names = fields[1:]
807 899d2a81 Michael Hanselmann
            if hostname in names:
808 899d2a81 Michael Hanselmann
              while hostname in names:
809 899d2a81 Michael Hanselmann
                names.remove(hostname)
810 899d2a81 Michael Hanselmann
              if names:
811 9440aeab Michael Hanselmann
                out.write("%s %s\n" % (fields[0], ' '.join(names)))
812 899d2a81 Michael Hanselmann
              continue
813 899d2a81 Michael Hanselmann
814 899d2a81 Michael Hanselmann
          out.write(line)
815 59f82e3f Michael Hanselmann
816 59f82e3f Michael Hanselmann
        out.flush()
817 2e3e75b7 Michael Hanselmann
        os.fsync(out)
818 59f82e3f Michael Hanselmann
        os.rename(tmpname, file_name)
819 59f82e3f Michael Hanselmann
      finally:
820 59f82e3f Michael Hanselmann
        f.close()
821 a8083063 Iustin Pop
    finally:
822 59f82e3f Michael Hanselmann
      out.close()
823 59f82e3f Michael Hanselmann
  except:
824 59f82e3f Michael Hanselmann
    RemoveFile(tmpname)
825 59f82e3f Michael Hanselmann
    raise
826 a8083063 Iustin Pop
827 a8083063 Iustin Pop
828 d9c02ca6 Michael Hanselmann
def RemoveHostFromEtcHosts(hostname):
829 d9c02ca6 Michael Hanselmann
  """Wrapper around RemoveEtcHostsEntry.
830 d9c02ca6 Michael Hanselmann

831 d9c02ca6 Michael Hanselmann
  """
832 d9c02ca6 Michael Hanselmann
  hi = HostInfo(name=hostname)
833 d9c02ca6 Michael Hanselmann
  RemoveEtcHostsEntry(constants.ETC_HOSTS, hi.name)
834 d9c02ca6 Michael Hanselmann
  RemoveEtcHostsEntry(constants.ETC_HOSTS, hi.ShortName())
835 d9c02ca6 Michael Hanselmann
836 d9c02ca6 Michael Hanselmann
837 a8083063 Iustin Pop
def CreateBackup(file_name):
838 a8083063 Iustin Pop
  """Creates a backup of a file.
839 a8083063 Iustin Pop

840 a8083063 Iustin Pop
  Returns: the path to the newly created backup file.
841 a8083063 Iustin Pop

842 a8083063 Iustin Pop
  """
843 a8083063 Iustin Pop
  if not os.path.isfile(file_name):
844 3ecf6786 Iustin Pop
    raise errors.ProgrammerError("Can't make a backup of a non-file '%s'" %
845 3ecf6786 Iustin Pop
                                file_name)
846 a8083063 Iustin Pop
847 081b1e69 Michael Hanselmann
  prefix = '%s.backup-%d.' % (os.path.basename(file_name), int(time.time()))
848 65fe4693 Iustin Pop
  dir_name = os.path.dirname(file_name)
849 081b1e69 Michael Hanselmann
850 081b1e69 Michael Hanselmann
  fsrc = open(file_name, 'rb')
851 081b1e69 Michael Hanselmann
  try:
852 65fe4693 Iustin Pop
    (fd, backup_name) = tempfile.mkstemp(prefix=prefix, dir=dir_name)
853 081b1e69 Michael Hanselmann
    fdst = os.fdopen(fd, 'wb')
854 081b1e69 Michael Hanselmann
    try:
855 081b1e69 Michael Hanselmann
      shutil.copyfileobj(fsrc, fdst)
856 081b1e69 Michael Hanselmann
    finally:
857 081b1e69 Michael Hanselmann
      fdst.close()
858 081b1e69 Michael Hanselmann
  finally:
859 081b1e69 Michael Hanselmann
    fsrc.close()
860 081b1e69 Michael Hanselmann
861 a8083063 Iustin Pop
  return backup_name
862 a8083063 Iustin Pop
863 a8083063 Iustin Pop
864 a8083063 Iustin Pop
def ShellQuote(value):
865 a8083063 Iustin Pop
  """Quotes shell argument according to POSIX.
866 3ecf6786 Iustin Pop

867 a8083063 Iustin Pop
  """
868 a8083063 Iustin Pop
  if _re_shell_unquoted.match(value):
869 a8083063 Iustin Pop
    return value
870 a8083063 Iustin Pop
  else:
871 a8083063 Iustin Pop
    return "'%s'" % value.replace("'", "'\\''")
872 a8083063 Iustin Pop
873 a8083063 Iustin Pop
874 a8083063 Iustin Pop
def ShellQuoteArgs(args):
875 a8083063 Iustin Pop
  """Quotes all given shell arguments and concatenates using spaces.
876 a8083063 Iustin Pop

877 a8083063 Iustin Pop
  """
878 a8083063 Iustin Pop
  return ' '.join([ShellQuote(i) for i in args])
879 88d14415 Michael Hanselmann
880 88d14415 Michael Hanselmann
881 b15d625f Iustin Pop
def TcpPing(target, port, timeout=10, live_port_needed=False, source=None):
882 2c30e9d7 Alexander Schreiber
  """Simple ping implementation using TCP connect(2).
883 2c30e9d7 Alexander Schreiber

884 b15d625f Iustin Pop
  Try to do a TCP connect(2) from an optional source IP to the
885 b15d625f Iustin Pop
  specified target IP and the specified target port. If the optional
886 b15d625f Iustin Pop
  parameter live_port_needed is set to true, requires the remote end
887 b15d625f Iustin Pop
  to accept the connection. The timeout is specified in seconds and
888 b15d625f Iustin Pop
  defaults to 10 seconds. If the source optional argument is not
889 b15d625f Iustin Pop
  passed, the source address selection is left to the kernel,
890 b15d625f Iustin Pop
  otherwise we try to connect using the passed address (failures to
891 b15d625f Iustin Pop
  bind other than EADDRNOTAVAIL will be ignored).
892 2c30e9d7 Alexander Schreiber

893 2c30e9d7 Alexander Schreiber
  """
894 2c30e9d7 Alexander Schreiber
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
895 2c30e9d7 Alexander Schreiber
896 2c30e9d7 Alexander Schreiber
  sucess = False
897 2c30e9d7 Alexander Schreiber
898 b15d625f Iustin Pop
  if source is not None:
899 b15d625f Iustin Pop
    try:
900 b15d625f Iustin Pop
      sock.bind((source, 0))
901 b15d625f Iustin Pop
    except socket.error, (errcode, errstring):
902 b15d625f Iustin Pop
      if errcode == errno.EADDRNOTAVAIL:
903 b15d625f Iustin Pop
        success = False
904 2c30e9d7 Alexander Schreiber
905 2c30e9d7 Alexander Schreiber
  sock.settimeout(timeout)
906 2c30e9d7 Alexander Schreiber
907 2c30e9d7 Alexander Schreiber
  try:
908 2c30e9d7 Alexander Schreiber
    sock.connect((target, port))
909 2c30e9d7 Alexander Schreiber
    sock.close()
910 2c30e9d7 Alexander Schreiber
    success = True
911 2c30e9d7 Alexander Schreiber
  except socket.timeout:
912 2c30e9d7 Alexander Schreiber
    success = False
913 2c30e9d7 Alexander Schreiber
  except socket.error, (errcode, errstring):
914 4ca1b175 Alexander Schreiber
    success = (not live_port_needed) and (errcode == errno.ECONNREFUSED)
915 2c30e9d7 Alexander Schreiber
916 2c30e9d7 Alexander Schreiber
  return success
917 eedbda4b Michael Hanselmann
918 eedbda4b Michael Hanselmann
919 eedbda4b Michael Hanselmann
def ListVisibleFiles(path):
920 eedbda4b Michael Hanselmann
  """Returns a list of all visible files in a directory.
921 eedbda4b Michael Hanselmann

922 eedbda4b Michael Hanselmann
  """
923 f3299a07 Michael Hanselmann
  files = [i for i in os.listdir(path) if not i.startswith(".")]
924 f3299a07 Michael Hanselmann
  files.sort()
925 f3299a07 Michael Hanselmann
  return files
926 2f8b60b3 Iustin Pop
927 2f8b60b3 Iustin Pop
928 257f4c0a Iustin Pop
def GetHomeDir(user, default=None):
929 257f4c0a Iustin Pop
  """Try to get the homedir of the given user.
930 257f4c0a Iustin Pop

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

935 2f8b60b3 Iustin Pop
  """
936 2f8b60b3 Iustin Pop
  try:
937 257f4c0a Iustin Pop
    if isinstance(user, basestring):
938 257f4c0a Iustin Pop
      result = pwd.getpwnam(user)
939 257f4c0a Iustin Pop
    elif isinstance(user, (int, long)):
940 257f4c0a Iustin Pop
      result = pwd.getpwuid(user)
941 257f4c0a Iustin Pop
    else:
942 257f4c0a Iustin Pop
      raise errors.ProgrammerError("Invalid type passed to GetHomeDir (%s)" %
943 257f4c0a Iustin Pop
                                   type(user))
944 2f8b60b3 Iustin Pop
  except KeyError:
945 2f8b60b3 Iustin Pop
    return default
946 2f8b60b3 Iustin Pop
  return result.pw_dir
947 59072e7e Michael Hanselmann
948 59072e7e Michael Hanselmann
949 24818e8f Michael Hanselmann
def NewUUID():
950 59072e7e Michael Hanselmann
  """Returns a random UUID.
951 59072e7e Michael Hanselmann

952 59072e7e Michael Hanselmann
  """
953 59072e7e Michael Hanselmann
  f = open("/proc/sys/kernel/random/uuid", "r")
954 59072e7e Michael Hanselmann
  try:
955 59072e7e Michael Hanselmann
    return f.read(128).rstrip("\n")
956 59072e7e Michael Hanselmann
  finally:
957 59072e7e Michael Hanselmann
    f.close()
958 087b34fe Iustin Pop
959 087b34fe Iustin Pop
960 087b34fe Iustin Pop
def WriteFile(file_name, fn=None, data=None,
961 087b34fe Iustin Pop
              mode=None, uid=-1, gid=-1,
962 71714516 Michael Hanselmann
              atime=None, mtime=None, close=True,
963 04a8d789 Michael Hanselmann
              dry_run=False, backup=False,
964 71714516 Michael Hanselmann
              prewrite=None, postwrite=None):
965 087b34fe Iustin Pop
  """(Over)write a file atomically.
966 087b34fe Iustin Pop

967 087b34fe Iustin Pop
  The file_name and either fn (a function taking one argument, the
968 087b34fe Iustin Pop
  file descriptor, and which should write the data to it) or data (the
969 087b34fe Iustin Pop
  contents of the file) must be passed. The other arguments are
970 087b34fe Iustin Pop
  optional and allow setting the file mode, owner and group, and the
971 087b34fe Iustin Pop
  mtime/atime of the file.
972 087b34fe Iustin Pop

973 087b34fe Iustin Pop
  If the function doesn't raise an exception, it has succeeded and the
974 087b34fe Iustin Pop
  target file has the new contents. If the file has raised an
975 087b34fe Iustin Pop
  exception, an existing target file should be unmodified and the
976 087b34fe Iustin Pop
  temporary file should be removed.
977 087b34fe Iustin Pop

978 71714516 Michael Hanselmann
  Args:
979 71714516 Michael Hanselmann
    file_name: New filename
980 71714516 Michael Hanselmann
    fn: Content writing function, called with file descriptor as parameter
981 71714516 Michael Hanselmann
    data: Content as string
982 71714516 Michael Hanselmann
    mode: File mode
983 71714516 Michael Hanselmann
    uid: Owner
984 71714516 Michael Hanselmann
    gid: Group
985 71714516 Michael Hanselmann
    atime: Access time
986 71714516 Michael Hanselmann
    mtime: Modification time
987 71714516 Michael Hanselmann
    close: Whether to close file after writing it
988 71714516 Michael Hanselmann
    prewrite: Function object called before writing content
989 71714516 Michael Hanselmann
    postwrite: Function object called after writing content
990 71714516 Michael Hanselmann

991 71714516 Michael Hanselmann
  Returns:
992 71714516 Michael Hanselmann
    None if "close" parameter evaluates to True, otherwise file descriptor.
993 71714516 Michael Hanselmann

994 087b34fe Iustin Pop
  """
995 04a8d789 Michael Hanselmann
  if not os.path.isabs(file_name):
996 087b34fe Iustin Pop
    raise errors.ProgrammerError("Path passed to WriteFile is not"
997 087b34fe Iustin Pop
                                 " absolute: '%s'" % file_name)
998 087b34fe Iustin Pop
999 087b34fe Iustin Pop
  if [fn, data].count(None) != 1:
1000 087b34fe Iustin Pop
    raise errors.ProgrammerError("fn or data required")
1001 087b34fe Iustin Pop
1002 087b34fe Iustin Pop
  if [atime, mtime].count(None) == 1:
1003 087b34fe Iustin Pop
    raise errors.ProgrammerError("Both atime and mtime must be either"
1004 087b34fe Iustin Pop
                                 " set or None")
1005 087b34fe Iustin Pop
1006 70f4497c Michael Hanselmann
  if backup and not dry_run and os.path.isfile(file_name):
1007 70f4497c Michael Hanselmann
    CreateBackup(file_name)
1008 087b34fe Iustin Pop
1009 087b34fe Iustin Pop
  dir_name, base_name = os.path.split(file_name)
1010 087b34fe Iustin Pop
  fd, new_name = tempfile.mkstemp('.new', base_name, dir_name)
1011 087b34fe Iustin Pop
  # here we need to make sure we remove the temp file, if any error
1012 087b34fe Iustin Pop
  # leaves it in place
1013 087b34fe Iustin Pop
  try:
1014 087b34fe Iustin Pop
    if uid != -1 or gid != -1:
1015 087b34fe Iustin Pop
      os.chown(new_name, uid, gid)
1016 087b34fe Iustin Pop
    if mode:
1017 087b34fe Iustin Pop
      os.chmod(new_name, mode)
1018 71714516 Michael Hanselmann
    if callable(prewrite):
1019 71714516 Michael Hanselmann
      prewrite(fd)
1020 087b34fe Iustin Pop
    if data is not None:
1021 087b34fe Iustin Pop
      os.write(fd, data)
1022 087b34fe Iustin Pop
    else:
1023 087b34fe Iustin Pop
      fn(fd)
1024 71714516 Michael Hanselmann
    if callable(postwrite):
1025 71714516 Michael Hanselmann
      postwrite(fd)
1026 087b34fe Iustin Pop
    os.fsync(fd)
1027 087b34fe Iustin Pop
    if atime is not None and mtime is not None:
1028 087b34fe Iustin Pop
      os.utime(new_name, (atime, mtime))
1029 70f4497c Michael Hanselmann
    if not dry_run:
1030 70f4497c Michael Hanselmann
      os.rename(new_name, file_name)
1031 087b34fe Iustin Pop
  finally:
1032 71714516 Michael Hanselmann
    if close:
1033 71714516 Michael Hanselmann
      os.close(fd)
1034 71714516 Michael Hanselmann
      result = None
1035 71714516 Michael Hanselmann
    else:
1036 71714516 Michael Hanselmann
      result = fd
1037 087b34fe Iustin Pop
    RemoveFile(new_name)
1038 78feb6fb Guido Trotter
1039 71714516 Michael Hanselmann
  return result
1040 71714516 Michael Hanselmann
1041 78feb6fb Guido Trotter
1042 7b4126b7 Iustin Pop
def FirstFree(seq, base=0):
1043 7b4126b7 Iustin Pop
  """Returns the first non-existing integer from seq.
1044 7b4126b7 Iustin Pop

1045 7b4126b7 Iustin Pop
  The seq argument should be a sorted list of positive integers. The
1046 7b4126b7 Iustin Pop
  first time the index of an element is smaller than the element
1047 7b4126b7 Iustin Pop
  value, the index will be returned.
1048 7b4126b7 Iustin Pop

1049 7b4126b7 Iustin Pop
  The base argument is used to start at a different offset,
1050 7b4126b7 Iustin Pop
  i.e. [3, 4, 6] with offset=3 will return 5.
1051 7b4126b7 Iustin Pop

1052 7b4126b7 Iustin Pop
  Example: [0, 1, 3] will return 2.
1053 7b4126b7 Iustin Pop

1054 7b4126b7 Iustin Pop
  """
1055 7b4126b7 Iustin Pop
  for idx, elem in enumerate(seq):
1056 7b4126b7 Iustin Pop
    assert elem >= base, "Passed element is higher than base offset"
1057 7b4126b7 Iustin Pop
    if elem > idx + base:
1058 7b4126b7 Iustin Pop
      # idx is not used
1059 7b4126b7 Iustin Pop
      return idx + base
1060 7b4126b7 Iustin Pop
  return None
1061 7b4126b7 Iustin Pop
1062 7b4126b7 Iustin Pop
1063 78feb6fb Guido Trotter
def all(seq, pred=bool):
1064 78feb6fb Guido Trotter
  "Returns True if pred(x) is True for every element in the iterable"
1065 78feb6fb Guido Trotter
  for elem in itertools.ifilterfalse(pred, seq):
1066 78feb6fb Guido Trotter
    return False
1067 78feb6fb Guido Trotter
  return True
1068 78feb6fb Guido Trotter
1069 78feb6fb Guido Trotter
1070 78feb6fb Guido Trotter
def any(seq, pred=bool):
1071 78feb6fb Guido Trotter
  "Returns True if pred(x) is True for at least one element in the iterable"
1072 78feb6fb Guido Trotter
  for elem in itertools.ifilter(pred, seq):
1073 78feb6fb Guido Trotter
    return True
1074 78feb6fb Guido Trotter
  return False
1075 f7414041 Michael Hanselmann
1076 f7414041 Michael Hanselmann
1077 f7414041 Michael Hanselmann
def UniqueSequence(seq):
1078 f7414041 Michael Hanselmann
  """Returns a list with unique elements.
1079 f7414041 Michael Hanselmann

1080 f7414041 Michael Hanselmann
  Element order is preserved.
1081 f7414041 Michael Hanselmann
  """
1082 f7414041 Michael Hanselmann
  seen = set()
1083 f7414041 Michael Hanselmann
  return [i for i in seq if i not in seen and not seen.add(i)]
1084 1862d460 Alexander Schreiber
1085 1862d460 Alexander Schreiber
1086 1862d460 Alexander Schreiber
def IsValidMac(mac):
1087 1862d460 Alexander Schreiber
  """Predicate to check if a MAC address is valid.
1088 1862d460 Alexander Schreiber

1089 1862d460 Alexander Schreiber
  Checks wether the supplied MAC address is formally correct, only
1090 1862d460 Alexander Schreiber
  accepts colon separated format.
1091 1862d460 Alexander Schreiber
  """
1092 1862d460 Alexander Schreiber
  mac_check = re.compile("^([0-9a-f]{2}(:|$)){6}$")
1093 1862d460 Alexander Schreiber
  return mac_check.match(mac) is not None
1094 06009e27 Iustin Pop
1095 06009e27 Iustin Pop
1096 06009e27 Iustin Pop
def TestDelay(duration):
1097 06009e27 Iustin Pop
  """Sleep for a fixed amount of time.
1098 06009e27 Iustin Pop

1099 06009e27 Iustin Pop
  """
1100 06009e27 Iustin Pop
  if duration < 0:
1101 06009e27 Iustin Pop
    return False
1102 06009e27 Iustin Pop
  time.sleep(duration)
1103 06009e27 Iustin Pop
  return True
1104 8f765069 Iustin Pop
1105 8f765069 Iustin Pop
1106 8ff612c2 Iustin Pop
def Daemonize(logfile, noclose_fds=None):
1107 8f765069 Iustin Pop
  """Daemonize the current process.
1108 8f765069 Iustin Pop

1109 8f765069 Iustin Pop
  This detaches the current process from the controlling terminal and
1110 8f765069 Iustin Pop
  runs it in the background as a daemon.
1111 8f765069 Iustin Pop

1112 8f765069 Iustin Pop
  """
1113 8f765069 Iustin Pop
  UMASK = 077
1114 8f765069 Iustin Pop
  WORKDIR = "/"
1115 8f765069 Iustin Pop
  # Default maximum for the number of available file descriptors.
1116 8f765069 Iustin Pop
  if 'SC_OPEN_MAX' in os.sysconf_names:
1117 8f765069 Iustin Pop
    try:
1118 8f765069 Iustin Pop
      MAXFD = os.sysconf('SC_OPEN_MAX')
1119 8f765069 Iustin Pop
      if MAXFD < 0:
1120 8f765069 Iustin Pop
        MAXFD = 1024
1121 8f765069 Iustin Pop
    except OSError:
1122 8f765069 Iustin Pop
      MAXFD = 1024
1123 8f765069 Iustin Pop
  else:
1124 8f765069 Iustin Pop
    MAXFD = 1024
1125 8f765069 Iustin Pop
1126 8f765069 Iustin Pop
  # this might fail
1127 8f765069 Iustin Pop
  pid = os.fork()
1128 8f765069 Iustin Pop
  if (pid == 0):  # The first child.
1129 8f765069 Iustin Pop
    os.setsid()
1130 8f765069 Iustin Pop
    # this might fail
1131 8f765069 Iustin Pop
    pid = os.fork() # Fork a second child.
1132 8f765069 Iustin Pop
    if (pid == 0):  # The second child.
1133 8f765069 Iustin Pop
      os.chdir(WORKDIR)
1134 8f765069 Iustin Pop
      os.umask(UMASK)
1135 8f765069 Iustin Pop
    else:
1136 8f765069 Iustin Pop
      # exit() or _exit()?  See below.
1137 8f765069 Iustin Pop
      os._exit(0) # Exit parent (the first child) of the second child.
1138 8f765069 Iustin Pop
  else:
1139 8f765069 Iustin Pop
    os._exit(0) # Exit parent of the first child.
1140 8f765069 Iustin Pop
  maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
1141 8f765069 Iustin Pop
  if (maxfd == resource.RLIM_INFINITY):
1142 8f765069 Iustin Pop
    maxfd = MAXFD
1143 8f765069 Iustin Pop
1144 8f765069 Iustin Pop
  # Iterate through and close all file descriptors.
1145 8f765069 Iustin Pop
  for fd in range(0, maxfd):
1146 8ff612c2 Iustin Pop
    if noclose_fds and fd in noclose_fds:
1147 8ff612c2 Iustin Pop
      continue
1148 8f765069 Iustin Pop
    try:
1149 8f765069 Iustin Pop
      os.close(fd)
1150 8f765069 Iustin Pop
    except OSError: # ERROR, fd wasn't open to begin with (ignored)
1151 8f765069 Iustin Pop
      pass
1152 8f765069 Iustin Pop
  os.open(logfile, os.O_RDWR|os.O_CREAT|os.O_APPEND, 0600)
1153 8f765069 Iustin Pop
  # Duplicate standard input to standard output and standard error.
1154 8f765069 Iustin Pop
  os.dup2(0, 1)     # standard output (1)
1155 8f765069 Iustin Pop
  os.dup2(0, 2)     # standard error (2)
1156 8f765069 Iustin Pop
  return 0
1157 57c177af Iustin Pop
1158 57c177af Iustin Pop
1159 57c177af Iustin Pop
def FindFile(name, search_path, test=os.path.exists):
1160 57c177af Iustin Pop
  """Look for a filesystem object in a given path.
1161 57c177af Iustin Pop

1162 57c177af Iustin Pop
  This is an abstract method to search for filesystem object (files,
1163 57c177af Iustin Pop
  dirs) under a given search path.
1164 57c177af Iustin Pop

1165 57c177af Iustin Pop
  Args:
1166 57c177af Iustin Pop
    - name: the name to look for
1167 57c177af Iustin Pop
    - search_path: list of directory names
1168 57c177af Iustin Pop
    - test: the test which the full path must satisfy
1169 57c177af Iustin Pop
      (defaults to os.path.exists)
1170 57c177af Iustin Pop

1171 57c177af Iustin Pop
  Returns:
1172 57c177af Iustin Pop
    - full path to the item if found
1173 57c177af Iustin Pop
    - None otherwise
1174 57c177af Iustin Pop

1175 57c177af Iustin Pop
  """
1176 57c177af Iustin Pop
  for dir_name in search_path:
1177 57c177af Iustin Pop
    item_name = os.path.sep.join([dir_name, name])
1178 57c177af Iustin Pop
    if test(item_name):
1179 57c177af Iustin Pop
      return item_name
1180 57c177af Iustin Pop
  return None
1181 8d1a2a64 Michael Hanselmann
1182 8d1a2a64 Michael Hanselmann
1183 8d1a2a64 Michael Hanselmann
def CheckVolumeGroupSize(vglist, vgname, minsize):
1184 8d1a2a64 Michael Hanselmann
  """Checks if the volume group list is valid.
1185 8d1a2a64 Michael Hanselmann

1186 8d1a2a64 Michael Hanselmann
  A non-None return value means there's an error, and the return value
1187 8d1a2a64 Michael Hanselmann
  is the error message.
1188 8d1a2a64 Michael Hanselmann

1189 8d1a2a64 Michael Hanselmann
  """
1190 8d1a2a64 Michael Hanselmann
  vgsize = vglist.get(vgname, None)
1191 8d1a2a64 Michael Hanselmann
  if vgsize is None:
1192 8d1a2a64 Michael Hanselmann
    return "volume group '%s' missing" % vgname
1193 8d1a2a64 Michael Hanselmann
  elif vgsize < minsize:
1194 8d1a2a64 Michael Hanselmann
    return ("volume group '%s' too small (%s MiB required, %d MiB found)" %
1195 8d1a2a64 Michael Hanselmann
            (vgname, minsize, vgsize))
1196 8d1a2a64 Michael Hanselmann
  return None