Statistics
| Branch: | Tag: | Revision:

root / lib / utils.py @ 5905901c

History | View | Annotate | Download (64.3 kB)

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

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

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

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

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

114 a8083063 Iustin Pop
    """
115 a8083063 Iustin Pop
    return self.stdout + self.stderr
116 a8083063 Iustin Pop
117 a8083063 Iustin Pop
  output = property(_GetOutput, None, None, "Return full output")
118 a8083063 Iustin Pop
119 a8083063 Iustin Pop
120 8797df43 Iustin Pop
def RunCmd(cmd, env=None, output=None, cwd='/'):
121 a8083063 Iustin Pop
  """Execute a (shell) command.
122 a8083063 Iustin Pop

123 a8083063 Iustin Pop
  The command should not read from its standard input, as it will be
124 a8083063 Iustin Pop
  closed.
125 a8083063 Iustin Pop

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

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

185 36117c2b Iustin Pop
  @type  cmd: string or list
186 36117c2b Iustin Pop
  @param cmd: Command to run
187 36117c2b Iustin Pop
  @type env: dict
188 36117c2b Iustin Pop
  @param env: The environment to use
189 36117c2b Iustin Pop
  @type via_shell: bool
190 36117c2b Iustin Pop
  @param via_shell: if we should run via the shell
191 8797df43 Iustin Pop
  @type cwd: string
192 8797df43 Iustin Pop
  @param cwd: the working directory for the program
193 36117c2b Iustin Pop
  @rtype: tuple
194 36117c2b Iustin Pop
  @return: (out, err, status)
195 36117c2b Iustin Pop

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

254 36117c2b Iustin Pop
  @type  cmd: string or list
255 36117c2b Iustin Pop
  @param cmd: Command to run
256 36117c2b Iustin Pop
  @type env: dict
257 36117c2b Iustin Pop
  @param env: The environment to use
258 36117c2b Iustin Pop
  @type via_shell: bool
259 36117c2b Iustin Pop
  @param via_shell: if we should run via the shell
260 36117c2b Iustin Pop
  @type output: str
261 36117c2b Iustin Pop
  @param output: the filename in which to save the output
262 8797df43 Iustin Pop
  @type cwd: string
263 8797df43 Iustin Pop
  @param cwd: the working directory for the program
264 36117c2b Iustin Pop
  @rtype: int
265 36117c2b Iustin Pop
  @return: the exit status
266 36117c2b Iustin Pop

267 36117c2b Iustin Pop
  """
268 36117c2b Iustin Pop
  fh = open(output, "a")
269 36117c2b Iustin Pop
  try:
270 36117c2b Iustin Pop
    child = subprocess.Popen(cmd, shell=via_shell,
271 36117c2b Iustin Pop
                             stderr=subprocess.STDOUT,
272 36117c2b Iustin Pop
                             stdout=fh,
273 36117c2b Iustin Pop
                             stdin=subprocess.PIPE,
274 8797df43 Iustin Pop
                             close_fds=True, env=env,
275 8797df43 Iustin Pop
                             cwd=cwd)
276 36117c2b Iustin Pop
277 36117c2b Iustin Pop
    child.stdin.close()
278 36117c2b Iustin Pop
    status = child.wait()
279 36117c2b Iustin Pop
  finally:
280 36117c2b Iustin Pop
    fh.close()
281 36117c2b Iustin Pop
  return status
282 a8083063 Iustin Pop
283 a8083063 Iustin Pop
284 a8083063 Iustin Pop
def RemoveFile(filename):
285 a8083063 Iustin Pop
  """Remove a file ignoring some errors.
286 a8083063 Iustin Pop

287 a8083063 Iustin Pop
  Remove a file, ignoring non-existing ones or directories. Other
288 a8083063 Iustin Pop
  errors are passed.
289 a8083063 Iustin Pop

290 58885d79 Iustin Pop
  @type filename: str
291 58885d79 Iustin Pop
  @param filename: the file to be removed
292 58885d79 Iustin Pop

293 a8083063 Iustin Pop
  """
294 a8083063 Iustin Pop
  try:
295 a8083063 Iustin Pop
    os.unlink(filename)
296 a8083063 Iustin Pop
  except OSError, err:
297 4ca1b175 Alexander Schreiber
    if err.errno not in (errno.ENOENT, errno.EISDIR):
298 a8083063 Iustin Pop
      raise
299 a8083063 Iustin Pop
300 a8083063 Iustin Pop
301 6e797216 Michael Hanselmann
def RenameFile(old, new, mkdir=False, mkdir_mode=0750):
302 6e797216 Michael Hanselmann
  """Renames a file.
303 6e797216 Michael Hanselmann

304 6e797216 Michael Hanselmann
  @type old: string
305 6e797216 Michael Hanselmann
  @param old: Original path
306 6e797216 Michael Hanselmann
  @type new: string
307 6e797216 Michael Hanselmann
  @param new: New path
308 6e797216 Michael Hanselmann
  @type mkdir: bool
309 6e797216 Michael Hanselmann
  @param mkdir: Whether to create target directory if it doesn't exist
310 6e797216 Michael Hanselmann
  @type mkdir_mode: int
311 6e797216 Michael Hanselmann
  @param mkdir_mode: Mode for newly created directories
312 6e797216 Michael Hanselmann

313 6e797216 Michael Hanselmann
  """
314 6e797216 Michael Hanselmann
  try:
315 6e797216 Michael Hanselmann
    return os.rename(old, new)
316 6e797216 Michael Hanselmann
  except OSError, err:
317 6e797216 Michael Hanselmann
    # In at least one use case of this function, the job queue, directory
318 6e797216 Michael Hanselmann
    # creation is very rare. Checking for the directory before renaming is not
319 6e797216 Michael Hanselmann
    # as efficient.
320 6e797216 Michael Hanselmann
    if mkdir and err.errno == errno.ENOENT:
321 6e797216 Michael Hanselmann
      # Create directory and try again
322 a426508d Michael Hanselmann
      dirname = os.path.dirname(new)
323 a426508d Michael Hanselmann
      try:
324 a426508d Michael Hanselmann
        os.makedirs(dirname, mode=mkdir_mode)
325 a426508d Michael Hanselmann
      except OSError, err:
326 a426508d Michael Hanselmann
        # Ignore EEXIST. This is only handled in os.makedirs as included in
327 a426508d Michael Hanselmann
        # Python 2.5 and above.
328 a426508d Michael Hanselmann
        if err.errno != errno.EEXIST or not os.path.exists(dirname):
329 a426508d Michael Hanselmann
          raise
330 a426508d Michael Hanselmann
331 6e797216 Michael Hanselmann
      return os.rename(old, new)
332 a426508d Michael Hanselmann
333 6e797216 Michael Hanselmann
    raise
334 6e797216 Michael Hanselmann
335 6e797216 Michael Hanselmann
336 a8083063 Iustin Pop
def _FingerprintFile(filename):
337 a8083063 Iustin Pop
  """Compute the fingerprint of a file.
338 a8083063 Iustin Pop

339 a8083063 Iustin Pop
  If the file does not exist, a None will be returned
340 a8083063 Iustin Pop
  instead.
341 a8083063 Iustin Pop

342 58885d79 Iustin Pop
  @type filename: str
343 58885d79 Iustin Pop
  @param filename: the filename to checksum
344 58885d79 Iustin Pop
  @rtype: str
345 58885d79 Iustin Pop
  @return: the hex digest of the sha checksum of the contents
346 58885d79 Iustin Pop
      of the file
347 a8083063 Iustin Pop

348 a8083063 Iustin Pop
  """
349 a8083063 Iustin Pop
  if not (os.path.exists(filename) and os.path.isfile(filename)):
350 a8083063 Iustin Pop
    return None
351 a8083063 Iustin Pop
352 a8083063 Iustin Pop
  f = open(filename)
353 a8083063 Iustin Pop
354 7ffe8fba Carlos Valiente
  fp = sha1()
355 a8083063 Iustin Pop
  while True:
356 a8083063 Iustin Pop
    data = f.read(4096)
357 a8083063 Iustin Pop
    if not data:
358 a8083063 Iustin Pop
      break
359 a8083063 Iustin Pop
360 a8083063 Iustin Pop
    fp.update(data)
361 a8083063 Iustin Pop
362 a8083063 Iustin Pop
  return fp.hexdigest()
363 a8083063 Iustin Pop
364 a8083063 Iustin Pop
365 a8083063 Iustin Pop
def FingerprintFiles(files):
366 a8083063 Iustin Pop
  """Compute fingerprints for a list of files.
367 a8083063 Iustin Pop

368 58885d79 Iustin Pop
  @type files: list
369 58885d79 Iustin Pop
  @param files: the list of filename to fingerprint
370 58885d79 Iustin Pop
  @rtype: dict
371 58885d79 Iustin Pop
  @return: a dictionary filename: fingerprint, holding only
372 58885d79 Iustin Pop
      existing files
373 a8083063 Iustin Pop

374 a8083063 Iustin Pop
  """
375 a8083063 Iustin Pop
  ret = {}
376 a8083063 Iustin Pop
377 a8083063 Iustin Pop
  for filename in files:
378 a8083063 Iustin Pop
    cksum = _FingerprintFile(filename)
379 a8083063 Iustin Pop
    if cksum:
380 a8083063 Iustin Pop
      ret[filename] = cksum
381 a8083063 Iustin Pop
382 a8083063 Iustin Pop
  return ret
383 a8083063 Iustin Pop
384 a8083063 Iustin Pop
385 a5728081 Guido Trotter
def ForceDictType(target, key_types, allowed_values=None):
386 a5728081 Guido Trotter
  """Force the values of a dict to have certain types.
387 a5728081 Guido Trotter

388 a5728081 Guido Trotter
  @type target: dict
389 a5728081 Guido Trotter
  @param target: the dict to update
390 a5728081 Guido Trotter
  @type key_types: dict
391 a5728081 Guido Trotter
  @param key_types: dict mapping target dict keys to types
392 a5728081 Guido Trotter
                    in constants.ENFORCEABLE_TYPES
393 a5728081 Guido Trotter
  @type allowed_values: list
394 a5728081 Guido Trotter
  @keyword allowed_values: list of specially allowed values
395 a5728081 Guido Trotter

396 a5728081 Guido Trotter
  """
397 a5728081 Guido Trotter
  if allowed_values is None:
398 a5728081 Guido Trotter
    allowed_values = []
399 a5728081 Guido Trotter
400 8b46606c Guido Trotter
  if not isinstance(target, dict):
401 8b46606c Guido Trotter
    msg = "Expected dictionary, got '%s'" % target
402 8b46606c Guido Trotter
    raise errors.TypeEnforcementError(msg)
403 8b46606c Guido Trotter
404 a5728081 Guido Trotter
  for key in target:
405 a5728081 Guido Trotter
    if key not in key_types:
406 a5728081 Guido Trotter
      msg = "Unknown key '%s'" % key
407 a5728081 Guido Trotter
      raise errors.TypeEnforcementError(msg)
408 a5728081 Guido Trotter
409 a5728081 Guido Trotter
    if target[key] in allowed_values:
410 a5728081 Guido Trotter
      continue
411 a5728081 Guido Trotter
412 29921401 Iustin Pop
    ktype = key_types[key]
413 29921401 Iustin Pop
    if ktype not in constants.ENFORCEABLE_TYPES:
414 29921401 Iustin Pop
      msg = "'%s' has non-enforceable type %s" % (key, ktype)
415 a5728081 Guido Trotter
      raise errors.ProgrammerError(msg)
416 a5728081 Guido Trotter
417 29921401 Iustin Pop
    if ktype == constants.VTYPE_STRING:
418 a5728081 Guido Trotter
      if not isinstance(target[key], basestring):
419 a5728081 Guido Trotter
        if isinstance(target[key], bool) and not target[key]:
420 a5728081 Guido Trotter
          target[key] = ''
421 a5728081 Guido Trotter
        else:
422 a5728081 Guido Trotter
          msg = "'%s' (value %s) is not a valid string" % (key, target[key])
423 a5728081 Guido Trotter
          raise errors.TypeEnforcementError(msg)
424 29921401 Iustin Pop
    elif ktype == constants.VTYPE_BOOL:
425 a5728081 Guido Trotter
      if isinstance(target[key], basestring) and target[key]:
426 a5728081 Guido Trotter
        if target[key].lower() == constants.VALUE_FALSE:
427 a5728081 Guido Trotter
          target[key] = False
428 a5728081 Guido Trotter
        elif target[key].lower() == constants.VALUE_TRUE:
429 a5728081 Guido Trotter
          target[key] = True
430 a5728081 Guido Trotter
        else:
431 a5728081 Guido Trotter
          msg = "'%s' (value %s) is not a valid boolean" % (key, target[key])
432 a5728081 Guido Trotter
          raise errors.TypeEnforcementError(msg)
433 a5728081 Guido Trotter
      elif target[key]:
434 a5728081 Guido Trotter
        target[key] = True
435 a5728081 Guido Trotter
      else:
436 a5728081 Guido Trotter
        target[key] = False
437 29921401 Iustin Pop
    elif ktype == constants.VTYPE_SIZE:
438 a5728081 Guido Trotter
      try:
439 a5728081 Guido Trotter
        target[key] = ParseUnit(target[key])
440 a5728081 Guido Trotter
      except errors.UnitParseError, err:
441 a5728081 Guido Trotter
        msg = "'%s' (value %s) is not a valid size. error: %s" % \
442 a5728081 Guido Trotter
              (key, target[key], err)
443 a5728081 Guido Trotter
        raise errors.TypeEnforcementError(msg)
444 29921401 Iustin Pop
    elif ktype == constants.VTYPE_INT:
445 a5728081 Guido Trotter
      try:
446 a5728081 Guido Trotter
        target[key] = int(target[key])
447 a5728081 Guido Trotter
      except (ValueError, TypeError):
448 a5728081 Guido Trotter
        msg = "'%s' (value %s) is not a valid integer" % (key, target[key])
449 a5728081 Guido Trotter
        raise errors.TypeEnforcementError(msg)
450 a5728081 Guido Trotter
451 a5728081 Guido Trotter
452 a8083063 Iustin Pop
def IsProcessAlive(pid):
453 a8083063 Iustin Pop
  """Check if a given pid exists on the system.
454 a8083063 Iustin Pop

455 44bf25ff Iustin Pop
  @note: zombie status is not handled, so zombie processes
456 44bf25ff Iustin Pop
      will be returned as alive
457 58885d79 Iustin Pop
  @type pid: int
458 58885d79 Iustin Pop
  @param pid: the process ID to check
459 58885d79 Iustin Pop
  @rtype: boolean
460 58885d79 Iustin Pop
  @return: True if the process exists
461 a8083063 Iustin Pop

462 a8083063 Iustin Pop
  """
463 d9f311d7 Iustin Pop
  if pid <= 0:
464 d9f311d7 Iustin Pop
    return False
465 d9f311d7 Iustin Pop
466 a8083063 Iustin Pop
  try:
467 44bf25ff Iustin Pop
    os.stat("/proc/%d/status" % pid)
468 44bf25ff Iustin Pop
    return True
469 44bf25ff Iustin Pop
  except EnvironmentError, err:
470 4ca1b175 Alexander Schreiber
    if err.errno in (errno.ENOENT, errno.ENOTDIR):
471 a8083063 Iustin Pop
      return False
472 44bf25ff Iustin Pop
    raise
473 a8083063 Iustin Pop
474 a8083063 Iustin Pop
475 d9f311d7 Iustin Pop
def ReadPidFile(pidfile):
476 58885d79 Iustin Pop
  """Read a pid from a file.
477 fee80e90 Guido Trotter

478 58885d79 Iustin Pop
  @type  pidfile: string
479 58885d79 Iustin Pop
  @param pidfile: path to the file containing the pid
480 58885d79 Iustin Pop
  @rtype: int
481 1de62f37 Guido Trotter
  @return: The process id, if the file exists and contains a valid PID,
482 d9f311d7 Iustin Pop
           otherwise 0
483 fee80e90 Guido Trotter

484 fee80e90 Guido Trotter
  """
485 fee80e90 Guido Trotter
  try:
486 13998ef2 Michael Hanselmann
    raw_data = ReadFile(pidfile)
487 d9f311d7 Iustin Pop
  except EnvironmentError, err:
488 d9f311d7 Iustin Pop
    if err.errno != errno.ENOENT:
489 13998ef2 Michael Hanselmann
      logging.exception("Can't read pid file")
490 d9f311d7 Iustin Pop
    return 0
491 fee80e90 Guido Trotter
492 fee80e90 Guido Trotter
  try:
493 13998ef2 Michael Hanselmann
    pid = int(raw_data)
494 d9f311d7 Iustin Pop
  except ValueError, err:
495 8161a646 Iustin Pop
    logging.info("Can't parse pid file contents", exc_info=True)
496 d9f311d7 Iustin Pop
    return 0
497 fee80e90 Guido Trotter
498 d9f311d7 Iustin Pop
  return pid
499 fee80e90 Guido Trotter
500 fee80e90 Guido Trotter
501 256eb94b Guido Trotter
def MatchNameComponent(key, name_list, case_sensitive=True):
502 a8083063 Iustin Pop
  """Try to match a name against a list.
503 a8083063 Iustin Pop

504 a8083063 Iustin Pop
  This function will try to match a name like test1 against a list
505 58885d79 Iustin Pop
  like C{['test1.example.com', 'test2.example.com', ...]}. Against
506 58885d79 Iustin Pop
  this list, I{'test1'} as well as I{'test1.example'} will match, but
507 58885d79 Iustin Pop
  not I{'test1.ex'}. A multiple match will be considered as no match
508 58885d79 Iustin Pop
  at all (e.g. I{'test1'} against C{['test1.example.com',
509 3a541d90 Iustin Pop
  'test1.example.org']}), except when the key fully matches an entry
