Statistics
| Branch: | Tag: | Revision:

root / lib / utils.py @ cea881e5

History | View | Annotate | Download (78.7 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 dfdc4060 Guido Trotter
def SingleWaitForFdCondition(fdobj, event, timeout):
1491 dcd511c8 Guido Trotter
  """Waits for a condition to occur on the socket.
1492 dcd511c8 Guido Trotter

1493 dfdc4060 Guido Trotter
  Immediately returns at the first interruption.
1494 dfdc4060 Guido Trotter

1495 dfdc4060 Guido Trotter
  @type fdobj: integer or object supporting a fileno() method
1496 dfdc4060 Guido Trotter
  @param fdobj: entity to wait for events on
1497 dfdc4060 Guido Trotter
  @type event: integer
1498 dcd511c8 Guido Trotter
  @param event: ORed condition (see select module)
1499 dcd511c8 Guido Trotter
  @type timeout: float or None
1500 dcd511c8 Guido Trotter
  @param timeout: Timeout in seconds
1501 dcd511c8 Guido Trotter
  @rtype: int or None
1502 dcd511c8 Guido Trotter
  @return: None for timeout, otherwise occured conditions
1503 dcd511c8 Guido Trotter

1504 dcd511c8 Guido Trotter
  """
1505 dcd511c8 Guido Trotter
  check = (event | select.POLLPRI |
1506 dcd511c8 Guido Trotter
           select.POLLNVAL | select.POLLHUP | select.POLLERR)
1507 dcd511c8 Guido Trotter
1508 dcd511c8 Guido Trotter
  if timeout is not None:
1509 dcd511c8 Guido Trotter
    # Poller object expects milliseconds
1510 dcd511c8 Guido Trotter
    timeout *= 1000
1511 dcd511c8 Guido Trotter
1512 dcd511c8 Guido Trotter
  poller = select.poll()
1513 dfdc4060 Guido Trotter
  poller.register(fdobj, event)
1514 dcd511c8 Guido Trotter
  try:
1515 dfdc4060 Guido Trotter
    # TODO: If the main thread receives a signal and we have no timeout, we
1516 dfdc4060 Guido Trotter
    # could wait forever. This should check a global "quit" flag or something
1517 dfdc4060 Guido Trotter
    # every so often.
1518 dfdc4060 Guido Trotter
    io_events = poller.poll(timeout)
1519 dfdc4060 Guido Trotter
  except select.error, err:
1520 dfdc4060 Guido Trotter
    if err[0] != errno.EINTR:
1521 dfdc4060 Guido Trotter
      raise
1522 dfdc4060 Guido Trotter
    io_events = []
1523 dfdc4060 Guido Trotter
  if io_events and io_events[0][1] & check:
1524 dfdc4060 Guido Trotter
    return io_events[0][1]
1525 dfdc4060 Guido Trotter
  else:
1526 dfdc4060 Guido Trotter
    return None
1527 dfdc4060 Guido Trotter
1528 dfdc4060 Guido Trotter
1529 dfdc4060 Guido Trotter
class FdConditionWaiterHelper(object):
1530 dfdc4060 Guido Trotter
  """Retry helper for WaitForFdCondition.
1531 dfdc4060 Guido Trotter

1532 dfdc4060 Guido Trotter
  This class contains the retried and wait functions that make sure
1533 dfdc4060 Guido Trotter
  WaitForFdCondition can continue waiting until the timeout is actually
1534 dfdc4060 Guido Trotter
  expired.
1535 dfdc4060 Guido Trotter

1536 dfdc4060 Guido Trotter
  """
1537 dfdc4060 Guido Trotter
1538 dfdc4060 Guido Trotter
  def __init__(self, timeout):
1539 dfdc4060 Guido Trotter
    self.timeout = timeout
1540 dfdc4060 Guido Trotter
1541 dfdc4060 Guido Trotter
  def Poll(self, fdobj, event):
1542 dfdc4060 Guido Trotter
    result = SingleWaitForFdCondition(fdobj, event, self.timeout)
1543 dfdc4060 Guido Trotter
    if result is None:
1544 dfdc4060 Guido Trotter
      raise RetryAgain()
1545 dfdc4060 Guido Trotter
    else:
1546 dfdc4060 Guido Trotter
      return result
1547 dfdc4060 Guido Trotter
1548 dfdc4060 Guido Trotter
  def UpdateTimeout(self, timeout):
1549 dfdc4060 Guido Trotter
    self.timeout = timeout
1550 dfdc4060 Guido Trotter
1551 dfdc4060 Guido Trotter
1552 dfdc4060 Guido Trotter
def WaitForFdCondition(fdobj, event, timeout):
1553 dfdc4060 Guido Trotter
  """Waits for a condition to occur on the socket.
1554 dfdc4060 Guido Trotter

1555 dfdc4060 Guido Trotter
  Retries until the timeout is expired, even if interrupted.
1556 dfdc4060 Guido Trotter

1557 dfdc4060 Guido Trotter
  @type fdobj: integer or object supporting a fileno() method
1558 dfdc4060 Guido Trotter
  @param fdobj: entity to wait for events on
1559 dfdc4060 Guido Trotter
  @type event: integer
1560 dfdc4060 Guido Trotter
  @param event: ORed condition (see select module)
1561 dfdc4060 Guido Trotter
  @type timeout: float or None
1562 dfdc4060 Guido Trotter
  @param timeout: Timeout in seconds
1563 dfdc4060 Guido Trotter
  @rtype: int or None
1564 dfdc4060 Guido Trotter
  @return: None for timeout, otherwise occured conditions
1565 dfdc4060 Guido Trotter

1566 dfdc4060 Guido Trotter
  """
1567 dfdc4060 Guido Trotter
  if timeout is not None:
1568 dfdc4060 Guido Trotter
    retrywaiter = FdConditionWaiterHelper(timeout)
1569 1b429e2a Iustin Pop
    try:
1570 1b429e2a Iustin Pop
      result = Retry(retrywaiter.Poll, RETRY_REMAINING_TIME, timeout,
1571 1b429e2a Iustin Pop
                     args=(fdobj, event), wait_fn=retrywaiter.UpdateTimeout)
1572 1b429e2a Iustin Pop
    except RetryTimeout:
1573 1b429e2a Iustin Pop
      result = None
1574 dfdc4060 Guido Trotter
  else:
1575 dfdc4060 Guido Trotter
    result = None
1576 dfdc4060 Guido Trotter
    while result is None:
1577 dfdc4060 Guido Trotter
      result = SingleWaitForFdCondition(fdobj, event, timeout)
1578 dfdc4060 Guido Trotter
  return result
1579 dcd511c8 Guido Trotter
1580 dcd511c8 Guido Trotter
1581 f7414041 Michael Hanselmann
def UniqueSequence(seq):
1582 f7414041 Michael Hanselmann
  """Returns a list with unique elements.
1583 f7414041 Michael Hanselmann

1584 f7414041 Michael Hanselmann
  Element order is preserved.
1585 58885d79 Iustin Pop

1586 58885d79 Iustin Pop
  @type seq: sequence
1587 5bbd3f7f Michael Hanselmann
  @param seq: the sequence with the source elements
1588 58885d79 Iustin Pop
  @rtype: list
1589 58885d79 Iustin Pop
  @return: list of unique elements from seq
1590 58885d79 Iustin Pop

1591 f7414041 Michael Hanselmann
  """
1592 f7414041 Michael Hanselmann
  seen = set()
1593 f7414041 Michael Hanselmann
  return [i for i in seq if i not in seen and not seen.add(i)]
1594 1862d460 Alexander Schreiber
1595 1862d460 Alexander Schreiber
1596 82187135 Renรฉ Nussbaumer
def NormalizeAndValidateMac(mac):
1597 82187135 Renรฉ Nussbaumer
  """Normalizes and check if a MAC address is valid.
1598 1862d460 Alexander Schreiber

1599 5bbd3f7f Michael Hanselmann
  Checks whether the supplied MAC address is formally correct, only
1600 82187135 Renรฉ Nussbaumer
  accepts colon separated format. Normalize it to all lower.
1601 58885d79 Iustin Pop

1602 58885d79 Iustin Pop
  @type mac: str
1603 58885d79 Iustin Pop
  @param mac: the MAC to be validated
1604 82187135 Renรฉ Nussbaumer
  @rtype: str
1605 82187135 Renรฉ Nussbaumer
  @return: returns the normalized and validated MAC.
1606 82187135 Renรฉ Nussbaumer

1607 82187135 Renรฉ Nussbaumer
  @raise errors.OpPrereqError: If the MAC isn't valid
1608 58885d79 Iustin Pop

1609 1862d460 Alexander Schreiber
  """
1610 82187135 Renรฉ Nussbaumer
  mac_check = re.compile("^([0-9a-f]{2}(:|$)){6}$", re.I)
1611 82187135 Renรฉ Nussbaumer
  if not mac_check.match(mac):
1612 82187135 Renรฉ Nussbaumer
    raise errors.OpPrereqError("Invalid MAC address specified: %s" %
1613 82187135 Renรฉ Nussbaumer
                               mac, errors.ECODE_INVAL)
1614 82187135 Renรฉ Nussbaumer
1615 82187135 Renรฉ Nussbaumer
  return mac.lower()
1616 06009e27 Iustin Pop
1617 06009e27 Iustin Pop
1618 06009e27 Iustin Pop
def TestDelay(duration):
1619 06009e27 Iustin Pop
  """Sleep for a fixed amount of time.
1620 06009e27 Iustin Pop

1621 58885d79 Iustin Pop
  @type duration: float
1622 58885d79 Iustin Pop
  @param duration: the sleep duration
1623 58885d79 Iustin Pop
  @rtype: boolean
1624 58885d79 Iustin Pop
  @return: False for negative value, True otherwise
1625 58885d79 Iustin Pop

1626 06009e27 Iustin Pop
  """
1627 06009e27 Iustin Pop
  if duration < 0:
1628 38ea42a1 Iustin Pop
    return False, "Invalid sleep duration"
1629 06009e27 Iustin Pop
  time.sleep(duration)
1630 38ea42a1 Iustin Pop
  return True, None
1631 8f765069 Iustin Pop
1632 8f765069 Iustin Pop
1633 7d88772a Iustin Pop
def _CloseFDNoErr(fd, retries=5):
1634 7d88772a Iustin Pop
  """Close a file descriptor ignoring errors.
1635 8f765069 Iustin Pop

1636 7d88772a Iustin Pop
  @type fd: int
1637 7d88772a Iustin Pop
  @param fd: the file descriptor
1638 7d88772a Iustin Pop
  @type retries: int
1639 7d88772a Iustin Pop
  @param retries: how many retries to make, in case we get any
1640 7d88772a Iustin Pop
      other error than EBADF
1641 7d88772a Iustin Pop

1642 7d88772a Iustin Pop
  """
1643 7d88772a Iustin Pop
  try:
1644 7d88772a Iustin Pop
    os.close(fd)
1645 7d88772a Iustin Pop
  except OSError, err:
1646 7d88772a Iustin Pop
    if err.errno != errno.EBADF:
1647 7d88772a Iustin Pop
      if retries > 0:
1648 7d88772a Iustin Pop
        _CloseFDNoErr(fd, retries - 1)
1649 7d88772a Iustin Pop
    # else either it's closed already or we're out of retries, so we
1650 7d88772a Iustin Pop
    # ignore this and go on
1651 7d88772a Iustin Pop
1652 7d88772a Iustin Pop
1653 7d88772a Iustin Pop
def CloseFDs(noclose_fds=None):
1654 7d88772a Iustin Pop
  """Close file descriptors.
1655 7d88772a Iustin Pop

1656 7d88772a Iustin Pop
  This closes all file descriptors above 2 (i.e. except
1657 7d88772a Iustin Pop
  stdin/out/err).
1658 8f765069 Iustin Pop

1659 58885d79 Iustin Pop
  @type noclose_fds: list or None
1660 58885d79 Iustin Pop
  @param noclose_fds: if given, it denotes a list of file descriptor
1661 58885d79 Iustin Pop
      that should not be closed
1662 58885d79 Iustin Pop

1663 8f765069 Iustin Pop
  """
1664 8f765069 Iustin Pop
  # Default maximum for the number of available file descriptors.
1665 8f765069 Iustin Pop
  if 'SC_OPEN_MAX' in os.sysconf_names:
1666 8f765069 Iustin Pop
    try:
1667 8f765069 Iustin Pop
      MAXFD = os.sysconf('SC_OPEN_MAX')
1668 8f765069 Iustin Pop
      if MAXFD < 0:
1669 8f765069 Iustin Pop
        MAXFD = 1024
1670 8f765069 Iustin Pop
    except OSError:
1671 8f765069 Iustin Pop
      MAXFD = 1024
1672 8f765069 Iustin Pop
  else:
1673 8f765069 Iustin Pop
    MAXFD = 1024
1674 7d88772a Iustin Pop
  maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
1675 7d88772a Iustin Pop
  if (maxfd == resource.RLIM_INFINITY):
1676 7d88772a Iustin Pop
    maxfd = MAXFD
1677 7d88772a Iustin Pop
1678 7d88772a Iustin Pop
  # Iterate through and close all file descriptors (except the standard ones)
1679 7d88772a Iustin Pop
  for fd in range(3, maxfd):
1680 7d88772a Iustin Pop
    if noclose_fds and fd in noclose_fds:
1681 7d88772a Iustin Pop
      continue
1682 7d88772a Iustin Pop
    _CloseFDNoErr(fd)
1683 7d88772a Iustin Pop
1684 7d88772a Iustin Pop
1685 7d88772a Iustin Pop
def Daemonize(logfile):
1686 7d88772a Iustin Pop
  """Daemonize the current process.
1687 7d88772a Iustin Pop

1688 7d88772a Iustin Pop
  This detaches the current process from the controlling terminal and
1689 7d88772a Iustin Pop
  runs it in the background as a daemon.
1690 7d88772a Iustin Pop

1691 7d88772a Iustin Pop
  @type logfile: str
1692 7d88772a Iustin Pop
  @param logfile: the logfile to which we should redirect stdout/stderr
1693 7d88772a Iustin Pop
  @rtype: int
1694 5fcc718f Iustin Pop
  @return: the value zero
1695 7d88772a Iustin Pop

1696 7d88772a Iustin Pop
  """
1697 7260cfbe Iustin Pop
  # pylint: disable-msg=W0212
1698 7260cfbe Iustin Pop
  # yes, we really want os._exit
1699 7d88772a Iustin Pop
  UMASK = 077
1700 7d88772a Iustin Pop
  WORKDIR = "/"
1701 8f765069 Iustin Pop
1702 8f765069 Iustin Pop
  # this might fail
1703 8f765069 Iustin Pop
  pid = os.fork()
1704 8f765069 Iustin Pop
  if (pid == 0):  # The first child.
1705 8f765069 Iustin Pop
    os.setsid()
1706 8f765069 Iustin Pop
    # this might fail
1707 8f765069 Iustin Pop
    pid = os.fork() # Fork a second child.
1708 8f765069 Iustin Pop
    if (pid == 0):  # The second child.
1709 8f765069 Iustin Pop
      os.chdir(WORKDIR)
1710 8f765069 Iustin Pop
      os.umask(UMASK)
1711 8f765069 Iustin Pop
    else:
1712 8f765069 Iustin Pop
      # exit() or _exit()?  See below.
1713 8f765069 Iustin Pop
      os._exit(0) # Exit parent (the first child) of the second child.
1714 8f765069 Iustin Pop
  else:
1715 8f765069 Iustin Pop
    os._exit(0) # Exit parent of the first child.
1716 8f765069 Iustin Pop
1717 7d88772a Iustin Pop
  for fd in range(3):
1718 7d88772a Iustin Pop
    _CloseFDNoErr(fd)
1719 7d88772a Iustin Pop
  i = os.open("/dev/null", os.O_RDONLY) # stdin
1720 7d88772a Iustin Pop
  assert i == 0, "Can't close/reopen stdin"
1721 7d88772a Iustin Pop
  i = os.open(logfile, os.O_WRONLY|os.O_CREAT|os.O_APPEND, 0600) # stdout
1722 7d88772a Iustin Pop
  assert i == 1, "Can't close/reopen stdout"
1723 7d88772a Iustin Pop
  # Duplicate standard output to standard error.
1724 7d88772a Iustin Pop
  os.dup2(1, 2)
1725 8f765069 Iustin Pop
  return 0
1726 57c177af Iustin Pop
1727 57c177af Iustin Pop
1728 53beffbb Iustin Pop
def DaemonPidFileName(name):
1729 58885d79 Iustin Pop
  """Compute a ganeti pid file absolute path
1730 58885d79 Iustin Pop

1731 58885d79 Iustin Pop
  @type name: str
1732 58885d79 Iustin Pop
  @param name: the daemon name
1733 58885d79 Iustin Pop
  @rtype: str
1734 58885d79 Iustin Pop
  @return: the full path to the pidfile corresponding to the given
1735 58885d79 Iustin Pop
      daemon name
1736 b330ac0b Guido Trotter

1737 b330ac0b Guido Trotter
  """
1738 c4feafe8 Iustin Pop
  return PathJoin(constants.RUN_GANETI_DIR, "%s.pid" % name)
1739 b330ac0b Guido Trotter
1740 b330ac0b Guido Trotter
1741 2826b361 Guido Trotter
def EnsureDaemon(name):
1742 2826b361 Guido Trotter
  """Check for and start daemon if not alive.
1743 2826b361 Guido Trotter

1744 2826b361 Guido Trotter
  """
1745 2826b361 Guido Trotter
  result = RunCmd([constants.DAEMON_UTIL, "check-and-start", name])
1746 2826b361 Guido Trotter
  if result.failed:
1747 2826b361 Guido Trotter
    logging.error("Can't start daemon '%s', failure %s, output: %s",
1748 2826b361 Guido Trotter
                  name, result.fail_reason, result.output)
1749 2826b361 Guido Trotter
    return False
1750 2826b361 Guido Trotter
1751 2826b361 Guido Trotter
  return True
1752 2826b361 Guido Trotter
1753 2826b361 Guido Trotter
1754 b330ac0b Guido Trotter
def WritePidFile(name):
1755 b330ac0b Guido Trotter
  """Write the current process pidfile.
1756 b330ac0b Guido Trotter

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

1759 58885d79 Iustin Pop
  @type name: str
1760 58885d79 Iustin Pop
  @param name: the daemon name to use
1761 58885d79 Iustin Pop
  @raise errors.GenericError: if the pid file already exists and
1762 58885d79 Iustin Pop
      points to a live process
1763 b330ac0b Guido Trotter

1764 b330ac0b Guido Trotter
  """
1765 b330ac0b Guido Trotter
  pid = os.getpid()
1766 53beffbb Iustin Pop
  pidfilename = DaemonPidFileName(name)
1767 d9f311d7 Iustin Pop
  if IsProcessAlive(ReadPidFile(pidfilename)):
1768 533bb4b1 Michael Hanselmann
    raise errors.GenericError("%s contains a live process" % pidfilename)
1769 b330ac0b Guido Trotter
1770 b330ac0b Guido Trotter
  WriteFile(pidfilename, data="%d\n" % pid)
1771 b330ac0b Guido Trotter
1772 b330ac0b Guido Trotter
1773 b330ac0b Guido Trotter
def RemovePidFile(name):
1774 b330ac0b Guido Trotter
  """Remove the current process pidfile.
1775 b330ac0b Guido Trotter

1776 b330ac0b Guido Trotter
  Any errors are ignored.
1777 b330ac0b Guido Trotter

1778 58885d79 Iustin Pop
  @type name: str
1779 58885d79 Iustin Pop
  @param name: the daemon name used to derive the pidfile name
1780 58885d79 Iustin Pop

1781 b330ac0b Guido Trotter
  """
1782 53beffbb Iustin Pop
  pidfilename = DaemonPidFileName(name)
1783 b330ac0b Guido Trotter
  # TODO: we could check here that the file contains our pid
1784 b330ac0b Guido Trotter
  try:
1785 b330ac0b Guido Trotter
    RemoveFile(pidfilename)
1786 7260cfbe Iustin Pop
  except: # pylint: disable-msg=W0702
1787 b330ac0b Guido Trotter
    pass
1788 b330ac0b Guido Trotter
1789 b330ac0b Guido Trotter
1790 ff5251bc Iustin Pop
def KillProcess(pid, signal_=signal.SIGTERM, timeout=30,
1791 ff5251bc Iustin Pop
                waitpid=False):
1792 b2a1f511 Iustin Pop
  """Kill a process given by its pid.
1793 b2a1f511 Iustin Pop

1794 b2a1f511 Iustin Pop
  @type pid: int
1795 b2a1f511 Iustin Pop
  @param pid: The PID to terminate.
1796 38206f3c Iustin Pop
  @type signal_: int
1797 38206f3c Iustin Pop
  @param signal_: The signal to send, by default SIGTERM
1798 b2a1f511 Iustin Pop
  @type timeout: int
1799 b2a1f511 Iustin Pop
  @param timeout: The timeout after which, if the process is still alive,
1800 b2a1f511 Iustin Pop
                  a SIGKILL will be sent. If not positive, no such checking
1801 b2a1f511 Iustin Pop
                  will be done
1802 ff5251bc Iustin Pop
  @type waitpid: boolean
1803 ff5251bc Iustin Pop
  @param waitpid: If true, we should waitpid on this process after
1804 ff5251bc Iustin Pop
      sending signals, since it's our own child and otherwise it
1805 ff5251bc Iustin Pop
      would remain as zombie
1806 b2a1f511 Iustin Pop

1807 b2a1f511 Iustin Pop
  """
1808 ff5251bc Iustin Pop
  def _helper(pid, signal_, wait):
1809 ff5251bc Iustin Pop
    """Simple helper to encapsulate the kill/waitpid sequence"""
1810 ff5251bc Iustin Pop
    os.kill(pid, signal_)
1811 ff5251bc Iustin Pop
    if wait:
1812 ff5251bc Iustin Pop
      try:
1813 ff5251bc Iustin Pop
        os.waitpid(pid, os.WNOHANG)
1814 ff5251bc Iustin Pop
      except OSError:
1815 ff5251bc Iustin Pop
        pass
1816 ff5251bc Iustin Pop
1817 b2a1f511 Iustin Pop
  if pid <= 0:
1818 b2a1f511 Iustin Pop
    # kill with pid=0 == suicide
1819 b2a1f511 Iustin Pop
    raise errors.ProgrammerError("Invalid pid given '%s'" % pid)
1820 b2a1f511 Iustin Pop
1821 b2a1f511 Iustin Pop
  if not IsProcessAlive(pid):
1822 b2a1f511 Iustin Pop
    return
1823 31892b4c Michael Hanselmann
1824 ff5251bc Iustin Pop
  _helper(pid, signal_, waitpid)
1825 31892b4c Michael Hanselmann
1826 b2a1f511 Iustin Pop
  if timeout <= 0:
1827 b2a1f511 Iustin Pop
    return
1828 7167159a Michael Hanselmann
1829 31892b4c Michael Hanselmann
  def _CheckProcess():
1830 31892b4c Michael Hanselmann
    if not IsProcessAlive(pid):
1831 31892b4c Michael Hanselmann
      return
1832 31892b4c Michael Hanselmann
1833 7167159a Michael Hanselmann
    try:
1834 7167159a Michael Hanselmann
      (result_pid, _) = os.waitpid(pid, os.WNOHANG)
1835 7167159a Michael Hanselmann
    except OSError:
1836 31892b4c Michael Hanselmann
      raise RetryAgain()
1837 31892b4c Michael Hanselmann
1838 31892b4c Michael Hanselmann
    if result_pid > 0:
1839 31892b4c Michael Hanselmann
      return
1840 31892b4c Michael Hanselmann
1841 31892b4c Michael Hanselmann
    raise RetryAgain()
1842 31892b4c Michael Hanselmann
1843 31892b4c Michael Hanselmann
  try:
1844 31892b4c Michael Hanselmann
    # Wait up to $timeout seconds
1845 31892b4c Michael Hanselmann
    Retry(_CheckProcess, (0.01, 1.5, 0.1), timeout)
1846 31892b4c Michael Hanselmann
  except RetryTimeout:
1847 31892b4c Michael Hanselmann
    pass
1848 7167159a Michael Hanselmann
1849 b2a1f511 Iustin Pop
  if IsProcessAlive(pid):
1850 7167159a Michael Hanselmann
    # Kill process if it's still alive
1851 e1bd0072 Iustin Pop
    _helper(pid, signal.SIGKILL, waitpid)
1852 b2a1f511 Iustin Pop
1853 b2a1f511 Iustin Pop
1854 57c177af Iustin Pop
def FindFile(name, search_path, test=os.path.exists):
1855 57c177af Iustin Pop
  """Look for a filesystem object in a given path.
1856 57c177af Iustin Pop

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

1860 58885d79 Iustin Pop
  @type name: str
1861 58885d79 Iustin Pop
  @param name: the name to look for
1862 58885d79 Iustin Pop
  @type search_path: str
1863 58885d79 Iustin Pop
  @param search_path: location to start at
1864 58885d79 Iustin Pop
  @type test: callable
1865 58885d79 Iustin Pop
  @param test: a function taking one argument that should return True
1866 58885d79 Iustin Pop
      if the a given object is valid; the default value is
1867 58885d79 Iustin Pop
      os.path.exists, causing only existing files to be returned
1868 58885d79 Iustin Pop
  @rtype: str or None
1869 58885d79 Iustin Pop
  @return: full path to the object if found, None otherwise
1870 57c177af Iustin Pop

1871 57c177af Iustin Pop
  """
1872 f95c81bf Iustin Pop
  # validate the filename mask
1873 f95c81bf Iustin Pop
  if constants.EXT_PLUGIN_MASK.match(name) is None:
1874 f95c81bf Iustin Pop
    logging.critical("Invalid value passed for external script name: '%s'",
1875 f95c81bf Iustin Pop
                     name)
1876 f95c81bf Iustin Pop
    return None
1877 f95c81bf Iustin Pop
1878 57c177af Iustin Pop
  for dir_name in search_path:
1879 e02b9114 Iustin Pop
    # FIXME: investigate switch to PathJoin
1880 57c177af Iustin Pop
    item_name = os.path.sep.join([dir_name, name])
1881 f95c81bf Iustin Pop
    # check the user test and that we're indeed resolving to the given
1882 f95c81bf Iustin Pop
    # basename
1883 f95c81bf Iustin Pop
    if test(item_name) and os.path.basename(item_name) == name:
1884 57c177af Iustin Pop
      return item_name
1885 57c177af Iustin Pop
  return None
1886 8d1a2a64 Michael Hanselmann
1887 8d1a2a64 Michael Hanselmann
1888 8d1a2a64 Michael Hanselmann
def CheckVolumeGroupSize(vglist, vgname, minsize):
1889 8d1a2a64 Michael Hanselmann
  """Checks if the volume group list is valid.
1890 8d1a2a64 Michael Hanselmann

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

1894 58885d79 Iustin Pop
  @type vglist: dict
1895 58885d79 Iustin Pop
  @param vglist: dictionary of volume group names and their size
1896 58885d79 Iustin Pop
  @type vgname: str
1897 58885d79 Iustin Pop
  @param vgname: the volume group we should check
1898 58885d79 Iustin Pop
  @type minsize: int
1899 58885d79 Iustin Pop
  @param minsize: the minimum size we accept
1900 58885d79 Iustin Pop
  @rtype: None or str
1901 58885d79 Iustin Pop
  @return: None for success, otherwise the error message
1902 8d1a2a64 Michael Hanselmann

1903 8d1a2a64 Michael Hanselmann
  """
1904 8d1a2a64 Michael Hanselmann
  vgsize = vglist.get(vgname, None)
1905 8d1a2a64 Michael Hanselmann
  if vgsize is None:
1906 8d1a2a64 Michael Hanselmann
    return "volume group '%s' missing" % vgname
1907 8d1a2a64 Michael Hanselmann
  elif vgsize < minsize:
1908 8d1a2a64 Michael Hanselmann
    return ("volume group '%s' too small (%s MiB required, %d MiB found)" %
1909 8d1a2a64 Michael Hanselmann
            (vgname, minsize, vgsize))
1910 8d1a2a64 Michael Hanselmann
  return None
1911 7996a135 Iustin Pop
1912 7996a135 Iustin Pop
1913 45bc5e4a Michael Hanselmann
def SplitTime(value):
1914 739be818 Michael Hanselmann
  """Splits time as floating point number into a tuple.
1915 739be818 Michael Hanselmann

1916 45bc5e4a Michael Hanselmann
  @param value: Time in seconds
1917 45bc5e4a Michael Hanselmann
  @type value: int or float
1918 45bc5e4a Michael Hanselmann
  @return: Tuple containing (seconds, microseconds)
1919 739be818 Michael Hanselmann

1920 739be818 Michael Hanselmann
  """
1921 45bc5e4a Michael Hanselmann
  (seconds, microseconds) = divmod(int(value * 1000000), 1000000)
1922 45bc5e4a Michael Hanselmann
1923 45bc5e4a Michael Hanselmann
  assert 0 <= seconds, \
1924 45bc5e4a Michael Hanselmann
    "Seconds must be larger than or equal to 0, but are %s" % seconds
1925 45bc5e4a Michael Hanselmann
  assert 0 <= microseconds <= 999999, \
1926 45bc5e4a Michael Hanselmann
    "Microseconds must be 0-999999, but are %s" % microseconds
1927 45bc5e4a Michael Hanselmann
1928 45bc5e4a Michael Hanselmann
  return (int(seconds), int(microseconds))
1929 739be818 Michael Hanselmann
1930 739be818 Michael Hanselmann
1931 739be818 Michael Hanselmann
def MergeTime(timetuple):
1932 739be818 Michael Hanselmann
  """Merges a tuple into time as a floating point number.
1933 739be818 Michael Hanselmann

1934 45bc5e4a Michael Hanselmann
  @param timetuple: Time as tuple, (seconds, microseconds)
1935 739be818 Michael Hanselmann
  @type timetuple: tuple
1936 739be818 Michael Hanselmann
  @return: Time as a floating point number expressed in seconds
1937 739be818 Michael Hanselmann

1938 739be818 Michael Hanselmann
  """
1939 45bc5e4a Michael Hanselmann
  (seconds, microseconds) = timetuple
1940 739be818 Michael Hanselmann
1941 45bc5e4a Michael Hanselmann
  assert 0 <= seconds, \
1942 45bc5e4a Michael Hanselmann
    "Seconds must be larger than or equal to 0, but are %s" % seconds
1943 45bc5e4a Michael Hanselmann
  assert 0 <= microseconds <= 999999, \
1944 45bc5e4a Michael Hanselmann
    "Microseconds must be 0-999999, but are %s" % microseconds
1945 739be818 Michael Hanselmann
1946 45bc5e4a Michael Hanselmann
  return float(seconds) + (float(microseconds) * 0.000001)
1947 739be818 Michael Hanselmann
1948 739be818 Michael Hanselmann
1949 cd50653c Guido Trotter
def GetDaemonPort(daemon_name):
1950 cd50653c Guido Trotter
  """Get the daemon port for this cluster.
1951 4a8b186a Michael Hanselmann

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

1956 cd50653c Guido Trotter
  @type daemon_name: string
1957 cd50653c Guido Trotter
  @param daemon_name: daemon name (in constants.DAEMONS_PORTS)
1958 58885d79 Iustin Pop
  @rtype: int
1959 58885d79 Iustin Pop

1960 4a8b186a Michael Hanselmann
  """
1961 cd50653c Guido Trotter
  if daemon_name not in constants.DAEMONS_PORTS:
1962 cd50653c Guido Trotter
    raise errors.ProgrammerError("Unknown daemon: %s" % daemon_name)
1963 cd50653c Guido Trotter
1964 cd50653c Guido Trotter
  (proto, default_port) = constants.DAEMONS_PORTS[daemon_name]
1965 4a8b186a Michael Hanselmann
  try:
1966 cd50653c Guido Trotter
    port = socket.getservbyname(daemon_name, proto)
1967 4a8b186a Michael Hanselmann
  except socket.error:
1968 cd50653c Guido Trotter
    port = default_port
1969 4a8b186a Michael Hanselmann
1970 4a8b186a Michael Hanselmann
  return port
1971 4a8b186a Michael Hanselmann
1972 4a8b186a Michael Hanselmann
1973 ea34193f Iustin Pop
def SetupLogging(logfile, debug=0, stderr_logging=False, program="",
1974 551b6283 Iustin Pop
                 multithreaded=False, syslog=constants.SYSLOG_USAGE):
1975 82d9caef Iustin Pop
  """Configures the logging module.
1976 82d9caef Iustin Pop

1977 58885d79 Iustin Pop
  @type logfile: str
1978 58885d79 Iustin Pop
  @param logfile: the filename to which we should log
1979 ea34193f Iustin Pop
  @type debug: integer
1980 ea34193f Iustin Pop
  @param debug: if greater than zero, enable debug messages, otherwise
1981 58885d79 Iustin Pop
      only those at C{INFO} and above level
1982 58885d79 Iustin Pop
  @type stderr_logging: boolean
1983 58885d79 Iustin Pop
  @param stderr_logging: whether we should also log to the standard error
1984 58885d79 Iustin Pop
  @type program: str
1985 58885d79 Iustin Pop
  @param program: the name under which we should log messages
1986 d21d09d6 Iustin Pop
  @type multithreaded: boolean
1987 d21d09d6 Iustin Pop
  @param multithreaded: if True, will add the thread name to the log file
1988 551b6283 Iustin Pop
  @type syslog: string
1989 551b6283 Iustin Pop
  @param syslog: one of 'no', 'yes', 'only':
1990 551b6283 Iustin Pop
      - if no, syslog is not used
1991 551b6283 Iustin Pop
      - if yes, syslog is used (in addition to file-logging)
1992 551b6283 Iustin Pop
      - if only, only syslog is used
1993 58885d79 Iustin Pop
  @raise EnvironmentError: if we can't open the log file and
1994 551b6283 Iustin Pop
      syslog/stderr logging is disabled
1995 58885d79 Iustin Pop

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

2062 da961187 Guido Trotter
  This avoids things like /dir/../../other/path to be valid.
2063 da961187 Guido Trotter

2064 da961187 Guido Trotter
  """
2065 da961187 Guido Trotter
  return os.path.normpath(path) == path and os.path.isabs(path)
2066 82d9caef Iustin Pop
2067 016d04b3 Michael Hanselmann
2068 4bb678e9 Iustin Pop
def PathJoin(*args):
2069 4bb678e9 Iustin Pop
  """Safe-join a list of path components.
2070 4bb678e9 Iustin Pop

2071 4bb678e9 Iustin Pop
  Requirements:
2072 4bb678e9 Iustin Pop
      - the first argument must be an absolute path
2073 4bb678e9 Iustin Pop
      - no component in the path must have backtracking (e.g. /../),
2074 4bb678e9 Iustin Pop
        since we check for normalization at the end
2075 4bb678e9 Iustin Pop

2076 4bb678e9 Iustin Pop
  @param args: the path components to be joined
2077 4bb678e9 Iustin Pop
  @raise ValueError: for invalid paths
2078 4bb678e9 Iustin Pop

2079 4bb678e9 Iustin Pop
  """
2080 4bb678e9 Iustin Pop
  # ensure we're having at least one path passed in
2081 4bb678e9 Iustin Pop
  assert args
2082 4bb678e9 Iustin Pop
  # ensure the first component is an absolute and normalized path name
2083 4bb678e9 Iustin Pop
  root = args[0]
2084 4bb678e9 Iustin Pop
  if not IsNormAbsPath(root):
2085 4bb678e9 Iustin Pop
    raise ValueError("Invalid parameter to PathJoin: '%s'" % str(args[0]))
2086 4bb678e9 Iustin Pop
  result = os.path.join(*args)
2087 4bb678e9 Iustin Pop
  # ensure that the whole path is normalized
2088 4bb678e9 Iustin Pop
  if not IsNormAbsPath(result):
2089 4bb678e9 Iustin Pop
    raise ValueError("Invalid parameters to PathJoin: '%s'" % str(args))
2090 4bb678e9 Iustin Pop
  # check that we're still under the original prefix
2091 4bb678e9 Iustin Pop
  prefix = os.path.commonprefix([root, result])
2092 4bb678e9 Iustin Pop
  if prefix != root:
2093 4bb678e9 Iustin Pop
    raise ValueError("Error: path joining resulted in different prefix"
2094 4bb678e9 Iustin Pop
                     " (%s != %s)" % (prefix, root))
2095 4bb678e9 Iustin Pop
  return result
2096 4bb678e9 Iustin Pop
2097 4bb678e9 Iustin Pop
2098 f65f63ef Iustin Pop
def TailFile(fname, lines=20):
2099 f65f63ef Iustin Pop
  """Return the last lines from a file.
2100 f65f63ef Iustin Pop

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

2105 f65f63ef Iustin Pop
  @param fname: the file name
2106 f65f63ef Iustin Pop
  @type lines: int
2107 f65f63ef Iustin Pop
  @param lines: the (maximum) number of lines to return
2108 f65f63ef Iustin Pop

2109 f65f63ef Iustin Pop
  """
2110 f65f63ef Iustin Pop
  fd = open(fname, "r")
2111 f65f63ef Iustin Pop
  try:
2112 f65f63ef Iustin Pop
    fd.seek(0, 2)
2113 f65f63ef Iustin Pop
    pos = fd.tell()
2114 f65f63ef Iustin Pop
    pos = max(0, pos-4096)
2115 f65f63ef Iustin Pop
    fd.seek(pos, 0)
2116 f65f63ef Iustin Pop
    raw_data = fd.read()
2117 f65f63ef Iustin Pop
  finally:
2118 f65f63ef Iustin Pop
    fd.close()
2119 f65f63ef Iustin Pop
2120 f65f63ef Iustin Pop
  rows = raw_data.splitlines()
2121 f65f63ef Iustin Pop
  return rows[-lines:]
2122 f65f63ef Iustin Pop
2123 f65f63ef Iustin Pop
2124 27e46076 Michael Hanselmann
def _ParseAsn1Generalizedtime(value):
2125 27e46076 Michael Hanselmann
  """Parses an ASN1 GENERALIZEDTIME timestamp as used by pyOpenSSL.
2126 27e46076 Michael Hanselmann

2127 27e46076 Michael Hanselmann
  @type value: string
2128 27e46076 Michael Hanselmann
  @param value: ASN1 GENERALIZEDTIME timestamp
2129 27e46076 Michael Hanselmann

2130 27e46076 Michael Hanselmann
  """
2131 27e46076 Michael Hanselmann
  m = re.match(r"^(\d+)([-+]\d\d)(\d\d)$", value)
2132 27e46076 Michael Hanselmann
  if m:
2133 27e46076 Michael Hanselmann
    # We have an offset
2134 27e46076 Michael Hanselmann
    asn1time = m.group(1)
2135 27e46076 Michael Hanselmann
    hours = int(m.group(2))
2136 27e46076 Michael Hanselmann
    minutes = int(m.group(3))
2137 27e46076 Michael Hanselmann
    utcoffset = (60 * hours) + minutes
2138 27e46076 Michael Hanselmann
  else:
2139 27e46076 Michael Hanselmann
    if not value.endswith("Z"):
2140 27e46076 Michael Hanselmann
      raise ValueError("Missing timezone")
2141 27e46076 Michael Hanselmann
    asn1time = value[:-1]
2142 27e46076 Michael Hanselmann
    utcoffset = 0
2143 27e46076 Michael Hanselmann
2144 27e46076 Michael Hanselmann
  parsed = time.strptime(asn1time, "%Y%m%d%H%M%S")
2145 27e46076 Michael Hanselmann
2146 27e46076 Michael Hanselmann
  tt = datetime.datetime(*(parsed[:7])) - datetime.timedelta(minutes=utcoffset)
2147 27e46076 Michael Hanselmann
2148 27e46076 Michael Hanselmann
  return calendar.timegm(tt.utctimetuple())
2149 27e46076 Michael Hanselmann
2150 27e46076 Michael Hanselmann
2151 27e46076 Michael Hanselmann
def GetX509CertValidity(cert):
2152 27e46076 Michael Hanselmann
  """Returns the validity period of the certificate.
2153 27e46076 Michael Hanselmann

2154 27e46076 Michael Hanselmann
  @type cert: OpenSSL.crypto.X509
2155 27e46076 Michael Hanselmann
  @param cert: X509 certificate object
2156 27e46076 Michael Hanselmann

2157 27e46076 Michael Hanselmann
  """
2158 27e46076 Michael Hanselmann
  # The get_notBefore and get_notAfter functions are only supported in
2159 27e46076 Michael Hanselmann
  # pyOpenSSL 0.7 and above.
2160 27e46076 Michael Hanselmann
  try:
2161 27e46076 Michael Hanselmann
    get_notbefore_fn = cert.get_notBefore
2162 27e46076 Michael Hanselmann
  except AttributeError:
2163 27e46076 Michael Hanselmann
    not_before = None
2164 27e46076 Michael Hanselmann
  else:
2165 27e46076 Michael Hanselmann
    not_before_asn1 = get_notbefore_fn()
2166 27e46076 Michael Hanselmann
2167 27e46076 Michael Hanselmann
    if not_before_asn1 is None:
2168 27e46076 Michael Hanselmann
      not_before = None
2169 27e46076 Michael Hanselmann
    else:
2170 27e46076 Michael Hanselmann
      not_before = _ParseAsn1Generalizedtime(not_before_asn1)
2171 27e46076 Michael Hanselmann
2172 27e46076 Michael Hanselmann
  try:
2173 27e46076 Michael Hanselmann
    get_notafter_fn = cert.get_notAfter
2174 27e46076 Michael Hanselmann
  except AttributeError:
2175 27e46076 Michael Hanselmann
    not_after = None
2176 27e46076 Michael Hanselmann
  else:
2177 27e46076 Michael Hanselmann
    not_after_asn1 = get_notafter_fn()
2178 27e46076 Michael Hanselmann
2179 27e46076 Michael Hanselmann
    if not_after_asn1 is None:
2180 27e46076 Michael Hanselmann
      not_after = None
2181 27e46076 Michael Hanselmann
    else:
2182 27e46076 Michael Hanselmann
      not_after = _ParseAsn1Generalizedtime(not_after_asn1)
2183 27e46076 Michael Hanselmann
2184 27e46076 Michael Hanselmann
  return (not_before, not_after)
2185 27e46076 Michael Hanselmann
2186 27e46076 Michael Hanselmann
2187 26f15862 Iustin Pop
def SafeEncode(text):
2188 26f15862 Iustin Pop
  """Return a 'safe' version of a source string.
2189 26f15862 Iustin Pop

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

2199 26f15862 Iustin Pop
  @type text: str or unicode
2200 26f15862 Iustin Pop
  @param text: input data
2201 26f15862 Iustin Pop
  @rtype: str
2202 26f15862 Iustin Pop
  @return: a safe version of text
2203 26f15862 Iustin Pop

2204 26f15862 Iustin Pop
  """
2205 d392fa34 Iustin Pop
  if isinstance(text, unicode):
2206 5bbd3f7f Michael Hanselmann
    # only if unicode; if str already, we handle it below
2207 d392fa34 Iustin Pop
    text = text.encode('ascii', 'backslashreplace')
2208 d392fa34 Iustin Pop
  resu = ""
2209 d392fa34 Iustin Pop
  for char in text:
2210 d392fa34 Iustin Pop
    c = ord(char)
2211 d392fa34 Iustin Pop
    if char  == '\t':
2212 d392fa34 Iustin Pop
      resu += r'\t'
2213 d392fa34 Iustin Pop
    elif char == '\n':
2214 d392fa34 Iustin Pop
      resu += r'\n'
2215 d392fa34 Iustin Pop
    elif char == '\r':
2216 d392fa34 Iustin Pop
      resu += r'\'r'
2217 d392fa34 Iustin Pop
    elif c < 32 or c >= 127: # non-printable
2218 d392fa34 Iustin Pop
      resu += "\\x%02x" % (c & 0xff)
2219 d392fa34 Iustin Pop
    else:
2220 d392fa34 Iustin Pop
      resu += char
2221 d392fa34 Iustin Pop
  return resu
2222 26f15862 Iustin Pop
2223 26f15862 Iustin Pop
2224 5b69bc7c Iustin Pop
def UnescapeAndSplit(text, sep=","):
2225 5b69bc7c Iustin Pop
  """Split and unescape a string based on a given separator.
2226 5b69bc7c Iustin Pop

2227 5b69bc7c Iustin Pop
  This function splits a string based on a separator where the
2228 5b69bc7c Iustin Pop
  separator itself can be escape in order to be an element of the
2229 5b69bc7c Iustin Pop
  elements. The escaping rules are (assuming coma being the
2230 5b69bc7c Iustin Pop
  separator):
2231 5b69bc7c Iustin Pop
    - a plain , separates the elements
2232 5b69bc7c Iustin Pop
    - a sequence \\\\, (double backslash plus comma) is handled as a
2233 5b69bc7c Iustin Pop
      backslash plus a separator comma
2234 5b69bc7c Iustin Pop
    - a sequence \, (backslash plus comma) is handled as a
2235 5b69bc7c Iustin Pop
      non-separator comma
2236 5b69bc7c Iustin Pop

2237 5b69bc7c Iustin Pop
  @type text: string
2238 5b69bc7c Iustin Pop
  @param text: the string to split
2239 5b69bc7c Iustin Pop
  @type sep: string
2240 5b69bc7c Iustin Pop
  @param text: the separator
2241 5b69bc7c Iustin Pop
  @rtype: string
2242 5b69bc7c Iustin Pop
  @return: a list of strings
2243 5b69bc7c Iustin Pop

2244 5b69bc7c Iustin Pop
  """
2245 5b69bc7c Iustin Pop
  # we split the list by sep (with no escaping at this stage)
2246 5b69bc7c Iustin Pop
  slist = text.split(sep)
2247 5b69bc7c Iustin Pop
  # next, we revisit the elements and if any of them ended with an odd
2248 5b69bc7c Iustin Pop
  # number of backslashes, then we join it with the next
2249 5b69bc7c Iustin Pop
  rlist = []
2250 5b69bc7c Iustin Pop
  while slist:
2251 5b69bc7c Iustin Pop
    e1 = slist.pop(0)
2252 5b69bc7c Iustin Pop
    if e1.endswith("\\"):
2253 5b69bc7c Iustin Pop
      num_b = len(e1) - len(e1.rstrip("\\"))
2254 5b69bc7c Iustin Pop
      if num_b % 2 == 1:
2255 5b69bc7c Iustin Pop
        e2 = slist.pop(0)
2256 5b69bc7c Iustin Pop
        # here the backslashes remain (all), and will be reduced in
2257 5b69bc7c Iustin Pop
        # the next step
2258 5b69bc7c Iustin Pop
        rlist.append(e1 + sep + e2)
2259 5b69bc7c Iustin Pop
        continue
2260 5b69bc7c Iustin Pop
    rlist.append(e1)
2261 5b69bc7c Iustin Pop
  # finally, replace backslash-something with something
2262 5b69bc7c Iustin Pop
  rlist = [re.sub(r"\\(.)", r"\1", v) for v in rlist]
2263 5b69bc7c Iustin Pop
  return rlist
2264 5b69bc7c Iustin Pop
2265 5b69bc7c Iustin Pop
2266 ab3e6da8 Iustin Pop
def CommaJoin(names):
2267 ab3e6da8 Iustin Pop
  """Nicely join a set of identifiers.
2268 ab3e6da8 Iustin Pop

2269 ab3e6da8 Iustin Pop
  @param names: set, list or tuple
2270 ab3e6da8 Iustin Pop
  @return: a string with the formatted results
2271 ab3e6da8 Iustin Pop

2272 ab3e6da8 Iustin Pop
  """
2273 1f864b60 Iustin Pop
  return ", ".join([str(val) for val in names])
2274 ab3e6da8 Iustin Pop
2275 ab3e6da8 Iustin Pop
2276 3f6a47a8 Michael Hanselmann
def BytesToMebibyte(value):
2277 3f6a47a8 Michael Hanselmann
  """Converts bytes to mebibytes.
2278 3f6a47a8 Michael Hanselmann

2279 3f6a47a8 Michael Hanselmann
  @type value: int
2280 3f6a47a8 Michael Hanselmann
  @param value: Value in bytes
2281 3f6a47a8 Michael Hanselmann
  @rtype: int
2282 3f6a47a8 Michael Hanselmann
  @return: Value in mebibytes
2283 3f6a47a8 Michael Hanselmann

2284 3f6a47a8 Michael Hanselmann
  """
2285 3f6a47a8 Michael Hanselmann
  return int(round(value / (1024.0 * 1024.0), 0))
2286 3f6a47a8 Michael Hanselmann
2287 3f6a47a8 Michael Hanselmann
2288 3f6a47a8 Michael Hanselmann
def CalculateDirectorySize(path):
2289 3f6a47a8 Michael Hanselmann
  """Calculates the size of a directory recursively.
2290 3f6a47a8 Michael Hanselmann

2291 3f6a47a8 Michael Hanselmann
  @type path: string
2292 3f6a47a8 Michael Hanselmann
  @param path: Path to directory
2293 3f6a47a8 Michael Hanselmann
  @rtype: int
2294 3f6a47a8 Michael Hanselmann
  @return: Size in mebibytes
2295 3f6a47a8 Michael Hanselmann

2296 3f6a47a8 Michael Hanselmann
  """
2297 3f6a47a8 Michael Hanselmann
  size = 0
2298 3f6a47a8 Michael Hanselmann
2299 3f6a47a8 Michael Hanselmann
  for (curpath, _, files) in os.walk(path):
2300 2a887df9 Michael Hanselmann
    for filename in files:
2301 c4feafe8 Iustin Pop
      st = os.lstat(PathJoin(curpath, filename))
2302 3f6a47a8 Michael Hanselmann
      size += st.st_size
2303 3f6a47a8 Michael Hanselmann
2304 3f6a47a8 Michael Hanselmann
  return BytesToMebibyte(size)
2305 3f6a47a8 Michael Hanselmann
2306 3f6a47a8 Michael Hanselmann
2307 620a85fd Iustin Pop
def GetFilesystemStats(path):
2308 620a85fd Iustin Pop
  """Returns the total and free space on a filesystem.
2309 3f6a47a8 Michael Hanselmann

2310 3f6a47a8 Michael Hanselmann
  @type path: string
2311 3f6a47a8 Michael Hanselmann
  @param path: Path on filesystem to be examined
2312 3f6a47a8 Michael Hanselmann
  @rtype: int
2313 620a85fd Iustin Pop
  @return: tuple of (Total space, Free space) in mebibytes
2314 3f6a47a8 Michael Hanselmann

2315 3f6a47a8 Michael Hanselmann
  """
2316 3f6a47a8 Michael Hanselmann
  st = os.statvfs(path)
2317 3f6a47a8 Michael Hanselmann
2318 620a85fd Iustin Pop
  fsize = BytesToMebibyte(st.f_bavail * st.f_frsize)
2319 620a85fd Iustin Pop
  tsize = BytesToMebibyte(st.f_blocks * st.f_frsize)
2320 620a85fd Iustin Pop
  return (tsize, fsize)
2321 3f6a47a8 Michael Hanselmann
2322 3f6a47a8 Michael Hanselmann
2323 bdefe5dd Michael Hanselmann
def RunInSeparateProcess(fn, *args):
2324 eb58f7bd Michael Hanselmann
  """Runs a function in a separate process.
2325 eb58f7bd Michael Hanselmann

2326 eb58f7bd Michael Hanselmann
  Note: Only boolean return values are supported.
2327 eb58f7bd Michael Hanselmann

2328 eb58f7bd Michael Hanselmann
  @type fn: callable
2329 eb58f7bd Michael Hanselmann
  @param fn: Function to be called
2330 bdefe5dd Michael Hanselmann
  @rtype: bool
2331 bdefe5dd Michael Hanselmann
  @return: Function's result
2332 eb58f7bd Michael Hanselmann

2333 eb58f7bd Michael Hanselmann
  """
2334 eb58f7bd Michael Hanselmann
  pid = os.fork()
2335 eb58f7bd Michael Hanselmann
  if pid == 0:
2336 eb58f7bd Michael Hanselmann
    # Child process
2337 eb58f7bd Michael Hanselmann
    try:
2338 82869978 Michael Hanselmann
      # In case the function uses temporary files
2339 82869978 Michael Hanselmann
      ResetTempfileModule()
2340 82869978 Michael Hanselmann
2341 eb58f7bd Michael Hanselmann
      # Call function
2342 bdefe5dd Michael Hanselmann
      result = int(bool(fn(*args)))
2343 eb58f7bd Michael Hanselmann
      assert result in (0, 1)
2344 eb58f7bd Michael Hanselmann
    except: # pylint: disable-msg=W0702
2345 eb58f7bd Michael Hanselmann
      logging.exception("Error while calling function in separate process")
2346 eb58f7bd Michael Hanselmann
      # 0 and 1 are reserved for the return value
2347 eb58f7bd Michael Hanselmann
      result = 33
2348 eb58f7bd Michael Hanselmann
2349 eb58f7bd Michael Hanselmann
    os._exit(result) # pylint: disable-msg=W0212
2350 eb58f7bd Michael Hanselmann
2351 eb58f7bd Michael Hanselmann
  # Parent process
2352 eb58f7bd Michael Hanselmann
2353 eb58f7bd Michael Hanselmann
  # Avoid zombies and check exit code
2354 eb58f7bd Michael Hanselmann
  (_, status) = os.waitpid(pid, 0)
2355 eb58f7bd Michael Hanselmann
2356 eb58f7bd Michael Hanselmann
  if os.WIFSIGNALED(status):
2357 eb58f7bd Michael Hanselmann
    exitcode = None
2358 eb58f7bd Michael Hanselmann
    signum = os.WTERMSIG(status)
2359 eb58f7bd Michael Hanselmann
  else:
2360 eb58f7bd Michael Hanselmann
    exitcode = os.WEXITSTATUS(status)
2361 eb58f7bd Michael Hanselmann
    signum = None
2362 eb58f7bd Michael Hanselmann
2363 eb58f7bd Michael Hanselmann
  if not (exitcode in (0, 1) and signum is None):
2364 eb58f7bd Michael Hanselmann
    raise errors.GenericError("Child program failed (code=%s, signal=%s)" %
2365 eb58f7bd Michael Hanselmann
                              (exitcode, signum))
2366 eb58f7bd Michael Hanselmann
2367 eb58f7bd Michael Hanselmann
  return bool(exitcode)
2368 eb58f7bd Michael Hanselmann
2369 eb58f7bd Michael Hanselmann
2370 7996a135 Iustin Pop
def LockedMethod(fn):
2371 7996a135 Iustin Pop
  """Synchronized object access decorator.
2372 7996a135 Iustin Pop

2373 7996a135 Iustin Pop
  This decorator is intended to protect access to an object using the
2374 7996a135 Iustin Pop
  object's own lock which is hardcoded to '_lock'.
2375 7996a135 Iustin Pop

2376 7996a135 Iustin Pop
  """
2377 e67bd559 Michael Hanselmann
  def _LockDebug(*args, **kwargs):
2378 e67bd559 Michael Hanselmann
    if debug_locks:
2379 e67bd559 Michael Hanselmann
      logging.debug(*args, **kwargs)
2380 e67bd559 Michael Hanselmann
2381 7996a135 Iustin Pop
  def wrapper(self, *args, **kwargs):
2382 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
2383 7996a135 Iustin Pop
    assert hasattr(self, '_lock')
2384 7996a135 Iustin Pop
    lock = self._lock
2385 e67bd559 Michael Hanselmann
    _LockDebug("Waiting for %s", lock)
2386 7996a135 Iustin Pop
    lock.acquire()
2387 7996a135 Iustin Pop
    try:
2388 e67bd559 Michael Hanselmann
      _LockDebug("Acquired %s", lock)
2389 7996a135 Iustin Pop
      result = fn(self, *args, **kwargs)
2390 7996a135 Iustin Pop
    finally:
2391 e67bd559 Michael Hanselmann
      _LockDebug("Releasing %s", lock)
2392 7996a135 Iustin Pop
      lock.release()
2393 e67bd559 Michael Hanselmann
      _LockDebug("Released %s", lock)
2394 7996a135 Iustin Pop
    return result
2395 7996a135 Iustin Pop
  return wrapper
2396 eb0f0ce0 Michael Hanselmann
2397 eb0f0ce0 Michael Hanselmann
2398 eb0f0ce0 Michael Hanselmann
def LockFile(fd):
2399 eb0f0ce0 Michael Hanselmann
  """Locks a file using POSIX locks.
2400 eb0f0ce0 Michael Hanselmann

2401 58885d79 Iustin Pop
  @type fd: int
2402 58885d79 Iustin Pop
  @param fd: the file descriptor we need to lock
2403 58885d79 Iustin Pop

2404 eb0f0ce0 Michael Hanselmann
  """
2405 eb0f0ce0 Michael Hanselmann
  try:
2406 eb0f0ce0 Michael Hanselmann
    fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
2407 eb0f0ce0 Michael Hanselmann
  except IOError, err:
2408 eb0f0ce0 Michael Hanselmann
    if err.errno == errno.EAGAIN:
2409 eb0f0ce0 Michael Hanselmann
      raise errors.LockError("File already locked")
2410 eb0f0ce0 Michael Hanselmann
    raise
2411 de499029 Michael Hanselmann
2412 de499029 Michael Hanselmann
2413 3b813dd2 Iustin Pop
def FormatTime(val):
2414 3b813dd2 Iustin Pop
  """Formats a time value.
2415 3b813dd2 Iustin Pop

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

2420 3b813dd2 Iustin Pop
  """
2421 3b813dd2 Iustin Pop
  if val is None or not isinstance(val, (int, float)):
2422 3b813dd2 Iustin Pop
    return "N/A"
2423 3b813dd2 Iustin Pop
  # these two codes works on Linux, but they are not guaranteed on all
2424 3b813dd2 Iustin Pop
  # platforms
2425 3b813dd2 Iustin Pop
  return time.strftime("%F %T", time.localtime(val))
2426 3b813dd2 Iustin Pop
2427 3b813dd2 Iustin Pop
2428 5cbe43a5 Michael Hanselmann
def ReadWatcherPauseFile(filename, now=None, remove_after=3600):
2429 05e50653 Michael Hanselmann
  """Reads the watcher pause file.
2430 05e50653 Michael Hanselmann

2431 5cbe43a5 Michael Hanselmann
  @type filename: string
2432 5cbe43a5 Michael Hanselmann
  @param filename: Path to watcher pause file
2433 5cbe43a5 Michael Hanselmann
  @type now: None, float or int
2434 5cbe43a5 Michael Hanselmann
  @param now: Current time as Unix timestamp
2435 5cbe43a5 Michael Hanselmann
  @type remove_after: int
2436 5cbe43a5 Michael Hanselmann
  @param remove_after: Remove watcher pause file after specified amount of
2437 5cbe43a5 Michael Hanselmann
    seconds past the pause end time
2438 5cbe43a5 Michael Hanselmann

2439 05e50653 Michael Hanselmann
  """
2440 05e50653 Michael Hanselmann
  if now is None:
2441 05e50653 Michael Hanselmann
    now = time.time()
2442 05e50653 Michael Hanselmann
2443 05e50653 Michael Hanselmann
  try:
2444 05e50653 Michael Hanselmann
    value = ReadFile(filename)
2445 05e50653 Michael Hanselmann
  except IOError, err:
2446 05e50653 Michael Hanselmann
    if err.errno != errno.ENOENT:
2447 05e50653 Michael Hanselmann
      raise
2448 05e50653 Michael Hanselmann
    value = None
2449 05e50653 Michael Hanselmann
2450 05e50653 Michael Hanselmann
  if value is not None:
2451 05e50653 Michael Hanselmann
    try:
2452 05e50653 Michael Hanselmann
      value = int(value)
2453 05e50653 Michael Hanselmann
    except ValueError:
2454 5cbe43a5 Michael Hanselmann
      logging.warning(("Watcher pause file (%s) contains invalid value,"
2455 5cbe43a5 Michael Hanselmann
                       " removing it"), filename)
2456 5cbe43a5 Michael Hanselmann
      RemoveFile(filename)
2457 05e50653 Michael Hanselmann
      value = None
2458 05e50653 Michael Hanselmann
2459 05e50653 Michael Hanselmann
    if value is not None:
2460 5cbe43a5 Michael Hanselmann
      # Remove file if it's outdated
2461 5cbe43a5 Michael Hanselmann
      if now > (value + remove_after):
2462 5cbe43a5 Michael Hanselmann
        RemoveFile(filename)
2463 5cbe43a5 Michael Hanselmann
        value = None
2464 5cbe43a5 Michael Hanselmann
2465 5cbe43a5 Michael Hanselmann
      elif now > value:
2466 05e50653 Michael Hanselmann
        value = None
2467 05e50653 Michael Hanselmann
2468 05e50653 Michael Hanselmann
  return value
2469 05e50653 Michael Hanselmann
2470 05e50653 Michael Hanselmann
2471 de0ea66b Michael Hanselmann
class RetryTimeout(Exception):
2472 de0ea66b Michael Hanselmann
  """Retry loop timed out.
2473 de0ea66b Michael Hanselmann

2474 de0ea66b Michael Hanselmann
  """
2475 de0ea66b Michael Hanselmann
2476 de0ea66b Michael Hanselmann
2477 de0ea66b Michael Hanselmann
class RetryAgain(Exception):
2478 de0ea66b Michael Hanselmann
  """Retry again.
2479 de0ea66b Michael Hanselmann

2480 de0ea66b Michael Hanselmann
  """
2481 de0ea66b Michael Hanselmann
2482 de0ea66b Michael Hanselmann
2483 de0ea66b Michael Hanselmann
class _RetryDelayCalculator(object):
2484 de0ea66b Michael Hanselmann
  """Calculator for increasing delays.
2485 de0ea66b Michael Hanselmann

2486 de0ea66b Michael Hanselmann
  """
2487 de0ea66b Michael Hanselmann
  __slots__ = [
2488 de0ea66b Michael Hanselmann
    "_factor",
2489 de0ea66b Michael Hanselmann
    "_limit",
2490 de0ea66b Michael Hanselmann
    "_next",
2491 de0ea66b Michael Hanselmann
    "_start",
2492 de0ea66b Michael Hanselmann
    ]
2493 de0ea66b Michael Hanselmann
2494 de0ea66b Michael Hanselmann
  def __init__(self, start, factor, limit):
2495 de0ea66b Michael Hanselmann
    """Initializes this class.
2496 de0ea66b Michael Hanselmann

2497 de0ea66b Michael Hanselmann
    @type start: float
2498 de0ea66b Michael Hanselmann
    @param start: Initial delay
2499 de0ea66b Michael Hanselmann
    @type factor: float
2500 de0ea66b Michael Hanselmann
    @param factor: Factor for delay increase
2501 de0ea66b Michael Hanselmann
    @type limit: float or None
2502 de0ea66b Michael Hanselmann
    @param limit: Upper limit for delay or None for no limit
2503 de0ea66b Michael Hanselmann

2504 de0ea66b Michael Hanselmann
    """
2505 de0ea66b Michael Hanselmann
    assert start > 0.0
2506 de0ea66b Michael Hanselmann
    assert factor >= 1.0
2507 de0ea66b Michael Hanselmann
    assert limit is None or limit >= 0.0
2508 de0ea66b Michael Hanselmann
2509 de0ea66b Michael Hanselmann
    self._start = start
2510 de0ea66b Michael Hanselmann
    self._factor = factor
2511 de0ea66b Michael Hanselmann
    self._limit = limit
2512 de0ea66b Michael Hanselmann
2513 de0ea66b Michael Hanselmann
    self._next = start
2514 de0ea66b Michael Hanselmann
2515 de0ea66b Michael Hanselmann
  def __call__(self):
2516 de0ea66b Michael Hanselmann
    """Returns current delay and calculates the next one.
2517 de0ea66b Michael Hanselmann

2518 de0ea66b Michael Hanselmann
    """
2519 de0ea66b Michael Hanselmann
    current = self._next
2520 de0ea66b Michael Hanselmann
2521 de0ea66b Michael Hanselmann
    # Update for next run
2522 de0ea66b Michael Hanselmann
    if self._limit is None or self._next < self._limit:
2523 26751075 Michael Hanselmann
      self._next = min(self._limit, self._next * self._factor)
2524 de0ea66b Michael Hanselmann
2525 de0ea66b Michael Hanselmann
    return current
2526 de0ea66b Michael Hanselmann
2527 de0ea66b Michael Hanselmann
2528 de0ea66b Michael Hanselmann
#: Special delay to specify whole remaining timeout
2529 de0ea66b Michael Hanselmann
RETRY_REMAINING_TIME = object()
2530 de0ea66b Michael Hanselmann
2531 de0ea66b Michael Hanselmann
2532 de0ea66b Michael Hanselmann
def Retry(fn, delay, timeout, args=None, wait_fn=time.sleep,
2533 de0ea66b Michael Hanselmann
          _time_fn=time.time):
2534 de0ea66b Michael Hanselmann
  """Call a function repeatedly until it succeeds.
2535 de0ea66b Michael Hanselmann

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

2540 de0ea66b Michael Hanselmann
  C{delay} can be one of the following:
2541 de0ea66b Michael Hanselmann
    - callable returning the delay length as a float
2542 de0ea66b Michael Hanselmann
    - Tuple of (start, factor, limit)
2543 de0ea66b Michael Hanselmann
    - L{RETRY_REMAINING_TIME} to sleep until the timeout expires (this is
2544 de0ea66b Michael Hanselmann
      useful when overriding L{wait_fn} to wait for an external event)
2545 de0ea66b Michael Hanselmann
    - A static delay as a number (int or float)
2546 de0ea66b Michael Hanselmann

2547 de0ea66b Michael Hanselmann
  @type fn: callable
2548 de0ea66b Michael Hanselmann
  @param fn: Function to be called
2549 de0ea66b Michael Hanselmann
  @param delay: Either a callable (returning the delay), a tuple of (start,
2550 de0ea66b Michael Hanselmann
                factor, limit) (see L{_RetryDelayCalculator}),
2551 de0ea66b Michael Hanselmann
                L{RETRY_REMAINING_TIME} or a number (int or float)
2552 de0ea66b Michael Hanselmann
  @type timeout: float
2553 de0ea66b Michael Hanselmann
  @param timeout: Total timeout
2554 de0ea66b Michael Hanselmann
  @type wait_fn: callable
2555 de0ea66b Michael Hanselmann
  @param wait_fn: Waiting function
2556 de0ea66b Michael Hanselmann
  @return: Return value of function
2557 de0ea66b Michael Hanselmann

2558 de0ea66b Michael Hanselmann
  """
2559 de0ea66b Michael Hanselmann
  assert callable(fn)
2560 de0ea66b Michael Hanselmann
  assert callable(wait_fn)
2561 de0ea66b Michael Hanselmann
  assert callable(_time_fn)
2562 de0ea66b Michael Hanselmann
2563 de0ea66b Michael Hanselmann
  if args is None:
2564 de0ea66b Michael Hanselmann
    args = []
2565 de0ea66b Michael Hanselmann
2566 de0ea66b Michael Hanselmann
  end_time = _time_fn() + timeout
2567 de0ea66b Michael Hanselmann
2568 de0ea66b Michael Hanselmann
  if callable(delay):
2569 de0ea66b Michael Hanselmann
    # External function to calculate delay
2570 de0ea66b Michael Hanselmann
    calc_delay = delay
2571 de0ea66b Michael Hanselmann
2572 de0ea66b Michael Hanselmann
  elif isinstance(delay, (tuple, list)):
2573 de0ea66b Michael Hanselmann
    # Increasing delay with optional upper boundary
2574 de0ea66b Michael Hanselmann
    (start, factor, limit) = delay
2575 de0ea66b Michael Hanselmann
    calc_delay = _RetryDelayCalculator(start, factor, limit)
2576 de0ea66b Michael Hanselmann
2577 de0ea66b Michael Hanselmann
  elif delay is RETRY_REMAINING_TIME:
2578 de0ea66b Michael Hanselmann
    # Always use the remaining time
2579 de0ea66b Michael Hanselmann
    calc_delay = None
2580 de0ea66b Michael Hanselmann
2581 de0ea66b Michael Hanselmann
  else:
2582 de0ea66b Michael Hanselmann
    # Static delay
2583 de0ea66b Michael Hanselmann
    calc_delay = lambda: delay
2584 de0ea66b Michael Hanselmann
2585 de0ea66b Michael Hanselmann
  assert calc_delay is None or callable(calc_delay)
2586 de0ea66b Michael Hanselmann
2587 de0ea66b Michael Hanselmann
  while True:
2588 de0ea66b Michael Hanselmann
    try:
2589 7260cfbe Iustin Pop
      # pylint: disable-msg=W0142
2590 de0ea66b Michael Hanselmann
      return fn(*args)
2591 de0ea66b Michael Hanselmann
    except RetryAgain:
2592 de0ea66b Michael Hanselmann
      pass
2593 1b429e2a Iustin Pop
    except RetryTimeout:
2594 1b429e2a Iustin Pop
      raise errors.ProgrammerError("Nested retry loop detected that didn't"
2595 1b429e2a Iustin Pop
                                   " handle RetryTimeout")
2596 de0ea66b Michael Hanselmann
2597 de0ea66b Michael Hanselmann
    remaining_time = end_time - _time_fn()
2598 de0ea66b Michael Hanselmann
2599 de0ea66b Michael Hanselmann
    if remaining_time < 0.0:
2600 de0ea66b Michael Hanselmann
      raise RetryTimeout()
2601 de0ea66b Michael Hanselmann
2602 de0ea66b Michael Hanselmann
    assert remaining_time >= 0.0
2603 de0ea66b Michael Hanselmann
2604 de0ea66b Michael Hanselmann
    if calc_delay is None:
2605 de0ea66b Michael Hanselmann
      wait_fn(remaining_time)
2606 de0ea66b Michael Hanselmann
    else:
2607 de0ea66b Michael Hanselmann
      current_delay = calc_delay()
2608 de0ea66b Michael Hanselmann
      if current_delay > 0.0:
2609 de0ea66b Michael Hanselmann
        wait_fn(current_delay)
2610 de0ea66b Michael Hanselmann
2611 de0ea66b Michael Hanselmann
2612 a87b4824 Michael Hanselmann
class FileLock(object):
2613 a87b4824 Michael Hanselmann
  """Utility class for file locks.
2614 a87b4824 Michael Hanselmann

2615 a87b4824 Michael Hanselmann
  """
2616 b4478d34 Michael Hanselmann
  def __init__(self, fd, filename):
2617 58885d79 Iustin Pop
    """Constructor for FileLock.
2618 58885d79 Iustin Pop

2619 b4478d34 Michael Hanselmann
    @type fd: file
2620 b4478d34 Michael Hanselmann
    @param fd: File object
2621 58885d79 Iustin Pop
    @type filename: str
2622 b4478d34 Michael Hanselmann
    @param filename: Path of the file opened at I{fd}
2623 58885d79 Iustin Pop

2624 58885d79 Iustin Pop
    """
2625 b4478d34 Michael Hanselmann
    self.fd = fd
2626 a87b4824 Michael Hanselmann
    self.filename = filename
2627 b4478d34 Michael Hanselmann
2628 b4478d34 Michael Hanselmann
  @classmethod
2629 b4478d34 Michael Hanselmann
  def Open(cls, filename):
2630 b4478d34 Michael Hanselmann
    """Creates and opens a file to be used as a file-based lock.
2631 b4478d34 Michael Hanselmann

2632 b4478d34 Michael Hanselmann
    @type filename: string
2633 b4478d34 Michael Hanselmann
    @param filename: path to the file to be locked
2634 b4478d34 Michael Hanselmann

2635 b4478d34 Michael Hanselmann
    """
2636 b4478d34 Michael Hanselmann
    # Using "os.open" is necessary to allow both opening existing file
2637 b4478d34 Michael Hanselmann
    # read/write and creating if not existing. Vanilla "open" will truncate an
2638 b4478d34 Michael Hanselmann
    # existing file -or- allow creating if not existing.
2639 b4478d34 Michael Hanselmann
    return cls(os.fdopen(os.open(filename, os.O_RDWR | os.O_CREAT), "w+"),
2640 b4478d34 Michael Hanselmann
               filename)
2641 a87b4824 Michael Hanselmann
2642 a87b4824 Michael Hanselmann
  def __del__(self):
2643 a87b4824 Michael Hanselmann
    self.Close()
2644 a87b4824 Michael Hanselmann
2645 a87b4824 Michael Hanselmann
  def Close(self):
2646 58885d79 Iustin Pop
    """Close the file and release the lock.
2647 58885d79 Iustin Pop

2648 58885d79 Iustin Pop
    """
2649 aac3fbf0 Iustin Pop
    if hasattr(self, "fd") and self.fd:
2650 a87b4824 Michael Hanselmann
      self.fd.close()
2651 a87b4824 Michael Hanselmann
      self.fd = None
2652 a87b4824 Michael Hanselmann
2653 aa74b828 Michael Hanselmann
  def _flock(self, flag, blocking, timeout, errmsg):
2654 aa74b828 Michael Hanselmann
    """Wrapper for fcntl.flock.
2655 aa74b828 Michael Hanselmann

2656 aa74b828 Michael Hanselmann
    @type flag: int
2657 58885d79 Iustin Pop
    @param flag: operation flag
2658 aa74b828 Michael Hanselmann
    @type blocking: bool
2659 58885d79 Iustin Pop
    @param blocking: whether the operation should be done in blocking mode.
2660 aa74b828 Michael Hanselmann
    @type timeout: None or float
2661 58885d79 Iustin Pop
    @param timeout: for how long the operation should be retried (implies
2662 aa74b828 Michael Hanselmann
                    non-blocking mode).
2663 aa74b828 Michael Hanselmann
    @type errmsg: string
2664 58885d79 Iustin Pop
    @param errmsg: error message in case operation fails.
2665 aa74b828 Michael Hanselmann

2666 aa74b828 Michael Hanselmann
    """
2667 a87b4824 Michael Hanselmann
    assert self.fd, "Lock was closed"
2668 aa74b828 Michael Hanselmann
    assert timeout is None or timeout >= 0, \
2669 aa74b828 Michael Hanselmann
      "If specified, timeout must be positive"
2670 cc4c9b91 Michael Hanselmann
    assert not (flag & fcntl.LOCK_NB), "LOCK_NB must not be set"
2671 a87b4824 Michael Hanselmann
2672 cc4c9b91 Michael Hanselmann
    # When a timeout is used, LOCK_NB must always be set
2673 cc4c9b91 Michael Hanselmann
    if not (timeout is None and blocking):
2674 a87b4824 Michael Hanselmann
      flag |= fcntl.LOCK_NB
2675 a87b4824 Michael Hanselmann
2676 cc4c9b91 Michael Hanselmann
    if timeout is None:
2677 cc4c9b91 Michael Hanselmann
      self._Lock(self.fd, flag, timeout)
2678 cc4c9b91 Michael Hanselmann
    else:
2679 cc4c9b91 Michael Hanselmann
      try:
2680 cc4c9b91 Michael Hanselmann
        Retry(self._Lock, (0.1, 1.2, 1.0), timeout,
2681 cc4c9b91 Michael Hanselmann
              args=(self.fd, flag, timeout))
2682 cc4c9b91 Michael Hanselmann
      except RetryTimeout:
2683 cc4c9b91 Michael Hanselmann
        raise errors.LockError(errmsg)
2684 aa74b828 Michael Hanselmann
2685 cc4c9b91 Michael Hanselmann
  @staticmethod
2686 cc4c9b91 Michael Hanselmann
  def _Lock(fd, flag, timeout):
2687 cc4c9b91 Michael Hanselmann
    try:
2688 cc4c9b91 Michael Hanselmann
      fcntl.flock(fd, flag)
2689 cc4c9b91 Michael Hanselmann
    except IOError, err:
2690 cc4c9b91 Michael Hanselmann
      if timeout is not None and err.errno == errno.EAGAIN:
2691 cc4c9b91 Michael Hanselmann
        raise RetryAgain()
2692 31892b4c Michael Hanselmann
2693 cc4c9b91 Michael Hanselmann
      logging.exception("fcntl.flock failed")
2694 cc4c9b91 Michael Hanselmann
      raise
2695 aa74b828 Michael Hanselmann
2696 aa74b828 Michael Hanselmann
  def Exclusive(self, blocking=False, timeout=None):
2697 a87b4824 Michael Hanselmann
    """Locks the file in exclusive mode.
2698 a87b4824 Michael Hanselmann

2699 58885d79 Iustin Pop
    @type blocking: boolean
2700 58885d79 Iustin Pop
    @param blocking: whether to block and wait until we
2701 58885d79 Iustin Pop
        can lock the file or return immediately
2702 58885d79 Iustin Pop
    @type timeout: int or None
2703 58885d79 Iustin Pop
    @param timeout: if not None, the duration to wait for the lock
2704 58885d79 Iustin Pop
        (in blocking mode)
2705 58885d79 Iustin Pop

2706 a87b4824 Michael Hanselmann
    """
2707 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_EX, blocking, timeout,
2708 a87b4824 Michael Hanselmann
                "Failed to lock %s in exclusive mode" % self.filename)
