Statistics
| Branch: | Tag: | Revision:

root / lib / utils / __init__.py @ 44c9b4fe

History | View | Annotate | Download (47.9 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 a5728081 Guido Trotter
def ForceDictType(target, key_types, allowed_values=None):
693 a5728081 Guido Trotter
  """Force the values of a dict to have certain types.
694 a5728081 Guido Trotter

695 a5728081 Guido Trotter
  @type target: dict
696 a5728081 Guido Trotter
  @param target: the dict to update
697 a5728081 Guido Trotter
  @type key_types: dict
698 a5728081 Guido Trotter
  @param key_types: dict mapping target dict keys to types
699 a5728081 Guido Trotter
                    in constants.ENFORCEABLE_TYPES
700 a5728081 Guido Trotter
  @type allowed_values: list
701 a5728081 Guido Trotter
  @keyword allowed_values: list of specially allowed values
702 a5728081 Guido Trotter

703 a5728081 Guido Trotter
  """
704 a5728081 Guido Trotter
  if allowed_values is None:
705 a5728081 Guido Trotter
    allowed_values = []
706 a5728081 Guido Trotter
707 8b46606c Guido Trotter
  if not isinstance(target, dict):
708 8b46606c Guido Trotter
    msg = "Expected dictionary, got '%s'" % target
709 8b46606c Guido Trotter
    raise errors.TypeEnforcementError(msg)
710 8b46606c Guido Trotter
711 a5728081 Guido Trotter
  for key in target:
712 a5728081 Guido Trotter
    if key not in key_types:
713 a5728081 Guido Trotter
      msg = "Unknown key '%s'" % key
714 a5728081 Guido Trotter
      raise errors.TypeEnforcementError(msg)
715 a5728081 Guido Trotter
716 a5728081 Guido Trotter
    if target[key] in allowed_values:
717 a5728081 Guido Trotter
      continue
718 a5728081 Guido Trotter
719 29921401 Iustin Pop
    ktype = key_types[key]
720 29921401 Iustin Pop
    if ktype not in constants.ENFORCEABLE_TYPES:
721 29921401 Iustin Pop
      msg = "'%s' has non-enforceable type %s" % (key, ktype)
722 a5728081 Guido Trotter
      raise errors.ProgrammerError(msg)
723 a5728081 Guido Trotter
724 59525e1f Michael Hanselmann
    if ktype in (constants.VTYPE_STRING, constants.VTYPE_MAYBE_STRING):
725 59525e1f Michael Hanselmann
      if target[key] is None and ktype == constants.VTYPE_MAYBE_STRING:
726 59525e1f Michael Hanselmann
        pass
727 59525e1f Michael Hanselmann
      elif not isinstance(target[key], basestring):
728 a5728081 Guido Trotter
        if isinstance(target[key], bool) and not target[key]:
729 a5728081 Guido Trotter
          target[key] = ''
730 a5728081 Guido Trotter
        else:
731 a5728081 Guido Trotter
          msg = "'%s' (value %s) is not a valid string" % (key, target[key])
732 a5728081 Guido Trotter
          raise errors.TypeEnforcementError(msg)
733 29921401 Iustin Pop
    elif ktype == constants.VTYPE_BOOL:
734 a5728081 Guido Trotter
      if isinstance(target[key], basestring) and target[key]:
735 a5728081 Guido Trotter
        if target[key].lower() == constants.VALUE_FALSE:
736 a5728081 Guido Trotter
          target[key] = False
737 a5728081 Guido Trotter
        elif target[key].lower() == constants.VALUE_TRUE:
738 a5728081 Guido Trotter
          target[key] = True
739 a5728081 Guido Trotter
        else:
740 a5728081 Guido Trotter
          msg = "'%s' (value %s) is not a valid boolean" % (key, target[key])
741 a5728081 Guido Trotter
          raise errors.TypeEnforcementError(msg)
742 a5728081 Guido Trotter
      elif target[key]:
743 a5728081 Guido Trotter
        target[key] = True
744 a5728081 Guido Trotter
      else:
745 a5728081 Guido Trotter
        target[key] = False
746 29921401 Iustin Pop
    elif ktype == constants.VTYPE_SIZE:
747 a5728081 Guido Trotter
      try:
748 a5728081 Guido Trotter
        target[key] = ParseUnit(target[key])
749 a5728081 Guido Trotter
      except errors.UnitParseError, err:
750 a5728081 Guido Trotter
        msg = "'%s' (value %s) is not a valid size. error: %s" % \
751 a5728081 Guido Trotter
              (key, target[key], err)
752 a5728081 Guido Trotter
        raise errors.TypeEnforcementError(msg)
753 29921401 Iustin Pop
    elif ktype == constants.VTYPE_INT:
754 a5728081 Guido Trotter
      try:
755 a5728081 Guido Trotter
        target[key] = int(target[key])
756 a5728081 Guido Trotter
      except (ValueError, TypeError):
757 a5728081 Guido Trotter
        msg = "'%s' (value %s) is not a valid integer" % (key, target[key])
758 a5728081 Guido Trotter
        raise errors.TypeEnforcementError(msg)
759 a5728081 Guido Trotter
760 a5728081 Guido Trotter
761 a01b500b Michael Hanselmann
def _GetProcStatusPath(pid):
762 a01b500b Michael Hanselmann
  """Returns the path for a PID's proc status file.
763 a01b500b Michael Hanselmann

764 a01b500b Michael Hanselmann
  @type pid: int
765 a01b500b Michael Hanselmann
  @param pid: Process ID
766 a01b500b Michael Hanselmann
  @rtype: string
767 a01b500b Michael Hanselmann

768 a01b500b Michael Hanselmann
  """
769 a01b500b Michael Hanselmann
  return "/proc/%d/status" % pid
770 a01b500b Michael Hanselmann
771 a01b500b Michael Hanselmann
772 a8083063 Iustin Pop
def IsProcessAlive(pid):
773 a8083063 Iustin Pop
  """Check if a given pid exists on the system.
774 a8083063 Iustin Pop

775 44bf25ff Iustin Pop
  @note: zombie status is not handled, so zombie processes
776 44bf25ff Iustin Pop
      will be returned as alive
777 58885d79 Iustin Pop
  @type pid: int
778 58885d79 Iustin Pop
  @param pid: the process ID to check
779 58885d79 Iustin Pop
  @rtype: boolean
780 58885d79 Iustin Pop
  @return: True if the process exists
781 a8083063 Iustin Pop

782 a8083063 Iustin Pop
  """
783 5ef5ea45 Guido Trotter
  def _TryStat(name):
784 5ef5ea45 Guido Trotter
    try:
785 5ef5ea45 Guido Trotter
      os.stat(name)
786 5ef5ea45 Guido Trotter
      return True
787 5ef5ea45 Guido Trotter
    except EnvironmentError, err:
788 5ef5ea45 Guido Trotter
      if err.errno in (errno.ENOENT, errno.ENOTDIR):
789 5ef5ea45 Guido Trotter
        return False
790 5ef5ea45 Guido Trotter
      elif err.errno == errno.EINVAL:
791 5ef5ea45 Guido Trotter
        raise RetryAgain(err)
792 5ef5ea45 Guido Trotter
      raise
793 5ef5ea45 Guido Trotter
794 5ef5ea45 Guido Trotter
  assert isinstance(pid, int), "pid must be an integer"
795 d9f311d7 Iustin Pop
  if pid <= 0:
796 d9f311d7 Iustin Pop
    return False
797 d9f311d7 Iustin Pop
798 5ef5ea45 Guido Trotter
  # /proc in a multiprocessor environment can have strange behaviors.
799 5ef5ea45 Guido Trotter
  # Retry the os.stat a few times until we get a good result.
800 a8083063 Iustin Pop
  try:
801 a01b500b Michael Hanselmann
    return Retry(_TryStat, (0.01, 1.5, 0.1), 0.5,
802 a01b500b Michael Hanselmann
                 args=[_GetProcStatusPath(pid)])
803 5ef5ea45 Guido Trotter
  except RetryTimeout, err:
804 5ef5ea45 Guido Trotter
    err.RaiseInner()
805 a8083063 Iustin Pop
806 a8083063 Iustin Pop
807 a01b500b Michael Hanselmann
def _ParseSigsetT(sigset):
808 a01b500b Michael Hanselmann
  """Parse a rendered sigset_t value.
809 a01b500b Michael Hanselmann

810 a01b500b Michael Hanselmann
  This is the opposite of the Linux kernel's fs/proc/array.c:render_sigset_t
811 a01b500b Michael Hanselmann
  function.
812 a01b500b Michael Hanselmann

813 a01b500b Michael Hanselmann
  @type sigset: string
814 a01b500b Michael Hanselmann
  @param sigset: Rendered signal set from /proc/$pid/status
815 a01b500b Michael Hanselmann
  @rtype: set
816 a01b500b Michael Hanselmann
  @return: Set of all enabled signal numbers
817 a01b500b Michael Hanselmann

818 a01b500b Michael Hanselmann
  """
819 a01b500b Michael Hanselmann
  result = set()
820 a01b500b Michael Hanselmann
821 a01b500b Michael Hanselmann
  signum = 0
822 a01b500b Michael Hanselmann
  for ch in reversed(sigset):
823 a01b500b Michael Hanselmann
    chv = int(ch, 16)
824 a01b500b Michael Hanselmann
825 a01b500b Michael Hanselmann
    # The following could be done in a loop, but it's easier to read and
826 a01b500b Michael Hanselmann
    # understand in the unrolled form
827 a01b500b Michael Hanselmann
    if chv & 1:
828 a01b500b Michael Hanselmann
      result.add(signum + 1)
829 a01b500b Michael Hanselmann
    if chv & 2:
830 a01b500b Michael Hanselmann
      result.add(signum + 2)
831 a01b500b Michael Hanselmann
    if chv & 4:
832 a01b500b Michael Hanselmann
      result.add(signum + 3)
833 a01b500b Michael Hanselmann
    if chv & 8:
834 a01b500b Michael Hanselmann
      result.add(signum + 4)
835 a01b500b Michael Hanselmann
836 a01b500b Michael Hanselmann
    signum += 4
837 a01b500b Michael Hanselmann
838 a01b500b Michael Hanselmann
  return result
839 a01b500b Michael Hanselmann
840 a01b500b Michael Hanselmann
841 a01b500b Michael Hanselmann
def _GetProcStatusField(pstatus, field):
842 a01b500b Michael Hanselmann
  """Retrieves a field from the contents of a proc status file.
843 a01b500b Michael Hanselmann

844 a01b500b Michael Hanselmann
  @type pstatus: string
845 a01b500b Michael Hanselmann
  @param pstatus: Contents of /proc/$pid/status
846 a01b500b Michael Hanselmann
  @type field: string
847 a01b500b Michael Hanselmann
  @param field: Name of field whose value should be returned
848 a01b500b Michael Hanselmann
  @rtype: string
849 a01b500b Michael Hanselmann

850 a01b500b Michael Hanselmann
  """
851 a01b500b Michael Hanselmann
  for line in pstatus.splitlines():
852 a01b500b Michael Hanselmann
    parts = line.split(":", 1)
853 a01b500b Michael Hanselmann
854 a01b500b Michael Hanselmann
    if len(parts) < 2 or parts[0] != field:
855 a01b500b Michael Hanselmann
      continue
856 a01b500b Michael Hanselmann
857 a01b500b Michael Hanselmann
    return parts[1].strip()
858 a01b500b Michael Hanselmann
859 a01b500b Michael Hanselmann
  return None
860 a01b500b Michael Hanselmann
861 a01b500b Michael Hanselmann
862 a01b500b Michael Hanselmann
def IsProcessHandlingSignal(pid, signum, status_path=None):
863 a01b500b Michael Hanselmann
  """Checks whether a process is handling a signal.
864 a01b500b Michael Hanselmann

865 a01b500b Michael Hanselmann
  @type pid: int
866 a01b500b Michael Hanselmann
  @param pid: Process ID
867 a01b500b Michael Hanselmann
  @type signum: int
868 a01b500b Michael Hanselmann
  @param signum: Signal number
869 a01b500b Michael Hanselmann
  @rtype: bool
870 a01b500b Michael Hanselmann

871 a01b500b Michael Hanselmann
  """
872 a01b500b Michael Hanselmann
  if status_path is None:
873 a01b500b Michael Hanselmann
    status_path = _GetProcStatusPath(pid)
874 a01b500b Michael Hanselmann
875 a01b500b Michael Hanselmann
  try:
876 a01b500b Michael Hanselmann
    proc_status = ReadFile(status_path)
877 a01b500b Michael Hanselmann
  except EnvironmentError, err:
878 a01b500b Michael Hanselmann
    # In at least one case, reading /proc/$pid/status failed with ESRCH.
879 a01b500b Michael Hanselmann
    if err.errno in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL, errno.ESRCH):
