Statistics
| Branch: | Tag: | Revision:

root / lib / utils / __init__.py @ 7d444d59

History | View | Annotate | Download (48.7 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 4fd029cf Michael Hanselmann
# Copyright (C) 2006, 2007, 2010, 2011 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 c1dd99d4 Michael Hanselmann
import sys
32 a8083063 Iustin Pop
import time
33 113b55aa Iustin Pop
import subprocess
34 a8083063 Iustin Pop
import re
35 a8083063 Iustin Pop
import socket
36 a8083063 Iustin Pop
import tempfile
37 a8083063 Iustin Pop
import shutil
38 4ca1b175 Alexander Schreiber
import errno
39 2f8b60b3 Iustin Pop
import pwd
40 78feb6fb Guido Trotter
import itertools
41 9c233417 Iustin Pop
import select
42 9c233417 Iustin Pop
import fcntl
43 8f765069 Iustin Pop
import resource
44 bb698c1f Iustin Pop
import logging
45 de499029 Michael Hanselmann
import signal
46 27e46076 Michael Hanselmann
import datetime
47 27e46076 Michael Hanselmann
import calendar
48 9c233417 Iustin Pop
49 9c233417 Iustin Pop
from cStringIO import StringIO
50 a8083063 Iustin Pop
51 a8083063 Iustin Pop
from ganeti import errors
52 3aecd2c7 Iustin Pop
from ganeti import constants
53 716a32cb Guido Trotter
from ganeti import compat
54 a8083063 Iustin Pop
55 4fd029cf Michael Hanselmann
from ganeti.utils.algo import * # pylint: disable-msg=W0401
56 79d22269 Michael Hanselmann
from ganeti.utils.retry import * # pylint: disable-msg=W0401
57 7fcffe27 Michael Hanselmann
from ganeti.utils.text import * # pylint: disable-msg=W0401
58 36a4acd4 Michael Hanselmann
from ganeti.utils.mlock import * # pylint: disable-msg=W0401
59 1ae4c5a1 Michael Hanselmann
from ganeti.utils.log import * # pylint: disable-msg=W0401
60 f21bb4b7 Michael Hanselmann
from ganeti.utils.hash import * # pylint: disable-msg=W0401
61 7831fc5f Michael Hanselmann
from ganeti.utils.wrapper import * # pylint: disable-msg=W0401
62 9d1b963f Michael Hanselmann
from ganeti.utils.filelock import * # pylint: disable-msg=W0401
63 3865ca48 Michael Hanselmann
from ganeti.utils.io import * # pylint: disable-msg=W0401
64 c50645c0 Michael Hanselmann
from ganeti.utils.x509 import * # pylint: disable-msg=W0401
65 17b97ab3 Michael Hanselmann
from ganeti.utils.nodesetup import * # pylint: disable-msg=W0401
66 16abfbc2 Alexander Schreiber
67 58885d79 Iustin Pop
68 58885d79 Iustin Pop
#: when set to True, L{RunCmd} is disabled
69 7b4baeb1 Michael Hanselmann
_no_fork = False
70 f362096f Iustin Pop
71 13998ef2 Michael Hanselmann
_RANDOM_UUID_FILE = "/proc/sys/kernel/random/uuid"
72 13998ef2 Michael Hanselmann
73 28f34048 Michael Hanselmann
_VALID_SERVICE_NAME_RE = re.compile("^[-_.a-zA-Z0-9]{1,128}$")
74 28f34048 Michael Hanselmann
75 05636402 Guido Trotter
UUID_RE = re.compile('^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-'
76 05636402 Guido Trotter
                     '[a-f0-9]{4}-[a-f0-9]{12}$')
77 05636402 Guido Trotter
78 c74cda62 René Nussbaumer
(_TIMEOUT_NONE,
79 c74cda62 René Nussbaumer
 _TIMEOUT_TERM,
80 c74cda62 René Nussbaumer
 _TIMEOUT_KILL) = range(3)
81 c74cda62 René Nussbaumer
82 0b5303da Iustin Pop
#: Shell param checker regexp
83 0b5303da Iustin Pop
_SHELLPARAM_REGEX = re.compile(r"^[-a-zA-Z0-9._+/:%@]+$")
84 0b5303da Iustin Pop
85 7c0d6283 Michael Hanselmann
86 7b4baeb1 Michael Hanselmann
def DisableFork():
87 7b4baeb1 Michael Hanselmann
  """Disables the use of fork(2).
88 7b4baeb1 Michael Hanselmann

89 7b4baeb1 Michael Hanselmann
  """
90 7b4baeb1 Michael Hanselmann
  global _no_fork # pylint: disable-msg=W0603
91 7b4baeb1 Michael Hanselmann
92 7b4baeb1 Michael Hanselmann
  _no_fork = True
93 7b4baeb1 Michael Hanselmann
94 7b4baeb1 Michael Hanselmann
95 a8083063 Iustin Pop
class RunResult(object):
96 58885d79 Iustin Pop
  """Holds the result of running external programs.
97 58885d79 Iustin Pop

98 58885d79 Iustin Pop
  @type exit_code: int
99 58885d79 Iustin Pop
  @ivar exit_code: the exit code of the program, or None (if the program
100 58885d79 Iustin Pop
      didn't exit())
101 58885d79 Iustin Pop
  @type signal: int or None
102 58885d79 Iustin Pop
  @ivar signal: the signal that caused the program to finish, or None
103 58885d79 Iustin Pop
      (if the program wasn't terminated by a signal)
104 58885d79 Iustin Pop
  @type stdout: str
105 58885d79 Iustin Pop
  @ivar stdout: the standard output of the program
106 58885d79 Iustin Pop
  @type stderr: str
107 58885d79 Iustin Pop
  @ivar stderr: the standard error of the program
108 58885d79 Iustin Pop
  @type failed: boolean
109 58885d79 Iustin Pop
  @ivar failed: True in case the program was
110 58885d79 Iustin Pop
      terminated by a signal or exited with a non-zero exit code
111 58885d79 Iustin Pop
  @ivar fail_reason: a string detailing the termination reason
112 a8083063 Iustin Pop

113 a8083063 Iustin Pop
  """
114 a8083063 Iustin Pop
  __slots__ = ["exit_code", "signal", "stdout", "stderr",
115 a8083063 Iustin Pop
               "failed", "fail_reason", "cmd"]
116 a8083063 Iustin Pop
117 a8083063 Iustin Pop
118 c74cda62 René Nussbaumer
  def __init__(self, exit_code, signal_, stdout, stderr, cmd, timeout_action,
119 c74cda62 René Nussbaumer
               timeout):
120 a8083063 Iustin Pop
    self.cmd = cmd
121 a8083063 Iustin Pop
    self.exit_code = exit_code
122 38206f3c Iustin Pop
    self.signal = signal_
123 a8083063 Iustin Pop
    self.stdout = stdout
124 a8083063 Iustin Pop
    self.stderr = stderr
125 38206f3c Iustin Pop
    self.failed = (signal_ is not None or exit_code != 0)
126 a8083063 Iustin Pop
127 c74cda62 René Nussbaumer
    fail_msgs = []
128 a8083063 Iustin Pop
    if self.signal is not None:
129 c74cda62 René Nussbaumer
      fail_msgs.append("terminated by signal %s" % self.signal)
130 a8083063 Iustin Pop
    elif self.exit_code is not None:
131 c74cda62 René Nussbaumer
      fail_msgs.append("exited with exit code %s" % self.exit_code)
132 a8083063 Iustin Pop
    else:
133 c74cda62 René Nussbaumer
      fail_msgs.append("unable to determine termination reason")
134 c74cda62 René Nussbaumer
135 c74cda62 René Nussbaumer
    if timeout_action == _TIMEOUT_TERM:
136 c74cda62 René Nussbaumer
      fail_msgs.append("terminated after timeout of %.2f seconds" % timeout)
137 c74cda62 René Nussbaumer
    elif timeout_action == _TIMEOUT_KILL:
138 c74cda62 René Nussbaumer
      fail_msgs.append(("force termination after timeout of %.2f seconds"
139 c74cda62 René Nussbaumer
                        " and linger for another %.2f seconds") %
140 c74cda62 René Nussbaumer
                       (timeout, constants.CHILD_LINGER_TIMEOUT))
141 c74cda62 René Nussbaumer
142 c74cda62 René Nussbaumer
    if fail_msgs and self.failed:
143 c74cda62 René Nussbaumer
      self.fail_reason = CommaJoin(fail_msgs)
144 a8083063 Iustin Pop
145 bb698c1f Iustin Pop
    if self.failed:
146 bb698c1f Iustin Pop
      logging.debug("Command '%s' failed (%s); output: %s",
147 bb698c1f Iustin Pop
                    self.cmd, self.fail_reason, self.output)
148 f362096f Iustin Pop
149 a8083063 Iustin Pop
  def _GetOutput(self):
150 a8083063 Iustin Pop
    """Returns the combined stdout and stderr for easier usage.
151 a8083063 Iustin Pop

152 a8083063 Iustin Pop
    """
153 a8083063 Iustin Pop
    return self.stdout + self.stderr
154 a8083063 Iustin Pop
155 a8083063 Iustin Pop
  output = property(_GetOutput, None, None, "Return full output")
156 a8083063 Iustin Pop
157 a8083063 Iustin Pop
158 bb3776b4 Michael Hanselmann
def _BuildCmdEnvironment(env, reset):
159 c1dd99d4 Michael Hanselmann
  """Builds the environment for an external program.
160 c1dd99d4 Michael Hanselmann

161 c1dd99d4 Michael Hanselmann
  """
162 bb3776b4 Michael Hanselmann
  if reset:
163 bb3776b4 Michael Hanselmann
    cmd_env = {}
164 bb3776b4 Michael Hanselmann
  else:
165 bb3776b4 Michael Hanselmann
    cmd_env = os.environ.copy()
166 bb3776b4 Michael Hanselmann
    cmd_env["LC_ALL"] = "C"
167 bb3776b4 Michael Hanselmann
168 c1dd99d4 Michael Hanselmann
  if env is not None:
169 c1dd99d4 Michael Hanselmann
    cmd_env.update(env)
170 bb3776b4 Michael Hanselmann
171 c1dd99d4 Michael Hanselmann
  return cmd_env
172 c1dd99d4 Michael Hanselmann
173 c1dd99d4 Michael Hanselmann
174 0963d545 René Nussbaumer
def RunCmd(cmd, env=None, output=None, cwd="/", reset_env=False,
175 c74cda62 René Nussbaumer
           interactive=False, timeout=None):
176 a8083063 Iustin Pop
  """Execute a (shell) command.
177 a8083063 Iustin Pop

178 a8083063 Iustin Pop
  The command should not read from its standard input, as it will be
179 a8083063 Iustin Pop
  closed.
180 a8083063 Iustin Pop

181 c1dd99d4 Michael Hanselmann
  @type cmd: string or list
182 36117c2b Iustin Pop
  @param cmd: Command to run
183 2557ff82 Guido Trotter
  @type env: dict
184 c1dd99d4 Michael Hanselmann
  @param env: Additional environment variables
185 36117c2b Iustin Pop
  @type output: str
186 58885d79 Iustin Pop
  @param output: if desired, the output of the command can be
187 36117c2b Iustin Pop
      saved in a file instead of the RunResult instance; this
188 36117c2b Iustin Pop
      parameter denotes the file name (if not None)
189 8797df43 Iustin Pop
  @type cwd: string
190 8797df43 Iustin Pop
  @param cwd: if specified, will be used as the working
191 8797df43 Iustin Pop
      directory for the command; the default will be /
192 bf4daac9 Guido Trotter
  @type reset_env: boolean
193 bf4daac9 Guido Trotter
  @param reset_env: whether to reset or keep the default os environment
194 0963d545 René Nussbaumer
  @type interactive: boolean
195 0963d545 René Nussbaumer
  @param interactive: weather we pipe stdin, stdout and stderr
196 0963d545 René Nussbaumer
                      (default behaviour) or run the command interactive
197 c74cda62 René Nussbaumer
  @type timeout: int
198 c74cda62 René Nussbaumer
  @param timeout: If not None, timeout in seconds until child process gets
199 c74cda62 René Nussbaumer
                  killed
200 36117c2b Iustin Pop
  @rtype: L{RunResult}
201 58885d79 Iustin Pop
  @return: RunResult instance
202 5bbd3f7f Michael Hanselmann
  @raise errors.ProgrammerError: if we call this when forks are disabled
203 a8083063 Iustin Pop

204 a8083063 Iustin Pop
  """
205 7b4baeb1 Michael Hanselmann
  if _no_fork:
206 b74159ee Iustin Pop
    raise errors.ProgrammerError("utils.RunCmd() called with fork() disabled")
207 b74159ee Iustin Pop
208 0963d545 René Nussbaumer
  if output and interactive:
209 0963d545 René Nussbaumer
    raise errors.ProgrammerError("Parameters 'output' and 'interactive' can"
210 0963d545 René Nussbaumer
                                 " not be provided at the same time")
211 0963d545 René Nussbaumer
212 c1dd99d4 Michael Hanselmann
  if isinstance(cmd, basestring):
213 c1dd99d4 Michael Hanselmann
    strcmd = cmd
214 c1dd99d4 Michael Hanselmann
    shell = True
215 c1dd99d4 Michael Hanselmann
  else:
216 a8083063 Iustin Pop
    cmd = [str(val) for val in cmd]
217 c1dd99d4 Michael Hanselmann
    strcmd = ShellQuoteArgs(cmd)
218 113b55aa Iustin Pop
    shell = False
219 c1dd99d4 Michael Hanselmann
220 c1dd99d4 Michael Hanselmann
  if output:
221 c1dd99d4 Michael Hanselmann
    logging.debug("RunCmd %s, output file '%s'", strcmd, output)
222 113b55aa Iustin Pop
  else:
223 c1dd99d4 Michael Hanselmann
    logging.debug("RunCmd %s", strcmd)
224 2557ff82 Guido Trotter
225 bb3776b4 Michael Hanselmann
  cmd_env = _BuildCmdEnvironment(env, reset_env)
226 2557ff82 Guido Trotter
227 c803b052 Iustin Pop
  try:
228 c803b052 Iustin Pop
    if output is None:
229 c74cda62 René Nussbaumer
      out, err, status, timeout_action = _RunCmdPipe(cmd, cmd_env, shell, cwd,
230 c74cda62 René Nussbaumer
                                                     interactive, timeout)
231 c803b052 Iustin Pop
    else:
232 c74cda62 René Nussbaumer
      timeout_action = _TIMEOUT_NONE
233 c803b052 Iustin Pop
      status = _RunCmdFile(cmd, cmd_env, shell, output, cwd)
234 c803b052 Iustin Pop
      out = err = ""
235 c803b052 Iustin Pop
  except OSError, err:
236 c803b052 Iustin Pop
    if err.errno == errno.ENOENT:
237 c803b052 Iustin Pop
      raise errors.OpExecError("Can't execute '%s': not found (%s)" %
238 c803b052 Iustin Pop
                               (strcmd, err))
239 c803b052 Iustin Pop
    else:
240 c803b052 Iustin Pop
      raise
241 36117c2b Iustin Pop
242 36117c2b Iustin Pop
  if status >= 0:
243 36117c2b Iustin Pop
    exitcode = status
244 36117c2b Iustin Pop
    signal_ = None
245 36117c2b Iustin Pop
  else:
246 36117c2b Iustin Pop
    exitcode = None
247 36117c2b Iustin Pop
    signal_ = -status
248 36117c2b Iustin Pop
249 c74cda62 René Nussbaumer
  return RunResult(exitcode, signal_, out, err, strcmd, timeout_action, timeout)
250 36117c2b Iustin Pop
251 ae59efea Michael Hanselmann
252 0260032c Iustin Pop
def SetupDaemonEnv(cwd="/", umask=077):
253 0260032c Iustin Pop
  """Setup a daemon's environment.
254 0260032c Iustin Pop

255 0260032c Iustin Pop
  This should be called between the first and second fork, due to
256 0260032c Iustin Pop
  setsid usage.
257 0260032c Iustin Pop

258 0260032c Iustin Pop
  @param cwd: the directory to which to chdir
259 0260032c Iustin Pop
  @param umask: the umask to setup
260 0260032c Iustin Pop

261 0260032c Iustin Pop
  """
262 0260032c Iustin Pop
  os.chdir(cwd)
263 0260032c Iustin Pop
  os.umask(umask)
264 0260032c Iustin Pop
  os.setsid()
265 0260032c Iustin Pop
266 0260032c Iustin Pop
267 79634555 Iustin Pop
def SetupDaemonFDs(output_file, output_fd):
268 79634555 Iustin Pop
  """Setups up a daemon's file descriptors.
269 79634555 Iustin Pop

270 79634555 Iustin Pop
  @param output_file: if not None, the file to which to redirect
271 79634555 Iustin Pop
      stdout/stderr
272 79634555 Iustin Pop
  @param output_fd: if not None, the file descriptor for stdout/stderr
273 79634555 Iustin Pop

274 79634555 Iustin Pop
  """
275 79634555 Iustin Pop
  # check that at most one is defined
276 79634555 Iustin Pop
  assert [output_file, output_fd].count(None) >= 1
277 79634555 Iustin Pop
278 79634555 Iustin Pop
  # Open /dev/null (read-only, only for stdin)
279 79634555 Iustin Pop
  devnull_fd = os.open(os.devnull, os.O_RDONLY)
280 79634555 Iustin Pop
281 79634555 Iustin Pop
  if output_fd is not None:
282 79634555 Iustin Pop
    pass
283 79634555 Iustin Pop
  elif output_file is not None:
284 79634555 Iustin Pop
    # Open output file
285 79634555 Iustin Pop
    try:
286 79634555 Iustin Pop
      output_fd = os.open(output_file,
287 79634555 Iustin Pop
                          os.O_WRONLY | os.O_CREAT | os.O_APPEND, 0600)
288 79634555 Iustin Pop
    except EnvironmentError, err:
289 79634555 Iustin Pop
      raise Exception("Opening output file failed: %s" % err)
290 79634555 Iustin Pop
  else:
291 79634555 Iustin Pop
    output_fd = os.open(os.devnull, os.O_WRONLY)
292 79634555 Iustin Pop
293 79634555 Iustin Pop
  # Redirect standard I/O
294 79634555 Iustin Pop
  os.dup2(devnull_fd, 0)
295 79634555 Iustin Pop
  os.dup2(output_fd, 1)
296 79634555 Iustin Pop
  os.dup2(output_fd, 2)
297 79634555 Iustin Pop
298 79634555 Iustin Pop
299 c1dd99d4 Michael Hanselmann
def StartDaemon(cmd, env=None, cwd="/", output=None, output_fd=None,
300 c1dd99d4 Michael Hanselmann
                pidfile=None):
301 c1dd99d4 Michael Hanselmann
  """Start a daemon process after forking twice.
302 c1dd99d4 Michael Hanselmann

303 c1dd99d4 Michael Hanselmann
  @type cmd: string or list
304 c1dd99d4 Michael Hanselmann
  @param cmd: Command to run
305 c1dd99d4 Michael Hanselmann
  @type env: dict
306 c1dd99d4 Michael Hanselmann
  @param env: Additional environment variables
307 c1dd99d4 Michael Hanselmann
  @type cwd: string
308 c1dd99d4 Michael Hanselmann
  @param cwd: Working directory for the program
309 c1dd99d4 Michael Hanselmann
  @type output: string
310 c1dd99d4 Michael Hanselmann
  @param output: Path to file in which to save the output
311 c1dd99d4 Michael Hanselmann
  @type output_fd: int
312 c1dd99d4 Michael Hanselmann
  @param output_fd: File descriptor for output
313 c1dd99d4 Michael Hanselmann
  @type pidfile: string
314 c1dd99d4 Michael Hanselmann
  @param pidfile: Process ID file
315 c1dd99d4 Michael Hanselmann
  @rtype: int
316 c1dd99d4 Michael Hanselmann
  @return: Daemon process ID
317 c1dd99d4 Michael Hanselmann
  @raise errors.ProgrammerError: if we call this when forks are disabled
318 c1dd99d4 Michael Hanselmann

319 c1dd99d4 Michael Hanselmann
  """
320 7b4baeb1 Michael Hanselmann
  if _no_fork:
321 c1dd99d4 Michael Hanselmann
    raise errors.ProgrammerError("utils.StartDaemon() called with fork()"
322 c1dd99d4 Michael Hanselmann
                                 " disabled")
323 c1dd99d4 Michael Hanselmann
324 c1dd99d4 Michael Hanselmann
  if output and not (bool(output) ^ (output_fd is not None)):
325 c1dd99d4 Michael Hanselmann
    raise errors.ProgrammerError("Only one of 'output' and 'output_fd' can be"
326 c1dd99d4 Michael Hanselmann
                                 " specified")
327 c1dd99d4 Michael Hanselmann
328 c1dd99d4 Michael Hanselmann
  if isinstance(cmd, basestring):
329 c1dd99d4 Michael Hanselmann
    cmd = ["/bin/sh", "-c", cmd]
330 c1dd99d4 Michael Hanselmann
331 c1dd99d4 Michael Hanselmann
  strcmd = ShellQuoteArgs(cmd)
332 c1dd99d4 Michael Hanselmann
333 c1dd99d4 Michael Hanselmann
  if output:
334 c1dd99d4 Michael Hanselmann
    logging.debug("StartDaemon %s, output file '%s'", strcmd, output)
335 c1dd99d4 Michael Hanselmann
  else:
336 c1dd99d4 Michael Hanselmann
    logging.debug("StartDaemon %s", strcmd)
337 c1dd99d4 Michael Hanselmann
338 bb3776b4 Michael Hanselmann
  cmd_env = _BuildCmdEnvironment(env, False)
339 c1dd99d4 Michael Hanselmann
340 c1dd99d4 Michael Hanselmann
  # Create pipe for sending PID back
341 c1dd99d4 Michael Hanselmann
  (pidpipe_read, pidpipe_write) = os.pipe()
342 c1dd99d4 Michael Hanselmann
  try:
343 c1dd99d4 Michael Hanselmann
    try:
344 c1dd99d4 Michael Hanselmann
      # Create pipe for sending error messages
345 c1dd99d4 Michael Hanselmann
      (errpipe_read, errpipe_write) = os.pipe()
346 c1dd99d4 Michael Hanselmann
      try:
347 c1dd99d4 Michael Hanselmann
        try:
348 c1dd99d4 Michael Hanselmann
          # First fork
349 c1dd99d4 Michael Hanselmann
          pid = os.fork()
350 c1dd99d4 Michael Hanselmann
          if pid == 0:
351 c1dd99d4 Michael Hanselmann
            try:
352 c1dd99d4 Michael Hanselmann
              # Child process, won't return
353 e0bb431e Michael Hanselmann
              _StartDaemonChild(errpipe_read, errpipe_write,
354 e0bb431e Michael Hanselmann
                                pidpipe_read, pidpipe_write,
355 e0bb431e Michael Hanselmann
                                cmd, cmd_env, cwd,
356 e0bb431e Michael Hanselmann
                                output, output_fd, pidfile)
357 c1dd99d4 Michael Hanselmann
            finally:
358 c1dd99d4 Michael Hanselmann
              # Well, maybe child process failed
359 e0bb431e Michael Hanselmann
              os._exit(1) # pylint: disable-msg=W0212
360 c1dd99d4 Michael Hanselmann
        finally:
361 71ab9dbe Michael Hanselmann
          CloseFdNoError(errpipe_write)
362 c1dd99d4 Michael Hanselmann
363 b78aa8c2 Iustin Pop
        # Wait for daemon to be started (or an error message to
364 b78aa8c2 Iustin Pop
        # arrive) and read up to 100 KB as an error message
365 c1dd99d4 Michael Hanselmann
        errormsg = RetryOnSignal(os.read, errpipe_read, 100 * 1024)
366 c1dd99d4 Michael Hanselmann
      finally:
367 71ab9dbe Michael Hanselmann
        CloseFdNoError(errpipe_read)
368 c1dd99d4 Michael Hanselmann
    finally:
369 71ab9dbe Michael Hanselmann
      CloseFdNoError(pidpipe_write)
370 c1dd99d4 Michael Hanselmann
371 c1dd99d4 Michael Hanselmann
    # Read up to 128 bytes for PID
372 c1dd99d4 Michael Hanselmann
    pidtext = RetryOnSignal(os.read, pidpipe_read, 128)
373 c1dd99d4 Michael Hanselmann
  finally:
374 71ab9dbe Michael Hanselmann
    CloseFdNoError(pidpipe_read)
375 c1dd99d4 Michael Hanselmann
376 c1dd99d4 Michael Hanselmann
  # Try to avoid zombies by waiting for child process
377 c1dd99d4 Michael Hanselmann
  try:
378 c1dd99d4 Michael Hanselmann
    os.waitpid(pid, 0)
379 c1dd99d4 Michael Hanselmann
  except OSError:
380 c1dd99d4 Michael Hanselmann
    pass
381 c1dd99d4 Michael Hanselmann
382 c1dd99d4 Michael Hanselmann
  if errormsg:
383 c1dd99d4 Michael Hanselmann
    raise errors.OpExecError("Error when starting daemon process: %r" %
384 c1dd99d4 Michael Hanselmann
                             errormsg)
385 c1dd99d4 Michael Hanselmann
386 c1dd99d4 Michael Hanselmann
  try:
387 c1dd99d4 Michael Hanselmann
    return int(pidtext)
388 c1dd99d4 Michael Hanselmann
  except (ValueError, TypeError), err:
389 c1dd99d4 Michael Hanselmann
    raise errors.OpExecError("Error while trying to parse PID %r: %s" %
390 c1dd99d4 Michael Hanselmann
                             (pidtext, err))
391 c1dd99d4 Michael Hanselmann
392 c1dd99d4 Michael Hanselmann
393 e0bb431e Michael Hanselmann
def _StartDaemonChild(errpipe_read, errpipe_write,
394 e0bb431e Michael Hanselmann
                      pidpipe_read, pidpipe_write,
395 e0bb431e Michael Hanselmann
                      args, env, cwd,
396 e0bb431e Michael Hanselmann
                      output, fd_output, pidfile):
397 c1dd99d4 Michael Hanselmann
  """Child process for starting daemon.
398 c1dd99d4 Michael Hanselmann

399 c1dd99d4 Michael Hanselmann
  """
400 c1dd99d4 Michael Hanselmann
  try:
401 c1dd99d4 Michael Hanselmann
    # Close parent's side
402 71ab9dbe Michael Hanselmann
    CloseFdNoError(errpipe_read)
403 71ab9dbe Michael Hanselmann
    CloseFdNoError(pidpipe_read)
404 c1dd99d4 Michael Hanselmann
405 c1dd99d4 Michael Hanselmann
    # First child process
406 0260032c Iustin Pop
    SetupDaemonEnv()
407 c1dd99d4 Michael Hanselmann
408 c1dd99d4 Michael Hanselmann
    # And fork for the second time
409 c1dd99d4 Michael Hanselmann
    pid = os.fork()
410 c1dd99d4 Michael Hanselmann
    if pid != 0:
411 c1dd99d4 Michael Hanselmann
      # Exit first child process
412 c1dd99d4 Michael Hanselmann
      os._exit(0) # pylint: disable-msg=W0212
413 c1dd99d4 Michael Hanselmann
414 0260032c Iustin Pop
    # Make sure pipe is closed on execv* (and thereby notifies
415 0260032c Iustin Pop
    # original process)
416 c1dd99d4 Michael Hanselmann
    SetCloseOnExecFlag(errpipe_write, True)
417 c1dd99d4 Michael Hanselmann
418 c1dd99d4 Michael Hanselmann
    # List of file descriptors to be left open
419 c1dd99d4 Michael Hanselmann
    noclose_fds = [errpipe_write]
420 c1dd99d4 Michael Hanselmann
421 c1dd99d4 Michael Hanselmann
    # Open PID file
422 c1dd99d4 Michael Hanselmann
    if pidfile:
423 5c4d37f9 Iustin Pop
      fd_pidfile = WritePidFile(pidfile)
424 c1dd99d4 Michael Hanselmann
425 c1dd99d4 Michael Hanselmann
      # Keeping the file open to hold the lock
426 c1dd99d4 Michael Hanselmann
      noclose_fds.append(fd_pidfile)
427 c1dd99d4 Michael Hanselmann
428 c1dd99d4 Michael Hanselmann
      SetCloseOnExecFlag(fd_pidfile, False)
429 c1dd99d4 Michael Hanselmann
    else:
430 c1dd99d4 Michael Hanselmann
      fd_pidfile = None
431 c1dd99d4 Michael Hanselmann
432 79634555 Iustin Pop
    SetupDaemonFDs(output, fd_output)
433 c1dd99d4 Michael Hanselmann
434 c1dd99d4 Michael Hanselmann
    # Send daemon PID to parent
435 c1dd99d4 Michael Hanselmann
    RetryOnSignal(os.write, pidpipe_write, str(os.getpid()))
436 c1dd99d4 Michael Hanselmann
437 c1dd99d4 Michael Hanselmann
    # Close all file descriptors except stdio and error message pipe
438 c1dd99d4 Michael Hanselmann
    CloseFDs(noclose_fds=noclose_fds)
439 c1dd99d4 Michael Hanselmann
440 c1dd99d4 Michael Hanselmann
    # Change working directory
441 c1dd99d4 Michael Hanselmann
    os.chdir(cwd)
442 c1dd99d4 Michael Hanselmann
443 c1dd99d4 Michael Hanselmann
    if env is None:
444 c1dd99d4 Michael Hanselmann
      os.execvp(args[0], args)
445 c1dd99d4 Michael Hanselmann
    else:
446 c1dd99d4 Michael Hanselmann
      os.execvpe(args[0], args, env)
447 c1dd99d4 Michael Hanselmann
  except: # pylint: disable-msg=W0702
448 c1dd99d4 Michael Hanselmann
    try:
449 c1dd99d4 Michael Hanselmann
      # Report errors to original process
450 ed3920e3 Iustin Pop
      WriteErrorToFD(errpipe_write, str(sys.exc_info()[1]))
451 c1dd99d4 Michael Hanselmann
    except: # pylint: disable-msg=W0702
452 c1dd99d4 Michael Hanselmann
      # Ignore errors in error handling
453 c1dd99d4 Michael Hanselmann
      pass
454 c1dd99d4 Michael Hanselmann
455 c1dd99d4 Michael Hanselmann
  os._exit(1) # pylint: disable-msg=W0212
456 c1dd99d4 Michael Hanselmann
457 c1dd99d4 Michael Hanselmann
458 ed3920e3 Iustin Pop
def WriteErrorToFD(fd, err):
459 ed3920e3 Iustin Pop
  """Possibly write an error message to a fd.
460 ed3920e3 Iustin Pop

461 ed3920e3 Iustin Pop
  @type fd: None or int (file descriptor)
462 ed3920e3 Iustin Pop
  @param fd: if not None, the error will be written to this fd
463 ed3920e3 Iustin Pop
  @param err: string, the error message
464 ed3920e3 Iustin Pop

465 ed3920e3 Iustin Pop
  """
466 ed3920e3 Iustin Pop
  if fd is None:
467 ed3920e3 Iustin Pop
    return
468 ed3920e3 Iustin Pop
469 ed3920e3 Iustin Pop
  if not err:
470 ed3920e3 Iustin Pop
    err = "<unknown error>"
471 ed3920e3 Iustin Pop
472 ed3920e3 Iustin Pop
  RetryOnSignal(os.write, fd, err)
473 ed3920e3 Iustin Pop
474 ed3920e3 Iustin Pop
475 c74cda62 René Nussbaumer
def _CheckIfAlive(child):
476 c74cda62 René Nussbaumer
  """Raises L{RetryAgain} if child is still alive.
477 c74cda62 René Nussbaumer

478 c74cda62 René Nussbaumer
  @raises RetryAgain: If child is still alive
479 c74cda62 René Nussbaumer

480 c74cda62 René Nussbaumer
  """
481 c74cda62 René Nussbaumer
  if child.poll() is None:
482 c74cda62 René Nussbaumer
    raise RetryAgain()
483 c74cda62 René Nussbaumer
484 c74cda62 René Nussbaumer
485 c74cda62 René Nussbaumer
def _WaitForProcess(child, timeout):
486 c74cda62 René Nussbaumer
  """Waits for the child to terminate or until we reach timeout.
487 c74cda62 René Nussbaumer

488 c74cda62 René Nussbaumer
  """
489 c74cda62 René Nussbaumer
  try:
490 c74cda62 René Nussbaumer
    Retry(_CheckIfAlive, (1.0, 1.2, 5.0), max(0, timeout), args=[child])
491 c74cda62 René Nussbaumer
  except RetryTimeout:
492 c74cda62 René Nussbaumer
    pass
493 c74cda62 René Nussbaumer
494 c74cda62 René Nussbaumer
495 c74cda62 René Nussbaumer
def _RunCmdPipe(cmd, env, via_shell, cwd, interactive, timeout,
496 c74cda62 René Nussbaumer
                _linger_timeout=constants.CHILD_LINGER_TIMEOUT):
497 36117c2b Iustin Pop
  """Run a command and return its output.
498 36117c2b Iustin Pop

499 36117c2b Iustin Pop
  @type  cmd: string or list
500 36117c2b Iustin Pop
  @param cmd: Command to run
501 36117c2b Iustin Pop
  @type env: dict
502 36117c2b Iustin Pop
  @param env: The environment to use
503 36117c2b Iustin Pop
  @type via_shell: bool
504 36117c2b Iustin Pop
  @param via_shell: if we should run via the shell
505 8797df43 Iustin Pop
  @type cwd: string
506 8797df43 Iustin Pop
  @param cwd: the working directory for the program
507 0963d545 René Nussbaumer
  @type interactive: boolean
508 0963d545 René Nussbaumer
  @param interactive: Run command interactive (without piping)
509 c74cda62 René Nussbaumer
  @type timeout: int
510 c74cda62 René Nussbaumer
  @param timeout: Timeout after the programm gets terminated
511 36117c2b Iustin Pop
  @rtype: tuple
512 36117c2b Iustin Pop
  @return: (out, err, status)
513 36117c2b Iustin Pop

514 36117c2b Iustin Pop
  """
515 9c233417 Iustin Pop
  poller = select.poll()
516 0963d545 René Nussbaumer
517 0963d545 René Nussbaumer
  stderr = subprocess.PIPE
518 0963d545 René Nussbaumer
  stdout = subprocess.PIPE
519 0963d545 René Nussbaumer
  stdin = subprocess.PIPE
520 0963d545 René Nussbaumer
521 0963d545 René Nussbaumer
  if interactive:
522 0963d545 René Nussbaumer
    stderr = stdout = stdin = None
523 0963d545 René Nussbaumer
524 36117c2b Iustin Pop
  child = subprocess.Popen(cmd, shell=via_shell,
525 0963d545 René Nussbaumer
                           stderr=stderr,
526 0963d545 René Nussbaumer
                           stdout=stdout,
527 0963d545 René Nussbaumer
                           stdin=stdin,
528 8797df43 Iustin Pop
                           close_fds=True, env=env,
529 8797df43 Iustin Pop
                           cwd=cwd)
530 113b55aa Iustin Pop
531 9c233417 Iustin Pop
  out = StringIO()
532 9c233417 Iustin Pop
  err = StringIO()
533 c74cda62 René Nussbaumer
534 c74cda62 René Nussbaumer
  linger_timeout = None
535 c74cda62 René Nussbaumer
536 c74cda62 René Nussbaumer
  if timeout is None:
537 c74cda62 René Nussbaumer
    poll_timeout = None
538 c74cda62 René Nussbaumer
  else:
539 c74cda62 René Nussbaumer
    poll_timeout = RunningTimeout(timeout, True).Remaining
540 c74cda62 René Nussbaumer
541 c74cda62 René Nussbaumer
  msg_timeout = ("Command %s (%d) run into execution timeout, terminating" %
542 c74cda62 René Nussbaumer
                 (cmd, child.pid))
543 c74cda62 René Nussbaumer
  msg_linger = ("Command %s (%d) run into linger timeout, killing" %
544 c74cda62 René Nussbaumer
                (cmd, child.pid))
545 c74cda62 René Nussbaumer
546 c74cda62 René Nussbaumer
  timeout_action = _TIMEOUT_NONE
547 c74cda62 René Nussbaumer
548 0963d545 René Nussbaumer
  if not interactive:
549 0963d545 René Nussbaumer
    child.stdin.close()
550 0963d545 René Nussbaumer
    poller.register(child.stdout, select.POLLIN)
551 0963d545 René Nussbaumer
    poller.register(child.stderr, select.POLLIN)
552 0963d545 René Nussbaumer
    fdmap = {
553 0963d545 René Nussbaumer
      child.stdout.fileno(): (out, child.stdout),
554 0963d545 René Nussbaumer
      child.stderr.fileno(): (err, child.stderr),
555 0963d545 René Nussbaumer
      }
556 0963d545 René Nussbaumer
    for fd in fdmap:
557 0963d545 René Nussbaumer
      SetNonblockFlag(fd, True)
558 0963d545 René Nussbaumer
559 0963d545 René Nussbaumer
    while fdmap:
560 c74cda62 René Nussbaumer
      if poll_timeout:
561 d05cf6fa Iustin Pop
        pt = poll_timeout() * 1000
562 d05cf6fa Iustin Pop
        if pt < 0:
563 c74cda62 René Nussbaumer
          if linger_timeout is None:
564 c74cda62 René Nussbaumer
            logging.warning(msg_timeout)
565 c74cda62 René Nussbaumer
            if child.poll() is None:
566 c74cda62 René Nussbaumer
              timeout_action = _TIMEOUT_TERM
567 c74cda62 René Nussbaumer
              IgnoreProcessNotFound(os.kill, child.pid, signal.SIGTERM)
568 c74cda62 René Nussbaumer
            linger_timeout = RunningTimeout(_linger_timeout, True).Remaining
569 d05cf6fa Iustin Pop
          pt = linger_timeout() * 1000
570 d05cf6fa Iustin Pop
          if pt < 0:
571 c74cda62 René Nussbaumer
            break
572 c74cda62 René Nussbaumer
      else:
573 c74cda62 René Nussbaumer
        pt = None
574 c74cda62 René Nussbaumer
575 c74cda62 René Nussbaumer
      pollresult = RetryOnSignal(poller.poll, pt)
576 0963d545 René Nussbaumer
577 0963d545 René Nussbaumer
      for fd, event in pollresult:
578 0963d545 René Nussbaumer
        if event & select.POLLIN or event & select.POLLPRI:
579 0963d545 René Nussbaumer
          data = fdmap[fd][1].read()
580 0963d545 René Nussbaumer
          # no data from read signifies EOF (the same as POLLHUP)
581 0963d545 René Nussbaumer
          if not data:
582 0963d545 René Nussbaumer
            poller.unregister(fd)
583 0963d545 René Nussbaumer
            del fdmap[fd]
584 0963d545 René Nussbaumer
            continue
585 0963d545 René Nussbaumer
          fdmap[fd][0].write(data)
586 0963d545 René Nussbaumer
        if (event & select.POLLNVAL or event & select.POLLHUP or
587 0963d545 René Nussbaumer
            event & select.POLLERR):
588 9c233417 Iustin Pop
          poller.unregister(fd)
589 9c233417 Iustin Pop
          del fdmap[fd]
590 9c233417 Iustin Pop
591 c74cda62 René Nussbaumer
  if timeout is not None:
592 c74cda62 René Nussbaumer
    assert callable(poll_timeout)
593 c74cda62 René Nussbaumer
594 c74cda62 René Nussbaumer
    # We have no I/O left but it might still run
595 c74cda62 René Nussbaumer
    if child.poll() is None:
596 c74cda62 René Nussbaumer
      _WaitForProcess(child, poll_timeout())
597 c74cda62 René Nussbaumer
598 c74cda62 René Nussbaumer
    # Terminate if still alive after timeout
599 c74cda62 René Nussbaumer
    if child.poll() is None:
600 c74cda62 René Nussbaumer
      if linger_timeout is None:
601 c74cda62 René Nussbaumer
        logging.warning(msg_timeout)
602 c74cda62 René Nussbaumer
        timeout_action = _TIMEOUT_TERM
603 c74cda62 René Nussbaumer
        IgnoreProcessNotFound(os.kill, child.pid, signal.SIGTERM)
604 c74cda62 René Nussbaumer
        lt = _linger_timeout
605 c74cda62 René Nussbaumer
      else:
606 c74cda62 René Nussbaumer
        lt = linger_timeout()
607 c74cda62 René Nussbaumer
      _WaitForProcess(child, lt)
608 c74cda62 René Nussbaumer
609 c74cda62 René Nussbaumer
    # Okay, still alive after timeout and linger timeout? Kill it!
610 c74cda62 René Nussbaumer
    if child.poll() is None:
611 c74cda62 René Nussbaumer
      timeout_action = _TIMEOUT_KILL
612 c74cda62 René Nussbaumer
      logging.warning(msg_linger)
613 c74cda62 René Nussbaumer
      IgnoreProcessNotFound(os.kill, child.pid, signal.SIGKILL)
614 c74cda62 René Nussbaumer
615 9c233417 Iustin Pop
  out = out.getvalue()
616 9c233417 Iustin Pop
  err = err.getvalue()
617 a8083063 Iustin Pop
618 a8083063 Iustin Pop
  status = child.wait()
619 c74cda62 René Nussbaumer
  return out, err, status, timeout_action
620 a8083063 Iustin Pop
621 36117c2b Iustin Pop
622 8797df43 Iustin Pop
def _RunCmdFile(cmd, env, via_shell, output, cwd):
623 36117c2b Iustin Pop
  """Run a command and save its output to a file.
624 36117c2b Iustin Pop

625 36117c2b Iustin Pop
  @type  cmd: string or list
626 36117c2b Iustin Pop
  @param cmd: Command to run
627 36117c2b Iustin Pop
  @type env: dict
628 36117c2b Iustin Pop
  @param env: The environment to use
629 36117c2b Iustin Pop
  @type via_shell: bool
630 36117c2b Iustin Pop
  @param via_shell: if we should run via the shell
631 36117c2b Iustin Pop
  @type output: str
632 36117c2b Iustin Pop
  @param output: the filename in which to save the output
633 8797df43 Iustin Pop
  @type cwd: string
634 8797df43 Iustin Pop
  @param cwd: the working directory for the program
635 36117c2b Iustin Pop
  @rtype: int
636 36117c2b Iustin Pop
  @return: the exit status
637 36117c2b Iustin Pop

638 36117c2b Iustin Pop
  """
639 36117c2b Iustin Pop
  fh = open(output, "a")
640 36117c2b Iustin Pop
  try:
641 36117c2b Iustin Pop
    child = subprocess.Popen(cmd, shell=via_shell,
642 36117c2b Iustin Pop
                             stderr=subprocess.STDOUT,
643 36117c2b Iustin Pop
                             stdout=fh,
644 36117c2b Iustin Pop
                             stdin=subprocess.PIPE,
645 8797df43 Iustin Pop
                             close_fds=True, env=env,
646 8797df43 Iustin Pop
                             cwd=cwd)
647 36117c2b Iustin Pop
648 36117c2b Iustin Pop
    child.stdin.close()
649 36117c2b Iustin Pop
    status = child.wait()
650 36117c2b Iustin Pop
  finally:
651 36117c2b Iustin Pop
    fh.close()
652 36117c2b Iustin Pop
  return status
653 a8083063 Iustin Pop
654 a8083063 Iustin Pop
655 6bb65e3a Guido Trotter
def RunParts(dir_name, env=None, reset_env=False):
656 6bb65e3a Guido Trotter
  """Run Scripts or programs in a directory
657 6bb65e3a Guido Trotter

658 6bb65e3a Guido Trotter
  @type dir_name: string
659 6bb65e3a Guido Trotter
  @param dir_name: absolute path to a directory
660 6bb65e3a Guido Trotter
  @type env: dict
661 6bb65e3a Guido Trotter
  @param env: The environment to use
662 6bb65e3a Guido Trotter
  @type reset_env: boolean
663 6bb65e3a Guido Trotter
  @param reset_env: whether to reset or keep the default os environment
664 6bb65e3a Guido Trotter
  @rtype: list of tuples
665 6bb65e3a Guido Trotter
  @return: list of (name, (one of RUNDIR_STATUS), RunResult)
666 6bb65e3a Guido Trotter

667 6bb65e3a Guido Trotter
  """
668 6bb65e3a Guido Trotter
  rr = []
669 6bb65e3a Guido Trotter
670 6bb65e3a Guido Trotter
  try:
671 6bb65e3a Guido Trotter
    dir_contents = ListVisibleFiles(dir_name)
672 6bb65e3a Guido Trotter
  except OSError, err:
673 6bb65e3a Guido Trotter
    logging.warning("RunParts: skipping %s (cannot list: %s)", dir_name, err)
674 6bb65e3a Guido Trotter
    return rr
675 6bb65e3a Guido Trotter
676 6bb65e3a Guido Trotter
  for relname in sorted(dir_contents):
677 c4feafe8 Iustin Pop
    fname = PathJoin(dir_name, relname)
678 6bb65e3a Guido Trotter
    if not (os.path.isfile(fname) and os.access(fname, os.X_OK) and
679 6bb65e3a Guido Trotter
            constants.EXT_PLUGIN_MASK.match(relname) is not None):
680 6bb65e3a Guido Trotter
      rr.append((relname, constants.RUNPARTS_SKIP, None))
681 6bb65e3a Guido Trotter
    else:
682 6bb65e3a Guido Trotter
      try:
683 6bb65e3a Guido Trotter
        result = RunCmd([fname], env=env, reset_env=reset_env)
684 6bb65e3a Guido Trotter
      except Exception, err: # pylint: disable-msg=W0703
685 6bb65e3a Guido Trotter
        rr.append((relname, constants.RUNPARTS_ERR, str(err)))
686 6bb65e3a Guido Trotter
      else:
687 6bb65e3a Guido Trotter
        rr.append((relname, constants.RUNPARTS_RUN, result))
688 6bb65e3a Guido Trotter
689 6bb65e3a Guido Trotter
  return rr
690 6bb65e3a Guido Trotter
691 6bb65e3a Guido Trotter
692 055f822b Michael Hanselmann
def ResetTempfileModule():
693 055f822b Michael Hanselmann
  """Resets the random name generator of the tempfile module.
694 055f822b Michael Hanselmann

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

701 055f822b Michael Hanselmann
  """
702 055f822b Michael Hanselmann
  # pylint: disable-msg=W0212
703 055f822b Michael Hanselmann
  if hasattr(tempfile, "_once_lock") and hasattr(tempfile, "_name_sequence"):
704 055f822b Michael Hanselmann
    tempfile._once_lock.acquire()
705 055f822b Michael Hanselmann
    try:
706 055f822b Michael Hanselmann
      # Reset random name generator
707 055f822b Michael Hanselmann
      tempfile._name_sequence = None
708 055f822b Michael Hanselmann
    finally:
709 055f822b Michael Hanselmann
      tempfile._once_lock.release()
710 055f822b Michael Hanselmann
  else:
711 055f822b Michael Hanselmann
    logging.critical("The tempfile module misses at least one of the"
712 055f822b Michael Hanselmann
                     " '_once_lock' and '_name_sequence' attributes")
713 055f822b Michael Hanselmann
714 055f822b Michael Hanselmann
715 a5728081 Guido Trotter
def ForceDictType(target, key_types, allowed_values=None):
716 a5728081 Guido Trotter
  """Force the values of a dict to have certain types.
717 a5728081 Guido Trotter

718 a5728081 Guido Trotter
  @type target: dict
719 a5728081 Guido Trotter
  @param target: the dict to update
720 a5728081 Guido Trotter
  @type key_types: dict
721 a5728081 Guido Trotter
  @param key_types: dict mapping target dict keys to types
722 a5728081 Guido Trotter
                    in constants.ENFORCEABLE_TYPES
723 a5728081 Guido Trotter
  @type allowed_values: list
724 a5728081 Guido Trotter
  @keyword allowed_values: list of specially allowed values
725 a5728081 Guido Trotter

726 a5728081 Guido Trotter
  """
727 a5728081 Guido Trotter
  if allowed_values is None:
728 a5728081 Guido Trotter
    allowed_values = []
729 a5728081 Guido Trotter
730 8b46606c Guido Trotter
  if not isinstance(target, dict):
731 8b46606c Guido Trotter
    msg = "Expected dictionary, got '%s'" % target
732 8b46606c Guido Trotter
    raise errors.TypeEnforcementError(msg)
733 8b46606c Guido Trotter
734 a5728081 Guido Trotter
  for key in target:
735 a5728081 Guido Trotter
    if key not in key_types:
736 a5728081 Guido Trotter
      msg = "Unknown key '%s'" % key
737 a5728081 Guido Trotter
      raise errors.TypeEnforcementError(msg)
738 a5728081 Guido Trotter
739 a5728081 Guido Trotter
    if target[key] in allowed_values:
740 a5728081 Guido Trotter
      continue
741 a5728081 Guido Trotter
742 29921401 Iustin Pop
    ktype = key_types[key]
743 29921401 Iustin Pop
    if ktype not in constants.ENFORCEABLE_TYPES:
744 29921401 Iustin Pop
      msg = "'%s' has non-enforceable type %s" % (key, ktype)
745 a5728081 Guido Trotter
      raise errors.ProgrammerError(msg)
746 a5728081 Guido Trotter
747 59525e1f Michael Hanselmann
    if ktype in (constants.VTYPE_STRING, constants.VTYPE_MAYBE_STRING):
748 59525e1f Michael Hanselmann
      if target[key] is None and ktype == constants.VTYPE_MAYBE_STRING:
749 59525e1f Michael Hanselmann
        pass
750 59525e1f Michael Hanselmann
      elif not isinstance(target[key], basestring):
751 a5728081 Guido Trotter
        if isinstance(target[key], bool) and not target[key]:
752 a5728081 Guido Trotter
          target[key] = ''
753 a5728081 Guido Trotter
        else:
754 a5728081 Guido Trotter
          msg = "'%s' (value %s) is not a valid string" % (key, target[key])
755 a5728081 Guido Trotter
          raise errors.TypeEnforcementError(msg)
756 29921401 Iustin Pop
    elif ktype == constants.VTYPE_BOOL:
757 a5728081 Guido Trotter
      if isinstance(target[key], basestring) and target[key]:
758 a5728081 Guido Trotter
        if target[key].lower() == constants.VALUE_FALSE:
759 a5728081 Guido Trotter
          target[key] = False
760 a5728081 Guido Trotter
        elif target[key].lower() == constants.VALUE_TRUE:
761 a5728081 Guido Trotter
          target[key] = True
762 a5728081 Guido Trotter
        else:
763 a5728081 Guido Trotter
          msg = "'%s' (value %s) is not a valid boolean" % (key, target[key])
764 a5728081 Guido Trotter
          raise errors.TypeEnforcementError(msg)
765 a5728081 Guido Trotter
      elif target[key]:
766 a5728081 Guido Trotter
        target[key] = True
767 a5728081 Guido Trotter
      else:
768 a5728081 Guido Trotter
        target[key] = False
769 29921401 Iustin Pop
    elif ktype == constants.VTYPE_SIZE:
770 a5728081 Guido Trotter
      try:
771 a5728081 Guido Trotter
        target[key] = ParseUnit(target[key])
772 a5728081 Guido Trotter
      except errors.UnitParseError, err:
773 a5728081 Guido Trotter
        msg = "'%s' (value %s) is not a valid size. error: %s" % \
774 a5728081 Guido Trotter
              (key, target[key], err)
775 a5728081 Guido Trotter
        raise errors.TypeEnforcementError(msg)
776 29921401 Iustin Pop
    elif ktype == constants.VTYPE_INT:
777 a5728081 Guido Trotter
      try:
778 a5728081 Guido Trotter
        target[key] = int(target[key])
779 a5728081 Guido Trotter
      except (ValueError, TypeError):
780 a5728081 Guido Trotter
        msg = "'%s' (value %s) is not a valid integer" % (key, target[key])
781 a5728081 Guido Trotter
        raise errors.TypeEnforcementError(msg)
782 a5728081 Guido Trotter
783 a5728081 Guido Trotter
784 a01b500b Michael Hanselmann
def _GetProcStatusPath(pid):
785 a01b500b Michael Hanselmann
  """Returns the path for a PID's proc status file.
786 a01b500b Michael Hanselmann

787 a01b500b Michael Hanselmann
  @type pid: int
788 a01b500b Michael Hanselmann
  @param pid: Process ID
789 a01b500b Michael Hanselmann
  @rtype: string
790 a01b500b Michael Hanselmann

791 a01b500b Michael Hanselmann
  """
792 a01b500b Michael Hanselmann
  return "/proc/%d/status" % pid
793 a01b500b Michael Hanselmann
794 a01b500b Michael Hanselmann
795 a8083063 Iustin Pop
def IsProcessAlive(pid):
796 a8083063 Iustin Pop
  """Check if a given pid exists on the system.
797 a8083063 Iustin Pop

798 44bf25ff Iustin Pop
  @note: zombie status is not handled, so zombie processes
799 44bf25ff Iustin Pop
      will be returned as alive
800 58885d79 Iustin Pop
  @type pid: int
801 58885d79 Iustin Pop
  @param pid: the process ID to check
802 58885d79 Iustin Pop
  @rtype: boolean
803 58885d79 Iustin Pop
  @return: True if the process exists
804 a8083063 Iustin Pop

805 a8083063 Iustin Pop
  """
806 5ef5ea45 Guido Trotter
  def _TryStat(name):
807 5ef5ea45 Guido Trotter
    try:
808 5ef5ea45 Guido Trotter
      os.stat(name)
809 5ef5ea45 Guido Trotter
      return True
810 5ef5ea45 Guido Trotter
    except EnvironmentError, err:
811 5ef5ea45 Guido Trotter
      if err.errno in (errno.ENOENT, errno.ENOTDIR):
812 5ef5ea45 Guido Trotter
        return False
813 5ef5ea45 Guido Trotter
      elif err.errno == errno.EINVAL:
814 5ef5ea45 Guido Trotter
        raise RetryAgain(err)
815 5ef5ea45 Guido Trotter
      raise
816 5ef5ea45 Guido Trotter
817 5ef5ea45 Guido Trotter
  assert isinstance(pid, int), "pid must be an integer"
818 d9f311d7 Iustin Pop
  if pid <= 0:
819 d9f311d7 Iustin Pop
    return False
820 d9f311d7 Iustin Pop
821 5ef5ea45 Guido Trotter
  # /proc in a multiprocessor environment can have strange behaviors.
822 5ef5ea45 Guido Trotter
  # Retry the os.stat a few times until we get a good result.
823 a8083063 Iustin Pop
  try:
824 a01b500b Michael Hanselmann
    return Retry(_TryStat, (0.01, 1.5, 0.1), 0.5,
825 a01b500b Michael Hanselmann
                 args=[_GetProcStatusPath(pid)])
826 5ef5ea45 Guido Trotter
  except RetryTimeout, err:
827 5ef5ea45 Guido Trotter
    err.RaiseInner()
828 a8083063 Iustin Pop
829 a8083063 Iustin Pop
830 a01b500b Michael Hanselmann
def _ParseSigsetT(sigset):
831 a01b500b Michael Hanselmann
  """Parse a rendered sigset_t value.
832 a01b500b Michael Hanselmann

833 a01b500b Michael Hanselmann
  This is the opposite of the Linux kernel's fs/proc/array.c:render_sigset_t
834 a01b500b Michael Hanselmann
  function.
835 a01b500b Michael Hanselmann

836 a01b500b Michael Hanselmann
  @type sigset: string
837 a01b500b Michael Hanselmann
  @param sigset: Rendered signal set from /proc/$pid/status
838 a01b500b Michael Hanselmann
  @rtype: set
839 a01b500b Michael Hanselmann
  @return: Set of all enabled signal numbers
840 a01b500b Michael Hanselmann

841 a01b500b Michael Hanselmann
  """
842 a01b500b Michael Hanselmann
  result = set()
843 a01b500b Michael Hanselmann
844 a01b500b Michael Hanselmann
  signum = 0
845 a01b500b Michael Hanselmann
  for ch in reversed(sigset):
846 a01b500b Michael Hanselmann
    chv = int(ch, 16)
847 a01b500b Michael Hanselmann
848 a01b500b Michael Hanselmann
    # The following could be done in a loop, but it's easier to read and
849 a01b500b Michael Hanselmann
    # understand in the unrolled form
850 a01b500b Michael Hanselmann
    if chv & 1:
851 a01b500b Michael Hanselmann
      result.add(signum + 1)
852 a01b500b Michael Hanselmann
    if chv & 2:
853 a01b500b Michael Hanselmann
      result.add(signum + 2)
854 a01b500b Michael Hanselmann
    if chv & 4:
855 a01b500b Michael Hanselmann
      result.add(signum + 3)
856 a01b500b Michael Hanselmann
    if chv & 8:
857 a01b500b Michael Hanselmann
      result.add(signum + 4)
858 a01b500b Michael Hanselmann
859 a01b500b Michael Hanselmann
    signum += 4
860 a01b500b Michael Hanselmann
861 a01b500b Michael Hanselmann
  return result
862 a01b500b Michael Hanselmann
863 a01b500b Michael Hanselmann
864 a01b500b Michael Hanselmann
def _GetProcStatusField(pstatus, field):
865 a01b500b Michael Hanselmann
  """Retrieves a field from the contents of a proc status file.
866 a01b500b Michael Hanselmann

867 a01b500b Michael Hanselmann
  @type pstatus: string
868 a01b500b Michael Hanselmann
  @param pstatus: Contents of /proc/$pid/status
869 a01b500b Michael Hanselmann
  @type field: string
870 a01b500b Michael Hanselmann
  @param field: Name of field whose value should be returned
871 a01b500b Michael Hanselmann
  @rtype: string
872 a01b500b Michael Hanselmann

873 a01b500b Michael Hanselmann
  """
874 a01b500b Michael Hanselmann
  for line in pstatus.splitlines():
875 a01b500b Michael Hanselmann
    parts = line.split(":", 1)
876 a01b500b Michael Hanselmann
877 a01b500b Michael Hanselmann
    if len(parts) < 2 or parts[0] != field:
878 a01b500b Michael Hanselmann
      continue
879 a01b500b Michael Hanselmann
880 a01b500b Michael Hanselmann
    return parts[1].strip()
881 a01b500b Michael Hanselmann
882 a01b500b Michael Hanselmann
  return None
883 a01b500b Michael Hanselmann
884 a01b500b Michael Hanselmann
885 a01b500b Michael Hanselmann
def IsProcessHandlingSignal(pid, signum, status_path=None):
886 a01b500b Michael Hanselmann
  """Checks whether a process is handling a signal.
887 a01b500b Michael Hanselmann

888 a01b500b Michael Hanselmann
  @type pid: int
889 a01b500b Michael Hanselmann
  @param pid: Process ID
890 a01b500b Michael Hanselmann
  @type signum: int
891 a01b500b Michael Hanselmann
  @param signum: Signal number
892 a01b500b Michael Hanselmann
  @rtype: bool
893 a01b500b Michael Hanselmann

894 a01b500b Michael Hanselmann
  """
895 a01b500b Michael Hanselmann
  if status_path is None:
896 a01b500b Michael Hanselmann
    status_path = _GetProcStatusPath(pid)
897 a01b500b Michael Hanselmann
898 a01b500b Michael Hanselmann
  try:
899 a01b500b Michael Hanselmann
    proc_status = ReadFile(status_path)
900 a01b500b Michael Hanselmann
  except EnvironmentError, err:
901 a01b500b Michael Hanselmann
    # In at least one case, reading /proc/$pid/status failed with ESRCH.
902 a01b500b Michael Hanselmann
    if err.errno in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL, errno.ESRCH):