510 3a541d90 Iustin Pop
  (e.g. I{'test1'} against C{['test1', 'test1.example.com']}).
511 a8083063 Iustin Pop

512 58885d79 Iustin Pop
  @type key: str
513 58885d79 Iustin Pop
  @param key: the name to be searched
514 58885d79 Iustin Pop
  @type name_list: list
515 58885d79 Iustin Pop
  @param name_list: the list of strings against which to search the key
516 256eb94b Guido Trotter
  @type case_sensitive: boolean
517 256eb94b Guido Trotter
  @param case_sensitive: whether to provide a case-sensitive match
518 a8083063 Iustin Pop

519 58885d79 Iustin Pop
  @rtype: None or str
520 58885d79 Iustin Pop
  @return: None if there is no match I{or} if there are multiple matches,
521 58885d79 Iustin Pop
      otherwise the element from the list which matches
522 a8083063 Iustin Pop

523 a8083063 Iustin Pop
  """
524 3a541d90 Iustin Pop
  if key in name_list:
525 3a541d90 Iustin Pop
    return key
526 256eb94b Guido Trotter
527 256eb94b Guido Trotter
  re_flags = 0
528 256eb94b Guido Trotter
  if not case_sensitive:
529 256eb94b Guido Trotter
    re_flags |= re.IGNORECASE
530 099c52ad Iustin Pop
    key = key.upper()
531 256eb94b Guido Trotter
  mo = re.compile("^%s(\..*)?$" % re.escape(key), re_flags)
532 256eb94b Guido Trotter
  names_filtered = []
533 256eb94b Guido Trotter
  string_matches = []
534 256eb94b Guido Trotter
  for name in name_list:
535 256eb94b Guido Trotter
    if mo.match(name) is not None:
536 256eb94b Guido Trotter
      names_filtered.append(name)
537 099c52ad Iustin Pop
      if not case_sensitive and key == name.upper():
538 256eb94b Guido Trotter
        string_matches.append(name)
539 256eb94b Guido Trotter
540 256eb94b Guido Trotter
  if len(string_matches) == 1:
541 256eb94b Guido Trotter
    return string_matches[0]
542 256eb94b Guido Trotter
  if len(names_filtered) == 1:
543 256eb94b Guido Trotter
    return names_filtered[0]
544 256eb94b Guido Trotter
  return None
545 a8083063 Iustin Pop
546 a8083063 Iustin Pop
547 bcf043c9 Iustin Pop
class HostInfo:
548 89e1fc26 Iustin Pop
  """Class implementing resolver and hostname functionality
549 bcf043c9 Iustin Pop

550 bcf043c9 Iustin Pop
  """
551 89e1fc26 Iustin Pop
  def __init__(self, name=None):
552 bcf043c9 Iustin Pop
    """Initialize the host name object.
553 bcf043c9 Iustin Pop

554 89e1fc26 Iustin Pop
    If the name argument is not passed, it will use this system's
555 89e1fc26 Iustin Pop
    name.
556 bcf043c9 Iustin Pop

557 bcf043c9 Iustin Pop
    """
558 89e1fc26 Iustin Pop
    if name is None:
559 89e1fc26 Iustin Pop
      name = self.SysName()
560 89e1fc26 Iustin Pop
561 89e1fc26 Iustin Pop
    self.query = name
562 89e1fc26 Iustin Pop
    self.name, self.aliases, self.ipaddrs = self.LookupHostname(name)
563 bcf043c9 Iustin Pop
    self.ip = self.ipaddrs[0]
564 bcf043c9 Iustin Pop
565 c8a0948f Michael Hanselmann
  def ShortName(self):
566 c8a0948f Michael Hanselmann
    """Returns the hostname without domain.
567 c8a0948f Michael Hanselmann

568 c8a0948f Michael Hanselmann
    """
569 c8a0948f Michael Hanselmann
    return self.name.split('.')[0]
570 c8a0948f Michael Hanselmann
571 89e1fc26 Iustin Pop
  @staticmethod
572 89e1fc26 Iustin Pop
  def SysName():
573 89e1fc26 Iustin Pop
    """Return the current system's name.
574 bcf043c9 Iustin Pop

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

577 89e1fc26 Iustin Pop
    """
578 89e1fc26 Iustin Pop
    return socket.gethostname()
579 a8083063 Iustin Pop
580 89e1fc26 Iustin Pop
  @staticmethod
581 89e1fc26 Iustin Pop
  def LookupHostname(hostname):
582 89e1fc26 Iustin Pop
    """Look up hostname
583 a8083063 Iustin Pop

584 58885d79 Iustin Pop
    @type hostname: str
585 58885d79 Iustin Pop
    @param hostname: hostname to look up
586 89e1fc26 Iustin Pop

587 58885d79 Iustin Pop
    @rtype: tuple
588 58885d79 Iustin Pop
    @return: a tuple (name, aliases, ipaddrs) as returned by
589 58885d79 Iustin Pop
        C{socket.gethostbyname_ex}
590 58885d79 Iustin Pop
    @raise errors.ResolverError: in case of errors in resolving
591 89e1fc26 Iustin Pop

592 89e1fc26 Iustin Pop
    """
593 89e1fc26 Iustin Pop
    try:
594 89e1fc26 Iustin Pop
      result = socket.gethostbyname_ex(hostname)
595 89e1fc26 Iustin Pop
    except socket.gaierror, err:
596 89e1fc26 Iustin Pop
      # hostname not found in DNS
597 89e1fc26 Iustin Pop
      raise errors.ResolverError(hostname, err.args[0], err.args[1])
598 a8083063 Iustin Pop
599 89e1fc26 Iustin Pop
    return result
600 a8083063 Iustin Pop
601 a8083063 Iustin Pop
602 104f4ca1 Iustin Pop
def GetHostInfo(name=None):
603 104f4ca1 Iustin Pop
  """Lookup host name and raise an OpPrereqError for failures"""
604 104f4ca1 Iustin Pop
605 104f4ca1 Iustin Pop
  try:
606 104f4ca1 Iustin Pop
    return HostInfo(name)
607 104f4ca1 Iustin Pop
  except errors.ResolverError, err:
608 104f4ca1 Iustin Pop
    raise errors.OpPrereqError("The given name (%s) does not resolve: %s" %
609 104f4ca1 Iustin Pop
                               (err[0], err[2]), errors.ECODE_RESOLVER)
610 104f4ca1 Iustin Pop
611 104f4ca1 Iustin Pop
612 a8083063 Iustin Pop
def ListVolumeGroups():
613 a8083063 Iustin Pop
  """List volume groups and their size
614 a8083063 Iustin Pop

615 58885d79 Iustin Pop
  @rtype: dict
616 58885d79 Iustin Pop
  @return:
617 58885d79 Iustin Pop
       Dictionary with keys volume name and values
618 58885d79 Iustin Pop
       the size of the volume
619 a8083063 Iustin Pop

620 a8083063 Iustin Pop
  """
621 a8083063 Iustin Pop
  command = "vgs --noheadings --units m --nosuffix -o name,size"
622 a8083063 Iustin Pop
  result = RunCmd(command)
623 a8083063 Iustin Pop
  retval = {}
624 a8083063 Iustin Pop
  if result.failed:
625 a8083063 Iustin Pop
    return retval
626 a8083063 Iustin Pop
627 a8083063 Iustin Pop
  for line in result.stdout.splitlines():
628 a8083063 Iustin Pop
    try:
629 a8083063 Iustin Pop
      name, size = line.split()
630 a8083063 Iustin Pop
      size = int(float(size))
631 a8083063 Iustin Pop
    except (IndexError, ValueError), err:
632 bb698c1f Iustin Pop
      logging.error("Invalid output from vgs (%s): %s", err, line)
633 a8083063 Iustin Pop
      continue
634 a8083063 Iustin Pop
635 a8083063 Iustin Pop
    retval[name] = size
636 a8083063 Iustin Pop
637 a8083063 Iustin Pop
  return retval
638 a8083063 Iustin Pop
639 a8083063 Iustin Pop
640 a8083063 Iustin Pop
def BridgeExists(bridge):
641 a8083063 Iustin Pop
  """Check whether the given bridge exists in the system
642 a8083063 Iustin Pop

643 58885d79 Iustin Pop
  @type bridge: str
644 58885d79 Iustin Pop
  @param bridge: the bridge name to check
645 58885d79 Iustin Pop
  @rtype: boolean
646 58885d79 Iustin Pop
  @return: True if it does
647 a8083063 Iustin Pop

648 a8083063 Iustin Pop
  """
649 a8083063 Iustin Pop
  return os.path.isdir("/sys/class/net/%s/bridge" % bridge)
650 a8083063 Iustin Pop
651 a8083063 Iustin Pop
652 a8083063 Iustin Pop
def NiceSort(name_list):
653 a8083063 Iustin Pop
  """Sort a list of strings based on digit and non-digit groupings.
654 a8083063 Iustin Pop

655 58885d79 Iustin Pop
  Given a list of names C{['a1', 'a10', 'a11', 'a2']} this function
656 58885d79 Iustin Pop
  will sort the list in the logical order C{['a1', 'a2', 'a10',
657 58885d79 Iustin Pop
  'a11']}.
658 a8083063 Iustin Pop

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

663 58885d79 Iustin Pop
  @type name_list: list
664 58885d79 Iustin Pop
  @param name_list: the names to be sorted
665 58885d79 Iustin Pop
  @rtype: list
666 58885d79 Iustin Pop
  @return: a copy of the name list sorted with our algorithm
667 a8083063 Iustin Pop

668 a8083063 Iustin Pop
  """
669 a8083063 Iustin Pop
  _SORTER_BASE = "(\D+|\d+)"
670 a8083063 Iustin Pop
  _SORTER_FULL = "^%s%s?%s?%s?%s?%s?%s?%s?.*$" % (_SORTER_BASE, _SORTER_BASE,
671 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE,
672 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE,
673 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE)
674 a8083063 Iustin Pop
  _SORTER_RE = re.compile(_SORTER_FULL)
675 a8083063 Iustin Pop
  _SORTER_NODIGIT = re.compile("^\D*$")
676 a8083063 Iustin Pop
  def _TryInt(val):
677 a8083063 Iustin Pop
    """Attempts to convert a variable to integer."""
678 a8083063 Iustin Pop
    if val is None or _SORTER_NODIGIT.match(val):
679 a8083063 Iustin Pop
      return val
680 a8083063 Iustin Pop
    rval = int(val)
681 a8083063 Iustin Pop
    return rval
682 a8083063 Iustin Pop
683 a8083063 Iustin Pop
  to_sort = [([_TryInt(grp) for grp in _SORTER_RE.match(name).groups()], name)
684 a8083063 Iustin Pop
             for name in name_list]
685 a8083063 Iustin Pop
  to_sort.sort()
686 a8083063 Iustin Pop
  return [tup[1] for tup in to_sort]
687 a8083063 Iustin Pop
688 a8083063 Iustin Pop
689 a8083063 Iustin Pop
def TryConvert(fn, val):
690 a8083063 Iustin Pop
  """Try to convert a value ignoring errors.
691 a8083063 Iustin Pop

692 58885d79 Iustin Pop
  This function tries to apply function I{fn} to I{val}. If no
693 58885d79 Iustin Pop
  C{ValueError} or C{TypeError} exceptions are raised, it will return
694 58885d79 Iustin Pop
  the result, else it will return the original value. Any other
695 58885d79 Iustin Pop
  exceptions are propagated to the caller.
696 58885d79 Iustin Pop

697 58885d79 Iustin Pop
  @type fn: callable
698 58885d79 Iustin Pop
  @param fn: function to apply to the value
699 58885d79 Iustin Pop
  @param val: the value to be converted
700 58885d79 Iustin Pop
  @return: The converted value if the conversion was successful,
701 58885d79 Iustin Pop
      otherwise the original value.
702 a8083063 Iustin Pop

703 a8083063 Iustin Pop
  """
704 a8083063 Iustin Pop
  try:
705 a8083063 Iustin Pop
    nv = fn(val)
706 7c4d6c7b Michael Hanselmann
  except (ValueError, TypeError):
707 a8083063 Iustin Pop
    nv = val
708 a8083063 Iustin Pop
  return nv
709 a8083063 Iustin Pop
710 a8083063 Iustin Pop
711 a8083063 Iustin Pop
def IsValidIP(ip):
712 58885d79 Iustin Pop
  """Verifies the syntax of an IPv4 address.
713 a8083063 Iustin Pop

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

717 58885d79 Iustin Pop
  @type ip: str
718 58885d79 Iustin Pop
  @param ip: the address to be checked
719 58885d79 Iustin Pop
  @rtype: a regular expression match object
720 5bbd3f7f Michael Hanselmann
  @return: a regular expression match object, or None if the
721 58885d79 Iustin Pop
      address is not valid
722 a8083063 Iustin Pop

723 a8083063 Iustin Pop
  """
724 a8083063 Iustin Pop
  unit = "(0|[1-9]\d{0,2})"
725 58885d79 Iustin Pop
  #TODO: convert and return only boolean
726 a8083063 Iustin Pop
  return re.match("^%s\.%s\.%s\.%s$" % (unit, unit, unit, unit), ip)
727 a8083063 Iustin Pop
728 a8083063 Iustin Pop
729 a8083063 Iustin Pop
def IsValidShellParam(word):
730 a8083063 Iustin Pop
  """Verifies is the given word is safe from the shell's p.o.v.
731 a8083063 Iustin Pop

732 a8083063 Iustin Pop
  This means that we can pass this to a command via the shell and be
733 a8083063 Iustin Pop
  sure that it doesn't alter the command line and is passed as such to
734 a8083063 Iustin Pop
  the actual command.
735 a8083063 Iustin Pop

736 a8083063 Iustin Pop
  Note that we are overly restrictive here, in order to be on the safe
737 a8083063 Iustin Pop
  side.
738 a8083063 Iustin Pop

739 58885d79 Iustin Pop
  @type word: str
740 58885d79 Iustin Pop
  @param word: the word to check
741 58885d79 Iustin Pop
  @rtype: boolean
742 58885d79 Iustin Pop
  @return: True if the word is 'safe'
743 58885d79 Iustin Pop

744 a8083063 Iustin Pop
  """
745 a8083063 Iustin Pop
  return bool(re.match("^[-a-zA-Z0-9._+/:%@]+$", word))
746 a8083063 Iustin Pop
747 a8083063 Iustin Pop
748 a8083063 Iustin Pop
def BuildShellCmd(template, *args):
749 a8083063 Iustin Pop
  """Build a safe shell command line from the given arguments.
750 a8083063 Iustin Pop

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

756 58885d79 Iustin Pop
  @type template: str
757 58885d79 Iustin Pop
  @param template: the string holding the template for the
758 58885d79 Iustin Pop
      string formatting
759 58885d79 Iustin Pop
  @rtype: str
760 58885d79 Iustin Pop
  @return: the expanded command line
761 58885d79 Iustin Pop

762 a8083063 Iustin Pop
  """
763 a8083063 Iustin Pop
  for word in args:
764 a8083063 Iustin Pop
    if not IsValidShellParam(word):
765 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Shell argument '%s' contains"
766 3ecf6786 Iustin Pop
                                   " invalid characters" % word)
767 a8083063 Iustin Pop
  return template % args
768 a8083063 Iustin Pop
769 a8083063 Iustin Pop
770 9fbfbb7b Iustin Pop
def FormatUnit(value, units):
771 a8083063 Iustin Pop
  """Formats an incoming number of MiB with the appropriate unit.
772 a8083063 Iustin Pop

773 58885d79 Iustin Pop
  @type value: int
774 58885d79 Iustin Pop
  @param value: integer representing the value in MiB (1048576)
775 9fbfbb7b Iustin Pop
  @type units: char
776 9fbfbb7b Iustin Pop
  @param units: the type of formatting we should do:
777 9fbfbb7b Iustin Pop
      - 'h' for automatic scaling
778 9fbfbb7b Iustin Pop
      - 'm' for MiBs
779 9fbfbb7b Iustin Pop
      - 'g' for GiBs
780 9fbfbb7b Iustin Pop
      - 't' for TiBs
781 58885d79 Iustin Pop
  @rtype: str
782 58885d79 Iustin Pop
  @return: the formatted value (with suffix)
783 a8083063 Iustin Pop

784 a8083063 Iustin Pop
  """
785 9fbfbb7b Iustin Pop
  if units not in ('m', 'g', 't', 'h'):
786 9fbfbb7b Iustin Pop
    raise errors.ProgrammerError("Invalid unit specified '%s'" % str(units))
787 a8083063 Iustin Pop
788 9fbfbb7b Iustin Pop
  suffix = ''
789 9fbfbb7b Iustin Pop
790 9fbfbb7b Iustin Pop
  if units == 'm' or (units == 'h' and value < 1024):
791 9fbfbb7b Iustin Pop
    if units == 'h':
792 9fbfbb7b Iustin Pop
      suffix = 'M'
793 9fbfbb7b Iustin Pop
    return "%d%s" % (round(value, 0), suffix)
794 9fbfbb7b Iustin Pop
795 9fbfbb7b Iustin Pop
  elif units == 'g' or (units == 'h' and value < (1024 * 1024)):
796 9fbfbb7b Iustin Pop
    if units == 'h':
797 9fbfbb7b Iustin Pop
      suffix = 'G'
798 9fbfbb7b Iustin Pop
    return "%0.1f%s" % (round(float(value) / 1024, 1), suffix)
799 a8083063 Iustin Pop
800 a8083063 Iustin Pop
  else:
801 9fbfbb7b Iustin Pop
    if units == 'h':
802 9fbfbb7b Iustin Pop
      suffix = 'T'
803 9fbfbb7b Iustin Pop
    return "%0.1f%s" % (round(float(value) / 1024 / 1024, 1), suffix)
804 a8083063 Iustin Pop
805 a8083063 Iustin Pop
806 a8083063 Iustin Pop
def ParseUnit(input_string):
807 a8083063 Iustin Pop
  """Tries to extract number and scale from the given string.