880 a01b500b Michael Hanselmann
      return False
881 a01b500b Michael Hanselmann
    raise
882 a01b500b Michael Hanselmann
883 a01b500b Michael Hanselmann
  sigcgt = _GetProcStatusField(proc_status, "SigCgt")
884 a01b500b Michael Hanselmann
  if sigcgt is None:
885 a01b500b Michael Hanselmann
    raise RuntimeError("%s is missing 'SigCgt' field" % status_path)
886 a01b500b Michael Hanselmann
887 a01b500b Michael Hanselmann
  # Now check whether signal is handled
888 a01b500b Michael Hanselmann
  return signum in _ParseSigsetT(sigcgt)
889 a01b500b Michael Hanselmann
890 a01b500b Michael Hanselmann
891 28f34048 Michael Hanselmann
def ValidateServiceName(name):
892 28f34048 Michael Hanselmann
  """Validate the given service name.
893 28f34048 Michael Hanselmann

894 28f34048 Michael Hanselmann
  @type name: number or string
895 28f34048 Michael Hanselmann
  @param name: Service name or port specification
896 28f34048 Michael Hanselmann

897 28f34048 Michael Hanselmann
  """
898 28f34048 Michael Hanselmann
  try:
899 28f34048 Michael Hanselmann
    numport = int(name)
900 28f34048 Michael Hanselmann
  except (ValueError, TypeError):
901 28f34048 Michael Hanselmann
    # Non-numeric service name
902 28f34048 Michael Hanselmann
    valid = _VALID_SERVICE_NAME_RE.match(name)
903 28f34048 Michael Hanselmann
  else:
904 28f34048 Michael Hanselmann
    # Numeric port (protocols other than TCP or UDP might need adjustments
905 28f34048 Michael Hanselmann
    # here)
906 28f34048 Michael Hanselmann
    valid = (numport >= 0 and numport < (1 << 16))
907 28f34048 Michael Hanselmann
908 28f34048 Michael Hanselmann
  if not valid:
909 28f34048 Michael Hanselmann
    raise errors.OpPrereqError("Invalid service name '%s'" % name,
910 28f34048 Michael Hanselmann
                               errors.ECODE_INVAL)
911 28f34048 Michael Hanselmann
912 28f34048 Michael Hanselmann
  return name
913 28f34048 Michael Hanselmann
914 28f34048 Michael Hanselmann
915 a8083063 Iustin Pop
def ListVolumeGroups():
916 a8083063 Iustin Pop
  """List volume groups and their size
917 a8083063 Iustin Pop

918 58885d79 Iustin Pop
  @rtype: dict
919 58885d79 Iustin Pop
  @return:
920 58885d79 Iustin Pop
       Dictionary with keys volume name and values
921 58885d79 Iustin Pop
       the size of the volume
922 a8083063 Iustin Pop

923 a8083063 Iustin Pop
  """
924 a8083063 Iustin Pop
  command = "vgs --noheadings --units m --nosuffix -o name,size"
925 a8083063 Iustin Pop
  result = RunCmd(command)
926 a8083063 Iustin Pop
  retval = {}
927 a8083063 Iustin Pop
  if result.failed:
928 a8083063 Iustin Pop
    return retval
929 a8083063 Iustin Pop
930 a8083063 Iustin Pop
  for line in result.stdout.splitlines():
931 a8083063 Iustin Pop
    try:
932 a8083063 Iustin Pop
      name, size = line.split()
933 a8083063 Iustin Pop
      size = int(float(size))
934 a8083063 Iustin Pop
    except (IndexError, ValueError), err:
935 bb698c1f Iustin Pop
      logging.error("Invalid output from vgs (%s): %s", err, line)
936 a8083063 Iustin Pop
      continue
937 a8083063 Iustin Pop
938 a8083063 Iustin Pop
    retval[name] = size
939 a8083063 Iustin Pop
940 a8083063 Iustin Pop
  return retval
941 a8083063 Iustin Pop
942 a8083063 Iustin Pop
943 a8083063 Iustin Pop
def BridgeExists(bridge):
944 a8083063 Iustin Pop
  """Check whether the given bridge exists in the system
945 a8083063 Iustin Pop

946 58885d79 Iustin Pop
  @type bridge: str
947 58885d79 Iustin Pop
  @param bridge: the bridge name to check
948 58885d79 Iustin Pop
  @rtype: boolean
949 58885d79 Iustin Pop
  @return: True if it does
950 a8083063 Iustin Pop

951 a8083063 Iustin Pop
  """
952 a8083063 Iustin Pop
  return os.path.isdir("/sys/class/net/%s/bridge" % bridge)