903 a01b500b Michael Hanselmann
      return False
904 a01b500b Michael Hanselmann
    raise
905 a01b500b Michael Hanselmann
906 a01b500b Michael Hanselmann
  sigcgt = _GetProcStatusField(proc_status, "SigCgt")
907 a01b500b Michael Hanselmann
  if sigcgt is None:
908 a01b500b Michael Hanselmann
    raise RuntimeError("%s is missing 'SigCgt' field" % status_path)
909 a01b500b Michael Hanselmann
910 a01b500b Michael Hanselmann
  # Now check whether signal is handled
911 a01b500b Michael Hanselmann
  return signum in _ParseSigsetT(sigcgt)
912 a01b500b Michael Hanselmann
913 a01b500b Michael Hanselmann
914 28f34048 Michael Hanselmann
def ValidateServiceName(name):
915 28f34048 Michael Hanselmann
  """Validate the given service name.
916 28f34048 Michael Hanselmann

917 28f34048 Michael Hanselmann
  @type name: number or string
918 28f34048 Michael Hanselmann
  @param name: Service name or port specification
919 28f34048 Michael Hanselmann

920 28f34048 Michael Hanselmann
  """
921 28f34048 Michael Hanselmann
  try:
922 28f34048 Michael Hanselmann
    numport = int(name)