808 a8083063 Iustin Pop

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

813 a8083063 Iustin Pop
  """
814 9939547b Iustin Pop
  m = re.match('^([.\d]+)\s*([a-zA-Z]+)?$', str(input_string))
815 a8083063 Iustin Pop
  if not m:
816 3ecf6786 Iustin Pop
    raise errors.UnitParseError("Invalid format")
817 a8083063 Iustin Pop
818 a8083063 Iustin Pop
  value = float(m.groups()[0])
819 a8083063 Iustin Pop
820 a8083063 Iustin Pop
  unit = m.groups()[1]
821 a8083063 Iustin Pop
  if unit:
822 a8083063 Iustin Pop
    lcunit = unit.lower()
823 a8083063 Iustin Pop
  else:
824 a8083063 Iustin Pop
    lcunit = 'm'
825 a8083063 Iustin Pop
826 a8083063 Iustin Pop
  if lcunit in ('m', 'mb', 'mib'):
827 a8083063 Iustin Pop
    # Value already in MiB
828 a8083063 Iustin Pop
    pass
829 a8083063 Iustin Pop
830 a8083063 Iustin Pop
  elif lcunit in ('g', 'gb', 'gib'):
831 a8083063 Iustin Pop
    value *= 1024
832 a8083063 Iustin Pop
833 a8083063 Iustin Pop
  elif lcunit in ('t', 'tb', 'tib'):
834 a8083063 Iustin Pop
    value *= 1024 * 1024
835 a8083063 Iustin Pop
836 a8083063 Iustin Pop
  else:
837 3ecf6786 Iustin Pop
    raise errors.UnitParseError("Unknown unit: %s" % unit)
838 a8083063 Iustin Pop
839 a8083063 Iustin Pop
  # Make sure we round up
840 a8083063 Iustin Pop
  if int(value) < value:
841 a8083063 Iustin Pop
    value += 1
842 a8083063 Iustin Pop
843 a8083063 Iustin Pop
  # Round up to the next multiple of 4
844 a8083063 Iustin Pop
  value = int(value)
845 a8083063 Iustin Pop
  if value % 4:
846 a8083063 Iustin Pop
    value += 4 - value % 4
847 a8083063 Iustin Pop
848 a8083063 Iustin Pop
  return value
849 a8083063 Iustin Pop
850 a8083063 Iustin Pop
851 a8083063 Iustin Pop
def AddAuthorizedKey(file_name, key):
852 a8083063 Iustin Pop
  """Adds an SSH public key to an authorized_keys file.
853 a8083063 Iustin Pop

854 58885d79 Iustin Pop
  @type file_name: str
855 58885d79 Iustin Pop
  @param file_name: path to authorized_keys file
856 58885d79 Iustin Pop
  @type key: str
857 58885d79 Iustin Pop
  @param key: string containing key
858 58885d79 Iustin Pop

859 a8083063 Iustin Pop
  """
860 a8083063 Iustin Pop
  key_fields = key.split()
861 a8083063 Iustin Pop
862 a8083063 Iustin Pop
  f = open(file_name, 'a+')
863 a8083063 Iustin Pop
  try:
864 a8083063 Iustin Pop
    nl = True
865 a8083063 Iustin Pop
    for line in f:
866 a8083063 Iustin Pop
      # Ignore whitespace changes
867 a8083063 Iustin Pop
      if line.split() == key_fields:
868 a8083063 Iustin Pop
        break
869 a8083063 Iustin Pop
      nl = line.endswith('\n')
870 a8083063 Iustin Pop
    else:
871 a8083063 Iustin Pop
      if not nl:
872 a8083063 Iustin Pop
        f.write("\n")
873 a8083063 Iustin Pop
      f.write(key.rstrip('\r\n'))
874 a8083063 Iustin Pop
      f.write("\n")
875 a8083063 Iustin Pop
      f.flush()
876 a8083063 Iustin Pop
  finally:
877 a8083063 Iustin Pop
    f.close()
878 a8083063 Iustin Pop
879 a8083063 Iustin Pop
880 a8083063 Iustin Pop
def RemoveAuthorizedKey(file_name, key):
881 a8083063 Iustin Pop
  """Removes an SSH public key from an authorized_keys file.
882 a8083063 Iustin Pop

883 58885d79 Iustin Pop
  @type file_name: str
884 58885d79 Iustin Pop
  @param file_name: path to authorized_keys file
885 58885d79 Iustin Pop
  @type key: str
886 58885d79 Iustin Pop
  @param key: string containing key
887 58885d79 Iustin Pop

888 a8083063 Iustin Pop
  """
889 a8083063 Iustin Pop
  key_fields = key.split()
890 a8083063 Iustin Pop
891 a8083063 Iustin Pop
  fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name))
892 a8083063 Iustin Pop
  try:
893 59f82e3f Michael Hanselmann
    out = os.fdopen(fd, 'w')
894 a8083063 Iustin Pop
    try:
895 59f82e3f Michael Hanselmann
      f = open(file_name, 'r')
896 59f82e3f Michael Hanselmann
      try:
897 59f82e3f Michael Hanselmann
        for line in f:
898 59f82e3f Michael Hanselmann
          # Ignore whitespace changes while comparing lines
899 59f82e3f Michael Hanselmann
          if line.split() != key_fields:
900 59f82e3f Michael Hanselmann
            out.write(line)
901 899d2a81 Michael Hanselmann
902 899d2a81 Michael Hanselmann
        out.flush()
903 899d2a81 Michael Hanselmann
        os.rename(tmpname, file_name)
904 899d2a81 Michael Hanselmann
      finally:
905 899d2a81 Michael Hanselmann
        f.close()
906 899d2a81 Michael Hanselmann
    finally:
907 899d2a81 Michael Hanselmann
      out.close()
908 899d2a81 Michael Hanselmann
  except:
909 899d2a81 Michael Hanselmann
    RemoveFile(tmpname)
910 899d2a81 Michael Hanselmann
    raise
911 899d2a81 Michael Hanselmann
912 899d2a81 Michael Hanselmann
913 9440aeab Michael Hanselmann
def SetEtcHostsEntry(file_name, ip, hostname, aliases):
914 9440aeab Michael Hanselmann
  """Sets the name of an IP address and hostname in /etc/hosts.
915 899d2a81 Michael Hanselmann

916 58885d79 Iustin Pop
  @type file_name: str
917 58885d79 Iustin Pop
  @param file_name: path to the file to modify (usually C{/etc/hosts})
918 58885d79 Iustin Pop
  @type ip: str
919 58885d79 Iustin Pop
  @param ip: the IP address
920 58885d79 Iustin Pop
  @type hostname: str
921 58885d79 Iustin Pop
  @param hostname: the hostname to be added
922 58885d79 Iustin Pop
  @type aliases: list
923 58885d79 Iustin Pop
  @param aliases: the list of aliases to add for the hostname
924 58885d79 Iustin Pop

925 899d2a81 Michael Hanselmann
  """
926 9b977740 Guido Trotter
  # FIXME: use WriteFile + fn rather than duplicating its efforts
927 7fbb1f65 Michael Hanselmann
  # Ensure aliases are unique
928 7fbb1f65 Michael Hanselmann
  aliases = UniqueSequence([hostname] + aliases)[1:]
929 7fbb1f65 Michael Hanselmann
930 9440aeab Michael Hanselmann
  fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name))
931 899d2a81 Michael Hanselmann
  try:
932 9440aeab Michael Hanselmann
    out = os.fdopen(fd, 'w')
933 9440aeab Michael Hanselmann
    try:
934 9440aeab Michael Hanselmann
      f = open(file_name, 'r')
935 9440aeab Michael Hanselmann
      try:
936 9440aeab Michael Hanselmann
        for line in f:
937 9440aeab Michael Hanselmann
          fields = line.split()
938 7e3dbb94 Iustin Pop
          if fields and not fields[0].startswith('#') and ip == fields[0]:
939 9440aeab Michael Hanselmann
            continue
940 9440aeab Michael Hanselmann
          out.write(line)
941 9440aeab Michael Hanselmann
942 7e3dbb94 Iustin Pop
        out.write("%s\t%s" % (ip, hostname))
943 9440aeab Michael Hanselmann
        if aliases:
944 9440aeab Michael Hanselmann
          out.write(" %s" % ' '.join(aliases))
945 9440aeab Michael Hanselmann
        out.write('\n')
946 9440aeab Michael Hanselmann
947 9440aeab Michael Hanselmann
        out.flush()
948 2e3e75b7 Michael Hanselmann
        os.fsync(out)
949 9b977740 Guido Trotter
        os.chmod(tmpname, 0644)
950 9440aeab Michael Hanselmann
        os.rename(tmpname, file_name)
951 9440aeab Michael Hanselmann
      finally:
952 9440aeab Michael Hanselmann
        f.close()
953 9440aeab Michael Hanselmann
    finally:
954 9440aeab Michael Hanselmann
      out.close()
955 9440aeab Michael Hanselmann
  except:
956 9440aeab Michael Hanselmann
    RemoveFile(tmpname)
957 9440aeab Michael Hanselmann
    raise
958 899d2a81 Michael Hanselmann
959 899d2a81 Michael Hanselmann
960 d9c02ca6 Michael Hanselmann
def AddHostToEtcHosts(hostname):
961 d9c02ca6 Michael Hanselmann
  """Wrapper around SetEtcHostsEntry.
962 d9c02ca6 Michael Hanselmann

963 58885d79 Iustin Pop
  @type hostname: str
964 58885d79 Iustin Pop
  @param hostname: a hostname that will be resolved and added to
965 58885d79 Iustin Pop
      L{constants.ETC_HOSTS}
966 58885d79 Iustin Pop

967 d9c02ca6 Michael Hanselmann
  """
968 d9c02ca6 Michael Hanselmann
  hi = HostInfo(name=hostname)
969 d9c02ca6 Michael Hanselmann
  SetEtcHostsEntry(constants.ETC_HOSTS, hi.ip, hi.name, [hi.ShortName()])
970 d9c02ca6 Michael Hanselmann
971 d9c02ca6 Michael Hanselmann
972 899d2a81 Michael Hanselmann
def RemoveEtcHostsEntry(file_name, hostname):
973 3e1cdf9f Michael Hanselmann
  """Removes a hostname from /etc/hosts.
974 899d2a81 Michael Hanselmann

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

977 58885d79 Iustin Pop
  @type file_name: str
978 58885d79 Iustin Pop
  @param file_name: path to the file to modify (usually C{/etc/hosts})
979 58885d79 Iustin Pop
  @type hostname: str
980 58885d79 Iustin Pop
  @param hostname: the hostname to be removed
981 58885d79 Iustin Pop

982 899d2a81 Michael Hanselmann
  """
983 9b977740 Guido Trotter
  # FIXME: use WriteFile + fn rather than duplicating its efforts
984 899d2a81 Michael Hanselmann
  fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name))
985 899d2a81 Michael Hanselmann
  try:
986 899d2a81 Michael Hanselmann
    out = os.fdopen(fd, 'w')
987 899d2a81 Michael Hanselmann
    try:
988 899d2a81 Michael Hanselmann
      f = open(file_name, 'r')
989 899d2a81 Michael Hanselmann
      try:
990 899d2a81 Michael Hanselmann
        for line in f:
991 899d2a81 Michael Hanselmann
          fields = line.split()
992 899d2a81 Michael Hanselmann
          if len(fields) > 1 and not fields[0].startswith('#'):
993 899d2a81 Michael Hanselmann
            names = fields[1:]
994 899d2a81 Michael Hanselmann
            if hostname in names:
995 899d2a81 Michael Hanselmann
              while hostname in names:
996 899d2a81 Michael Hanselmann
                names.remove(hostname)
997 899d2a81 Michael Hanselmann
              if names:
998 9440aeab Michael Hanselmann
                out.write("%s %s\n" % (fields[0], ' '.join(names)))
999 899d2a81 Michael Hanselmann
              continue
1000 899d2a81 Michael Hanselmann
1001 899d2a81 Michael Hanselmann
          out.write(line)
1002 59f82e3f Michael Hanselmann
1003 59f82e3f Michael Hanselmann
        out.flush()
1004 2e3e75b7 Michael Hanselmann
        os.fsync(out)
1005 9b977740 Guido Trotter
        os.chmod(tmpname, 0644)
1006 59f82e3f Michael Hanselmann
        os.rename(tmpname, file_name)
1007 59f82e3f Michael Hanselmann
      finally:
1008 59f82e3f Michael Hanselmann
        f.close()
1009 a8083063 Iustin Pop
    finally:
1010 59f82e3f Michael Hanselmann
      out.close()
1011 59f82e3f Michael Hanselmann
  except:
1012 59f82e3f Michael Hanselmann
    RemoveFile(tmpname)
1013 59f82e3f Michael Hanselmann
    raise
1014 a8083063 Iustin Pop
1015 a8083063 Iustin Pop
1016 d9c02ca6 Michael Hanselmann
def RemoveHostFromEtcHosts(hostname):
1017 d9c02ca6 Michael Hanselmann
  """Wrapper around RemoveEtcHostsEntry.
1018 d9c02ca6 Michael Hanselmann

1019 58885d79 Iustin Pop
  @type hostname: str
1020 58885d79 Iustin Pop
  @param hostname: hostname that will be resolved and its
1021 58885d79 Iustin Pop
      full and shot name will be removed from
1022 58885d79 Iustin Pop
      L{constants.ETC_HOSTS}
1023 58885d79 Iustin Pop

1024 d9c02ca6 Michael Hanselmann
  """
1025 d9c02ca6 Michael Hanselmann
  hi = HostInfo(name=hostname)
1026 d9c02ca6 Michael Hanselmann
  RemoveEtcHostsEntry(constants.ETC_HOSTS, hi.name)
1027 d9c02ca6 Michael Hanselmann
  RemoveEtcHostsEntry(constants.ETC_HOSTS, hi.ShortName())
1028 d9c02ca6 Michael Hanselmann
1029 d9c02ca6 Michael Hanselmann
1030 a8083063 Iustin Pop
def CreateBackup(file_name):
1031 a8083063 Iustin Pop
  """Creates a backup of a file.
1032 a8083063 Iustin Pop

1033 58885d79 Iustin Pop
  @type file_name: str
1034 58885d79 Iustin Pop
  @param file_name: file to be backed up
1035 58885d79 Iustin Pop
  @rtype: str
1036 58885d79 Iustin Pop
  @return: the path to the newly created backup
1037 58885d79 Iustin Pop
  @raise errors.ProgrammerError: for invalid file names
1038 a8083063 Iustin Pop

1039 a8083063 Iustin Pop
  """
1040 a8083063 Iustin Pop
  if not os.path.isfile(file_name):
1041 3ecf6786 Iustin Pop
    raise errors.ProgrammerError("Can't make a backup of a non-file '%s'" %
1042 3ecf6786 Iustin Pop
                                file_name)
1043 a8083063 Iustin Pop
1044 081b1e69 Michael Hanselmann
  prefix = '%s.backup-%d.' % (os.path.basename(file_name), int(time.time()))
1045 65fe4693 Iustin Pop
  dir_name = os.path.dirname(file_name)
1046 081b1e69 Michael Hanselmann
1047 081b1e69 Michael Hanselmann
  fsrc = open(file_name, 'rb')
1048 081b1e69 Michael Hanselmann
  try:
1049 65fe4693 Iustin Pop
    (fd, backup_name) = tempfile.mkstemp(prefix=prefix, dir=dir_name)
1050 081b1e69 Michael Hanselmann
    fdst = os.fdopen(fd, 'wb')
1051 081b1e69 Michael Hanselmann
    try:
1052 081b1e69 Michael Hanselmann
      shutil.copyfileobj(fsrc, fdst)
1053 081b1e69 Michael Hanselmann
    finally:
1054 081b1e69 Michael Hanselmann
      fdst.close()
1055 081b1e69 Michael Hanselmann
  finally:
1056 081b1e69 Michael Hanselmann
    fsrc.close()
1057 081b1e69 Michael Hanselmann
1058 a8083063 Iustin Pop
  return backup_name
1059 a8083063 Iustin Pop
1060 a8083063 Iustin Pop
1061 a8083063 Iustin Pop
def ShellQuote(value):
1062 a8083063 Iustin Pop
  """Quotes shell argument according to POSIX.
1063 3ecf6786 Iustin Pop

1064 58885d79 Iustin Pop
  @type value: str
1065 58885d79 Iustin Pop
  @param value: the argument to be quoted
1066 58885d79 Iustin Pop
  @rtype: str
1067 58885d79 Iustin Pop
  @return: the quoted value
1068 58885d79 Iustin Pop

1069 a8083063 Iustin Pop
  """
1070 a8083063 Iustin Pop
  if _re_shell_unquoted.match(value):
1071 a8083063 Iustin Pop
    return value
1072 a8083063 Iustin Pop
  else:
1073 a8083063 Iustin Pop
    return "'%s'" % value.replace("'", "'\\''")
1074 a8083063 Iustin Pop
1075 a8083063 Iustin Pop
1076 a8083063 Iustin Pop
def ShellQuoteArgs(args):
1077 58885d79 Iustin Pop
  """Quotes a list of shell arguments.
1078 58885d79 Iustin Pop

1079 58885d79 Iustin Pop
  @type args: list
1080 58885d79 Iustin Pop
  @param args: list of arguments to be quoted
1081 58885d79 Iustin Pop
  @rtype: str
1082 5bbd3f7f Michael Hanselmann
  @return: the quoted arguments concatenated with spaces
1083 a8083063 Iustin Pop

