Statistics
| Branch: | Tag: | Revision:

root / lib / utils.py @ 339be5a8

History | View | Annotate | Download (79.3 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 58885d79 Iustin Pop
"""Ganeti utility module.
23 58885d79 Iustin Pop

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

27 a8083063 Iustin Pop
"""
28 a8083063 Iustin Pop
29 a8083063 Iustin Pop
30 a8083063 Iustin Pop
import os
31 a8083063 Iustin Pop
import time
32 113b55aa Iustin Pop
import subprocess
33 a8083063 Iustin Pop
import re
34 a8083063 Iustin Pop
import socket
35 a8083063 Iustin Pop
import tempfile
36 a8083063 Iustin Pop
import shutil
37 4ca1b175 Alexander Schreiber
import errno
38 2f8b60b3 Iustin Pop
import pwd
39 78feb6fb Guido Trotter
import itertools
40 9c233417 Iustin Pop
import select
41 9c233417 Iustin Pop
import fcntl
42 8f765069 Iustin Pop
import resource
43 bb698c1f Iustin Pop
import logging
44 551b6283 Iustin Pop
import logging.handlers
45 de499029 Michael Hanselmann
import signal
46 27e46076 Michael Hanselmann
import datetime
47 27e46076 Michael Hanselmann
import calendar
48 339be5a8 Michael Hanselmann
import collections
49 9c233417 Iustin Pop
50 9c233417 Iustin Pop
from cStringIO import StringIO
51 a8083063 Iustin Pop
52 7ffe8fba Carlos Valiente
try:
53 7ffe8fba Carlos Valiente
  from hashlib import sha1
54 7ffe8fba Carlos Valiente
except ImportError:
55 7ffe8fba Carlos Valiente
  import sha
56 7ffe8fba Carlos Valiente
  sha1 = sha.new
57 7ffe8fba Carlos Valiente
58 a8083063 Iustin Pop
from ganeti import errors
59 3aecd2c7 Iustin Pop
from ganeti import constants
60 a8083063 Iustin Pop
61 16abfbc2 Alexander Schreiber
62 a8083063 Iustin Pop
_locksheld = []
63 a8083063 Iustin Pop
_re_shell_unquoted = re.compile('^[-.,=:/_+@A-Za-z0-9]+$')
64 a8083063 Iustin Pop
65 e67bd559 Michael Hanselmann
debug_locks = False
66 58885d79 Iustin Pop
67 58885d79 Iustin Pop
#: when set to True, L{RunCmd} is disabled
68 b74159ee Iustin Pop
no_fork = False
69 f362096f Iustin Pop
70 13998ef2 Michael Hanselmann
_RANDOM_UUID_FILE = "/proc/sys/kernel/random/uuid"
71 13998ef2 Michael Hanselmann
72 7c0d6283 Michael Hanselmann
73 a8083063 Iustin Pop
class RunResult(object):
74 58885d79 Iustin Pop
  """Holds the result of running external programs.
75 58885d79 Iustin Pop

76 58885d79 Iustin Pop
  @type exit_code: int
77 58885d79 Iustin Pop
  @ivar exit_code: the exit code of the program, or None (if the program
78 58885d79 Iustin Pop
      didn't exit())
79 58885d79 Iustin Pop
  @type signal: int or None
80 58885d79 Iustin Pop
  @ivar signal: the signal that caused the program to finish, or None
81 58885d79 Iustin Pop
      (if the program wasn't terminated by a signal)
82 58885d79 Iustin Pop
  @type stdout: str
83 58885d79 Iustin Pop
  @ivar stdout: the standard output of the program
84 58885d79 Iustin Pop
  @type stderr: str
85 58885d79 Iustin Pop
  @ivar stderr: the standard error of the program
86 58885d79 Iustin Pop
  @type failed: boolean
87 58885d79 Iustin Pop
  @ivar failed: True in case the program was
88 58885d79 Iustin Pop
      terminated by a signal or exited with a non-zero exit code
89 58885d79 Iustin Pop
  @ivar fail_reason: a string detailing the termination reason
90 a8083063 Iustin Pop

91 a8083063 Iustin Pop
  """
92 a8083063 Iustin Pop
  __slots__ = ["exit_code", "signal", "stdout", "stderr",
93 a8083063 Iustin Pop
               "failed", "fail_reason", "cmd"]
94 a8083063 Iustin Pop
95 a8083063 Iustin Pop
96 38206f3c Iustin Pop
  def __init__(self, exit_code, signal_, stdout, stderr, cmd):
97 a8083063 Iustin Pop
    self.cmd = cmd
98 a8083063 Iustin Pop
    self.exit_code = exit_code
99 38206f3c Iustin Pop
    self.signal = signal_
100 a8083063 Iustin Pop
    self.stdout = stdout
101 a8083063 Iustin Pop
    self.stderr = stderr
102 38206f3c Iustin Pop
    self.failed = (signal_ is not None or exit_code != 0)
103 a8083063 Iustin Pop
104 a8083063 Iustin Pop
    if self.signal is not None:
105 a8083063 Iustin Pop
      self.fail_reason = "terminated by signal %s" % self.signal
106 a8083063 Iustin Pop
    elif self.exit_code is not None:
107 a8083063 Iustin Pop
      self.fail_reason = "exited with exit code %s" % self.exit_code
108 a8083063 Iustin Pop
    else:
109 a8083063 Iustin Pop
      self.fail_reason = "unable to determine termination reason"
110 a8083063 Iustin Pop
111 bb698c1f Iustin Pop
    if self.failed:
112 bb698c1f Iustin Pop
      logging.debug("Command '%s' failed (%s); output: %s",
113 bb698c1f Iustin Pop
                    self.cmd, self.fail_reason, self.output)
114 f362096f Iustin Pop
115 a8083063 Iustin Pop
  def _GetOutput(self):
116 a8083063 Iustin Pop
    """Returns the combined stdout and stderr for easier usage.
117 a8083063 Iustin Pop

118 a8083063 Iustin Pop
    """
119 a8083063 Iustin Pop
    return self.stdout + self.stderr
120 a8083063 Iustin Pop
121 a8083063 Iustin Pop
  output = property(_GetOutput, None, None, "Return full output")
122 a8083063 Iustin Pop
123 a8083063 Iustin Pop
124 bf4daac9 Guido Trotter
def RunCmd(cmd, env=None, output=None, cwd='/', reset_env=False):
125 a8083063 Iustin Pop
  """Execute a (shell) command.
126 a8083063 Iustin Pop

127 a8083063 Iustin Pop
  The command should not read from its standard input, as it will be
128 a8083063 Iustin Pop
  closed.
129 a8083063 Iustin Pop

130 bf4daac9 Guido Trotter
  @type cmd: string or list
131 36117c2b Iustin Pop
  @param cmd: Command to run
132 2557ff82 Guido Trotter
  @type env: dict
133 58885d79 Iustin Pop
  @param env: Additional environment
134 36117c2b Iustin Pop
  @type output: str
135 58885d79 Iustin Pop
  @param output: if desired, the output of the command can be
136 36117c2b Iustin Pop
      saved in a file instead of the RunResult instance; this
137 36117c2b Iustin Pop
      parameter denotes the file name (if not None)
138 8797df43 Iustin Pop
  @type cwd: string
139 8797df43 Iustin Pop
  @param cwd: if specified, will be used as the working
140 8797df43 Iustin Pop
      directory for the command; the default will be /
141 bf4daac9 Guido Trotter
  @type reset_env: boolean
142 bf4daac9 Guido Trotter
  @param reset_env: whether to reset or keep the default os environment
143 36117c2b Iustin Pop
  @rtype: L{RunResult}
144 58885d79 Iustin Pop
  @return: RunResult instance
145 5bbd3f7f Michael Hanselmann
  @raise errors.ProgrammerError: if we call this when forks are disabled
146 a8083063 Iustin Pop

147 a8083063 Iustin Pop
  """
148 b74159ee Iustin Pop
  if no_fork:
149 b74159ee Iustin Pop
    raise errors.ProgrammerError("utils.RunCmd() called with fork() disabled")
150 b74159ee Iustin Pop
151 a8083063 Iustin Pop
  if isinstance(cmd, list):
152 a8083063 Iustin Pop
    cmd = [str(val) for val in cmd]
153 113b55aa Iustin Pop
    strcmd = " ".join(cmd)
154 113b55aa Iustin Pop
    shell = False
155 113b55aa Iustin Pop
  else:
156 113b55aa Iustin Pop
    strcmd = cmd
157 113b55aa Iustin Pop
    shell = True
158 bb698c1f Iustin Pop
  logging.debug("RunCmd '%s'", strcmd)
159 2557ff82 Guido Trotter
160 bf4daac9 Guido Trotter
  if not reset_env:
161 bf4daac9 Guido Trotter
    cmd_env = os.environ.copy()
162 bf4daac9 Guido Trotter
    cmd_env["LC_ALL"] = "C"
163 bf4daac9 Guido Trotter
  else:
164 bf4daac9 Guido Trotter
    cmd_env = {}
165 bf4daac9 Guido Trotter
166 2557ff82 Guido Trotter
  if env is not None:
167 2557ff82 Guido Trotter
    cmd_env.update(env)
168 2557ff82 Guido Trotter
169 c803b052 Iustin Pop
  try:
170 c803b052 Iustin Pop
    if output is None:
171 c803b052 Iustin Pop
      out, err, status = _RunCmdPipe(cmd, cmd_env, shell, cwd)
172 c803b052 Iustin Pop
    else:
173 c803b052 Iustin Pop
      status = _RunCmdFile(cmd, cmd_env, shell, output, cwd)
174 c803b052 Iustin Pop
      out = err = ""
175 c803b052 Iustin Pop
  except OSError, err:
176 c803b052 Iustin Pop
    if err.errno == errno.ENOENT:
177 c803b052 Iustin Pop
      raise errors.OpExecError("Can't execute '%s': not found (%s)" %
178 c803b052 Iustin Pop
                               (strcmd, err))
179 c803b052 Iustin Pop
    else:
180 c803b052 Iustin Pop
      raise
181 36117c2b Iustin Pop
182 36117c2b Iustin Pop
  if status >= 0:
183 36117c2b Iustin Pop
    exitcode = status
184 36117c2b Iustin Pop
    signal_ = None
185 36117c2b Iustin Pop
  else:
186 36117c2b Iustin Pop
    exitcode = None
187 36117c2b Iustin Pop
    signal_ = -status
188 36117c2b Iustin Pop
189 36117c2b Iustin Pop
  return RunResult(exitcode, signal_, out, err, strcmd)
190 36117c2b Iustin Pop
191 ae59efea Michael Hanselmann
192 8797df43 Iustin Pop
def _RunCmdPipe(cmd, env, via_shell, cwd):
193 36117c2b Iustin Pop
  """Run a command and return its output.
194 36117c2b Iustin Pop

195 36117c2b Iustin Pop
  @type  cmd: string or list
196 36117c2b Iustin Pop
  @param cmd: Command to run
197 36117c2b Iustin Pop
  @type env: dict
198 36117c2b Iustin Pop
  @param env: The environment to use
199 36117c2b Iustin Pop
  @type via_shell: bool
200 36117c2b Iustin Pop
  @param via_shell: if we should run via the shell
201 8797df43 Iustin Pop
  @type cwd: string
202 8797df43 Iustin Pop
  @param cwd: the working directory for the program
203 36117c2b Iustin Pop
  @rtype: tuple
204 36117c2b Iustin Pop
  @return: (out, err, status)
205 36117c2b Iustin Pop

206 36117c2b Iustin Pop
  """
207 9c233417 Iustin Pop
  poller = select.poll()
208 36117c2b Iustin Pop
  child = subprocess.Popen(cmd, shell=via_shell,
209 113b55aa Iustin Pop
                           stderr=subprocess.PIPE,
210 113b55aa Iustin Pop
                           stdout=subprocess.PIPE,
211 113b55aa Iustin Pop
                           stdin=subprocess.PIPE,
212 8797df43 Iustin Pop
                           close_fds=True, env=env,
213 8797df43 Iustin Pop
                           cwd=cwd)
214 113b55aa Iustin Pop
215 113b55aa Iustin Pop
  child.stdin.close()
216 9c233417 Iustin Pop
  poller.register(child.stdout, select.POLLIN)
217 9c233417 Iustin Pop
  poller.register(child.stderr, select.POLLIN)
218 9c233417 Iustin Pop
  out = StringIO()
219 9c233417 Iustin Pop
  err = StringIO()
220 9c233417 Iustin Pop
  fdmap = {
221 9c233417 Iustin Pop
    child.stdout.fileno(): (out, child.stdout),
222 9c233417 Iustin Pop
    child.stderr.fileno(): (err, child.stderr),
223 9c233417 Iustin Pop
    }
224 9c233417 Iustin Pop
  for fd in fdmap:
225 9c233417 Iustin Pop
    status = fcntl.fcntl(fd, fcntl.F_GETFL)
226 9c233417 Iustin Pop
    fcntl.fcntl(fd, fcntl.F_SETFL, status | os.O_NONBLOCK)
227 9c233417 Iustin Pop
228 9c233417 Iustin Pop
  while fdmap:
229 bf988c29 Guido Trotter
    try:
230 bf988c29 Guido Trotter
      pollresult = poller.poll()
231 bf988c29 Guido Trotter
    except EnvironmentError, eerr:
232 bf988c29 Guido Trotter
      if eerr.errno == errno.EINTR:
233 bf988c29 Guido Trotter
        continue
234 bf988c29 Guido Trotter
      raise
235 bf988c29 Guido Trotter
    except select.error, serr:
236 bf988c29 Guido Trotter
      if serr[0] == errno.EINTR:
237 bf988c29 Guido Trotter
        continue
238 bf988c29 Guido Trotter
      raise
239 bf988c29 Guido Trotter
240 bf988c29 Guido Trotter
    for fd, event in pollresult:
241 9c233417 Iustin Pop
      if event & select.POLLIN or event & select.POLLPRI:
242 9c233417 Iustin Pop
        data = fdmap[fd][1].read()
243 9c233417 Iustin Pop
        # no data from read signifies EOF (the same as POLLHUP)
244 9c233417 Iustin Pop
        if not data:
245 9c233417 Iustin Pop
          poller.unregister(fd)
246 9c233417 Iustin Pop
          del fdmap[fd]
247 9c233417 Iustin Pop
          continue
248 9c233417 Iustin Pop
        fdmap[fd][0].write(data)
249 9c233417 Iustin Pop
      if (event & select.POLLNVAL or event & select.POLLHUP or
250 9c233417 Iustin Pop
          event & select.POLLERR):
251 9c233417 Iustin Pop
        poller.unregister(fd)
252 9c233417 Iustin Pop
        del fdmap[fd]
253 9c233417 Iustin Pop
254 9c233417 Iustin Pop
  out = out.getvalue()
255 9c233417 Iustin Pop
  err = err.getvalue()
256 a8083063 Iustin Pop
257 a8083063 Iustin Pop
  status = child.wait()
258 36117c2b Iustin Pop
  return out, err, status
259 a8083063 Iustin Pop
260 36117c2b Iustin Pop
261 8797df43 Iustin Pop
def _RunCmdFile(cmd, env, via_shell, output, cwd):
262 36117c2b Iustin Pop
  """Run a command and save its output to a file.
263 36117c2b Iustin Pop

264 36117c2b Iustin Pop
  @type  cmd: string or list
265 36117c2b Iustin Pop
  @param cmd: Command to run
266 36117c2b Iustin Pop
  @type env: dict
267 36117c2b Iustin Pop
  @param env: The environment to use
268 36117c2b Iustin Pop
  @type via_shell: bool
269 36117c2b Iustin Pop
  @param via_shell: if we should run via the shell
270 36117c2b Iustin Pop
  @type output: str
271 36117c2b Iustin Pop
  @param output: the filename in which to save the output
272 8797df43 Iustin Pop
  @type cwd: string
273 8797df43 Iustin Pop
  @param cwd: the working directory for the program
274 36117c2b Iustin Pop
  @rtype: int
275 36117c2b Iustin Pop
  @return: the exit status
276 36117c2b Iustin Pop

277 36117c2b Iustin Pop
  """
278 36117c2b Iustin Pop
  fh = open(output, "a")
279 36117c2b Iustin Pop
  try:
280 36117c2b Iustin Pop
    child = subprocess.Popen(cmd, shell=via_shell,
281 36117c2b Iustin Pop
                             stderr=subprocess.STDOUT,
282 36117c2b Iustin Pop
                             stdout=fh,
283 36117c2b Iustin Pop
                             stdin=subprocess.PIPE,
284 8797df43 Iustin Pop
                             close_fds=True, env=env,
285 8797df43 Iustin Pop
                             cwd=cwd)
286 36117c2b Iustin Pop
287 36117c2b Iustin Pop
    child.stdin.close()
288 36117c2b Iustin Pop
    status = child.wait()
289 36117c2b Iustin Pop
  finally:
290 36117c2b Iustin Pop
    fh.close()
291 36117c2b Iustin Pop
  return status
292 a8083063 Iustin Pop
293 a8083063 Iustin Pop
294 6bb65e3a Guido Trotter
def RunParts(dir_name, env=None, reset_env=False):
295 6bb65e3a Guido Trotter
  """Run Scripts or programs in a directory
296 6bb65e3a Guido Trotter

297 6bb65e3a Guido Trotter
  @type dir_name: string
298 6bb65e3a Guido Trotter
  @param dir_name: absolute path to a directory
299 6bb65e3a Guido Trotter
  @type env: dict
300 6bb65e3a Guido Trotter
  @param env: The environment to use
301 6bb65e3a Guido Trotter
  @type reset_env: boolean
302 6bb65e3a Guido Trotter
  @param reset_env: whether to reset or keep the default os environment
303 6bb65e3a Guido Trotter
  @rtype: list of tuples
304 6bb65e3a Guido Trotter
  @return: list of (name, (one of RUNDIR_STATUS), RunResult)
305 6bb65e3a Guido Trotter

306 6bb65e3a Guido Trotter
  """
307 6bb65e3a Guido Trotter
  rr = []
308 6bb65e3a Guido Trotter
309 6bb65e3a Guido Trotter
  try:
310 6bb65e3a Guido Trotter
    dir_contents = ListVisibleFiles(dir_name)
311 6bb65e3a Guido Trotter
  except OSError, err:
312 6bb65e3a Guido Trotter
    logging.warning("RunParts: skipping %s (cannot list: %s)", dir_name, err)
313 6bb65e3a Guido Trotter
    return rr
314 6bb65e3a Guido Trotter
315 6bb65e3a Guido Trotter
  for relname in sorted(dir_contents):
316 c4feafe8 Iustin Pop
    fname = PathJoin(dir_name, relname)
317 6bb65e3a Guido Trotter
    if not (os.path.isfile(fname) and os.access(fname, os.X_OK) and
318 6bb65e3a Guido Trotter
            constants.EXT_PLUGIN_MASK.match(relname) is not None):
319 6bb65e3a Guido Trotter
      rr.append((relname, constants.RUNPARTS_SKIP, None))
320 6bb65e3a Guido Trotter
    else:
321 6bb65e3a Guido Trotter
      try:
322 6bb65e3a Guido Trotter
        result = RunCmd([fname], env=env, reset_env=reset_env)
323 6bb65e3a Guido Trotter
      except Exception, err: # pylint: disable-msg=W0703
324 6bb65e3a Guido Trotter
        rr.append((relname, constants.RUNPARTS_ERR, str(err)))
325 6bb65e3a Guido Trotter
      else:
326 6bb65e3a Guido Trotter
        rr.append((relname, constants.RUNPARTS_RUN, result))
327 6bb65e3a Guido Trotter
328 6bb65e3a Guido Trotter
  return rr
329 6bb65e3a Guido Trotter
330 6bb65e3a Guido Trotter
331 a8083063 Iustin Pop
def RemoveFile(filename):
332 a8083063 Iustin Pop
  """Remove a file ignoring some errors.
333 a8083063 Iustin Pop

334 a8083063 Iustin Pop
  Remove a file, ignoring non-existing ones or directories. Other
335 a8083063 Iustin Pop
  errors are passed.
336 a8083063 Iustin Pop

337 58885d79 Iustin Pop
  @type filename: str
338 58885d79 Iustin Pop
  @param filename: the file to be removed
339 58885d79 Iustin Pop

340 a8083063 Iustin Pop
  """
341 a8083063 Iustin Pop
  try:
342 a8083063 Iustin Pop
    os.unlink(filename)
343 a8083063 Iustin Pop
  except OSError, err:
344 4ca1b175 Alexander Schreiber
    if err.errno not in (errno.ENOENT, errno.EISDIR):
345 a8083063 Iustin Pop
      raise
346 a8083063 Iustin Pop
347 a8083063 Iustin Pop
348 6e797216 Michael Hanselmann
def RenameFile(old, new, mkdir=False, mkdir_mode=0750):
349 6e797216 Michael Hanselmann
  """Renames a file.
350 6e797216 Michael Hanselmann

351 6e797216 Michael Hanselmann
  @type old: string
352 6e797216 Michael Hanselmann
  @param old: Original path
353 6e797216 Michael Hanselmann
  @type new: string
354 6e797216 Michael Hanselmann
  @param new: New path
355 6e797216 Michael Hanselmann
  @type mkdir: bool
356 6e797216 Michael Hanselmann
  @param mkdir: Whether to create target directory if it doesn't exist
357 6e797216 Michael Hanselmann
  @type mkdir_mode: int
358 6e797216 Michael Hanselmann
  @param mkdir_mode: Mode for newly created directories
359 6e797216 Michael Hanselmann

360 6e797216 Michael Hanselmann
  """
361 6e797216 Michael Hanselmann
  try:
362 6e797216 Michael Hanselmann
    return os.rename(old, new)
363 6e797216 Michael Hanselmann
  except OSError, err:
364 6e797216 Michael Hanselmann
    # In at least one use case of this function, the job queue, directory
365 6e797216 Michael Hanselmann
    # creation is very rare. Checking for the directory before renaming is not
366 6e797216 Michael Hanselmann
    # as efficient.
367 6e797216 Michael Hanselmann
    if mkdir and err.errno == errno.ENOENT:
368 6e797216 Michael Hanselmann
      # Create directory and try again
369 cc2f004d Michael Hanselmann
      Makedirs(os.path.dirname(new), mode=mkdir_mode)
370 a426508d Michael Hanselmann
371 6e797216 Michael Hanselmann
      return os.rename(old, new)
372 a426508d Michael Hanselmann
373 6e797216 Michael Hanselmann
    raise
374 6e797216 Michael Hanselmann
375 6e797216 Michael Hanselmann
376 76e5f8b5 Michael Hanselmann
def Makedirs(path, mode=0750):
377 76e5f8b5 Michael Hanselmann
  """Super-mkdir; create a leaf directory and all intermediate ones.
378 76e5f8b5 Michael Hanselmann

379 76e5f8b5 Michael Hanselmann
  This is a wrapper around C{os.makedirs} adding error handling not implemented
380 76e5f8b5 Michael Hanselmann
  before Python 2.5.
381 76e5f8b5 Michael Hanselmann

382 76e5f8b5 Michael Hanselmann
  """
383 76e5f8b5 Michael Hanselmann
  try:
384 76e5f8b5 Michael Hanselmann
    os.makedirs(path, mode)
385 76e5f8b5 Michael Hanselmann
  except OSError, err:
386 76e5f8b5 Michael Hanselmann
    # Ignore EEXIST. This is only handled in os.makedirs as included in
387 76e5f8b5 Michael Hanselmann
    # Python 2.5 and above.
388 76e5f8b5 Michael Hanselmann
    if err.errno != errno.EEXIST or not os.path.exists(path):
389 76e5f8b5 Michael Hanselmann
      raise
390 76e5f8b5 Michael Hanselmann
391 76e5f8b5 Michael Hanselmann
392 055f822b Michael Hanselmann
def ResetTempfileModule():
393 055f822b Michael Hanselmann
  """Resets the random name generator of the tempfile module.
394 055f822b Michael Hanselmann

395 055f822b Michael Hanselmann
  This function should be called after C{os.fork} in the child process to
396 055f822b Michael Hanselmann
  ensure it creates a newly seeded random generator. Otherwise it would
397 055f822b Michael Hanselmann
  generate the same random parts as the parent process. If several processes
398 055f822b Michael Hanselmann
  race for the creation of a temporary file, this could lead to one not getting
399 055f822b Michael Hanselmann
  a temporary name.
400 055f822b Michael Hanselmann

401 055f822b Michael Hanselmann
  """
402 055f822b Michael Hanselmann
  # pylint: disable-msg=W0212
403 055f822b Michael Hanselmann
  if hasattr(tempfile, "_once_lock") and hasattr(tempfile, "_name_sequence"):
404 055f822b Michael Hanselmann
    tempfile._once_lock.acquire()
405 055f822b Michael Hanselmann
    try:
406 055f822b Michael Hanselmann
      # Reset random name generator
407 055f822b Michael Hanselmann
      tempfile._name_sequence = None
408 055f822b Michael Hanselmann
    finally:
409 055f822b Michael Hanselmann
      tempfile._once_lock.release()
410 055f822b Michael Hanselmann
  else:
411 055f822b Michael Hanselmann
    logging.critical("The tempfile module misses at least one of the"
412 055f822b Michael Hanselmann
                     " '_once_lock' and '_name_sequence' attributes")
413 055f822b Michael Hanselmann
414 055f822b Michael Hanselmann
415 a8083063 Iustin Pop
def _FingerprintFile(filename):
416 a8083063 Iustin Pop
  """Compute the fingerprint of a file.
417 a8083063 Iustin Pop

418 a8083063 Iustin Pop
  If the file does not exist, a None will be returned
419 a8083063 Iustin Pop
  instead.
420 a8083063 Iustin Pop

421 58885d79 Iustin Pop
  @type filename: str
422 58885d79 Iustin Pop
  @param filename: the filename to checksum
423 58885d79 Iustin Pop
  @rtype: str
424 58885d79 Iustin Pop
  @return: the hex digest of the sha checksum of the contents
425 58885d79 Iustin Pop
      of the file
426 a8083063 Iustin Pop

427 a8083063 Iustin Pop
  """
428 a8083063 Iustin Pop
  if not (os.path.exists(filename) and os.path.isfile(filename)):
429 a8083063 Iustin Pop
    return None
430 a8083063 Iustin Pop
431 a8083063 Iustin Pop
  f = open(filename)
432 a8083063 Iustin Pop
433 7ffe8fba Carlos Valiente
  fp = sha1()
434 a8083063 Iustin Pop
  while True:
435 a8083063 Iustin Pop
    data = f.read(4096)
436 a8083063 Iustin Pop
    if not data:
437 a8083063 Iustin Pop
      break
438 a8083063 Iustin Pop
439 a8083063 Iustin Pop
    fp.update(data)
440 a8083063 Iustin Pop
441 a8083063 Iustin Pop
  return fp.hexdigest()
442 a8083063 Iustin Pop
443 a8083063 Iustin Pop
444 a8083063 Iustin Pop
def FingerprintFiles(files):
445 a8083063 Iustin Pop
  """Compute fingerprints for a list of files.
446 a8083063 Iustin Pop

447 58885d79 Iustin Pop
  @type files: list
448 58885d79 Iustin Pop
  @param files: the list of filename to fingerprint
449 58885d79 Iustin Pop
  @rtype: dict
450 58885d79 Iustin Pop
  @return: a dictionary filename: fingerprint, holding only
451 58885d79 Iustin Pop
      existing files
452 a8083063 Iustin Pop

453 a8083063 Iustin Pop
  """
454 a8083063 Iustin Pop
  ret = {}
455 a8083063 Iustin Pop
456 a8083063 Iustin Pop
  for filename in files:
457 a8083063 Iustin Pop
    cksum = _FingerprintFile(filename)
458 a8083063 Iustin Pop
    if cksum:
459 a8083063 Iustin Pop
      ret[filename] = cksum
460 a8083063 Iustin Pop
461 a8083063 Iustin Pop
  return ret
462 a8083063 Iustin Pop
463 a8083063 Iustin Pop
464 a5728081 Guido Trotter
def ForceDictType(target, key_types, allowed_values=None):
465 a5728081 Guido Trotter
  """Force the values of a dict to have certain types.
466 a5728081 Guido Trotter

467 a5728081 Guido Trotter
  @type target: dict
468 a5728081 Guido Trotter
  @param target: the dict to update
469 a5728081 Guido Trotter
  @type key_types: dict
470 a5728081 Guido Trotter
  @param key_types: dict mapping target dict keys to types
471 a5728081 Guido Trotter
                    in constants.ENFORCEABLE_TYPES
472 a5728081 Guido Trotter
  @type allowed_values: list
473 a5728081 Guido Trotter
  @keyword allowed_values: list of specially allowed values
474 a5728081 Guido Trotter

475 a5728081 Guido Trotter
  """
476 a5728081 Guido Trotter
  if allowed_values is None:
477 a5728081 Guido Trotter
    allowed_values = []
478 a5728081 Guido Trotter
479 8b46606c Guido Trotter
  if not isinstance(target, dict):
480 8b46606c Guido Trotter
    msg = "Expected dictionary, got '%s'" % target
481 8b46606c Guido Trotter
    raise errors.TypeEnforcementError(msg)
482 8b46606c Guido Trotter
483 a5728081 Guido Trotter
  for key in target:
484 a5728081 Guido Trotter
    if key not in key_types:
485 a5728081 Guido Trotter
      msg = "Unknown key '%s'" % key
486 a5728081 Guido Trotter
      raise errors.TypeEnforcementError(msg)
487 a5728081 Guido Trotter
488 a5728081 Guido Trotter
    if target[key] in allowed_values:
489 a5728081 Guido Trotter
      continue
490 a5728081 Guido Trotter
491 29921401 Iustin Pop
    ktype = key_types[key]
492 29921401 Iustin Pop
    if ktype not in constants.ENFORCEABLE_TYPES:
493 29921401 Iustin Pop
      msg = "'%s' has non-enforceable type %s" % (key, ktype)
494 a5728081 Guido Trotter
      raise errors.ProgrammerError(msg)
495 a5728081 Guido Trotter
496 29921401 Iustin Pop
    if ktype == constants.VTYPE_STRING:
497 a5728081 Guido Trotter
      if not isinstance(target[key], basestring):
498 a5728081 Guido Trotter
        if isinstance(target[key], bool) and not target[key]:
499 a5728081 Guido Trotter
          target[key] = ''
500 a5728081 Guido Trotter
        else:
501 a5728081 Guido Trotter
          msg = "'%s' (value %s) is not a valid string" % (key, target[key])
502 a5728081 Guido Trotter
          raise errors.TypeEnforcementError(msg)
503 29921401 Iustin Pop
    elif ktype == constants.VTYPE_BOOL:
504 a5728081 Guido Trotter
      if isinstance(target[key], basestring) and target[key]:
505 a5728081 Guido Trotter
        if target[key].lower() == constants.VALUE_FALSE:
506 a5728081 Guido Trotter
          target[key] = False
507 a5728081 Guido Trotter
        elif target[key].lower() == constants.VALUE_TRUE:
508 a5728081 Guido Trotter
          target[key] = True
509 a5728081 Guido Trotter
        else:
510 a5728081 Guido Trotter
          msg = "'%s' (value %s) is not a valid boolean" % (key, target[key])
511 a5728081 Guido Trotter
          raise errors.TypeEnforcementError(msg)
512 a5728081 Guido Trotter
      elif target[key]:
513 a5728081 Guido Trotter
        target[key] = True
514 a5728081 Guido Trotter
      else:
515 a5728081 Guido Trotter
        target[key] = False
516 29921401 Iustin Pop
    elif ktype == constants.VTYPE_SIZE:
517 a5728081 Guido Trotter
      try:
518 a5728081 Guido Trotter
        target[key] = ParseUnit(target[key])
519 a5728081 Guido Trotter
      except errors.UnitParseError, err:
520 a5728081 Guido Trotter
        msg = "'%s' (value %s) is not a valid size. error: %s" % \
521 a5728081 Guido Trotter
              (key, target[key], err)
522 a5728081 Guido Trotter
        raise errors.TypeEnforcementError(msg)
523 29921401 Iustin Pop
    elif ktype == constants.VTYPE_INT:
524 a5728081 Guido Trotter
      try:
525 a5728081 Guido Trotter
        target[key] = int(target[key])
526 a5728081 Guido Trotter
      except (ValueError, TypeError):
527 a5728081 Guido Trotter
        msg = "'%s' (value %s) is not a valid integer" % (key, target[key])
528 a5728081 Guido Trotter
        raise errors.TypeEnforcementError(msg)
529 a5728081 Guido Trotter
530 a5728081 Guido Trotter
531 a8083063 Iustin Pop
def IsProcessAlive(pid):
532 a8083063 Iustin Pop
  """Check if a given pid exists on the system.
533 a8083063 Iustin Pop

534 44bf25ff Iustin Pop
  @note: zombie status is not handled, so zombie processes
535 44bf25ff Iustin Pop
      will be returned as alive
536 58885d79 Iustin Pop
  @type pid: int
537 58885d79 Iustin Pop
  @param pid: the process ID to check
538 58885d79 Iustin Pop
  @rtype: boolean
539 58885d79 Iustin Pop
  @return: True if the process exists
540 a8083063 Iustin Pop

541 a8083063 Iustin Pop
  """
542 d9f311d7 Iustin Pop
  if pid <= 0:
543 d9f311d7 Iustin Pop
    return False
544 d9f311d7 Iustin Pop
545 a8083063 Iustin Pop
  try:
546 44bf25ff Iustin Pop
    os.stat("/proc/%d/status" % pid)
547 44bf25ff Iustin Pop
    return True
548 44bf25ff Iustin Pop
  except EnvironmentError, err:
549 4ca1b175 Alexander Schreiber
    if err.errno in (errno.ENOENT, errno.ENOTDIR):
550 a8083063 Iustin Pop
      return False
551 44bf25ff Iustin Pop
    raise
552 a8083063 Iustin Pop
553 a8083063 Iustin Pop
554 d9f311d7 Iustin Pop
def ReadPidFile(pidfile):
555 58885d79 Iustin Pop
  """Read a pid from a file.
556 fee80e90 Guido Trotter

557 58885d79 Iustin Pop
  @type  pidfile: string
558 58885d79 Iustin Pop
  @param pidfile: path to the file containing the pid
559 58885d79 Iustin Pop
  @rtype: int
560 1de62f37 Guido Trotter
  @return: The process id, if the file exists and contains a valid PID,
561 d9f311d7 Iustin Pop
           otherwise 0
562 fee80e90 Guido Trotter

563 fee80e90 Guido Trotter
  """
564 fee80e90 Guido Trotter
  try:
565 13998ef2 Michael Hanselmann
    raw_data = ReadFile(pidfile)
566 d9f311d7 Iustin Pop
  except EnvironmentError, err:
567 d9f311d7 Iustin Pop
    if err.errno != errno.ENOENT:
568 13998ef2 Michael Hanselmann
      logging.exception("Can't read pid file")
569 d9f311d7 Iustin Pop
    return 0
570 fee80e90 Guido Trotter
571 fee80e90 Guido Trotter
  try:
572 13998ef2 Michael Hanselmann
    pid = int(raw_data)
573 691744c4 Iustin Pop
  except (TypeError, ValueError), err:
574 8161a646 Iustin Pop
    logging.info("Can't parse pid file contents", exc_info=True)
575 d9f311d7 Iustin Pop
    return 0
576 fee80e90 Guido Trotter
577 d9f311d7 Iustin Pop
  return pid
578 fee80e90 Guido Trotter
579 fee80e90 Guido Trotter
580 256eb94b Guido Trotter
def MatchNameComponent(key, name_list, case_sensitive=True):
581 a8083063 Iustin Pop
  """Try to match a name against a list.
582 a8083063 Iustin Pop

583 a8083063 Iustin Pop
  This function will try to match a name like test1 against a list
584 58885d79 Iustin Pop
  like C{['test1.example.com', 'test2.example.com', ...]}. Against
585 58885d79 Iustin Pop
  this list, I{'test1'} as well as I{'test1.example'} will match, but
586 58885d79 Iustin Pop
  not I{'test1.ex'}. A multiple match will be considered as no match
587 58885d79 Iustin Pop
  at all (e.g. I{'test1'} against C{['test1.example.com',
588 3a541d90 Iustin Pop
  'test1.example.org']}), except when the key fully matches an entry
589 3a541d90 Iustin Pop
  (e.g. I{'test1'} against C{['test1', 'test1.example.com']}).
590 a8083063 Iustin Pop

591 58885d79 Iustin Pop
  @type key: str
592 58885d79 Iustin Pop
  @param key: the name to be searched
593 58885d79 Iustin Pop
  @type name_list: list
594 58885d79 Iustin Pop
  @param name_list: the list of strings against which to search the key
595 256eb94b Guido Trotter
  @type case_sensitive: boolean
596 256eb94b Guido Trotter
  @param case_sensitive: whether to provide a case-sensitive match
597 a8083063 Iustin Pop

598 58885d79 Iustin Pop
  @rtype: None or str
599 58885d79 Iustin Pop
  @return: None if there is no match I{or} if there are multiple matches,
600 58885d79 Iustin Pop
      otherwise the element from the list which matches
601 a8083063 Iustin Pop

602 a8083063 Iustin Pop
  """
603 3a541d90 Iustin Pop
  if key in name_list:
604 3a541d90 Iustin Pop
    return key
605 256eb94b Guido Trotter
606 256eb94b Guido Trotter
  re_flags = 0
607 256eb94b Guido Trotter
  if not case_sensitive:
608 256eb94b Guido Trotter
    re_flags |= re.IGNORECASE
609 099c52ad Iustin Pop
    key = key.upper()
610 256eb94b Guido Trotter
  mo = re.compile("^%s(\..*)?$" % re.escape(key), re_flags)
611 256eb94b Guido Trotter
  names_filtered = []
612 256eb94b Guido Trotter
  string_matches = []
613 256eb94b Guido Trotter
  for name in name_list:
614 256eb94b Guido Trotter
    if mo.match(name) is not None:
615 256eb94b Guido Trotter
      names_filtered.append(name)
616 099c52ad Iustin Pop
      if not case_sensitive and key == name.upper():
617 256eb94b Guido Trotter
        string_matches.append(name)
618 256eb94b Guido Trotter
619 256eb94b Guido Trotter
  if len(string_matches) == 1:
620 256eb94b Guido Trotter
    return string_matches[0]
621 256eb94b Guido Trotter
  if len(names_filtered) == 1:
622 256eb94b Guido Trotter
    return names_filtered[0]
623 256eb94b Guido Trotter
  return None
624 a8083063 Iustin Pop
625 a8083063 Iustin Pop
626 bcf043c9 Iustin Pop
class HostInfo:
627 89e1fc26 Iustin Pop
  """Class implementing resolver and hostname functionality
628 bcf043c9 Iustin Pop

629 bcf043c9 Iustin Pop
  """
630 26288e68 Iustin Pop
  _VALID_NAME_RE = re.compile("^[a-z0-9._-]{1,255}$")
631 26288e68 Iustin Pop
632 89e1fc26 Iustin Pop
  def __init__(self, name=None):
633 bcf043c9 Iustin Pop
    """Initialize the host name object.
634 bcf043c9 Iustin Pop

635 89e1fc26 Iustin Pop
    If the name argument is not passed, it will use this system's
636 89e1fc26 Iustin Pop
    name.
637 bcf043c9 Iustin Pop

638 bcf043c9 Iustin Pop
    """
639 89e1fc26 Iustin Pop
    if name is None:
640 89e1fc26 Iustin Pop
      name = self.SysName()
641 89e1fc26 Iustin Pop
642 89e1fc26 Iustin Pop
    self.query = name
643 89e1fc26 Iustin Pop
    self.name, self.aliases, self.ipaddrs = self.LookupHostname(name)
644 bcf043c9 Iustin Pop
    self.ip = self.ipaddrs[0]
645 bcf043c9 Iustin Pop
646 c8a0948f Michael Hanselmann
  def ShortName(self):
647 c8a0948f Michael Hanselmann
    """Returns the hostname without domain.
648 c8a0948f Michael Hanselmann

649 c8a0948f Michael Hanselmann
    """
650 c8a0948f Michael Hanselmann
    return self.name.split('.')[0]
651 c8a0948f Michael Hanselmann
652 89e1fc26 Iustin Pop
  @staticmethod
653 89e1fc26 Iustin Pop
  def SysName():
654 89e1fc26 Iustin Pop
    """Return the current system's name.
655 bcf043c9 Iustin Pop

656 58885d79 Iustin Pop
    This is simply a wrapper over C{socket.gethostname()}.
657 a8083063 Iustin Pop

658 89e1fc26 Iustin Pop
    """
659 89e1fc26 Iustin Pop
    return socket.gethostname()
660 a8083063 Iustin Pop
661 89e1fc26 Iustin Pop
  @staticmethod
662 89e1fc26 Iustin Pop
  def LookupHostname(hostname):
663 89e1fc26 Iustin Pop
    """Look up hostname
664 a8083063 Iustin Pop

665 58885d79 Iustin Pop
    @type hostname: str
666 58885d79 Iustin Pop
    @param hostname: hostname to look up
667 89e1fc26 Iustin Pop

668 58885d79 Iustin Pop
    @rtype: tuple
669 58885d79 Iustin Pop
    @return: a tuple (name, aliases, ipaddrs) as returned by
670 58885d79 Iustin Pop
        C{socket.gethostbyname_ex}
671 58885d79 Iustin Pop
    @raise errors.ResolverError: in case of errors in resolving
672 89e1fc26 Iustin Pop

673 89e1fc26 Iustin Pop
    """
674 89e1fc26 Iustin Pop
    try:
675 89e1fc26 Iustin Pop
      result = socket.gethostbyname_ex(hostname)
676 89e1fc26 Iustin Pop
    except socket.gaierror, err:
677 89e1fc26 Iustin Pop
      # hostname not found in DNS
678 89e1fc26 Iustin Pop
      raise errors.ResolverError(hostname, err.args[0], err.args[1])
679 a8083063 Iustin Pop
680 89e1fc26 Iustin Pop
    return result
681 a8083063 Iustin Pop
682 26288e68 Iustin Pop
  @classmethod
683 26288e68 Iustin Pop
  def NormalizeName(cls, hostname):
684 26288e68 Iustin Pop
    """Validate and normalize the given hostname.
685 26288e68 Iustin Pop

686 26288e68 Iustin Pop
    @attention: the validation is a bit more relaxed than the standards
687 26288e68 Iustin Pop
        require; most importantly, we allow underscores in names
688 26288e68 Iustin Pop
    @raise errors.OpPrereqError: when the name is not valid
689 26288e68 Iustin Pop

690 26288e68 Iustin Pop
    """
691 26288e68 Iustin Pop
    hostname = hostname.lower()
692 26288e68 Iustin Pop
    if (not cls._VALID_NAME_RE.match(hostname) or
693 26288e68 Iustin Pop
        # double-dots, meaning empty label
694 26288e68 Iustin Pop
        ".." in hostname or
695 26288e68 Iustin Pop
        # empty initial label
696 26288e68 Iustin Pop
        hostname.startswith(".")):
697 26288e68 Iustin Pop
      raise errors.OpPrereqError("Invalid hostname '%s'" % hostname,
698 26288e68 Iustin Pop
                                 errors.ECODE_INVAL)
699 26288e68 Iustin Pop
    if hostname.endswith("."):
700 26288e68 Iustin Pop
      hostname = hostname.rstrip(".")
701 26288e68 Iustin Pop
    return hostname
702 26288e68 Iustin Pop
703 a8083063 Iustin Pop
704 104f4ca1 Iustin Pop
def GetHostInfo(name=None):
705 104f4ca1 Iustin Pop
  """Lookup host name and raise an OpPrereqError for failures"""
706 104f4ca1 Iustin Pop
707 104f4ca1 Iustin Pop
  try:
708 104f4ca1 Iustin Pop
    return HostInfo(name)
709 104f4ca1 Iustin Pop
  except errors.ResolverError, err:
710 104f4ca1 Iustin Pop
    raise errors.OpPrereqError("The given name (%s) does not resolve: %s" %
711 104f4ca1 Iustin Pop
                               (err[0], err[2]), errors.ECODE_RESOLVER)
712 104f4ca1 Iustin Pop
713 104f4ca1 Iustin Pop
714 a8083063 Iustin Pop
def ListVolumeGroups():
715 a8083063 Iustin Pop
  """List volume groups and their size
716 a8083063 Iustin Pop

717 58885d79 Iustin Pop
  @rtype: dict
718 58885d79 Iustin Pop
  @return:
719 58885d79 Iustin Pop
       Dictionary with keys volume name and values
720 58885d79 Iustin Pop
       the size of the volume
721 a8083063 Iustin Pop

722 a8083063 Iustin Pop
  """
723 a8083063 Iustin Pop
  command = "vgs --noheadings --units m --nosuffix -o name,size"
724 a8083063 Iustin Pop
  result = RunCmd(command)
725 a8083063 Iustin Pop
  retval = {}
726 a8083063 Iustin Pop
  if result.failed:
727 a8083063 Iustin Pop
    return retval
728 a8083063 Iustin Pop
729 a8083063 Iustin Pop
  for line in result.stdout.splitlines():
730 a8083063 Iustin Pop
    try:
731 a8083063 Iustin Pop
      name, size = line.split()
732 a8083063 Iustin Pop
      size = int(float(size))
733 a8083063 Iustin Pop
    except (IndexError, ValueError), err:
734 bb698c1f Iustin Pop
      logging.error("Invalid output from vgs (%s): %s", err, line)
735 a8083063 Iustin Pop
      continue
736 a8083063 Iustin Pop
737 a8083063 Iustin Pop
    retval[name] = size
738 a8083063 Iustin Pop
739 a8083063 Iustin Pop
  return retval
740 a8083063 Iustin Pop
741 a8083063 Iustin Pop
742 a8083063 Iustin Pop
def BridgeExists(bridge):
743 a8083063 Iustin Pop
  """Check whether the given bridge exists in the system
744 a8083063 Iustin Pop

745 58885d79 Iustin Pop
  @type bridge: str
746 58885d79 Iustin Pop
  @param bridge: the bridge name to check
747 58885d79 Iustin Pop
  @rtype: boolean
748 58885d79 Iustin Pop
  @return: True if it does
749 a8083063 Iustin Pop

750 a8083063 Iustin Pop
  """
751 a8083063 Iustin Pop
  return os.path.isdir("/sys/class/net/%s/bridge" % bridge)
752 a8083063 Iustin Pop
753 a8083063 Iustin Pop
754 a8083063 Iustin Pop
def NiceSort(name_list):
755 a8083063 Iustin Pop
  """Sort a list of strings based on digit and non-digit groupings.
756 a8083063 Iustin Pop

757 58885d79 Iustin Pop
  Given a list of names C{['a1', 'a10', 'a11', 'a2']} this function
758 58885d79 Iustin Pop
  will sort the list in the logical order C{['a1', 'a2', 'a10',
759 58885d79 Iustin Pop
  'a11']}.
760 a8083063 Iustin Pop

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

765 58885d79 Iustin Pop
  @type name_list: list
766 58885d79 Iustin Pop
  @param name_list: the names to be sorted
767 58885d79 Iustin Pop
  @rtype: list
768 58885d79 Iustin Pop
  @return: a copy of the name list sorted with our algorithm
769 a8083063 Iustin Pop

770 a8083063 Iustin Pop
  """
771 a8083063 Iustin Pop
  _SORTER_BASE = "(\D+|\d+)"
772 a8083063 Iustin Pop
  _SORTER_FULL = "^%s%s?%s?%s?%s?%s?%s?%s?.*$" % (_SORTER_BASE, _SORTER_BASE,
773 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE,
774 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE,
775 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE)
776 a8083063 Iustin Pop
  _SORTER_RE = re.compile(_SORTER_FULL)
777 a8083063 Iustin Pop
  _SORTER_NODIGIT = re.compile("^\D*$")
778 a8083063 Iustin Pop
  def _TryInt(val):
779 a8083063 Iustin Pop
    """Attempts to convert a variable to integer."""
780 a8083063 Iustin Pop
    if val is None or _SORTER_NODIGIT.match(val):
781 a8083063 Iustin Pop
      return val
782 a8083063 Iustin Pop
    rval = int(val)
783 a8083063 Iustin Pop
    return rval
784 a8083063 Iustin Pop
785 a8083063 Iustin Pop
  to_sort = [([_TryInt(grp) for grp in _SORTER_RE.match(name).groups()], name)
786 a8083063 Iustin Pop
             for name in name_list]
787 a8083063 Iustin Pop
  to_sort.sort()
788 a8083063 Iustin Pop
  return [tup[1] for tup in to_sort]
789 a8083063 Iustin Pop
790 a8083063 Iustin Pop
791 a8083063 Iustin Pop
def TryConvert(fn, val):
792 a8083063 Iustin Pop
  """Try to convert a value ignoring errors.
793 a8083063 Iustin Pop

794 58885d79 Iustin Pop
  This function tries to apply function I{fn} to I{val}. If no
795 58885d79 Iustin Pop
  C{ValueError} or C{TypeError} exceptions are raised, it will return
796 58885d79 Iustin Pop
  the result, else it will return the original value. Any other
797 58885d79 Iustin Pop
  exceptions are propagated to the caller.
798 58885d79 Iustin Pop

799 58885d79 Iustin Pop
  @type fn: callable
800 58885d79 Iustin Pop
  @param fn: function to apply to the value
801 58885d79 Iustin Pop
  @param val: the value to be converted
802 58885d79 Iustin Pop
  @return: The converted value if the conversion was successful,
803 58885d79 Iustin Pop
      otherwise the original value.
804 a8083063 Iustin Pop

805 a8083063 Iustin Pop
  """
806 a8083063 Iustin Pop
  try:
807 a8083063 Iustin Pop
    nv = fn(val)
808 7c4d6c7b Michael Hanselmann
  except (ValueError, TypeError):
809 a8083063 Iustin Pop
    nv = val
810 a8083063 Iustin Pop
  return nv
811 a8083063 Iustin Pop
812 a8083063 Iustin Pop
813 a8083063 Iustin Pop
def IsValidIP(ip):
814 58885d79 Iustin Pop
  """Verifies the syntax of an IPv4 address.
815 a8083063 Iustin Pop

816 58885d79 Iustin Pop
  This function checks if the IPv4 address passes is valid or not based
817 58885d79 Iustin Pop
  on syntax (not IP range, class calculations, etc.).
818 58885d79 Iustin Pop

819 58885d79 Iustin Pop
  @type ip: str
820 58885d79 Iustin Pop
  @param ip: the address to be checked
821 58885d79 Iustin Pop
  @rtype: a regular expression match object
822 5bbd3f7f Michael Hanselmann
  @return: a regular expression match object, or None if the
823 58885d79 Iustin Pop
      address is not valid
824 a8083063 Iustin Pop

825 a8083063 Iustin Pop
  """
826 a8083063 Iustin Pop
  unit = "(0|[1-9]\d{0,2})"
827 58885d79 Iustin Pop
  #TODO: convert and return only boolean
828 a8083063 Iustin Pop
  return re.match("^%s\.%s\.%s\.%s$" % (unit, unit, unit, unit), ip)
829 a8083063 Iustin Pop
830 a8083063 Iustin Pop
831 a8083063 Iustin Pop
def IsValidShellParam(word):
832 a8083063 Iustin Pop
  """Verifies is the given word is safe from the shell's p.o.v.
833 a8083063 Iustin Pop

834 a8083063 Iustin Pop
  This means that we can pass this to a command via the shell and be
835 a8083063 Iustin Pop
  sure that it doesn't alter the command line and is passed as such to
836 a8083063 Iustin Pop
  the actual command.
837 a8083063 Iustin Pop

838 a8083063 Iustin Pop
  Note that we are overly restrictive here, in order to be on the safe
839 a8083063 Iustin Pop
  side.
840 a8083063 Iustin Pop

841 58885d79 Iustin Pop
  @type word: str
842 58885d79 Iustin Pop
  @param word: the word to check
843 58885d79 Iustin Pop
  @rtype: boolean
844 58885d79 Iustin Pop
  @return: True if the word is 'safe'
845 58885d79 Iustin Pop

846 a8083063 Iustin Pop
  """
847 a8083063 Iustin Pop
  return bool(re.match("^[-a-zA-Z0-9._+/:%@]+$", word))
848 a8083063 Iustin Pop
849 a8083063 Iustin Pop
850 a8083063 Iustin Pop
def BuildShellCmd(template, *args):
851 a8083063 Iustin Pop
  """Build a safe shell command line from the given arguments.
852 a8083063 Iustin Pop

853 a8083063 Iustin Pop
  This function will check all arguments in the args list so that they
854 a8083063 Iustin Pop
  are valid shell parameters (i.e. they don't contain shell
855 5bbd3f7f Michael Hanselmann
  metacharacters). If everything is ok, it will return the result of
856 a8083063 Iustin Pop
  template % args.
857 a8083063 Iustin Pop

858 58885d79 Iustin Pop
  @type template: str
859 58885d79 Iustin Pop
  @param template: the string holding the template for the
860 58885d79 Iustin Pop
      string formatting
861 58885d79 Iustin Pop
  @rtype: str
862 58885d79 Iustin Pop
  @return: the expanded command line
863 58885d79 Iustin Pop

864 a8083063 Iustin Pop
  """
865 a8083063 Iustin Pop
  for word in args:
866 a8083063 Iustin Pop
    if not IsValidShellParam(word):
867 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Shell argument '%s' contains"
868 3ecf6786 Iustin Pop
                                   " invalid characters" % word)