2709 a87b4824 Michael Hanselmann
2710 aa74b828 Michael Hanselmann
  def Shared(self, blocking=False, timeout=None):
2711 a87b4824 Michael Hanselmann
    """Locks the file in shared mode.
2712 a87b4824 Michael Hanselmann

2713 58885d79 Iustin Pop
    @type blocking: boolean
2714 58885d79 Iustin Pop
    @param blocking: whether to block and wait until we
2715 58885d79 Iustin Pop
        can lock the file or return immediately
2716 58885d79 Iustin Pop
    @type timeout: int or None
2717 58885d79 Iustin Pop
    @param timeout: if not None, the duration to wait for the lock
2718 58885d79 Iustin Pop
        (in blocking mode)
2719 58885d79 Iustin Pop

2720 a87b4824 Michael Hanselmann
    """
2721 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_SH, blocking, timeout,
2722 a87b4824 Michael Hanselmann
                "Failed to lock %s in shared mode" % self.filename)
2723 a87b4824 Michael Hanselmann
2724 aa74b828 Michael Hanselmann
  def Unlock(self, blocking=True, timeout=None):
2725 a87b4824 Michael Hanselmann
    """Unlocks the file.
2726 a87b4824 Michael Hanselmann

2727 58885d79 Iustin Pop
    According to C{flock(2)}, unlocking can also be a nonblocking
2728 58885d79 Iustin Pop
    operation::
2729 58885d79 Iustin Pop

2730 58885d79 Iustin Pop
      To make a non-blocking request, include LOCK_NB with any of the above
2731 58885d79 Iustin Pop
      operations.
2732 58885d79 Iustin Pop

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 a87b4824 Michael Hanselmann

2740 a87b4824 Michael Hanselmann
    """