1084 a8083063 Iustin Pop
  """
1085 a8083063 Iustin Pop
  return ' '.join([ShellQuote(i) for i in args])
1086 88d14415 Michael Hanselmann
1087 88d14415 Michael Hanselmann
1088 b15d625f Iustin Pop
def TcpPing(target, port, timeout=10, live_port_needed=False, source=None):
1089 2c30e9d7 Alexander Schreiber
  """Simple ping implementation using TCP connect(2).
1090 2c30e9d7 Alexander Schreiber

1091 58885d79 Iustin Pop
  Check if the given IP is reachable by doing attempting a TCP connect
1092 58885d79 Iustin Pop
  to it.
1093 58885d79 Iustin Pop

1094 58885d79 Iustin Pop
  @type target: str
1095 58885d79 Iustin Pop
  @param target: the IP or hostname to ping
1096 58885d79 Iustin Pop
  @type port: int
1097 58885d79 Iustin Pop
  @param port: the port to connect to
1098 58885d79 Iustin Pop
  @type timeout: int
1099 5bbd3f7f Michael Hanselmann
  @param timeout: the timeout on the connection attempt
1100 58885d79 Iustin Pop
  @type live_port_needed: boolean
1101 58885d79 Iustin Pop
  @param live_port_needed: whether a closed port will cause the
1102 58885d79 Iustin Pop
      function to return failure, as if there was a timeout
1103 58885d79 Iustin Pop
  @type source: str or None
1104 58885d79 Iustin Pop
  @param source: if specified, will cause the connect to be made
1105 58885d79 Iustin Pop
      from this specific source address; failures to bind other
1106 58885d79 Iustin Pop
      than C{EADDRNOTAVAIL} will be ignored
1107 2c30e9d7 Alexander Schreiber

1108 2c30e9d7 Alexander Schreiber
  """
1109 2c30e9d7 Alexander Schreiber
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1110 2c30e9d7 Alexander Schreiber
1111 0b5ad33e Iustin Pop
  success = False
1112 2c30e9d7 Alexander Schreiber
1113 b15d625f Iustin Pop
  if source is not None:
1114 b15d625f Iustin Pop
    try:
1115 b15d625f Iustin Pop
      sock.bind((source, 0))
1116 7c4d6c7b Michael Hanselmann
    except socket.error, (errcode, _):
1117 b15d625f Iustin Pop
      if errcode == errno.EADDRNOTAVAIL:
1118 b15d625f Iustin Pop
        success = False
1119 2c30e9d7 Alexander Schreiber
1120 2c30e9d7 Alexander Schreiber
  sock.settimeout(timeout)
1121 2c30e9d7 Alexander Schreiber
1122 2c30e9d7 Alexander Schreiber
  try:
1123 2c30e9d7 Alexander Schreiber
    sock.connect((target, port))
1124 2c30e9d7 Alexander Schreiber
    sock.close()
1125 2c30e9d7 Alexander Schreiber
    success = True
1126 2c30e9d7 Alexander Schreiber
  except socket.timeout:
1127 2c30e9d7 Alexander Schreiber
    success = False
1128 099c52ad Iustin Pop
  except socket.error, (errcode, _):
1129 4ca1b175 Alexander Schreiber
    success = (not live_port_needed) and (errcode == errno.ECONNREFUSED)
1130 2c30e9d7 Alexander Schreiber
1131 2c30e9d7 Alexander Schreiber
  return success
1132 eedbda4b Michael Hanselmann
1133 eedbda4b Michael Hanselmann
1134 caad16e2 Iustin Pop
def OwnIpAddress(address):
1135 caad16e2 Iustin Pop
  """Check if the current host has the the given IP address.
1136 caad16e2 Iustin Pop

1137 58885d79 Iustin Pop
  Currently this is done by TCP-pinging the address from the loopback
1138 caad16e2 Iustin Pop
  address.
1139 caad16e2 Iustin Pop

1140 caad16e2 Iustin Pop
  @type address: string
1141 5bbd3f7f Michael Hanselmann
  @param address: the address to check
1142 caad16e2 Iustin Pop
  @rtype: bool
1143 58885d79 Iustin Pop
  @return: True if we own the address
1144 caad16e2 Iustin Pop

1145 caad16e2 Iustin Pop
  """
1146 caad16e2 Iustin Pop
  return TcpPing(address, constants.DEFAULT_NODED_PORT,
1147 caad16e2 Iustin Pop
                 source=constants.LOCALHOST_IP_ADDRESS)
1148 caad16e2 Iustin Pop
1149 caad16e2 Iustin Pop
1150 eedbda4b Michael Hanselmann
def ListVisibleFiles(path):
1151 58885d79 Iustin Pop
  """Returns a list of visible files in a directory.
1152 58885d79 Iustin Pop

1153 58885d79 Iustin Pop
  @type path: str
1154 58885d79 Iustin Pop
  @param path: the directory to enumerate
1155 58885d79 Iustin Pop
  @rtype: list
1156 58885d79 Iustin Pop
  @return: the list of all files not starting with a dot
1157 eedbda4b Michael Hanselmann

1158 eedbda4b Michael Hanselmann
  """
1159 f3299a07 Michael Hanselmann
  files = [i for i in os.listdir(path) if not i.startswith(".")]
1160 f3299a07 Michael Hanselmann
  files.sort()
1161 f3299a07 Michael Hanselmann
  return files
1162 2f8b60b3 Iustin Pop
1163 2f8b60b3 Iustin Pop
1164 257f4c0a Iustin Pop
def GetHomeDir(user, default=None):
1165 257f4c0a Iustin Pop
  """Try to get the homedir of the given user.
1166 257f4c0a Iustin Pop

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

1171 2f8b60b3 Iustin Pop
  """
1172 2f8b60b3 Iustin Pop
  try:
1173 257f4c0a Iustin Pop
    if isinstance(user, basestring):
1174 257f4c0a Iustin Pop
      result = pwd.getpwnam(user)
1175 257f4c0a Iustin Pop
    elif isinstance(user, (int, long)):
1176 257f4c0a Iustin Pop
      result = pwd.getpwuid(user)
1177 257f4c0a Iustin Pop
    else:
1178 257f4c0a Iustin Pop
      raise errors.ProgrammerError("Invalid type passed to GetHomeDir (%s)" %
1179 257f4c0a Iustin Pop
                                   type(user))
1180 2f8b60b3 Iustin Pop
  except KeyError:
1181 2f8b60b3 Iustin Pop
    return default
1182 2f8b60b3 Iustin Pop
  return result.pw_dir
1183 59072e7e Michael Hanselmann
1184 59072e7e Michael Hanselmann
1185 24818e8f Michael Hanselmann
def NewUUID():
1186 59072e7e Michael Hanselmann
  """Returns a random UUID.
1187 59072e7e Michael Hanselmann

1188 58885d79 Iustin Pop
  @note: This is a Linux-specific method as it uses the /proc
1189 58885d79 Iustin Pop
      filesystem.
1190 58885d79 Iustin Pop
  @rtype: str
1191 58885d79 Iustin Pop

1192 59072e7e Michael Hanselmann
  """
1193 13998ef2 Michael Hanselmann
  return ReadFile(_RANDOM_UUID_FILE, size=128).rstrip("\n")
1194 087b34fe Iustin Pop
1195 087b34fe Iustin Pop
1196 ec2c2bc4 Luca Bigliardi
def GenerateSecret(numbytes=20):
1197 33081d90 Iustin Pop
  """Generates a random secret.
1198 33081d90 Iustin Pop

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

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

1207 33081d90 Iustin Pop
  """
1208 ec2c2bc4 Luca Bigliardi
  return os.urandom(numbytes).encode('hex')
1209 33081d90 Iustin Pop
1210 33081d90 Iustin Pop
1211 9dae41ad Guido Trotter
def EnsureDirs(dirs):
1212 9dae41ad Guido Trotter
  """Make required directories, if they don't exist.
1213 9dae41ad Guido Trotter

1214 9dae41ad Guido Trotter
  @param dirs: list of tuples (dir_name, dir_mode)
1215 9dae41ad Guido Trotter
  @type dirs: list of (string, integer)
1216 9dae41ad Guido Trotter

1217 9dae41ad Guido Trotter
  """
1218 9dae41ad Guido Trotter
  for dir_name, dir_mode in dirs:
1219 9dae41ad Guido Trotter
    try:
1220 1b2c8f85 Iustin Pop
      os.mkdir(dir_name, dir_mode)
1221 9dae41ad Guido Trotter
    except EnvironmentError, err:
1222 9dae41ad Guido Trotter
      if err.errno != errno.EEXIST:
1223 9dae41ad Guido Trotter
        raise errors.GenericError("Cannot create needed directory"
1224 1b2c8f85 Iustin Pop
                                  " '%s': %s" % (dir_name, err))
1225 9dae41ad Guido Trotter
    if not os.path.isdir(dir_name):
1226 9dae41ad Guido Trotter
      raise errors.GenericError("%s is not a directory" % dir_name)
1227 9dae41ad Guido Trotter
1228 9dae41ad Guido Trotter
1229 016308cb Iustin Pop
def ReadFile(file_name, size=-1):
1230 ca0aa6d0 Michael Hanselmann
  """Reads a file.
1231 ca0aa6d0 Michael Hanselmann

1232 016308cb Iustin Pop
  @type size: int
1233 016308cb Iustin Pop
  @param size: Read at most size bytes (if negative, entire file)
1234 58885d79 Iustin Pop
  @rtype: str
1235 5bbd3f7f Michael Hanselmann
  @return: the (possibly partial) content of the file
1236 ca0aa6d0 Michael Hanselmann

1237 ca0aa6d0 Michael Hanselmann
  """
1238 ca0aa6d0 Michael Hanselmann
  f = open(file_name, "r")
1239 ca0aa6d0 Michael Hanselmann
  try:
1240 016308cb Iustin Pop
    return f.read(size)
1241 ca0aa6d0 Michael Hanselmann
  finally:
1242 ca0aa6d0 Michael Hanselmann
    f.close()
1243 ca0aa6d0 Michael Hanselmann
1244 ca0aa6d0 Michael Hanselmann
1245 087b34fe Iustin Pop
def WriteFile(file_name, fn=None, data=None,
1246 087b34fe Iustin Pop
              mode=None, uid=-1, gid=-1,
1247 71714516 Michael Hanselmann
              atime=None, mtime=None, close=True,
1248 04a8d789 Michael Hanselmann
              dry_run=False, backup=False,
1249 71714516 Michael Hanselmann
              prewrite=None, postwrite=None):
1250 087b34fe Iustin Pop
  """(Over)write a file atomically.
1251 087b34fe Iustin Pop

1252 087b34fe Iustin Pop
  The file_name and either fn (a function taking one argument, the
1253 087b34fe Iustin Pop
  file descriptor, and which should write the data to it) or data (the
1254 087b34fe Iustin Pop
  contents of the file) must be passed. The other arguments are
1255 087b34fe Iustin Pop
  optional and allow setting the file mode, owner and group, and the
1256 087b34fe Iustin Pop
  mtime/atime of the file.
1257 087b34fe Iustin Pop

1258 087b34fe Iustin Pop
  If the function doesn't raise an exception, it has succeeded and the
1259 69efe319 Michael Hanselmann
  target file has the new contents. If the function has raised an
1260 087b34fe Iustin Pop
  exception, an existing target file should be unmodified and the
1261 087b34fe Iustin Pop
  temporary file should be removed.
1262 087b34fe Iustin Pop

1263 58885d79 Iustin Pop
  @type file_name: str
1264 58885d79 Iustin Pop
  @param file_name: the target filename
1265 58885d79 Iustin Pop
  @type fn: callable
1266 58885d79 Iustin Pop
  @param fn: content writing function, called with
1267 58885d79 Iustin Pop
      file descriptor as parameter
1268 69efe319 Michael Hanselmann
  @type data: str
1269 58885d79 Iustin Pop
  @param data: contents of the file
1270 58885d79 Iustin Pop
  @type mode: int
1271 58885d79 Iustin Pop
  @param mode: file mode
1272 58885d79 Iustin Pop
  @type uid: int
1273 58885d79 Iustin Pop
  @param uid: the owner of the file
1274 58885d79 Iustin Pop
  @type gid: int
1275 58885d79 Iustin Pop
  @param gid: the group of the file
1276 58885d79 Iustin Pop
  @type atime: int
1277 58885d79 Iustin Pop
  @param atime: a custom access time to be set on the file
1278 58885d79 Iustin Pop
  @type mtime: int
1279 58885d79 Iustin Pop
  @param mtime: a custom modification time to be set on the file
1280 58885d79 Iustin Pop
  @type close: boolean
1281 58885d79 Iustin Pop
  @param close: whether to close file after writing it
1282 58885d79 Iustin Pop
  @type prewrite: callable
1283 58885d79 Iustin Pop
  @param prewrite: function to be called before writing content
1284 58885d79 Iustin Pop
  @type postwrite: callable
1285 58885d79 Iustin Pop
  @param postwrite: function to be called after writing content
1286 58885d79 Iustin Pop

1287 58885d79 Iustin Pop
  @rtype: None or int
1288 58885d79 Iustin Pop
  @return: None if the 'close' parameter evaluates to True,
1289 58885d79 Iustin Pop
      otherwise the file descriptor
1290 58885d79 Iustin Pop

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

1293 087b34fe Iustin Pop
  """
1294 04a8d789 Michael Hanselmann
  if not os.path.isabs(file_name):
1295 087b34fe Iustin Pop
    raise errors.ProgrammerError("Path passed to WriteFile is not"
1296 087b34fe Iustin Pop
                                 " absolute: '%s'" % file_name)
1297 087b34fe Iustin Pop
1298 087b34fe Iustin Pop
  if [fn, data].count(None) != 1:
1299 087b34fe Iustin Pop
    raise errors.ProgrammerError("fn or data required")
1300 087b34fe Iustin Pop
1301 087b34fe Iustin Pop
  if [atime, mtime].count(None) == 1:
1302 087b34fe Iustin Pop
    raise errors.ProgrammerError("Both atime and mtime must be either"
1303 087b34fe Iustin Pop
                                 " set or None")
1304 087b34fe Iustin Pop
1305 70f4497c Michael Hanselmann
  if backup and not dry_run and os.path.isfile(file_name):
1306 70f4497c Michael Hanselmann
    CreateBackup(file_name)
1307 087b34fe Iustin Pop
1308 087b34fe Iustin Pop
  dir_name, base_name = os.path.split(file_name)
1309 087b34fe Iustin Pop
  fd, new_name = tempfile.mkstemp('.new', base_name, dir_name)
1310 81b7354c Iustin Pop
  do_remove = True
1311 087b34fe Iustin Pop
  # here we need to make sure we remove the temp file, if any error
1312 087b34fe Iustin Pop
  # leaves it in place
1313 087b34fe Iustin Pop
  try:
1314 087b34fe Iustin Pop
    if uid != -1 or gid != -1:
1315 087b34fe Iustin Pop
      os.chown(new_name, uid, gid)
1316 087b34fe Iustin Pop
    if mode:
1317 087b34fe Iustin Pop
      os.chmod(new_name, mode)
1318 71714516 Michael Hanselmann
    if callable(prewrite):
1319 71714516 Michael Hanselmann
      prewrite(fd)
1320 087b34fe Iustin Pop
    if data is not None:
1321 087b34fe Iustin Pop
      os.write(fd, data)
1322 087b34fe Iustin Pop
    else:
1323 087b34fe Iustin Pop
      fn(fd)
1324 71714516 Michael Hanselmann
    if callable(postwrite):
1325 71714516 Michael Hanselmann
      postwrite(fd)
1326 087b34fe Iustin Pop
    os.fsync(fd)
1327 087b34fe Iustin Pop
    if atime is not None and mtime is not None:
1328 087b34fe Iustin Pop
      os.utime(new_name, (atime, mtime))
1329 70f4497c Michael Hanselmann
    if not dry_run:
1330 70f4497c Michael Hanselmann
      os.rename(new_name, file_name)
1331 81b7354c Iustin Pop
      do_remove = False
1332 087b34fe Iustin Pop
  finally:
1333 71714516 Michael Hanselmann
    if close:
1334 71714516 Michael Hanselmann
      os.close(fd)
1335 71714516 Michael Hanselmann
      result = None
1336 71714516 Michael Hanselmann
    else:
1337 71714516 Michael Hanselmann
      result = fd
1338 81b7354c Iustin Pop
    if do_remove:
1339 81b7354c Iustin Pop
      RemoveFile(new_name)
1340 78feb6fb Guido Trotter
1341 71714516 Michael Hanselmann
  return result
1342 71714516 Michael Hanselmann
1343 78feb6fb Guido Trotter
1344 7b4126b7 Iustin Pop
def FirstFree(seq, base=0):
1345 7b4126b7 Iustin Pop
  """Returns the first non-existing integer from seq.
1346 7b4126b7 Iustin Pop

1347 7b4126b7 Iustin Pop
  The seq argument should be a sorted list of positive integers. The
1348 7b4126b7 Iustin Pop
  first time the index of an element is smaller than the element
1349 7b4126b7 Iustin Pop
  value, the index will be returned.
1350 7b4126b7 Iustin Pop

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

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

1356 58885d79 Iustin Pop
  @type seq: sequence
1357 58885d79 Iustin Pop
  @param seq: the sequence to be analyzed.
1358 58885d79 Iustin Pop
  @type base: int
1359 58885d79 Iustin Pop
  @param base: use this value as the base index of the sequence
1360 58885d79 Iustin Pop
  @rtype: int
1361 58885d79 Iustin Pop
  @return: the first non-used index in the sequence
1362 7b4126b7 Iustin Pop