869 a8083063 Iustin Pop
  return template % args
870 a8083063 Iustin Pop
871 a8083063 Iustin Pop
872 9fbfbb7b Iustin Pop
def FormatUnit(value, units):
873 a8083063 Iustin Pop
  """Formats an incoming number of MiB with the appropriate unit.
874 a8083063 Iustin Pop

875 58885d79 Iustin Pop
  @type value: int
876 58885d79 Iustin Pop
  @param value: integer representing the value in MiB (1048576)
877 9fbfbb7b Iustin Pop
  @type units: char
878 9fbfbb7b Iustin Pop
  @param units: the type of formatting we should do:
879 9fbfbb7b Iustin Pop
      - 'h' for automatic scaling
880 9fbfbb7b Iustin Pop
      - 'm' for MiBs
881 9fbfbb7b Iustin Pop
      - 'g' for GiBs
882 9fbfbb7b Iustin Pop
      - 't' for TiBs
883 58885d79 Iustin Pop
  @rtype: str
884 58885d79 Iustin Pop
  @return: the formatted value (with suffix)
885 a8083063 Iustin Pop

886 a8083063 Iustin Pop
  """
887 9fbfbb7b Iustin Pop
  if units not in ('m', 'g', 't', 'h'):
888 9fbfbb7b Iustin Pop
    raise errors.ProgrammerError("Invalid unit specified '%s'" % str(units))