923 28f34048 Michael Hanselmann
  except (ValueError, TypeError):
924 28f34048 Michael Hanselmann
    # Non-numeric service name
925 28f34048 Michael Hanselmann
    valid = _VALID_SERVICE_NAME_RE.match(name)
926 28f34048 Michael Hanselmann
  else:
927 28f34048 Michael Hanselmann
    # Numeric port (protocols other than TCP or UDP might need adjustments
928 28f34048 Michael Hanselmann
    # here)
929 28f34048 Michael Hanselmann
    valid = (numport >= 0 and numport < (1 << 16))
930 28f34048 Michael Hanselmann
931 28f34048 Michael Hanselmann
  if not valid:
932 28f34048 Michael Hanselmann
    raise errors.OpPrereqError("Invalid service name '%s'" % name,
933 28f34048 Michael Hanselmann
                               errors.ECODE_INVAL)
934 28f34048 Michael Hanselmann
935 28f34048 Michael Hanselmann
  return name
936 28f34048 Michael Hanselmann
937 28f34048 Michael Hanselmann
938 a8083063 Iustin Pop
def ListVolumeGroups():
939 a8083063 Iustin Pop
  """List volume groups and their size
940 a8083063 Iustin Pop

941 58885d79 Iustin Pop
  @rtype: dict
942 58885d79 Iustin Pop
  @return:
943 58885d79 Iustin Pop
       Dictionary with keys volume name and values
944 58885d79 Iustin Pop
       the size of the volume
945 a8083063 Iustin Pop

946 a8083063 Iustin Pop
  """