953 a8083063 Iustin Pop
954 a8083063 Iustin Pop
955 a8083063 Iustin Pop
def TryConvert(fn, val):
956 a8083063 Iustin Pop
  """Try to convert a value ignoring errors.
957 a8083063 Iustin Pop

958 58885d79 Iustin Pop
  This function tries to apply function I{fn} to I{val}. If no
959 58885d79 Iustin Pop
  C{ValueError} or C{TypeError} exceptions are raised, it will return
960 58885d79 Iustin Pop
  the result, else it will return the original value. Any other
961 58885d79 Iustin Pop
  exceptions are propagated to the caller.
962 58885d79 Iustin Pop

963 58885d79 Iustin Pop
  @type fn: callable
964 58885d79 Iustin Pop
  @param fn: function to apply to the value
965 58885d79 Iustin Pop
  @param val: the value to be converted
966 58885d79 Iustin Pop
  @return: The converted value if the conversion was successful,
967 58885d79 Iustin Pop
      otherwise the original value.
968 a8083063 Iustin Pop

969 a8083063 Iustin Pop
  """
970 a8083063 Iustin Pop
  try:
971 a8083063 Iustin Pop
    nv = fn(val)
972 7c4d6c7b Michael Hanselmann
  except (ValueError, TypeError):
973 a8083063 Iustin Pop
    nv = val
974 a8083063 Iustin Pop
  return nv
975 a8083063 Iustin Pop
976 a8083063 Iustin Pop
977 a8083063 Iustin Pop
def IsValidShellParam(word):
978 a8083063 Iustin Pop
  """Verifies is the given word is safe from the shell's p.o.v.
979 a8083063 Iustin Pop

980 a8083063 Iustin Pop
  This means that we can pass this to a command via the shell and be
981 a8083063 Iustin Pop
  sure that it doesn't alter the command line and is passed as such to
982 a8083063 Iustin Pop
  the actual command.
983 a8083063 Iustin Pop

984 a8083063 Iustin Pop
  Note that we are overly restrictive here, in order to be on the safe
985 a8083063 Iustin Pop
  side.
986 a8083063 Iustin Pop

987 58885d79 Iustin Pop
  @type word: str
988 58885d79 Iustin Pop
  @param word: the word to check
989 58885d79 Iustin Pop
  @rtype: boolean
990 58885d79 Iustin Pop
  @return: True if the word is 'safe'
991 58885d79 Iustin Pop

992 a8083063 Iustin Pop
  """
993 0b5303da Iustin Pop
  return bool(_SHELLPARAM_REGEX.match(word))
994 a8083063 Iustin Pop
995 a8083063 Iustin Pop
996 a8083063 Iustin Pop
def BuildShellCmd(template, *args):
997 a8083063 Iustin Pop
  """Build a safe shell command line from the given arguments.
998 a8083063 Iustin Pop

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

1004 58885d79 Iustin Pop
  @type template: str
1005 58885d79 Iustin Pop
  @param template: the string holding the template for the
1006 58885d79 Iustin Pop
      string formatting
1007 58885d79 Iustin Pop
  @rtype: str
1008 58885d79 Iustin Pop
  @return: the expanded command line
1009 58885d79 Iustin Pop

1010 a8083063 Iustin Pop
  """
1011 a8083063 Iustin Pop
  for word in args:
1012 a8083063 Iustin Pop
    if not IsValidShellParam(word):
1013 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Shell argument '%s' contains"
1014 3ecf6786 Iustin Pop
                                   " invalid characters" % word)
1015 a8083063 Iustin Pop
  return template % args
1016 a8083063 Iustin Pop
1017 a8083063 Iustin Pop
1018 31155d60 Balazs Lecz
def ParseCpuMask(cpu_mask):
1019 31155d60 Balazs Lecz
  """Parse a CPU mask definition and return the list of CPU IDs.
1020 31155d60 Balazs Lecz

1021 31155d60 Balazs Lecz
  CPU mask format: comma-separated list of CPU IDs
1022 31155d60 Balazs Lecz
  or dash-separated ID ranges
1023 31155d60 Balazs Lecz
  Example: "0-2,5" -> "0,1,2,5"
1024 31155d60 Balazs Lecz

1025 31155d60 Balazs Lecz
  @type cpu_mask: str
1026 31155d60 Balazs Lecz
  @param cpu_mask: CPU mask definition
1027 31155d60 Balazs Lecz
  @rtype: list of int
1028 31155d60 Balazs Lecz
  @return: list of CPU IDs
1029 31155d60 Balazs Lecz

1030 31155d60 Balazs Lecz
  """
1031 31155d60 Balazs Lecz
  if not cpu_mask:
1032 31155d60 Balazs Lecz
    return []
1033 31155d60 Balazs Lecz
  cpu_list = []
1034 31155d60 Balazs Lecz
  for range_def in cpu_mask.split(","):
1035 31155d60 Balazs Lecz
    boundaries = range_def.split("-")
1036 31155d60 Balazs Lecz
    n_elements = len(boundaries)
1037 31155d60 Balazs Lecz
    if n_elements > 2:
1038 31155d60 Balazs Lecz
      raise errors.ParseError("Invalid CPU ID range definition"
1039 31155d60 Balazs Lecz
                              " (only one hyphen allowed): %s" % range_def)
1040 31155d60 Balazs Lecz
    try:
1041 31155d60 Balazs Lecz
      lower = int(boundaries[0])
1042 31155d60 Balazs Lecz
    except (ValueError, TypeError), err:
1043 31155d60 Balazs Lecz
      raise errors.ParseError("Invalid CPU ID value for lower boundary of"
1044 31155d60 Balazs Lecz
                              " CPU ID range: %s" % str(err))
1045 31155d60 Balazs Lecz
    try:
1046 31155d60 Balazs Lecz
      higher = int(boundaries[-1])
1047 31155d60 Balazs Lecz
    except (ValueError, TypeError), err:
1048 31155d60 Balazs Lecz
      raise errors.ParseError("Invalid CPU ID value for higher boundary of"
1049 31155d60 Balazs Lecz
                              " CPU ID range: %s" % str(err))
1050 31155d60 Balazs Lecz
    if lower > higher:
1051 31155d60 Balazs Lecz
      raise errors.ParseError("Invalid CPU ID range definition"
1052 31155d60 Balazs Lecz
                              " (%d > %d): %s" % (lower, higher, range_def))
1053 31155d60 Balazs Lecz
    cpu_list.extend(range(lower, higher + 1))
1054 31155d60 Balazs Lecz
  return cpu_list
1055 31155d60 Balazs Lecz
1056 31155d60 Balazs Lecz
1057 257f4c0a Iustin Pop
def GetHomeDir(user, default=None):
1058 257f4c0a Iustin Pop
  """Try to get the homedir of the given user.
1059 257f4c0a Iustin Pop

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

1064 2f8b60b3 Iustin Pop
  """
1065 2f8b60b3 Iustin Pop
  try:
1066 257f4c0a Iustin Pop
    if isinstance(user, basestring):
1067 257f4c0a Iustin Pop
      result = pwd.getpwnam(user)
1068 257f4c0a Iustin Pop
    elif isinstance(user, (int, long)):
1069 257f4c0a Iustin Pop
      result = pwd.getpwuid(user)
1070 257f4c0a Iustin Pop
    else:
1071 257f4c0a Iustin Pop
      raise errors.ProgrammerError("Invalid type passed to GetHomeDir (%s)" %
1072 257f4c0a Iustin Pop
                                   type(user))
1073 2f8b60b3 Iustin Pop
  except KeyError:
1074 2f8b60b3 Iustin Pop
    return default
1075 2f8b60b3 Iustin Pop
  return result.pw_dir
1076 59072e7e Michael Hanselmann
1077 59072e7e Michael Hanselmann
1078 24818e8f Michael Hanselmann
def NewUUID():
1079 59072e7e Michael Hanselmann
  """Returns a random UUID.
1080 59072e7e Michael Hanselmann

1081 58885d79 Iustin Pop
  @note: This is a Linux-specific method as it uses the /proc
1082 58885d79 Iustin Pop
      filesystem.
1083 58885d79 Iustin Pop
  @rtype: str
1084 58885d79 Iustin Pop

1085 59072e7e Michael Hanselmann
  """
1086 13998ef2 Michael Hanselmann
  return ReadFile(_RANDOM_UUID_FILE, size=128).rstrip("\n")
1087 087b34fe Iustin Pop
1088 087b34fe Iustin Pop
1089 7b4126b7 Iustin Pop
def FirstFree(seq, base=0):
1090 7b4126b7 Iustin Pop
  """Returns the first non-existing integer from seq.
1091 7b4126b7 Iustin Pop

1092 7b4126b7 Iustin Pop
  The seq argument should be a sorted list of positive integers. The
1093 7b4126b7 Iustin Pop
  first time the index of an element is smaller than the element
1094 7b4126b7 Iustin Pop
  value, the index will be returned.
1095 7b4126b7 Iustin Pop

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

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

1101 58885d79 Iustin Pop
  @type seq: sequence
1102 58885d79 Iustin Pop
  @param seq: the sequence to be analyzed.
1103 58885d79 Iustin Pop
  @type base: int
1104 58885d79 Iustin Pop
  @param base: use this value as the base index of the sequence
1105 58885d79 Iustin Pop
  @rtype: int
1106 58885d79 Iustin Pop
  @return: the first non-used index in the sequence
1107 7b4126b7 Iustin Pop

1108 7b4126b7 Iustin Pop
  """