889 a8083063 Iustin Pop
890 9fbfbb7b Iustin Pop
  suffix = ''
891 9fbfbb7b Iustin Pop
892 9fbfbb7b Iustin Pop
  if units == 'm' or (units == 'h' and value < 1024):
893 9fbfbb7b Iustin Pop
    if units == 'h':
894 9fbfbb7b Iustin Pop
      suffix = 'M'
895 9fbfbb7b Iustin Pop
    return "%d%s" % (round(value, 0), suffix)
896 9fbfbb7b Iustin Pop
897 9fbfbb7b Iustin Pop
  elif units == 'g' or (units == 'h' and value < (1024 * 1024)):
898 9fbfbb7b Iustin Pop
    if units == 'h':
899 9fbfbb7b Iustin Pop
      suffix = 'G'
900 9fbfbb7b Iustin Pop
    return "%0.1f%s" % (round(float(value) / 1024, 1), suffix)
901 a8083063 Iustin Pop
902 a8083063 Iustin Pop
  else:
903 9fbfbb7b Iustin Pop
    if units == 'h':
904 9fbfbb7b Iustin Pop
      suffix = 'T'
905 9fbfbb7b Iustin Pop
    return "%0.1f%s" % (round(float(value) / 1024 / 1024, 1), suffix)
906 a8083063 Iustin Pop
907 a8083063 Iustin Pop
908 a8083063 Iustin Pop
def ParseUnit(input_string):
909 a8083063 Iustin Pop
  """Tries to extract number and scale from the given string.
910 a8083063 Iustin Pop

911 58885d79 Iustin Pop
  Input must be in the format C{NUMBER+ [DOT NUMBER+] SPACE*
912 58885d79 Iustin Pop
  [UNIT]}. If no unit is specified, it defaults to MiB. Return value
913 58885d79 Iustin Pop
  is always an int in MiB.
914 a8083063 Iustin Pop

915 a8083063 Iustin Pop
  """
916 9939547b Iustin Pop
  m = re.match('^([.\d]+)\s*([a-zA-Z]+)?$', str(input_string))
917 a8083063 Iustin Pop
  if not m:
918 3ecf6786 Iustin Pop
    raise errors.UnitParseError("Invalid format")
919 a8083063 Iustin Pop
920 a8083063 Iustin Pop
  value = float(m.groups()[0])
921 a8083063 Iustin Pop
922 a8083063 Iustin Pop
  unit = m.groups()[1]
923 a8083063 Iustin Pop
  if unit:
924 a8083063 Iustin Pop
    lcunit = unit.lower()
925 a8083063 Iustin Pop
  else:
926 a8083063 Iustin Pop
    lcunit = 'm'
927 a8083063 Iustin Pop
928 a8083063 Iustin Pop
  if lcunit in ('m', 'mb', 'mib'):
929 a8083063 Iustin Pop
    # Value already in MiB
930 a8083063 Iustin Pop
    pass
931 a8083063 Iustin Pop
932 a8083063 Iustin Pop
  elif lcunit in ('g', 'gb', 'gib'):
933 a8083063 Iustin Pop
    value *= 1024
934 a8083063 Iustin Pop
935 a8083063 Iustin Pop
  elif lcunit in ('t', 'tb', 'tib'):
936 a8083063 Iustin Pop
    value *= 1024 * 1024
937 a8083063 Iustin Pop
938 a8083063 Iustin Pop
  else:
939 3ecf6786 Iustin Pop
    raise errors.UnitParseError("Unknown unit: %s" % unit)
940 a8083063 Iustin Pop
941 a8083063 Iustin Pop
  # Make sure we round up
942 a8083063 Iustin Pop
  if int(value) < value:
943 a8083063 Iustin Pop
    value += 1
944 a8083063 Iustin Pop
945 a8083063 Iustin Pop
  # Round up to the next multiple of 4
946 a8083063 Iustin Pop
  value = int(value)
947 a8083063 Iustin Pop
  if value % 4:
948 a8083063 Iustin Pop
    value += 4 - value % 4
949 a8083063 Iustin Pop
950 a8083063 Iustin Pop
  return value
951 a8083063 Iustin Pop
952 a8083063 Iustin Pop
953 a8083063 Iustin Pop
def AddAuthorizedKey(file_name, key):
954 a8083063 Iustin Pop
  """Adds an SSH public key to an authorized_keys file.
955 a8083063 Iustin Pop

956 58885d79 Iustin Pop
  @type file_name: str
957 58885d79 Iustin Pop
  @param file_name: path to authorized_keys file
958 58885d79 Iustin Pop
  @type key: str
959 58885d79 Iustin Pop
  @param key: string containing key
960 58885d79 Iustin Pop

961 a8083063 Iustin Pop
  """
962 a8083063 Iustin Pop
  key_fields = key.split()
963 a8083063 Iustin Pop
964 a8083063 Iustin Pop
  f = open(file_name, 'a+')
965 a8083063 Iustin Pop
  try:
966 a8083063 Iustin Pop
    nl = True
967 a8083063 Iustin Pop
    for line in f:
968 a8083063 Iustin Pop
      # Ignore whitespace changes
969 a8083063 Iustin Pop
      if line.split() == key_fields:
970 a8083063 Iustin Pop
        break
971 a8083063 Iustin Pop
      nl = line.endswith('\n')
972 a8083063 Iustin Pop
    else:
973 a8083063 Iustin Pop
      if not nl:
974 a8083063 Iustin Pop
        f.write("\n")
975 a8083063 Iustin Pop
      f.write(key.rstrip('\r\n'))
976 a8083063 Iustin Pop
      f.write("\n")
977 a8083063 Iustin Pop
      f.flush()
978 a8083063 Iustin Pop
  finally:
979 a8083063 Iustin Pop
    f.close()
980 a8083063 Iustin Pop
981 a8083063 Iustin Pop
982 a8083063 Iustin Pop
def RemoveAuthorizedKey(file_name, key):
983 a8083063 Iustin Pop
  """Removes an SSH public key from an authorized_keys file.
984 a8083063 Iustin Pop

985 58885d79 Iustin Pop
  @type file_name: str
986 58885d79 Iustin Pop
  @param file_name: path to authorized_keys file
987 58885d79 Iustin Pop
  @type key: str
988 58885d79 Iustin Pop
  @param key: string containing key
989 58885d79 Iustin Pop

990 a8083063 Iustin Pop
  """
991 a8083063 Iustin Pop
  key_fields = key.split()
992 a8083063 Iustin Pop
993 a8083063 Iustin Pop
  fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name))
994 a8083063 Iustin Pop
  try:
995 59f82e3f Michael Hanselmann
    out = os.fdopen(fd, 'w')
996 a8083063 Iustin Pop
    try:
997 59f82e3f Michael Hanselmann
      f = open(file_name, 'r')
998 59f82e3f Michael Hanselmann
      try:
999 59f82e3f Michael Hanselmann
        for line in f:
1000 59f82e3f Michael Hanselmann
          # Ignore whitespace changes while comparing lines
1001 59f82e3f Michael Hanselmann
          if line.split() != key_fields:
1002 59f82e3f Michael Hanselmann
            out.write(line)
1003 899d2a81 Michael Hanselmann
1004 899d2a81 Michael Hanselmann
        out.flush()
1005 899d2a81 Michael Hanselmann
        os.rename(tmpname, file_name)
1006 899d2a81 Michael Hanselmann
      finally:
1007 899d2a81 Michael Hanselmann
        f.close()
1008 899d2a81 Michael Hanselmann
    finally:
1009 899d2a81 Michael Hanselmann
      out.close()
1010 899d2a81 Michael Hanselmann
  except:
1011 899d2a81 Michael Hanselmann
    RemoveFile(tmpname)
1012 899d2a81 Michael Hanselmann
    raise
1013 899d2a81 Michael Hanselmann
1014 899d2a81 Michael Hanselmann
1015 9440aeab Michael Hanselmann
def SetEtcHostsEntry(file_name, ip, hostname, aliases):
1016 9440aeab Michael Hanselmann
  """Sets the name of an IP address and hostname in /etc/hosts.
1017 899d2a81 Michael Hanselmann

1018 58885d79 Iustin Pop
  @type file_name: str
1019 58885d79 Iustin Pop
  @param file_name: path to the file to modify (usually C{/etc/hosts})
1020 58885d79 Iustin Pop
  @type ip: str
1021 58885d79 Iustin Pop
  @param ip: the IP address
1022 58885d79 Iustin Pop
  @type hostname: str
1023 58885d79 Iustin Pop
  @param hostname: the hostname to be added
1024 58885d79 Iustin Pop
  @type aliases: list
1025 58885d79 Iustin Pop
  @param aliases: the list of aliases to add for the hostname
1026 58885d79 Iustin Pop

1027 899d2a81 Michael Hanselmann
  """
1028 9b977740 Guido Trotter
  # FIXME: use WriteFile + fn rather than duplicating its efforts
1029 7fbb1f65 Michael Hanselmann
  # Ensure aliases are unique
1030 7fbb1f65 Michael Hanselmann
  aliases = UniqueSequence([hostname] + aliases)[1:]
1031 7fbb1f65 Michael Hanselmann
1032 9440aeab Michael Hanselmann
  fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name))
1033 899d2a81 Michael Hanselmann
  try:
1034 9440aeab Michael Hanselmann
    out = os.fdopen(fd, 'w')
1035 9440aeab Michael Hanselmann
    try:
1036 9440aeab Michael Hanselmann
      f = open(file_name, 'r')
1037 9440aeab Michael Hanselmann
      try:
1038 9440aeab Michael Hanselmann
        for line in f:
1039 9440aeab Michael Hanselmann
          fields = line.split()
1040 7e3dbb94 Iustin Pop
          if fields and not fields[0].startswith('#') and ip == fields[0]:
1041 9440aeab Michael Hanselmann
            continue
1042 9440aeab Michael Hanselmann
          out.write(line)
1043 9440aeab Michael Hanselmann
1044 7e3dbb94 Iustin Pop
        out.write("%s\t%s" % (ip, hostname))
1045 9440aeab Michael Hanselmann
        if aliases:
1046 9440aeab Michael Hanselmann
          out.write(" %s" % ' '.join(aliases))
1047 9440aeab Michael Hanselmann
        out.write('\n')
1048 9440aeab Michael Hanselmann
1049 9440aeab Michael Hanselmann
        out.flush()
1050 2e3e75b7 Michael Hanselmann
        os.fsync(out)
1051 9b977740 Guido Trotter
        os.chmod(tmpname, 0644)
1052 9440aeab Michael Hanselmann
        os.rename(tmpname, file_name)
1053 9440aeab Michael Hanselmann
      finally:
1054 9440aeab Michael Hanselmann
        f.close()
1055 9440aeab Michael Hanselmann
    finally:
1056 9440aeab Michael Hanselmann
      out.close()
1057 9440aeab Michael Hanselmann
  except:
1058 9440aeab Michael Hanselmann
    RemoveFile(tmpname)
1059 9440aeab Michael Hanselmann
    raise
1060 899d2a81 Michael Hanselmann
1061 899d2a81 Michael Hanselmann
1062 d9c02ca6 Michael Hanselmann
def AddHostToEtcHosts(hostname):
1063 d9c02ca6 Michael Hanselmann
  """Wrapper around SetEtcHostsEntry.
1064 d9c02ca6 Michael Hanselmann

1065 58885d79 Iustin Pop
  @type hostname: str
1066 58885d79 Iustin Pop
  @param hostname: a hostname that will be resolved and added to
1067 58885d79 Iustin Pop
      L{constants.ETC_HOSTS}
1068 58885d79 Iustin Pop

1069 d9c02ca6 Michael Hanselmann
  """
1070 d9c02ca6 Michael Hanselmann
  hi = HostInfo(name=hostname)
1071 d9c02ca6 Michael Hanselmann
  SetEtcHostsEntry(constants.ETC_HOSTS, hi.ip, hi.name, [hi.ShortName()])
1072 d9c02ca6 Michael Hanselmann
1073 d9c02ca6 Michael Hanselmann
1074 899d2a81 Michael Hanselmann
def RemoveEtcHostsEntry(file_name, hostname):
1075 3e1cdf9f Michael Hanselmann
  """Removes a hostname from /etc/hosts.
1076 899d2a81 Michael Hanselmann

1077 9440aeab Michael Hanselmann
  IP addresses without names are removed from the file.
1078 58885d79 Iustin Pop

1079 58885d79 Iustin Pop
  @type file_name: str
1080 58885d79 Iustin Pop
  @param file_name: path to the file to modify (usually C{/etc/hosts})
1081 58885d79 Iustin Pop
  @type hostname: str
1082 58885d79 Iustin Pop
  @param hostname: the hostname to be removed
1083 58885d79 Iustin Pop

1084 899d2a81 Michael Hanselmann
  """
1085 9b977740 Guido Trotter
  # FIXME: use WriteFile + fn rather than duplicating its efforts
1086 899d2a81 Michael Hanselmann
  fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name))
1087 899d2a81 Michael Hanselmann
  try:
1088 899d2a81 Michael Hanselmann
    out = os.fdopen(fd, 'w')
1089 899d2a81 Michael Hanselmann
    try:
1090 899d2a81 Michael Hanselmann
      f = open(file_name, 'r')
1091 899d2a81 Michael Hanselmann
      try:
1092 899d2a81 Michael Hanselmann
        for line in f:
1093 899d2a81 Michael Hanselmann
          fields = line.split()
1094 899d2a81 Michael Hanselmann
          if len(fields) > 1 and not fields[0].startswith('#'):
1095 899d2a81 Michael Hanselmann
            names = fields[1:]
1096 899d2a81 Michael Hanselmann
            if hostname in names:
1097 899d2a81 Michael Hanselmann
              while hostname in names:
1098 899d2a81 Michael Hanselmann
                names.remove(hostname)
1099 899d2a81 Michael Hanselmann
              if names:
1100 9440aeab Michael Hanselmann
                out.write("%s %s\n" % (fields[0], ' '.join(names)))
1101 899d2a81 Michael Hanselmann
              continue
1102 899d2a81 Michael Hanselmann
1103 899d2a81 Michael Hanselmann
          out.write(line)
1104 59f82e3f Michael Hanselmann
1105 59f82e3f Michael Hanselmann
        out.flush()
1106 2e3e75b7 Michael Hanselmann
        os.fsync(out)
1107 9b977740 Guido Trotter
        os.chmod(tmpname, 0644)
1108 59f82e3f Michael Hanselmann
        os.rename(tmpname, file_name)
1109 59f82e3f Michael Hanselmann
      finally:
1110 59f82e3f Michael Hanselmann
        f.close()
1111 a8083063 Iustin Pop
    finally:
1112 59f82e3f Michael Hanselmann
      out.close()
1113 59f82e3f Michael Hanselmann
  except:
1114 59f82e3f Michael Hanselmann
    RemoveFile(tmpname)
1115 59f82e3f Michael Hanselmann
    raise
1116 a8083063 Iustin Pop
1117 a8083063 Iustin Pop
1118 d9c02ca6 Michael Hanselmann
def RemoveHostFromEtcHosts(hostname):
1119 d9c02ca6 Michael Hanselmann
  """Wrapper around RemoveEtcHostsEntry.
1120 d9c02ca6 Michael Hanselmann

1121 58885d79 Iustin Pop
  @type hostname: str
1122 58885d79 Iustin Pop
  @param hostname: hostname that will be resolved and its
1123 58885d79 Iustin Pop
      full and shot name will be removed from
1124 58885d79 Iustin Pop
      L{constants.ETC_HOSTS}
1125 58885d79 Iustin Pop

1126 d9c02ca6 Michael Hanselmann
  """
1127 d9c02ca6 Michael Hanselmann
  hi = HostInfo(name=hostname)
1128 d9c02ca6 Michael Hanselmann
  RemoveEtcHostsEntry(constants.ETC_HOSTS, hi.name)
1129 d9c02ca6 Michael Hanselmann
  RemoveEtcHostsEntry(constants.ETC_HOSTS, hi.ShortName())
1130 d9c02ca6 Michael Hanselmann
1131 d9c02ca6 Michael Hanselmann
1132 1d466a4f Michael Hanselmann
def TimestampForFilename():
1133 1d466a4f Michael Hanselmann
  """Returns the current time formatted for filenames.
1134 1d466a4f Michael Hanselmann

1135 1d466a4f Michael Hanselmann
  The format doesn't contain colons as some shells and applications them as
1136 1d466a4f Michael Hanselmann
  separators.
1137 1d466a4f Michael Hanselmann

1138 1d466a4f Michael Hanselmann
  """
1139 1d466a4f Michael Hanselmann
  return time.strftime("%Y-%m-%d_%H_%M_%S")
1140 1d466a4f Michael Hanselmann
1141 1d466a4f Michael Hanselmann
1142 a8083063 Iustin Pop
def CreateBackup(file_name):
1143 a8083063 Iustin Pop
  """Creates a backup of a file.
1144 a8083063 Iustin Pop

1145 58885d79 Iustin Pop
  @type file_name: str
1146 58885d79 Iustin Pop
  @param file_name: file to be backed up
1147 58885d79 Iustin Pop
  @rtype: str
1148 58885d79 Iustin Pop
  @return: the path to the newly created backup
1149 58885d79 Iustin Pop
  @raise errors.ProgrammerError: for invalid file names
1150 a8083063 Iustin Pop

1151 a8083063 Iustin Pop
  """
1152 a8083063 Iustin Pop
  if not os.path.isfile(file_name):
1153 3ecf6786 Iustin Pop
    raise errors.ProgrammerError("Can't make a backup of a non-file '%s'" %
1154 3ecf6786 Iustin Pop
                                file_name)
1155 a8083063 Iustin Pop
1156 1d466a4f Michael Hanselmann
  prefix = ("%s.backup-%s." %
1157 1d466a4f Michael Hanselmann
            (os.path.basename(file_name), TimestampForFilename()))
1158 65fe4693 Iustin Pop
  dir_name = os.path.dirname(file_name)
1159 081b1e69 Michael Hanselmann
1160 081b1e69 Michael Hanselmann
  fsrc = open(file_name, 'rb')
1161 081b1e69 Michael Hanselmann
  try:
1162 65fe4693 Iustin Pop
    (fd, backup_name) = tempfile.mkstemp(prefix=prefix, dir=dir_name)
1163 081b1e69 Michael Hanselmann
    fdst = os.fdopen(fd, 'wb')
1164 081b1e69 Michael Hanselmann
    try:
1165 1d466a4f Michael Hanselmann
      logging.debug("Backing up %s at %s", file_name, backup_name)
1166 081b1e69 Michael Hanselmann
      shutil.copyfileobj(fsrc, fdst)
1167 081b1e69 Michael Hanselmann
    finally:
1168 081b1e69 Michael Hanselmann
      fdst.close()
1169 081b1e69 Michael Hanselmann
  finally:
1170 081b1e69 Michael Hanselmann
    fsrc.close()
1171 081b1e69 Michael Hanselmann
1172 a8083063 Iustin Pop
  return backup_name
1173 a8083063 Iustin Pop
1174 a8083063 Iustin Pop
1175 a8083063 Iustin Pop
def ShellQuote(value):
1176 a8083063 Iustin Pop
  """Quotes shell argument according to POSIX.
1177 3ecf6786 Iustin Pop

1178 58885d79 Iustin Pop
  @type value: str
1179 58885d79 Iustin Pop
  @param value: the argument to be quoted
1180 58885d79 Iustin Pop
  @rtype: str
1181 58885d79 Iustin Pop
  @return: the quoted value
1182 58885d79 Iustin Pop

1183 a8083063 Iustin Pop
  """
1184 a8083063 Iustin Pop
  if _re_shell_unquoted.match(value):
1185 a8083063 Iustin Pop
    return value
1186 a8083063 Iustin Pop
  else:
1187 a8083063 Iustin Pop
    return "'%s'" % value.replace("'", "'\\''")
1188 a8083063 Iustin Pop
1189 a8083063 Iustin Pop
1190 a8083063 Iustin Pop
def ShellQuoteArgs(args):
1191 58885d79 Iustin Pop
  """Quotes a list of shell arguments.
1192 58885d79 Iustin Pop

1193 58885d79 Iustin Pop
  @type args: list
1194 58885d79 Iustin Pop
  @param args: list of arguments to be quoted
1195 58885d79 Iustin Pop
  @rtype: str
1196 5bbd3f7f Michael Hanselmann
  @return: the quoted arguments concatenated with spaces
1197 a8083063 Iustin Pop

1198 a8083063 Iustin Pop
  """
1199 a8083063 Iustin Pop
  return ' '.join([ShellQuote(i) for i in args])
1200 88d14415 Michael Hanselmann
1201 88d14415 Michael Hanselmann
1202 b15d625f Iustin Pop
def TcpPing(target, port, timeout=10, live_port_needed=False, source=None):
1203 2c30e9d7 Alexander Schreiber
  """Simple ping implementation using TCP connect(2).
1204 2c30e9d7 Alexander Schreiber

1205 58885d79 Iustin Pop
  Check if the given IP is reachable by doing attempting a TCP connect
1206 58885d79 Iustin Pop
  to it.
1207 58885d79 Iustin Pop

1208 58885d79 Iustin Pop
  @type target: str
1209 58885d79 Iustin Pop
  @param target: the IP or hostname to ping
1210 58885d79 Iustin Pop
  @type port: int
1211 58885d79 Iustin Pop
  @param port: the port to connect to
1212 58885d79 Iustin Pop
  @type timeout: int
1213 5bbd3f7f Michael Hanselmann
  @param timeout: the timeout on the connection attempt
1214 58885d79 Iustin Pop
  @type live_port_needed: boolean
1215 58885d79 Iustin Pop
  @param live_port_needed: whether a closed port will cause the
1216 58885d79 Iustin Pop
      function to return failure, as if there was a timeout
1217 58885d79 Iustin Pop
  @type source: str or None
1218 58885d79 Iustin Pop
  @param source: if specified, will cause the connect to be made
1219 58885d79 Iustin Pop
      from this specific source address; failures to bind other
1220 58885d79 Iustin Pop
      than C{EADDRNOTAVAIL} will be ignored
1221 2c30e9d7 Alexander Schreiber

1222 2c30e9d7 Alexander Schreiber
  """
1223 2c30e9d7 Alexander Schreiber
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1224 2c30e9d7 Alexander Schreiber
1225 0b5ad33e Iustin Pop
  success = False
1226 2c30e9d7 Alexander Schreiber
1227 b15d625f Iustin Pop
  if source is not None:
1228 b15d625f Iustin Pop
    try:
1229 b15d625f Iustin Pop
      sock.bind((source, 0))
1230 7c4d6c7b Michael Hanselmann
    except socket.error, (errcode, _):
1231 b15d625f Iustin Pop
      if errcode == errno.EADDRNOTAVAIL:
1232 b15d625f Iustin Pop
        success = False
1233 2c30e9d7 Alexander Schreiber
1234 2c30e9d7 Alexander Schreiber
  sock.settimeout(timeout)
1235 2c30e9d7 Alexander Schreiber
1236 2c30e9d7 Alexander Schreiber
  try:
1237 2c30e9d7 Alexander Schreiber
    sock.connect((target, port))
1238 2c30e9d7 Alexander Schreiber
    sock.close()
1239 2c30e9d7 Alexander Schreiber
    success = True
1240 2c30e9d7 Alexander Schreiber
  except socket.timeout:
1241 2c30e9d7 Alexander Schreiber
    success = False
1242 099c52ad Iustin Pop
  except socket.error, (errcode, _):
1243 4ca1b175 Alexander Schreiber
    success = (not live_port_needed) and (errcode == errno.ECONNREFUSED)
1244 2c30e9d7 Alexander Schreiber
1245 2c30e9d7 Alexander Schreiber
  return success
1246 eedbda4b Michael Hanselmann
1247 eedbda4b Michael Hanselmann
1248 caad16e2 Iustin Pop
def OwnIpAddress(address):
1249 caad16e2 Iustin Pop
  """Check if the current host has the the given IP address.
1250 caad16e2 Iustin Pop

1251 58885d79 Iustin Pop
  Currently this is done by TCP-pinging the address from the loopback
1252 caad16e2 Iustin Pop
  address.
1253 caad16e2 Iustin Pop

1254 caad16e2 Iustin Pop
  @type address: string
1255 5bbd3f7f Michael Hanselmann
  @param address: the address to check
1256 caad16e2 Iustin Pop
  @rtype: bool
1257 58885d79 Iustin Pop
  @return: True if we own the address
1258 caad16e2 Iustin Pop

1259 caad16e2 Iustin Pop
  """
1260 caad16e2 Iustin Pop
  return TcpPing(address, constants.DEFAULT_NODED_PORT,
1261 caad16e2 Iustin Pop
                 source=constants.LOCALHOST_IP_ADDRESS)
1262 caad16e2 Iustin Pop
1263 caad16e2 Iustin Pop
1264 eedbda4b Michael Hanselmann
def ListVisibleFiles(path):
1265 58885d79 Iustin Pop
  """Returns a list of visible files in a directory.
1266 58885d79 Iustin Pop

1267 58885d79 Iustin Pop
  @type path: str
1268 58885d79 Iustin Pop
  @param path: the directory to enumerate
1269 58885d79 Iustin Pop
  @rtype: list
1270 58885d79 Iustin Pop
  @return: the list of all files not starting with a dot
1271 04a69a18 Iustin Pop
  @raise ProgrammerError: if L{path} is not an absolue and normalized path
1272 eedbda4b Michael Hanselmann

1273 eedbda4b Michael Hanselmann
  """
1274 04a69a18 Iustin Pop
  if not IsNormAbsPath(path):
1275 04a69a18 Iustin Pop
    raise errors.ProgrammerError("Path passed to ListVisibleFiles is not"
1276 04a69a18 Iustin Pop
                                 " absolute/normalized: '%s'" % path)
1277 f3299a07 Michael Hanselmann
  files = [i for i in os.listdir(path) if not i.startswith(".")]
1278 f3299a07 Michael Hanselmann
  files.sort()
1279 f3299a07 Michael Hanselmann
  return files
1280 2f8b60b3 Iustin Pop
1281 2f8b60b3 Iustin Pop
1282 257f4c0a Iustin Pop
def GetHomeDir(user, default=None):
1283 257f4c0a Iustin Pop
  """Try to get the homedir of the given user.
1284 257f4c0a Iustin Pop

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

1289 2f8b60b3 Iustin Pop
  """
1290 2f8b60b3 Iustin Pop
  try:
1291 257f4c0a Iustin Pop
    if isinstance(user, basestring):
1292 257f4c0a Iustin Pop
      result = pwd.getpwnam(user)
1293 257f4c0a Iustin Pop
    elif isinstance(user, (int, long)):
1294 257f4c0a Iustin Pop
      result = pwd.getpwuid(user)
1295 257f4c0a Iustin Pop
    else:
1296 257f4c0a Iustin Pop
      raise errors.ProgrammerError("Invalid type passed to GetHomeDir (%s)" %
1297 257f4c0a Iustin Pop
                                   type(user))
1298 2f8b60b3 Iustin Pop
  except KeyError:
1299 2f8b60b3 Iustin Pop
    return default
1300 2f8b60b3 Iustin Pop
  return result.pw_dir
1301 59072e7e Michael Hanselmann
1302 59072e7e Michael Hanselmann
1303 24818e8f Michael Hanselmann
def NewUUID():
1304 59072e7e Michael Hanselmann
  """Returns a random UUID.
1305 59072e7e Michael Hanselmann

1306 58885d79 Iustin Pop
  @note: This is a Linux-specific method as it uses the /proc
1307 58885d79 Iustin Pop
      filesystem.
1308 58885d79 Iustin Pop
  @rtype: str
1309 58885d79 Iustin Pop

1310 59072e7e Michael Hanselmann
  """
1311 13998ef2 Michael Hanselmann
  return ReadFile(_RANDOM_UUID_FILE, size=128).rstrip("\n")
1312 087b34fe Iustin Pop
1313 087b34fe Iustin Pop
1314 ec2c2bc4 Luca Bigliardi
def GenerateSecret(numbytes=20):
1315 33081d90 Iustin Pop
  """Generates a random secret.
1316 33081d90 Iustin Pop

1317 ec2c2bc4 Luca Bigliardi
  This will generate a pseudo-random secret returning an hex string
1318 33081d90 Iustin Pop
  (so that it can be used where an ASCII string is needed).
1319 33081d90 Iustin Pop

1320 ec2c2bc4 Luca Bigliardi
  @param numbytes: the number of bytes which will be represented by the returned
1321 ec2c2bc4 Luca Bigliardi
      string (defaulting to 20, the length of a SHA1 hash)
1322 58885d79 Iustin Pop
  @rtype: str
1323 ec2c2bc4 Luca Bigliardi
  @return: an hex representation of the pseudo-random sequence
1324 58885d79 Iustin Pop

1325 33081d90 Iustin Pop
  """
1326 ec2c2bc4 Luca Bigliardi
  return os.urandom(numbytes).encode('hex')
1327 33081d90 Iustin Pop
1328 33081d90 Iustin Pop
1329 9dae41ad Guido Trotter
def EnsureDirs(dirs):
1330 9dae41ad Guido Trotter
  """Make required directories, if they don't exist.
1331 9dae41ad Guido Trotter

1332 9dae41ad Guido Trotter
  @param dirs: list of tuples (dir_name, dir_mode)
1333 9dae41ad Guido Trotter
  @type dirs: list of (string, integer)
1334 9dae41ad Guido Trotter

1335 9dae41ad Guido Trotter
  """
1336 9dae41ad Guido Trotter
  for dir_name, dir_mode in dirs:
1337 9dae41ad Guido Trotter
    try:
1338 1b2c8f85 Iustin Pop
      os.mkdir(dir_name, dir_mode)
1339 9dae41ad Guido Trotter
    except EnvironmentError, err:
1340 9dae41ad Guido Trotter
      if err.errno != errno.EEXIST:
1341 9dae41ad Guido Trotter
        raise errors.GenericError("Cannot create needed directory"
1342 1b2c8f85 Iustin Pop
                                  " '%s': %s" % (dir_name, err))
1343 9dae41ad Guido Trotter
    if not os.path.isdir(dir_name):
1344 9dae41ad Guido Trotter
      raise errors.GenericError("%s is not a directory" % dir_name)
1345 9dae41ad Guido Trotter
1346 9dae41ad Guido Trotter
1347 016308cb Iustin Pop
def ReadFile(file_name, size=-1):
1348 ca0aa6d0 Michael Hanselmann
  """Reads a file.
1349 ca0aa6d0 Michael Hanselmann

1350 016308cb Iustin Pop
  @type size: int
1351 016308cb Iustin Pop
  @param size: Read at most size bytes (if negative, entire file)
1352 58885d79 Iustin Pop
  @rtype: str
1353 5bbd3f7f Michael Hanselmann
  @return: the (possibly partial) content of the file
1354 ca0aa6d0 Michael Hanselmann

1355 ca0aa6d0 Michael Hanselmann
  """
1356 ca0aa6d0 Michael Hanselmann
  f = open(file_name, "r")
1357 ca0aa6d0 Michael Hanselmann
  try:
1358 016308cb Iustin Pop
    return f.read(size)
1359 ca0aa6d0 Michael Hanselmann
  finally:
1360 ca0aa6d0 Michael Hanselmann
    f.close()
1361 ca0aa6d0 Michael Hanselmann
1362 ca0aa6d0 Michael Hanselmann
1363 087b34fe Iustin Pop
def WriteFile(file_name, fn=None, data=None,
1364 087b34fe Iustin Pop
              mode=None, uid=-1, gid=-1,
1365 71714516 Michael Hanselmann
              atime=None, mtime=None, close=True,
1366 04a8d789 Michael Hanselmann
              dry_run=False, backup=False,
1367 71714516 Michael Hanselmann
              prewrite=None, postwrite=None):
1368 087b34fe Iustin Pop
  """(Over)write a file atomically.
1369 087b34fe Iustin Pop

1370 087b34fe Iustin Pop
  The file_name and either fn (a function taking one argument, the
1371 087b34fe Iustin Pop
  file descriptor, and which should write the data to it) or data (the
1372 087b34fe Iustin Pop
  contents of the file) must be passed. The other arguments are
1373 087b34fe Iustin Pop
  optional and allow setting the file mode, owner and group, and the
1374 087b34fe Iustin Pop
  mtime/atime of the file.
1375 087b34fe Iustin Pop

1376 087b34fe Iustin Pop
  If the function doesn't raise an exception, it has succeeded and the
1377 69efe319 Michael Hanselmann
  target file has the new contents. If the function has raised an
1378 087b34fe Iustin Pop
  exception, an existing target file should be unmodified and the
1379 087b34fe Iustin Pop
  temporary file should be removed.
1380 087b34fe Iustin Pop

1381 58885d79 Iustin Pop
  @type file_name: str
1382 58885d79 Iustin Pop
  @param file_name: the target filename
1383 58885d79 Iustin Pop
  @type fn: callable
1384 58885d79 Iustin Pop
  @param fn: content writing function, called with
1385 58885d79 Iustin Pop
      file descriptor as parameter
1386 69efe319 Michael Hanselmann
  @type data: str
1387 58885d79 Iustin Pop
  @param data: contents of the file
1388 58885d79 Iustin Pop
  @type mode: int
1389 58885d79 Iustin Pop
  @param mode: file mode
1390 58885d79 Iustin Pop
  @type uid: int
1391 58885d79 Iustin Pop
  @param uid: the owner of the file
1392 58885d79 Iustin Pop
  @type gid: int
1393 58885d79 Iustin Pop
  @param gid: the group of the file
1394 58885d79 Iustin Pop
  @type atime: int
1395 58885d79 Iustin Pop
  @param atime: a custom access time to be set on the file
1396 58885d79 Iustin Pop
  @type mtime: int
1397 58885d79 Iustin Pop
  @param mtime: a custom modification time to be set on the file
1398 58885d79 Iustin Pop
  @type close: boolean
1399 58885d79 Iustin Pop
  @param close: whether to close file after writing it
1400 58885d79 Iustin Pop
  @type prewrite: callable
1401 58885d79 Iustin Pop
  @param prewrite: function to be called before writing content
1402 58885d79 Iustin Pop
  @type postwrite: callable
1403 58885d79 Iustin Pop
  @param postwrite: function to be called after writing content
1404 58885d79 Iustin Pop

1405 58885d79 Iustin Pop
  @rtype: None or int
1406 58885d79 Iustin Pop
  @return: None if the 'close' parameter evaluates to True,
1407 58885d79 Iustin Pop
      otherwise the file descriptor
1408 58885d79 Iustin Pop

1409 69efe319 Michael Hanselmann
  @raise errors.ProgrammerError: if any of the arguments are not valid
1410 71714516 Michael Hanselmann

1411 087b34fe Iustin Pop
  """
1412 04a8d789 Michael Hanselmann
  if not os.path.isabs(file_name):
1413 087b34fe Iustin Pop
    raise errors.ProgrammerError("Path passed to WriteFile is not"
1414 087b34fe Iustin Pop
                                 " absolute: '%s'" % file_name)
1415 087b34fe Iustin Pop
1416 087b34fe Iustin Pop
  if [fn, data].count(None) != 1:
1417 087b34fe Iustin Pop
    raise errors.ProgrammerError("fn or data required")
1418 087b34fe Iustin Pop
1419 087b34fe Iustin Pop
  if [atime, mtime].count(None) == 1:
1420 087b34fe Iustin Pop
    raise errors.ProgrammerError("Both atime and mtime must be either"
1421 087b34fe Iustin Pop
                                 " set or None")
1422 087b34fe Iustin Pop
1423 70f4497c Michael Hanselmann
  if backup and not dry_run and os.path.isfile(file_name):
1424 70f4497c Michael Hanselmann
    CreateBackup(file_name)
1425 087b34fe Iustin Pop
1426 087b34fe Iustin Pop
  dir_name, base_name = os.path.split(file_name)
1427 087b34fe Iustin Pop
  fd, new_name = tempfile.mkstemp('.new', base_name, dir_name)
1428 81b7354c Iustin Pop
  do_remove = True
1429 087b34fe Iustin Pop
  # here we need to make sure we remove the temp file, if any error
1430 087b34fe Iustin Pop
  # leaves it in place
1431 087b34fe Iustin Pop
  try:
1432 087b34fe Iustin Pop
    if uid != -1 or gid != -1:
1433 087b34fe Iustin Pop
      os.chown(new_name, uid, gid)
1434 087b34fe Iustin Pop
    if mode:
1435 087b34fe Iustin Pop
      os.chmod(new_name, mode)
1436 71714516 Michael Hanselmann
    if callable(prewrite):
1437 71714516 Michael Hanselmann
      prewrite(fd)
1438 087b34fe Iustin Pop
    if data is not None:
1439 087b34fe Iustin Pop
      os.write(fd, data)
1440 087b34fe Iustin Pop
    else:
1441 087b34fe Iustin Pop
      fn(fd)
1442 71714516 Michael Hanselmann
    if callable(postwrite):
1443 71714516 Michael Hanselmann
      postwrite(fd)
1444 087b34fe Iustin Pop
    os.fsync(fd)
1445 087b34fe Iustin Pop
    if atime is not None and mtime is not None:
1446 087b34fe Iustin Pop
      os.utime(new_name, (atime, mtime))
1447 70f4497c Michael Hanselmann
    if not dry_run:
1448 70f4497c Michael Hanselmann
      os.rename(new_name, file_name)
1449 81b7354c Iustin Pop
      do_remove = False
1450 087b34fe Iustin Pop
  finally:
1451 71714516 Michael Hanselmann
    if close:
1452 71714516 Michael Hanselmann
      os.close(fd)
1453 71714516 Michael Hanselmann
      result = None
1454 71714516 Michael Hanselmann
    else:
1455 71714516 Michael Hanselmann
      result = fd
1456 81b7354c Iustin Pop
    if do_remove:
1457 81b7354c Iustin Pop
      RemoveFile(new_name)
1458 78feb6fb Guido Trotter
1459 71714516 Michael Hanselmann
  return result
1460 71714516 Michael Hanselmann
1461 78feb6fb Guido Trotter
1462 7b4126b7 Iustin Pop
def FirstFree(seq, base=0):
1463 7b4126b7 Iustin Pop
  """Returns the first non-existing integer from seq.
1464 7b4126b7 Iustin Pop

1465 7b4126b7 Iustin Pop
  The seq argument should be a sorted list of positive integers. The
1466 7b4126b7 Iustin Pop
  first time the index of an element is smaller than the element
1467 7b4126b7 Iustin Pop
  value, the index will be returned.
1468 7b4126b7 Iustin Pop

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

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

1474 58885d79 Iustin Pop
  @type seq: sequence
1475 58885d79 Iustin Pop
  @param seq: the sequence to be analyzed.
1476 58885d79 Iustin Pop
  @type base: int
1477 58885d79 Iustin Pop
  @param base: use this value as the base index of the sequence
1478 58885d79 Iustin Pop
  @rtype: int
1479 58885d79 Iustin Pop
  @return: the first non-used index in the sequence
1480 7b4126b7 Iustin Pop

1481 7b4126b7 Iustin Pop
  """
1482 7b4126b7 Iustin Pop
  for idx, elem in enumerate(seq):
1483 7b4126b7 Iustin Pop
    assert elem >= base, "Passed element is higher than base offset"
1484 7b4126b7 Iustin Pop
    if elem > idx + base:
1485 7b4126b7 Iustin Pop
      # idx is not used
1486 7b4126b7 Iustin Pop
      return idx + base
1487 7b4126b7 Iustin Pop
  return None
1488 7b4126b7 Iustin Pop
1489 7b4126b7 Iustin Pop
1490 284c69f0 Guido Trotter
def all(seq, pred=bool): # pylint: disable-msg=W0622
1491 284c69f0 Guido Trotter
  "Returns True if pred(x) is True for every element in the iterable"
1492 284c69f0 Guido Trotter
  for _ in itertools.ifilterfalse(pred, seq):
1493 284c69f0 Guido Trotter
    return False
1494 284c69f0 Guido Trotter
  return True
1495 78feb6fb Guido Trotter
1496 78feb6fb Guido Trotter
1497 284c69f0 Guido Trotter
def any(seq, pred=bool): # pylint: disable-msg=W0622
1498 284c69f0 Guido Trotter
  "Returns True if pred(x) is True for at least one element in the iterable"
1499 284c69f0 Guido Trotter
  for _ in itertools.ifilter(pred, seq):
1500 284c69f0 Guido Trotter
    return True
1501 284c69f0 Guido Trotter
  return False
1502 f7414041 Michael Hanselmann
1503 f7414041 Michael Hanselmann
1504 dfdc4060 Guido Trotter
def SingleWaitForFdCondition(fdobj, event, timeout):
1505 dcd511c8 Guido Trotter
  """Waits for a condition to occur on the socket.
1506 dcd511c8 Guido Trotter

1507 dfdc4060 Guido Trotter
  Immediately returns at the first interruption.
1508 dfdc4060 Guido Trotter

1509 dfdc4060 Guido Trotter
  @type fdobj: integer or object supporting a fileno() method
1510 dfdc4060 Guido Trotter
  @param fdobj: entity to wait for events on
1511 dfdc4060 Guido Trotter
  @type event: integer
1512 dcd511c8 Guido Trotter
  @param event: ORed condition (see select module)
1513 dcd511c8 Guido Trotter
  @type timeout: float or None
1514 dcd511c8 Guido Trotter
  @param timeout: Timeout in seconds
1515 dcd511c8 Guido Trotter
  @rtype: int or None
1516 dcd511c8 Guido Trotter
  @return: None for timeout, otherwise occured conditions
1517 dcd511c8 Guido Trotter

1518 dcd511c8 Guido Trotter
  """
1519 dcd511c8 Guido Trotter
  check = (event | select.POLLPRI |
1520 dcd511c8 Guido Trotter
           select.POLLNVAL | select.POLLHUP | select.POLLERR)
1521 dcd511c8 Guido Trotter
1522 dcd511c8 Guido Trotter
  if timeout is not None:
1523 dcd511c8 Guido Trotter
    # Poller object expects milliseconds
1524 dcd511c8 Guido Trotter
    timeout *= 1000
1525 dcd511c8 Guido Trotter
1526 dcd511c8 Guido Trotter
  poller = select.poll()
1527 dfdc4060 Guido Trotter
  poller.register(fdobj, event)
1528 dcd511c8 Guido Trotter
  try:
1529 dfdc4060 Guido Trotter
    # TODO: If the main thread receives a signal and we have no timeout, we
1530 dfdc4060 Guido Trotter
    # could wait forever. This should check a global "quit" flag or something
1531 dfdc4060 Guido Trotter
    # every so often.
1532 dfdc4060 Guido Trotter
    io_events = poller.poll(timeout)