2741 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_UN, blocking, timeout,
2742 a87b4824 Michael Hanselmann
                "Failed to unlock %s" % self.filename)
2743 a87b4824 Michael Hanselmann
2744 a87b4824 Michael Hanselmann
2745 339be5a8 Michael Hanselmann
class LineSplitter:
2746 339be5a8 Michael Hanselmann
  """Splits data chunks into lines separated by newline.
2747 339be5a8 Michael Hanselmann

2748 339be5a8 Michael Hanselmann
  Instances provide a file-like interface.
2749 339be5a8 Michael Hanselmann

2750 339be5a8 Michael Hanselmann
  """
2751 339be5a8 Michael Hanselmann
  def __init__(self, line_fn, *args):
2752 339be5a8 Michael Hanselmann
    """Initializes this class.
2753 339be5a8 Michael Hanselmann

2754 339be5a8 Michael Hanselmann
    @type line_fn: callable
2755 339be5a8 Michael Hanselmann
    @param line_fn: Function called for each line, first parameter is line
2756 339be5a8 Michael Hanselmann
    @param args: Extra arguments for L{line_fn}
2757 339be5a8 Michael Hanselmann

2758 339be5a8 Michael Hanselmann
    """
2759 339be5a8 Michael Hanselmann
    assert callable(line_fn)