947 a8083063 Iustin Pop
  command = "vgs --noheadings --units m --nosuffix -o name,size"
948 a8083063 Iustin Pop
  result = RunCmd(command)
949 a8083063 Iustin Pop
  retval = {}
950 a8083063 Iustin Pop
  if result.failed:
951 a8083063 Iustin Pop
    return retval
952 a8083063 Iustin Pop
953 a8083063 Iustin Pop
  for line in result.stdout.splitlines():
954 a8083063 Iustin Pop
    try:
955 a8083063 Iustin Pop
      name, size = line.split()
956 a8083063 Iustin Pop
      size = int(float(size))
957 a8083063 Iustin Pop
    except (IndexError, ValueError), err:
958 bb698c1f Iustin Pop
      logging.error("Invalid output from vgs (%s): %s", err, line)
959 a8083063 Iustin Pop
      continue
960 a8083063 Iustin Pop
961 a8083063 Iustin Pop
    retval[name] = size
962 a8083063 Iustin Pop
963 a8083063 Iustin Pop
  return retval
964 a8083063 Iustin Pop
965 a8083063 Iustin Pop
966 a8083063 Iustin Pop
def BridgeExists(bridge):
967 a8083063 Iustin Pop
  """Check whether the given bridge exists in the system
968 a8083063 Iustin Pop

969 58885d79 Iustin Pop
  @type bridge: str
970 58885d79 Iustin Pop
  @param bridge: the bridge name to check
971 58885d79 Iustin Pop
  @rtype: boolean
972 58885d79 Iustin Pop
  @return: True if it does
973 a8083063 Iustin Pop

974 a8083063 Iustin Pop
  """