1533 dfdc4060 Guido Trotter
  except select.error, err:
1534 dfdc4060 Guido Trotter
    if err[0] != errno.EINTR:
1535 dfdc4060 Guido Trotter
      raise
1536 dfdc4060 Guido Trotter
    io_events = []
1537 dfdc4060 Guido Trotter
  if io_events and io_events[0][1] & check:
1538 dfdc4060 Guido Trotter
    return io_events[0][1]
1539 dfdc4060 Guido Trotter
  else:
1540 dfdc4060 Guido Trotter
    return None
1541 dfdc4060 Guido Trotter
1542 dfdc4060 Guido Trotter
1543 dfdc4060 Guido Trotter
class FdConditionWaiterHelper(object):
1544 dfdc4060 Guido Trotter
  """Retry helper for WaitForFdCondition.
1545 dfdc4060 Guido Trotter

1546 dfdc4060 Guido Trotter
  This class contains the retried and wait functions that make sure
1547 dfdc4060 Guido Trotter
  WaitForFdCondition can continue waiting until the timeout is actually
1548 dfdc4060 Guido Trotter
  expired.
1549 dfdc4060 Guido Trotter

1550 dfdc4060 Guido Trotter
  """
1551 dfdc4060 Guido Trotter
1552 dfdc4060 Guido Trotter
  def __init__(self, timeout):
1553 dfdc4060 Guido Trotter
    self.timeout = timeout
1554 dfdc4060 Guido Trotter
1555 dfdc4060 Guido Trotter
  def Poll(self, fdobj, event):
1556 dfdc4060 Guido Trotter
    result = SingleWaitForFdCondition(fdobj, event, self.timeout)
1557 dfdc4060 Guido Trotter
    if result is None:
1558 dfdc4060 Guido Trotter
      raise RetryAgain()
1559 dfdc4060 Guido Trotter
    else:
1560 dfdc4060 Guido Trotter
      return result
1561 dfdc4060 Guido Trotter
1562 dfdc4060 Guido Trotter
  def UpdateTimeout(self, timeout):
1563 dfdc4060 Guido Trotter
    self.timeout = timeout
1564 dfdc4060 Guido Trotter
1565 dfdc4060 Guido Trotter
1566 dfdc4060 Guido Trotter
def WaitForFdCondition(fdobj, event, timeout):
1567 dfdc4060 Guido Trotter
  """Waits for a condition to occur on the socket.
1568 dfdc4060 Guido Trotter

1569 dfdc4060 Guido Trotter
  Retries until the timeout is expired, even if interrupted.
1570 dfdc4060 Guido Trotter

1571 dfdc4060 Guido Trotter
  @type fdobj: integer or object supporting a fileno() method
1572 dfdc4060 Guido Trotter
  @param fdobj: entity to wait for events on
1573 dfdc4060 Guido Trotter
  @type event: integer
1574 dfdc4060 Guido Trotter
  @param event: ORed condition (see select module)
1575 dfdc4060 Guido Trotter
  @type timeout: float or None
1576 dfdc4060 Guido Trotter
  @param timeout: Timeout in seconds
1577 dfdc4060 Guido Trotter
  @rtype: int or None
1578 dfdc4060 Guido Trotter
  @return: None for timeout, otherwise occured conditions
1579 dfdc4060 Guido Trotter

1580 dfdc4060 Guido Trotter
  """
1581 dfdc4060 Guido Trotter
  if timeout is not None:
1582 dfdc4060 Guido Trotter
    retrywaiter = FdConditionWaiterHelper(timeout)
1583 1b429e2a Iustin Pop
    try:
1584 1b429e2a Iustin Pop
      result = Retry(retrywaiter.Poll, RETRY_REMAINING_TIME, timeout,
1585 1b429e2a Iustin Pop
                     args=(fdobj, event), wait_fn=retrywaiter.UpdateTimeout)
1586 1b429e2a Iustin Pop
    except RetryTimeout:
1587 1b429e2a Iustin Pop
      result = None
1588 dfdc4060 Guido Trotter
  else:
1589 dfdc4060 Guido Trotter
    result = None
1590 dfdc4060 Guido Trotter
    while result is None:
1591 dfdc4060 Guido Trotter
      result = SingleWaitForFdCondition(fdobj, event, timeout)
1592 dfdc4060 Guido Trotter
  return result
1593 dcd511c8 Guido Trotter
1594 dcd511c8 Guido Trotter
1595 2de64672 Iustin Pop
def partition(seq, pred=bool): # # pylint: disable-msg=W0622
1596 2de64672 Iustin Pop
  "Partition a list in two, based on the given predicate"
1597 2de64672 Iustin Pop
  return (list(itertools.ifilter(pred, seq)),
1598 2de64672 Iustin Pop
          list(itertools.ifilterfalse(pred, seq)))
1599 2de64672 Iustin Pop
1600 2de64672 Iustin Pop
1601 f7414041 Michael Hanselmann
def UniqueSequence(seq):
1602 f7414041 Michael Hanselmann
  """Returns a list with unique elements.
1603 f7414041 Michael Hanselmann

1604 f7414041 Michael Hanselmann
  Element order is preserved.
1605 58885d79 Iustin Pop

1606 58885d79 Iustin Pop
  @type seq: sequence
1607 5bbd3f7f Michael Hanselmann
  @param seq: the sequence with the source elements
1608 58885d79 Iustin Pop
  @rtype: list
1609 58885d79 Iustin Pop
  @return: list of unique elements from seq
1610 58885d79 Iustin Pop

1611 f7414041 Michael Hanselmann
  """
1612 f7414041 Michael Hanselmann
  seen = set()
1613 f7414041 Michael Hanselmann
  return [i for i in seq if i not in seen and not seen.add(i)]
1614 1862d460 Alexander Schreiber
1615 1862d460 Alexander Schreiber
1616 82187135 René Nussbaumer
def NormalizeAndValidateMac(mac):
1617 82187135 René Nussbaumer
  """Normalizes and check if a MAC address is valid.
1618 1862d460 Alexander Schreiber

1619 5bbd3f7f Michael Hanselmann
  Checks whether the supplied MAC address is formally correct, only
1620 82187135 René Nussbaumer
  accepts colon separated format. Normalize it to all lower.
1621 58885d79 Iustin Pop

1622 58885d79 Iustin Pop
  @type mac: str
1623 58885d79 Iustin Pop
  @param mac: the MAC to be validated
1624 82187135 René Nussbaumer
  @rtype: str
1625 82187135 René Nussbaumer
  @return: returns the normalized and validated MAC.
1626 82187135 René Nussbaumer

1627 82187135 René Nussbaumer
  @raise errors.OpPrereqError: If the MAC isn't valid
1628 58885d79 Iustin Pop

1629 1862d460 Alexander Schreiber
  """
1630 82187135 René Nussbaumer
  mac_check = re.compile("^([0-9a-f]{2}(:|$)){6}$", re.I)
1631 82187135 René Nussbaumer
  if not mac_check.match(mac):
1632 82187135 René Nussbaumer
    raise errors.OpPrereqError("Invalid MAC address specified: %s" %
1633 82187135 René Nussbaumer
                               mac, errors.ECODE_INVAL)
1634 82187135 René Nussbaumer
1635 82187135 René Nussbaumer
  return mac.lower()
1636 06009e27 Iustin Pop
1637 06009e27 Iustin Pop
1638 06009e27 Iustin Pop
def TestDelay(duration):
1639 06009e27 Iustin Pop
  """Sleep for a fixed amount of time.
1640 06009e27 Iustin Pop

1641 58885d79 Iustin Pop
  @type duration: float
1642 58885d79 Iustin Pop
  @param duration: the sleep duration
1643 58885d79 Iustin Pop
  @rtype: boolean
1644 58885d79 Iustin Pop
  @return: False for negative value, True otherwise
1645 58885d79 Iustin Pop

1646 06009e27 Iustin Pop
  """
1647 06009e27 Iustin Pop
  if duration < 0:
1648 38ea42a1 Iustin Pop
    return False, "Invalid sleep duration"
1649 06009e27 Iustin Pop
  time.sleep(duration)
1650 38ea42a1 Iustin Pop
  return True, None
1651 8f765069 Iustin Pop
1652 8f765069 Iustin Pop
1653 7d88772a Iustin Pop
def _CloseFDNoErr(fd, retries=5):
1654 7d88772a Iustin Pop
  """Close a file descriptor ignoring errors.
1655 8f765069 Iustin Pop

1656 7d88772a Iustin Pop
  @type fd: int
1657 7d88772a Iustin Pop
  @param fd: the file descriptor
1658 7d88772a Iustin Pop
  @type retries: int
1659 7d88772a Iustin Pop
  @param retries: how many retries to make, in case we get any
1660 7d88772a Iustin Pop
      other error than EBADF
1661 7d88772a Iustin Pop

1662 7d88772a Iustin Pop
  """
1663 7d88772a Iustin Pop
  try:
1664 7d88772a Iustin Pop
    os.close(fd)
1665 7d88772a Iustin Pop
  except OSError, err:
1666 7d88772a Iustin Pop
    if err.errno != errno.EBADF:
1667 7d88772a Iustin Pop
      if retries > 0:
1668 7d88772a Iustin Pop
        _CloseFDNoErr(fd, retries - 1)
1669 7d88772a Iustin Pop
    # else either it's closed already or we're out of retries, so we
1670 7d88772a Iustin Pop
    # ignore this and go on
1671 7d88772a Iustin Pop
1672 7d88772a Iustin Pop
1673 7d88772a Iustin Pop
def CloseFDs(noclose_fds=None):
1674 7d88772a Iustin Pop
  """Close file descriptors.
1675 7d88772a Iustin Pop

1676 7d88772a Iustin Pop
  This closes all file descriptors above 2 (i.e. except
1677 7d88772a Iustin Pop
  stdin/out/err).
1678 8f765069 Iustin Pop

1679 58885d79 Iustin Pop
  @type noclose_fds: list or None
1680 58885d79 Iustin Pop
  @param noclose_fds: if given, it denotes a list of file descriptor
1681 58885d79 Iustin Pop
      that should not be closed
1682 58885d79 Iustin Pop

1683 8f765069 Iustin Pop
  """
1684 8f765069 Iustin Pop
  # Default maximum for the number of available file descriptors.
1685 8f765069 Iustin Pop
  if 'SC_OPEN_MAX' in os.sysconf_names:
1686 8f765069 Iustin Pop
    try:
1687 8f765069 Iustin Pop
      MAXFD = os.sysconf('SC_OPEN_MAX')
1688 8f765069 Iustin Pop
      if MAXFD < 0:
1689 8f765069 Iustin Pop
        MAXFD = 1024
1690 8f765069 Iustin Pop
    except OSError:
1691 8f765069 Iustin Pop
      MAXFD = 1024
1692 8f765069 Iustin Pop
  else:
1693 8f765069 Iustin Pop
    MAXFD = 1024
1694 7d88772a Iustin Pop
  maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
1695 7d88772a Iustin Pop
  if (maxfd == resource.RLIM_INFINITY):
1696 7d88772a Iustin Pop
    maxfd = MAXFD
1697 7d88772a Iustin Pop
1698 7d88772a Iustin Pop
  # Iterate through and close all file descriptors (except the standard ones)
1699 7d88772a Iustin Pop
  for fd in range(3, maxfd):
1700 7d88772a Iustin Pop
    if noclose_fds and fd in noclose_fds:
1701 7d88772a Iustin Pop
      continue
1702 7d88772a Iustin Pop
    _CloseFDNoErr(fd)
1703 7d88772a Iustin Pop
1704 7d88772a Iustin Pop
1705 7d88772a Iustin Pop
def Daemonize(logfile):
1706 7d88772a Iustin Pop
  """Daemonize the current process.
1707 7d88772a Iustin Pop

1708 7d88772a Iustin Pop
  This detaches the current process from the controlling terminal and
1709 7d88772a Iustin Pop
  runs it in the background as a daemon.
1710 7d88772a Iustin Pop

1711 7d88772a Iustin Pop
  @type logfile: str
1712 7d88772a Iustin Pop
  @param logfile: the logfile to which we should redirect stdout/stderr
1713 7d88772a Iustin Pop
  @rtype: int
1714 5fcc718f Iustin Pop
  @return: the value zero
1715 7d88772a Iustin Pop

1716 7d88772a Iustin Pop
  """
1717 7260cfbe Iustin Pop
  # pylint: disable-msg=W0212
1718 7260cfbe Iustin Pop
  # yes, we really want os._exit
1719 7d88772a Iustin Pop
  UMASK = 077
1720 7d88772a Iustin Pop
  WORKDIR = "/"
1721 8f765069 Iustin Pop
1722 8f765069 Iustin Pop
  # this might fail
1723 8f765069 Iustin Pop
  pid = os.fork()
1724 8f765069 Iustin Pop
  if (pid == 0):  # The first child.
1725 8f765069 Iustin Pop
    os.setsid()
1726 8f765069 Iustin Pop
    # this might fail
1727 8f765069 Iustin Pop
    pid = os.fork() # Fork a second child.
1728 8f765069 Iustin Pop
    if (pid == 0):  # The second child.
1729 8f765069 Iustin Pop
      os.chdir(WORKDIR)
1730 8f765069 Iustin Pop
      os.umask(UMASK)
1731 8f765069 Iustin Pop
    else:
1732 8f765069 Iustin Pop
      # exit() or _exit()?  See below.
1733 8f765069 Iustin Pop
      os._exit(0) # Exit parent (the first child) of the second child.
1734 8f765069 Iustin Pop
  else:
1735 8f765069 Iustin Pop
    os._exit(0) # Exit parent of the first child.
1736 8f765069 Iustin Pop
1737 7d88772a Iustin Pop
  for fd in range(3):
1738 7d88772a Iustin Pop
    _CloseFDNoErr(fd)
1739 7d88772a Iustin Pop
  i = os.open("/dev/null", os.O_RDONLY) # stdin
1740 7d88772a Iustin Pop
  assert i == 0, "Can't close/reopen stdin"
1741 7d88772a Iustin Pop
  i = os.open(logfile, os.O_WRONLY|os.O_CREAT|os.O_APPEND, 0600) # stdout
1742 7d88772a Iustin Pop
  assert i == 1, "Can't close/reopen stdout"
1743 7d88772a Iustin Pop
  # Duplicate standard output to standard error.
1744 7d88772a Iustin Pop
  os.dup2(1, 2)
1745 8f765069 Iustin Pop
  return 0
1746 57c177af Iustin Pop
1747 57c177af Iustin Pop
1748 53beffbb Iustin Pop
def DaemonPidFileName(name):
1749 58885d79 Iustin Pop
  """Compute a ganeti pid file absolute path
1750 58885d79 Iustin Pop

1751 58885d79 Iustin Pop
  @type name: str
1752 58885d79 Iustin Pop
  @param name: the daemon name
1753 58885d79 Iustin Pop
  @rtype: str
1754 58885d79 Iustin Pop
  @return: the full path to the pidfile corresponding to the given
1755 58885d79 Iustin Pop
      daemon name
1756 b330ac0b Guido Trotter

1757 b330ac0b Guido Trotter
  """
1758 c4feafe8 Iustin Pop
  return PathJoin(constants.RUN_GANETI_DIR, "%s.pid" % name)
1759 b330ac0b Guido Trotter
1760 b330ac0b Guido Trotter
1761 2826b361 Guido Trotter
def EnsureDaemon(name):
1762 2826b361 Guido Trotter
  """Check for and start daemon if not alive.
1763 2826b361 Guido Trotter

1764 2826b361 Guido Trotter
  """
1765 2826b361 Guido Trotter
  result = RunCmd([constants.DAEMON_UTIL, "check-and-start", name])
1766 2826b361 Guido Trotter
  if result.failed:
1767 2826b361 Guido Trotter
    logging.error("Can't start daemon '%s', failure %s, output: %s",
1768 2826b361 Guido Trotter
                  name, result.fail_reason, result.output)
1769 2826b361 Guido Trotter
    return False
1770 2826b361 Guido Trotter
1771 2826b361 Guido Trotter
  return True
1772 2826b361 Guido Trotter
1773 2826b361 Guido Trotter
1774 b330ac0b Guido Trotter
def WritePidFile(name):
1775 b330ac0b Guido Trotter
  """Write the current process pidfile.
1776 b330ac0b Guido Trotter

1777 58885d79 Iustin Pop
  The file will be written to L{constants.RUN_GANETI_DIR}I{/name.pid}
1778 58885d79 Iustin Pop

1779 58885d79 Iustin Pop
  @type name: str
1780 58885d79 Iustin Pop
  @param name: the daemon name to use
1781 58885d79 Iustin Pop
  @raise errors.GenericError: if the pid file already exists and
1782 58885d79 Iustin Pop
      points to a live process
1783 b330ac0b Guido Trotter

1784 b330ac0b Guido Trotter
  """
1785 b330ac0b Guido Trotter
  pid = os.getpid()
1786 53beffbb Iustin Pop
  pidfilename = DaemonPidFileName(name)
1787 d9f311d7 Iustin Pop
  if IsProcessAlive(ReadPidFile(pidfilename)):
1788 533bb4b1 Michael Hanselmann
    raise errors.GenericError("%s contains a live process" % pidfilename)
1789 b330ac0b Guido Trotter
1790 b330ac0b Guido Trotter
  WriteFile(pidfilename, data="%d\n" % pid)
1791 b330ac0b Guido Trotter
1792 b330ac0b Guido Trotter
1793 b330ac0b Guido Trotter
def RemovePidFile(name):
1794 b330ac0b Guido Trotter
  """Remove the current process pidfile.
1795 b330ac0b Guido Trotter

1796 b330ac0b Guido Trotter
  Any errors are ignored.
1797 b330ac0b Guido Trotter

1798 58885d79 Iustin Pop
  @type name: str
1799 58885d79 Iustin Pop
  @param name: the daemon name used to derive the pidfile name
1800 58885d79 Iustin Pop

1801 b330ac0b Guido Trotter
  """
1802 53beffbb Iustin Pop
  pidfilename = DaemonPidFileName(name)
1803 b330ac0b Guido Trotter
  # TODO: we could check here that the file contains our pid
1804 b330ac0b Guido Trotter
  try:
1805 b330ac0b Guido Trotter
    RemoveFile(pidfilename)
1806 7260cfbe Iustin Pop
  except: # pylint: disable-msg=W0702
1807 b330ac0b Guido Trotter
    pass
1808 b330ac0b Guido Trotter
1809 b330ac0b Guido Trotter
1810 ff5251bc Iustin Pop
def KillProcess(pid, signal_=signal.SIGTERM, timeout=30,
1811 ff5251bc Iustin Pop
                waitpid=False):
1812 b2a1f511 Iustin Pop
  """Kill a process given by its pid.
1813 b2a1f511 Iustin Pop

1814 b2a1f511 Iustin Pop
  @type pid: int
1815 b2a1f511 Iustin Pop
  @param pid: The PID to terminate.
1816 38206f3c Iustin Pop
  @type signal_: int
1817 38206f3c Iustin Pop
  @param signal_: The signal to send, by default SIGTERM
1818 b2a1f511 Iustin Pop
  @type timeout: int
1819 b2a1f511 Iustin Pop
  @param timeout: The timeout after which, if the process is still alive,
1820 b2a1f511 Iustin Pop
                  a SIGKILL will be sent. If not positive, no such checking
1821 b2a1f511 Iustin Pop
                  will be done
1822 ff5251bc Iustin Pop
  @type waitpid: boolean
1823 ff5251bc Iustin Pop
  @param waitpid: If true, we should waitpid on this process after
1824 ff5251bc Iustin Pop
      sending signals, since it's our own child and otherwise it
1825 ff5251bc Iustin Pop
      would remain as zombie
1826 b2a1f511 Iustin Pop

1827 b2a1f511 Iustin Pop
  """
1828 ff5251bc Iustin Pop
  def _helper(pid, signal_, wait):
1829 ff5251bc Iustin Pop
    """Simple helper to encapsulate the kill/waitpid sequence"""
1830 ff5251bc Iustin Pop
    os.kill(pid, signal_)
1831 ff5251bc Iustin Pop
    if wait:
1832 ff5251bc Iustin Pop
      try:
1833 ff5251bc Iustin Pop
        os.waitpid(pid, os.WNOHANG)
1834 ff5251bc Iustin Pop
      except OSError:
1835 ff5251bc Iustin Pop
        pass
1836 ff5251bc Iustin Pop
1837 b2a1f511 Iustin Pop
  if pid <= 0:
1838 b2a1f511 Iustin Pop
    # kill with pid=0 == suicide
1839 b2a1f511 Iustin Pop
    raise errors.ProgrammerError("Invalid pid given '%s'" % pid)
1840 b2a1f511 Iustin Pop
1841 b2a1f511 Iustin Pop
  if not IsProcessAlive(pid):
1842 b2a1f511 Iustin Pop
    return
1843 31892b4c Michael Hanselmann
1844 ff5251bc Iustin Pop
  _helper(pid, signal_, waitpid)
1845 31892b4c Michael Hanselmann
1846 b2a1f511 Iustin Pop
  if timeout <= 0:
1847 b2a1f511 Iustin Pop
    return
1848 7167159a Michael Hanselmann
1849 31892b4c Michael Hanselmann
  def _CheckProcess():
1850 31892b4c Michael Hanselmann
    if not IsProcessAlive(pid):
1851 31892b4c Michael Hanselmann
      return
1852 31892b4c Michael Hanselmann
1853 7167159a Michael Hanselmann
    try:
1854 7167159a Michael Hanselmann
      (result_pid, _) = os.waitpid(pid, os.WNOHANG)
1855 7167159a Michael Hanselmann
    except OSError:
1856 31892b4c Michael Hanselmann
      raise RetryAgain()
1857 31892b4c Michael Hanselmann
1858 31892b4c Michael Hanselmann
    if result_pid > 0:
1859 31892b4c Michael Hanselmann
      return
1860 31892b4c Michael Hanselmann
1861 31892b4c Michael Hanselmann
    raise RetryAgain()
1862 31892b4c Michael Hanselmann
1863 31892b4c Michael Hanselmann
  try:
1864 31892b4c Michael Hanselmann
    # Wait up to $timeout seconds
1865 31892b4c Michael Hanselmann
    Retry(_CheckProcess, (0.01, 1.5, 0.1), timeout)
1866 31892b4c Michael Hanselmann
  except RetryTimeout:
1867 31892b4c Michael Hanselmann
    pass
1868 7167159a Michael Hanselmann
1869 b2a1f511 Iustin Pop
  if IsProcessAlive(pid):
1870 7167159a Michael Hanselmann
    # Kill process if it's still alive
1871 e1bd0072 Iustin Pop
    _helper(pid, signal.SIGKILL, waitpid)
1872 b2a1f511 Iustin Pop
1873 b2a1f511 Iustin Pop
1874 57c177af Iustin Pop
def FindFile(name, search_path, test=os.path.exists):
1875 57c177af Iustin Pop
  """Look for a filesystem object in a given path.
1876 57c177af Iustin Pop

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

1880 58885d79 Iustin Pop
  @type name: str
1881 58885d79 Iustin Pop
  @param name: the name to look for
1882 58885d79 Iustin Pop
  @type search_path: str
1883 58885d79 Iustin Pop
  @param search_path: location to start at
1884 58885d79 Iustin Pop
  @type test: callable
1885 58885d79 Iustin Pop
  @param test: a function taking one argument that should return True
1886 58885d79 Iustin Pop
      if the a given object is valid; the default value is
1887 58885d79 Iustin Pop
      os.path.exists, causing only existing files to be returned
1888 58885d79 Iustin Pop
  @rtype: str or None
1889 58885d79 Iustin Pop
  @return: full path to the object if found, None otherwise
1890 57c177af Iustin Pop

1891 57c177af Iustin Pop
  """
1892 f95c81bf Iustin Pop
  # validate the filename mask
1893 f95c81bf Iustin Pop
  if constants.EXT_PLUGIN_MASK.match(name) is None:
1894 f95c81bf Iustin Pop
    logging.critical("Invalid value passed for external script name: '%s'",
1895 f95c81bf Iustin Pop
                     name)
1896 f95c81bf Iustin Pop
    return None
1897 f95c81bf Iustin Pop
1898 57c177af Iustin Pop
  for dir_name in search_path:
1899 e02b9114 Iustin Pop
    # FIXME: investigate switch to PathJoin
1900 57c177af Iustin Pop
    item_name = os.path.sep.join([dir_name, name])
1901 f95c81bf Iustin Pop
    # check the user test and that we're indeed resolving to the given