2760 339be5a8 Michael Hanselmann
2761 339be5a8 Michael Hanselmann
    if args:
2762 339be5a8 Michael Hanselmann
      # Python 2.4 doesn't have functools.partial yet
2763 339be5a8 Michael Hanselmann
      self._line_fn = \
2764 339be5a8 Michael Hanselmann
        lambda line: line_fn(line, *args) # pylint: disable-msg=W0142
2765 339be5a8 Michael Hanselmann
    else:
2766 339be5a8 Michael Hanselmann
      self._line_fn = line_fn
2767 339be5a8 Michael Hanselmann
2768 339be5a8 Michael Hanselmann
    self._lines = collections.deque()
2769 339be5a8 Michael Hanselmann
    self._buffer = ""
2770 339be5a8 Michael Hanselmann
2771 339be5a8 Michael Hanselmann
  def write(self, data):
2772 339be5a8 Michael Hanselmann
    parts = (self._buffer + data).split("\n")
2773 339be5a8 Michael Hanselmann
    self._buffer = parts.pop()
2774 339be5a8 Michael Hanselmann
    self._lines.extend(parts)
2775 339be5a8 Michael Hanselmann
2776 339be5a8 Michael Hanselmann
  def flush(self):
2777 339be5a8 Michael Hanselmann
    while self._lines:
2778 339be5a8 Michael Hanselmann
      self._line_fn(self._lines.popleft().rstrip("\r\n"))
2779 339be5a8 Michael Hanselmann
2780 339be5a8 Michael Hanselmann
  def close(self):
2781 339be5a8 Michael Hanselmann
    self.flush()
2782 339be5a8 Michael Hanselmann
    if self._buffer:
2783 339be5a8 Michael Hanselmann
      self._line_fn(self._buffer)
2784 339be5a8 Michael Hanselmann
2785 339be5a8 Michael Hanselmann
2786 451575de Guido Trotter
def SignalHandled(signums):
2787 451575de Guido Trotter
  """Signal Handled decoration.
2788 451575de Guido Trotter

2789 451575de Guido Trotter
  This special decorator installs a signal handler and then calls the target
2790 451575de Guido Trotter
  function. The function must accept a 'signal_handlers' keyword argument,
2791 451575de Guido Trotter
  which will contain a dict indexed by signal number, with SignalHandler
2792 451575de Guido Trotter
  objects as values.
2793 451575de Guido Trotter

2794 451575de Guido Trotter
  The decorator can be safely stacked with iself, to handle multiple signals
2795 451575de Guido Trotter
  with different handlers.
2796 451575de Guido Trotter

2797 451575de Guido Trotter
  @type signums: list
2798 451575de Guido Trotter
  @param signums: signals to intercept
2799 451575de Guido Trotter

2800 451575de Guido Trotter
  """
