Statistics
| Branch: | Tag: | Revision:

root / lib / utils.py @ d06565e0

History | View | Annotate | Download (23.1 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 a8083063 Iustin Pop
"""
24 a8083063 Iustin Pop
25 a8083063 Iustin Pop
26 a8083063 Iustin Pop
import sys
27 a8083063 Iustin Pop
import os
28 a8083063 Iustin Pop
import sha
29 a8083063 Iustin Pop
import time
30 113b55aa Iustin Pop
import subprocess
31 a8083063 Iustin Pop
import re
32 a8083063 Iustin Pop
import socket
33 a8083063 Iustin Pop
import tempfile
34 a8083063 Iustin Pop
import shutil
35 4ca1b175 Alexander Schreiber
import errno
36 2f8b60b3 Iustin Pop
import pwd
37 78feb6fb Guido Trotter
import itertools
38 a8083063 Iustin Pop
39 a8083063 Iustin Pop
from ganeti import logger
40 a8083063 Iustin Pop
from ganeti import errors
41 a8083063 Iustin Pop
42 16abfbc2 Alexander Schreiber
43 a8083063 Iustin Pop
_locksheld = []
44 a8083063 Iustin Pop
_re_shell_unquoted = re.compile('^[-.,=:/_+@A-Za-z0-9]+$')
45 a8083063 Iustin Pop
46 a8083063 Iustin Pop
class RunResult(object):
47 a8083063 Iustin Pop
  """Simple class for holding the result of running external programs.
48 a8083063 Iustin Pop

49 a8083063 Iustin Pop
  Instance variables:
50 a8083063 Iustin Pop
    exit_code: the exit code of the program, or None (if the program
51 a8083063 Iustin Pop
               didn't exit())
52 a8083063 Iustin Pop
    signal: numeric signal that caused the program to finish, or None
53 a8083063 Iustin Pop
            (if the program wasn't terminated by a signal)
54 a8083063 Iustin Pop
    stdout: the standard output of the program
55 a8083063 Iustin Pop
    stderr: the standard error of the program
56 a8083063 Iustin Pop
    failed: a Boolean value which is True in case the program was
57 a8083063 Iustin Pop
            terminated by a signal or exited with a non-zero exit code
58 a8083063 Iustin Pop
    fail_reason: a string detailing the termination reason
59 a8083063 Iustin Pop

60 a8083063 Iustin Pop
  """
61 a8083063 Iustin Pop
  __slots__ = ["exit_code", "signal", "stdout", "stderr",
62 a8083063 Iustin Pop
               "failed", "fail_reason", "cmd"]
63 a8083063 Iustin Pop
64 a8083063 Iustin Pop
65 a8083063 Iustin Pop
  def __init__(self, exit_code, signal, stdout, stderr, cmd):
66 a8083063 Iustin Pop
    self.cmd = cmd
67 a8083063 Iustin Pop
    self.exit_code = exit_code
68 a8083063 Iustin Pop
    self.signal = signal
69 a8083063 Iustin Pop
    self.stdout = stdout
70 a8083063 Iustin Pop
    self.stderr = stderr
71 a8083063 Iustin Pop
    self.failed = (signal is not None or exit_code != 0)
72 a8083063 Iustin Pop
73 a8083063 Iustin Pop
    if self.signal is not None:
74 a8083063 Iustin Pop
      self.fail_reason = "terminated by signal %s" % self.signal
75 a8083063 Iustin Pop
    elif self.exit_code is not None:
76 a8083063 Iustin Pop
      self.fail_reason = "exited with exit code %s" % self.exit_code
77 a8083063 Iustin Pop
    else:
78 a8083063 Iustin Pop
      self.fail_reason = "unable to determine termination reason"
79 a8083063 Iustin Pop
80 a8083063 Iustin Pop
  def _GetOutput(self):
81 a8083063 Iustin Pop
    """Returns the combined stdout and stderr for easier usage.
82 a8083063 Iustin Pop

83 a8083063 Iustin Pop
    """
84 a8083063 Iustin Pop
    return self.stdout + self.stderr
85 a8083063 Iustin Pop
86 a8083063 Iustin Pop
  output = property(_GetOutput, None, None, "Return full output")
87 a8083063 Iustin Pop
88 a8083063 Iustin Pop
89 a8083063 Iustin Pop
def _GetLockFile(subsystem):
90 a8083063 Iustin Pop
  """Compute the file name for a given lock name."""
91 a8083063 Iustin Pop
  return "/var/lock/ganeti_lock_%s" % subsystem
92 a8083063 Iustin Pop
93 a8083063 Iustin Pop
94 a8083063 Iustin Pop
def Lock(name, max_retries=None, debug=False):
95 a8083063 Iustin Pop
  """Lock a given subsystem.
96 a8083063 Iustin Pop

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

100 a8083063 Iustin Pop
  When the optional integer argument 'max_retries' is passed with a
101 a8083063 Iustin Pop
  non-zero value, the function will sleep only for this number of
102 a8083063 Iustin Pop
  times, and then it will will raise a LockError if the lock can't be
103 a8083063 Iustin Pop
  acquired. Passing in a negative number will cause only one try to
104 a8083063 Iustin Pop
  get the lock. Passing a positive number will make the function retry
105 a8083063 Iustin Pop
  for approximately that number of seconds.
106 a8083063 Iustin Pop

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

164 098c0958 Michael Hanselmann
  """
165 a8083063 Iustin Pop
  lockfile = _GetLockFile(name)
166 a8083063 Iustin Pop
167 a8083063 Iustin Pop
  try:
168 a8083063 Iustin Pop
    fd = os.open(lockfile, os.O_RDONLY)
169 a8083063 Iustin Pop
  except OSError:
170 a8083063 Iustin Pop
    raise errors.LockError('Lock "%s" not held.' % (name,))
171 a8083063 Iustin Pop
172 a8083063 Iustin Pop
  f = os.fdopen(fd, 'r')
173 a8083063 Iustin Pop
  pid_str = f.read()
174 a8083063 Iustin Pop
175 a8083063 Iustin Pop
  try:
176 a8083063 Iustin Pop
    pid = int(pid_str)
177 a8083063 Iustin Pop
  except ValueError:
178 a8083063 Iustin Pop
    raise errors.LockError('Unable to determine PID of locking process.')
179 a8083063 Iustin Pop
180 a8083063 Iustin Pop
  if pid != os.getpid():
181 a8083063 Iustin Pop
    raise errors.LockError('Lock not held by me (%d != %d)' %
182 a8083063 Iustin Pop
                           (os.getpid(), pid,))
183 a8083063 Iustin Pop
184 a8083063 Iustin Pop
  os.unlink(lockfile)
185 a8083063 Iustin Pop
  _locksheld.remove(name)
186 a8083063 Iustin Pop
187 a8083063 Iustin Pop
188 a8083063 Iustin Pop
def LockCleanup():
189 098c0958 Michael Hanselmann
  """Remove all locks.
190 a8083063 Iustin Pop

191 098c0958 Michael Hanselmann
  """
192 a8083063 Iustin Pop
  for lock in _locksheld:
193 a8083063 Iustin Pop
    Unlock(lock)
194 a8083063 Iustin Pop
195 a8083063 Iustin Pop
196 a8083063 Iustin Pop
def RunCmd(cmd):
197 a8083063 Iustin Pop
  """Execute a (shell) command.
198 a8083063 Iustin Pop

199 a8083063 Iustin Pop
  The command should not read from its standard input, as it will be
200 a8083063 Iustin Pop
  closed.
201 a8083063 Iustin Pop

202 a8083063 Iustin Pop
  Args:
203 a8083063 Iustin Pop
    cmd: command to run. (str)
204 a8083063 Iustin Pop

205 a8083063 Iustin Pop
  Returns: `RunResult` instance
206 a8083063 Iustin Pop

207 a8083063 Iustin Pop
  """
208 a8083063 Iustin Pop
  if isinstance(cmd, list):
209 a8083063 Iustin Pop
    cmd = [str(val) for val in cmd]
210 113b55aa Iustin Pop
    strcmd = " ".join(cmd)
211 113b55aa Iustin Pop
    shell = False
212 113b55aa Iustin Pop
  else:
213 113b55aa Iustin Pop
    strcmd = cmd
214 113b55aa Iustin Pop
    shell = True
215 23f41a3e Michael Hanselmann
  env = os.environ.copy()
216 23f41a3e Michael Hanselmann
  env["LC_ALL"] = "C"
217 113b55aa Iustin Pop
  child = subprocess.Popen(cmd, shell=shell,
218 113b55aa Iustin Pop
                           stderr=subprocess.PIPE,
219 113b55aa Iustin Pop
                           stdout=subprocess.PIPE,
220 113b55aa Iustin Pop
                           stdin=subprocess.PIPE,
221 23f41a3e Michael Hanselmann
                           close_fds=True, env=env)
222 113b55aa Iustin Pop
223 113b55aa Iustin Pop
  child.stdin.close()
224 113b55aa Iustin Pop
  out = child.stdout.read()
225 113b55aa Iustin Pop
  err = child.stderr.read()
226 a8083063 Iustin Pop
227 a8083063 Iustin Pop
  status = child.wait()
228 113b55aa Iustin Pop
  if status >= 0:
229 113b55aa Iustin Pop
    exitcode = status
230 a8083063 Iustin Pop
    signal = None
231 a8083063 Iustin Pop
  else:
232 a8083063 Iustin Pop
    exitcode = None
233 113b55aa Iustin Pop
    signal = -status
234 a8083063 Iustin Pop
235 a8083063 Iustin Pop
  return RunResult(exitcode, signal, out, err, strcmd)
236 a8083063 Iustin Pop
237 a8083063 Iustin Pop
238 a8083063 Iustin Pop
def RunCmdUnlocked(cmd):
239 a8083063 Iustin Pop
  """Execute a shell command without the 'cmd' lock.
240 a8083063 Iustin Pop

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

245 a8083063 Iustin Pop
  The argument and return values are the same as for the `RunCmd()`
246 a8083063 Iustin Pop
  function.
247 a8083063 Iustin Pop

248 a8083063 Iustin Pop
  Args:
249 a8083063 Iustin Pop
    cmd - command to run. (str)
250 a8083063 Iustin Pop

251 a8083063 Iustin Pop
  Returns:
252 a8083063 Iustin Pop
    `RunResult`
253 a8083063 Iustin Pop

254 a8083063 Iustin Pop
  """
255 a8083063 Iustin Pop
  Unlock('cmd')
256 a8083063 Iustin Pop
  ret = RunCmd(cmd)
257 a8083063 Iustin Pop
  Lock('cmd')
258 a8083063 Iustin Pop
259 a8083063 Iustin Pop
  return ret
260 a8083063 Iustin Pop
261 a8083063 Iustin Pop
262 a8083063 Iustin Pop
def RemoveFile(filename):
263 a8083063 Iustin Pop
  """Remove a file ignoring some errors.
264 a8083063 Iustin Pop

265 a8083063 Iustin Pop
  Remove a file, ignoring non-existing ones or directories. Other
266 a8083063 Iustin Pop
  errors are passed.
267 a8083063 Iustin Pop

268 a8083063 Iustin Pop
  """
269 a8083063 Iustin Pop
  try:
270 a8083063 Iustin Pop
    os.unlink(filename)
271 a8083063 Iustin Pop
  except OSError, err:
272 4ca1b175 Alexander Schreiber
    if err.errno not in (errno.ENOENT, errno.EISDIR):
273 a8083063 Iustin Pop
      raise
274 a8083063 Iustin Pop
275 a8083063 Iustin Pop
276 a8083063 Iustin Pop
def _FingerprintFile(filename):
277 a8083063 Iustin Pop
  """Compute the fingerprint of a file.
278 a8083063 Iustin Pop

279 a8083063 Iustin Pop
  If the file does not exist, a None will be returned
280 a8083063 Iustin Pop
  instead.
281 a8083063 Iustin Pop

282 a8083063 Iustin Pop
  Args:
283 a8083063 Iustin Pop
    filename - Filename (str)
284 a8083063 Iustin Pop

285 a8083063 Iustin Pop
  """
286 a8083063 Iustin Pop
  if not (os.path.exists(filename) and os.path.isfile(filename)):
287 a8083063 Iustin Pop
    return None
288 a8083063 Iustin Pop
289 a8083063 Iustin Pop
  f = open(filename)
290 a8083063 Iustin Pop
291 a8083063 Iustin Pop
  fp = sha.sha()
292 a8083063 Iustin Pop
  while True:
293 a8083063 Iustin Pop
    data = f.read(4096)
294 a8083063 Iustin Pop
    if not data:
295 a8083063 Iustin Pop
      break
296 a8083063 Iustin Pop
297 a8083063 Iustin Pop
    fp.update(data)
298 a8083063 Iustin Pop
299 a8083063 Iustin Pop
  return fp.hexdigest()
300 a8083063 Iustin Pop
301 a8083063 Iustin Pop
302 a8083063 Iustin Pop
def FingerprintFiles(files):
303 a8083063 Iustin Pop
  """Compute fingerprints for a list of files.
304 a8083063 Iustin Pop

305 a8083063 Iustin Pop
  Args:
306 a8083063 Iustin Pop
    files - array of filenames.  ( [str, ...] )
307 a8083063 Iustin Pop

308 a8083063 Iustin Pop
  Return value:
309 a8083063 Iustin Pop
    dictionary of filename: fingerprint for the files that exist
310 a8083063 Iustin Pop

311 a8083063 Iustin Pop
  """
312 a8083063 Iustin Pop
  ret = {}
313 a8083063 Iustin Pop
314 a8083063 Iustin Pop
  for filename in files:
315 a8083063 Iustin Pop
    cksum = _FingerprintFile(filename)
316 a8083063 Iustin Pop
    if cksum:
317 a8083063 Iustin Pop
      ret[filename] = cksum
318 a8083063 Iustin Pop
319 a8083063 Iustin Pop
  return ret
320 a8083063 Iustin Pop
321 a8083063 Iustin Pop
322 a8083063 Iustin Pop
def CheckDict(target, template, logname=None):
323 a8083063 Iustin Pop
  """Ensure a dictionary has a required set of keys.
324 a8083063 Iustin Pop

325 a8083063 Iustin Pop
  For the given dictionaries `target` and `template`, ensure target
326 a8083063 Iustin Pop
  has all the keys from template. Missing keys are added with values
327 a8083063 Iustin Pop
  from template.
328 a8083063 Iustin Pop

329 a8083063 Iustin Pop
  Args:
330 a8083063 Iustin Pop
    target   - the dictionary to check
331 a8083063 Iustin Pop
    template - template dictionary
332 a8083063 Iustin Pop
    logname  - a caller-chosen string to identify the debug log
333 a8083063 Iustin Pop
               entry; if None, no logging will be done
334 a8083063 Iustin Pop

335 a8083063 Iustin Pop
  Returns value:
336 a8083063 Iustin Pop
    None
337 a8083063 Iustin Pop

338 a8083063 Iustin Pop
  """
339 a8083063 Iustin Pop
  missing = []
340 a8083063 Iustin Pop
  for k in template:
341 a8083063 Iustin Pop
    if k not in target:
342 a8083063 Iustin Pop
      missing.append(k)
343 a8083063 Iustin Pop
      target[k] = template[k]
344 a8083063 Iustin Pop
345 a8083063 Iustin Pop
  if missing and logname:
346 a8083063 Iustin Pop
    logger.Debug('%s missing keys %s' %
347 a8083063 Iustin Pop
                 (logname, ', '.join(missing)))
348 a8083063 Iustin Pop
349 a8083063 Iustin Pop
350 a8083063 Iustin Pop
def IsProcessAlive(pid):
351 a8083063 Iustin Pop
  """Check if a given pid exists on the system.
352 a8083063 Iustin Pop

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

355 a8083063 Iustin Pop
  Remarks: zombie processes treated as not alive
356 a8083063 Iustin Pop

357 a8083063 Iustin Pop
  """
358 a8083063 Iustin Pop
  try:
359 a8083063 Iustin Pop
    f = open("/proc/%d/status" % pid)
360 a8083063 Iustin Pop
  except IOError, err:
361 4ca1b175 Alexander Schreiber
    if err.errno in (errno.ENOENT, errno.ENOTDIR):
362 a8083063 Iustin Pop
      return False
363 a8083063 Iustin Pop
364 a8083063 Iustin Pop
  alive = True
365 a8083063 Iustin Pop
  try:
366 a8083063 Iustin Pop
    data = f.readlines()
367 a8083063 Iustin Pop
    if len(data) > 1:
368 a8083063 Iustin Pop
      state = data[1].split()
369 a8083063 Iustin Pop
      if len(state) > 1 and state[1] == "Z":
370 a8083063 Iustin Pop
        alive = False
371 a8083063 Iustin Pop
  finally:
372 a8083063 Iustin Pop
    f.close()
373 a8083063 Iustin Pop
374 a8083063 Iustin Pop
  return alive
375 a8083063 Iustin Pop
376 a8083063 Iustin Pop
377 a8083063 Iustin Pop
def MatchNameComponent(key, name_list):
378 a8083063 Iustin Pop
  """Try to match a name against a list.
379 a8083063 Iustin Pop

380 a8083063 Iustin Pop
  This function will try to match a name like test1 against a list
381 a8083063 Iustin Pop
  like ['test1.example.com', 'test2.example.com', ...]. Against this
382 a8083063 Iustin Pop
  list, 'test1' as well as 'test1.example' will match, but not
383 a8083063 Iustin Pop
  'test1.ex'. A multiple match will be considered as no match at all
384 a8083063 Iustin Pop
  (e.g. 'test1' against ['test1.example.com', 'test1.example.org']).
385 a8083063 Iustin Pop

386 a8083063 Iustin Pop
  Args:
387 a8083063 Iustin Pop
    key: the name to be searched
388 a8083063 Iustin Pop
    name_list: the list of strings against which to search the key
389 a8083063 Iustin Pop

390 a8083063 Iustin Pop
  Returns:
391 a8083063 Iustin Pop
    None if there is no match *or* if there are multiple matches
392 a8083063 Iustin Pop
    otherwise the element from the list which matches
393 a8083063 Iustin Pop

394 a8083063 Iustin Pop
  """
395 a8083063 Iustin Pop
  mo = re.compile("^%s(\..*)?$" % re.escape(key))
396 a8083063 Iustin Pop
  names_filtered = [name for name in name_list if mo.match(name) is not None]
397 a8083063 Iustin Pop
  if len(names_filtered) != 1:
398 a8083063 Iustin Pop
    return None
399 a8083063 Iustin Pop
  return names_filtered[0]
400 a8083063 Iustin Pop
401 a8083063 Iustin Pop
402 bcf043c9 Iustin Pop
class HostInfo:
403 89e1fc26 Iustin Pop
  """Class implementing resolver and hostname functionality
404 bcf043c9 Iustin Pop

405 bcf043c9 Iustin Pop
  """
406 89e1fc26 Iustin Pop
  def __init__(self, name=None):
407 bcf043c9 Iustin Pop
    """Initialize the host name object.
408 bcf043c9 Iustin Pop

409 89e1fc26 Iustin Pop
    If the name argument is not passed, it will use this system's
410 89e1fc26 Iustin Pop
    name.
411 bcf043c9 Iustin Pop

412 bcf043c9 Iustin Pop
    """
413 89e1fc26 Iustin Pop
    if name is None:
414 89e1fc26 Iustin Pop
      name = self.SysName()
415 89e1fc26 Iustin Pop
416 89e1fc26 Iustin Pop
    self.query = name
417 89e1fc26 Iustin Pop
    self.name, self.aliases, self.ipaddrs = self.LookupHostname(name)
418 bcf043c9 Iustin Pop
    self.ip = self.ipaddrs[0]
419 bcf043c9 Iustin Pop
420 89e1fc26 Iustin Pop
  @staticmethod
421 89e1fc26 Iustin Pop
  def SysName():
422 89e1fc26 Iustin Pop
    """Return the current system's name.
423 bcf043c9 Iustin Pop

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

426 89e1fc26 Iustin Pop
    """
427 89e1fc26 Iustin Pop
    return socket.gethostname()
428 a8083063 Iustin Pop
429 89e1fc26 Iustin Pop
  @staticmethod
430 89e1fc26 Iustin Pop
  def LookupHostname(hostname):
431 89e1fc26 Iustin Pop
    """Look up hostname
432 a8083063 Iustin Pop

433 89e1fc26 Iustin Pop
    Args:
434 89e1fc26 Iustin Pop
      hostname: hostname to look up
435 89e1fc26 Iustin Pop

436 89e1fc26 Iustin Pop
    Returns:
437 89e1fc26 Iustin Pop
      a tuple (name, aliases, ipaddrs) as returned by socket.gethostbyname_ex
438 89e1fc26 Iustin Pop
      in case of errors in resolving, we raise a ResolverError
439 89e1fc26 Iustin Pop

440 89e1fc26 Iustin Pop
    """
441 89e1fc26 Iustin Pop
    try:
442 89e1fc26 Iustin Pop
      result = socket.gethostbyname_ex(hostname)
443 89e1fc26 Iustin Pop
    except socket.gaierror, err:
444 89e1fc26 Iustin Pop
      # hostname not found in DNS
445 89e1fc26 Iustin Pop
      raise errors.ResolverError(hostname, err.args[0], err.args[1])
446 a8083063 Iustin Pop
447 89e1fc26 Iustin Pop
    return result
448 a8083063 Iustin Pop
449 a8083063 Iustin Pop
450 a8083063 Iustin Pop
def ListVolumeGroups():
451 a8083063 Iustin Pop
  """List volume groups and their size
452 a8083063 Iustin Pop

453 a8083063 Iustin Pop
  Returns:
454 a8083063 Iustin Pop
     Dictionary with keys volume name and values the size of the volume
455 a8083063 Iustin Pop

456 a8083063 Iustin Pop
  """
457 a8083063 Iustin Pop
  command = "vgs --noheadings --units m --nosuffix -o name,size"
458 a8083063 Iustin Pop
  result = RunCmd(command)
459 a8083063 Iustin Pop
  retval = {}
460 a8083063 Iustin Pop
  if result.failed:
461 a8083063 Iustin Pop
    return retval
462 a8083063 Iustin Pop
463 a8083063 Iustin Pop
  for line in result.stdout.splitlines():
464 a8083063 Iustin Pop
    try:
465 a8083063 Iustin Pop
      name, size = line.split()
466 a8083063 Iustin Pop
      size = int(float(size))
467 a8083063 Iustin Pop
    except (IndexError, ValueError), err:
468 a8083063 Iustin Pop
      logger.Error("Invalid output from vgs (%s): %s" % (err, line))
469 a8083063 Iustin Pop
      continue
470 a8083063 Iustin Pop
471 a8083063 Iustin Pop
    retval[name] = size
472 a8083063 Iustin Pop
473 a8083063 Iustin Pop
  return retval
474 a8083063 Iustin Pop
475 a8083063 Iustin Pop
476 a8083063 Iustin Pop
def BridgeExists(bridge):
477 a8083063 Iustin Pop
  """Check whether the given bridge exists in the system
478 a8083063 Iustin Pop

479 a8083063 Iustin Pop
  Returns:
480 a8083063 Iustin Pop
     True if it does, false otherwise.
481 a8083063 Iustin Pop

482 a8083063 Iustin Pop
  """
483 a8083063 Iustin Pop
  return os.path.isdir("/sys/class/net/%s/bridge" % bridge)
484 a8083063 Iustin Pop
485 a8083063 Iustin Pop
486 a8083063 Iustin Pop
def NiceSort(name_list):
487 a8083063 Iustin Pop
  """Sort a list of strings based on digit and non-digit groupings.
488 a8083063 Iustin Pop

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

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

496 a8083063 Iustin Pop
  Return value
497 a8083063 Iustin Pop
    - a copy of the list sorted according to our algorithm
498 a8083063 Iustin Pop

499 a8083063 Iustin Pop
  """
500 a8083063 Iustin Pop
  _SORTER_BASE = "(\D+|\d+)"
501 a8083063 Iustin Pop
  _SORTER_FULL = "^%s%s?%s?%s?%s?%s?%s?%s?.*$" % (_SORTER_BASE, _SORTER_BASE,
502 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE,
503 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE,
504 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE)
505 a8083063 Iustin Pop
  _SORTER_RE = re.compile(_SORTER_FULL)
506 a8083063 Iustin Pop
  _SORTER_NODIGIT = re.compile("^\D*$")
507 a8083063 Iustin Pop
  def _TryInt(val):
508 a8083063 Iustin Pop
    """Attempts to convert a variable to integer."""
509 a8083063 Iustin Pop
    if val is None or _SORTER_NODIGIT.match(val):
510 a8083063 Iustin Pop
      return val
511 a8083063 Iustin Pop
    rval = int(val)
512 a8083063 Iustin Pop
    return rval
513 a8083063 Iustin Pop
514 a8083063 Iustin Pop
  to_sort = [([_TryInt(grp) for grp in _SORTER_RE.match(name).groups()], name)
515 a8083063 Iustin Pop
             for name in name_list]
516 a8083063 Iustin Pop
  to_sort.sort()
517 a8083063 Iustin Pop
  return [tup[1] for tup in to_sort]
518 a8083063 Iustin Pop
519 a8083063 Iustin Pop
520 a8083063 Iustin Pop
def CheckDaemonAlive(pid_file, process_string):
521 a8083063 Iustin Pop
  """Check wether the specified daemon is alive.
522 a8083063 Iustin Pop

523 a8083063 Iustin Pop
  Args:
524 a8083063 Iustin Pop
   - pid_file: file to read the daemon pid from, the file is
525 a8083063 Iustin Pop
               expected to contain only a single line containing
526 a8083063 Iustin Pop
               only the PID
527 a8083063 Iustin Pop
   - process_string: a substring that we expect to find in
528 a8083063 Iustin Pop
                     the command line of the daemon process
529 a8083063 Iustin Pop

530 a8083063 Iustin Pop
  Returns:
531 a8083063 Iustin Pop
   - True if the daemon is judged to be alive (that is:
532 a8083063 Iustin Pop
      - the PID file exists, is readable and contains a number
533 a8083063 Iustin Pop
      - a process of the specified PID is running
534 a8083063 Iustin Pop
      - that process contains the specified string in its
535 a8083063 Iustin Pop
        command line
536 a8083063 Iustin Pop
      - the process is not in state Z (zombie))
537 a8083063 Iustin Pop
   - False otherwise
538 a8083063 Iustin Pop

539 a8083063 Iustin Pop
  """
540 a8083063 Iustin Pop
  try:
541 a8083063 Iustin Pop
    pid_file = file(pid_file, 'r')
542 a8083063 Iustin Pop
    try:
543 a8083063 Iustin Pop
      pid = int(pid_file.readline())
544 a8083063 Iustin Pop
    finally:
545 a8083063 Iustin Pop
      pid_file.close()
546 a8083063 Iustin Pop
547 a8083063 Iustin Pop
    cmdline_file_path = "/proc/%s/cmdline" % (pid)
548 a8083063 Iustin Pop
    cmdline_file = open(cmdline_file_path, 'r')
549 a8083063 Iustin Pop
    try:
550 a8083063 Iustin Pop
      cmdline = cmdline_file.readline()
551 a8083063 Iustin Pop
    finally:
552 a8083063 Iustin Pop
      cmdline_file.close()
553 a8083063 Iustin Pop
554 a8083063 Iustin Pop
    if not process_string in cmdline:
555 a8083063 Iustin Pop
      return False
556 a8083063 Iustin Pop
557 a8083063 Iustin Pop
    stat_file_path =  "/proc/%s/stat" % (pid)
558 a8083063 Iustin Pop
    stat_file = open(stat_file_path, 'r')
559 a8083063 Iustin Pop
    try:
560 a8083063 Iustin Pop
      process_state = stat_file.readline().split()[2]
561 a8083063 Iustin Pop
    finally:
562 a8083063 Iustin Pop
      stat_file.close()
563 a8083063 Iustin Pop
564 a8083063 Iustin Pop
    if process_state == 'Z':
565 a8083063 Iustin Pop
      return False
566 a8083063 Iustin Pop
567 a8083063 Iustin Pop
  except (IndexError, IOError, ValueError):
568 a8083063 Iustin Pop
    return False
569 a8083063 Iustin Pop
570 a8083063 Iustin Pop
  return True
571 a8083063 Iustin Pop
572 a8083063 Iustin Pop
573 a8083063 Iustin Pop
def TryConvert(fn, val):
574 a8083063 Iustin Pop
  """Try to convert a value ignoring errors.
575 a8083063 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

720 a8083063 Iustin Pop
  Args:
721 a8083063 Iustin Pop
    file_name: Path to authorized_keys file
722 a8083063 Iustin Pop
    key: String containing key
723 a8083063 Iustin Pop
  """
724 a8083063 Iustin Pop
  key_fields = key.split()
725 a8083063 Iustin Pop
726 a8083063 Iustin Pop
  fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name))
727 a8083063 Iustin Pop
  out = os.fdopen(fd, 'w')
728 a8083063 Iustin Pop
  try:
729 a8083063 Iustin Pop
    f = open(file_name, 'r')
730 a8083063 Iustin Pop
    try:
731 a8083063 Iustin Pop
      for line in f:
732 a8083063 Iustin Pop
        # Ignore whitespace changes while comparing lines
733 a8083063 Iustin Pop
        if line.split() != key_fields:
734 a8083063 Iustin Pop
          out.write(line)
735 a8083063 Iustin Pop
736 a8083063 Iustin Pop
      out.flush()
737 a8083063 Iustin Pop
      os.rename(tmpname, file_name)
738 a8083063 Iustin Pop
    finally:
739 a8083063 Iustin Pop
      f.close()
740 a8083063 Iustin Pop
  finally:
741 a8083063 Iustin Pop
    out.close()
742 a8083063 Iustin Pop
743 a8083063 Iustin Pop
744 a8083063 Iustin Pop
def CreateBackup(file_name):
745 a8083063 Iustin Pop
  """Creates a backup of a file.
746 a8083063 Iustin Pop

747 a8083063 Iustin Pop
  Returns: the path to the newly created backup file.
748 a8083063 Iustin Pop

749 a8083063 Iustin Pop
  """
750 a8083063 Iustin Pop
  if not os.path.isfile(file_name):
751 3ecf6786 Iustin Pop
    raise errors.ProgrammerError("Can't make a backup of a non-file '%s'" %
752 3ecf6786 Iustin Pop
                                file_name)
753 a8083063 Iustin Pop
754 081b1e69 Michael Hanselmann
  prefix = '%s.backup-%d.' % (os.path.basename(file_name), int(time.time()))
755 081b1e69 Michael Hanselmann
  dir = os.path.dirname(file_name)
756 081b1e69 Michael Hanselmann
757 081b1e69 Michael Hanselmann
  fsrc = open(file_name, 'rb')
758 081b1e69 Michael Hanselmann
  try:
759 081b1e69 Michael Hanselmann
    (fd, backup_name) = tempfile.mkstemp(prefix=prefix, dir=dir)
760 081b1e69 Michael Hanselmann
    fdst = os.fdopen(fd, 'wb')
761 081b1e69 Michael Hanselmann
    try:
762 081b1e69 Michael Hanselmann
      shutil.copyfileobj(fsrc, fdst)
763 081b1e69 Michael Hanselmann
    finally:
764 081b1e69 Michael Hanselmann
      fdst.close()
765 081b1e69 Michael Hanselmann
  finally:
766 081b1e69 Michael Hanselmann
    fsrc.close()
767 081b1e69 Michael Hanselmann
768 a8083063 Iustin Pop
  return backup_name
769 a8083063 Iustin Pop
770 a8083063 Iustin Pop
771 a8083063 Iustin Pop
def ShellQuote(value):
772 a8083063 Iustin Pop
  """Quotes shell argument according to POSIX.
773 3ecf6786 Iustin Pop

774 a8083063 Iustin Pop
  """
775 a8083063 Iustin Pop
  if _re_shell_unquoted.match(value):
776 a8083063 Iustin Pop
    return value
777 a8083063 Iustin Pop
  else:
778 a8083063 Iustin Pop
    return "'%s'" % value.replace("'", "'\\''")
779 a8083063 Iustin Pop
780 a8083063 Iustin Pop
781 a8083063 Iustin Pop
def ShellQuoteArgs(args):
782 a8083063 Iustin Pop
  """Quotes all given shell arguments and concatenates using spaces.
783 a8083063 Iustin Pop

784 a8083063 Iustin Pop
  """
785 a8083063 Iustin Pop
  return ' '.join([ShellQuote(i) for i in args])
786 88d14415 Michael Hanselmann
787 88d14415 Michael Hanselmann
788 2c30e9d7 Alexander Schreiber
789 16abfbc2 Alexander Schreiber
def TcpPing(source, target, port, timeout=10, live_port_needed=False):
790 2c30e9d7 Alexander Schreiber
  """Simple ping implementation using TCP connect(2).
791 2c30e9d7 Alexander Schreiber

792 2c30e9d7 Alexander Schreiber
  Try to do a TCP connect(2) from the specified source IP to the specified
793 2c30e9d7 Alexander Schreiber
  target IP and the specified target port. If live_port_needed is set to true,
794 2c30e9d7 Alexander Schreiber
  requires the remote end to accept the connection. The timeout is specified
795 2c30e9d7 Alexander Schreiber
  in seconds and defaults to 10 seconds
796 2c30e9d7 Alexander Schreiber

797 2c30e9d7 Alexander Schreiber
  """
798 2c30e9d7 Alexander Schreiber
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
799 2c30e9d7 Alexander Schreiber
800 2c30e9d7 Alexander Schreiber
  sucess = False
801 2c30e9d7 Alexander Schreiber
802 2c30e9d7 Alexander Schreiber
  try:
803 2c30e9d7 Alexander Schreiber
    sock.bind((source, 0))
804 2c30e9d7 Alexander Schreiber
  except socket.error, (errcode, errstring):
805 4ca1b175 Alexander Schreiber
    if errcode == errno.EADDRNOTAVAIL:
806 2c30e9d7 Alexander Schreiber
      success = False
807 2c30e9d7 Alexander Schreiber
808 2c30e9d7 Alexander Schreiber
  sock.settimeout(timeout)
809 2c30e9d7 Alexander Schreiber
810 2c30e9d7 Alexander Schreiber
  try:
811 2c30e9d7 Alexander Schreiber
    sock.connect((target, port))
812 2c30e9d7 Alexander Schreiber
    sock.close()
813 2c30e9d7 Alexander Schreiber
    success = True
814 2c30e9d7 Alexander Schreiber
  except socket.timeout:
815 2c30e9d7 Alexander Schreiber
    success = False
816 2c30e9d7 Alexander Schreiber
  except socket.error, (errcode, errstring):
817 4ca1b175 Alexander Schreiber
    success = (not live_port_needed) and (errcode == errno.ECONNREFUSED)
818 2c30e9d7 Alexander Schreiber
819 2c30e9d7 Alexander Schreiber
  return success
820 eedbda4b Michael Hanselmann
821 eedbda4b Michael Hanselmann
822 eedbda4b Michael Hanselmann
def ListVisibleFiles(path):
823 eedbda4b Michael Hanselmann
  """Returns a list of all visible files in a directory.
824 eedbda4b Michael Hanselmann

825 eedbda4b Michael Hanselmann
  """
826 eedbda4b Michael Hanselmann
  return [i for i in os.listdir(path) if not i.startswith(".")]
827 2f8b60b3 Iustin Pop
828 2f8b60b3 Iustin Pop
829 257f4c0a Iustin Pop
def GetHomeDir(user, default=None):
830 257f4c0a Iustin Pop
  """Try to get the homedir of the given user.
831 257f4c0a Iustin Pop

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

836 2f8b60b3 Iustin Pop
  """
837 2f8b60b3 Iustin Pop
  try:
838 257f4c0a Iustin Pop
    if isinstance(user, basestring):
839 257f4c0a Iustin Pop
      result = pwd.getpwnam(user)
840 257f4c0a Iustin Pop
    elif isinstance(user, (int, long)):
841 257f4c0a Iustin Pop
      result = pwd.getpwuid(user)
842 257f4c0a Iustin Pop
    else:
843 257f4c0a Iustin Pop
      raise errors.ProgrammerError("Invalid type passed to GetHomeDir (%s)" %
844 257f4c0a Iustin Pop
                                   type(user))
845 2f8b60b3 Iustin Pop
  except KeyError:
846 2f8b60b3 Iustin Pop
    return default
847 2f8b60b3 Iustin Pop
  return result.pw_dir
848 59072e7e Michael Hanselmann
849 59072e7e Michael Hanselmann
850 59072e7e Michael Hanselmann
def GetUUID():
851 59072e7e Michael Hanselmann
  """Returns a random UUID.
852 59072e7e Michael Hanselmann

853 59072e7e Michael Hanselmann
  """
854 59072e7e Michael Hanselmann
  f = open("/proc/sys/kernel/random/uuid", "r")
855 59072e7e Michael Hanselmann
  try:
856 59072e7e Michael Hanselmann
    return f.read(128).rstrip("\n")
857 59072e7e Michael Hanselmann
  finally:
858 59072e7e Michael Hanselmann
    f.close()
859 087b34fe Iustin Pop
860 087b34fe Iustin Pop
861 087b34fe Iustin Pop
def WriteFile(file_name, fn=None, data=None,
862 087b34fe Iustin Pop
              mode=None, uid=-1, gid=-1,
863 087b34fe Iustin Pop
              atime=None, mtime=None):
864 087b34fe Iustin Pop
  """(Over)write a file atomically.
865 087b34fe Iustin Pop

866 087b34fe Iustin Pop
  The file_name and either fn (a function taking one argument, the
867 087b34fe Iustin Pop
  file descriptor, and which should write the data to it) or data (the
868 087b34fe Iustin Pop
  contents of the file) must be passed. The other arguments are
869 087b34fe Iustin Pop
  optional and allow setting the file mode, owner and group, and the
870 087b34fe Iustin Pop
  mtime/atime of the file.
871 087b34fe Iustin Pop

872 087b34fe Iustin Pop
  If the function doesn't raise an exception, it has succeeded and the
873 087b34fe Iustin Pop
  target file has the new contents. If the file has raised an
874 087b34fe Iustin Pop
  exception, an existing target file should be unmodified and the
875 087b34fe Iustin Pop
  temporary file should be removed.
876 087b34fe Iustin Pop

877 087b34fe Iustin Pop
  """
878 087b34fe Iustin Pop
  if not os.path.isabs(file_name):
879 087b34fe Iustin Pop
    raise errors.ProgrammerError("Path passed to WriteFile is not"
880 087b34fe Iustin Pop
                                 " absolute: '%s'" % file_name)
881 087b34fe Iustin Pop
882 087b34fe Iustin Pop
  if [fn, data].count(None) != 1:
883 087b34fe Iustin Pop
    raise errors.ProgrammerError("fn or data required")
884 087b34fe Iustin Pop
885 087b34fe Iustin Pop
  if [atime, mtime].count(None) == 1:
886 087b34fe Iustin Pop
    raise errors.ProgrammerError("Both atime and mtime must be either"
887 087b34fe Iustin Pop
                                 " set or None")
888 087b34fe Iustin Pop
889 087b34fe Iustin Pop
890 087b34fe Iustin Pop
  dir_name, base_name = os.path.split(file_name)
891 087b34fe Iustin Pop
  fd, new_name = tempfile.mkstemp('.new', base_name, dir_name)
892 087b34fe Iustin Pop
  # here we need to make sure we remove the temp file, if any error
893 087b34fe Iustin Pop
  # leaves it in place
894 087b34fe Iustin Pop
  try:
895 087b34fe Iustin Pop
    if uid != -1 or gid != -1:
896 087b34fe Iustin Pop
      os.chown(new_name, uid, gid)
897 087b34fe Iustin Pop
    if mode:
898 087b34fe Iustin Pop
      os.chmod(new_name, mode)
899 087b34fe Iustin Pop
    if data is not None:
900 087b34fe Iustin Pop
      os.write(fd, data)
901 087b34fe Iustin Pop
    else:
902 087b34fe Iustin Pop
      fn(fd)
903 087b34fe Iustin Pop
    os.fsync(fd)
904 087b34fe Iustin Pop
    if atime is not None and mtime is not None:
905 087b34fe Iustin Pop
      os.utime(new_name, (atime, mtime))
906 087b34fe Iustin Pop
    os.rename(new_name, file_name)
907 087b34fe Iustin Pop
  finally:
908 087b34fe Iustin Pop
    os.close(fd)
909 087b34fe Iustin Pop
    RemoveFile(new_name)
910 78feb6fb Guido Trotter
911 78feb6fb Guido Trotter
912 78feb6fb Guido Trotter
def all(seq, pred=bool):
913 78feb6fb Guido Trotter
  "Returns True if pred(x) is True for every element in the iterable"
914 78feb6fb Guido Trotter
  for elem in itertools.ifilterfalse(pred, seq):
915 78feb6fb Guido Trotter
    return False
916 78feb6fb Guido Trotter
  return True
917 78feb6fb Guido Trotter
918 78feb6fb Guido Trotter
919 78feb6fb Guido Trotter
def any(seq, pred=bool):
920 78feb6fb Guido Trotter
  "Returns True if pred(x) is True for at least one element in the iterable"
921 78feb6fb Guido Trotter
  for elem in itertools.ifilter(pred, seq):
922 78feb6fb Guido Trotter
    return True
923 78feb6fb Guido Trotter
  return False