1363 7b4126b7 Iustin Pop
  """
1364 7b4126b7 Iustin Pop
  for idx, elem in enumerate(seq):
1365 7b4126b7 Iustin Pop
    assert elem >= base, "Passed element is higher than base offset"
1366 7b4126b7 Iustin Pop
    if elem > idx + base:
1367 7b4126b7 Iustin Pop
      # idx is not used
1368 7b4126b7 Iustin Pop
      return idx + base
1369 7b4126b7 Iustin Pop
  return None
1370 7b4126b7 Iustin Pop
1371 7b4126b7 Iustin Pop
1372 78feb6fb Guido Trotter
def all(seq, pred=bool):
1373 78feb6fb Guido Trotter
  "Returns True if pred(x) is True for every element in the iterable"
1374 7c4d6c7b Michael Hanselmann
  for _ in itertools.ifilterfalse(pred, seq):
1375 78feb6fb Guido Trotter
    return False
1376 78feb6fb Guido Trotter
  return True
1377 78feb6fb Guido Trotter
1378 78feb6fb Guido Trotter
1379 78feb6fb Guido Trotter
def any(seq, pred=bool):
1380 78feb6fb Guido Trotter
  "Returns True if pred(x) is True for at least one element in the iterable"
1381 7c4d6c7b Michael Hanselmann
  for _ in itertools.ifilter(pred, seq):
1382 78feb6fb Guido Trotter
    return True
1383 78feb6fb Guido Trotter
  return False
1384 f7414041 Michael Hanselmann
1385 f7414041 Michael Hanselmann
1386 f7414041 Michael Hanselmann
def UniqueSequence(seq):
1387 f7414041 Michael Hanselmann
  """Returns a list with unique elements.
1388 f7414041 Michael Hanselmann

1389 f7414041 Michael Hanselmann
  Element order is preserved.
1390 58885d79 Iustin Pop

1391 58885d79 Iustin Pop
  @type seq: sequence
1392 5bbd3f7f Michael Hanselmann
  @param seq: the sequence with the source elements
1393 58885d79 Iustin Pop
  @rtype: list
1394 58885d79 Iustin Pop
  @return: list of unique elements from seq
1395 58885d79 Iustin Pop

1396 f7414041 Michael Hanselmann
  """
1397 f7414041 Michael Hanselmann
  seen = set()
1398 f7414041 Michael Hanselmann
  return [i for i in seq if i not in seen and not seen.add(i)]
1399 1862d460 Alexander Schreiber
1400 1862d460 Alexander Schreiber
1401 1862d460 Alexander Schreiber
def IsValidMac(mac):
1402 1862d460 Alexander Schreiber
  """Predicate to check if a MAC address is valid.
1403 1862d460 Alexander Schreiber

1404 5bbd3f7f Michael Hanselmann
  Checks whether the supplied MAC address is formally correct, only
1405 1862d460 Alexander Schreiber
  accepts colon separated format.
1406 58885d79 Iustin Pop

1407 58885d79 Iustin Pop
  @type mac: str
1408 58885d79 Iustin Pop
  @param mac: the MAC to be validated
1409 58885d79 Iustin Pop
  @rtype: boolean
1410 58885d79 Iustin Pop
  @return: True is the MAC seems valid
1411 58885d79 Iustin Pop

1412 1862d460 Alexander Schreiber
  """
1413 1862d460 Alexander Schreiber
  mac_check = re.compile("^([0-9a-f]{2}(:|$)){6}$")
1414 1862d460 Alexander Schreiber
  return mac_check.match(mac) is not None
1415 06009e27 Iustin Pop
1416 06009e27 Iustin Pop
1417 06009e27 Iustin Pop
def TestDelay(duration):
1418 06009e27 Iustin Pop
  """Sleep for a fixed amount of time.
1419 06009e27 Iustin Pop

1420 58885d79 Iustin Pop
  @type duration: float
1421 58885d79 Iustin Pop
  @param duration: the sleep duration
1422 58885d79 Iustin Pop
  @rtype: boolean
1423 58885d79 Iustin Pop
  @return: False for negative value, True otherwise
1424 58885d79 Iustin Pop

1425 06009e27 Iustin Pop
  """
1426 06009e27 Iustin Pop
  if duration < 0:
1427 38ea42a1 Iustin Pop
    return False, "Invalid sleep duration"
1428 06009e27 Iustin Pop
  time.sleep(duration)
1429 38ea42a1 Iustin Pop
  return True, None
1430 8f765069 Iustin Pop
1431 8f765069 Iustin Pop
1432 7d88772a Iustin Pop
def _CloseFDNoErr(fd, retries=5):
1433 7d88772a Iustin Pop
  """Close a file descriptor ignoring errors.
1434 8f765069 Iustin Pop

1435 7d88772a Iustin Pop
  @type fd: int
1436 7d88772a Iustin Pop
  @param fd: the file descriptor
1437 7d88772a Iustin Pop
  @type retries: int
1438 7d88772a Iustin Pop
  @param retries: how many retries to make, in case we get any
1439 7d88772a Iustin Pop
      other error than EBADF
1440 7d88772a Iustin Pop

1441 7d88772a Iustin Pop
  """
1442 7d88772a Iustin Pop
  try:
1443 7d88772a Iustin Pop
    os.close(fd)
1444 7d88772a Iustin Pop
  except OSError, err:
1445 7d88772a Iustin Pop
    if err.errno != errno.EBADF:
1446 7d88772a Iustin Pop
      if retries > 0:
1447 7d88772a Iustin Pop
        _CloseFDNoErr(fd, retries - 1)
1448 7d88772a Iustin Pop
    # else either it's closed already or we're out of retries, so we
1449 7d88772a Iustin Pop
    # ignore this and go on
1450 7d88772a Iustin Pop
1451 7d88772a Iustin Pop
1452 7d88772a Iustin Pop
def CloseFDs(noclose_fds=None):
1453 7d88772a Iustin Pop
  """Close file descriptors.
1454 7d88772a Iustin Pop

1455 7d88772a Iustin Pop
  This closes all file descriptors above 2 (i.e. except
1456 7d88772a Iustin Pop
  stdin/out/err).
1457 8f765069 Iustin Pop

1458 58885d79 Iustin Pop
  @type noclose_fds: list or None
1459 58885d79 Iustin Pop
  @param noclose_fds: if given, it denotes a list of file descriptor
1460 58885d79 Iustin Pop
      that should not be closed
1461 58885d79 Iustin Pop

1462 8f765069 Iustin Pop
  """
1463 8f765069 Iustin Pop
  # Default maximum for the number of available file descriptors.
1464 8f765069 Iustin Pop
  if 'SC_OPEN_MAX' in os.sysconf_names:
1465 8f765069 Iustin Pop
    try:
1466 8f765069 Iustin Pop
      MAXFD = os.sysconf('SC_OPEN_MAX')
1467 8f765069 Iustin Pop
      if MAXFD < 0:
1468 8f765069 Iustin Pop
        MAXFD = 1024
1469 8f765069 Iustin Pop
    except OSError:
1470 8f765069 Iustin Pop
      MAXFD = 1024
1471 8f765069 Iustin Pop
  else:
1472 8f765069 Iustin Pop
    MAXFD = 1024
1473 7d88772a Iustin Pop
  maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
1474 7d88772a Iustin Pop
  if (maxfd == resource.RLIM_INFINITY):
1475 7d88772a Iustin Pop
    maxfd = MAXFD
1476 7d88772a Iustin Pop
1477 7d88772a Iustin Pop
  # Iterate through and close all file descriptors (except the standard ones)
1478 7d88772a Iustin Pop
  for fd in range(3, maxfd):
1479 7d88772a Iustin Pop
    if noclose_fds and fd in noclose_fds:
1480 7d88772a Iustin Pop
      continue
1481 7d88772a Iustin Pop
    _CloseFDNoErr(fd)
1482 7d88772a Iustin Pop
1483 7d88772a Iustin Pop
1484 7d88772a Iustin Pop
def Daemonize(logfile):
1485 7d88772a Iustin Pop
  """Daemonize the current process.
1486 7d88772a Iustin Pop

1487 7d88772a Iustin Pop
  This detaches the current process from the controlling terminal and
1488 7d88772a Iustin Pop
  runs it in the background as a daemon.
1489 7d88772a Iustin Pop

1490 7d88772a Iustin Pop
  @type logfile: str
1491 7d88772a Iustin Pop
  @param logfile: the logfile to which we should redirect stdout/stderr
1492 7d88772a Iustin Pop
  @rtype: int
1493 5fcc718f Iustin Pop
  @return: the value zero
1494 7d88772a Iustin Pop

1495 7d88772a Iustin Pop
  """
1496 7d88772a Iustin Pop
  UMASK = 077
1497 7d88772a Iustin Pop
  WORKDIR = "/"
1498 8f765069 Iustin Pop
1499 8f765069 Iustin Pop
  # this might fail
1500 8f765069 Iustin Pop
  pid = os.fork()
1501 8f765069 Iustin Pop
  if (pid == 0):  # The first child.
1502 8f765069 Iustin Pop
    os.setsid()
1503 8f765069 Iustin Pop
    # this might fail
1504 8f765069 Iustin Pop
    pid = os.fork() # Fork a second child.
1505 8f765069 Iustin Pop
    if (pid == 0):  # The second child.
1506 8f765069 Iustin Pop
      os.chdir(WORKDIR)
1507 8f765069 Iustin Pop
      os.umask(UMASK)
1508 8f765069 Iustin Pop
    else:
1509 8f765069 Iustin Pop
      # exit() or _exit()?  See below.
1510 8f765069 Iustin Pop
      os._exit(0) # Exit parent (the first child) of the second child.
1511 8f765069 Iustin Pop
  else:
1512 8f765069 Iustin Pop
    os._exit(0) # Exit parent of the first child.
1513 8f765069 Iustin Pop
1514 7d88772a Iustin Pop
  for fd in range(3):
1515 7d88772a Iustin Pop
    _CloseFDNoErr(fd)
1516 7d88772a Iustin Pop
  i = os.open("/dev/null", os.O_RDONLY) # stdin
1517 7d88772a Iustin Pop
  assert i == 0, "Can't close/reopen stdin"
1518 7d88772a Iustin Pop
  i = os.open(logfile, os.O_WRONLY|os.O_CREAT|os.O_APPEND, 0600) # stdout
1519 7d88772a Iustin Pop
  assert i == 1, "Can't close/reopen stdout"
1520 7d88772a Iustin Pop
  # Duplicate standard output to standard error.
1521 7d88772a Iustin Pop
  os.dup2(1, 2)
1522 8f765069 Iustin Pop
  return 0
1523 57c177af Iustin Pop
1524 57c177af Iustin Pop
1525 53beffbb Iustin Pop
def DaemonPidFileName(name):
1526 58885d79 Iustin Pop
  """Compute a ganeti pid file absolute path
1527 58885d79 Iustin Pop

1528 58885d79 Iustin Pop
  @type name: str
1529 58885d79 Iustin Pop
  @param name: the daemon name
1530 58885d79 Iustin Pop
  @rtype: str
1531 58885d79 Iustin Pop
  @return: the full path to the pidfile corresponding to the given
1532 58885d79 Iustin Pop
      daemon name
1533 b330ac0b Guido Trotter

1534 b330ac0b Guido Trotter
  """
1535 b330ac0b Guido Trotter
  return os.path.join(constants.RUN_GANETI_DIR, "%s.pid" % name)
1536 b330ac0b Guido Trotter
1537 b330ac0b Guido Trotter
1538 b330ac0b Guido Trotter
def WritePidFile(name):
1539 b330ac0b Guido Trotter
  """Write the current process pidfile.
1540 b330ac0b Guido Trotter

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

1543 58885d79 Iustin Pop
  @type name: str
1544 58885d79 Iustin Pop
  @param name: the daemon name to use
1545 58885d79 Iustin Pop
  @raise errors.GenericError: if the pid file already exists and
1546 58885d79 Iustin Pop
      points to a live process
1547 b330ac0b Guido Trotter

1548 b330ac0b Guido Trotter
  """
1549 b330ac0b Guido Trotter
  pid = os.getpid()
1550 53beffbb Iustin Pop
  pidfilename = DaemonPidFileName(name)
1551 d9f311d7 Iustin Pop
  if IsProcessAlive(ReadPidFile(pidfilename)):
1552 533bb4b1 Michael Hanselmann
    raise errors.GenericError("%s contains a live process" % pidfilename)
1553 b330ac0b Guido Trotter
1554 b330ac0b Guido Trotter
  WriteFile(pidfilename, data="%d\n" % pid)
1555 b330ac0b Guido Trotter
1556 b330ac0b Guido Trotter
1557 b330ac0b Guido Trotter
def RemovePidFile(name):
1558 b330ac0b Guido Trotter
  """Remove the current process pidfile.
1559 b330ac0b Guido Trotter

1560 b330ac0b Guido Trotter
  Any errors are ignored.
1561 b330ac0b Guido Trotter

1562 58885d79 Iustin Pop
  @type name: str
1563 58885d79 Iustin Pop
  @param name: the daemon name used to derive the pidfile name
1564 58885d79 Iustin Pop

1565 b330ac0b Guido Trotter
  """
1566 53beffbb Iustin Pop
  pidfilename = DaemonPidFileName(name)
1567 b330ac0b Guido Trotter
  # TODO: we could check here that the file contains our pid
1568 b330ac0b Guido Trotter
  try:
1569 b330ac0b Guido Trotter
    RemoveFile(pidfilename)
1570 b330ac0b Guido Trotter
  except:
1571 b330ac0b Guido Trotter
    pass
1572 b330ac0b Guido Trotter
1573 b330ac0b Guido Trotter
1574 ff5251bc Iustin Pop
def KillProcess(pid, signal_=signal.SIGTERM, timeout=30,
1575 ff5251bc Iustin Pop
                waitpid=False):
1576 b2a1f511 Iustin Pop
  """Kill a process given by its pid.
1577 b2a1f511 Iustin Pop

1578 b2a1f511 Iustin Pop
  @type pid: int
1579 b2a1f511 Iustin Pop
  @param pid: The PID to terminate.
1580 38206f3c Iustin Pop
  @type signal_: int
1581 38206f3c Iustin Pop
  @param signal_: The signal to send, by default SIGTERM
1582 b2a1f511 Iustin Pop
  @type timeout: int
1583 b2a1f511 Iustin Pop
  @param timeout: The timeout after which, if the process is still alive,
1584 b2a1f511 Iustin Pop
                  a SIGKILL will be sent. If not positive, no such checking
1585 b2a1f511 Iustin Pop
                  will be done
1586 ff5251bc Iustin Pop
  @type waitpid: boolean
1587 ff5251bc Iustin Pop
  @param waitpid: If true, we should waitpid on this process after
1588 ff5251bc Iustin Pop
      sending signals, since it's our own child and otherwise it
1589 ff5251bc Iustin Pop
      would remain as zombie
1590 b2a1f511 Iustin Pop

1591 b2a1f511 Iustin Pop
  """
1592 ff5251bc Iustin Pop
  def _helper(pid, signal_, wait):
1593 ff5251bc Iustin Pop
    """Simple helper to encapsulate the kill/waitpid sequence"""
1594 ff5251bc Iustin Pop
    os.kill(pid, signal_)
1595 ff5251bc Iustin Pop
    if wait:
1596 ff5251bc Iustin Pop
      try:
1597 ff5251bc Iustin Pop
        os.waitpid(pid, os.WNOHANG)
1598 ff5251bc Iustin Pop
      except OSError:
1599 ff5251bc Iustin Pop
        pass
1600 ff5251bc Iustin Pop
1601 b2a1f511 Iustin Pop
  if pid <= 0:
1602 b2a1f511 Iustin Pop
    # kill with pid=0 == suicide
1603 b2a1f511 Iustin Pop
    raise errors.ProgrammerError("Invalid pid given '%s'" % pid)
1604 b2a1f511 Iustin Pop
1605 b2a1f511 Iustin Pop
  if not IsProcessAlive(pid):
1606 b2a1f511 Iustin Pop
    return
1607 31892b4c Michael Hanselmann
1608 ff5251bc Iustin Pop
  _helper(pid, signal_, waitpid)
1609 31892b4c Michael Hanselmann
1610 b2a1f511 Iustin Pop
  if timeout <= 0:
1611 b2a1f511 Iustin Pop
    return
1612 7167159a Michael Hanselmann
1613 31892b4c Michael Hanselmann
  def _CheckProcess():
1614 31892b4c Michael Hanselmann
    if not IsProcessAlive(pid):
1615 31892b4c Michael Hanselmann
      return
1616 31892b4c Michael Hanselmann
1617 7167159a Michael Hanselmann
    try:
1618 7167159a Michael Hanselmann
      (result_pid, _) = os.waitpid(pid, os.WNOHANG)
1619 7167159a Michael Hanselmann
    except OSError:
1620 31892b4c Michael Hanselmann
      raise RetryAgain()
1621 31892b4c Michael Hanselmann
1622 31892b4c Michael Hanselmann
    if result_pid > 0:
1623 31892b4c Michael Hanselmann
      return
1624 31892b4c Michael Hanselmann
1625 31892b4c Michael Hanselmann
    raise RetryAgain()
1626 31892b4c Michael Hanselmann
1627 31892b4c Michael Hanselmann
  try:
1628 31892b4c Michael Hanselmann
    # Wait up to $timeout seconds
1629 31892b4c Michael Hanselmann
    Retry(_CheckProcess, (0.01, 1.5, 0.1), timeout)
1630 31892b4c Michael Hanselmann
  except RetryTimeout:
1631 31892b4c Michael Hanselmann
    pass
1632 7167159a Michael Hanselmann
1633 b2a1f511 Iustin Pop
  if IsProcessAlive(pid):
1634 7167159a Michael Hanselmann
    # Kill process if it's still alive
1635 e1bd0072 Iustin Pop
    _helper(pid, signal.SIGKILL, waitpid)
1636 b2a1f511 Iustin Pop
1637 b2a1f511 Iustin Pop
1638 57c177af Iustin Pop
def FindFile(name, search_path, test=os.path.exists):
1639 57c177af Iustin Pop
  """Look for a filesystem object in a given path.