975 a8083063 Iustin Pop
  return os.path.isdir("/sys/class/net/%s/bridge" % bridge)
976 a8083063 Iustin Pop
977 a8083063 Iustin Pop
978 a8083063 Iustin Pop
def TryConvert(fn, val):
979 a8083063 Iustin Pop
  """Try to convert a value ignoring errors.
980 a8083063 Iustin Pop

981 58885d79 Iustin Pop
  This function tries to apply function I{fn} to I{val}. If no
982 58885d79 Iustin Pop
  C{ValueError} or C{TypeError} exceptions are raised, it will return
983 58885d79 Iustin Pop
  the result, else it will return the original value. Any other
984 58885d79 Iustin Pop
  exceptions are propagated to the caller.
985 58885d79 Iustin Pop

986 58885d79 Iustin Pop
  @type fn: callable
987 58885d79 Iustin Pop
  @param fn: function to apply to the value
988 58885d79 Iustin Pop
  @param val: the value to be converted
989 58885d79 Iustin Pop
  @return: The converted value if the conversion was successful,
990 58885d79 Iustin Pop
      otherwise the original value.
991 a8083063 Iustin Pop

992 a8083063 Iustin Pop
  """
993 a8083063 Iustin Pop
  try:
994 a8083063 Iustin Pop
    nv = fn(val)
995 7c4d6c7b Michael Hanselmann
  except (ValueError, TypeError):
996 a8083063 Iustin Pop
    nv = val
997 a8083063 Iustin Pop
  return nv
998 a8083063 Iustin Pop
999 a8083063 Iustin Pop
1000 a8083063 Iustin Pop
def IsValidShellParam(word):
1001 a8083063 Iustin Pop
  """Verifies is the given word is safe from the shell's p.o.v.
1002 a8083063 Iustin Pop

1003 a8083063 Iustin Pop
  This means that we can pass this to a command via the shell and be
1004 a8083063 Iustin Pop
  sure that it doesn't alter the command line and is passed as such to
1005 a8083063 Iustin Pop
  the actual command.
1006 a8083063 Iustin Pop

1007 a8083063 Iustin Pop
  Note that we are overly restrictive here, in order to be on the safe
1008 a8083063 Iustin Pop
  side.
1009 a8083063 Iustin Pop

1010 58885d79 Iustin Pop
  @type word: str
1011 58885d79 Iustin Pop
  @param word: the word to check
1012 58885d79 Iustin Pop
  @rtype: boolean
1013 58885d79 Iustin Pop
  @return: True if the word is 'safe'
1014 58885d79 Iustin Pop

1015 a8083063 Iustin Pop
  """
1016 0b5303da Iustin Pop
  return bool(_SHELLPARAM_REGEX.match(word))
1017 a8083063 Iustin Pop
1018 a8083063 Iustin Pop
1019 a8083063 Iustin Pop
def BuildShellCmd(template, *args):
1020 a8083063 Iustin Pop
  """Build a safe shell command line from the given arguments.
1021 a8083063 Iustin Pop

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

1027 58885d79 Iustin Pop
  @type template: str
1028 58885d79 Iustin Pop
  @param template: the string holding the template for the
1029 58885d79 Iustin Pop
      string formatting
1030 58885d79 Iustin Pop
  @rtype: str
1031 58885d79 Iustin Pop
  @return: the expanded command line
1032 58885d79 Iustin Pop

1033 a8083063 Iustin Pop
  """
1034 a8083063 Iustin Pop
  for word in args:
1035 a8083063 Iustin Pop
    if not IsValidShellParam(word):
1036 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Shell argument '%s' contains"
1037 3ecf6786 Iustin Pop
                                   " invalid characters" % word)
1038 a8083063 Iustin Pop
  return template % args
1039 a8083063 Iustin Pop
1040 a8083063 Iustin Pop
1041 31155d60 Balazs Lecz
def ParseCpuMask(cpu_mask):
1042 31155d60 Balazs Lecz
  """Parse a CPU mask definition and return the list of CPU IDs.
1043 31155d60 Balazs Lecz

1044 31155d60 Balazs Lecz
  CPU mask format: comma-separated list of CPU IDs
1045 31155d60 Balazs Lecz
  or dash-separated ID ranges
1046 31155d60 Balazs Lecz
  Example: "0-2,5" -> "0,1,2,5"
1047 31155d60 Balazs Lecz

1048 31155d60 Balazs Lecz
  @type cpu_mask: str
1049 31155d60 Balazs Lecz
  @param cpu_mask: CPU mask definition
1050 31155d60 Balazs Lecz
  @rtype: list of int
1051 31155d60 Balazs Lecz
  @return: list of CPU IDs
1052 31155d60 Balazs Lecz

1053 31155d60 Balazs Lecz
  """
1054 31155d60 Balazs Lecz
  if not cpu_mask:
1055 31155d60 Balazs Lecz
    return []
1056 31155d60 Balazs Lecz
  cpu_list = []
1057 31155d60 Balazs Lecz
  for range_def in cpu_mask.split(","):
1058 31155d60 Balazs Lecz
    boundaries = range_def.split("-")
1059 31155d60 Balazs Lecz
    n_elements = len(boundaries)
1060 31155d60 Balazs Lecz
    if n_elements > 2:
1061 31155d60 Balazs Lecz
      raise errors.ParseError("Invalid CPU ID range definition"
1062 31155d60 Balazs Lecz
                              " (only one hyphen allowed): %s" % range_def)
1063 31155d60 Balazs Lecz
    try:
1064 31155d60 Balazs Lecz
      lower = int(boundaries[0])
1065 31155d60 Balazs Lecz
    except (ValueError, TypeError), err:
1066 31155d60 Balazs Lecz
      raise errors.ParseError("Invalid CPU ID value for lower boundary of"
1067 31155d60 Balazs Lecz
                              " CPU ID range: %s" % str(err))
1068 31155d60 Balazs Lecz
    try:
1069 31155d60 Balazs Lecz
      higher = int(boundaries[-1])
1070 31155d60 Balazs Lecz
    except (ValueError, TypeError), err:
1071 31155d60 Balazs Lecz
      raise errors.ParseError("Invalid CPU ID value for higher boundary of"
1072 31155d60 Balazs Lecz
                              " CPU ID range: %s" % str(err))
1073 31155d60 Balazs Lecz
    if lower > higher:
1074 31155d60 Balazs Lecz
      raise errors.ParseError("Invalid CPU ID range definition"
1075 31155d60 Balazs Lecz
                              " (%d > %d): %s" % (lower, higher, range_def))
1076 31155d60 Balazs Lecz
    cpu_list.extend(range(lower, higher + 1))
1077 31155d60 Balazs Lecz
  return cpu_list
1078 31155d60 Balazs Lecz
1079 31155d60 Balazs Lecz
1080 257f4c0a Iustin Pop
def GetHomeDir(user, default=None):
1081 257f4c0a Iustin Pop
  """Try to get the homedir of the given user.
1082 257f4c0a Iustin Pop

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

1087 2f8b60b3 Iustin Pop
  """
1088 2f8b60b3 Iustin Pop
  try:
1089 257f4c0a Iustin Pop
    if isinstance(user, basestring):
1090 257f4c0a Iustin Pop
      result = pwd.getpwnam(user)
1091 257f4c0a Iustin Pop
    elif isinstance(user, (int, long)):
1092 257f4c0a Iustin Pop
      result = pwd.getpwuid(user)
1093 257f4c0a Iustin Pop
    else:
1094 257f4c0a Iustin Pop
      raise errors.ProgrammerError("Invalid type passed to GetHomeDir (%s)" %
1095 257f4c0a Iustin Pop
                                   type(user))
1096 2f8b60b3 Iustin Pop
  except KeyError:
1097 2f8b60b3 Iustin Pop
    return default
1098 2f8b60b3 Iustin Pop
  return result.pw_dir
1099 59072e7e Michael Hanselmann
1100 59072e7e Michael Hanselmann
1101 24818e8f Michael Hanselmann
def NewUUID():
1102 59072e7e Michael Hanselmann
  """Returns a random UUID.
1103 59072e7e Michael Hanselmann

1104 58885d79 Iustin Pop
  @note: This is a Linux-specific method as it uses the /proc
1105 58885d79 Iustin Pop
      filesystem.
1106 58885d79 Iustin Pop
  @rtype: str
1107 58885d79 Iustin Pop

1108 59072e7e Michael Hanselmann
  """
1109 13998ef2 Michael Hanselmann
  return ReadFile(_RANDOM_UUID_FILE, size=128).rstrip("\n")
1110 087b34fe Iustin Pop
1111 087b34fe Iustin Pop
1112 7b4126b7 Iustin Pop
def FirstFree(seq, base=0):
1113 7b4126b7 Iustin Pop
  """Returns the first non-existing integer from seq.
1114 7b4126b7 Iustin Pop

1115 7b4126b7 Iustin Pop
  The seq argument should be a sorted list of positive integers. The
1116 7b4126b7 Iustin Pop
  first time the index of an element is smaller than the element
1117 7b4126b7 Iustin Pop
  value, the index will be returned.
1118 7b4126b7 Iustin Pop

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

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

1124 58885d79 Iustin Pop
  @type seq: sequence
1125 58885d79 Iustin Pop
  @param seq: the sequence to be analyzed.
1126 58885d79 Iustin Pop
  @type base: int
1127 58885d79 Iustin Pop
  @param base: use this value as the base index of the sequence
1128 58885d79 Iustin Pop
  @rtype: int
1129 58885d79 Iustin Pop
  @return: the first non-used index in the sequence
1130 7b4126b7 Iustin Pop

1131 7b4126b7 Iustin Pop
  """