1109 7b4126b7 Iustin Pop
  for idx, elem in enumerate(seq):
1110 7b4126b7 Iustin Pop
    assert elem >= base, "Passed element is higher than base offset"
1111 7b4126b7 Iustin Pop
    if elem > idx + base:
1112 7b4126b7 Iustin Pop
      # idx is not used
1113 7b4126b7 Iustin Pop
      return idx + base
1114 7b4126b7 Iustin Pop
  return None
1115 7b4126b7 Iustin Pop
1116 7b4126b7 Iustin Pop
1117 dfdc4060 Guido Trotter
def SingleWaitForFdCondition(fdobj, event, timeout):
1118 dcd511c8 Guido Trotter
  """Waits for a condition to occur on the socket.
1119 dcd511c8 Guido Trotter

1120 dfdc4060 Guido Trotter
  Immediately returns at the first interruption.
1121 dfdc4060 Guido Trotter

1122 dfdc4060 Guido Trotter
  @type fdobj: integer or object supporting a fileno() method
1123 dfdc4060 Guido Trotter
  @param fdobj: entity to wait for events on
1124 dfdc4060 Guido Trotter
  @type event: integer
1125 dcd511c8 Guido Trotter
  @param event: ORed condition (see select module)
1126 dcd511c8 Guido Trotter
  @type timeout: float or None
1127 dcd511c8 Guido Trotter
  @param timeout: Timeout in seconds
1128 dcd511c8 Guido Trotter
  @rtype: int or None
1129 dcd511c8 Guido Trotter
  @return: None for timeout, otherwise occured conditions
1130 dcd511c8 Guido Trotter

1131 dcd511c8 Guido Trotter
  """
1132 dcd511c8 Guido Trotter
  check = (event | select.POLLPRI |
1133 dcd511c8 Guido Trotter
           select.POLLNVAL | select.POLLHUP | select.POLLERR)
1134 dcd511c8 Guido Trotter
1135 dcd511c8 Guido Trotter
  if timeout is not None:
1136 dcd511c8 Guido Trotter
    # Poller object expects milliseconds
1137 dcd511c8 Guido Trotter
    timeout *= 1000
1138 dcd511c8 Guido Trotter
1139 dcd511c8 Guido Trotter
  poller = select.poll()
1140 dfdc4060 Guido Trotter
  poller.register(fdobj, event)
1141 dcd511c8 Guido Trotter
  try:
1142 dfdc4060 Guido Trotter
    # TODO: If the main thread receives a signal and we have no timeout, we
1143 dfdc4060 Guido Trotter
    # could wait forever. This should check a global "quit" flag or something
1144 dfdc4060 Guido Trotter
    # every so often.
1145 dfdc4060 Guido Trotter
    io_events = poller.poll(timeout)
1146 dfdc4060 Guido Trotter
  except select.error, err:
1147 dfdc4060 Guido Trotter
    if err[0] != errno.EINTR:
1148 dfdc4060 Guido Trotter
      raise
1149 dfdc4060 Guido Trotter
    io_events = []
1150 dfdc4060 Guido Trotter
  if io_events and io_events[0][1] & check:
1151 dfdc4060 Guido Trotter
    return io_events[0][1]
1152 dfdc4060 Guido Trotter
  else:
1153 dfdc4060 Guido Trotter
    return None
1154 dfdc4060 Guido Trotter
1155 dfdc4060 Guido Trotter
1156 dfdc4060 Guido Trotter
class FdConditionWaiterHelper(object):
1157 dfdc4060 Guido Trotter
  """Retry helper for WaitForFdCondition.
1158 dfdc4060 Guido Trotter

1159 dfdc4060 Guido Trotter
  This class contains the retried and wait functions that make sure
1160 dfdc4060 Guido Trotter
  WaitForFdCondition can continue waiting until the timeout is actually
1161 dfdc4060 Guido Trotter
  expired.
1162 dfdc4060 Guido Trotter

1163 dfdc4060 Guido Trotter
  """
1164 dfdc4060 Guido Trotter
1165 dfdc4060 Guido Trotter
  def __init__(self, timeout):
1166 dfdc4060 Guido Trotter
    self.timeout = timeout
1167 dfdc4060 Guido Trotter
1168 dfdc4060 Guido Trotter
  def Poll(self, fdobj, event):
1169 dfdc4060 Guido Trotter
    result = SingleWaitForFdCondition(fdobj, event, self.timeout)
1170 dfdc4060 Guido Trotter
    if result is None:
1171 dfdc4060 Guido Trotter
      raise RetryAgain()
1172 dfdc4060 Guido Trotter
    else:
1173 dfdc4060 Guido Trotter
      return result
1174 dfdc4060 Guido Trotter
1175 dfdc4060 Guido Trotter
  def UpdateTimeout(self, timeout):
1176 dfdc4060 Guido Trotter
    self.timeout = timeout
1177 dfdc4060 Guido Trotter
1178 dfdc4060 Guido Trotter
1179 dfdc4060 Guido Trotter
def WaitForFdCondition(fdobj, event, timeout):
1180 dfdc4060 Guido Trotter
  """Waits for a condition to occur on the socket.
1181 dfdc4060 Guido Trotter

1182 dfdc4060 Guido Trotter
  Retries until the timeout is expired, even if interrupted.
1183 dfdc4060 Guido Trotter

1184 dfdc4060 Guido Trotter
  @type fdobj: integer or object supporting a fileno() method
1185 dfdc4060 Guido Trotter
  @param fdobj: entity to wait for events on
1186 dfdc4060 Guido Trotter
  @type event: integer
1187 dfdc4060 Guido Trotter
  @param event: ORed condition (see select module)
1188 dfdc4060 Guido Trotter
  @type timeout: float or None
1189 dfdc4060 Guido Trotter
  @param timeout: Timeout in seconds
1190 dfdc4060 Guido Trotter
  @rtype: int or None
1191 dfdc4060 Guido Trotter
  @return: None for timeout, otherwise occured conditions
1192 dfdc4060 Guido Trotter

1193 dfdc4060 Guido Trotter
  """
1194 dfdc4060 Guido Trotter
  if timeout is not None:
1195 dfdc4060 Guido Trotter
    retrywaiter = FdConditionWaiterHelper(timeout)
1196 1b429e2a Iustin Pop
    try:
1197 1b429e2a Iustin Pop
      result = Retry(retrywaiter.Poll, RETRY_REMAINING_TIME, timeout,
1198 1b429e2a Iustin Pop
                     args=(fdobj, event), wait_fn=retrywaiter.UpdateTimeout)
1199 1b429e2a Iustin Pop
    except RetryTimeout:
1200 1b429e2a Iustin Pop
      result = None
1201 dfdc4060 Guido Trotter
  else:
1202 dfdc4060 Guido Trotter
    result = None
1203 dfdc4060 Guido Trotter
    while result is None:
1204 dfdc4060 Guido Trotter
      result = SingleWaitForFdCondition(fdobj, event, timeout)
1205 dfdc4060 Guido Trotter
  return result
1206 2de64672 Iustin Pop
1207 2de64672 Iustin Pop
1208 7d88772a Iustin Pop
def CloseFDs(noclose_fds=None):
1209 7d88772a Iustin Pop
  """Close file descriptors.
1210 7d88772a Iustin Pop

1211 7d88772a Iustin Pop
  This closes all file descriptors above 2 (i.e. except
1212 7d88772a Iustin Pop
  stdin/out/err).
1213 8f765069 Iustin Pop

1214 58885d79 Iustin Pop
  @type noclose_fds: list or None
1215 58885d79 Iustin Pop
  @param noclose_fds: if given, it denotes a list of file descriptor
1216 58885d79 Iustin Pop
      that should not be closed
1217 58885d79 Iustin Pop

1218 8f765069 Iustin Pop
  """
1219 8f765069 Iustin Pop
  # Default maximum for the number of available file descriptors.
1220 8f765069 Iustin Pop
  if 'SC_OPEN_MAX' in os.sysconf_names:
1221 8f765069 Iustin Pop
    try:
1222 8f765069 Iustin Pop
      MAXFD = os.sysconf('SC_OPEN_MAX')
1223 8f765069 Iustin Pop
      if MAXFD < 0:
1224 8f765069 Iustin Pop
        MAXFD = 1024
1225 8f765069 Iustin Pop
    except OSError:
1226 8f765069 Iustin Pop
      MAXFD = 1024
1227 8f765069 Iustin Pop
  else:
1228 8f765069 Iustin Pop
    MAXFD = 1024
1229 7d88772a Iustin Pop
  maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