1640 57c177af Iustin Pop

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

1644 58885d79 Iustin Pop
  @type name: str
1645 58885d79 Iustin Pop
  @param name: the name to look for
1646 58885d79 Iustin Pop
  @type search_path: str
1647 58885d79 Iustin Pop
  @param search_path: location to start at
1648 58885d79 Iustin Pop
  @type test: callable
1649 58885d79 Iustin Pop
  @param test: a function taking one argument that should return True
1650 58885d79 Iustin Pop
      if the a given object is valid; the default value is
1651 58885d79 Iustin Pop
      os.path.exists, causing only existing files to be returned
1652 58885d79 Iustin Pop
  @rtype: str or None
1653 58885d79 Iustin Pop
  @return: full path to the object if found, None otherwise
1654 57c177af Iustin Pop

1655 57c177af Iustin Pop
  """
1656 f95c81bf Iustin Pop
  # validate the filename mask
1657 f95c81bf Iustin Pop
  if constants.EXT_PLUGIN_MASK.match(name) is None:
1658 f95c81bf Iustin Pop
    logging.critical("Invalid value passed for external script name: '%s'",
1659 f95c81bf Iustin Pop
                     name)
1660 f95c81bf Iustin Pop
    return None
1661 f95c81bf Iustin Pop
1662 57c177af Iustin Pop
  for dir_name in search_path:
1663 57c177af Iustin Pop
    item_name = os.path.sep.join([dir_name, name])
1664 f95c81bf Iustin Pop
    # check the user test and that we're indeed resolving to the given
1665 f95c81bf Iustin Pop
    # basename
1666 f95c81bf Iustin Pop
    if test(item_name) and os.path.basename(item_name) == name:
1667 57c177af Iustin Pop
      return item_name
1668 57c177af Iustin Pop
  return None
1669 8d1a2a64 Michael Hanselmann
1670 8d1a2a64 Michael Hanselmann
1671 8d1a2a64 Michael Hanselmann
def CheckVolumeGroupSize(vglist, vgname, minsize):
1672 8d1a2a64 Michael Hanselmann
  """Checks if the volume group list is valid.
1673 8d1a2a64 Michael Hanselmann

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

1677 58885d79 Iustin Pop
  @type vglist: dict
1678 58885d79 Iustin Pop
  @param vglist: dictionary of volume group names and their size
1679 58885d79 Iustin Pop
  @type vgname: str
1680 58885d79 Iustin Pop
  @param vgname: the volume group we should check
1681 58885d79 Iustin Pop
  @type minsize: int
1682 58885d79 Iustin Pop
  @param minsize: the minimum size we accept
1683 58885d79 Iustin Pop
  @rtype: None or str
1684 58885d79 Iustin Pop
  @return: None for success, otherwise the error message
1685 8d1a2a64 Michael Hanselmann

1686 8d1a2a64 Michael Hanselmann
  """
1687 8d1a2a64 Michael Hanselmann
  vgsize = vglist.get(vgname, None)
1688 8d1a2a64 Michael Hanselmann
  if vgsize is None:
1689 8d1a2a64 Michael Hanselmann
    return "volume group '%s' missing" % vgname
1690 8d1a2a64 Michael Hanselmann
  elif vgsize < minsize:
1691 8d1a2a64 Michael Hanselmann
    return ("volume group '%s' too small (%s MiB required, %d MiB found)" %
1692 8d1a2a64 Michael Hanselmann
            (vgname, minsize, vgsize))
1693 8d1a2a64 Michael Hanselmann
  return None
1694 7996a135 Iustin Pop
1695 7996a135 Iustin Pop
1696 45bc5e4a Michael Hanselmann
def SplitTime(value):
1697 739be818 Michael Hanselmann
  """Splits time as floating point number into a tuple.
1698 739be818 Michael Hanselmann

1699 45bc5e4a Michael Hanselmann
  @param value: Time in seconds
1700 45bc5e4a Michael Hanselmann
  @type value: int or float
1701 45bc5e4a Michael Hanselmann
  @return: Tuple containing (seconds, microseconds)
1702 739be818 Michael Hanselmann

1703 739be818 Michael Hanselmann
  """
1704 45bc5e4a Michael Hanselmann
  (seconds, microseconds) = divmod(int(value * 1000000), 1000000)
1705 45bc5e4a Michael Hanselmann
1706 45bc5e4a Michael Hanselmann
  assert 0 <= seconds, \
1707 45bc5e4a Michael Hanselmann
    "Seconds must be larger than or equal to 0, but are %s" % seconds
1708 45bc5e4a Michael Hanselmann
  assert 0 <= microseconds <= 999999, \
1709 45bc5e4a Michael Hanselmann
    "Microseconds must be 0-999999, but are %s" % microseconds
1710 45bc5e4a Michael Hanselmann
1711 45bc5e4a Michael Hanselmann
  return (int(seconds), int(microseconds))
1712 739be818 Michael Hanselmann
1713 739be818 Michael Hanselmann
1714 739be818 Michael Hanselmann
def MergeTime(timetuple):
1715 739be818 Michael Hanselmann
  """Merges a tuple into time as a floating point number.
1716 739be818 Michael Hanselmann

1717 45bc5e4a Michael Hanselmann
  @param timetuple: Time as tuple, (seconds, microseconds)
1718 739be818 Michael Hanselmann
  @type timetuple: tuple
1719 739be818 Michael Hanselmann
  @return: Time as a floating point number expressed in seconds
1720 739be818 Michael Hanselmann

1721 739be818 Michael Hanselmann
  """
1722 45bc5e4a Michael Hanselmann
  (seconds, microseconds) = timetuple
1723 739be818 Michael Hanselmann
1724 45bc5e4a Michael Hanselmann
  assert 0 <= seconds, \
1725 45bc5e4a Michael Hanselmann
    "Seconds must be larger than or equal to 0, but are %s" % seconds
1726 45bc5e4a Michael Hanselmann
  assert 0 <= microseconds <= 999999, \
1727 45bc5e4a Michael Hanselmann
    "Microseconds must be 0-999999, but are %s" % microseconds
1728 739be818 Michael Hanselmann
1729 45bc5e4a Michael Hanselmann
  return float(seconds) + (float(microseconds) * 0.000001)
1730 739be818 Michael Hanselmann
1731 739be818 Michael Hanselmann
1732 cd50653c Guido Trotter
def GetDaemonPort(daemon_name):
1733 cd50653c Guido Trotter
  """Get the daemon port for this cluster.
1734 4a8b186a Michael Hanselmann

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

1739 cd50653c Guido Trotter
  @type daemon_name: string
1740 cd50653c Guido Trotter
  @param daemon_name: daemon name (in constants.DAEMONS_PORTS)
1741 58885d79 Iustin Pop
  @rtype: int
1742 58885d79 Iustin Pop

1743 4a8b186a Michael Hanselmann
  """
1744 cd50653c Guido Trotter
  if daemon_name not in constants.DAEMONS_PORTS:
1745 cd50653c Guido Trotter
    raise errors.ProgrammerError("Unknown daemon: %s" % daemon_name)
1746 cd50653c Guido Trotter
1747 cd50653c Guido Trotter
  (proto, default_port) = constants.DAEMONS_PORTS[daemon_name]
1748 4a8b186a Michael Hanselmann
  try:
1749 cd50653c Guido Trotter
    port = socket.getservbyname(daemon_name, proto)
1750 4a8b186a Michael Hanselmann
  except socket.error:
1751 cd50653c Guido Trotter
    port = default_port
1752 4a8b186a Michael Hanselmann
1753 4a8b186a Michael Hanselmann
  return port
1754 4a8b186a Michael Hanselmann
1755 4a8b186a Michael Hanselmann
1756 d21d09d6 Iustin Pop
def SetupLogging(logfile, debug=False, stderr_logging=False, program="",
1757 d21d09d6 Iustin Pop
                 multithreaded=False):
1758 82d9caef Iustin Pop
  """Configures the logging module.
1759 82d9caef Iustin Pop

1760 58885d79 Iustin Pop
  @type logfile: str
1761 58885d79 Iustin Pop
  @param logfile: the filename to which we should log
1762 58885d79 Iustin Pop
  @type debug: boolean
1763 58885d79 Iustin Pop
  @param debug: whether to enable debug messages too or
1764 58885d79 Iustin Pop
      only those at C{INFO} and above level
1765 58885d79 Iustin Pop
  @type stderr_logging: boolean
1766 58885d79 Iustin Pop
  @param stderr_logging: whether we should also log to the standard error
1767 58885d79 Iustin Pop
  @type program: str
1768 58885d79 Iustin Pop
  @param program: the name under which we should log messages
1769 d21d09d6 Iustin Pop
  @type multithreaded: boolean
1770 d21d09d6 Iustin Pop
  @param multithreaded: if True, will add the thread name to the log file
1771 58885d79 Iustin Pop
  @raise EnvironmentError: if we can't open the log file and
1772 58885d79 Iustin Pop
      stderr logging is disabled
1773 58885d79 Iustin Pop

1774 82d9caef Iustin Pop
  """
1775 d21d09d6 Iustin Pop
  fmt = "%(asctime)s: " + program + " pid=%(process)d"
1776 d21d09d6 Iustin Pop
  if multithreaded:
1777 d21d09d6 Iustin Pop
    fmt += "/%(threadName)s"
1778 82d9caef Iustin Pop
  if debug:
1779 d21d09d6 Iustin Pop
    fmt += " %(module)s:%(lineno)s"
1780 d21d09d6 Iustin Pop
  fmt += " %(levelname)s %(message)s"
1781 82d9caef Iustin Pop
  formatter = logging.Formatter(fmt)
1782 82d9caef Iustin Pop
1783 82d9caef Iustin Pop
  root_logger = logging.getLogger("")
1784 82d9caef Iustin Pop
  root_logger.setLevel(logging.NOTSET)
1785 82d9caef Iustin Pop
1786 6346a9e5 Michael Hanselmann
  # Remove all previously setup handlers
1787 6346a9e5 Michael Hanselmann
  for handler in root_logger.handlers:
1788 7d88772a Iustin Pop
    handler.close()
1789 6346a9e5 Michael Hanselmann
    root_logger.removeHandler(handler)
1790 6346a9e5 Michael Hanselmann
1791 82d9caef Iustin Pop
  if stderr_logging:
1792 82d9caef Iustin Pop
    stderr_handler = logging.StreamHandler()
1793 82d9caef Iustin Pop
    stderr_handler.setFormatter(formatter)
1794 82d9caef Iustin Pop
    if debug:
1795 82d9caef Iustin Pop
      stderr_handler.setLevel(logging.NOTSET)
1796 82d9caef Iustin Pop
    else:
1797 82d9caef Iustin Pop
      stderr_handler.setLevel(logging.CRITICAL)
1798 82d9caef Iustin Pop
    root_logger.addHandler(stderr_handler)
1799 82d9caef Iustin Pop
1800 82d9caef Iustin Pop
  # this can fail, if the logging directories are not setup or we have
1801 82d9caef Iustin Pop
  # a permisssion problem; in this case, it's best to log but ignore
1802 82d9caef Iustin Pop
  # the error if stderr_logging is True, and if false we re-raise the
1803 82d9caef Iustin Pop
  # exception since otherwise we could run but without any logs at all
1804 82d9caef Iustin Pop
  try:
1805 82d9caef Iustin Pop
    logfile_handler = logging.FileHandler(logfile)
1806 82d9caef Iustin Pop
    logfile_handler.setFormatter(formatter)
1807 82d9caef Iustin Pop
    if debug:
1808 82d9caef Iustin Pop
      logfile_handler.setLevel(logging.DEBUG)
1809 82d9caef Iustin Pop
    else:
1810 82d9caef Iustin Pop
      logfile_handler.setLevel(logging.INFO)
1811 82d9caef Iustin Pop
    root_logger.addHandler(logfile_handler)
1812 d21d09d6 Iustin Pop
  except EnvironmentError:
1813 82d9caef Iustin Pop
    if stderr_logging:
1814 82d9caef Iustin Pop
      logging.exception("Failed to enable logging to file '%s'", logfile)
1815 82d9caef Iustin Pop
    else:
1816 82d9caef Iustin Pop
      # we need to re-raise the exception
1817 82d9caef Iustin Pop
      raise
1818 82d9caef Iustin Pop
1819 016d04b3 Michael Hanselmann
1820 da961187 Guido Trotter
def IsNormAbsPath(path):
1821 17c61836 Guido Trotter
  """Check whether a path is absolute and also normalized
1822 da961187 Guido Trotter

1823 da961187 Guido Trotter
  This avoids things like /dir/../../other/path to be valid.
1824 da961187 Guido Trotter

1825 da961187 Guido Trotter
  """
1826 da961187 Guido Trotter
  return os.path.normpath(path) == path and os.path.isabs(path)
1827 82d9caef Iustin Pop
1828 016d04b3 Michael Hanselmann
1829 f65f63ef Iustin Pop
def TailFile(fname, lines=20):
1830 f65f63ef Iustin Pop
  """Return the last lines from a file.
1831 f65f63ef Iustin Pop

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

1836 f65f63ef Iustin Pop
  @param fname: the file name
1837 f65f63ef Iustin Pop
  @type lines: int
1838 f65f63ef Iustin Pop
  @param lines: the (maximum) number of lines to return
1839 f65f63ef Iustin Pop

1840 f65f63ef Iustin Pop
  """
1841 f65f63ef Iustin Pop
  fd = open(fname, "r")
1842 f65f63ef Iustin Pop
  try:
1843 f65f63ef Iustin Pop
    fd.seek(0, 2)
1844 f65f63ef Iustin Pop
    pos = fd.tell()
1845 f65f63ef Iustin Pop
    pos = max(0, pos-4096)
1846 f65f63ef Iustin Pop
    fd.seek(pos, 0)
1847 f65f63ef Iustin Pop
    raw_data = fd.read()
1848 f65f63ef Iustin Pop
  finally:
1849 f65f63ef Iustin Pop
    fd.close()
1850 f65f63ef Iustin Pop
1851 f65f63ef Iustin Pop
  rows = raw_data.splitlines()
1852 f65f63ef Iustin Pop
  return rows[-lines:]
1853 f65f63ef Iustin Pop
1854 f65f63ef Iustin Pop
1855 26f15862 Iustin Pop
def SafeEncode(text):
1856 26f15862 Iustin Pop
  """Return a 'safe' version of a source string.
1857 26f15862 Iustin Pop

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

1867 26f15862 Iustin Pop
  @type text: str or unicode
1868 26f15862 Iustin Pop
  @param text: input data
1869 26f15862 Iustin Pop
  @rtype: str
1870 26f15862 Iustin Pop
  @return: a safe version of text
1871 26f15862 Iustin Pop

1872 26f15862 Iustin Pop
  """
1873 d392fa34 Iustin Pop
  if isinstance(text, unicode):
1874 5bbd3f7f Michael Hanselmann
    # only if unicode; if str already, we handle it below
1875 d392fa34 Iustin Pop
    text = text.encode('ascii', 'backslashreplace')
1876 d392fa34 Iustin Pop
  resu = ""
1877 d392fa34 Iustin Pop
  for char in text:
1878 d392fa34 Iustin Pop
    c = ord(char)
1879 d392fa34 Iustin Pop
    if char  == '\t':
1880 d392fa34 Iustin Pop
      resu += r'\t'
1881 d392fa34 Iustin Pop
    elif char == '\n':
1882 d392fa34 Iustin Pop
      resu += r'\n'
1883 d392fa34 Iustin Pop
    elif char == '\r':
1884 d392fa34 Iustin Pop
      resu += r'\'r'
1885 d392fa34 Iustin Pop
    elif c < 32 or c >= 127: # non-printable
1886 d392fa34 Iustin Pop
      resu += "\\x%02x" % (c & 0xff)
1887 d392fa34 Iustin Pop
    else:
1888 d392fa34 Iustin Pop
      resu += char
1889 d392fa34 Iustin Pop
  return resu
1890 26f15862 Iustin Pop
1891 26f15862 Iustin Pop
1892 ab3e6da8 Iustin Pop
def CommaJoin(names):
1893 ab3e6da8 Iustin Pop
  """Nicely join a set of identifiers.
1894 ab3e6da8 Iustin Pop

1895 ab3e6da8 Iustin Pop
  @param names: set, list or tuple
1896 ab3e6da8 Iustin Pop
  @return: a string with the formatted results
1897 ab3e6da8 Iustin Pop

1898 ab3e6da8 Iustin Pop
  """
1899 1f864b60 Iustin Pop
  return ", ".join([str(val) for val in names])
1900 ab3e6da8 Iustin Pop
1901 ab3e6da8 Iustin Pop
1902 3f6a47a8 Michael Hanselmann
def BytesToMebibyte(value):
1903 3f6a47a8 Michael Hanselmann
  """Converts bytes to mebibytes.
1904 3f6a47a8 Michael Hanselmann

1905 3f6a47a8 Michael Hanselmann
  @type value: int
1906 3f6a47a8 Michael Hanselmann
  @param value: Value in bytes
1907 3f6a47a8 Michael Hanselmann
  @rtype: int
1908 3f6a47a8 Michael Hanselmann
  @return: Value in mebibytes
1909 3f6a47a8 Michael Hanselmann

1910 3f6a47a8 Michael Hanselmann
  """
1911 3f6a47a8 Michael Hanselmann
  return int(round(value / (1024.0 * 1024.0), 0))
1912 3f6a47a8 Michael Hanselmann
1913 3f6a47a8 Michael Hanselmann
1914 3f6a47a8 Michael Hanselmann
def CalculateDirectorySize(path):
1915 3f6a47a8 Michael Hanselmann
  """Calculates the size of a directory recursively.
1916 3f6a47a8 Michael Hanselmann