1902 f95c81bf Iustin Pop
    # basename
1903 f95c81bf Iustin Pop
    if test(item_name) and os.path.basename(item_name) == name:
1904 57c177af Iustin Pop
      return item_name
1905 57c177af Iustin Pop
  return None
1906 8d1a2a64 Michael Hanselmann
1907 8d1a2a64 Michael Hanselmann
1908 8d1a2a64 Michael Hanselmann
def CheckVolumeGroupSize(vglist, vgname, minsize):
1909 8d1a2a64 Michael Hanselmann
  """Checks if the volume group list is valid.
1910 8d1a2a64 Michael Hanselmann

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

1914 58885d79 Iustin Pop
  @type vglist: dict
1915 58885d79 Iustin Pop
  @param vglist: dictionary of volume group names and their size
1916 58885d79 Iustin Pop
  @type vgname: str
1917 58885d79 Iustin Pop
  @param vgname: the volume group we should check
1918 58885d79 Iustin Pop
  @type minsize: int
1919 58885d79 Iustin Pop
  @param minsize: the minimum size we accept
1920 58885d79 Iustin Pop
  @rtype: None or str
1921 58885d79 Iustin Pop
  @return: None for success, otherwise the error message
1922 8d1a2a64 Michael Hanselmann

1923 8d1a2a64 Michael Hanselmann
  """
1924 8d1a2a64 Michael Hanselmann
  vgsize = vglist.get(vgname, None)
1925 8d1a2a64 Michael Hanselmann
  if vgsize is None:
1926 8d1a2a64 Michael Hanselmann
    return "volume group '%s' missing" % vgname
1927 8d1a2a64 Michael Hanselmann
  elif vgsize < minsize:
1928 8d1a2a64 Michael Hanselmann
    return ("volume group '%s' too small (%s MiB required, %d MiB found)" %
1929 8d1a2a64 Michael Hanselmann
            (vgname, minsize, vgsize))
1930 8d1a2a64 Michael Hanselmann
  return None
1931 7996a135 Iustin Pop
1932 7996a135 Iustin Pop
1933 45bc5e4a Michael Hanselmann
def SplitTime(value):
1934 739be818 Michael Hanselmann
  """Splits time as floating point number into a tuple.
1935 739be818 Michael Hanselmann

1936 45bc5e4a Michael Hanselmann
  @param value: Time in seconds
1937 45bc5e4a Michael Hanselmann
  @type value: int or float
1938 45bc5e4a Michael Hanselmann
  @return: Tuple containing (seconds, microseconds)
1939 739be818 Michael Hanselmann

1940 739be818 Michael Hanselmann
  """
1941 45bc5e4a Michael Hanselmann
  (seconds, microseconds) = divmod(int(value * 1000000), 1000000)
1942 45bc5e4a Michael Hanselmann
1943 45bc5e4a Michael Hanselmann
  assert 0 <= seconds, \
1944 45bc5e4a Michael Hanselmann
    "Seconds must be larger than or equal to 0, but are %s" % seconds
1945 45bc5e4a Michael Hanselmann
  assert 0 <= microseconds <= 999999, \
1946 45bc5e4a Michael Hanselmann
    "Microseconds must be 0-999999, but are %s" % microseconds
1947 45bc5e4a Michael Hanselmann
1948 45bc5e4a Michael Hanselmann
  return (int(seconds), int(microseconds))
1949 739be818 Michael Hanselmann
1950 739be818 Michael Hanselmann
1951 739be818 Michael Hanselmann
def MergeTime(timetuple):
1952 739be818 Michael Hanselmann
  """Merges a tuple into time as a floating point number.
1953 739be818 Michael Hanselmann

1954 45bc5e4a Michael Hanselmann
  @param timetuple: Time as tuple, (seconds, microseconds)
1955 739be818 Michael Hanselmann
  @type timetuple: tuple
1956 739be818 Michael Hanselmann
  @return: Time as a floating point number expressed in seconds
1957 739be818 Michael Hanselmann

1958 739be818 Michael Hanselmann
  """
1959 45bc5e4a Michael Hanselmann
  (seconds, microseconds) = timetuple
1960 739be818 Michael Hanselmann
1961 45bc5e4a Michael Hanselmann
  assert 0 <= seconds, \
1962 45bc5e4a Michael Hanselmann
    "Seconds must be larger than or equal to 0, but are %s" % seconds
1963 45bc5e4a Michael Hanselmann
  assert 0 <= microseconds <= 999999, \
1964 45bc5e4a Michael Hanselmann
    "Microseconds must be 0-999999, but are %s" % microseconds
1965 739be818 Michael Hanselmann
1966 45bc5e4a Michael Hanselmann
  return float(seconds) + (float(microseconds) * 0.000001)
1967 739be818 Michael Hanselmann
1968 739be818 Michael Hanselmann
1969 cd50653c Guido Trotter
def GetDaemonPort(daemon_name):
1970 cd50653c Guido Trotter
  """Get the daemon port for this cluster.
1971 4a8b186a Michael Hanselmann

1972 4a8b186a Michael Hanselmann
  Note that this routine does not read a ganeti-specific file, but
1973 58885d79 Iustin Pop
  instead uses C{socket.getservbyname} to allow pre-customization of
1974 4a8b186a Michael Hanselmann
  this parameter outside of Ganeti.
1975 4a8b186a Michael Hanselmann

1976 cd50653c Guido Trotter
  @type daemon_name: string
1977 cd50653c Guido Trotter
  @param daemon_name: daemon name (in constants.DAEMONS_PORTS)
1978 58885d79 Iustin Pop
  @rtype: int
1979 58885d79 Iustin Pop

1980 4a8b186a Michael Hanselmann
  """
1981 cd50653c Guido Trotter
  if daemon_name not in constants.DAEMONS_PORTS:
1982 cd50653c Guido Trotter
    raise errors.ProgrammerError("Unknown daemon: %s" % daemon_name)
1983 cd50653c Guido Trotter
1984 cd50653c Guido Trotter
  (proto, default_port) = constants.DAEMONS_PORTS[daemon_name]
1985 4a8b186a Michael Hanselmann
  try:
1986 cd50653c Guido Trotter
    port = socket.getservbyname(daemon_name, proto)
1987 4a8b186a Michael Hanselmann
  except socket.error:
1988 cd50653c Guido Trotter
    port = default_port
1989 4a8b186a Michael Hanselmann
1990 4a8b186a Michael Hanselmann
  return port
1991 4a8b186a Michael Hanselmann
1992 4a8b186a Michael Hanselmann
1993 ea34193f Iustin Pop
def SetupLogging(logfile, debug=0, stderr_logging=False, program="",
1994 551b6283 Iustin Pop
                 multithreaded=False, syslog=constants.SYSLOG_USAGE):
1995 82d9caef Iustin Pop
  """Configures the logging module.
1996 82d9caef Iustin Pop

1997 58885d79 Iustin Pop
  @type logfile: str
1998 58885d79 Iustin Pop
  @param logfile: the filename to which we should log
1999 ea34193f Iustin Pop
  @type debug: integer
2000 ea34193f Iustin Pop
  @param debug: if greater than zero, enable debug messages, otherwise
2001 58885d79 Iustin Pop
      only those at C{INFO} and above level
2002 58885d79 Iustin Pop
  @type stderr_logging: boolean
2003 58885d79 Iustin Pop
  @param stderr_logging: whether we should also log to the standard error
2004 58885d79 Iustin Pop
  @type program: str
2005 58885d79 Iustin Pop
  @param program: the name under which we should log messages
2006 d21d09d6 Iustin Pop
  @type multithreaded: boolean
2007 d21d09d6 Iustin Pop
  @param multithreaded: if True, will add the thread name to the log file
2008 551b6283 Iustin Pop
  @type syslog: string
2009 551b6283 Iustin Pop
  @param syslog: one of 'no', 'yes', 'only':
2010 551b6283 Iustin Pop
      - if no, syslog is not used
2011 551b6283 Iustin Pop
      - if yes, syslog is used (in addition to file-logging)
2012 551b6283 Iustin Pop
      - if only, only syslog is used
2013 58885d79 Iustin Pop
  @raise EnvironmentError: if we can't open the log file and
2014 551b6283 Iustin Pop
      syslog/stderr logging is disabled
2015 58885d79 Iustin Pop

2016 82d9caef Iustin Pop
  """
2017 d21d09d6 Iustin Pop
  fmt = "%(asctime)s: " + program + " pid=%(process)d"
2018 551b6283 Iustin Pop
  sft = program + "[%(process)d]:"
2019 d21d09d6 Iustin Pop
  if multithreaded:
2020 d21d09d6 Iustin Pop
    fmt += "/%(threadName)s"
2021 551b6283 Iustin Pop
    sft += " (%(threadName)s)"
2022 82d9caef Iustin Pop
  if debug:
2023 d21d09d6 Iustin Pop
    fmt += " %(module)s:%(lineno)s"
2024 551b6283 Iustin Pop
    # no debug info for syslog loggers
2025 d21d09d6 Iustin Pop
  fmt += " %(levelname)s %(message)s"
2026 551b6283 Iustin Pop
  # yes, we do want the textual level, as remote syslog will probably
2027 551b6283 Iustin Pop
  # lose the error level, and it's easier to grep for it
2028 551b6283 Iustin Pop
  sft += " %(levelname)s %(message)s"
2029 82d9caef Iustin Pop
  formatter = logging.Formatter(fmt)
2030 551b6283 Iustin Pop
  sys_fmt = logging.Formatter(sft)
2031 82d9caef Iustin Pop
2032 82d9caef Iustin Pop
  root_logger = logging.getLogger("")
2033 82d9caef Iustin Pop
  root_logger.setLevel(logging.NOTSET)
2034 82d9caef Iustin Pop
2035 6346a9e5 Michael Hanselmann
  # Remove all previously setup handlers
2036 6346a9e5 Michael Hanselmann
  for handler in root_logger.handlers:
2037 7d88772a Iustin Pop
    handler.close()
2038 6346a9e5 Michael Hanselmann
    root_logger.removeHandler(handler)
2039 6346a9e5 Michael Hanselmann
2040 82d9caef Iustin Pop
  if stderr_logging:
2041 82d9caef Iustin Pop
    stderr_handler = logging.StreamHandler()
2042 82d9caef Iustin Pop
    stderr_handler.setFormatter(formatter)
2043 82d9caef Iustin Pop
    if debug:
2044 82d9caef Iustin Pop
      stderr_handler.setLevel(logging.NOTSET)
2045 82d9caef Iustin Pop
    else:
2046 82d9caef Iustin Pop
      stderr_handler.setLevel(logging.CRITICAL)
2047 82d9caef Iustin Pop
    root_logger.addHandler(stderr_handler)
2048 82d9caef Iustin Pop
2049 551b6283 Iustin Pop
  if syslog in (constants.SYSLOG_YES, constants.SYSLOG_ONLY):
2050 551b6283 Iustin Pop
    facility = logging.handlers.SysLogHandler.LOG_DAEMON
2051 551b6283 Iustin Pop
    syslog_handler = logging.handlers.SysLogHandler(constants.SYSLOG_SOCKET,
2052 551b6283 Iustin Pop
                                                    facility)
2053 551b6283 Iustin Pop
    syslog_handler.setFormatter(sys_fmt)
2054 551b6283 Iustin Pop
    # Never enable debug over syslog
2055 551b6283 Iustin Pop
    syslog_handler.setLevel(logging.INFO)
2056 551b6283 Iustin Pop
    root_logger.addHandler(syslog_handler)
2057 551b6283 Iustin Pop
2058 551b6283 Iustin Pop
  if syslog != constants.SYSLOG_ONLY:
2059 551b6283 Iustin Pop
    # this can fail, if the logging directories are not setup or we have
2060 551b6283 Iustin Pop
    # a permisssion problem; in this case, it's best to log but ignore
2061 551b6283 Iustin Pop
    # the error if stderr_logging is True, and if false we re-raise the
2062 551b6283 Iustin Pop
    # exception since otherwise we could run but without any logs at all
2063 551b6283 Iustin Pop
    try:
2064 551b6283 Iustin Pop
      logfile_handler = logging.FileHandler(logfile)
2065 551b6283 Iustin Pop
      logfile_handler.setFormatter(formatter)
2066 551b6283 Iustin Pop
      if debug:
2067 551b6283 Iustin Pop
        logfile_handler.setLevel(logging.DEBUG)
2068 551b6283 Iustin Pop
      else:
2069 551b6283 Iustin Pop
        logfile_handler.setLevel(logging.INFO)
2070 551b6283 Iustin Pop
      root_logger.addHandler(logfile_handler)
2071 551b6283 Iustin Pop
    except EnvironmentError:
2072 551b6283 Iustin Pop
      if stderr_logging or syslog == constants.SYSLOG_YES:
2073 551b6283 Iustin Pop
        logging.exception("Failed to enable logging to file '%s'", logfile)
2074 551b6283 Iustin Pop
      else:
2075 551b6283 Iustin Pop
        # we need to re-raise the exception
2076 551b6283 Iustin Pop
        raise
2077 82d9caef Iustin Pop
2078 016d04b3 Michael Hanselmann
2079 da961187 Guido Trotter
def IsNormAbsPath(path):
2080 17c61836 Guido Trotter
  """Check whether a path is absolute and also normalized
2081 da961187 Guido Trotter

2082 da961187 Guido Trotter
  This avoids things like /dir/../../other/path to be valid.
2083 da961187 Guido Trotter

2084 da961187 Guido Trotter
  """
2085 da961187 Guido Trotter
  return os.path.normpath(path) == path and os.path.isabs(path)
2086 82d9caef Iustin Pop
2087 016d04b3 Michael Hanselmann
2088 4bb678e9 Iustin Pop
def PathJoin(*args):
2089 4bb678e9 Iustin Pop
  """Safe-join a list of path components.
2090 4bb678e9 Iustin Pop

2091 4bb678e9 Iustin Pop
  Requirements:
2092 4bb678e9 Iustin Pop
      - the first argument must be an absolute path
2093 4bb678e9 Iustin Pop
      - no component in the path must have backtracking (e.g. /../),
2094 4bb678e9 Iustin Pop
        since we check for normalization at the end
2095 4bb678e9 Iustin Pop

2096 4bb678e9 Iustin Pop
  @param args: the path components to be joined
2097 4bb678e9 Iustin Pop
  @raise ValueError: for invalid paths
2098 4bb678e9 Iustin Pop

2099 4bb678e9 Iustin Pop
  """
2100 4bb678e9 Iustin Pop
  # ensure we're having at least one path passed in
2101 4bb678e9 Iustin Pop
  assert args
2102 4bb678e9 Iustin Pop
  # ensure the first component is an absolute and normalized path name
2103 4bb678e9 Iustin Pop
  root = args[0]
2104 4bb678e9 Iustin Pop
  if not IsNormAbsPath(root):
2105 4bb678e9 Iustin Pop
    raise ValueError("Invalid parameter to PathJoin: '%s'" % str(args[0]))
2106 4bb678e9 Iustin Pop
  result = os.path.join(*args)
2107 4bb678e9 Iustin Pop
  # ensure that the whole path is normalized
2108 4bb678e9 Iustin Pop
  if not IsNormAbsPath(result):
2109 4bb678e9 Iustin Pop
    raise ValueError("Invalid parameters to PathJoin: '%s'" % str(args))
2110 4bb678e9 Iustin Pop
  # check that we're still under the original prefix
2111 4bb678e9 Iustin Pop
  prefix = os.path.commonprefix([root, result])
2112 4bb678e9 Iustin Pop
  if prefix != root:
2113 4bb678e9 Iustin Pop
    raise ValueError("Error: path joining resulted in different prefix"
2114 4bb678e9 Iustin Pop
                     " (%s != %s)" % (prefix, root))
2115 4bb678e9 Iustin Pop
  return result
2116 4bb678e9 Iustin Pop
2117 4bb678e9 Iustin Pop
2118 f65f63ef Iustin Pop
def TailFile(fname, lines=20):
2119 f65f63ef Iustin Pop
  """Return the last lines from a file.
2120 f65f63ef Iustin Pop

2121 f65f63ef Iustin Pop
  @note: this function will only read and parse the last 4KB of
2122 f65f63ef Iustin Pop
      the file; if the lines are very long, it could be that less
2123 f65f63ef Iustin Pop
      than the requested number of lines are returned
2124 f65f63ef Iustin Pop

2125 f65f63ef Iustin Pop
  @param fname: the file name
2126 f65f63ef Iustin Pop
  @type lines: int
2127 f65f63ef Iustin Pop
  @param lines: the (maximum) number of lines to return
2128 f65f63ef Iustin Pop

2129 f65f63ef Iustin Pop
  """
2130 f65f63ef Iustin Pop
  fd = open(fname, "r")
2131 f65f63ef Iustin Pop
  try:
2132 f65f63ef Iustin Pop
    fd.seek(0, 2)
2133 f65f63ef Iustin Pop
    pos = fd.tell()
2134 f65f63ef Iustin Pop
    pos = max(0, pos-4096)
2135 f65f63ef Iustin Pop
    fd.seek(pos, 0)
2136 f65f63ef Iustin Pop
    raw_data = fd.read()
2137 f65f63ef Iustin Pop
  finally:
2138 f65f63ef Iustin Pop
    fd.close()
2139 f65f63ef Iustin Pop
2140 f65f63ef Iustin Pop
  rows = raw_data.splitlines()
2141 f65f63ef Iustin Pop
  return rows[-lines:]
2142 f65f63ef Iustin Pop
2143 f65f63ef Iustin Pop
2144 27e46076 Michael Hanselmann
def _ParseAsn1Generalizedtime(value):
2145 27e46076 Michael Hanselmann
  """Parses an ASN1 GENERALIZEDTIME timestamp as used by pyOpenSSL.
2146 27e46076 Michael Hanselmann

2147 27e46076 Michael Hanselmann
  @type value: string
2148 27e46076 Michael Hanselmann
  @param value: ASN1 GENERALIZEDTIME timestamp
2149 27e46076 Michael Hanselmann

2150 27e46076 Michael Hanselmann
  """
2151 27e46076 Michael Hanselmann
  m = re.match(r"^(\d+)([-+]\d\d)(\d\d)$", value)
2152 27e46076 Michael Hanselmann
  if m:
2153 27e46076 Michael Hanselmann
    # We have an offset
2154 27e46076 Michael Hanselmann
    asn1time = m.group(1)
2155 27e46076 Michael Hanselmann
    hours = int(m.group(2))
2156 27e46076 Michael Hanselmann
    minutes = int(m.group(3))
2157 27e46076 Michael Hanselmann
    utcoffset = (60 * hours) + minutes
2158 27e46076 Michael Hanselmann
  else:
2159 27e46076 Michael Hanselmann
    if not value.endswith("Z"):
2160 27e46076 Michael Hanselmann
      raise ValueError("Missing timezone")
2161 27e46076 Michael Hanselmann
    asn1time = value[:-1]
2162 27e46076 Michael Hanselmann
    utcoffset = 0
2163 27e46076 Michael Hanselmann
2164 27e46076 Michael Hanselmann
  parsed = time.strptime(asn1time, "%Y%m%d%H%M%S")
2165 27e46076 Michael Hanselmann
2166 27e46076 Michael Hanselmann
  tt = datetime.datetime(*(parsed[:7])) - datetime.timedelta(minutes=utcoffset)
2167 27e46076 Michael Hanselmann
2168 27e46076 Michael Hanselmann
  return calendar.timegm(tt.utctimetuple())
2169 27e46076 Michael Hanselmann
2170 27e46076 Michael Hanselmann
2171 27e46076 Michael Hanselmann
def GetX509CertValidity(cert):
2172 27e46076 Michael Hanselmann
  """Returns the validity period of the certificate.
2173 27e46076 Michael Hanselmann

2174 27e46076 Michael Hanselmann
  @type cert: OpenSSL.crypto.X509
2175 27e46076 Michael Hanselmann
  @param cert: X509 certificate object
2176 27e46076 Michael Hanselmann

2177 27e46076 Michael Hanselmann
  """
2178 27e46076 Michael Hanselmann
  # The get_notBefore and get_notAfter functions are only supported in
2179 27e46076 Michael Hanselmann
  # pyOpenSSL 0.7 and above.
2180 27e46076 Michael Hanselmann
  try:
2181 27e46076 Michael Hanselmann
    get_notbefore_fn = cert.get_notBefore
2182 27e46076 Michael Hanselmann
  except AttributeError:
2183 27e46076 Michael Hanselmann
    not_before = None
2184 27e46076 Michael Hanselmann
  else:
2185 27e46076 Michael Hanselmann
    not_before_asn1 = get_notbefore_fn()
2186 27e46076 Michael Hanselmann
2187 27e46076 Michael Hanselmann
    if not_before_asn1 is None:
2188 27e46076 Michael Hanselmann
      not_before = None
2189 27e46076 Michael Hanselmann
    else:
2190 27e46076 Michael Hanselmann
      not_before = _ParseAsn1Generalizedtime(not_before_asn1)
2191 27e46076 Michael Hanselmann
2192 27e46076 Michael Hanselmann
  try:
2193 27e46076 Michael Hanselmann
    get_notafter_fn = cert.get_notAfter
2194 27e46076 Michael Hanselmann
  except AttributeError:
2195 27e46076 Michael Hanselmann
    not_after = None
2196 27e46076 Michael Hanselmann
  else:
2197 27e46076 Michael Hanselmann
    not_after_asn1 = get_notafter_fn()
2198 27e46076 Michael Hanselmann
2199 27e46076 Michael Hanselmann
    if not_after_asn1 is None:
2200 27e46076 Michael Hanselmann
      not_after = None
2201 27e46076 Michael Hanselmann
    else:
2202 27e46076 Michael Hanselmann
      not_after = _ParseAsn1Generalizedtime(not_after_asn1)
2203 27e46076 Michael Hanselmann
2204 27e46076 Michael Hanselmann
  return (not_before, not_after)
2205 27e46076 Michael Hanselmann
2206 27e46076 Michael Hanselmann
2207 26f15862 Iustin Pop
def SafeEncode(text):
2208 26f15862 Iustin Pop
  """Return a 'safe' version of a source string.
2209 26f15862 Iustin Pop

2210 26f15862 Iustin Pop
  This function mangles the input string and returns a version that
2211 d392fa34 Iustin Pop
  should be safe to display/encode as ASCII. To this end, we first
2212 26f15862 Iustin Pop
  convert it to ASCII using the 'backslashreplace' encoding which
2213 d392fa34 Iustin Pop
  should get rid of any non-ASCII chars, and then we process it
2214 d392fa34 Iustin Pop
  through a loop copied from the string repr sources in the python; we
2215 d392fa34 Iustin Pop
  don't use string_escape anymore since that escape single quotes and
2216 d392fa34 Iustin Pop
  backslashes too, and that is too much; and that escaping is not
2217 d392fa34 Iustin Pop
  stable, i.e. string_escape(string_escape(x)) != string_escape(x).
2218 26f15862 Iustin Pop

2219 26f15862 Iustin Pop
  @type text: str or unicode
2220 26f15862 Iustin Pop
  @param text: input data
2221 26f15862 Iustin Pop
  @rtype: str
2222 26f15862 Iustin Pop
  @return: a safe version of text
2223 26f15862 Iustin Pop

2224 26f15862 Iustin Pop
  """
2225 d392fa34 Iustin Pop
  if isinstance(text, unicode):
2226 5bbd3f7f Michael Hanselmann
    # only if unicode; if str already, we handle it below
2227 d392fa34 Iustin Pop
    text = text.encode('ascii', 'backslashreplace')
2228 d392fa34 Iustin Pop
  resu = ""
2229 d392fa34 Iustin Pop
  for char in text:
2230 d392fa34 Iustin Pop
    c = ord(char)
2231 d392fa34 Iustin Pop
    if char  == '\t':
2232 d392fa34 Iustin Pop
      resu += r'\t'
2233 d392fa34 Iustin Pop
    elif char == '\n':
2234 d392fa34 Iustin Pop
      resu += r'\n'
2235 d392fa34 Iustin Pop
    elif char == '\r':
2236 d392fa34 Iustin Pop
      resu += r'\'r'
2237 d392fa34 Iustin Pop
    elif c < 32 or c >= 127: # non-printable
2238 d392fa34 Iustin Pop
      resu += "\\x%02x" % (c & 0xff)
2239 d392fa34 Iustin Pop
    else:
2240 d392fa34 Iustin Pop
      resu += char
2241 d392fa34 Iustin Pop
  return resu