1230 7d88772a Iustin Pop
  if (maxfd == resource.RLIM_INFINITY):
1231 7d88772a Iustin Pop
    maxfd = MAXFD
1232 7d88772a Iustin Pop
1233 7d88772a Iustin Pop
  # Iterate through and close all file descriptors (except the standard ones)
1234 7d88772a Iustin Pop
  for fd in range(3, maxfd):
1235 7d88772a Iustin Pop
    if noclose_fds and fd in noclose_fds:
1236 7d88772a Iustin Pop
      continue
1237 71ab9dbe Michael Hanselmann
    CloseFdNoError(fd)
1238 7d88772a Iustin Pop
1239 7d88772a Iustin Pop
1240 0070a462 René Nussbaumer
def Daemonize(logfile):
1241 7d88772a Iustin Pop
  """Daemonize the current process.
1242 7d88772a Iustin Pop

1243 7d88772a Iustin Pop
  This detaches the current process from the controlling terminal and
1244 7d88772a Iustin Pop
  runs it in the background as a daemon.
1245 7d88772a Iustin Pop

1246 7d88772a Iustin Pop
  @type logfile: str
1247 7d88772a Iustin Pop
  @param logfile: the logfile to which we should redirect stdout/stderr
1248 7d88772a Iustin Pop
  @rtype: int
1249 5fcc718f Iustin Pop
  @return: the value zero
1250 7d88772a Iustin Pop

1251 7d88772a Iustin Pop
  """
1252 7260cfbe Iustin Pop
  # pylint: disable-msg=W0212
1253 7260cfbe Iustin Pop
  # yes, we really want os._exit
1254 8f765069 Iustin Pop
1255 b78aa8c2 Iustin Pop
  # TODO: do another attempt to merge Daemonize and StartDaemon, or at
1256 b78aa8c2 Iustin Pop
  # least abstract the pipe functionality between them
1257 b78aa8c2 Iustin Pop
1258 b78aa8c2 Iustin Pop
  # Create pipe for sending error messages
1259 b78aa8c2 Iustin Pop
  (rpipe, wpipe) = os.pipe()
1260 b78aa8c2 Iustin Pop
1261 8f765069 Iustin Pop
  # this might fail
1262 8f765069 Iustin Pop
  pid = os.fork()
1263 8f765069 Iustin Pop
  if (pid == 0):  # The first child.
1264 0260032c Iustin Pop
    SetupDaemonEnv()
1265 0260032c Iustin Pop
1266 8f765069 Iustin Pop
    # this might fail
1267 8f765069 Iustin Pop
    pid = os.fork() # Fork a second child.
1268 8f765069 Iustin Pop
    if (pid == 0):  # The second child.
1269 71ab9dbe Michael Hanselmann
      CloseFdNoError(rpipe)
1270 8f765069 Iustin Pop
    else:
1271 8f765069 Iustin Pop
      # exit() or _exit()?  See below.
1272 8f765069 Iustin Pop
      os._exit(0) # Exit parent (the first child) of the second child.
1273 8f765069 Iustin Pop
  else:
1274 71ab9dbe Michael Hanselmann
    CloseFdNoError(wpipe)
1275 b78aa8c2 Iustin Pop
    # Wait for daemon to be started (or an error message to
1276 b78aa8c2 Iustin Pop
    # arrive) and read up to 100 KB as an error message
1277 b78aa8c2 Iustin Pop
    errormsg = RetryOnSignal(os.read, rpipe, 100 * 1024)
1278 b78aa8c2 Iustin Pop
    if errormsg:
1279 b78aa8c2 Iustin Pop
      sys.stderr.write("Error when starting daemon process: %r\n" % errormsg)
1280 b78aa8c2 Iustin Pop
      rcode = 1
1281 b78aa8c2 Iustin Pop
    else:
1282 b78aa8c2 Iustin Pop
      rcode = 0
1283 b78aa8c2 Iustin Pop
    os._exit(rcode) # Exit parent of the first child.
1284 8f765069 Iustin Pop
1285 79634555 Iustin Pop
  SetupDaemonFDs(logfile, None)
1286 b78aa8c2 Iustin Pop
  return wpipe
1287 57c177af Iustin Pop
1288 57c177af Iustin Pop
1289 2826b361 Guido Trotter
def EnsureDaemon(name):
1290 2826b361 Guido Trotter
  """Check for and start daemon if not alive.
1291 2826b361 Guido Trotter

1292 2826b361 Guido Trotter
  """
1293 2826b361 Guido Trotter
  result = RunCmd([constants.DAEMON_UTIL, "check-and-start", name])
1294 2826b361 Guido Trotter
  if result.failed:
1295 2826b361 Guido Trotter
    logging.error("Can't start daemon '%s', failure %s, output: %s",
1296 2826b361 Guido Trotter
                  name, result.fail_reason, result.output)
1297 2826b361 Guido Trotter
    return False
1298 2826b361 Guido Trotter
1299 2826b361 Guido Trotter
  return True
1300 b330ac0b Guido Trotter
1301 b330ac0b Guido Trotter
1302 db147305 Tom Limoncelli
def StopDaemon(name):
1303 db147305 Tom Limoncelli
  """Stop daemon
1304 db147305 Tom Limoncelli

1305 db147305 Tom Limoncelli
  """
1306 db147305 Tom Limoncelli
  result = RunCmd([constants.DAEMON_UTIL, "stop", name])
1307 db147305 Tom Limoncelli
  if result.failed:
1308 db147305 Tom Limoncelli
    logging.error("Can't stop daemon '%s', failure %s, output: %s",
1309 db147305 Tom Limoncelli
                  name, result.fail_reason, result.output)
1310 db147305 Tom Limoncelli
    return False
1311 db147305 Tom Limoncelli
1312 db147305 Tom Limoncelli
  return True
1313 db147305 Tom Limoncelli
1314 db147305 Tom Limoncelli
1315 ff5251bc Iustin Pop
def KillProcess(pid, signal_=signal.SIGTERM, timeout=30,
1316 ff5251bc Iustin Pop
                waitpid=False):
1317 b2a1f511 Iustin Pop
  """Kill a process given by its pid.
1318 b2a1f511 Iustin Pop

1319 b2a1f511 Iustin Pop
  @type pid: int
1320 b2a1f511 Iustin Pop
  @param pid: The PID to terminate.
1321 38206f3c Iustin Pop
  @type signal_: int
1322 38206f3c Iustin Pop
  @param signal_: The signal to send, by default SIGTERM
1323 b2a1f511 Iustin Pop
  @type timeout: int
1324 b2a1f511 Iustin Pop
  @param timeout: The timeout after which, if the process is still alive,
1325 b2a1f511 Iustin Pop
                  a SIGKILL will be sent. If not positive, no such checking
1326 b2a1f511 Iustin Pop
                  will be done
1327 ff5251bc Iustin Pop
  @type waitpid: boolean
1328 ff5251bc Iustin Pop
  @param waitpid: If true, we should waitpid on this process after
1329 ff5251bc Iustin Pop
      sending signals, since it's our own child and otherwise it
1330 ff5251bc Iustin Pop
      would remain as zombie
1331 b2a1f511 Iustin Pop

1332 b2a1f511 Iustin Pop
  """
1333 ff5251bc Iustin Pop
  def _helper(pid, signal_, wait):
1334 ff5251bc Iustin Pop
    """Simple helper to encapsulate the kill/waitpid sequence"""
1335 560cbec1 Michael Hanselmann
    if IgnoreProcessNotFound(os.kill, pid, signal_) and wait:
1336 ff5251bc Iustin Pop
      try:
1337 ff5251bc Iustin Pop
        os.waitpid(pid, os.WNOHANG)
1338 ff5251bc Iustin Pop
      except OSError:
1339 ff5251bc Iustin Pop
        pass
1340 ff5251bc Iustin Pop
1341 b2a1f511 Iustin Pop
  if pid <= 0:
1342 b2a1f511 Iustin Pop
    # kill with pid=0 == suicide
1343 b2a1f511 Iustin Pop
    raise errors.ProgrammerError("Invalid pid given '%s'" % pid)
1344 b2a1f511 Iustin Pop
1345 b2a1f511 Iustin Pop
  if not IsProcessAlive(pid):
1346 b2a1f511 Iustin Pop
    return
1347 31892b4c Michael Hanselmann
1348 ff5251bc Iustin Pop
  _helper(pid, signal_, waitpid)
1349 31892b4c Michael Hanselmann
1350 b2a1f511 Iustin Pop
  if timeout <= 0:
1351 b2a1f511 Iustin Pop
    return
1352 7167159a Michael Hanselmann
1353 31892b4c Michael Hanselmann
  def _CheckProcess():
1354 31892b4c Michael Hanselmann
    if not IsProcessAlive(pid):
1355 31892b4c Michael Hanselmann
      return
1356 31892b4c Michael Hanselmann
1357 7167159a Michael Hanselmann
    try:
1358 7167159a Michael Hanselmann
      (result_pid, _) = os.waitpid(pid, os.WNOHANG)
1359 7167159a Michael Hanselmann
    except OSError:
1360 31892b4c Michael Hanselmann
      raise RetryAgain()
1361 31892b4c Michael Hanselmann
1362 31892b4c Michael Hanselmann
    if result_pid > 0:
1363 31892b4c Michael Hanselmann
      return
1364 31892b4c Michael Hanselmann
1365 31892b4c Michael Hanselmann
    raise RetryAgain()
1366 31892b4c Michael Hanselmann
1367 31892b4c Michael Hanselmann
  try:
1368 31892b4c Michael Hanselmann
    # Wait up to $timeout seconds
1369 31892b4c Michael Hanselmann
    Retry(_CheckProcess, (0.01, 1.5, 0.1), timeout)
1370 31892b4c Michael Hanselmann
  except RetryTimeout:
1371 31892b4c Michael Hanselmann
    pass
1372 7167159a Michael Hanselmann
1373 b2a1f511 Iustin Pop
  if IsProcessAlive(pid):
1374 7167159a Michael Hanselmann
    # Kill process if it's still alive
1375 e1bd0072 Iustin Pop
    _helper(pid, signal.SIGKILL, waitpid)
1376 b2a1f511 Iustin Pop
1377 b2a1f511 Iustin Pop
1378 8d1a2a64 Michael Hanselmann
def CheckVolumeGroupSize(vglist, vgname, minsize):
1379 8d1a2a64 Michael Hanselmann
  """Checks if the volume group list is valid.
1380 8d1a2a64 Michael Hanselmann

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

1384 58885d79 Iustin Pop
  @type vglist: dict
1385 58885d79 Iustin Pop
  @param vglist: dictionary of volume group names and their size
1386 58885d79 Iustin Pop
  @type vgname: str
1387 58885d79 Iustin Pop
  @param vgname: the volume group we should check
1388 58885d79 Iustin Pop
  @type minsize: int
1389 58885d79 Iustin Pop
  @param minsize: the minimum size we accept
1390 58885d79 Iustin Pop
  @rtype: None or str
1391 58885d79 Iustin Pop
  @return: None for success, otherwise the error message
1392 8d1a2a64 Michael Hanselmann

1393 8d1a2a64 Michael Hanselmann
  """
1394 8d1a2a64 Michael Hanselmann
  vgsize = vglist.get(vgname, None)
1395 8d1a2a64 Michael Hanselmann
  if vgsize is None:
1396 8d1a2a64 Michael Hanselmann
    return "volume group '%s' missing" % vgname
1397 8d1a2a64 Michael Hanselmann
  elif vgsize < minsize:
1398 8d1a2a64 Michael Hanselmann
    return ("volume group '%s' too small (%s MiB required, %d MiB found)" %
1399 8d1a2a64 Michael Hanselmann
            (vgname, minsize, vgsize))
1400 8d1a2a64 Michael Hanselmann
  return None
1401 7996a135 Iustin Pop
1402 7996a135 Iustin Pop
1403 45bc5e4a Michael Hanselmann
def SplitTime(value):
1404 739be818 Michael Hanselmann
  """Splits time as floating point number into a tuple.
1405 739be818 Michael Hanselmann

1406 45bc5e4a Michael Hanselmann
  @param value: Time in seconds
1407 45bc5e4a Michael Hanselmann
  @type value: int or float
1408 45bc5e4a Michael Hanselmann
  @return: Tuple containing (seconds, microseconds)
1409 739be818 Michael Hanselmann

1410 739be818 Michael Hanselmann
  """
1411 45bc5e4a Michael Hanselmann
  (seconds, microseconds) = divmod(int(value * 1000000), 1000000)
1412 45bc5e4a Michael Hanselmann
1413 45bc5e4a Michael Hanselmann
  assert 0 <= seconds, \
1414 45bc5e4a Michael Hanselmann
    "Seconds must be larger than or equal to 0, but are %s" % seconds
1415 45bc5e4a Michael Hanselmann
  assert 0 <= microseconds <= 999999, \
1416 45bc5e4a Michael Hanselmann
    "Microseconds must be 0-999999, but are %s" % microseconds
1417 45bc5e4a Michael Hanselmann
1418 45bc5e4a Michael Hanselmann
  return (int(seconds), int(microseconds))
1419 739be818 Michael Hanselmann
1420 739be818 Michael Hanselmann
1421 739be818 Michael Hanselmann
def MergeTime(timetuple):
1422 739be818 Michael Hanselmann
  """Merges a tuple into time as a floating point number.
1423 739be818 Michael Hanselmann

1424 45bc5e4a Michael Hanselmann
  @param timetuple: Time as tuple, (seconds, microseconds)
1425 739be818 Michael Hanselmann
  @type timetuple: tuple
1426 739be818 Michael Hanselmann
  @return: Time as a floating point number expressed in seconds
1427 739be818 Michael Hanselmann

1428 739be818 Michael Hanselmann
  """
1429 45bc5e4a Michael Hanselmann
  (seconds, microseconds) = timetuple
1430 739be818 Michael Hanselmann
1431 45bc5e4a Michael Hanselmann
  assert 0 <= seconds, \
1432 45bc5e4a Michael Hanselmann
    "Seconds must be larger than or equal to 0, but are %s" % seconds
1433 45bc5e4a Michael Hanselmann
  assert 0 <= microseconds <= 999999, \
1434 45bc5e4a Michael Hanselmann
    "Microseconds must be 0-999999, but are %s" % microseconds
1435 739be818 Michael Hanselmann
1436 45bc5e4a Michael Hanselmann
  return float(seconds) + (float(microseconds) * 0.000001)
1437 739be818 Michael Hanselmann
1438 739be818 Michael Hanselmann
1439 691c81b7 Michael Hanselmann
def FindMatch(data, name):
1440 691c81b7 Michael Hanselmann
  """Tries to find an item in a dictionary matching a name.
1441 691c81b7 Michael Hanselmann

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

1446 691c81b7 Michael Hanselmann
  @type data: dict
1447 691c81b7 Michael Hanselmann
  @param data: Dictionary containing data
1448 691c81b7 Michael Hanselmann
  @type name: string
1449 691c81b7 Michael Hanselmann
  @param name: Name to look for
1450 691c81b7 Michael Hanselmann
  @rtype: tuple; (value in dictionary, matched groups as list)
1451 691c81b7 Michael Hanselmann

1452 691c81b7 Michael Hanselmann
  """
1453 691c81b7 Michael Hanselmann
  if name in data:
1454 691c81b7 Michael Hanselmann
    return (data[name], [])
1455 691c81b7 Michael Hanselmann
1456 691c81b7 Michael Hanselmann
  for key, value in data.items():
1457 691c81b7 Michael Hanselmann
    # Regex objects
1458 691c81b7 Michael Hanselmann
    if hasattr(key, "match"):
1459 691c81b7 Michael Hanselmann
      m = key.match(name)
1460 691c81b7 Michael Hanselmann
      if m:
1461 691c81b7 Michael Hanselmann
        return (value, list(m.groups()))
1462 691c81b7 Michael Hanselmann
1463 691c81b7 Michael Hanselmann
  return None
1464 691c81b7 Michael Hanselmann
1465 691c81b7 Michael Hanselmann
1466 1b045f5d Balazs Lecz
def GetMounts(filename=constants.PROC_MOUNTS):
1467 1b045f5d Balazs Lecz
  """Returns the list of mounted filesystems.
1468 1b045f5d Balazs Lecz

1469 1b045f5d Balazs Lecz
  This function is Linux-specific.
1470 1b045f5d Balazs Lecz

1471 1b045f5d Balazs Lecz
  @param filename: path of mounts file (/proc/mounts by default)
1472 1b045f5d Balazs Lecz
  @rtype: list of tuples
1473 1b045f5d Balazs Lecz
  @return: list of mount entries (device, mountpoint, fstype, options)
1474 1b045f5d Balazs Lecz

1475 1b045f5d Balazs Lecz
  """
1476 1b045f5d Balazs Lecz
  # TODO(iustin): investigate non-Linux options (e.g. via mount output)
1477 1b045f5d Balazs Lecz
  data = []
1478 1b045f5d Balazs Lecz
  mountlines = ReadFile(filename).splitlines()
1479 1b045f5d Balazs Lecz
  for line in mountlines:
1480 1b045f5d Balazs Lecz
    device, mountpoint, fstype, options, _ = line.split(None, 4)
1481 1b045f5d Balazs Lecz
    data.append((device, mountpoint, fstype, options))
1482 1b045f5d Balazs Lecz
1483 1b045f5d Balazs Lecz
  return data