1917 3f6a47a8 Michael Hanselmann
  @type path: string
1918 3f6a47a8 Michael Hanselmann
  @param path: Path to directory
1919 3f6a47a8 Michael Hanselmann
  @rtype: int
1920 3f6a47a8 Michael Hanselmann
  @return: Size in mebibytes
1921 3f6a47a8 Michael Hanselmann

1922 3f6a47a8 Michael Hanselmann
  """
1923 3f6a47a8 Michael Hanselmann
  size = 0
1924 3f6a47a8 Michael Hanselmann
1925 3f6a47a8 Michael Hanselmann
  for (curpath, _, files) in os.walk(path):
1926 2a887df9 Michael Hanselmann
    for filename in files:
1927 2a887df9 Michael Hanselmann
      st = os.lstat(os.path.join(curpath, filename))
1928 3f6a47a8 Michael Hanselmann
      size += st.st_size
1929 3f6a47a8 Michael Hanselmann
1930 3f6a47a8 Michael Hanselmann
  return BytesToMebibyte(size)
1931 3f6a47a8 Michael Hanselmann
1932 3f6a47a8 Michael Hanselmann
1933 620a85fd Iustin Pop
def GetFilesystemStats(path):
1934 620a85fd Iustin Pop
  """Returns the total and free space on a filesystem.
1935 3f6a47a8 Michael Hanselmann

1936 3f6a47a8 Michael Hanselmann
  @type path: string
1937 3f6a47a8 Michael Hanselmann
  @param path: Path on filesystem to be examined
1938 3f6a47a8 Michael Hanselmann
  @rtype: int
1939 620a85fd Iustin Pop
  @return: tuple of (Total space, Free space) in mebibytes
1940 3f6a47a8 Michael Hanselmann

1941 3f6a47a8 Michael Hanselmann
  """
1942 3f6a47a8 Michael Hanselmann
  st = os.statvfs(path)
1943 3f6a47a8 Michael Hanselmann
1944 620a85fd Iustin Pop
  fsize = BytesToMebibyte(st.f_bavail * st.f_frsize)
1945 620a85fd Iustin Pop
  tsize = BytesToMebibyte(st.f_blocks * st.f_frsize)
1946 620a85fd Iustin Pop
  return (tsize, fsize)
1947 3f6a47a8 Michael Hanselmann
1948 3f6a47a8 Michael Hanselmann
1949 7996a135 Iustin Pop
def LockedMethod(fn):
1950 7996a135 Iustin Pop
  """Synchronized object access decorator.
1951 7996a135 Iustin Pop

1952 7996a135 Iustin Pop
  This decorator is intended to protect access to an object using the
1953 7996a135 Iustin Pop
  object's own lock which is hardcoded to '_lock'.
1954 7996a135 Iustin Pop

1955 7996a135 Iustin Pop
  """
1956 e67bd559 Michael Hanselmann
  def _LockDebug(*args, **kwargs):
1957 e67bd559 Michael Hanselmann
    if debug_locks:
1958 e67bd559 Michael Hanselmann
      logging.debug(*args, **kwargs)
1959 e67bd559 Michael Hanselmann
1960 7996a135 Iustin Pop
  def wrapper(self, *args, **kwargs):
1961 7996a135 Iustin Pop
    assert hasattr(self, '_lock')
1962 7996a135 Iustin Pop
    lock = self._lock
1963 e67bd559 Michael Hanselmann
    _LockDebug("Waiting for %s", lock)
1964 7996a135 Iustin Pop
    lock.acquire()
1965 7996a135 Iustin Pop
    try:
1966 e67bd559 Michael Hanselmann
      _LockDebug("Acquired %s", lock)
1967 7996a135 Iustin Pop
      result = fn(self, *args, **kwargs)
1968 7996a135 Iustin Pop
    finally:
1969 e67bd559 Michael Hanselmann
      _LockDebug("Releasing %s", lock)
1970 7996a135 Iustin Pop
      lock.release()
1971 e67bd559 Michael Hanselmann
      _LockDebug("Released %s", lock)
1972 7996a135 Iustin Pop
    return result
1973 7996a135 Iustin Pop
  return wrapper
1974 eb0f0ce0 Michael Hanselmann
1975 eb0f0ce0 Michael Hanselmann
1976 eb0f0ce0 Michael Hanselmann
def LockFile(fd):
1977 eb0f0ce0 Michael Hanselmann
  """Locks a file using POSIX locks.
1978 eb0f0ce0 Michael Hanselmann

1979 58885d79 Iustin Pop
  @type fd: int
1980 58885d79 Iustin Pop
  @param fd: the file descriptor we need to lock
1981 58885d79 Iustin Pop

1982 eb0f0ce0 Michael Hanselmann
  """
1983 eb0f0ce0 Michael Hanselmann
  try:
1984 eb0f0ce0 Michael Hanselmann
    fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
1985 eb0f0ce0 Michael Hanselmann
  except IOError, err:
1986 eb0f0ce0 Michael Hanselmann
    if err.errno == errno.EAGAIN:
1987 eb0f0ce0 Michael Hanselmann
      raise errors.LockError("File already locked")
1988 eb0f0ce0 Michael Hanselmann
    raise
1989 de499029 Michael Hanselmann
1990 de499029 Michael Hanselmann
1991 3b813dd2 Iustin Pop
def FormatTime(val):
1992 3b813dd2 Iustin Pop
  """Formats a time value.
1993 3b813dd2 Iustin Pop

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

1998 3b813dd2 Iustin Pop
  """
1999 3b813dd2 Iustin Pop
  if val is None or not isinstance(val, (int, float)):
2000 3b813dd2 Iustin Pop
    return "N/A"
2001 3b813dd2 Iustin Pop
  # these two codes works on Linux, but they are not guaranteed on all
2002 3b813dd2 Iustin Pop
  # platforms
2003 3b813dd2 Iustin Pop
  return time.strftime("%F %T", time.localtime(val))
2004 3b813dd2 Iustin Pop
2005 3b813dd2 Iustin Pop
2006 5cbe43a5 Michael Hanselmann
def ReadWatcherPauseFile(filename, now=None, remove_after=3600):
2007 05e50653 Michael Hanselmann
  """Reads the watcher pause file.
2008 05e50653 Michael Hanselmann

2009 5cbe43a5 Michael Hanselmann
  @type filename: string
2010 5cbe43a5 Michael Hanselmann
  @param filename: Path to watcher pause file
2011 5cbe43a5 Michael Hanselmann
  @type now: None, float or int
2012 5cbe43a5 Michael Hanselmann
  @param now: Current time as Unix timestamp
2013 5cbe43a5 Michael Hanselmann
  @type remove_after: int
2014 5cbe43a5 Michael Hanselmann
  @param remove_after: Remove watcher pause file after specified amount of
2015 5cbe43a5 Michael Hanselmann
    seconds past the pause end time
2016 5cbe43a5 Michael Hanselmann

2017 05e50653 Michael Hanselmann
  """
2018 05e50653 Michael Hanselmann
  if now is None:
2019 05e50653 Michael Hanselmann
    now = time.time()
2020 05e50653 Michael Hanselmann
2021 05e50653 Michael Hanselmann
  try:
2022 05e50653 Michael Hanselmann
    value = ReadFile(filename)
2023 05e50653 Michael Hanselmann
  except IOError, err:
2024 05e50653 Michael Hanselmann
    if err.errno != errno.ENOENT:
2025 05e50653 Michael Hanselmann
      raise
2026 05e50653 Michael Hanselmann
    value = None
2027 05e50653 Michael Hanselmann
2028 05e50653 Michael Hanselmann
  if value is not None:
2029 05e50653 Michael Hanselmann
    try:
2030 05e50653 Michael Hanselmann
      value = int(value)
2031 05e50653 Michael Hanselmann
    except ValueError:
2032 5cbe43a5 Michael Hanselmann
      logging.warning(("Watcher pause file (%s) contains invalid value,"
2033 5cbe43a5 Michael Hanselmann
                       " removing it"), filename)
2034 5cbe43a5 Michael Hanselmann
      RemoveFile(filename)
2035 05e50653 Michael Hanselmann
      value = None
2036 05e50653 Michael Hanselmann
2037 05e50653 Michael Hanselmann
    if value is not None:
2038 5cbe43a5 Michael Hanselmann
      # Remove file if it's outdated
2039 5cbe43a5 Michael Hanselmann
      if now > (value + remove_after):
2040 5cbe43a5 Michael Hanselmann
        RemoveFile(filename)
2041 5cbe43a5 Michael Hanselmann
        value = None
2042 5cbe43a5 Michael Hanselmann
2043 5cbe43a5 Michael Hanselmann
      elif now > value:
2044 05e50653 Michael Hanselmann
        value = None
2045 05e50653 Michael Hanselmann
2046 05e50653 Michael Hanselmann
  return value
2047 05e50653 Michael Hanselmann
2048 05e50653 Michael Hanselmann
2049 de0ea66b Michael Hanselmann
class RetryTimeout(Exception):
2050 de0ea66b Michael Hanselmann
  """Retry loop timed out.
2051 de0ea66b Michael Hanselmann

2052 de0ea66b Michael Hanselmann
  """
2053 de0ea66b Michael Hanselmann
2054 de0ea66b Michael Hanselmann
2055 de0ea66b Michael Hanselmann
class RetryAgain(Exception):
2056 de0ea66b Michael Hanselmann
  """Retry again.
2057 de0ea66b Michael Hanselmann

2058 de0ea66b Michael Hanselmann
  """
2059 de0ea66b Michael Hanselmann
2060 de0ea66b Michael Hanselmann
2061 de0ea66b Michael Hanselmann
class _RetryDelayCalculator(object):
2062 de0ea66b Michael Hanselmann
  """Calculator for increasing delays.
2063 de0ea66b Michael Hanselmann

2064 de0ea66b Michael Hanselmann
  """
2065 de0ea66b Michael Hanselmann
  __slots__ = [
2066 de0ea66b Michael Hanselmann
    "_factor",
2067 de0ea66b Michael Hanselmann
    "_limit",
2068 de0ea66b Michael Hanselmann
    "_next",
2069 de0ea66b Michael Hanselmann
    "_start",
2070 de0ea66b Michael Hanselmann
    ]
2071 de0ea66b Michael Hanselmann
2072 de0ea66b Michael Hanselmann
  def __init__(self, start, factor, limit):
2073 de0ea66b Michael Hanselmann
    """Initializes this class.
2074 de0ea66b Michael Hanselmann

2075 de0ea66b Michael Hanselmann
    @type start: float
2076 de0ea66b Michael Hanselmann
    @param start: Initial delay
2077 de0ea66b Michael Hanselmann
    @type factor: float
2078 de0ea66b Michael Hanselmann
    @param factor: Factor for delay increase
2079 de0ea66b Michael Hanselmann
    @type limit: float or None
2080 de0ea66b Michael Hanselmann
    @param limit: Upper limit for delay or None for no limit
2081 de0ea66b Michael Hanselmann

2082 de0ea66b Michael Hanselmann
    """
2083 de0ea66b Michael Hanselmann
    assert start > 0.0
2084 de0ea66b Michael Hanselmann
    assert factor >= 1.0
2085 de0ea66b Michael Hanselmann
    assert limit is None or limit >= 0.0
2086 de0ea66b Michael Hanselmann
2087 de0ea66b Michael Hanselmann
    self._start = start
2088 de0ea66b Michael Hanselmann
    self._factor = factor
2089 de0ea66b Michael Hanselmann
    self._limit = limit
2090 de0ea66b Michael Hanselmann
2091 de0ea66b Michael Hanselmann
    self._next = start
2092 de0ea66b Michael Hanselmann
2093 de0ea66b Michael Hanselmann
  def __call__(self):
2094 de0ea66b Michael Hanselmann
    """Returns current delay and calculates the next one.
2095 de0ea66b Michael Hanselmann

2096 de0ea66b Michael Hanselmann
    """
2097 de0ea66b Michael Hanselmann
    current = self._next
2098 de0ea66b Michael Hanselmann
2099 de0ea66b Michael Hanselmann
    # Update for next run
2100 de0ea66b Michael Hanselmann
    if self._limit is None or self._next < self._limit:
2101 de0ea66b Michael Hanselmann
      self._next = max(self._limit, self._next * self._factor)
2102 de0ea66b Michael Hanselmann
2103 de0ea66b Michael Hanselmann
    return current
2104 de0ea66b Michael Hanselmann
2105 de0ea66b Michael Hanselmann
2106 de0ea66b Michael Hanselmann
#: Special delay to specify whole remaining timeout
2107 de0ea66b Michael Hanselmann
RETRY_REMAINING_TIME = object()
2108 de0ea66b Michael Hanselmann
2109 de0ea66b Michael Hanselmann
2110 de0ea66b Michael Hanselmann
def Retry(fn, delay, timeout, args=None, wait_fn=time.sleep,
2111 de0ea66b Michael Hanselmann
          _time_fn=time.time):
2112 de0ea66b Michael Hanselmann
  """Call a function repeatedly until it succeeds.
2113 de0ea66b Michael Hanselmann

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

2118 de0ea66b Michael Hanselmann
  C{delay} can be one of the following:
2119 de0ea66b Michael Hanselmann
    - callable returning the delay length as a float
2120 de0ea66b Michael Hanselmann
    - Tuple of (start, factor, limit)
2121 de0ea66b Michael Hanselmann
    - L{RETRY_REMAINING_TIME} to sleep until the timeout expires (this is
2122 de0ea66b Michael Hanselmann
      useful when overriding L{wait_fn} to wait for an external event)
2123 de0ea66b Michael Hanselmann
    - A static delay as a number (int or float)
2124 de0ea66b Michael Hanselmann

2125 de0ea66b Michael Hanselmann
  @type fn: callable
2126 de0ea66b Michael Hanselmann
  @param fn: Function to be called
2127 de0ea66b Michael Hanselmann
  @param delay: Either a callable (returning the delay), a tuple of (start,
2128 de0ea66b Michael Hanselmann
                factor, limit) (see L{_RetryDelayCalculator}),
2129 de0ea66b Michael Hanselmann
                L{RETRY_REMAINING_TIME} or a number (int or float)
2130 de0ea66b Michael Hanselmann
  @type timeout: float
2131 de0ea66b Michael Hanselmann
  @param timeout: Total timeout
2132 de0ea66b Michael Hanselmann
  @type wait_fn: callable
2133 de0ea66b Michael Hanselmann
  @param wait_fn: Waiting function
2134 de0ea66b Michael Hanselmann
  @return: Return value of function
2135 de0ea66b Michael Hanselmann

2136 de0ea66b Michael Hanselmann
  """
2137 de0ea66b Michael Hanselmann
  assert callable(fn)
2138 de0ea66b Michael Hanselmann
  assert callable(wait_fn)
2139 de0ea66b Michael Hanselmann
  assert callable(_time_fn)
2140 de0ea66b Michael Hanselmann
2141 de0ea66b Michael Hanselmann
  if args is None:
2142 de0ea66b Michael Hanselmann
    args = []
2143 de0ea66b Michael Hanselmann
2144 de0ea66b Michael Hanselmann
  end_time = _time_fn() + timeout
2145 de0ea66b Michael Hanselmann
2146 de0ea66b Michael Hanselmann
  if callable(delay):
2147 de0ea66b Michael Hanselmann
    # External function to calculate delay
2148 de0ea66b Michael Hanselmann
    calc_delay = delay
2149 de0ea66b Michael Hanselmann
2150 de0ea66b Michael Hanselmann
  elif isinstance(delay, (tuple, list)):
2151 de0ea66b Michael Hanselmann
    # Increasing delay with optional upper boundary
2152 de0ea66b Michael Hanselmann
    (start, factor, limit) = delay
2153 de0ea66b Michael Hanselmann
    calc_delay = _RetryDelayCalculator(start, factor, limit)
2154 de0ea66b Michael Hanselmann
2155 de0ea66b Michael Hanselmann
  elif delay is RETRY_REMAINING_TIME:
2156 de0ea66b Michael Hanselmann
    # Always use the remaining time
2157 de0ea66b Michael Hanselmann
    calc_delay = None
2158 de0ea66b Michael Hanselmann
2159 de0ea66b Michael Hanselmann
  else:
2160 de0ea66b Michael Hanselmann
    # Static delay
2161 de0ea66b Michael Hanselmann
    calc_delay = lambda: delay
2162 de0ea66b Michael Hanselmann
2163 de0ea66b Michael Hanselmann
  assert calc_delay is None or callable(calc_delay)
2164 de0ea66b Michael Hanselmann
2165 de0ea66b Michael Hanselmann
  while True:
2166 de0ea66b Michael Hanselmann
    try:
2167 de0ea66b Michael Hanselmann
      return fn(*args)
2168 de0ea66b Michael Hanselmann
    except RetryAgain:
2169 de0ea66b Michael Hanselmann
      pass
2170 de0ea66b Michael Hanselmann
2171 de0ea66b Michael Hanselmann
    remaining_time = end_time - _time_fn()
2172 de0ea66b Michael Hanselmann
2173 de0ea66b Michael Hanselmann
    if remaining_time < 0.0:
2174 de0ea66b Michael Hanselmann
      raise RetryTimeout()
2175 de0ea66b Michael Hanselmann
2176 de0ea66b Michael Hanselmann
    assert remaining_time >= 0.0
2177 de0ea66b Michael Hanselmann
2178 de0ea66b Michael Hanselmann
    if calc_delay is None:
2179 de0ea66b Michael Hanselmann
      wait_fn(remaining_time)
2180 de0ea66b Michael Hanselmann
    else:
2181 de0ea66b Michael Hanselmann
      current_delay = calc_delay()
2182 de0ea66b Michael Hanselmann
      if current_delay > 0.0:
2183 de0ea66b Michael Hanselmann
        wait_fn(current_delay)
2184 de0ea66b Michael Hanselmann
2185 de0ea66b Michael Hanselmann
2186 a87b4824 Michael Hanselmann
class FileLock(object):
2187 a87b4824 Michael Hanselmann
  """Utility class for file locks.