2242 26f15862 Iustin Pop
2243 26f15862 Iustin Pop
2244 5b69bc7c Iustin Pop
def UnescapeAndSplit(text, sep=","):
2245 5b69bc7c Iustin Pop
  """Split and unescape a string based on a given separator.
2246 5b69bc7c Iustin Pop

2247 5b69bc7c Iustin Pop
  This function splits a string based on a separator where the
2248 5b69bc7c Iustin Pop
  separator itself can be escape in order to be an element of the
2249 5b69bc7c Iustin Pop
  elements. The escaping rules are (assuming coma being the
2250 5b69bc7c Iustin Pop
  separator):
2251 5b69bc7c Iustin Pop
    - a plain , separates the elements
2252 5b69bc7c Iustin Pop
    - a sequence \\\\, (double backslash plus comma) is handled as a
2253 5b69bc7c Iustin Pop
      backslash plus a separator comma
2254 5b69bc7c Iustin Pop
    - a sequence \, (backslash plus comma) is handled as a
2255 5b69bc7c Iustin Pop
      non-separator comma
2256 5b69bc7c Iustin Pop

2257 5b69bc7c Iustin Pop
  @type text: string
2258 5b69bc7c Iustin Pop
  @param text: the string to split
2259 5b69bc7c Iustin Pop
  @type sep: string
2260 5b69bc7c Iustin Pop
  @param text: the separator
2261 5b69bc7c Iustin Pop
  @rtype: string
2262 5b69bc7c Iustin Pop
  @return: a list of strings
2263 5b69bc7c Iustin Pop

2264 5b69bc7c Iustin Pop
  """
2265 5b69bc7c Iustin Pop
  # we split the list by sep (with no escaping at this stage)
2266 5b69bc7c Iustin Pop
  slist = text.split(sep)
2267 5b69bc7c Iustin Pop
  # next, we revisit the elements and if any of them ended with an odd
2268 5b69bc7c Iustin Pop
  # number of backslashes, then we join it with the next
2269 5b69bc7c Iustin Pop
  rlist = []
2270 5b69bc7c Iustin Pop
  while slist:
2271 5b69bc7c Iustin Pop
    e1 = slist.pop(0)
2272 5b69bc7c Iustin Pop
    if e1.endswith("\\"):
2273 5b69bc7c Iustin Pop
      num_b = len(e1) - len(e1.rstrip("\\"))
2274 5b69bc7c Iustin Pop
      if num_b % 2 == 1:
2275 5b69bc7c Iustin Pop
        e2 = slist.pop(0)
2276 5b69bc7c Iustin Pop
        # here the backslashes remain (all), and will be reduced in
2277 5b69bc7c Iustin Pop
        # the next step
2278 5b69bc7c Iustin Pop
        rlist.append(e1 + sep + e2)
2279 5b69bc7c Iustin Pop
        continue
2280 5b69bc7c Iustin Pop
    rlist.append(e1)
2281 5b69bc7c Iustin Pop
  # finally, replace backslash-something with something
2282 5b69bc7c Iustin Pop
  rlist = [re.sub(r"\\(.)", r"\1", v) for v in rlist]
2283 5b69bc7c Iustin Pop
  return rlist
2284 5b69bc7c Iustin Pop
2285 5b69bc7c Iustin Pop
2286 ab3e6da8 Iustin Pop
def CommaJoin(names):
2287 ab3e6da8 Iustin Pop
  """Nicely join a set of identifiers.
2288 ab3e6da8 Iustin Pop

2289 ab3e6da8 Iustin Pop
  @param names: set, list or tuple
2290 ab3e6da8 Iustin Pop
  @return: a string with the formatted results
2291 ab3e6da8 Iustin Pop

2292 ab3e6da8 Iustin Pop
  """
2293 1f864b60 Iustin Pop
  return ", ".join([str(val) for val in names])
2294 ab3e6da8 Iustin Pop
2295 ab3e6da8 Iustin Pop
2296 3f6a47a8 Michael Hanselmann
def BytesToMebibyte(value):
2297 3f6a47a8 Michael Hanselmann
  """Converts bytes to mebibytes.
2298 3f6a47a8 Michael Hanselmann

2299 3f6a47a8 Michael Hanselmann
  @type value: int
2300 3f6a47a8 Michael Hanselmann
  @param value: Value in bytes
2301 3f6a47a8 Michael Hanselmann
  @rtype: int
2302 3f6a47a8 Michael Hanselmann
  @return: Value in mebibytes
2303 3f6a47a8 Michael Hanselmann

2304 3f6a47a8 Michael Hanselmann
  """
2305 3f6a47a8 Michael Hanselmann
  return int(round(value / (1024.0 * 1024.0), 0))
2306 3f6a47a8 Michael Hanselmann
2307 3f6a47a8 Michael Hanselmann
2308 3f6a47a8 Michael Hanselmann
def CalculateDirectorySize(path):
2309 3f6a47a8 Michael Hanselmann
  """Calculates the size of a directory recursively.
2310 3f6a47a8 Michael Hanselmann

2311 3f6a47a8 Michael Hanselmann
  @type path: string
2312 3f6a47a8 Michael Hanselmann
  @param path: Path to directory
2313 3f6a47a8 Michael Hanselmann
  @rtype: int
2314 3f6a47a8 Michael Hanselmann
  @return: Size in mebibytes
2315 3f6a47a8 Michael Hanselmann

2316 3f6a47a8 Michael Hanselmann
  """
2317 3f6a47a8 Michael Hanselmann
  size = 0
2318 3f6a47a8 Michael Hanselmann
2319 3f6a47a8 Michael Hanselmann
  for (curpath, _, files) in os.walk(path):
2320 2a887df9 Michael Hanselmann
    for filename in files:
2321 c4feafe8 Iustin Pop
      st = os.lstat(PathJoin(curpath, filename))
2322 3f6a47a8 Michael Hanselmann
      size += st.st_size
2323 3f6a47a8 Michael Hanselmann
2324 3f6a47a8 Michael Hanselmann
  return BytesToMebibyte(size)
2325 3f6a47a8 Michael Hanselmann
2326 3f6a47a8 Michael Hanselmann
2327 620a85fd Iustin Pop
def GetFilesystemStats(path):
2328 620a85fd Iustin Pop
  """Returns the total and free space on a filesystem.
2329 3f6a47a8 Michael Hanselmann

2330 3f6a47a8 Michael Hanselmann
  @type path: string
2331 3f6a47a8 Michael Hanselmann
  @param path: Path on filesystem to be examined
2332 3f6a47a8 Michael Hanselmann
  @rtype: int
2333 620a85fd Iustin Pop
  @return: tuple of (Total space, Free space) in mebibytes
2334 3f6a47a8 Michael Hanselmann

2335 3f6a47a8 Michael Hanselmann
  """
2336 3f6a47a8 Michael Hanselmann
  st = os.statvfs(path)
2337 3f6a47a8 Michael Hanselmann
2338 620a85fd Iustin Pop
  fsize = BytesToMebibyte(st.f_bavail * st.f_frsize)
2339 620a85fd Iustin Pop
  tsize = BytesToMebibyte(st.f_blocks * st.f_frsize)
2340 620a85fd Iustin Pop
  return (tsize, fsize)
2341 3f6a47a8 Michael Hanselmann
2342 3f6a47a8 Michael Hanselmann
2343 bdefe5dd Michael Hanselmann
def RunInSeparateProcess(fn, *args):
2344 eb58f7bd Michael Hanselmann
  """Runs a function in a separate process.
2345 eb58f7bd Michael Hanselmann

2346 eb58f7bd Michael Hanselmann
  Note: Only boolean return values are supported.
2347 eb58f7bd Michael Hanselmann

2348 eb58f7bd Michael Hanselmann
  @type fn: callable
2349 eb58f7bd Michael Hanselmann
  @param fn: Function to be called
2350 bdefe5dd Michael Hanselmann
  @rtype: bool
2351 bdefe5dd Michael Hanselmann
  @return: Function's result
2352 eb58f7bd Michael Hanselmann

2353 eb58f7bd Michael Hanselmann
  """
2354 eb58f7bd Michael Hanselmann
  pid = os.fork()
2355 eb58f7bd Michael Hanselmann
  if pid == 0:
2356 eb58f7bd Michael Hanselmann
    # Child process
2357 eb58f7bd Michael Hanselmann
    try:
2358 82869978 Michael Hanselmann
      # In case the function uses temporary files
2359 82869978 Michael Hanselmann
      ResetTempfileModule()
2360 82869978 Michael Hanselmann
2361 eb58f7bd Michael Hanselmann
      # Call function
2362 bdefe5dd Michael Hanselmann
      result = int(bool(fn(*args)))
2363 eb58f7bd Michael Hanselmann
      assert result in (0, 1)
2364 eb58f7bd Michael Hanselmann
    except: # pylint: disable-msg=W0702
2365 eb58f7bd Michael Hanselmann
      logging.exception("Error while calling function in separate process")
2366 eb58f7bd Michael Hanselmann
      # 0 and 1 are reserved for the return value
2367 eb58f7bd Michael Hanselmann
      result = 33
2368 eb58f7bd Michael Hanselmann
2369 eb58f7bd Michael Hanselmann
    os._exit(result) # pylint: disable-msg=W0212
2370 eb58f7bd Michael Hanselmann
2371 eb58f7bd Michael Hanselmann
  # Parent process
2372 eb58f7bd Michael Hanselmann
2373 eb58f7bd Michael Hanselmann
  # Avoid zombies and check exit code
2374 eb58f7bd Michael Hanselmann
  (_, status) = os.waitpid(pid, 0)
2375 eb58f7bd Michael Hanselmann
2376 eb58f7bd Michael Hanselmann
  if os.WIFSIGNALED(status):
2377 eb58f7bd Michael Hanselmann
    exitcode = None
2378 eb58f7bd Michael Hanselmann
    signum = os.WTERMSIG(status)
2379 eb58f7bd Michael Hanselmann
  else:
2380 eb58f7bd Michael Hanselmann
    exitcode = os.WEXITSTATUS(status)
2381 eb58f7bd Michael Hanselmann
    signum = None
2382 eb58f7bd Michael Hanselmann
2383 eb58f7bd Michael Hanselmann
  if not (exitcode in (0, 1) and signum is None):
2384 eb58f7bd Michael Hanselmann
    raise errors.GenericError("Child program failed (code=%s, signal=%s)" %
2385 eb58f7bd Michael Hanselmann
                              (exitcode, signum))
2386 eb58f7bd Michael Hanselmann
2387 eb58f7bd Michael Hanselmann
  return bool(exitcode)
2388 eb58f7bd Michael Hanselmann
2389 eb58f7bd Michael Hanselmann
2390 7996a135 Iustin Pop
def LockedMethod(fn):
2391 7996a135 Iustin Pop
  """Synchronized object access decorator.
2392 7996a135 Iustin Pop

2393 7996a135 Iustin Pop
  This decorator is intended to protect access to an object using the
2394 7996a135 Iustin Pop
  object's own lock which is hardcoded to '_lock'.
2395 7996a135 Iustin Pop

2396 7996a135 Iustin Pop
  """
2397 e67bd559 Michael Hanselmann
  def _LockDebug(*args, **kwargs):
2398 e67bd559 Michael Hanselmann
    if debug_locks:
2399 e67bd559 Michael Hanselmann
      logging.debug(*args, **kwargs)
2400 e67bd559 Michael Hanselmann
2401 7996a135 Iustin Pop
  def wrapper(self, *args, **kwargs):
2402 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
2403 7996a135 Iustin Pop
    assert hasattr(self, '_lock')
2404 7996a135 Iustin Pop
    lock = self._lock
2405 e67bd559 Michael Hanselmann
    _LockDebug("Waiting for %s", lock)
2406 7996a135 Iustin Pop
    lock.acquire()
2407 7996a135 Iustin Pop
    try:
2408 e67bd559 Michael Hanselmann
      _LockDebug("Acquired %s", lock)
2409 7996a135 Iustin Pop
      result = fn(self, *args, **kwargs)
2410 7996a135 Iustin Pop
    finally:
2411 e67bd559 Michael Hanselmann
      _LockDebug("Releasing %s", lock)
2412 7996a135 Iustin Pop
      lock.release()
2413 e67bd559 Michael Hanselmann
      _LockDebug("Released %s", lock)
2414 7996a135 Iustin Pop
    return result
2415 7996a135 Iustin Pop
  return wrapper
2416 eb0f0ce0 Michael Hanselmann
2417 eb0f0ce0 Michael Hanselmann
2418 eb0f0ce0 Michael Hanselmann
def LockFile(fd):
2419 eb0f0ce0 Michael Hanselmann
  """Locks a file using POSIX locks.
2420 eb0f0ce0 Michael Hanselmann

2421 58885d79 Iustin Pop
  @type fd: int
2422 58885d79 Iustin Pop
  @param fd: the file descriptor we need to lock
2423 58885d79 Iustin Pop

2424 eb0f0ce0 Michael Hanselmann
  """
2425 eb0f0ce0 Michael Hanselmann
  try:
2426 eb0f0ce0 Michael Hanselmann
    fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
2427 eb0f0ce0 Michael Hanselmann
  except IOError, err:
2428 eb0f0ce0 Michael Hanselmann
    if err.errno == errno.EAGAIN:
2429 eb0f0ce0 Michael Hanselmann
      raise errors.LockError("File already locked")
2430 eb0f0ce0 Michael Hanselmann
    raise
2431 de499029 Michael Hanselmann
2432 de499029 Michael Hanselmann
2433 3b813dd2 Iustin Pop
def FormatTime(val):
2434 3b813dd2 Iustin Pop
  """Formats a time value.
2435 3b813dd2 Iustin Pop

2436 3b813dd2 Iustin Pop
  @type val: float or None
2437 3b813dd2 Iustin Pop
  @param val: the timestamp as returned by time.time()
2438 3b813dd2 Iustin Pop
  @return: a string value or N/A if we don't have a valid timestamp
2439 3b813dd2 Iustin Pop

2440 3b813dd2 Iustin Pop
  """
2441 3b813dd2 Iustin Pop
  if val is None or not isinstance(val, (int, float)):
2442 3b813dd2 Iustin Pop
    return "N/A"
2443 3b813dd2 Iustin Pop
  # these two codes works on Linux, but they are not guaranteed on all
2444 3b813dd2 Iustin Pop
  # platforms
2445 3b813dd2 Iustin Pop
  return time.strftime("%F %T", time.localtime(val))
2446 3b813dd2 Iustin Pop
2447 3b813dd2 Iustin Pop
2448 5cbe43a5 Michael Hanselmann
def ReadWatcherPauseFile(filename, now=None, remove_after=3600):
2449 05e50653 Michael Hanselmann
  """Reads the watcher pause file.
2450 05e50653 Michael Hanselmann

2451 5cbe43a5 Michael Hanselmann
  @type filename: string
2452 5cbe43a5 Michael Hanselmann
  @param filename: Path to watcher pause file
2453 5cbe43a5 Michael Hanselmann
  @type now: None, float or int
2454 5cbe43a5 Michael Hanselmann
  @param now: Current time as Unix timestamp
2455 5cbe43a5 Michael Hanselmann
  @type remove_after: int
2456 5cbe43a5 Michael Hanselmann
  @param remove_after: Remove watcher pause file after specified amount of
2457 5cbe43a5 Michael Hanselmann
    seconds past the pause end time
2458 5cbe43a5 Michael Hanselmann

2459 05e50653 Michael Hanselmann
  """
2460 05e50653 Michael Hanselmann
  if now is None:
2461 05e50653 Michael Hanselmann
    now = time.time()
2462 05e50653 Michael Hanselmann
2463 05e50653 Michael Hanselmann
  try:
2464 05e50653 Michael Hanselmann
    value = ReadFile(filename)
2465 05e50653 Michael Hanselmann
  except IOError, err:
2466 05e50653 Michael Hanselmann
    if err.errno != errno.ENOENT:
2467 05e50653 Michael Hanselmann
      raise
2468 05e50653 Michael Hanselmann
    value = None
2469 05e50653 Michael Hanselmann
2470 05e50653 Michael Hanselmann
  if value is not None:
2471 05e50653 Michael Hanselmann
    try:
2472 05e50653 Michael Hanselmann
      value = int(value)
2473 05e50653 Michael Hanselmann
    except ValueError:
2474 5cbe43a5 Michael Hanselmann
      logging.warning(("Watcher pause file (%s) contains invalid value,"
2475 5cbe43a5 Michael Hanselmann
                       " removing it"), filename)
2476 5cbe43a5 Michael Hanselmann
      RemoveFile(filename)
2477 05e50653 Michael Hanselmann
      value = None
2478 05e50653 Michael Hanselmann
2479 05e50653 Michael Hanselmann
    if value is not None:
2480 5cbe43a5 Michael Hanselmann
      # Remove file if it's outdated
2481 5cbe43a5 Michael Hanselmann
      if now > (value + remove_after):
2482 5cbe43a5 Michael Hanselmann
        RemoveFile(filename)
2483 5cbe43a5 Michael Hanselmann
        value = None
2484 5cbe43a5 Michael Hanselmann
2485 5cbe43a5 Michael Hanselmann
      elif now > value:
2486 05e50653 Michael Hanselmann
        value = None
2487 05e50653 Michael Hanselmann
2488 05e50653 Michael Hanselmann
  return value
2489 05e50653 Michael Hanselmann
2490 05e50653 Michael Hanselmann
2491 de0ea66b Michael Hanselmann
class RetryTimeout(Exception):
2492 de0ea66b Michael Hanselmann
  """Retry loop timed out.
2493 de0ea66b Michael Hanselmann

2494 de0ea66b Michael Hanselmann
  """
2495 de0ea66b Michael Hanselmann
2496 de0ea66b Michael Hanselmann
2497 de0ea66b Michael Hanselmann
class RetryAgain(Exception):
2498 de0ea66b Michael Hanselmann
  """Retry again.
2499 de0ea66b Michael Hanselmann

2500 de0ea66b Michael Hanselmann
  """
2501 de0ea66b Michael Hanselmann
2502 de0ea66b Michael Hanselmann
2503 de0ea66b Michael Hanselmann
class _RetryDelayCalculator(object):
2504 de0ea66b Michael Hanselmann
  """Calculator for increasing delays.
2505 de0ea66b Michael Hanselmann

2506 de0ea66b Michael Hanselmann
  """
2507 de0ea66b Michael Hanselmann
  __slots__ = [
2508 de0ea66b Michael Hanselmann
    "_factor",
2509 de0ea66b Michael Hanselmann
    "_limit",
2510 de0ea66b Michael Hanselmann
    "_next",
2511 de0ea66b Michael Hanselmann
    "_start",
2512 de0ea66b Michael Hanselmann
    ]
2513 de0ea66b Michael Hanselmann
2514 de0ea66b Michael Hanselmann
  def __init__(self, start, factor, limit):
2515 de0ea66b Michael Hanselmann
    """Initializes this class.
2516 de0ea66b Michael Hanselmann

2517 de0ea66b Michael Hanselmann
    @type start: float
2518 de0ea66b Michael Hanselmann
    @param start: Initial delay
2519 de0ea66b Michael Hanselmann
    @type factor: float
2520 de0ea66b Michael Hanselmann
    @param factor: Factor for delay increase
2521 de0ea66b Michael Hanselmann
    @type limit: float or None
2522 de0ea66b Michael Hanselmann
    @param limit: Upper limit for delay or None for no limit
2523 de0ea66b Michael Hanselmann

2524 de0ea66b Michael Hanselmann
    """
2525 de0ea66b Michael Hanselmann
    assert start > 0.0
2526 de0ea66b Michael Hanselmann
    assert factor >= 1.0
2527 de0ea66b Michael Hanselmann
    assert limit is None or limit >= 0.0
2528 de0ea66b Michael Hanselmann
2529 de0ea66b Michael Hanselmann
    self._start = start
2530 de0ea66b Michael Hanselmann
    self._factor = factor
2531 de0ea66b Michael Hanselmann
    self._limit = limit
2532 de0ea66b Michael Hanselmann
2533 de0ea66b Michael Hanselmann
    self._next = start
2534 de0ea66b Michael Hanselmann
2535 de0ea66b Michael Hanselmann
  def __call__(self):
2536 de0ea66b Michael Hanselmann
    """Returns current delay and calculates the next one.
2537 de0ea66b Michael Hanselmann

2538 de0ea66b Michael Hanselmann
    """
2539 de0ea66b Michael Hanselmann
    current = self._next
2540 de0ea66b Michael Hanselmann
2541 de0ea66b Michael Hanselmann
    # Update for next run
2542 de0ea66b Michael Hanselmann
    if self._limit is None or self._next < self._limit:
2543 26751075 Michael Hanselmann
      self._next = min(self._limit, self._next * self._factor)
2544 de0ea66b Michael Hanselmann
2545 de0ea66b Michael Hanselmann
    return current
2546 de0ea66b Michael Hanselmann
2547 de0ea66b Michael Hanselmann
2548 de0ea66b Michael Hanselmann
#: Special delay to specify whole remaining timeout
2549 de0ea66b Michael Hanselmann
RETRY_REMAINING_TIME = object()
2550 de0ea66b Michael Hanselmann
2551 de0ea66b Michael Hanselmann
2552 de0ea66b Michael Hanselmann
def Retry(fn, delay, timeout, args=None, wait_fn=time.sleep,
2553 de0ea66b Michael Hanselmann
          _time_fn=time.time):
2554 de0ea66b Michael Hanselmann
  """Call a function repeatedly until it succeeds.
2555 de0ea66b Michael Hanselmann

2556 de0ea66b Michael Hanselmann
  The function C{fn} is called repeatedly until it doesn't throw L{RetryAgain}
2557 de0ea66b Michael Hanselmann
  anymore. Between calls a delay, specified by C{delay}, is inserted. After a
2558 de0ea66b Michael Hanselmann
  total of C{timeout} seconds, this function throws L{RetryTimeout}.
2559 de0ea66b Michael Hanselmann

2560 de0ea66b Michael Hanselmann
  C{delay} can be one of the following:
2561 de0ea66b Michael Hanselmann
    - callable returning the delay length as a float
2562 de0ea66b Michael Hanselmann
    - Tuple of (start, factor, limit)
2563 de0ea66b Michael Hanselmann
    - L{RETRY_REMAINING_TIME} to sleep until the timeout expires (this is
2564 de0ea66b Michael Hanselmann
      useful when overriding L{wait_fn} to wait for an external event)
2565 de0ea66b Michael Hanselmann
    - A static delay as a number (int or float)
2566 de0ea66b Michael Hanselmann

2567 de0ea66b Michael Hanselmann
  @type fn: callable
2568 de0ea66b Michael Hanselmann
  @param fn: Function to be called
2569 de0ea66b Michael Hanselmann
  @param delay: Either a callable (returning the delay), a tuple of (start,
2570 de0ea66b Michael Hanselmann
                factor, limit) (see L{_RetryDelayCalculator}),
2571 de0ea66b Michael Hanselmann
                L{RETRY_REMAINING_TIME} or a number (int or float)
2572 de0ea66b Michael Hanselmann
  @type timeout: float
2573 de0ea66b Michael Hanselmann
  @param timeout: Total timeout
2574 de0ea66b Michael Hanselmann
  @type wait_fn: callable
2575 de0ea66b Michael Hanselmann
  @param wait_fn: Waiting function
2576 de0ea66b Michael Hanselmann
  @return: Return value of function
2577 de0ea66b Michael Hanselmann

2578 de0ea66b Michael Hanselmann
  """
2579 de0ea66b Michael Hanselmann
  assert callable(fn)
2580 de0ea66b Michael Hanselmann
  assert callable(wait_fn)
2581 de0ea66b Michael Hanselmann
  assert callable(_time_fn)
2582 de0ea66b Michael Hanselmann
2583 de0ea66b Michael Hanselmann
  if args is None:
2584 de0ea66b Michael Hanselmann
    args = []
2585 de0ea66b Michael Hanselmann
2586 de0ea66b Michael Hanselmann
  end_time = _time_fn() + timeout
2587 de0ea66b Michael Hanselmann
2588 de0ea66b Michael Hanselmann
  if callable(delay):
2589 de0ea66b Michael Hanselmann
    # External function to calculate delay
2590 de0ea66b Michael Hanselmann
    calc_delay = delay
2591 de0ea66b Michael Hanselmann
2592 de0ea66b Michael Hanselmann
  elif isinstance(delay, (tuple, list)):
2593 de0ea66b Michael Hanselmann
    # Increasing delay with optional upper boundary
2594 de0ea66b Michael Hanselmann
    (start, factor, limit) = delay