1484 1b045f5d Balazs Lecz
1485 1b045f5d Balazs Lecz
1486 bdefe5dd Michael Hanselmann
def RunInSeparateProcess(fn, *args):
1487 eb58f7bd Michael Hanselmann
  """Runs a function in a separate process.
1488 eb58f7bd Michael Hanselmann

1489 eb58f7bd Michael Hanselmann
  Note: Only boolean return values are supported.
1490 eb58f7bd Michael Hanselmann

1491 eb58f7bd Michael Hanselmann
  @type fn: callable
1492 eb58f7bd Michael Hanselmann
  @param fn: Function to be called
1493 bdefe5dd Michael Hanselmann
  @rtype: bool
1494 bdefe5dd Michael Hanselmann
  @return: Function's result
1495 eb58f7bd Michael Hanselmann

1496 eb58f7bd Michael Hanselmann
  """
1497 eb58f7bd Michael Hanselmann
  pid = os.fork()
1498 eb58f7bd Michael Hanselmann
  if pid == 0:
1499 eb58f7bd Michael Hanselmann
    # Child process
1500 eb58f7bd Michael Hanselmann
    try:
1501 82869978 Michael Hanselmann
      # In case the function uses temporary files
1502 82869978 Michael Hanselmann
      ResetTempfileModule()
1503 82869978 Michael Hanselmann
1504 eb58f7bd Michael Hanselmann
      # Call function
1505 bdefe5dd Michael Hanselmann
      result = int(bool(fn(*args)))
1506 eb58f7bd Michael Hanselmann
      assert result in (0, 1)
1507 eb58f7bd Michael Hanselmann
    except: # pylint: disable-msg=W0702
1508 eb58f7bd Michael Hanselmann
      logging.exception("Error while calling function in separate process")
1509 eb58f7bd Michael Hanselmann
      # 0 and 1 are reserved for the return value
1510 eb58f7bd Michael Hanselmann
      result = 33
1511 eb58f7bd Michael Hanselmann
1512 eb58f7bd Michael Hanselmann
    os._exit(result) # pylint: disable-msg=W0212
1513 eb58f7bd Michael Hanselmann
1514 eb58f7bd Michael Hanselmann
  # Parent process
1515 eb58f7bd Michael Hanselmann
1516 eb58f7bd Michael Hanselmann
  # Avoid zombies and check exit code
1517 eb58f7bd Michael Hanselmann
  (_, status) = os.waitpid(pid, 0)
1518 eb58f7bd Michael Hanselmann
1519 eb58f7bd Michael Hanselmann
  if os.WIFSIGNALED(status):
1520 eb58f7bd Michael Hanselmann
    exitcode = None
1521 eb58f7bd Michael Hanselmann
    signum = os.WTERMSIG(status)
1522 eb58f7bd Michael Hanselmann
  else:
1523 eb58f7bd Michael Hanselmann
    exitcode = os.WEXITSTATUS(status)
1524 eb58f7bd Michael Hanselmann
    signum = None
1525 eb58f7bd Michael Hanselmann
1526 eb58f7bd Michael Hanselmann
  if not (exitcode in (0, 1) and signum is None):
1527 eb58f7bd Michael Hanselmann
    raise errors.GenericError("Child program failed (code=%s, signal=%s)" %
1528 eb58f7bd Michael Hanselmann
                              (exitcode, signum))
1529 eb58f7bd Michael Hanselmann
1530 eb58f7bd Michael Hanselmann
  return bool(exitcode)
1531 eb58f7bd Michael Hanselmann
1532 eb58f7bd Michael Hanselmann
1533 451575de Guido Trotter
def SignalHandled(signums):
1534 451575de Guido Trotter
  """Signal Handled decoration.
1535 451575de Guido Trotter

1536 451575de Guido Trotter
  This special decorator installs a signal handler and then calls the target
1537 451575de Guido Trotter
  function. The function must accept a 'signal_handlers' keyword argument,
1538 451575de Guido Trotter
  which will contain a dict indexed by signal number, with SignalHandler
1539 451575de Guido Trotter
  objects as values.
1540 451575de Guido Trotter

1541 451575de Guido Trotter
  The decorator can be safely stacked with iself, to handle multiple signals
1542 451575de Guido Trotter
  with different handlers.
1543 451575de Guido Trotter

1544 451575de Guido Trotter
  @type signums: list
1545 451575de Guido Trotter
  @param signums: signals to intercept
1546 451575de Guido Trotter

1547 451575de Guido Trotter
  """
1548 451575de Guido Trotter
  def wrap(fn):
1549 451575de Guido Trotter
    def sig_function(*args, **kwargs):
1550 451575de Guido Trotter
      assert 'signal_handlers' not in kwargs or \
1551 451575de Guido Trotter
             kwargs['signal_handlers'] is None or \
1552 451575de Guido Trotter
             isinstance(kwargs['signal_handlers'], dict), \
1553 451575de Guido Trotter
             "Wrong signal_handlers parameter in original function call"
1554 451575de Guido Trotter
      if 'signal_handlers' in kwargs and kwargs['signal_handlers'] is not None:
1555 451575de Guido Trotter
        signal_handlers = kwargs['signal_handlers']
1556 451575de Guido Trotter
      else:
1557 451575de Guido Trotter
        signal_handlers = {}
1558 451575de Guido Trotter
        kwargs['signal_handlers'] = signal_handlers
1559 451575de Guido Trotter
      sighandler = SignalHandler(signums)
1560 451575de Guido Trotter
      try:
1561 451575de Guido Trotter
        for sig in signums:
1562 451575de Guido Trotter
          signal_handlers[sig] = sighandler
1563 451575de Guido Trotter
        return fn(*args, **kwargs)
1564 451575de Guido Trotter
      finally:
1565 451575de Guido Trotter
        sighandler.Reset()
1566 451575de Guido Trotter
    return sig_function
1567 451575de Guido Trotter
  return wrap
1568 451575de Guido Trotter
1569 451575de Guido Trotter
1570 b9768937 Michael Hanselmann
class SignalWakeupFd(object):
1571 b9768937 Michael Hanselmann
  try:
1572 b9768937 Michael Hanselmann
    # This is only supported in Python 2.5 and above (some distributions
1573 b9768937 Michael Hanselmann
    # backported it to Python 2.4)
1574 b9768937 Michael Hanselmann
    _set_wakeup_fd_fn = signal.set_wakeup_fd
1575 b9768937 Michael Hanselmann
  except AttributeError:
1576 b9768937 Michael Hanselmann
    # Not supported
1577 b9768937 Michael Hanselmann
    def _SetWakeupFd(self, _): # pylint: disable-msg=R0201
1578 b9768937 Michael Hanselmann
      return -1
1579 b9768937 Michael Hanselmann
  else:
1580 b9768937 Michael Hanselmann
    def _SetWakeupFd(self, fd):
1581 b9768937 Michael Hanselmann
      return self._set_wakeup_fd_fn(fd)
1582 b9768937 Michael Hanselmann
1583 b9768937 Michael Hanselmann
  def __init__(self):
1584 b9768937 Michael Hanselmann
    """Initializes this class.
1585 b9768937 Michael Hanselmann

1586 b9768937 Michael Hanselmann
    """
1587 b9768937 Michael Hanselmann
    (read_fd, write_fd) = os.pipe()
1588 b9768937 Michael Hanselmann
1589 b9768937 Michael Hanselmann
    # Once these succeeded, the file descriptors will be closed automatically.
1590 b9768937 Michael Hanselmann
    # Buffer size 0 is important, otherwise .read() with a specified length
1591 b9768937 Michael Hanselmann
    # might buffer data and the file descriptors won't be marked readable.
1592 b9768937 Michael Hanselmann
    self._read_fh = os.fdopen(read_fd, "r", 0)
1593 b9768937 Michael Hanselmann
    self._write_fh = os.fdopen(write_fd, "w", 0)
1594 b9768937 Michael Hanselmann
1595 b9768937 Michael Hanselmann
    self._previous = self._SetWakeupFd(self._write_fh.fileno())
1596 b9768937 Michael Hanselmann
1597 b9768937 Michael Hanselmann
    # Utility functions
1598 b9768937 Michael Hanselmann
    self.fileno = self._read_fh.fileno
1599 b9768937 Michael Hanselmann
    self.read = self._read_fh.read
1600 b9768937 Michael Hanselmann
1601 b9768937 Michael Hanselmann
  def Reset(self):
1602 b9768937 Michael Hanselmann
    """Restores the previous wakeup file descriptor.
1603 b9768937 Michael Hanselmann

1604 b9768937 Michael Hanselmann
    """
1605 b9768937 Michael Hanselmann
    if hasattr(self, "_previous") and self._previous is not None:
1606 b9768937 Michael Hanselmann
      self._SetWakeupFd(self._previous)
1607 b9768937 Michael Hanselmann
      self._previous = None
1608 b9768937 Michael Hanselmann
1609 b9768937 Michael Hanselmann
  def Notify(self):
1610 b9768937 Michael Hanselmann
    """Notifies the wakeup file descriptor.
1611 b9768937 Michael Hanselmann

1612 b9768937 Michael Hanselmann
    """