2188 a87b4824 Michael Hanselmann

2189 a87b4824 Michael Hanselmann
  """
2190 a87b4824 Michael Hanselmann
  def __init__(self, filename):
2191 58885d79 Iustin Pop
    """Constructor for FileLock.
2192 58885d79 Iustin Pop

2193 58885d79 Iustin Pop
    This will open the file denoted by the I{filename} argument.
2194 58885d79 Iustin Pop

2195 58885d79 Iustin Pop
    @type filename: str
2196 58885d79 Iustin Pop
    @param filename: path to the file to be locked
2197 58885d79 Iustin Pop

2198 58885d79 Iustin Pop
    """
2199 a87b4824 Michael Hanselmann
    self.filename = filename
2200 a87b4824 Michael Hanselmann
    self.fd = open(self.filename, "w")
2201 a87b4824 Michael Hanselmann
2202 a87b4824 Michael Hanselmann
  def __del__(self):
2203 a87b4824 Michael Hanselmann
    self.Close()
2204 a87b4824 Michael Hanselmann
2205 a87b4824 Michael Hanselmann
  def Close(self):
2206 58885d79 Iustin Pop
    """Close the file and release the lock.
2207 58885d79 Iustin Pop

2208 58885d79 Iustin Pop
    """
2209 a87b4824 Michael Hanselmann
    if self.fd:
2210 a87b4824 Michael Hanselmann
      self.fd.close()
2211 a87b4824 Michael Hanselmann
      self.fd = None
2212 a87b4824 Michael Hanselmann
2213 aa74b828 Michael Hanselmann
  def _flock(self, flag, blocking, timeout, errmsg):
2214 aa74b828 Michael Hanselmann
    """Wrapper for fcntl.flock.
2215 aa74b828 Michael Hanselmann

2216 aa74b828 Michael Hanselmann
    @type flag: int
2217 58885d79 Iustin Pop
    @param flag: operation flag
2218 aa74b828 Michael Hanselmann
    @type blocking: bool
2219 58885d79 Iustin Pop
    @param blocking: whether the operation should be done in blocking mode.
2220 aa74b828 Michael Hanselmann
    @type timeout: None or float
2221 58885d79 Iustin Pop
    @param timeout: for how long the operation should be retried (implies
2222 aa74b828 Michael Hanselmann
                    non-blocking mode).
2223 aa74b828 Michael Hanselmann
    @type errmsg: string
2224 58885d79 Iustin Pop
    @param errmsg: error message in case operation fails.
2225 aa74b828 Michael Hanselmann

2226 aa74b828 Michael Hanselmann
    """
2227 a87b4824 Michael Hanselmann
    assert self.fd, "Lock was closed"
2228 aa74b828 Michael Hanselmann
    assert timeout is None or timeout >= 0, \
2229 aa74b828 Michael Hanselmann
      "If specified, timeout must be positive"
2230 a87b4824 Michael Hanselmann
2231 aa74b828 Michael Hanselmann
    if timeout is not None:
2232 a87b4824 Michael Hanselmann
      flag |= fcntl.LOCK_NB
2233 aa74b828 Michael Hanselmann
      timeout_end = time.time() + timeout
2234 a87b4824 Michael Hanselmann
2235 aa74b828 Michael Hanselmann
    # Blocking doesn't have effect with timeout
2236 aa74b828 Michael Hanselmann
    elif not blocking:
2237 aa74b828 Michael Hanselmann
      flag |= fcntl.LOCK_NB
2238 aa74b828 Michael Hanselmann
      timeout_end = None
2239 aa74b828 Michael Hanselmann
2240 31892b4c Michael Hanselmann
    # TODO: Convert to utils.Retry
2241 31892b4c Michael Hanselmann
2242 aa74b828 Michael Hanselmann
    retry = True
2243 aa74b828 Michael Hanselmann
    while retry:
2244 aa74b828 Michael Hanselmann
      try:
2245 aa74b828 Michael Hanselmann
        fcntl.flock(self.fd, flag)
2246 aa74b828 Michael Hanselmann
        retry = False
2247 aa74b828 Michael Hanselmann
      except IOError, err:
2248 aa74b828 Michael Hanselmann
        if err.errno in (errno.EAGAIN, ):
2249 aa74b828 Michael Hanselmann
          if timeout_end is not None and time.time() < timeout_end:
2250 aa74b828 Michael Hanselmann
            # Wait before trying again
2251 aa74b828 Michael Hanselmann
            time.sleep(max(0.1, min(1.0, timeout)))
2252 aa74b828 Michael Hanselmann
          else:
2253 aa74b828 Michael Hanselmann
            raise errors.LockError(errmsg)
2254 aa74b828 Michael Hanselmann
        else:
2255 aa74b828 Michael Hanselmann
          logging.exception("fcntl.flock failed")
2256 aa74b828 Michael Hanselmann
          raise
2257 aa74b828 Michael Hanselmann
2258 aa74b828 Michael Hanselmann
  def Exclusive(self, blocking=False, timeout=None):
2259 a87b4824 Michael Hanselmann
    """Locks the file in exclusive mode.
2260 a87b4824 Michael Hanselmann

2261 58885d79 Iustin Pop
    @type blocking: boolean
2262 58885d79 Iustin Pop
    @param blocking: whether to block and wait until we
2263 58885d79 Iustin Pop
        can lock the file or return immediately
2264 58885d79 Iustin Pop
    @type timeout: int or None
2265 58885d79 Iustin Pop
    @param timeout: if not None, the duration to wait for the lock
2266 58885d79 Iustin Pop
        (in blocking mode)
2267 58885d79 Iustin Pop

2268 a87b4824 Michael Hanselmann
    """
2269 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_EX, blocking, timeout,
2270 a87b4824 Michael Hanselmann
                "Failed to lock %s in exclusive mode" % self.filename)
2271 a87b4824 Michael Hanselmann
2272 aa74b828 Michael Hanselmann
  def Shared(self, blocking=False, timeout=None):
2273 a87b4824 Michael Hanselmann
    """Locks the file in shared mode.
2274 a87b4824 Michael Hanselmann

2275 58885d79 Iustin Pop
    @type blocking: boolean
2276 58885d79 Iustin Pop
    @param blocking: whether to block and wait until we
2277 58885d79 Iustin Pop
        can lock the file or return immediately
2278 58885d79 Iustin Pop
    @type timeout: int or None
2279 58885d79 Iustin Pop
    @param timeout: if not None, the duration to wait for the lock
2280 58885d79 Iustin Pop
        (in blocking mode)
2281 58885d79 Iustin Pop

2282 a87b4824 Michael Hanselmann
    """
2283 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_SH, blocking, timeout,
2284 a87b4824 Michael Hanselmann
                "Failed to lock %s in shared mode" % self.filename)
2285 a87b4824 Michael Hanselmann
2286 aa74b828 Michael Hanselmann
  def Unlock(self, blocking=True, timeout=None):
2287 a87b4824 Michael Hanselmann
    """Unlocks the file.
2288 a87b4824 Michael Hanselmann

2289 58885d79 Iustin Pop
    According to C{flock(2)}, unlocking can also be a nonblocking
2290 58885d79 Iustin Pop
    operation::
2291 58885d79 Iustin Pop

2292 58885d79 Iustin Pop
      To make a non-blocking request, include LOCK_NB with any of the above
2293 58885d79 Iustin Pop
      operations.
2294 58885d79 Iustin Pop

2295 58885d79 Iustin Pop
    @type blocking: boolean
2296 58885d79 Iustin Pop
    @param blocking: whether to block and wait until we
2297 58885d79 Iustin Pop
        can lock the file or return immediately
2298 58885d79 Iustin Pop
    @type timeout: int or None
2299 58885d79 Iustin Pop
    @param timeout: if not None, the duration to wait for the lock
2300 58885d79 Iustin Pop
        (in blocking mode)
2301 a87b4824 Michael Hanselmann

2302 a87b4824 Michael Hanselmann
    """
2303 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_UN, blocking, timeout,
2304 a87b4824 Michael Hanselmann
                "Failed to unlock %s" % self.filename)
2305 a87b4824 Michael Hanselmann
2306 a87b4824 Michael Hanselmann
2307 451575de Guido Trotter
def SignalHandled(signums):
2308 451575de Guido Trotter
  """Signal Handled decoration.
2309 451575de Guido Trotter

2310 451575de Guido Trotter
  This special decorator installs a signal handler and then calls the target
2311 451575de Guido Trotter
  function. The function must accept a 'signal_handlers' keyword argument,
2312 451575de Guido Trotter
  which will contain a dict indexed by signal number, with SignalHandler
2313 451575de Guido Trotter
  objects as values.
2314 451575de Guido Trotter

2315 451575de Guido Trotter
  The decorator can be safely stacked with iself, to handle multiple signals
2316 451575de Guido Trotter
  with different handlers.
2317 451575de Guido Trotter

2318 451575de Guido Trotter
  @type signums: list
2319 451575de Guido Trotter
  @param signums: signals to intercept
2320 451575de Guido Trotter

2321 451575de Guido Trotter
  """
2322 451575de Guido Trotter
  def wrap(fn):
2323 451575de Guido Trotter
    def sig_function(*args, **kwargs):
2324 451575de Guido Trotter
      assert 'signal_handlers' not in kwargs or \
2325 451575de Guido Trotter
             kwargs['signal_handlers'] is None or \
2326 451575de Guido Trotter
             isinstance(kwargs['signal_handlers'], dict), \
2327 451575de Guido Trotter
             "Wrong signal_handlers parameter in original function call"
2328 451575de Guido Trotter
      if 'signal_handlers' in kwargs and kwargs['signal_handlers'] is not None:
2329 451575de Guido Trotter
        signal_handlers = kwargs['signal_handlers']
2330 451575de Guido Trotter
      else:
2331 451575de Guido Trotter
        signal_handlers = {}
2332 451575de Guido Trotter
        kwargs['signal_handlers'] = signal_handlers
2333 451575de Guido Trotter
      sighandler = SignalHandler(signums)
2334 451575de Guido Trotter
      try:
2335 451575de Guido Trotter
        for sig in signums:
2336 451575de Guido Trotter
          signal_handlers[sig] = sighandler
2337 451575de Guido Trotter
        return fn(*args, **kwargs)
2338 451575de Guido Trotter
      finally:
2339 451575de Guido Trotter
        sighandler.Reset()
2340 451575de Guido Trotter
    return sig_function
2341 451575de Guido Trotter
  return wrap
2342 451575de Guido Trotter
2343 451575de Guido Trotter
2344 de499029 Michael Hanselmann
class SignalHandler(object):
2345 de499029 Michael Hanselmann
  """Generic signal handler class.
2346 de499029 Michael Hanselmann

2347 58885d79 Iustin Pop
  It automatically restores the original handler when deconstructed or
2348 58885d79 Iustin Pop
  when L{Reset} is called. You can either pass your own handler
2349 58885d79 Iustin Pop
  function in or query the L{called} attribute to detect whether the
2350 58885d79 Iustin Pop
  signal was sent.
2351 58885d79 Iustin Pop

2352 58885d79 Iustin Pop
  @type signum: list
2353 58885d79 Iustin Pop
  @ivar signum: the signals we handle
2354 58885d79 Iustin Pop
  @type called: boolean
2355 58885d79 Iustin Pop
  @ivar called: tracks whether any of the signals have been raised
2356 de499029 Michael Hanselmann

2357 de499029 Michael Hanselmann
  """
2358 de499029 Michael Hanselmann
  def __init__(self, signum):
2359 de499029 Michael Hanselmann
    """Constructs a new SignalHandler instance.
2360 de499029 Michael Hanselmann

2361 58885d79 Iustin Pop
    @type signum: int or list of ints
2362 de499029 Michael Hanselmann
    @param signum: Single signal number or set of signal numbers
2363 de499029 Michael Hanselmann

2364 de499029 Michael Hanselmann
    """
2365 6c52849e Guido Trotter
    self.signum = set(signum)
2366 de499029 Michael Hanselmann
    self.called = False
2367 de499029 Michael Hanselmann
2368 de499029 Michael Hanselmann
    self._previous = {}
2369 de499029 Michael Hanselmann
    try:
2370 de499029 Michael Hanselmann
      for signum in self.signum:
2371 de499029 Michael Hanselmann
        # Setup handler
2372 de499029 Michael Hanselmann
        prev_handler = signal.signal(signum, self._HandleSignal)
2373 de499029 Michael Hanselmann
        try:
2374 de499029 Michael Hanselmann
          self._previous[signum] = prev_handler
2375 de499029 Michael Hanselmann
        except:
2376 de499029 Michael Hanselmann
          # Restore previous handler
2377 de499029 Michael Hanselmann
          signal.signal(signum, prev_handler)
2378 de499029 Michael Hanselmann
          raise
2379 de499029 Michael Hanselmann
    except:
2380 de499029 Michael Hanselmann
      # Reset all handlers
2381 de499029 Michael Hanselmann
      self.Reset()
2382 de499029 Michael Hanselmann
      # Here we have a race condition: a handler may have already been called,
2383 de499029 Michael Hanselmann
      # but there's not much we can do about it at this point.
2384 de499029 Michael Hanselmann
      raise
2385 de499029 Michael Hanselmann
2386 de499029 Michael Hanselmann
  def __del__(self):
2387 de499029 Michael Hanselmann
    self.Reset()
2388 de499029 Michael Hanselmann
2389 de499029 Michael Hanselmann
  def Reset(self):
2390 de499029 Michael Hanselmann
    """Restore previous handler.
2391 de499029 Michael Hanselmann

2392 58885d79 Iustin Pop
    This will reset all the signals to their previous handlers.
2393 58885d79 Iustin Pop

2394 de499029 Michael Hanselmann
    """
2395 de499029 Michael Hanselmann
    for signum, prev_handler in self._previous.items():
2396 de499029 Michael Hanselmann
      signal.signal(signum, prev_handler)
2397 de499029 Michael Hanselmann
      # If successful, remove from dict
2398 de499029 Michael Hanselmann
      del self._previous[signum]
2399 de499029 Michael Hanselmann
2400 de499029 Michael Hanselmann
  def Clear(self):
2401 58885d79 Iustin Pop
    """Unsets the L{called} flag.
2402 de499029 Michael Hanselmann

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

2405 de499029 Michael Hanselmann
    """
2406 de499029 Michael Hanselmann
    self.called = False
2407 de499029 Michael Hanselmann
2408 de499029 Michael Hanselmann
  def _HandleSignal(self, signum, frame):
2409 de499029 Michael Hanselmann
    """Actual signal handling function.
2410 de499029 Michael Hanselmann

2411 de499029 Michael Hanselmann
    """
2412 de499029 Michael Hanselmann
    # This is not nice and not absolutely atomic, but it appears to be the only
2413 de499029 Michael Hanselmann
    # solution in Python -- there are no atomic types.
2414 de499029 Michael Hanselmann
    self.called = True
2415 a2d2e1a7 Iustin Pop
2416 a2d2e1a7 Iustin Pop
2417 a2d2e1a7 Iustin Pop
class FieldSet(object):
2418 a2d2e1a7 Iustin Pop
  """A simple field set.
2419 a2d2e1a7 Iustin Pop

2420 a2d2e1a7 Iustin Pop
  Among the features are:
2421 a2d2e1a7 Iustin Pop
    - checking if a string is among a list of static string or regex objects
2422 a2d2e1a7 Iustin Pop
    - checking if a whole list of string matches
2423 a2d2e1a7 Iustin Pop
    - returning the matching groups from a regex match
2424 a2d2e1a7 Iustin Pop

2425 a2d2e1a7 Iustin Pop
  Internally, all fields are held as regular expression objects.
2426 a2d2e1a7 Iustin Pop

2427 a2d2e1a7 Iustin Pop
  """
2428 a2d2e1a7 Iustin Pop
  def __init__(self, *items):
2429 a2d2e1a7 Iustin Pop
    self.items = [re.compile("^%s$" % value) for value in items]
2430 a2d2e1a7 Iustin Pop
2431 a2d2e1a7 Iustin Pop
  def Extend(self, other_set):
2432 a2d2e1a7 Iustin Pop
    """Extend the field set with the items from another one"""
2433 a2d2e1a7 Iustin Pop
    self.items.extend(other_set.items)
2434 a2d2e1a7 Iustin Pop
2435 a2d2e1a7 Iustin Pop
  def Matches(self, field):
2436 a2d2e1a7 Iustin Pop
    """Checks if a field matches the current set
2437 a2d2e1a7 Iustin Pop

2438 a2d2e1a7 Iustin Pop
    @type field: str
2439 a2d2e1a7 Iustin Pop
    @param field: the string to match
2440 6c881c52 Iustin Pop
    @return: either None or a regular expression match object
2441 a2d2e1a7 Iustin Pop

2442 a2d2e1a7 Iustin Pop
    """
2443 a2d2e1a7 Iustin Pop
    for m in itertools.ifilter(None, (val.match(field) for val in self.items)):
2444 a2d2e1a7 Iustin Pop
      return m
2445 6c881c52 Iustin Pop
    return None
2446 a2d2e1a7 Iustin Pop
2447 a2d2e1a7 Iustin Pop
  def NonMatching(self, items):
2448 a2d2e1a7 Iustin Pop
    """Returns the list of fields not matching the current set
2449 a2d2e1a7 Iustin Pop

2450 a2d2e1a7 Iustin Pop
    @type items: list
2451 a2d2e1a7 Iustin Pop
    @param items: the list of fields to check
2452 a2d2e1a7 Iustin Pop
    @rtype: list
2453 a2d2e1a7 Iustin Pop
    @return: list of non-matching fields
2454 a2d2e1a7 Iustin Pop

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