1132 7b4126b7 Iustin Pop
  for idx, elem in enumerate(seq):
1133 7b4126b7 Iustin Pop
    assert elem >= base, "Passed element is higher than base offset"
1134 7b4126b7 Iustin Pop
    if elem > idx + base:
1135 7b4126b7 Iustin Pop
      # idx is not used
1136 7b4126b7 Iustin Pop
      return idx + base
1137 7b4126b7 Iustin Pop
  return None
1138 7b4126b7 Iustin Pop
1139 7b4126b7 Iustin Pop
1140 dfdc4060 Guido Trotter
def SingleWaitForFdCondition(fdobj, event, timeout):
1141 dcd511c8 Guido Trotter
  """Waits for a condition to occur on the socket.
1142 dcd511c8 Guido Trotter

1143 dfdc4060 Guido Trotter
  Immediately returns at the first interruption.
1144 dfdc4060 Guido Trotter

1145 dfdc4060 Guido Trotter
  @type fdobj: integer or object supporting a fileno() method
1146 dfdc4060 Guido Trotter
  @param fdobj: entity to wait for events on
1147 dfdc4060 Guido Trotter
  @type event: integer
1148 dcd511c8 Guido Trotter
  @param event: ORed condition (see select module)
1149 dcd511c8 Guido Trotter
  @type timeout: float or None
1150 dcd511c8 Guido Trotter
  @param timeout: Timeout in seconds
1151 dcd511c8 Guido Trotter
  @rtype: int or None
1152 dcd511c8 Guido Trotter
  @return: None for timeout, otherwise occured conditions
1153 dcd511c8 Guido Trotter

1154 dcd511c8 Guido Trotter
  """
1155 dcd511c8 Guido Trotter
  check = (event | select.POLLPRI |
1156 dcd511c8 Guido Trotter
           select.POLLNVAL | select.POLLHUP | select.POLLERR)
1157 dcd511c8 Guido Trotter
1158 dcd511c8 Guido Trotter
  if timeout is not None:
1159 dcd511c8 Guido Trotter
    # Poller object expects milliseconds
1160 dcd511c8 Guido Trotter
    timeout *= 1000
1161 dcd511c8 Guido Trotter
1162 dcd511c8 Guido Trotter
  poller = select.poll()
1163 dfdc4060 Guido Trotter
  poller.register(fdobj, event)
1164 dcd511c8 Guido Trotter
  try:
1165 dfdc4060 Guido Trotter
    # TODO: If the main thread receives a signal and we have no timeout, we
1166 dfdc4060 Guido Trotter
    # could wait forever. This should check a global "quit" flag or something
1167 dfdc4060 Guido Trotter
    # every so often.
1168 dfdc4060 Guido Trotter
    io_events = poller.poll(timeout)
1169 dfdc4060 Guido Trotter
  except select.error, err:
1170 dfdc4060 Guido Trotter
    if err[0] != errno.EINTR:
1171 dfdc4060 Guido Trotter
      raise
1172 dfdc4060 Guido Trotter
    io_events = []
1173 dfdc4060 Guido Trotter
  if io_events and io_events[0][1] & check:
1174 dfdc4060 Guido Trotter
    return io_events[0][1]
1175 dfdc4060 Guido Trotter
  else:
1176 dfdc4060 Guido Trotter
    return None
1177 dfdc4060 Guido Trotter
1178 dfdc4060 Guido Trotter
1179 dfdc4060 Guido Trotter
class FdConditionWaiterHelper(object):
1180 dfdc4060 Guido Trotter
  """Retry helper for WaitForFdCondition.
1181 dfdc4060 Guido Trotter

1182 dfdc4060 Guido Trotter
  This class contains the retried and wait functions that make sure
1183 dfdc4060 Guido Trotter
  WaitForFdCondition can continue waiting until the timeout is actually
1184 dfdc4060 Guido Trotter
  expired.
1185 dfdc4060 Guido Trotter

1186 dfdc4060 Guido Trotter
  """
1187 dfdc4060 Guido Trotter
1188 dfdc4060 Guido Trotter
  def __init__(self, timeout):
1189 dfdc4060 Guido Trotter
    self.timeout = timeout
1190 dfdc4060 Guido Trotter
1191 dfdc4060 Guido Trotter
  def Poll(self, fdobj, event):
1192 dfdc4060 Guido Trotter
    result = SingleWaitForFdCondition(fdobj, event, self.timeout)
1193 dfdc4060 Guido Trotter
    if result is None:
1194 dfdc4060 Guido Trotter
      raise RetryAgain()
1195 dfdc4060 Guido Trotter
    else:
1196 dfdc4060 Guido Trotter
      return result
1197 dfdc4060 Guido Trotter
1198 dfdc4060 Guido Trotter
  def UpdateTimeout(self, timeout):
1199 dfdc4060 Guido Trotter
    self.timeout = timeout
1200 dfdc4060 Guido Trotter
1201 dfdc4060 Guido Trotter
1202 dfdc4060 Guido Trotter
def WaitForFdCondition(fdobj, event, timeout):
1203 dfdc4060 Guido Trotter
  """Waits for a condition to occur on the socket.
1204 dfdc4060 Guido Trotter

1205 dfdc4060 Guido Trotter
  Retries until the timeout is expired, even if interrupted.
1206 dfdc4060 Guido Trotter

1207 dfdc4060 Guido Trotter
  @type fdobj: integer or object supporting a fileno() method
1208 dfdc4060 Guido Trotter
  @param fdobj: entity to wait for events on
1209 dfdc4060 Guido Trotter
  @type event: integer
1210 dfdc4060 Guido Trotter
  @param event: ORed condition (see select module)
1211 dfdc4060 Guido Trotter
  @type timeout: float or None
1212 dfdc4060 Guido Trotter
  @param timeout: Timeout in seconds
1213 dfdc4060 Guido Trotter
  @rtype: int or None
1214 dfdc4060 Guido Trotter
  @return: None for timeout, otherwise occured conditions
1215 dfdc4060 Guido Trotter

1216 dfdc4060 Guido Trotter
  """
1217 dfdc4060 Guido Trotter
  if timeout is not None:
1218 dfdc4060 Guido Trotter
    retrywaiter = FdConditionWaiterHelper(timeout)
1219 1b429e2a Iustin Pop
    try:
1220 1b429e2a Iustin Pop
      result = Retry(retrywaiter.Poll, RETRY_REMAINING_TIME, timeout,
1221 1b429e2a Iustin Pop
                     args=(fdobj, event), wait_fn=retrywaiter.UpdateTimeout)
1222 1b429e2a Iustin Pop
    except RetryTimeout:
1223 1b429e2a Iustin Pop
      result = None
1224 dfdc4060 Guido Trotter
  else:
1225 dfdc4060 Guido Trotter
    result = None
1226 dfdc4060 Guido Trotter
    while result is None:
1227 dfdc4060 Guido Trotter
      result = SingleWaitForFdCondition(fdobj, event, timeout)
1228 dfdc4060 Guido Trotter
  return result
1229 2de64672 Iustin Pop
1230 2de64672 Iustin Pop
1231 7d88772a Iustin Pop
def CloseFDs(noclose_fds=None):
1232 7d88772a Iustin Pop
  """Close file descriptors.
1233 7d88772a Iustin Pop

1234 7d88772a Iustin Pop
  This closes all file descriptors above 2 (i.e. except
1235 7d88772a Iustin Pop
  stdin/out/err).
1236 8f765069 Iustin Pop

1237 58885d79 Iustin Pop
  @type noclose_fds: list or None
1238 58885d79 Iustin Pop
  @param noclose_fds: if given, it denotes a list of file descriptor
1239 58885d79 Iustin Pop
      that should not be closed
1240 58885d79 Iustin Pop

1241 8f765069 Iustin Pop
  """
1242 8f765069 Iustin Pop
  # Default maximum for the number of available file descriptors.
1243 8f765069 Iustin Pop
  if 'SC_OPEN_MAX' in os.sysconf_names:
1244 8f765069 Iustin Pop
    try:
1245 8f765069 Iustin Pop
      MAXFD = os.sysconf('SC_OPEN_MAX')
1246 8f765069 Iustin Pop
      if MAXFD < 0:
1247 8f765069 Iustin Pop
        MAXFD = 1024
1248 8f765069 Iustin Pop
    except OSError:
1249 8f765069 Iustin Pop
      MAXFD = 1024
1250 8f765069 Iustin Pop
  else:
1251 8f765069 Iustin Pop
    MAXFD = 1024
1252 7d88772a Iustin Pop
  maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
1253 7d88772a Iustin Pop
  if (maxfd == resource.RLIM_INFINITY):
1254 7d88772a Iustin Pop
    maxfd = MAXFD
1255 7d88772a Iustin Pop
1256 7d88772a Iustin Pop
  # Iterate through and close all file descriptors (except the standard ones)
1257 7d88772a Iustin Pop
  for fd in range(3, maxfd):
1258 7d88772a Iustin Pop
    if noclose_fds and fd in noclose_fds:
1259 7d88772a Iustin Pop
      continue
1260 71ab9dbe Michael Hanselmann
    CloseFdNoError(fd)
1261 7d88772a Iustin Pop
1262 7d88772a Iustin Pop
1263 0070a462 René Nussbaumer
def Daemonize(logfile):
1264 7d88772a Iustin Pop
  """Daemonize the current process.
1265 7d88772a Iustin Pop

1266 7d88772a Iustin Pop
  This detaches the current process from the controlling terminal and
1267 7d88772a Iustin Pop
  runs it in the background as a daemon.
1268 7d88772a Iustin Pop

1269 7d88772a Iustin Pop
  @type logfile: str
1270 7d88772a Iustin Pop
  @param logfile: the logfile to which we should redirect stdout/stderr
1271 7d88772a Iustin Pop
  @rtype: int
1272 5fcc718f Iustin Pop
  @return: the value zero
1273 7d88772a Iustin Pop

1274 7d88772a Iustin Pop
  """
1275 7260cfbe Iustin Pop
  # pylint: disable-msg=W0212
1276 7260cfbe Iustin Pop
  # yes, we really want os._exit
1277 8f765069 Iustin Pop
1278 b78aa8c2 Iustin Pop
  # TODO: do another attempt to merge Daemonize and StartDaemon, or at
1279 b78aa8c2 Iustin Pop
  # least abstract the pipe functionality between them
1280 b78aa8c2 Iustin Pop
1281 b78aa8c2 Iustin Pop
  # Create pipe for sending error messages
1282 b78aa8c2 Iustin Pop
  (rpipe, wpipe) = os.pipe()
1283 b78aa8c2 Iustin Pop
1284 8f765069 Iustin Pop
  # this might fail
1285 8f765069 Iustin Pop
  pid = os.fork()
1286 8f765069 Iustin Pop
  if (pid == 0):  # The first child.
1287 0260032c Iustin Pop
    SetupDaemonEnv()
1288 0260032c Iustin Pop
1289 8f765069 Iustin Pop
    # this might fail
1290 8f765069 Iustin Pop
    pid = os.fork() # Fork a second child.
1291 8f765069 Iustin Pop
    if (pid == 0):  # The second child.
1292 71ab9dbe Michael Hanselmann
      CloseFdNoError(rpipe)
1293 8f765069 Iustin Pop
    else:
1294 8f765069 Iustin Pop
      # exit() or _exit()?  See below.
1295 8f765069 Iustin Pop
      os._exit(0) # Exit parent (the first child) of the second child.
1296 8f765069 Iustin Pop
  else:
1297 71ab9dbe Michael Hanselmann
    CloseFdNoError(wpipe)
1298 b78aa8c2 Iustin Pop
    # Wait for daemon to be started (or an error message to
1299 b78aa8c2 Iustin Pop
    # arrive) and read up to 100 KB as an error message
1300 b78aa8c2 Iustin Pop
    errormsg = RetryOnSignal(os.read, rpipe, 100 * 1024)
1301 b78aa8c2 Iustin Pop
    if errormsg:
1302 b78aa8c2 Iustin Pop
      sys.stderr.write("Error when starting daemon process: %r\n" % errormsg)
1303 b78aa8c2 Iustin Pop
      rcode = 1
1304 b78aa8c2 Iustin Pop
    else:
1305 b78aa8c2 Iustin Pop
      rcode = 0
1306 b78aa8c2 Iustin Pop
    os._exit(rcode) # Exit parent of the first child.
1307 8f765069 Iustin Pop
1308 79634555 Iustin Pop
  SetupDaemonFDs(logfile, None)
1309 b78aa8c2 Iustin Pop
  return wpipe
1310 57c177af Iustin Pop
1311 57c177af Iustin Pop
1312 2826b361 Guido Trotter
def EnsureDaemon(name):
1313 2826b361 Guido Trotter
  """Check for and start daemon if not alive.
1314 2826b361 Guido Trotter

1315 2826b361 Guido Trotter
  """
1316 2826b361 Guido Trotter
  result = RunCmd([constants.DAEMON_UTIL, "check-and-start", name])
1317 2826b361 Guido Trotter
  if result.failed:
1318 2826b361 Guido Trotter
    logging.error("Can't start daemon '%s', failure %s, output: %s",
1319 2826b361 Guido Trotter
                  name, result.fail_reason, result.output)
1320 2826b361 Guido Trotter
    return False
1321 2826b361 Guido Trotter
1322 2826b361 Guido Trotter
  return True
1323 b330ac0b Guido Trotter
1324 b330ac0b Guido Trotter
1325 db147305 Tom Limoncelli
def StopDaemon(name):
1326 db147305 Tom Limoncelli
  """Stop daemon
1327 db147305 Tom Limoncelli

1328 db147305 Tom Limoncelli
  """
1329 db147305 Tom Limoncelli
  result = RunCmd([constants.DAEMON_UTIL, "stop", name])
1330 db147305 Tom Limoncelli
  if result.failed:
1331 db147305 Tom Limoncelli
    logging.error("Can't stop daemon '%s', failure %s, output: %s",
1332 db147305 Tom Limoncelli
                  name, result.fail_reason, result.output)
1333 db147305 Tom Limoncelli
    return False
1334 db147305 Tom Limoncelli
1335 db147305 Tom Limoncelli
  return True
1336 db147305 Tom Limoncelli
1337 db147305 Tom Limoncelli
1338 ff5251bc Iustin Pop
def KillProcess(pid, signal_=signal.SIGTERM, timeout=30,
1339 ff5251bc Iustin Pop
                waitpid=False):