2595 de0ea66b Michael Hanselmann
    calc_delay = _RetryDelayCalculator(start, factor, limit)
2596 de0ea66b Michael Hanselmann
2597 de0ea66b Michael Hanselmann
  elif delay is RETRY_REMAINING_TIME:
2598 de0ea66b Michael Hanselmann
    # Always use the remaining time
2599 de0ea66b Michael Hanselmann
    calc_delay = None
2600 de0ea66b Michael Hanselmann
2601 de0ea66b Michael Hanselmann
  else:
2602 de0ea66b Michael Hanselmann
    # Static delay
2603 de0ea66b Michael Hanselmann
    calc_delay = lambda: delay
2604 de0ea66b Michael Hanselmann
2605 de0ea66b Michael Hanselmann
  assert calc_delay is None or callable(calc_delay)
2606 de0ea66b Michael Hanselmann
2607 de0ea66b Michael Hanselmann
  while True:
2608 de0ea66b Michael Hanselmann
    try:
2609 7260cfbe Iustin Pop
      # pylint: disable-msg=W0142
2610 de0ea66b Michael Hanselmann
      return fn(*args)
2611 de0ea66b Michael Hanselmann
    except RetryAgain:
2612 de0ea66b Michael Hanselmann
      pass
2613 1b429e2a Iustin Pop
    except RetryTimeout:
2614 1b429e2a Iustin Pop
      raise errors.ProgrammerError("Nested retry loop detected that didn't"
2615 1b429e2a Iustin Pop
                                   " handle RetryTimeout")
2616 de0ea66b Michael Hanselmann
2617 de0ea66b Michael Hanselmann
    remaining_time = end_time - _time_fn()
2618 de0ea66b Michael Hanselmann
2619 de0ea66b Michael Hanselmann
    if remaining_time < 0.0:
2620 de0ea66b Michael Hanselmann
      raise RetryTimeout()
2621 de0ea66b Michael Hanselmann
2622 de0ea66b Michael Hanselmann
    assert remaining_time >= 0.0
2623 de0ea66b Michael Hanselmann
2624 de0ea66b Michael Hanselmann
    if calc_delay is None:
2625 de0ea66b Michael Hanselmann
      wait_fn(remaining_time)
2626 de0ea66b Michael Hanselmann
    else:
2627 de0ea66b Michael Hanselmann
      current_delay = calc_delay()
2628 de0ea66b Michael Hanselmann
      if current_delay > 0.0:
2629 de0ea66b Michael Hanselmann
        wait_fn(current_delay)
2630 de0ea66b Michael Hanselmann
2631 de0ea66b Michael Hanselmann
2632 a87b4824 Michael Hanselmann
class FileLock(object):
2633 a87b4824 Michael Hanselmann
  """Utility class for file locks.
2634 a87b4824 Michael Hanselmann

2635 a87b4824 Michael Hanselmann
  """
2636 b4478d34 Michael Hanselmann
  def __init__(self, fd, filename):
2637 58885d79 Iustin Pop
    """Constructor for FileLock.
2638 58885d79 Iustin Pop

2639 b4478d34 Michael Hanselmann
    @type fd: file
2640 b4478d34 Michael Hanselmann
    @param fd: File object
2641 58885d79 Iustin Pop
    @type filename: str
2642 b4478d34 Michael Hanselmann
    @param filename: Path of the file opened at I{fd}
2643 58885d79 Iustin Pop

2644 58885d79 Iustin Pop
    """
2645 b4478d34 Michael Hanselmann
    self.fd = fd
2646 a87b4824 Michael Hanselmann
    self.filename = filename
2647 b4478d34 Michael Hanselmann
2648 b4478d34 Michael Hanselmann
  @classmethod
2649 b4478d34 Michael Hanselmann
  def Open(cls, filename):
2650 b4478d34 Michael Hanselmann
    """Creates and opens a file to be used as a file-based lock.
2651 b4478d34 Michael Hanselmann

2652 b4478d34 Michael Hanselmann
    @type filename: string
2653 b4478d34 Michael Hanselmann
    @param filename: path to the file to be locked
2654 b4478d34 Michael Hanselmann

2655 b4478d34 Michael Hanselmann
    """
2656 b4478d34 Michael Hanselmann
    # Using "os.open" is necessary to allow both opening existing file
2657 b4478d34 Michael Hanselmann
    # read/write and creating if not existing. Vanilla "open" will truncate an
2658 b4478d34 Michael Hanselmann
    # existing file -or- allow creating if not existing.
2659 b4478d34 Michael Hanselmann
    return cls(os.fdopen(os.open(filename, os.O_RDWR | os.O_CREAT), "w+"),
2660 b4478d34 Michael Hanselmann
               filename)
2661 a87b4824 Michael Hanselmann
2662 a87b4824 Michael Hanselmann
  def __del__(self):
2663 a87b4824 Michael Hanselmann
    self.Close()
2664 a87b4824 Michael Hanselmann
2665 a87b4824 Michael Hanselmann
  def Close(self):
2666 58885d79 Iustin Pop
    """Close the file and release the lock.
2667 58885d79 Iustin Pop

2668 58885d79 Iustin Pop
    """
2669 aac3fbf0 Iustin Pop
    if hasattr(self, "fd") and self.fd:
2670 a87b4824 Michael Hanselmann
      self.fd.close()
2671 a87b4824 Michael Hanselmann
      self.fd = None
2672 a87b4824 Michael Hanselmann
2673 aa74b828 Michael Hanselmann
  def _flock(self, flag, blocking, timeout, errmsg):
2674 aa74b828 Michael Hanselmann
    """Wrapper for fcntl.flock.
2675 aa74b828 Michael Hanselmann

2676 aa74b828 Michael Hanselmann
    @type flag: int
2677 58885d79 Iustin Pop
    @param flag: operation flag
2678 aa74b828 Michael Hanselmann
    @type blocking: bool
2679 58885d79 Iustin Pop
    @param blocking: whether the operation should be done in blocking mode.
2680 aa74b828 Michael Hanselmann
    @type timeout: None or float
2681 58885d79 Iustin Pop
    @param timeout: for how long the operation should be retried (implies
2682 aa74b828 Michael Hanselmann
                    non-blocking mode).
2683 aa74b828 Michael Hanselmann
    @type errmsg: string
2684 58885d79 Iustin Pop
    @param errmsg: error message in case operation fails.
2685 aa74b828 Michael Hanselmann

2686 aa74b828 Michael Hanselmann
    """
2687 a87b4824 Michael Hanselmann
    assert self.fd, "Lock was closed"
2688 aa74b828 Michael Hanselmann
    assert timeout is None or timeout >= 0, \
2689 aa74b828 Michael Hanselmann
      "If specified, timeout must be positive"
2690 cc4c9b91 Michael Hanselmann
    assert not (flag & fcntl.LOCK_NB), "LOCK_NB must not be set"
2691 a87b4824 Michael Hanselmann
2692 cc4c9b91 Michael Hanselmann
    # When a timeout is used, LOCK_NB must always be set
2693 cc4c9b91 Michael Hanselmann
    if not (timeout is None and blocking):
2694 a87b4824 Michael Hanselmann
      flag |= fcntl.LOCK_NB
2695 a87b4824 Michael Hanselmann
2696 cc4c9b91 Michael Hanselmann
    if timeout is None:
2697 cc4c9b91 Michael Hanselmann
      self._Lock(self.fd, flag, timeout)
2698 cc4c9b91 Michael Hanselmann
    else:
2699 cc4c9b91 Michael Hanselmann
      try:
2700 cc4c9b91 Michael Hanselmann
        Retry(self._Lock, (0.1, 1.2, 1.0), timeout,
2701 cc4c9b91 Michael Hanselmann
              args=(self.fd, flag, timeout))
2702 cc4c9b91 Michael Hanselmann
      except RetryTimeout:
2703 cc4c9b91 Michael Hanselmann
        raise errors.LockError(errmsg)
2704 aa74b828 Michael Hanselmann
2705 cc4c9b91 Michael Hanselmann
  @staticmethod
2706 cc4c9b91 Michael Hanselmann
  def _Lock(fd, flag, timeout):
2707 cc4c9b91 Michael Hanselmann
    try:
2708 cc4c9b91 Michael Hanselmann
      fcntl.flock(fd, flag)
2709 cc4c9b91 Michael Hanselmann
    except IOError, err:
2710 cc4c9b91 Michael Hanselmann
      if timeout is not None and err.errno == errno.EAGAIN:
2711 cc4c9b91 Michael Hanselmann
        raise RetryAgain()
2712 31892b4c Michael Hanselmann
2713 cc4c9b91 Michael Hanselmann
      logging.exception("fcntl.flock failed")
2714 cc4c9b91 Michael Hanselmann
      raise
2715 aa74b828 Michael Hanselmann
2716 aa74b828 Michael Hanselmann
  def Exclusive(self, blocking=False, timeout=None):
2717 a87b4824 Michael Hanselmann
    """Locks the file in exclusive mode.
2718 a87b4824 Michael Hanselmann

2719 58885d79 Iustin Pop
    @type blocking: boolean
2720 58885d79 Iustin Pop
    @param blocking: whether to block and wait until we
2721 58885d79 Iustin Pop
        can lock the file or return immediately
2722 58885d79 Iustin Pop
    @type timeout: int or None
2723 58885d79 Iustin Pop
    @param timeout: if not None, the duration to wait for the lock
2724 58885d79 Iustin Pop
        (in blocking mode)
2725 58885d79 Iustin Pop

2726 a87b4824 Michael Hanselmann
    """
2727 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_EX, blocking, timeout,
2728 a87b4824 Michael Hanselmann
                "Failed to lock %s in exclusive mode" % self.filename)
2729 a87b4824 Michael Hanselmann
2730 aa74b828 Michael Hanselmann
  def Shared(self, blocking=False, timeout=None):
2731 a87b4824 Michael Hanselmann
    """Locks the file in shared mode.
2732 a87b4824 Michael Hanselmann

2733 58885d79 Iustin Pop
    @type blocking: boolean
2734 58885d79 Iustin Pop
    @param blocking: whether to block and wait until we
2735 58885d79 Iustin Pop
        can lock the file or return immediately
2736 58885d79 Iustin Pop
    @type timeout: int or None
2737 58885d79 Iustin Pop
    @param timeout: if not None, the duration to wait for the lock
2738 58885d79 Iustin Pop
        (in blocking mode)
2739 58885d79 Iustin Pop

2740 a87b4824 Michael Hanselmann
    """
2741 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_SH, blocking, timeout,
2742 a87b4824 Michael Hanselmann
                "Failed to lock %s in shared mode" % self.filename)
2743 a87b4824 Michael Hanselmann
2744 aa74b828 Michael Hanselmann
  def Unlock(self, blocking=True, timeout=None):
2745 a87b4824 Michael Hanselmann
    """Unlocks the file.
2746 a87b4824 Michael Hanselmann

2747 58885d79 Iustin Pop
    According to C{flock(2)}, unlocking can also be a nonblocking
2748 58885d79 Iustin Pop
    operation::
2749 58885d79 Iustin Pop

2750 58885d79 Iustin Pop
      To make a non-blocking request, include LOCK_NB with any of the above
2751 58885d79 Iustin Pop
      operations.
2752 58885d79 Iustin Pop

2753 58885d79 Iustin Pop
    @type blocking: boolean
2754 58885d79 Iustin Pop
    @param blocking: whether to block and wait until we
2755 58885d79 Iustin Pop
        can lock the file or return immediately
2756 58885d79 Iustin Pop
    @type timeout: int or None
2757 58885d79 Iustin Pop
    @param timeout: if not None, the duration to wait for the lock
2758 58885d79 Iustin Pop
        (in blocking mode)
2759 a87b4824 Michael Hanselmann

2760 a87b4824 Michael Hanselmann
    """
2761 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_UN, blocking, timeout,
2762 a87b4824 Michael Hanselmann
                "Failed to unlock %s" % self.filename)
2763 a87b4824 Michael Hanselmann
2764 a87b4824 Michael Hanselmann
2765 339be5a8 Michael Hanselmann
class LineSplitter:
2766 339be5a8 Michael Hanselmann
  """Splits data chunks into lines separated by newline.
2767 339be5a8 Michael Hanselmann

2768 339be5a8 Michael Hanselmann
  Instances provide a file-like interface.
2769 339be5a8 Michael Hanselmann

2770 339be5a8 Michael Hanselmann
  """
2771 339be5a8 Michael Hanselmann
  def __init__(self, line_fn, *args):
2772 339be5a8 Michael Hanselmann
    """Initializes this class.
2773 339be5a8 Michael Hanselmann

2774 339be5a8 Michael Hanselmann
    @type line_fn: callable
2775 339be5a8 Michael Hanselmann
    @param line_fn: Function called for each line, first parameter is line
2776 339be5a8 Michael Hanselmann
    @param args: Extra arguments for L{line_fn}
2777 339be5a8 Michael Hanselmann

2778 339be5a8 Michael Hanselmann
    """
2779 339be5a8 Michael Hanselmann
    assert callable(line_fn)
2780 339be5a8 Michael Hanselmann
2781 339be5a8 Michael Hanselmann
    if args:
2782 339be5a8 Michael Hanselmann
      # Python 2.4 doesn't have functools.partial yet
2783 339be5a8 Michael Hanselmann
      self._line_fn = \
2784 339be5a8 Michael Hanselmann
        lambda line: line_fn(line, *args) # pylint: disable-msg=W0142
2785 339be5a8 Michael Hanselmann
    else:
2786 339be5a8 Michael Hanselmann
      self._line_fn = line_fn
2787 339be5a8 Michael Hanselmann
2788 339be5a8 Michael Hanselmann
    self._lines = collections.deque()
2789 339be5a8 Michael Hanselmann
    self._buffer = ""
2790 339be5a8 Michael Hanselmann
2791 339be5a8 Michael Hanselmann
  def write(self, data):
2792 339be5a8 Michael Hanselmann
    parts = (self._buffer + data).split("\n")
2793 339be5a8 Michael Hanselmann
    self._buffer = parts.pop()
2794 339be5a8 Michael Hanselmann
    self._lines.extend(parts)
2795 339be5a8 Michael Hanselmann
2796 339be5a8 Michael Hanselmann
  def flush(self):
2797 339be5a8 Michael Hanselmann
    while self._lines:
2798 339be5a8 Michael Hanselmann
      self._line_fn(self._lines.popleft().rstrip("\r\n"))
2799 339be5a8 Michael Hanselmann
2800 339be5a8 Michael Hanselmann
  def close(self):
2801 339be5a8 Michael Hanselmann
    self.flush()
2802 339be5a8 Michael Hanselmann
    if self._buffer:
2803 339be5a8 Michael Hanselmann
      self._line_fn(self._buffer)
2804 339be5a8 Michael Hanselmann
2805 339be5a8 Michael Hanselmann
2806 451575de Guido Trotter
def SignalHandled(signums):
2807 451575de Guido Trotter
  """Signal Handled decoration.
2808 451575de Guido Trotter

2809 451575de Guido Trotter
  This special decorator installs a signal handler and then calls the target
2810 451575de Guido Trotter
  function. The function must accept a 'signal_handlers' keyword argument,
2811 451575de Guido Trotter
  which will contain a dict indexed by signal number, with SignalHandler
2812 451575de Guido Trotter
  objects as values.
2813 451575de Guido Trotter

2814 451575de Guido Trotter
  The decorator can be safely stacked with iself, to handle multiple signals
2815 451575de Guido Trotter
  with different handlers.
2816 451575de Guido Trotter

2817 451575de Guido Trotter
  @type signums: list
2818 451575de Guido Trotter
  @param signums: signals to intercept
2819 451575de Guido Trotter

2820 451575de Guido Trotter
  """
2821 451575de Guido Trotter
  def wrap(fn):
2822 451575de Guido Trotter
    def sig_function(*args, **kwargs):
2823 451575de Guido Trotter
      assert 'signal_handlers' not in kwargs or \
2824 451575de Guido Trotter
             kwargs['signal_handlers'] is None or \
2825 451575de Guido Trotter
             isinstance(kwargs['signal_handlers'], dict), \
2826 451575de Guido Trotter
             "Wrong signal_handlers parameter in original function call"
2827 451575de Guido Trotter
      if 'signal_handlers' in kwargs and kwargs['signal_handlers'] is not None:
2828 451575de Guido Trotter
        signal_handlers = kwargs['signal_handlers']
2829 451575de Guido Trotter
      else:
2830 451575de Guido Trotter
        signal_handlers = {}
2831 451575de Guido Trotter
        kwargs['signal_handlers'] = signal_handlers
2832 451575de Guido Trotter
      sighandler = SignalHandler(signums)
2833 451575de Guido Trotter
      try:
2834 451575de Guido Trotter
        for sig in signums:
2835 451575de Guido Trotter
          signal_handlers[sig] = sighandler
2836 451575de Guido Trotter
        return fn(*args, **kwargs)
2837 451575de Guido Trotter
      finally:
2838 451575de Guido Trotter
        sighandler.Reset()
2839 451575de Guido Trotter
    return sig_function
2840 451575de Guido Trotter
  return wrap
2841 451575de Guido Trotter
2842 451575de Guido Trotter
2843 de499029 Michael Hanselmann
class SignalHandler(object):
2844 de499029 Michael Hanselmann
  """Generic signal handler class.
2845 de499029 Michael Hanselmann

2846 58885d79 Iustin Pop
  It automatically restores the original handler when deconstructed or
2847 58885d79 Iustin Pop
  when L{Reset} is called. You can either pass your own handler
2848 58885d79 Iustin Pop
  function in or query the L{called} attribute to detect whether the
2849 58885d79 Iustin Pop
  signal was sent.
2850 58885d79 Iustin Pop

2851 58885d79 Iustin Pop
  @type signum: list
2852 58885d79 Iustin Pop
  @ivar signum: the signals we handle
2853 58885d79 Iustin Pop
  @type called: boolean
2854 58885d79 Iustin Pop
  @ivar called: tracks whether any of the signals have been raised
2855 de499029 Michael Hanselmann

2856 de499029 Michael Hanselmann
  """
2857 de499029 Michael Hanselmann
  def __init__(self, signum):
2858 de499029 Michael Hanselmann
    """Constructs a new SignalHandler instance.
2859 de499029 Michael Hanselmann

2860 58885d79 Iustin Pop
    @type signum: int or list of ints
2861 de499029 Michael Hanselmann
    @param signum: Single signal number or set of signal numbers
2862 de499029 Michael Hanselmann

2863 de499029 Michael Hanselmann
    """
2864 6c52849e Guido Trotter
    self.signum = set(signum)
2865 de499029 Michael Hanselmann
    self.called = False
2866 de499029 Michael Hanselmann
2867 de499029 Michael Hanselmann
    self._previous = {}
2868 de499029 Michael Hanselmann
    try:
2869 de499029 Michael Hanselmann
      for signum in self.signum:
2870 de499029 Michael Hanselmann
        # Setup handler
2871 de499029 Michael Hanselmann
        prev_handler = signal.signal(signum, self._HandleSignal)
2872 de499029 Michael Hanselmann
        try:
2873 de499029 Michael Hanselmann
          self._previous[signum] = prev_handler
2874 de499029 Michael Hanselmann
        except:
2875 de499029 Michael Hanselmann
          # Restore previous handler
2876 de499029 Michael Hanselmann
          signal.signal(signum, prev_handler)
2877 de499029 Michael Hanselmann
          raise
2878 de499029 Michael Hanselmann
    except:
2879 de499029 Michael Hanselmann
      # Reset all handlers
2880 de499029 Michael Hanselmann
      self.Reset()
2881 de499029 Michael Hanselmann
      # Here we have a race condition: a handler may have already been called,
2882 de499029 Michael Hanselmann
      # but there's not much we can do about it at this point.
2883 de499029 Michael Hanselmann
      raise
2884 de499029 Michael Hanselmann
2885 de499029 Michael Hanselmann
  def __del__(self):
2886 de499029 Michael Hanselmann
    self.Reset()
2887 de499029 Michael Hanselmann
2888 de499029 Michael Hanselmann
  def Reset(self):
2889 de499029 Michael Hanselmann
    """Restore previous handler.
2890 de499029 Michael Hanselmann

2891 58885d79 Iustin Pop
    This will reset all the signals to their previous handlers.
2892 58885d79 Iustin Pop

2893 de499029 Michael Hanselmann
    """
2894 de499029 Michael Hanselmann
    for signum, prev_handler in self._previous.items():
2895 de499029 Michael Hanselmann
      signal.signal(signum, prev_handler)
2896 de499029 Michael Hanselmann
      # If successful, remove from dict
2897 de499029 Michael Hanselmann
      del self._previous[signum]
2898 de499029 Michael Hanselmann
2899 de499029 Michael Hanselmann
  def Clear(self):
2900 58885d79 Iustin Pop
    """Unsets the L{called} flag.
2901 de499029 Michael Hanselmann

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

2904 de499029 Michael Hanselmann
    """
2905 de499029 Michael Hanselmann
    self.called = False
2906 de499029 Michael Hanselmann
2907 2d54e29c Iustin Pop
  # we don't care about arguments, but we leave them named for the future
2908 2d54e29c Iustin Pop
  def _HandleSignal(self, signum, frame): # pylint: disable-msg=W0613
2909 de499029 Michael Hanselmann
    """Actual signal handling function.
2910 de499029 Michael Hanselmann

2911 de499029 Michael Hanselmann
    """
2912 de499029 Michael Hanselmann
    # This is not nice and not absolutely atomic, but it appears to be the only
2913 de499029 Michael Hanselmann
    # solution in Python -- there are no atomic types.
2914 de499029 Michael Hanselmann
    self.called = True
2915 a2d2e1a7 Iustin Pop
2916 a2d2e1a7 Iustin Pop
2917 a2d2e1a7 Iustin Pop
class FieldSet(object):
2918 a2d2e1a7 Iustin Pop
  """A simple field set.
2919 a2d2e1a7 Iustin Pop

2920 a2d2e1a7 Iustin Pop
  Among the features are:
2921 a2d2e1a7 Iustin Pop
    - checking if a string is among a list of static string or regex objects
2922 a2d2e1a7 Iustin Pop
    - checking if a whole list of string matches
2923 a2d2e1a7 Iustin Pop
    - returning the matching groups from a regex match
2924 a2d2e1a7 Iustin Pop

2925 a2d2e1a7 Iustin Pop
  Internally, all fields are held as regular expression objects.
2926 a2d2e1a7 Iustin Pop

2927 a2d2e1a7 Iustin Pop
  """
2928 a2d2e1a7 Iustin Pop
  def __init__(self, *items):
2929 a2d2e1a7 Iustin Pop
    self.items = [re.compile("^%s$" % value) for value in items]
2930 a2d2e1a7 Iustin Pop
2931 a2d2e1a7 Iustin Pop
  def Extend(self, other_set):
2932 a2d2e1a7 Iustin Pop
    """Extend the field set with the items from another one"""
2933 a2d2e1a7 Iustin Pop
    self.items.extend(other_set.items)
2934 a2d2e1a7 Iustin Pop
2935 a2d2e1a7 Iustin Pop
  def Matches(self, field):
2936 a2d2e1a7 Iustin Pop
    """Checks if a field matches the current set
2937 a2d2e1a7 Iustin Pop

2938 a2d2e1a7 Iustin Pop
    @type field: str
2939 a2d2e1a7 Iustin Pop
    @param field: the string to match
2940 6c881c52 Iustin Pop
    @return: either None or a regular expression match object
2941 a2d2e1a7 Iustin Pop

2942 a2d2e1a7 Iustin Pop
    """
2943 a2d2e1a7 Iustin Pop
    for m in itertools.ifilter(None, (val.match(field) for val in self.items)):
2944 a2d2e1a7 Iustin Pop
      return m
2945 6c881c52 Iustin Pop
    return None
2946 a2d2e1a7 Iustin Pop
2947 a2d2e1a7 Iustin Pop
  def NonMatching(self, items):
2948 a2d2e1a7 Iustin Pop
    """Returns the list of fields not matching the current set
2949 a2d2e1a7 Iustin Pop

2950 a2d2e1a7 Iustin Pop
    @type items: list
2951 a2d2e1a7 Iustin Pop
    @param items: the list of fields to check
2952 a2d2e1a7 Iustin Pop
    @rtype: list
2953 a2d2e1a7 Iustin Pop
    @return: list of non-matching fields
2954 a2d2e1a7 Iustin Pop

2955 a2d2e1a7 Iustin Pop
    """
2956 a2d2e1a7 Iustin Pop
    return [val for val in items if not self.Matches(val)]