1613 b9768937 Michael Hanselmann
    self._write_fh.write("\0")
1614 b9768937 Michael Hanselmann
1615 b9768937 Michael Hanselmann
  def __del__(self):
1616 b9768937 Michael Hanselmann
    """Called before object deletion.
1617 b9768937 Michael Hanselmann

1618 b9768937 Michael Hanselmann
    """
1619 b9768937 Michael Hanselmann
    self.Reset()
1620 b9768937 Michael Hanselmann
1621 b9768937 Michael Hanselmann
1622 de499029 Michael Hanselmann
class SignalHandler(object):
1623 de499029 Michael Hanselmann
  """Generic signal handler class.
1624 de499029 Michael Hanselmann

1625 58885d79 Iustin Pop
  It automatically restores the original handler when deconstructed or
1626 58885d79 Iustin Pop
  when L{Reset} is called. You can either pass your own handler
1627 58885d79 Iustin Pop
  function in or query the L{called} attribute to detect whether the
1628 58885d79 Iustin Pop
  signal was sent.
1629 58885d79 Iustin Pop

1630 58885d79 Iustin Pop
  @type signum: list
1631 58885d79 Iustin Pop
  @ivar signum: the signals we handle
1632 58885d79 Iustin Pop
  @type called: boolean
1633 58885d79 Iustin Pop
  @ivar called: tracks whether any of the signals have been raised
1634 de499029 Michael Hanselmann

1635 de499029 Michael Hanselmann
  """
1636 b9768937 Michael Hanselmann
  def __init__(self, signum, handler_fn=None, wakeup=None):
1637 de499029 Michael Hanselmann
    """Constructs a new SignalHandler instance.
1638 de499029 Michael Hanselmann

1639 58885d79 Iustin Pop
    @type signum: int or list of ints
1640 de499029 Michael Hanselmann
    @param signum: Single signal number or set of signal numbers
1641 92b61ec7 Michael Hanselmann
    @type handler_fn: callable
1642 92b61ec7 Michael Hanselmann
    @param handler_fn: Signal handling function
1643 de499029 Michael Hanselmann

1644 de499029 Michael Hanselmann
    """
1645 92b61ec7 Michael Hanselmann
    assert handler_fn is None or callable(handler_fn)
1646 92b61ec7 Michael Hanselmann
1647 6c52849e Guido Trotter
    self.signum = set(signum)
1648 de499029 Michael Hanselmann
    self.called = False
1649 de499029 Michael Hanselmann
1650 92b61ec7 Michael Hanselmann
    self._handler_fn = handler_fn
1651 b9768937 Michael Hanselmann
    self._wakeup = wakeup
1652 92b61ec7 Michael Hanselmann
1653 de499029 Michael Hanselmann
    self._previous = {}
1654 de499029 Michael Hanselmann
    try:
1655 de499029 Michael Hanselmann
      for signum in self.signum:
1656 de499029 Michael Hanselmann
        # Setup handler
1657 de499029 Michael Hanselmann
        prev_handler = signal.signal(signum, self._HandleSignal)
1658 de499029 Michael Hanselmann
        try:
1659 de499029 Michael Hanselmann
          self._previous[signum] = prev_handler
1660 de499029 Michael Hanselmann
        except:
1661 de499029 Michael Hanselmann
          # Restore previous handler
1662 de499029 Michael Hanselmann
          signal.signal(signum, prev_handler)
1663 de499029 Michael Hanselmann
          raise
1664 de499029 Michael Hanselmann
    except:
1665 de499029 Michael Hanselmann
      # Reset all handlers
1666 de499029 Michael Hanselmann
      self.Reset()
1667 de499029 Michael Hanselmann
      # Here we have a race condition: a handler may have already been called,
1668 de499029 Michael Hanselmann
      # but there's not much we can do about it at this point.
1669 de499029 Michael Hanselmann
      raise
1670 de499029 Michael Hanselmann
1671 de499029 Michael Hanselmann
  def __del__(self):
1672 de499029 Michael Hanselmann
    self.Reset()
1673 de499029 Michael Hanselmann
1674 de499029 Michael Hanselmann
  def Reset(self):
1675 de499029 Michael Hanselmann
    """Restore previous handler.
1676 de499029 Michael Hanselmann

1677 58885d79 Iustin Pop
    This will reset all the signals to their previous handlers.
1678 58885d79 Iustin Pop

1679 de499029 Michael Hanselmann
    """
1680 de499029 Michael Hanselmann
    for signum, prev_handler in self._previous.items():
1681 de499029 Michael Hanselmann
      signal.signal(signum, prev_handler)
1682 de499029 Michael Hanselmann
      # If successful, remove from dict
1683 de499029 Michael Hanselmann
      del self._previous[signum]
1684 de499029 Michael Hanselmann
1685 de499029 Michael Hanselmann
  def Clear(self):
1686 58885d79 Iustin Pop
    """Unsets the L{called} flag.
1687 de499029 Michael Hanselmann

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

1690 de499029 Michael Hanselmann
    """
1691 de499029 Michael Hanselmann
    self.called = False
1692 de499029 Michael Hanselmann
1693 92b61ec7 Michael Hanselmann
  def _HandleSignal(self, signum, frame):
1694 de499029 Michael Hanselmann
    """Actual signal handling function.
1695 de499029 Michael Hanselmann

1696 de499029 Michael Hanselmann
    """
1697 de499029 Michael Hanselmann
    # This is not nice and not absolutely atomic, but it appears to be the only
1698 de499029 Michael Hanselmann
    # solution in Python -- there are no atomic types.
1699 de499029 Michael Hanselmann
    self.called = True
1700 a2d2e1a7 Iustin Pop
1701 b9768937 Michael Hanselmann
    if self._wakeup:
1702 b9768937 Michael Hanselmann
      # Notify whoever is interested in signals
1703 b9768937 Michael Hanselmann
      self._wakeup.Notify()
1704 b9768937 Michael Hanselmann
1705 92b61ec7 Michael Hanselmann
    if self._handler_fn:
1706 92b61ec7 Michael Hanselmann
      self._handler_fn(signum, frame)
1707 92b61ec7 Michael Hanselmann
1708 a2d2e1a7 Iustin Pop
1709 a2d2e1a7 Iustin Pop
class FieldSet(object):
1710 a2d2e1a7 Iustin Pop
  """A simple field set.
1711 a2d2e1a7 Iustin Pop

1712 a2d2e1a7 Iustin Pop
  Among the features are:
1713 a2d2e1a7 Iustin Pop
    - checking if a string is among a list of static string or regex objects
1714 a2d2e1a7 Iustin Pop
    - checking if a whole list of string matches
1715 a2d2e1a7 Iustin Pop
    - returning the matching groups from a regex match
1716 a2d2e1a7 Iustin Pop

1717 a2d2e1a7 Iustin Pop
  Internally, all fields are held as regular expression objects.
1718 a2d2e1a7 Iustin Pop

1719 a2d2e1a7 Iustin Pop
  """
1720 a2d2e1a7 Iustin Pop
  def __init__(self, *items):
1721 a2d2e1a7 Iustin Pop
    self.items = [re.compile("^%s$" % value) for value in items]
1722 a2d2e1a7 Iustin Pop
1723 a2d2e1a7 Iustin Pop
  def Extend(self, other_set):
1724 a2d2e1a7 Iustin Pop
    """Extend the field set with the items from another one"""
1725 a2d2e1a7 Iustin Pop
    self.items.extend(other_set.items)
1726 a2d2e1a7 Iustin Pop
1727 a2d2e1a7 Iustin Pop
  def Matches(self, field):
1728 a2d2e1a7 Iustin Pop
    """Checks if a field matches the current set
1729 a2d2e1a7 Iustin Pop

1730 a2d2e1a7 Iustin Pop
    @type field: str
1731 a2d2e1a7 Iustin Pop
    @param field: the string to match
1732 6c881c52 Iustin Pop
    @return: either None or a regular expression match object
1733 a2d2e1a7 Iustin Pop

1734 a2d2e1a7 Iustin Pop
    """
1735 a2d2e1a7 Iustin Pop
    for m in itertools.ifilter(None, (val.match(field) for val in self.items)):
1736 a2d2e1a7 Iustin Pop
      return m
1737 6c881c52 Iustin Pop
    return None
1738 a2d2e1a7 Iustin Pop
1739 a2d2e1a7 Iustin Pop
  def NonMatching(self, items):
1740 a2d2e1a7 Iustin Pop
    """Returns the list of fields not matching the current set
1741 a2d2e1a7 Iustin Pop

1742 a2d2e1a7 Iustin Pop
    @type items: list
1743 a2d2e1a7 Iustin Pop
    @param items: the list of fields to check
1744 a2d2e1a7 Iustin Pop
    @rtype: list
1745 a2d2e1a7 Iustin Pop
    @return: list of non-matching fields
1746 a2d2e1a7 Iustin Pop

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