1340 b2a1f511 Iustin Pop
  """Kill a process given by its pid.
1341 b2a1f511 Iustin Pop

1342 b2a1f511 Iustin Pop
  @type pid: int
1343 b2a1f511 Iustin Pop
  @param pid: The PID to terminate.
1344 38206f3c Iustin Pop
  @type signal_: int
1345 38206f3c Iustin Pop
  @param signal_: The signal to send, by default SIGTERM
1346 b2a1f511 Iustin Pop
  @type timeout: int
1347 b2a1f511 Iustin Pop
  @param timeout: The timeout after which, if the process is still alive,
1348 b2a1f511 Iustin Pop
                  a SIGKILL will be sent. If not positive, no such checking
1349 b2a1f511 Iustin Pop
                  will be done
1350 ff5251bc Iustin Pop
  @type waitpid: boolean
1351 ff5251bc Iustin Pop
  @param waitpid: If true, we should waitpid on this process after
1352 ff5251bc Iustin Pop
      sending signals, since it's our own child and otherwise it
1353 ff5251bc Iustin Pop
      would remain as zombie
1354 b2a1f511 Iustin Pop

1355 b2a1f511 Iustin Pop
  """
1356 ff5251bc Iustin Pop
  def _helper(pid, signal_, wait):
1357 ff5251bc Iustin Pop
    """Simple helper to encapsulate the kill/waitpid sequence"""
1358 560cbec1 Michael Hanselmann
    if IgnoreProcessNotFound(os.kill, pid, signal_) and wait:
1359 ff5251bc Iustin Pop
      try:
1360 ff5251bc Iustin Pop
        os.waitpid(pid, os.WNOHANG)
1361 ff5251bc Iustin Pop
      except OSError:
1362 ff5251bc Iustin Pop
        pass
1363 ff5251bc Iustin Pop
1364 b2a1f511 Iustin Pop
  if pid <= 0:
1365 b2a1f511 Iustin Pop
    # kill with pid=0 == suicide
1366 b2a1f511 Iustin Pop
    raise errors.ProgrammerError("Invalid pid given '%s'" % pid)
1367 b2a1f511 Iustin Pop
1368 b2a1f511 Iustin Pop
  if not IsProcessAlive(pid):
1369 b2a1f511 Iustin Pop
    return
1370 31892b4c Michael Hanselmann
1371 ff5251bc Iustin Pop
  _helper(pid, signal_, waitpid)
1372 31892b4c Michael Hanselmann
1373 b2a1f511 Iustin Pop
  if timeout <= 0:
1374 b2a1f511 Iustin Pop
    return
1375 7167159a Michael Hanselmann
1376 31892b4c Michael Hanselmann
  def _CheckProcess():
1377 31892b4c Michael Hanselmann
    if not IsProcessAlive(pid):
1378 31892b4c Michael Hanselmann
      return
1379 31892b4c Michael Hanselmann
1380 7167159a Michael Hanselmann
    try:
1381 7167159a Michael Hanselmann
      (result_pid, _) = os.waitpid(pid, os.WNOHANG)
1382 7167159a Michael Hanselmann
    except OSError:
1383 31892b4c Michael Hanselmann
      raise RetryAgain()
1384 31892b4c Michael Hanselmann
1385 31892b4c Michael Hanselmann
    if result_pid > 0:
1386 31892b4c Michael Hanselmann
      return
1387 31892b4c Michael Hanselmann
1388 31892b4c Michael Hanselmann
    raise RetryAgain()
1389 31892b4c Michael Hanselmann
1390 31892b4c Michael Hanselmann
  try:
1391 31892b4c Michael Hanselmann
    # Wait up to $timeout seconds
1392 31892b4c Michael Hanselmann
    Retry(_CheckProcess, (0.01, 1.5, 0.1), timeout)
1393 31892b4c Michael Hanselmann
  except RetryTimeout:
1394 31892b4c Michael Hanselmann
    pass
1395 7167159a Michael Hanselmann
1396 b2a1f511 Iustin Pop
  if IsProcessAlive(pid):
1397 7167159a Michael Hanselmann
    # Kill process if it's still alive
1398 e1bd0072 Iustin Pop
    _helper(pid, signal.SIGKILL, waitpid)
1399 b2a1f511 Iustin Pop
1400 b2a1f511 Iustin Pop
1401 8d1a2a64 Michael Hanselmann
def CheckVolumeGroupSize(vglist, vgname, minsize):
1402 8d1a2a64 Michael Hanselmann
  """Checks if the volume group list is valid.
1403 8d1a2a64 Michael Hanselmann

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

1407 58885d79 Iustin Pop
  @type vglist: dict
1408 58885d79 Iustin Pop
  @param vglist: dictionary of volume group names and their size
1409 58885d79 Iustin Pop
  @type vgname: str
1410 58885d79 Iustin Pop
  @param vgname: the volume group we should check
1411 58885d79 Iustin Pop
  @type minsize: int
1412 58885d79 Iustin Pop
  @param minsize: the minimum size we accept
1413 58885d79 Iustin Pop
  @rtype: None or str
1414 58885d79 Iustin Pop
  @return: None for success, otherwise the error message
1415 8d1a2a64 Michael Hanselmann

1416 8d1a2a64 Michael Hanselmann
  """
1417 8d1a2a64 Michael Hanselmann
  vgsize = vglist.get(vgname, None)
1418 8d1a2a64 Michael Hanselmann
  if vgsize is None:
1419 8d1a2a64 Michael Hanselmann
    return "volume group '%s' missing" % vgname
1420 8d1a2a64 Michael Hanselmann
  elif vgsize < minsize:
1421 8d1a2a64 Michael Hanselmann
    return ("volume group '%s' too small (%s MiB required, %d MiB found)" %
1422 8d1a2a64 Michael Hanselmann
            (vgname, minsize, vgsize))
1423 8d1a2a64 Michael Hanselmann
  return None
1424 7996a135 Iustin Pop
1425 7996a135 Iustin Pop
1426 45bc5e4a Michael Hanselmann
def SplitTime(value):
1427 739be818 Michael Hanselmann
  """Splits time as floating point number into a tuple.
1428 739be818 Michael Hanselmann

1429 45bc5e4a Michael Hanselmann
  @param value: Time in seconds
1430 45bc5e4a Michael Hanselmann
  @type value: int or float
1431 45bc5e4a Michael Hanselmann
  @return: Tuple containing (seconds, microseconds)
1432 739be818 Michael Hanselmann

1433 739be818 Michael Hanselmann
  """
1434 45bc5e4a Michael Hanselmann
  (seconds, microseconds) = divmod(int(value * 1000000), 1000000)
1435 45bc5e4a Michael Hanselmann
1436 45bc5e4a Michael Hanselmann
  assert 0 <= seconds, \
1437 45bc5e4a Michael Hanselmann
    "Seconds must be larger than or equal to 0, but are %s" % seconds
1438 45bc5e4a Michael Hanselmann
  assert 0 <= microseconds <= 999999, \
1439 45bc5e4a Michael Hanselmann
    "Microseconds must be 0-999999, but are %s" % microseconds
1440 45bc5e4a Michael Hanselmann
1441 45bc5e4a Michael Hanselmann
  return (int(seconds), int(microseconds))
1442 739be818 Michael Hanselmann
1443 739be818 Michael Hanselmann
1444 739be818 Michael Hanselmann
def MergeTime(timetuple):
1445 739be818 Michael Hanselmann
  """Merges a tuple into time as a floating point number.
1446 739be818 Michael Hanselmann

1447 45bc5e4a Michael Hanselmann
  @param timetuple: Time as tuple, (seconds, microseconds)
1448 739be818 Michael Hanselmann
  @type timetuple: tuple
1449 739be818 Michael Hanselmann
  @return: Time as a floating point number expressed in seconds
1450 739be818 Michael Hanselmann

1451 739be818 Michael Hanselmann
  """
1452 45bc5e4a Michael Hanselmann
  (seconds, microseconds) = timetuple
1453 739be818 Michael Hanselmann
1454 45bc5e4a Michael Hanselmann
  assert 0 <= seconds, \
1455 45bc5e4a Michael Hanselmann
    "Seconds must be larger than or equal to 0, but are %s" % seconds
1456 45bc5e4a Michael Hanselmann
  assert 0 <= microseconds <= 999999, \
1457 45bc5e4a Michael Hanselmann
    "Microseconds must be 0-999999, but are %s" % microseconds
1458 739be818 Michael Hanselmann
1459 45bc5e4a Michael Hanselmann
  return float(seconds) + (float(microseconds) * 0.000001)
1460 739be818 Michael Hanselmann
1461 739be818 Michael Hanselmann
1462 691c81b7 Michael Hanselmann
def FindMatch(data, name):
1463 691c81b7 Michael Hanselmann
  """Tries to find an item in a dictionary matching a name.
1464 691c81b7 Michael Hanselmann

1465 691c81b7 Michael Hanselmann
  Callers have to ensure the data names aren't contradictory (e.g. a regexp
1466 691c81b7 Michael Hanselmann
  that matches a string). If the name isn't a direct key, all regular
1467 691c81b7 Michael Hanselmann
  expression objects in the dictionary are matched against it.
1468 691c81b7 Michael Hanselmann

1469 691c81b7 Michael Hanselmann
  @type data: dict
1470 691c81b7 Michael Hanselmann
  @param data: Dictionary containing data
1471 691c81b7 Michael Hanselmann
  @type name: string
1472 691c81b7 Michael Hanselmann
  @param name: Name to look for
1473 691c81b7 Michael Hanselmann
  @rtype: tuple; (value in dictionary, matched groups as list)
1474 691c81b7 Michael Hanselmann

1475 691c81b7 Michael Hanselmann
  """
1476 691c81b7 Michael Hanselmann
  if name in data:
1477 691c81b7 Michael Hanselmann
    return (data[name], [])
1478 691c81b7 Michael Hanselmann
1479 691c81b7 Michael Hanselmann
  for key, value in data.items():
1480 691c81b7 Michael Hanselmann
    # Regex objects
1481 691c81b7 Michael Hanselmann
    if hasattr(key, "match"):
1482 691c81b7 Michael Hanselmann
      m = key.match(name)
1483 691c81b7 Michael Hanselmann
      if m:
1484 691c81b7 Michael Hanselmann
        return (value, list(m.groups()))
1485 691c81b7 Michael Hanselmann
1486 691c81b7 Michael Hanselmann
  return None
1487 691c81b7 Michael Hanselmann
1488 691c81b7 Michael Hanselmann
1489 1b045f5d Balazs Lecz
def GetMounts(filename=constants.PROC_MOUNTS):
1490 1b045f5d Balazs Lecz
  """Returns the list of mounted filesystems.
1491 1b045f5d Balazs Lecz

1492 1b045f5d Balazs Lecz
  This function is Linux-specific.
1493 1b045f5d Balazs Lecz

1494 1b045f5d Balazs Lecz
  @param filename: path of mounts file (/proc/mounts by default)
1495 1b045f5d Balazs Lecz
  @rtype: list of tuples
1496 1b045f5d Balazs Lecz
  @return: list of mount entries (device, mountpoint, fstype, options)
1497 1b045f5d Balazs Lecz

1498 1b045f5d Balazs Lecz
  """
1499 1b045f5d Balazs Lecz
  # TODO(iustin): investigate non-Linux options (e.g. via mount output)
1500 1b045f5d Balazs Lecz
  data = []
1501 1b045f5d Balazs Lecz
  mountlines = ReadFile(filename).splitlines()
1502 1b045f5d Balazs Lecz
  for line in mountlines:
1503 1b045f5d Balazs Lecz
    device, mountpoint, fstype, options, _ = line.split(None, 4)
1504 1b045f5d Balazs Lecz
    data.append((device, mountpoint, fstype, options))
1505 1b045f5d Balazs Lecz
1506 1b045f5d Balazs Lecz
  return data
1507 1b045f5d Balazs Lecz
1508 1b045f5d Balazs Lecz
1509 bdefe5dd Michael Hanselmann
def RunInSeparateProcess(fn, *args):
1510 eb58f7bd Michael Hanselmann
  """Runs a function in a separate process.
1511 eb58f7bd Michael Hanselmann

1512 eb58f7bd Michael Hanselmann
  Note: Only boolean return values are supported.
1513 eb58f7bd Michael Hanselmann

1514 eb58f7bd Michael Hanselmann
  @type fn: callable
1515 eb58f7bd Michael Hanselmann
  @param fn: Function to be called
1516 bdefe5dd Michael Hanselmann
  @rtype: bool
1517 bdefe5dd Michael Hanselmann
  @return: Function's result
1518 eb58f7bd Michael Hanselmann

1519 eb58f7bd Michael Hanselmann
  """
1520 eb58f7bd Michael Hanselmann
  pid = os.fork()
1521 eb58f7bd Michael Hanselmann
  if pid == 0:
1522 eb58f7bd Michael Hanselmann
    # Child process
1523 eb58f7bd Michael Hanselmann
    try:
1524 82869978 Michael Hanselmann
      # In case the function uses temporary files
1525 82869978 Michael Hanselmann
      ResetTempfileModule()
1526 82869978 Michael Hanselmann
1527 eb58f7bd Michael Hanselmann
      # Call function
1528 bdefe5dd Michael Hanselmann
      result = int(bool(fn(*args)))
1529 eb58f7bd Michael Hanselmann
      assert result in (0, 1)
1530 eb58f7bd Michael Hanselmann
    except: # pylint: disable-msg=W0702
1531 eb58f7bd Michael Hanselmann
      logging.exception("Error while calling function in separate process")
1532 eb58f7bd Michael Hanselmann
      # 0 and 1 are reserved for the return value
1533 eb58f7bd Michael Hanselmann
      result = 33
1534 eb58f7bd Michael Hanselmann
1535 eb58f7bd Michael Hanselmann
    os._exit(result) # pylint: disable-msg=W0212
1536 eb58f7bd Michael Hanselmann
1537 eb58f7bd Michael Hanselmann
  # Parent process
1538 eb58f7bd Michael Hanselmann
1539 eb58f7bd Michael Hanselmann
  # Avoid zombies and check exit code
1540 eb58f7bd Michael Hanselmann
  (_, status) = os.waitpid(pid, 0)
1541 eb58f7bd Michael Hanselmann
1542 eb58f7bd Michael Hanselmann
  if os.WIFSIGNALED(status):
1543 eb58f7bd Michael Hanselmann
    exitcode = None
1544 eb58f7bd Michael Hanselmann
    signum = os.WTERMSIG(status)
1545 eb58f7bd Michael Hanselmann
  else:
1546 eb58f7bd Michael Hanselmann
    exitcode = os.WEXITSTATUS(status)
1547 eb58f7bd Michael Hanselmann
    signum = None
1548 eb58f7bd Michael Hanselmann
1549 eb58f7bd Michael Hanselmann
  if not (exitcode in (0, 1) and signum is None):