2801 451575de Guido Trotter
  def wrap(fn):
2802 451575de Guido Trotter
    def sig_function(*args, **kwargs):
2803 451575de Guido Trotter
      assert 'signal_handlers' not in kwargs or \
2804 451575de Guido Trotter
             kwargs['signal_handlers'] is None or \
2805 451575de Guido Trotter
             isinstance(kwargs['signal_handlers'], dict), \
2806 451575de Guido Trotter
             "Wrong signal_handlers parameter in original function call"
2807 451575de Guido Trotter
      if 'signal_handlers' in kwargs and kwargs['signal_handlers'] is not None:
2808 451575de Guido Trotter
        signal_handlers = kwargs['signal_handlers']
2809 451575de Guido Trotter
      else:
2810 451575de Guido Trotter
        signal_handlers = {}
2811 451575de Guido Trotter
        kwargs['signal_handlers'] = signal_handlers
2812 451575de Guido Trotter
      sighandler = SignalHandler(signums)
2813 451575de Guido Trotter
      try:
2814 451575de Guido Trotter
        for sig in signums:
2815 451575de Guido Trotter
          signal_handlers[sig] = sighandler
2816 451575de Guido Trotter
        return fn(*args, **kwargs)
2817 451575de Guido Trotter
      finally:
2818 451575de Guido Trotter
        sighandler.Reset()