1550 eb58f7bd Michael Hanselmann
    raise errors.GenericError("Child program failed (code=%s, signal=%s)" %
1551 eb58f7bd Michael Hanselmann
                              (exitcode, signum))
1552 eb58f7bd Michael Hanselmann
1553 eb58f7bd Michael Hanselmann
  return bool(exitcode)
1554 eb58f7bd Michael Hanselmann
1555 eb58f7bd Michael Hanselmann
1556 451575de Guido Trotter
def SignalHandled(signums):
1557 451575de Guido Trotter
  """Signal Handled decoration.
1558 451575de Guido Trotter

1559 451575de Guido Trotter
  This special decorator installs a signal handler and then calls the target
1560 451575de Guido Trotter
  function. The function must accept a 'signal_handlers' keyword argument,
1561 451575de Guido Trotter
  which will contain a dict indexed by signal number, with SignalHandler
1562 451575de Guido Trotter
  objects as values.
1563 451575de Guido Trotter

1564 451575de Guido Trotter
  The decorator can be safely stacked with iself, to handle multiple signals
1565 451575de Guido Trotter
  with different handlers.
1566 451575de Guido Trotter

1567 451575de Guido Trotter
  @type signums: list
1568 451575de Guido Trotter
  @param signums: signals to intercept
1569 451575de Guido Trotter

1570 451575de Guido Trotter
  """
1571 451575de Guido Trotter
  def wrap(fn):
1572 451575de Guido Trotter
    def sig_function(*args, **kwargs):
1573 451575de Guido Trotter
      assert 'signal_handlers' not in kwargs or \
1574 451575de Guido Trotter
             kwargs['signal_handlers'] is None or \
1575 451575de Guido Trotter
             isinstance(kwargs['signal_handlers'], dict), \
1576 451575de Guido Trotter
             "Wrong signal_handlers parameter in original function call"
1577 451575de Guido Trotter
      if 'signal_handlers' in kwargs and kwargs['signal_handlers'] is not None:
1578 451575de Guido Trotter
        signal_handlers = kwargs['signal_handlers']
1579 451575de Guido Trotter
      else:
1580 451575de Guido Trotter
        signal_handlers = {}
1581 451575de Guido Trotter
        kwargs['signal_handlers'] = signal_handlers
1582 451575de Guido Trotter
      sighandler = SignalHandler(signums)
1583 451575de Guido Trotter
      try:
1584 451575de Guido Trotter
        for sig in signums:
1585 451575de Guido Trotter
          signal_handlers[sig] = sighandler
1586 451575de Guido Trotter
        return fn(*args, **kwargs)
1587 451575de Guido Trotter
      finally:
1588 451575de Guido Trotter
        sighandler.Reset()
1589 451575de Guido Trotter
    return sig_function
1590 451575de Guido Trotter
  return wrap
1591 451575de Guido Trotter
1592 451575de Guido Trotter
1593 b9768937 Michael Hanselmann
class SignalWakeupFd(object):
1594 b9768937 Michael Hanselmann
  try:
1595 b9768937 Michael Hanselmann
    # This is only supported in Python 2.5 and above (some distributions
1596 b9768937 Michael Hanselmann
    # backported it to Python 2.4)
1597 b9768937 Michael Hanselmann
    _set_wakeup_fd_fn = signal.set_wakeup_fd
1598 b9768937 Michael Hanselmann
  except AttributeError:
1599 b9768937 Michael Hanselmann
    # Not supported
1600 b9768937 Michael Hanselmann
    def _SetWakeupFd(self, _): # pylint: disable-msg=R0201
1601 b9768937 Michael Hanselmann
      return -1
1602 b9768937 Michael Hanselmann
  else:
1603 b9768937 Michael Hanselmann
    def _SetWakeupFd(self, fd):
1604 b9768937 Michael Hanselmann
      return self._set_wakeup_fd_fn(fd)
1605 b9768937 Michael Hanselmann
1606 b9768937 Michael Hanselmann
  def __init__(self):
1607 b9768937 Michael Hanselmann
    """Initializes this class.
1608 b9768937 Michael Hanselmann

1609 b9768937 Michael Hanselmann
    """
1610 b9768937 Michael Hanselmann
    (read_fd, write_fd) = os.pipe()
1611 b9768937 Michael Hanselmann
1612 b9768937 Michael Hanselmann
    # Once these succeeded, the file descriptors will be closed automatically.
1613 b9768937 Michael Hanselmann
    # Buffer size 0 is important, otherwise .read() with a specified length
1614 b9768937 Michael Hanselmann
    # might buffer data and the file descriptors won't be marked readable.
1615 b9768937 Michael Hanselmann
    self._read_fh = os.fdopen(read_fd, "r", 0)
1616 b9768937 Michael Hanselmann
    self._write_fh = os.fdopen(write_fd, "w", 0)
1617 b9768937 Michael Hanselmann
1618 b9768937 Michael Hanselmann
    self._previous = self._SetWakeupFd(self._write_fh.fileno())
1619 b9768937 Michael Hanselmann
1620 b9768937 Michael Hanselmann
    # Utility functions
1621 b9768937 Michael Hanselmann
    self.fileno = self._read_fh.fileno
1622 b9768937 Michael Hanselmann
    self.read = self._read_fh.read
1623 b9768937 Michael Hanselmann
1624 b9768937 Michael Hanselmann
  def Reset(self):
1625 b9768937 Michael Hanselmann
    """Restores the previous wakeup file descriptor.
1626 b9768937 Michael Hanselmann

1627 b9768937 Michael Hanselmann
    """
1628 b9768937 Michael Hanselmann
    if hasattr(self, "_previous") and self._previous is not None:
1629 b9768937 Michael Hanselmann
      self._SetWakeupFd(self._previous)
1630 b9768937 Michael Hanselmann
      self._previous = None
1631 b9768937 Michael Hanselmann
1632 b9768937 Michael Hanselmann
  def Notify(self):
1633 b9768937 Michael Hanselmann
    """Notifies the wakeup file descriptor.
1634 b9768937 Michael Hanselmann

1635 b9768937 Michael Hanselmann
    """
1636 b9768937 Michael Hanselmann
    self._write_fh.write("\0")
1637 b9768937 Michael Hanselmann
1638 b9768937 Michael Hanselmann
  def __del__(self):
1639 b9768937 Michael Hanselmann
    """Called before object deletion.
1640 b9768937 Michael Hanselmann

1641 b9768937 Michael Hanselmann
    """
1642 b9768937 Michael Hanselmann
    self.Reset()
1643 b9768937 Michael Hanselmann
1644 b9768937 Michael Hanselmann
1645 de499029 Michael Hanselmann
class SignalHandler(object):
1646 de499029 Michael Hanselmann
  """Generic signal handler class.
1647 de499029 Michael Hanselmann

1648 58885d79 Iustin Pop
  It automatically restores the original handler when deconstructed or
1649 58885d79 Iustin Pop
  when L{Reset} is called. You can either pass your own handler
1650 58885d79 Iustin Pop
  function in or query the L{called} attribute to detect whether the
1651 58885d79 Iustin Pop
  signal was sent.
1652 58885d79 Iustin Pop

1653 58885d79 Iustin Pop
  @type signum: list
1654 58885d79 Iustin Pop
  @ivar signum: the signals we handle
1655 58885d79 Iustin Pop
  @type called: boolean
1656 58885d79 Iustin Pop
  @ivar called: tracks whether any of the signals have been raised
1657 de499029 Michael Hanselmann

1658 de499029 Michael Hanselmann
  """
1659 b9768937 Michael Hanselmann
  def __init__(self, signum, handler_fn=None, wakeup=None):
1660 de499029 Michael Hanselmann
    """Constructs a new SignalHandler instance.
1661 de499029 Michael Hanselmann

1662 58885d79 Iustin Pop
    @type signum: int or list of ints
1663 de499029 Michael Hanselmann
    @param signum: Single signal number or set of signal numbers
1664 92b61ec7 Michael Hanselmann
    @type handler_fn: callable
1665 92b61ec7 Michael Hanselmann
    @param handler_fn: Signal handling function
1666 de499029 Michael Hanselmann

1667 de499029 Michael Hanselmann
    """
1668 92b61ec7 Michael Hanselmann
    assert handler_fn is None or callable(handler_fn)
1669 92b61ec7 Michael Hanselmann
1670 6c52849e Guido Trotter
    self.signum = set(signum)
1671 de499029 Michael Hanselmann
    self.called = False
1672 de499029 Michael Hanselmann
1673 92b61ec7 Michael Hanselmann
    self._handler_fn = handler_fn
1674 b9768937 Michael Hanselmann
    self._wakeup = wakeup
1675 92b61ec7 Michael Hanselmann
1676 de499029 Michael Hanselmann
    self._previous = {}
1677 de499029 Michael Hanselmann
    try:
1678 de499029 Michael Hanselmann
      for signum in self.signum:
1679 de499029 Michael Hanselmann
        # Setup handler
1680 de499029 Michael Hanselmann
        prev_handler = signal.signal(signum, self._HandleSignal)
1681 de499029 Michael Hanselmann
        try:
1682 de499029 Michael Hanselmann
          self._previous[signum] = prev_handler
1683 de499029 Michael Hanselmann
        except:
1684 de499029 Michael Hanselmann
          # Restore previous handler
1685 de499029 Michael Hanselmann
          signal.signal(signum, prev_handler)
1686 de499029 Michael Hanselmann
          raise
1687 de499029 Michael Hanselmann
    except:
1688 de499029 Michael Hanselmann
      # Reset all handlers
1689 de499029 Michael Hanselmann
      self.Reset()
1690 de499029 Michael Hanselmann
      # Here we have a race condition: a handler may have already been called,
1691 de499029 Michael Hanselmann
      # but there's not much we can do about it at this point.
1692 de499029 Michael Hanselmann
      raise
1693 de499029 Michael Hanselmann
1694 de499029 Michael Hanselmann
  def __del__(self):
1695 de499029 Michael Hanselmann
    self.Reset()
1696 de499029 Michael Hanselmann
1697 de499029 Michael Hanselmann
  def Reset(self):
1698 de499029 Michael Hanselmann
    """Restore previous handler.
1699 de499029 Michael Hanselmann

1700 58885d79 Iustin Pop
    This will reset all the signals to their previous handlers.
1701 58885d79 Iustin Pop

1702 de499029 Michael Hanselmann
    """
1703 de499029 Michael Hanselmann
    for signum, prev_handler in self._previous.items():
1704 de499029 Michael Hanselmann
      signal.signal(signum, prev_handler)
1705 de499029 Michael Hanselmann
      # If successful, remove from dict
1706 de499029 Michael Hanselmann
      del self._previous[signum]
1707 de499029 Michael Hanselmann
1708 de499029 Michael Hanselmann
  def Clear(self):
1709 58885d79 Iustin Pop
    """Unsets the L{called} flag.
1710 de499029 Michael Hanselmann

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

1713 de499029 Michael Hanselmann
    """
1714 de499029 Michael Hanselmann
    self.called = False
1715 de499029 Michael Hanselmann
1716 92b61ec7 Michael Hanselmann
  def _HandleSignal(self, signum, frame):
1717 de499029 Michael Hanselmann
    """Actual signal handling function.
1718 de499029 Michael Hanselmann

1719 de499029 Michael Hanselmann
    """
1720 de499029 Michael Hanselmann
    # This is not nice and not absolutely atomic, but it appears to be the only
1721 de499029 Michael Hanselmann
    # solution in Python -- there are no atomic types.
1722 de499029 Michael Hanselmann
    self.called = True
1723 a2d2e1a7 Iustin Pop
1724 b9768937 Michael Hanselmann
    if self._wakeup:
1725 b9768937 Michael Hanselmann
      # Notify whoever is interested in signals
1726 b9768937 Michael Hanselmann
      self._wakeup.Notify()
1727 b9768937 Michael Hanselmann
1728 92b61ec7 Michael Hanselmann
    if self._handler_fn:
1729 92b61ec7 Michael Hanselmann
      self._handler_fn(signum, frame)
1730 92b61ec7 Michael Hanselmann
1731 a2d2e1a7 Iustin Pop
1732 a2d2e1a7 Iustin Pop
class FieldSet(object):
1733 a2d2e1a7 Iustin Pop
  """A simple field set.
1734 a2d2e1a7 Iustin Pop

1735 a2d2e1a7 Iustin Pop
  Among the features are:
1736 a2d2e1a7 Iustin Pop
    - checking if a string is among a list of static string or regex objects
1737 a2d2e1a7 Iustin Pop
    - checking if a whole list of string matches
1738 a2d2e1a7 Iustin Pop
    - returning the matching groups from a regex match
1739 a2d2e1a7 Iustin Pop

1740 a2d2e1a7 Iustin Pop
  Internally, all fields are held as regular expression objects.
1741 a2d2e1a7 Iustin Pop

1742 a2d2e1a7 Iustin Pop
  """
1743 a2d2e1a7 Iustin Pop
  def __init__(self, *items):
1744 a2d2e1a7 Iustin Pop
    self.items = [re.compile("^%s$" % value) for value in items]
1745 a2d2e1a7 Iustin Pop
1746 a2d2e1a7 Iustin Pop
  def Extend(self, other_set):
1747 a2d2e1a7 Iustin Pop
    """Extend the field set with the items from another one"""
1748 a2d2e1a7 Iustin Pop
    self.items.extend(other_set.items)
1749 a2d2e1a7 Iustin Pop
1750 a2d2e1a7 Iustin Pop
  def Matches(self, field):
1751 a2d2e1a7 Iustin Pop
    """Checks if a field matches the current set
1752 a2d2e1a7 Iustin Pop

1753 a2d2e1a7 Iustin Pop
    @type field: str
1754 a2d2e1a7 Iustin Pop
    @param field: the string to match
1755 6c881c52 Iustin Pop
    @return: either None or a regular expression match object
1756 a2d2e1a7 Iustin Pop

1757 a2d2e1a7 Iustin Pop
    """
1758 a2d2e1a7 Iustin Pop
    for m in itertools.ifilter(None, (val.match(field) for val in self.items)):
1759 a2d2e1a7 Iustin Pop
      return m
1760 6c881c52 Iustin Pop
    return None
1761 a2d2e1a7 Iustin Pop
1762 a2d2e1a7 Iustin Pop
  def NonMatching(self, items):
1763 a2d2e1a7 Iustin Pop
    """Returns the list of fields not matching the current set
1764 a2d2e1a7 Iustin Pop

1765 a2d2e1a7 Iustin Pop
    @type items: list
1766 a2d2e1a7 Iustin Pop
    @param items: the list of fields to check
1767 a2d2e1a7 Iustin Pop
    @rtype: list
1768 a2d2e1a7 Iustin Pop
    @return: list of non-matching fields
1769 a2d2e1a7 Iustin Pop

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