2819 451575de Guido Trotter
    return sig_function
2820 451575de Guido Trotter
  return wrap
2821 451575de Guido Trotter
2822 451575de Guido Trotter
2823 de499029 Michael Hanselmann
class SignalHandler(object):
2824 de499029 Michael Hanselmann
  """Generic signal handler class.
2825 de499029 Michael Hanselmann

2826 58885d79 Iustin Pop
  It automatically restores the original handler when deconstructed or
2827 58885d79 Iustin Pop
  when L{Reset} is called. You can either pass your own handler
2828 58885d79 Iustin Pop
  function in or query the L{called} attribute to detect whether the
2829 58885d79 Iustin Pop
  signal was sent.
2830 58885d79 Iustin Pop

2831 58885d79 Iustin Pop
  @type signum: list
2832 58885d79 Iustin Pop
  @ivar signum: the signals we handle
2833 58885d79 Iustin Pop
  @type called: boolean
2834 58885d79 Iustin Pop
  @ivar called: tracks whether any of the signals have been raised
2835 de499029 Michael Hanselmann

2836 de499029 Michael Hanselmann
  """
2837 de499029 Michael Hanselmann
  def __init__(self, signum):
2838 de499029 Michael Hanselmann
    """Constructs a new SignalHandler instance.
2839 de499029 Michael Hanselmann

2840 58885d79 Iustin Pop
    @type signum: int or list of ints
2841 de499029 Michael Hanselmann
    @param signum: Single signal number or set of signal numbers
2842 de499029 Michael Hanselmann

2843 de499029 Michael Hanselmann
    """
2844 6c52849e Guido Trotter
    self.signum = set(signum)
2845 de499029 Michael Hanselmann
    self.called = False
2846 de499029 Michael Hanselmann
2847 de499029 Michael Hanselmann
    self._previous = {}
2848 de499029 Michael Hanselmann
    try:
2849 de499029 Michael Hanselmann
      for signum in self.signum:
2850 de499029 Michael Hanselmann
        # Setup handler
2851 de499029 Michael Hanselmann
        prev_handler = signal.signal(signum, self._HandleSignal)
2852 de499029 Michael Hanselmann
        try:
2853 de499029 Michael Hanselmann
          self._previous[signum] = prev_handler
2854 de499029 Michael Hanselmann
        except:
2855 de499029 Michael Hanselmann
          # Restore previous handler
2856 de499029 Michael Hanselmann
          signal.signal(signum, prev_handler)
2857 de499029 Michael Hanselmann
          raise
2858 de499029 Michael Hanselmann
    except:
2859 de499029 Michael Hanselmann
      # Reset all handlers
2860 de499029 Michael Hanselmann
      self.Reset()
2861 de499029 Michael Hanselmann
      # Here we have a race condition: a handler may have already been called,
2862 de499029 Michael Hanselmann
      # but there's not much we can do about it at this point.
2863 de499029 Michael Hanselmann
      raise
2864 de499029 Michael Hanselmann
2865 de499029 Michael Hanselmann
  def __del__(self):
2866 de499029 Michael Hanselmann
    self.Reset()
2867 de499029 Michael Hanselmann
2868 de499029 Michael Hanselmann
  def Reset(self):
2869 de499029 Michael Hanselmann
    """Restore previous handler.
2870 de499029 Michael Hanselmann

2871 58885d79 Iustin Pop
    This will reset all the signals to their previous handlers.
2872 58885d79 Iustin Pop

2873 de499029 Michael Hanselmann
    """
2874 de499029 Michael Hanselmann
    for signum, prev_handler in self._previous.items():
2875 de499029 Michael Hanselmann
      signal.signal(signum, prev_handler)
2876 de499029 Michael Hanselmann
      # If successful, remove from dict
2877 de499029 Michael Hanselmann
      del self._previous[signum]
2878 de499029 Michael Hanselmann
2879 de499029 Michael Hanselmann
  def Clear(self):
2880 58885d79 Iustin Pop
    """Unsets the L{called} flag.
2881 de499029 Michael Hanselmann

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

2884 de499029 Michael Hanselmann
    """
2885 de499029 Michael Hanselmann
    self.called = False
2886 de499029 Michael Hanselmann
2887 2d54e29c Iustin Pop
  # we don't care about arguments, but we leave them named for the future
2888 2d54e29c Iustin Pop
  def _HandleSignal(self, signum, frame): # pylint: disable-msg=W0613
2889 de499029 Michael Hanselmann
    """Actual signal handling function.
2890 de499029 Michael Hanselmann

2891 de499029 Michael Hanselmann
    """
2892 de499029 Michael Hanselmann
    # This is not nice and not absolutely atomic, but it appears to be the only
2893 de499029 Michael Hanselmann
    # solution in Python -- there are no atomic types.
2894 de499029 Michael Hanselmann
    self.called = True
2895 a2d2e1a7 Iustin Pop
2896 a2d2e1a7 Iustin Pop
2897 a2d2e1a7 Iustin Pop
class FieldSet(object):
2898 a2d2e1a7 Iustin Pop
  """A simple field set.
2899 a2d2e1a7 Iustin Pop

2900 a2d2e1a7 Iustin Pop
  Among the features are:
2901 a2d2e1a7 Iustin Pop
    - checking if a string is among a list of static string or regex objects
2902 a2d2e1a7 Iustin Pop
    - checking if a whole list of string matches
2903 a2d2e1a7 Iustin Pop
    - returning the matching groups from a regex match
2904 a2d2e1a7 Iustin Pop

2905 a2d2e1a7 Iustin Pop
  Internally, all fields are held as regular expression objects.
2906 a2d2e1a7 Iustin Pop

2907 a2d2e1a7 Iustin Pop
  """
2908 a2d2e1a7 Iustin Pop
  def __init__(self, *items):
2909 a2d2e1a7 Iustin Pop
    self.items = [re.compile("^%s$" % value) for value in items]
2910 a2d2e1a7 Iustin Pop
2911 a2d2e1a7 Iustin Pop
  def Extend(self, other_set):
2912 a2d2e1a7 Iustin Pop
    """Extend the field set with the items from another one"""
2913 a2d2e1a7 Iustin Pop
    self.items.extend(other_set.items)
2914 a2d2e1a7 Iustin Pop
2915 a2d2e1a7 Iustin Pop
  def Matches(self, field):
2916 a2d2e1a7 Iustin Pop
    """Checks if a field matches the current set
2917 a2d2e1a7 Iustin Pop

2918 a2d2e1a7 Iustin Pop
    @type field: str
2919 a2d2e1a7 Iustin Pop
    @param field: the string to match
2920 6c881c52 Iustin Pop
    @return: either None or a regular expression match object
2921 a2d2e1a7 Iustin Pop

2922 a2d2e1a7 Iustin Pop
    """
2923 a2d2e1a7 Iustin Pop
    for m in itertools.ifilter(None, (val.match(field) for val in self.items)):
2924 a2d2e1a7 Iustin Pop
      return m
2925 6c881c52 Iustin Pop
    return None
2926 a2d2e1a7 Iustin Pop
2927 a2d2e1a7 Iustin Pop
  def NonMatching(self, items):
2928 a2d2e1a7 Iustin Pop
    """Returns the list of fields not matching the current set
2929 a2d2e1a7 Iustin Pop

2930 a2d2e1a7 Iustin Pop
    @type items: list
2931 a2d2e1a7 Iustin Pop
    @param items: the list of fields to check
2932 a2d2e1a7 Iustin Pop
    @rtype: list
2933 a2d2e1a7 Iustin Pop
    @return: list of non-matching fields
2934 a2d2e1a7 Iustin Pop

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