Statistics
| Branch: | Tag: | Revision:

root / lib / utils.py @ 9f4bb951

History | View | Annotate | Download (105.7 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 600535f0 Manuel Franceschini
# Copyright (C) 2006, 2007, 2010 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 551b6283 Iustin Pop
import logging.handlers
46 de499029 Michael Hanselmann
import signal
47 bdd5e420 Michael Hanselmann
import OpenSSL
48 27e46076 Michael Hanselmann
import datetime
49 27e46076 Michael Hanselmann
import calendar
50 68857643 Michael Hanselmann
import hmac
51 339be5a8 Michael Hanselmann
import collections
52 9c233417 Iustin Pop
53 9c233417 Iustin Pop
from cStringIO import StringIO
54 a8083063 Iustin Pop
55 7ffe8fba Carlos Valiente
try:
56 23e0ef8c Guido Trotter
  # pylint: disable-msg=F0401
57 4b6fa0bf Luca Bigliardi
  import ctypes
58 4b6fa0bf Luca Bigliardi
except ImportError:
59 4b6fa0bf Luca Bigliardi
  ctypes = None
60 4b6fa0bf Luca Bigliardi
61 a8083063 Iustin Pop
from ganeti import errors
62 3aecd2c7 Iustin Pop
from ganeti import constants
63 716a32cb Guido Trotter
from ganeti import compat
64 a8083063 Iustin Pop
65 16abfbc2 Alexander Schreiber
66 a8083063 Iustin Pop
_locksheld = []
67 a8083063 Iustin Pop
_re_shell_unquoted = re.compile('^[-.,=:/_+@A-Za-z0-9]+$')
68 a8083063 Iustin Pop
69 e67bd559 Michael Hanselmann
debug_locks = False
70 58885d79 Iustin Pop
71 58885d79 Iustin Pop
#: when set to True, L{RunCmd} is disabled
72 b74159ee Iustin Pop
no_fork = False
73 f362096f Iustin Pop
74 13998ef2 Michael Hanselmann
_RANDOM_UUID_FILE = "/proc/sys/kernel/random/uuid"
75 13998ef2 Michael Hanselmann
76 68857643 Michael Hanselmann
HEX_CHAR_RE = r"[a-zA-Z0-9]"
77 68857643 Michael Hanselmann
VALID_X509_SIGNATURE_SALT = re.compile("^%s+$" % HEX_CHAR_RE, re.S)
78 68857643 Michael Hanselmann
X509_SIGNATURE = re.compile(r"^%s:\s*(?P<salt>%s+)/(?P<sign>%s+)$" %
79 68857643 Michael Hanselmann
                            (re.escape(constants.X509_CERT_SIGNATURE_HEADER),
80 68857643 Michael Hanselmann
                             HEX_CHAR_RE, HEX_CHAR_RE),
81 68857643 Michael Hanselmann
                            re.S | re.I)
82 68857643 Michael Hanselmann
83 28f34048 Michael Hanselmann
_VALID_SERVICE_NAME_RE = re.compile("^[-_.a-zA-Z0-9]{1,128}$")
84 28f34048 Michael Hanselmann
85 05636402 Guido Trotter
UUID_RE = re.compile('^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-'
86 05636402 Guido Trotter
                     '[a-f0-9]{4}-[a-f0-9]{12}$')
87 05636402 Guido Trotter
88 24d70417 Michael Hanselmann
# Certificate verification results
89 24d70417 Michael Hanselmann
(CERT_WARNING,
90 24d70417 Michael Hanselmann
 CERT_ERROR) = range(1, 3)
91 24d70417 Michael Hanselmann
92 4b6fa0bf Luca Bigliardi
# Flags for mlockall() (from bits/mman.h)
93 4b6fa0bf Luca Bigliardi
_MCL_CURRENT = 1
94 4b6fa0bf Luca Bigliardi
_MCL_FUTURE = 2
95 4b6fa0bf Luca Bigliardi
96 8fb00704 Iustin Pop
#: MAC checker regexp
97 8fb00704 Iustin Pop
_MAC_CHECK = re.compile("^([0-9a-f]{2}:){5}[0-9a-f]{2}$", re.I)
98 8fb00704 Iustin Pop
99 7c0d6283 Michael Hanselmann
100 a8083063 Iustin Pop
class RunResult(object):
101 58885d79 Iustin Pop
  """Holds the result of running external programs.
102 58885d79 Iustin Pop

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

118 a8083063 Iustin Pop
  """
119 a8083063 Iustin Pop
  __slots__ = ["exit_code", "signal", "stdout", "stderr",
120 a8083063 Iustin Pop
               "failed", "fail_reason", "cmd"]
121 a8083063 Iustin Pop
122 a8083063 Iustin Pop
123 38206f3c Iustin Pop
  def __init__(self, exit_code, signal_, stdout, stderr, cmd):
124 a8083063 Iustin Pop
    self.cmd = cmd
125 a8083063 Iustin Pop
    self.exit_code = exit_code
126 38206f3c Iustin Pop
    self.signal = signal_
127 a8083063 Iustin Pop
    self.stdout = stdout
128 a8083063 Iustin Pop
    self.stderr = stderr
129 38206f3c Iustin Pop
    self.failed = (signal_ is not None or exit_code != 0)
130 a8083063 Iustin Pop
131 a8083063 Iustin Pop
    if self.signal is not None:
132 a8083063 Iustin Pop
      self.fail_reason = "terminated by signal %s" % self.signal
133 a8083063 Iustin Pop
    elif self.exit_code is not None:
134 a8083063 Iustin Pop
      self.fail_reason = "exited with exit code %s" % self.exit_code
135 a8083063 Iustin Pop
    else:
136 a8083063 Iustin Pop
      self.fail_reason = "unable to determine termination reason"
137 a8083063 Iustin Pop
138 bb698c1f Iustin Pop
    if self.failed:
139 bb698c1f Iustin Pop
      logging.debug("Command '%s' failed (%s); output: %s",
140 bb698c1f Iustin Pop
                    self.cmd, self.fail_reason, self.output)
141 f362096f Iustin Pop
142 a8083063 Iustin Pop
  def _GetOutput(self):
143 a8083063 Iustin Pop
    """Returns the combined stdout and stderr for easier usage.
144 a8083063 Iustin Pop

145 a8083063 Iustin Pop
    """
146 a8083063 Iustin Pop
    return self.stdout + self.stderr
147 a8083063 Iustin Pop
148 a8083063 Iustin Pop
  output = property(_GetOutput, None, None, "Return full output")
149 a8083063 Iustin Pop
150 a8083063 Iustin Pop
151 bb3776b4 Michael Hanselmann
def _BuildCmdEnvironment(env, reset):
152 c1dd99d4 Michael Hanselmann
  """Builds the environment for an external program.
153 c1dd99d4 Michael Hanselmann

154 c1dd99d4 Michael Hanselmann
  """
155 bb3776b4 Michael Hanselmann
  if reset:
156 bb3776b4 Michael Hanselmann
    cmd_env = {}
157 bb3776b4 Michael Hanselmann
  else:
158 bb3776b4 Michael Hanselmann
    cmd_env = os.environ.copy()
159 bb3776b4 Michael Hanselmann
    cmd_env["LC_ALL"] = "C"
160 bb3776b4 Michael Hanselmann
161 c1dd99d4 Michael Hanselmann
  if env is not None:
162 c1dd99d4 Michael Hanselmann
    cmd_env.update(env)
163 bb3776b4 Michael Hanselmann
164 c1dd99d4 Michael Hanselmann
  return cmd_env
165 c1dd99d4 Michael Hanselmann
166 c1dd99d4 Michael Hanselmann
167 0963d545 Renรฉ Nussbaumer
def RunCmd(cmd, env=None, output=None, cwd="/", reset_env=False,
168 0963d545 Renรฉ Nussbaumer
           interactive=False):
169 a8083063 Iustin Pop
  """Execute a (shell) command.
170 a8083063 Iustin Pop

171 a8083063 Iustin Pop
  The command should not read from its standard input, as it will be
172 a8083063 Iustin Pop
  closed.
173 a8083063 Iustin Pop

174 c1dd99d4 Michael Hanselmann
  @type cmd: string or list
175 36117c2b Iustin Pop
  @param cmd: Command to run
176 2557ff82 Guido Trotter
  @type env: dict
177 c1dd99d4 Michael Hanselmann
  @param env: Additional environment variables
178 36117c2b Iustin Pop
  @type output: str
179 58885d79 Iustin Pop
  @param output: if desired, the output of the command can be
180 36117c2b Iustin Pop
      saved in a file instead of the RunResult instance; this
181 36117c2b Iustin Pop
      parameter denotes the file name (if not None)
182 8797df43 Iustin Pop
  @type cwd: string
183 8797df43 Iustin Pop
  @param cwd: if specified, will be used as the working
184 8797df43 Iustin Pop
      directory for the command; the default will be /
185 bf4daac9 Guido Trotter
  @type reset_env: boolean
186 bf4daac9 Guido Trotter
  @param reset_env: whether to reset or keep the default os environment
187 0963d545 Renรฉ Nussbaumer
  @type interactive: boolean
188 0963d545 Renรฉ Nussbaumer
  @param interactive: weather we pipe stdin, stdout and stderr
189 0963d545 Renรฉ Nussbaumer
                      (default behaviour) or run the command interactive
190 36117c2b Iustin Pop
  @rtype: L{RunResult}
191 58885d79 Iustin Pop
  @return: RunResult instance
192 5bbd3f7f Michael Hanselmann
  @raise errors.ProgrammerError: if we call this when forks are disabled
193 a8083063 Iustin Pop

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

243 0260032c Iustin Pop
  This should be called between the first and second fork, due to
244 0260032c Iustin Pop
  setsid usage.
245 0260032c Iustin Pop

246 0260032c Iustin Pop
  @param cwd: the directory to which to chdir
247 0260032c Iustin Pop
  @param umask: the umask to setup
248 0260032c Iustin Pop

249 0260032c Iustin Pop
  """
250 0260032c Iustin Pop
  os.chdir(cwd)
251 0260032c Iustin Pop
  os.umask(umask)
252 0260032c Iustin Pop
  os.setsid()
253 0260032c Iustin Pop
254 0260032c Iustin Pop
255 79634555 Iustin Pop
def SetupDaemonFDs(output_file, output_fd):
256 79634555 Iustin Pop
  """Setups up a daemon's file descriptors.
257 79634555 Iustin Pop

258 79634555 Iustin Pop
  @param output_file: if not None, the file to which to redirect
259 79634555 Iustin Pop
      stdout/stderr
260 79634555 Iustin Pop
  @param output_fd: if not None, the file descriptor for stdout/stderr
261 79634555 Iustin Pop

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

291 c1dd99d4 Michael Hanselmann
  @type cmd: string or list
292 c1dd99d4 Michael Hanselmann
  @param cmd: Command to run
293 c1dd99d4 Michael Hanselmann
  @type env: dict
294 c1dd99d4 Michael Hanselmann
  @param env: Additional environment variables
295 c1dd99d4 Michael Hanselmann
  @type cwd: string
296 c1dd99d4 Michael Hanselmann
  @param cwd: Working directory for the program
297 c1dd99d4 Michael Hanselmann
  @type output: string
298 c1dd99d4 Michael Hanselmann
  @param output: Path to file in which to save the output
299 c1dd99d4 Michael Hanselmann
  @type output_fd: int
300 c1dd99d4 Michael Hanselmann
  @param output_fd: File descriptor for output
301 c1dd99d4 Michael Hanselmann
  @type pidfile: string
302 c1dd99d4 Michael Hanselmann
  @param pidfile: Process ID file
303 c1dd99d4 Michael Hanselmann
  @rtype: int
304 c1dd99d4 Michael Hanselmann
  @return: Daemon process ID
305 c1dd99d4 Michael Hanselmann
  @raise errors.ProgrammerError: if we call this when forks are disabled
306 c1dd99d4 Michael Hanselmann

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

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

449 ed3920e3 Iustin Pop
  @type fd: None or int (file descriptor)
450 ed3920e3 Iustin Pop
  @param fd: if not None, the error will be written to this fd
451 ed3920e3 Iustin Pop
  @param err: string, the error message
452 ed3920e3 Iustin Pop

453 ed3920e3 Iustin Pop
  """
454 ed3920e3 Iustin Pop
  if fd is None:
455 ed3920e3 Iustin Pop
    return
456 ed3920e3 Iustin Pop
457 ed3920e3 Iustin Pop
  if not err:
458 ed3920e3 Iustin Pop
    err = "<unknown error>"
459 ed3920e3 Iustin Pop
460 ed3920e3 Iustin Pop
  RetryOnSignal(os.write, fd, err)
461 ed3920e3 Iustin Pop
462 ed3920e3 Iustin Pop
463 0963d545 Renรฉ Nussbaumer
def _RunCmdPipe(cmd, env, via_shell, cwd, interactive):
464 36117c2b Iustin Pop
  """Run a command and return its output.
465 36117c2b Iustin Pop

466 36117c2b Iustin Pop
  @type  cmd: string or list
467 36117c2b Iustin Pop
  @param cmd: Command to run
468 36117c2b Iustin Pop
  @type env: dict
469 36117c2b Iustin Pop
  @param env: The environment to use
470 36117c2b Iustin Pop
  @type via_shell: bool
471 36117c2b Iustin Pop
  @param via_shell: if we should run via the shell
472 8797df43 Iustin Pop
  @type cwd: string
473 8797df43 Iustin Pop
  @param cwd: the working directory for the program
474 0963d545 Renรฉ Nussbaumer
  @type interactive: boolean
475 0963d545 Renรฉ Nussbaumer
  @param interactive: Run command interactive (without piping)
476 36117c2b Iustin Pop
  @rtype: tuple
477 36117c2b Iustin Pop
  @return: (out, err, status)
478 36117c2b Iustin Pop

479 36117c2b Iustin Pop
  """
480 9c233417 Iustin Pop
  poller = select.poll()
481 0963d545 Renรฉ Nussbaumer
482 0963d545 Renรฉ Nussbaumer
  stderr = subprocess.PIPE
483 0963d545 Renรฉ Nussbaumer
  stdout = subprocess.PIPE
484 0963d545 Renรฉ Nussbaumer
  stdin = subprocess.PIPE
485 0963d545 Renรฉ Nussbaumer
486 0963d545 Renรฉ Nussbaumer
  if interactive:
487 0963d545 Renรฉ Nussbaumer
    stderr = stdout = stdin = None
488 0963d545 Renรฉ Nussbaumer
489 36117c2b Iustin Pop
  child = subprocess.Popen(cmd, shell=via_shell,
490 0963d545 Renรฉ Nussbaumer
                           stderr=stderr,
491 0963d545 Renรฉ Nussbaumer
                           stdout=stdout,
492 0963d545 Renรฉ Nussbaumer
                           stdin=stdin,
493 8797df43 Iustin Pop
                           close_fds=True, env=env,
494 8797df43 Iustin Pop
                           cwd=cwd)
495 113b55aa Iustin Pop
496 9c233417 Iustin Pop
  out = StringIO()
497 9c233417 Iustin Pop
  err = StringIO()
498 0963d545 Renรฉ Nussbaumer
  if not interactive:
499 0963d545 Renรฉ Nussbaumer
    child.stdin.close()
500 0963d545 Renรฉ Nussbaumer
    poller.register(child.stdout, select.POLLIN)
501 0963d545 Renรฉ Nussbaumer
    poller.register(child.stderr, select.POLLIN)
502 0963d545 Renรฉ Nussbaumer
    fdmap = {
503 0963d545 Renรฉ Nussbaumer
      child.stdout.fileno(): (out, child.stdout),
504 0963d545 Renรฉ Nussbaumer
      child.stderr.fileno(): (err, child.stderr),
505 0963d545 Renรฉ Nussbaumer
      }
506 0963d545 Renรฉ Nussbaumer
    for fd in fdmap:
507 0963d545 Renรฉ Nussbaumer
      SetNonblockFlag(fd, True)
508 0963d545 Renรฉ Nussbaumer
509 0963d545 Renรฉ Nussbaumer
    while fdmap:
510 0963d545 Renรฉ Nussbaumer
      pollresult = RetryOnSignal(poller.poll)
511 0963d545 Renรฉ Nussbaumer
512 0963d545 Renรฉ Nussbaumer
      for fd, event in pollresult:
513 0963d545 Renรฉ Nussbaumer
        if event & select.POLLIN or event & select.POLLPRI:
514 0963d545 Renรฉ Nussbaumer
          data = fdmap[fd][1].read()
515 0963d545 Renรฉ Nussbaumer
          # no data from read signifies EOF (the same as POLLHUP)
516 0963d545 Renรฉ Nussbaumer
          if not data:
517 0963d545 Renรฉ Nussbaumer
            poller.unregister(fd)
518 0963d545 Renรฉ Nussbaumer
            del fdmap[fd]
519 0963d545 Renรฉ Nussbaumer
            continue
520 0963d545 Renรฉ Nussbaumer
          fdmap[fd][0].write(data)
521 0963d545 Renรฉ Nussbaumer
        if (event & select.POLLNVAL or event & select.POLLHUP or
522 0963d545 Renรฉ Nussbaumer
            event & select.POLLERR):
523 9c233417 Iustin Pop
          poller.unregister(fd)
524 9c233417 Iustin Pop
          del fdmap[fd]
525 9c233417 Iustin Pop
526 9c233417 Iustin Pop
  out = out.getvalue()
527 9c233417 Iustin Pop
  err = err.getvalue()
528 a8083063 Iustin Pop
529 a8083063 Iustin Pop
  status = child.wait()
530 36117c2b Iustin Pop
  return out, err, status
531 a8083063 Iustin Pop
532 36117c2b Iustin Pop
533 8797df43 Iustin Pop
def _RunCmdFile(cmd, env, via_shell, output, cwd):
534 36117c2b Iustin Pop
  """Run a command and save its output to a file.
535 36117c2b Iustin Pop

536 36117c2b Iustin Pop
  @type  cmd: string or list
537 36117c2b Iustin Pop
  @param cmd: Command to run
538 36117c2b Iustin Pop
  @type env: dict
539 36117c2b Iustin Pop
  @param env: The environment to use
540 36117c2b Iustin Pop
  @type via_shell: bool
541 36117c2b Iustin Pop
  @param via_shell: if we should run via the shell
542 36117c2b Iustin Pop
  @type output: str
543 36117c2b Iustin Pop
  @param output: the filename in which to save the output
544 8797df43 Iustin Pop
  @type cwd: string
545 8797df43 Iustin Pop
  @param cwd: the working directory for the program
546 36117c2b Iustin Pop
  @rtype: int
547 36117c2b Iustin Pop
  @return: the exit status
548 36117c2b Iustin Pop

549 36117c2b Iustin Pop
  """
550 36117c2b Iustin Pop
  fh = open(output, "a")
551 36117c2b Iustin Pop
  try:
552 36117c2b Iustin Pop
    child = subprocess.Popen(cmd, shell=via_shell,
553 36117c2b Iustin Pop
                             stderr=subprocess.STDOUT,
554 36117c2b Iustin Pop
                             stdout=fh,
555 36117c2b Iustin Pop
                             stdin=subprocess.PIPE,
556 8797df43 Iustin Pop
                             close_fds=True, env=env,
557 8797df43 Iustin Pop
                             cwd=cwd)
558 36117c2b Iustin Pop
559 36117c2b Iustin Pop
    child.stdin.close()
560 36117c2b Iustin Pop
    status = child.wait()
561 36117c2b Iustin Pop
  finally:
562 36117c2b Iustin Pop
    fh.close()
563 36117c2b Iustin Pop
  return status
564 a8083063 Iustin Pop
565 a8083063 Iustin Pop
566 73027ed2 Michael Hanselmann
def SetCloseOnExecFlag(fd, enable):
567 73027ed2 Michael Hanselmann
  """Sets or unsets the close-on-exec flag on a file descriptor.
568 73027ed2 Michael Hanselmann

569 73027ed2 Michael Hanselmann
  @type fd: int
570 73027ed2 Michael Hanselmann
  @param fd: File descriptor
571 73027ed2 Michael Hanselmann
  @type enable: bool
572 73027ed2 Michael Hanselmann
  @param enable: Whether to set or unset it.
573 73027ed2 Michael Hanselmann

574 73027ed2 Michael Hanselmann
  """
575 73027ed2 Michael Hanselmann
  flags = fcntl.fcntl(fd, fcntl.F_GETFD)
576 73027ed2 Michael Hanselmann
577 73027ed2 Michael Hanselmann
  if enable:
578 73027ed2 Michael Hanselmann
    flags |= fcntl.FD_CLOEXEC
579 73027ed2 Michael Hanselmann
  else:
580 73027ed2 Michael Hanselmann
    flags &= ~fcntl.FD_CLOEXEC
581 73027ed2 Michael Hanselmann
582 73027ed2 Michael Hanselmann
  fcntl.fcntl(fd, fcntl.F_SETFD, flags)
583 73027ed2 Michael Hanselmann
584 73027ed2 Michael Hanselmann
585 287a1740 Michael Hanselmann
def SetNonblockFlag(fd, enable):
586 287a1740 Michael Hanselmann
  """Sets or unsets the O_NONBLOCK flag on on a file descriptor.
587 287a1740 Michael Hanselmann

588 287a1740 Michael Hanselmann
  @type fd: int
589 287a1740 Michael Hanselmann
  @param fd: File descriptor
590 287a1740 Michael Hanselmann
  @type enable: bool
591 287a1740 Michael Hanselmann
  @param enable: Whether to set or unset it
592 287a1740 Michael Hanselmann

593 287a1740 Michael Hanselmann
  """
594 287a1740 Michael Hanselmann
  flags = fcntl.fcntl(fd, fcntl.F_GETFL)
595 287a1740 Michael Hanselmann
596 287a1740 Michael Hanselmann
  if enable:
597 287a1740 Michael Hanselmann
    flags |= os.O_NONBLOCK
598 287a1740 Michael Hanselmann
  else:
599 287a1740 Michael Hanselmann
    flags &= ~os.O_NONBLOCK
600 287a1740 Michael Hanselmann
601 287a1740 Michael Hanselmann
  fcntl.fcntl(fd, fcntl.F_SETFL, flags)
602 287a1740 Michael Hanselmann
603 287a1740 Michael Hanselmann
604 edcb5d9e Michael Hanselmann
def RetryOnSignal(fn, *args, **kwargs):
605 edcb5d9e Michael Hanselmann
  """Calls a function again if it failed due to EINTR.
606 edcb5d9e Michael Hanselmann

607 edcb5d9e Michael Hanselmann
  """
608 edcb5d9e Michael Hanselmann
  while True:
609 edcb5d9e Michael Hanselmann
    try:
610 edcb5d9e Michael Hanselmann
      return fn(*args, **kwargs)
611 965d0e5b Guido Trotter
    except EnvironmentError, err:
612 edcb5d9e Michael Hanselmann
      if err.errno != errno.EINTR:
613 edcb5d9e Michael Hanselmann
        raise
614 965d0e5b Guido Trotter
    except (socket.error, select.error), err:
615 965d0e5b Guido Trotter
      # In python 2.6 and above select.error is an IOError, so it's handled
616 965d0e5b Guido Trotter
      # above, in 2.5 and below it's not, and it's handled here.
617 edcb5d9e Michael Hanselmann
      if not (err.args and err.args[0] == errno.EINTR):
618 edcb5d9e Michael Hanselmann
        raise
619 edcb5d9e Michael Hanselmann
620 edcb5d9e Michael Hanselmann
621 6bb65e3a Guido Trotter
def RunParts(dir_name, env=None, reset_env=False):
622 6bb65e3a Guido Trotter
  """Run Scripts or programs in a directory
623 6bb65e3a Guido Trotter

624 6bb65e3a Guido Trotter
  @type dir_name: string
625 6bb65e3a Guido Trotter
  @param dir_name: absolute path to a directory
626 6bb65e3a Guido Trotter
  @type env: dict
627 6bb65e3a Guido Trotter
  @param env: The environment to use
628 6bb65e3a Guido Trotter
  @type reset_env: boolean
629 6bb65e3a Guido Trotter
  @param reset_env: whether to reset or keep the default os environment
630 6bb65e3a Guido Trotter
  @rtype: list of tuples
631 6bb65e3a Guido Trotter
  @return: list of (name, (one of RUNDIR_STATUS), RunResult)
632 6bb65e3a Guido Trotter

633 6bb65e3a Guido Trotter
  """
634 6bb65e3a Guido Trotter
  rr = []
635 6bb65e3a Guido Trotter
636 6bb65e3a Guido Trotter
  try:
637 6bb65e3a Guido Trotter
    dir_contents = ListVisibleFiles(dir_name)
638 6bb65e3a Guido Trotter
  except OSError, err:
639 6bb65e3a Guido Trotter
    logging.warning("RunParts: skipping %s (cannot list: %s)", dir_name, err)
640 6bb65e3a Guido Trotter
    return rr
641 6bb65e3a Guido Trotter
642 6bb65e3a Guido Trotter
  for relname in sorted(dir_contents):
643 c4feafe8 Iustin Pop
    fname = PathJoin(dir_name, relname)
644 6bb65e3a Guido Trotter
    if not (os.path.isfile(fname) and os.access(fname, os.X_OK) and
645 6bb65e3a Guido Trotter
            constants.EXT_PLUGIN_MASK.match(relname) is not None):
646 6bb65e3a Guido Trotter
      rr.append((relname, constants.RUNPARTS_SKIP, None))
647 6bb65e3a Guido Trotter
    else:
648 6bb65e3a Guido Trotter
      try:
649 6bb65e3a Guido Trotter
        result = RunCmd([fname], env=env, reset_env=reset_env)
650 6bb65e3a Guido Trotter
      except Exception, err: # pylint: disable-msg=W0703
651 6bb65e3a Guido Trotter
        rr.append((relname, constants.RUNPARTS_ERR, str(err)))
652 6bb65e3a Guido Trotter
      else:
653 6bb65e3a Guido Trotter
        rr.append((relname, constants.RUNPARTS_RUN, result))
654 6bb65e3a Guido Trotter
655 6bb65e3a Guido Trotter
  return rr
656 6bb65e3a Guido Trotter
657 6bb65e3a Guido Trotter
658 a8083063 Iustin Pop
def RemoveFile(filename):
659 a8083063 Iustin Pop
  """Remove a file ignoring some errors.
660 a8083063 Iustin Pop

661 a8083063 Iustin Pop
  Remove a file, ignoring non-existing ones or directories. Other
662 a8083063 Iustin Pop
  errors are passed.
663 a8083063 Iustin Pop

664 58885d79 Iustin Pop
  @type filename: str
665 58885d79 Iustin Pop
  @param filename: the file to be removed
666 58885d79 Iustin Pop

667 a8083063 Iustin Pop
  """
668 a8083063 Iustin Pop
  try:
669 a8083063 Iustin Pop
    os.unlink(filename)
670 a8083063 Iustin Pop
  except OSError, err:
671 4ca1b175 Alexander Schreiber
    if err.errno not in (errno.ENOENT, errno.EISDIR):
672 a8083063 Iustin Pop
      raise
673 a8083063 Iustin Pop
674 72087dcd Balazs Lecz
675 72087dcd Balazs Lecz
def RemoveDir(dirname):
676 72087dcd Balazs Lecz
  """Remove an empty directory.
677 72087dcd Balazs Lecz

678 72087dcd Balazs Lecz
  Remove a directory, ignoring non-existing ones.
679 72087dcd Balazs Lecz
  Other errors are passed. This includes the case,
680 72087dcd Balazs Lecz
  where the directory is not empty, so it can't be removed.
681 72087dcd Balazs Lecz

682 72087dcd Balazs Lecz
  @type dirname: str
683 72087dcd Balazs Lecz
  @param dirname: the empty directory to be removed
684 72087dcd Balazs Lecz

685 72087dcd Balazs Lecz
  """
686 72087dcd Balazs Lecz
  try:
687 72087dcd Balazs Lecz
    os.rmdir(dirname)
688 72087dcd Balazs Lecz
  except OSError, err:
689 72087dcd Balazs Lecz
    if err.errno != errno.ENOENT:
690 72087dcd Balazs Lecz
      raise
691 72087dcd Balazs Lecz
692 a8083063 Iustin Pop
693 6e797216 Michael Hanselmann
def RenameFile(old, new, mkdir=False, mkdir_mode=0750):
694 6e797216 Michael Hanselmann
  """Renames a file.
695 6e797216 Michael Hanselmann

696 6e797216 Michael Hanselmann
  @type old: string
697 6e797216 Michael Hanselmann
  @param old: Original path
698 6e797216 Michael Hanselmann
  @type new: string
699 6e797216 Michael Hanselmann
  @param new: New path
700 6e797216 Michael Hanselmann
  @type mkdir: bool
701 6e797216 Michael Hanselmann
  @param mkdir: Whether to create target directory if it doesn't exist
702 6e797216 Michael Hanselmann
  @type mkdir_mode: int
703 6e797216 Michael Hanselmann
  @param mkdir_mode: Mode for newly created directories
704 6e797216 Michael Hanselmann

705 6e797216 Michael Hanselmann
  """
706 6e797216 Michael Hanselmann
  try:
707 6e797216 Michael Hanselmann
    return os.rename(old, new)
708 6e797216 Michael Hanselmann
  except OSError, err:
709 6e797216 Michael Hanselmann
    # In at least one use case of this function, the job queue, directory
710 6e797216 Michael Hanselmann
    # creation is very rare. Checking for the directory before renaming is not
711 6e797216 Michael Hanselmann
    # as efficient.
712 6e797216 Michael Hanselmann
    if mkdir and err.errno == errno.ENOENT:
713 6e797216 Michael Hanselmann
      # Create directory and try again
714 cc2f004d Michael Hanselmann
      Makedirs(os.path.dirname(new), mode=mkdir_mode)
715 a426508d Michael Hanselmann
716 6e797216 Michael Hanselmann
      return os.rename(old, new)
717 a426508d Michael Hanselmann
718 6e797216 Michael Hanselmann
    raise
719 6e797216 Michael Hanselmann
720 6e797216 Michael Hanselmann
721 76e5f8b5 Michael Hanselmann
def Makedirs(path, mode=0750):
722 76e5f8b5 Michael Hanselmann
  """Super-mkdir; create a leaf directory and all intermediate ones.
723 76e5f8b5 Michael Hanselmann

724 76e5f8b5 Michael Hanselmann
  This is a wrapper around C{os.makedirs} adding error handling not implemented
725 76e5f8b5 Michael Hanselmann
  before Python 2.5.
726 76e5f8b5 Michael Hanselmann

727 76e5f8b5 Michael Hanselmann
  """
728 76e5f8b5 Michael Hanselmann
  try:
729 76e5f8b5 Michael Hanselmann
    os.makedirs(path, mode)
730 76e5f8b5 Michael Hanselmann
  except OSError, err:
731 76e5f8b5 Michael Hanselmann
    # Ignore EEXIST. This is only handled in os.makedirs as included in
732 76e5f8b5 Michael Hanselmann
    # Python 2.5 and above.
733 76e5f8b5 Michael Hanselmann
    if err.errno != errno.EEXIST or not os.path.exists(path):
734 76e5f8b5 Michael Hanselmann
      raise
735 76e5f8b5 Michael Hanselmann
736 76e5f8b5 Michael Hanselmann
737 055f822b Michael Hanselmann
def ResetTempfileModule():
738 055f822b Michael Hanselmann
  """Resets the random name generator of the tempfile module.
739 055f822b Michael Hanselmann

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

746 055f822b Michael Hanselmann
  """
747 055f822b Michael Hanselmann
  # pylint: disable-msg=W0212
748 055f822b Michael Hanselmann
  if hasattr(tempfile, "_once_lock") and hasattr(tempfile, "_name_sequence"):
749 055f822b Michael Hanselmann
    tempfile._once_lock.acquire()
750 055f822b Michael Hanselmann
    try:
751 055f822b Michael Hanselmann
      # Reset random name generator
752 055f822b Michael Hanselmann
      tempfile._name_sequence = None
753 055f822b Michael Hanselmann
    finally:
754 055f822b Michael Hanselmann
      tempfile._once_lock.release()
755 055f822b Michael Hanselmann
  else:
756 055f822b Michael Hanselmann
    logging.critical("The tempfile module misses at least one of the"
757 055f822b Michael Hanselmann
                     " '_once_lock' and '_name_sequence' attributes")
758 055f822b Michael Hanselmann
759 055f822b Michael Hanselmann
760 a8083063 Iustin Pop
def _FingerprintFile(filename):
761 a8083063 Iustin Pop
  """Compute the fingerprint of a file.
762 a8083063 Iustin Pop

763 a8083063 Iustin Pop
  If the file does not exist, a None will be returned
764 a8083063 Iustin Pop
  instead.
765 a8083063 Iustin Pop

766 58885d79 Iustin Pop
  @type filename: str
767 58885d79 Iustin Pop
  @param filename: the filename to checksum
768 58885d79 Iustin Pop
  @rtype: str
769 58885d79 Iustin Pop
  @return: the hex digest of the sha checksum of the contents
770 58885d79 Iustin Pop
      of the file
771 a8083063 Iustin Pop

772 a8083063 Iustin Pop
  """
773 a8083063 Iustin Pop
  if not (os.path.exists(filename) and os.path.isfile(filename)):
774 a8083063 Iustin Pop
    return None
775 a8083063 Iustin Pop
776 a8083063 Iustin Pop
  f = open(filename)
777 a8083063 Iustin Pop
778 716a32cb Guido Trotter
  fp = compat.sha1_hash()
779 a8083063 Iustin Pop
  while True:
780 a8083063 Iustin Pop
    data = f.read(4096)
781 a8083063 Iustin Pop
    if not data:
782 a8083063 Iustin Pop
      break
783 a8083063 Iustin Pop
784 a8083063 Iustin Pop
    fp.update(data)
785 a8083063 Iustin Pop
786 a8083063 Iustin Pop
  return fp.hexdigest()
787 a8083063 Iustin Pop
788 a8083063 Iustin Pop
789 a8083063 Iustin Pop
def FingerprintFiles(files):
790 a8083063 Iustin Pop
  """Compute fingerprints for a list of files.
791 a8083063 Iustin Pop

792 58885d79 Iustin Pop
  @type files: list
793 58885d79 Iustin Pop
  @param files: the list of filename to fingerprint
794 58885d79 Iustin Pop
  @rtype: dict
795 58885d79 Iustin Pop
  @return: a dictionary filename: fingerprint, holding only
796 58885d79 Iustin Pop
      existing files
797 a8083063 Iustin Pop

798 a8083063 Iustin Pop
  """
799 a8083063 Iustin Pop
  ret = {}
800 a8083063 Iustin Pop
801 a8083063 Iustin Pop
  for filename in files:
802 a8083063 Iustin Pop
    cksum = _FingerprintFile(filename)
803 a8083063 Iustin Pop
    if cksum:
804 a8083063 Iustin Pop
      ret[filename] = cksum
805 a8083063 Iustin Pop
806 a8083063 Iustin Pop
  return ret
807 a8083063 Iustin Pop
808 a8083063 Iustin Pop
809 a5728081 Guido Trotter
def ForceDictType(target, key_types, allowed_values=None):
810 a5728081 Guido Trotter
  """Force the values of a dict to have certain types.
811 a5728081 Guido Trotter

812 a5728081 Guido Trotter
  @type target: dict
813 a5728081 Guido Trotter
  @param target: the dict to update
814 a5728081 Guido Trotter
  @type key_types: dict
815 a5728081 Guido Trotter
  @param key_types: dict mapping target dict keys to types
816 a5728081 Guido Trotter
                    in constants.ENFORCEABLE_TYPES
817 a5728081 Guido Trotter
  @type allowed_values: list
818 a5728081 Guido Trotter
  @keyword allowed_values: list of specially allowed values
819 a5728081 Guido Trotter

820 a5728081 Guido Trotter
  """
821 a5728081 Guido Trotter
  if allowed_values is None:
822 a5728081 Guido Trotter
    allowed_values = []
823 a5728081 Guido Trotter
824 8b46606c Guido Trotter
  if not isinstance(target, dict):
825 8b46606c Guido Trotter
    msg = "Expected dictionary, got '%s'" % target
826 8b46606c Guido Trotter
    raise errors.TypeEnforcementError(msg)
827 8b46606c Guido Trotter
828 a5728081 Guido Trotter
  for key in target:
829 a5728081 Guido Trotter
    if key not in key_types:
830 a5728081 Guido Trotter
      msg = "Unknown key '%s'" % key
831 a5728081 Guido Trotter
      raise errors.TypeEnforcementError(msg)
832 a5728081 Guido Trotter
833 a5728081 Guido Trotter
    if target[key] in allowed_values:
834 a5728081 Guido Trotter
      continue
835 a5728081 Guido Trotter
836 29921401 Iustin Pop
    ktype = key_types[key]
837 29921401 Iustin Pop
    if ktype not in constants.ENFORCEABLE_TYPES:
838 29921401 Iustin Pop
      msg = "'%s' has non-enforceable type %s" % (key, ktype)
839 a5728081 Guido Trotter
      raise errors.ProgrammerError(msg)
840 a5728081 Guido Trotter
841 59525e1f Michael Hanselmann
    if ktype in (constants.VTYPE_STRING, constants.VTYPE_MAYBE_STRING):
842 59525e1f Michael Hanselmann
      if target[key] is None and ktype == constants.VTYPE_MAYBE_STRING:
843 59525e1f Michael Hanselmann
        pass
844 59525e1f Michael Hanselmann
      elif not isinstance(target[key], basestring):
845 a5728081 Guido Trotter
        if isinstance(target[key], bool) and not target[key]:
846 a5728081 Guido Trotter
          target[key] = ''
847 a5728081 Guido Trotter
        else:
848 a5728081 Guido Trotter
          msg = "'%s' (value %s) is not a valid string" % (key, target[key])
849 a5728081 Guido Trotter
          raise errors.TypeEnforcementError(msg)
850 29921401 Iustin Pop
    elif ktype == constants.VTYPE_BOOL:
851 a5728081 Guido Trotter
      if isinstance(target[key], basestring) and target[key]:
852 a5728081 Guido Trotter
        if target[key].lower() == constants.VALUE_FALSE:
853 a5728081 Guido Trotter
          target[key] = False
854 a5728081 Guido Trotter
        elif target[key].lower() == constants.VALUE_TRUE:
855 a5728081 Guido Trotter
          target[key] = True
856 a5728081 Guido Trotter
        else:
857 a5728081 Guido Trotter
          msg = "'%s' (value %s) is not a valid boolean" % (key, target[key])
858 a5728081 Guido Trotter
          raise errors.TypeEnforcementError(msg)
859 a5728081 Guido Trotter
      elif target[key]:
860 a5728081 Guido Trotter
        target[key] = True
861 a5728081 Guido Trotter
      else:
862 a5728081 Guido Trotter
        target[key] = False
863 29921401 Iustin Pop
    elif ktype == constants.VTYPE_SIZE:
864 a5728081 Guido Trotter
      try:
865 a5728081 Guido Trotter
        target[key] = ParseUnit(target[key])
866 a5728081 Guido Trotter
      except errors.UnitParseError, err:
867 a5728081 Guido Trotter
        msg = "'%s' (value %s) is not a valid size. error: %s" % \
868 a5728081 Guido Trotter
              (key, target[key], err)
869 a5728081 Guido Trotter
        raise errors.TypeEnforcementError(msg)
870 29921401 Iustin Pop
    elif ktype == constants.VTYPE_INT:
871 a5728081 Guido Trotter
      try:
872 a5728081 Guido Trotter
        target[key] = int(target[key])
873 a5728081 Guido Trotter
      except (ValueError, TypeError):
874 a5728081 Guido Trotter
        msg = "'%s' (value %s) is not a valid integer" % (key, target[key])
875 a5728081 Guido Trotter
        raise errors.TypeEnforcementError(msg)
876 a5728081 Guido Trotter
877 a5728081 Guido Trotter
878 a01b500b Michael Hanselmann
def _GetProcStatusPath(pid):
879 a01b500b Michael Hanselmann
  """Returns the path for a PID's proc status file.
880 a01b500b Michael Hanselmann

881 a01b500b Michael Hanselmann
  @type pid: int
882 a01b500b Michael Hanselmann
  @param pid: Process ID
883 a01b500b Michael Hanselmann
  @rtype: string
884 a01b500b Michael Hanselmann

885 a01b500b Michael Hanselmann
  """
886 a01b500b Michael Hanselmann
  return "/proc/%d/status" % pid
887 a01b500b Michael Hanselmann
888 a01b500b Michael Hanselmann
889 a8083063 Iustin Pop
def IsProcessAlive(pid):
890 a8083063 Iustin Pop
  """Check if a given pid exists on the system.
891 a8083063 Iustin Pop

892 44bf25ff Iustin Pop
  @note: zombie status is not handled, so zombie processes
893 44bf25ff Iustin Pop
      will be returned as alive
894 58885d79 Iustin Pop
  @type pid: int
895 58885d79 Iustin Pop
  @param pid: the process ID to check
896 58885d79 Iustin Pop
  @rtype: boolean
897 58885d79 Iustin Pop
  @return: True if the process exists
898 a8083063 Iustin Pop

899 a8083063 Iustin Pop
  """
900 5ef5ea45 Guido Trotter
  def _TryStat(name):
901 5ef5ea45 Guido Trotter
    try:
902 5ef5ea45 Guido Trotter
      os.stat(name)
903 5ef5ea45 Guido Trotter
      return True
904 5ef5ea45 Guido Trotter
    except EnvironmentError, err:
905 5ef5ea45 Guido Trotter
      if err.errno in (errno.ENOENT, errno.ENOTDIR):
906 5ef5ea45 Guido Trotter
        return False
907 5ef5ea45 Guido Trotter
      elif err.errno == errno.EINVAL:
908 5ef5ea45 Guido Trotter
        raise RetryAgain(err)
909 5ef5ea45 Guido Trotter
      raise
910 5ef5ea45 Guido Trotter
911 5ef5ea45 Guido Trotter
  assert isinstance(pid, int), "pid must be an integer"
912 d9f311d7 Iustin Pop
  if pid <= 0:
913 d9f311d7 Iustin Pop
    return False
914 d9f311d7 Iustin Pop
915 5ef5ea45 Guido Trotter
  # /proc in a multiprocessor environment can have strange behaviors.
916 5ef5ea45 Guido Trotter
  # Retry the os.stat a few times until we get a good result.
917 a8083063 Iustin Pop
  try:
918 a01b500b Michael Hanselmann
    return Retry(_TryStat, (0.01, 1.5, 0.1), 0.5,
919 a01b500b Michael Hanselmann
                 args=[_GetProcStatusPath(pid)])
920 5ef5ea45 Guido Trotter
  except RetryTimeout, err:
921 5ef5ea45 Guido Trotter
    err.RaiseInner()
922 a8083063 Iustin Pop
923 a8083063 Iustin Pop
924 a01b500b Michael Hanselmann
def _ParseSigsetT(sigset):
925 a01b500b Michael Hanselmann
  """Parse a rendered sigset_t value.
926 a01b500b Michael Hanselmann

927 a01b500b Michael Hanselmann
  This is the opposite of the Linux kernel's fs/proc/array.c:render_sigset_t
928 a01b500b Michael Hanselmann
  function.
929 a01b500b Michael Hanselmann

930 a01b500b Michael Hanselmann
  @type sigset: string
931 a01b500b Michael Hanselmann
  @param sigset: Rendered signal set from /proc/$pid/status
932 a01b500b Michael Hanselmann
  @rtype: set
933 a01b500b Michael Hanselmann
  @return: Set of all enabled signal numbers
934 a01b500b Michael Hanselmann

935 a01b500b Michael Hanselmann
  """
936 a01b500b Michael Hanselmann
  result = set()
937 a01b500b Michael Hanselmann
938 a01b500b Michael Hanselmann
  signum = 0
939 a01b500b Michael Hanselmann
  for ch in reversed(sigset):
940 a01b500b Michael Hanselmann
    chv = int(ch, 16)
941 a01b500b Michael Hanselmann
942 a01b500b Michael Hanselmann
    # The following could be done in a loop, but it's easier to read and
943 a01b500b Michael Hanselmann
    # understand in the unrolled form
944 a01b500b Michael Hanselmann
    if chv & 1:
945 a01b500b Michael Hanselmann
      result.add(signum + 1)
946 a01b500b Michael Hanselmann
    if chv & 2:
947 a01b500b Michael Hanselmann
      result.add(signum + 2)
948 a01b500b Michael Hanselmann
    if chv & 4:
949 a01b500b Michael Hanselmann
      result.add(signum + 3)
950 a01b500b Michael Hanselmann
    if chv & 8:
951 a01b500b Michael Hanselmann
      result.add(signum + 4)
952 a01b500b Michael Hanselmann
953 a01b500b Michael Hanselmann
    signum += 4
954 a01b500b Michael Hanselmann
955 a01b500b Michael Hanselmann
  return result
956 a01b500b Michael Hanselmann
957 a01b500b Michael Hanselmann
958 a01b500b Michael Hanselmann
def _GetProcStatusField(pstatus, field):
959 a01b500b Michael Hanselmann
  """Retrieves a field from the contents of a proc status file.
960 a01b500b Michael Hanselmann

961 a01b500b Michael Hanselmann
  @type pstatus: string
962 a01b500b Michael Hanselmann
  @param pstatus: Contents of /proc/$pid/status
963 a01b500b Michael Hanselmann
  @type field: string
964 a01b500b Michael Hanselmann
  @param field: Name of field whose value should be returned
965 a01b500b Michael Hanselmann
  @rtype: string
966 a01b500b Michael Hanselmann

967 a01b500b Michael Hanselmann
  """
968 a01b500b Michael Hanselmann
  for line in pstatus.splitlines():
969 a01b500b Michael Hanselmann
    parts = line.split(":", 1)
970 a01b500b Michael Hanselmann
971 a01b500b Michael Hanselmann
    if len(parts) < 2 or parts[0] != field:
972 a01b500b Michael Hanselmann
      continue
973 a01b500b Michael Hanselmann
974 a01b500b Michael Hanselmann
    return parts[1].strip()
975 a01b500b Michael Hanselmann
976 a01b500b Michael Hanselmann
  return None
977 a01b500b Michael Hanselmann
978 a01b500b Michael Hanselmann
979 a01b500b Michael Hanselmann
def IsProcessHandlingSignal(pid, signum, status_path=None):
980 a01b500b Michael Hanselmann
  """Checks whether a process is handling a signal.
981 a01b500b Michael Hanselmann

982 a01b500b Michael Hanselmann
  @type pid: int
983 a01b500b Michael Hanselmann
  @param pid: Process ID
984 a01b500b Michael Hanselmann
  @type signum: int
985 a01b500b Michael Hanselmann
  @param signum: Signal number
986 a01b500b Michael Hanselmann
  @rtype: bool
987 a01b500b Michael Hanselmann

988 a01b500b Michael Hanselmann
  """
989 a01b500b Michael Hanselmann
  if status_path is None:
990 a01b500b Michael Hanselmann
    status_path = _GetProcStatusPath(pid)
991 a01b500b Michael Hanselmann
992 a01b500b Michael Hanselmann
  try:
993 a01b500b Michael Hanselmann
    proc_status = ReadFile(status_path)
994 a01b500b Michael Hanselmann
  except EnvironmentError, err:
995 a01b500b Michael Hanselmann
    # In at least one case, reading /proc/$pid/status failed with ESRCH.
996 a01b500b Michael Hanselmann
    if err.errno in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL, errno.ESRCH):
997 a01b500b Michael Hanselmann
      return False
998 a01b500b Michael Hanselmann
    raise
999 a01b500b Michael Hanselmann
1000 a01b500b Michael Hanselmann
  sigcgt = _GetProcStatusField(proc_status, "SigCgt")
1001 a01b500b Michael Hanselmann
  if sigcgt is None:
1002 a01b500b Michael Hanselmann
    raise RuntimeError("%s is missing 'SigCgt' field" % status_path)
1003 a01b500b Michael Hanselmann
1004 a01b500b Michael Hanselmann
  # Now check whether signal is handled
1005 a01b500b Michael Hanselmann
  return signum in _ParseSigsetT(sigcgt)
1006 a01b500b Michael Hanselmann
1007 a01b500b Michael Hanselmann
1008 d9f311d7 Iustin Pop
def ReadPidFile(pidfile):
1009 58885d79 Iustin Pop
  """Read a pid from a file.
1010 fee80e90 Guido Trotter

1011 58885d79 Iustin Pop
  @type  pidfile: string
1012 58885d79 Iustin Pop
  @param pidfile: path to the file containing the pid
1013 58885d79 Iustin Pop
  @rtype: int
1014 1de62f37 Guido Trotter
  @return: The process id, if the file exists and contains a valid PID,
1015 d9f311d7 Iustin Pop
           otherwise 0
1016 fee80e90 Guido Trotter

1017 fee80e90 Guido Trotter
  """
1018 fee80e90 Guido Trotter
  try:
1019 682f7601 Guido Trotter
    raw_data = ReadOneLineFile(pidfile)
1020 d9f311d7 Iustin Pop
  except EnvironmentError, err:
1021 d9f311d7 Iustin Pop
    if err.errno != errno.ENOENT:
1022 13998ef2 Michael Hanselmann
      logging.exception("Can't read pid file")
1023 d9f311d7 Iustin Pop
    return 0
1024 fee80e90 Guido Trotter
1025 fee80e90 Guido Trotter
  try:
1026 13998ef2 Michael Hanselmann
    pid = int(raw_data)
1027 691744c4 Iustin Pop
  except (TypeError, ValueError), err:
1028 8161a646 Iustin Pop
    logging.info("Can't parse pid file contents", exc_info=True)
1029 d9f311d7 Iustin Pop
    return 0
1030 fee80e90 Guido Trotter
1031 d9f311d7 Iustin Pop
  return pid
1032 fee80e90 Guido Trotter
1033 fee80e90 Guido Trotter
1034 debed9ae Michael Hanselmann
def ReadLockedPidFile(path):
1035 debed9ae Michael Hanselmann
  """Reads a locked PID file.
1036 debed9ae Michael Hanselmann

1037 debed9ae Michael Hanselmann
  This can be used together with L{StartDaemon}.
1038 debed9ae Michael Hanselmann

1039 debed9ae Michael Hanselmann
  @type path: string
1040 debed9ae Michael Hanselmann
  @param path: Path to PID file
1041 debed9ae Michael Hanselmann
  @return: PID as integer or, if file was unlocked or couldn't be opened, None
1042 debed9ae Michael Hanselmann

1043 debed9ae Michael Hanselmann
  """
1044 debed9ae Michael Hanselmann
  try:
1045 debed9ae Michael Hanselmann
    fd = os.open(path, os.O_RDONLY)
1046 debed9ae Michael Hanselmann
  except EnvironmentError, err:
1047 debed9ae Michael Hanselmann
    if err.errno == errno.ENOENT:
1048 debed9ae Michael Hanselmann
      # PID file doesn't exist
1049 debed9ae Michael Hanselmann
      return None
1050 debed9ae Michael Hanselmann
    raise
1051 debed9ae Michael Hanselmann
1052 debed9ae Michael Hanselmann
  try:
1053 debed9ae Michael Hanselmann
    try:
1054 debed9ae Michael Hanselmann
      # Try to acquire lock
1055 debed9ae Michael Hanselmann
      LockFile(fd)
1056 debed9ae Michael Hanselmann
    except errors.LockError:
1057 debed9ae Michael Hanselmann
      # Couldn't lock, daemon is running
1058 debed9ae Michael Hanselmann
      return int(os.read(fd, 100))
1059 debed9ae Michael Hanselmann
  finally:
1060 debed9ae Michael Hanselmann
    os.close(fd)
1061 debed9ae Michael Hanselmann
1062 debed9ae Michael Hanselmann
  return None
1063 debed9ae Michael Hanselmann
1064 debed9ae Michael Hanselmann
1065 256eb94b Guido Trotter
def MatchNameComponent(key, name_list, case_sensitive=True):
1066 a8083063 Iustin Pop
  """Try to match a name against a list.
1067 a8083063 Iustin Pop

1068 a8083063 Iustin Pop
  This function will try to match a name like test1 against a list
1069 58885d79 Iustin Pop
  like C{['test1.example.com', 'test2.example.com', ...]}. Against
1070 58885d79 Iustin Pop
  this list, I{'test1'} as well as I{'test1.example'} will match, but
1071 58885d79 Iustin Pop
  not I{'test1.ex'}. A multiple match will be considered as no match
1072 58885d79 Iustin Pop
  at all (e.g. I{'test1'} against C{['test1.example.com',
1073 3a541d90 Iustin Pop
  'test1.example.org']}), except when the key fully matches an entry
1074 3a541d90 Iustin Pop
  (e.g. I{'test1'} against C{['test1', 'test1.example.com']}).
1075 a8083063 Iustin Pop

1076 58885d79 Iustin Pop
  @type key: str
1077 58885d79 Iustin Pop
  @param key: the name to be searched
1078 58885d79 Iustin Pop
  @type name_list: list
1079 58885d79 Iustin Pop
  @param name_list: the list of strings against which to search the key
1080 256eb94b Guido Trotter
  @type case_sensitive: boolean
1081 256eb94b Guido Trotter
  @param case_sensitive: whether to provide a case-sensitive match
1082 a8083063 Iustin Pop

1083 58885d79 Iustin Pop
  @rtype: None or str
1084 58885d79 Iustin Pop
  @return: None if there is no match I{or} if there are multiple matches,
1085 58885d79 Iustin Pop
      otherwise the element from the list which matches
1086 a8083063 Iustin Pop

1087 a8083063 Iustin Pop
  """
1088 3a541d90 Iustin Pop
  if key in name_list:
1089 3a541d90 Iustin Pop
    return key
1090 256eb94b Guido Trotter
1091 256eb94b Guido Trotter
  re_flags = 0
1092 256eb94b Guido Trotter
  if not case_sensitive:
1093 256eb94b Guido Trotter
    re_flags |= re.IGNORECASE
1094 099c52ad Iustin Pop
    key = key.upper()
1095 256eb94b Guido Trotter
  mo = re.compile("^%s(\..*)?$" % re.escape(key), re_flags)
1096 256eb94b Guido Trotter
  names_filtered = []
1097 256eb94b Guido Trotter
  string_matches = []
1098 256eb94b Guido Trotter
  for name in name_list:
1099 256eb94b Guido Trotter
    if mo.match(name) is not None:
1100 256eb94b Guido Trotter
      names_filtered.append(name)
1101 099c52ad Iustin Pop
      if not case_sensitive and key == name.upper():
1102 256eb94b Guido Trotter
        string_matches.append(name)
1103 256eb94b Guido Trotter
1104 256eb94b Guido Trotter
  if len(string_matches) == 1:
1105 256eb94b Guido Trotter
    return string_matches[0]
1106 256eb94b Guido Trotter
  if len(names_filtered) == 1:
1107 256eb94b Guido Trotter
    return names_filtered[0]
1108 256eb94b Guido Trotter
  return None
1109 a8083063 Iustin Pop
1110 a8083063 Iustin Pop
1111 28f34048 Michael Hanselmann
def ValidateServiceName(name):
1112 28f34048 Michael Hanselmann
  """Validate the given service name.
1113 28f34048 Michael Hanselmann

1114 28f34048 Michael Hanselmann
  @type name: number or string
1115 28f34048 Michael Hanselmann
  @param name: Service name or port specification
1116 28f34048 Michael Hanselmann

1117 28f34048 Michael Hanselmann
  """
1118 28f34048 Michael Hanselmann
  try:
1119 28f34048 Michael Hanselmann
    numport = int(name)
1120 28f34048 Michael Hanselmann
  except (ValueError, TypeError):
1121 28f34048 Michael Hanselmann
    # Non-numeric service name
1122 28f34048 Michael Hanselmann
    valid = _VALID_SERVICE_NAME_RE.match(name)
1123 28f34048 Michael Hanselmann
  else:
1124 28f34048 Michael Hanselmann
    # Numeric port (protocols other than TCP or UDP might need adjustments
1125 28f34048 Michael Hanselmann
    # here)
1126 28f34048 Michael Hanselmann
    valid = (numport >= 0 and numport < (1 << 16))
1127 28f34048 Michael Hanselmann
1128 28f34048 Michael Hanselmann
  if not valid:
1129 28f34048 Michael Hanselmann
    raise errors.OpPrereqError("Invalid service name '%s'" % name,
1130 28f34048 Michael Hanselmann
                               errors.ECODE_INVAL)
1131 28f34048 Michael Hanselmann
1132 28f34048 Michael Hanselmann
  return name
1133 28f34048 Michael Hanselmann
1134 28f34048 Michael Hanselmann
1135 a8083063 Iustin Pop
def ListVolumeGroups():
1136 a8083063 Iustin Pop
  """List volume groups and their size
1137 a8083063 Iustin Pop

1138 58885d79 Iustin Pop
  @rtype: dict
1139 58885d79 Iustin Pop
  @return:
1140 58885d79 Iustin Pop
       Dictionary with keys volume name and values
1141 58885d79 Iustin Pop
       the size of the volume
1142 a8083063 Iustin Pop

1143 a8083063 Iustin Pop
  """
1144 a8083063 Iustin Pop
  command = "vgs --noheadings --units m --nosuffix -o name,size"
1145 a8083063 Iustin Pop
  result = RunCmd(command)
1146 a8083063 Iustin Pop
  retval = {}
1147 a8083063 Iustin Pop
  if result.failed:
1148 a8083063 Iustin Pop
    return retval
1149 a8083063 Iustin Pop
1150 a8083063 Iustin Pop
  for line in result.stdout.splitlines():
1151 a8083063 Iustin Pop
    try:
1152 a8083063 Iustin Pop
      name, size = line.split()
1153 a8083063 Iustin Pop
      size = int(float(size))
1154 a8083063 Iustin Pop
    except (IndexError, ValueError), err:
1155 bb698c1f Iustin Pop
      logging.error("Invalid output from vgs (%s): %s", err, line)
1156 a8083063 Iustin Pop
      continue
1157 a8083063 Iustin Pop
1158 a8083063 Iustin Pop
    retval[name] = size
1159 a8083063 Iustin Pop
1160 a8083063 Iustin Pop
  return retval
1161 a8083063 Iustin Pop
1162 a8083063 Iustin Pop
1163 a8083063 Iustin Pop
def BridgeExists(bridge):
1164 a8083063 Iustin Pop
  """Check whether the given bridge exists in the system
1165 a8083063 Iustin Pop

1166 58885d79 Iustin Pop
  @type bridge: str
1167 58885d79 Iustin Pop
  @param bridge: the bridge name to check
1168 58885d79 Iustin Pop
  @rtype: boolean
1169 58885d79 Iustin Pop
  @return: True if it does
1170 a8083063 Iustin Pop

1171 a8083063 Iustin Pop
  """
1172 a8083063 Iustin Pop
  return os.path.isdir("/sys/class/net/%s/bridge" % bridge)
1173 a8083063 Iustin Pop
1174 a8083063 Iustin Pop
1175 a8083063 Iustin Pop
def NiceSort(name_list):
1176 a8083063 Iustin Pop
  """Sort a list of strings based on digit and non-digit groupings.
1177 a8083063 Iustin Pop

1178 58885d79 Iustin Pop
  Given a list of names C{['a1', 'a10', 'a11', 'a2']} this function
1179 58885d79 Iustin Pop
  will sort the list in the logical order C{['a1', 'a2', 'a10',
1180 58885d79 Iustin Pop
  'a11']}.
1181 a8083063 Iustin Pop

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

1186 58885d79 Iustin Pop
  @type name_list: list
1187 58885d79 Iustin Pop
  @param name_list: the names to be sorted
1188 58885d79 Iustin Pop
  @rtype: list
1189 58885d79 Iustin Pop
  @return: a copy of the name list sorted with our algorithm
1190 a8083063 Iustin Pop

1191 a8083063 Iustin Pop
  """
1192 a8083063 Iustin Pop
  _SORTER_BASE = "(\D+|\d+)"
1193 a8083063 Iustin Pop
  _SORTER_FULL = "^%s%s?%s?%s?%s?%s?%s?%s?.*$" % (_SORTER_BASE, _SORTER_BASE,
1194 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE,
1195 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE,
1196 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE)
1197 a8083063 Iustin Pop
  _SORTER_RE = re.compile(_SORTER_FULL)
1198 a8083063 Iustin Pop
  _SORTER_NODIGIT = re.compile("^\D*$")
1199 a8083063 Iustin Pop
  def _TryInt(val):
1200 a8083063 Iustin Pop
    """Attempts to convert a variable to integer."""
1201 a8083063 Iustin Pop
    if val is None or _SORTER_NODIGIT.match(val):
1202 a8083063 Iustin Pop
      return val
1203 a8083063 Iustin Pop
    rval = int(val)
1204 a8083063 Iustin Pop
    return rval
1205 a8083063 Iustin Pop
1206 a8083063 Iustin Pop
  to_sort = [([_TryInt(grp) for grp in _SORTER_RE.match(name).groups()], name)
1207 a8083063 Iustin Pop
             for name in name_list]
1208 a8083063 Iustin Pop
  to_sort.sort()
1209 a8083063 Iustin Pop
  return [tup[1] for tup in to_sort]
1210 a8083063 Iustin Pop
1211 a8083063 Iustin Pop
1212 a8083063 Iustin Pop
def TryConvert(fn, val):
1213 a8083063 Iustin Pop
  """Try to convert a value ignoring errors.
1214 a8083063 Iustin Pop

1215 58885d79 Iustin Pop
  This function tries to apply function I{fn} to I{val}. If no
1216 58885d79 Iustin Pop
  C{ValueError} or C{TypeError} exceptions are raised, it will return
1217 58885d79 Iustin Pop
  the result, else it will return the original value. Any other
1218 58885d79 Iustin Pop
  exceptions are propagated to the caller.
1219 58885d79 Iustin Pop

1220 58885d79 Iustin Pop
  @type fn: callable
1221 58885d79 Iustin Pop
  @param fn: function to apply to the value
1222 58885d79 Iustin Pop
  @param val: the value to be converted
1223 58885d79 Iustin Pop
  @return: The converted value if the conversion was successful,
1224 58885d79 Iustin Pop
      otherwise the original value.
1225 a8083063 Iustin Pop

1226 a8083063 Iustin Pop
  """
1227 a8083063 Iustin Pop
  try:
1228 a8083063 Iustin Pop
    nv = fn(val)
1229 7c4d6c7b Michael Hanselmann
  except (ValueError, TypeError):
1230 a8083063 Iustin Pop
    nv = val
1231 a8083063 Iustin Pop
  return nv
1232 a8083063 Iustin Pop
1233 a8083063 Iustin Pop
1234 a8083063 Iustin Pop
def IsValidShellParam(word):
1235 a8083063 Iustin Pop
  """Verifies is the given word is safe from the shell's p.o.v.
1236 a8083063 Iustin Pop

1237 a8083063 Iustin Pop
  This means that we can pass this to a command via the shell and be
1238 a8083063 Iustin Pop
  sure that it doesn't alter the command line and is passed as such to
1239 a8083063 Iustin Pop
  the actual command.
1240 a8083063 Iustin Pop

1241 a8083063 Iustin Pop
  Note that we are overly restrictive here, in order to be on the safe
1242 a8083063 Iustin Pop
  side.
1243 a8083063 Iustin Pop

1244 58885d79 Iustin Pop
  @type word: str
1245 58885d79 Iustin Pop
  @param word: the word to check
1246 58885d79 Iustin Pop
  @rtype: boolean
1247 58885d79 Iustin Pop
  @return: True if the word is 'safe'
1248 58885d79 Iustin Pop

1249 a8083063 Iustin Pop
  """
1250 a8083063 Iustin Pop
  return bool(re.match("^[-a-zA-Z0-9._+/:%@]+$", word))
1251 a8083063 Iustin Pop
1252 a8083063 Iustin Pop
1253 a8083063 Iustin Pop
def BuildShellCmd(template, *args):
1254 a8083063 Iustin Pop
  """Build a safe shell command line from the given arguments.
1255 a8083063 Iustin Pop

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

1261 58885d79 Iustin Pop
  @type template: str
1262 58885d79 Iustin Pop
  @param template: the string holding the template for the
1263 58885d79 Iustin Pop
      string formatting
1264 58885d79 Iustin Pop
  @rtype: str
1265 58885d79 Iustin Pop
  @return: the expanded command line
1266 58885d79 Iustin Pop

1267 a8083063 Iustin Pop
  """
1268 a8083063 Iustin Pop
  for word in args:
1269 a8083063 Iustin Pop
    if not IsValidShellParam(word):
1270 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Shell argument '%s' contains"
1271 3ecf6786 Iustin Pop
                                   " invalid characters" % word)
1272 a8083063 Iustin Pop
  return template % args
1273 a8083063 Iustin Pop
1274 a8083063 Iustin Pop
1275 9fbfbb7b Iustin Pop
def FormatUnit(value, units):
1276 a8083063 Iustin Pop
  """Formats an incoming number of MiB with the appropriate unit.
1277 a8083063 Iustin Pop

1278 58885d79 Iustin Pop
  @type value: int
1279 58885d79 Iustin Pop
  @param value: integer representing the value in MiB (1048576)
1280 9fbfbb7b Iustin Pop
  @type units: char
1281 9fbfbb7b Iustin Pop
  @param units: the type of formatting we should do:
1282 9fbfbb7b Iustin Pop
      - 'h' for automatic scaling
1283 9fbfbb7b Iustin Pop
      - 'm' for MiBs
1284 9fbfbb7b Iustin Pop
      - 'g' for GiBs
1285 9fbfbb7b Iustin Pop
      - 't' for TiBs
1286 58885d79 Iustin Pop
  @rtype: str
1287 58885d79 Iustin Pop
  @return: the formatted value (with suffix)
1288 a8083063 Iustin Pop

1289 a8083063 Iustin Pop
  """
1290 9fbfbb7b Iustin Pop
  if units not in ('m', 'g', 't', 'h'):
1291 9fbfbb7b Iustin Pop
    raise errors.ProgrammerError("Invalid unit specified '%s'" % str(units))
1292 a8083063 Iustin Pop
1293 9fbfbb7b Iustin Pop
  suffix = ''
1294 9fbfbb7b Iustin Pop
1295 9fbfbb7b Iustin Pop
  if units == 'm' or (units == 'h' and value < 1024):
1296 9fbfbb7b Iustin Pop
    if units == 'h':
1297 9fbfbb7b Iustin Pop
      suffix = 'M'
1298 9fbfbb7b Iustin Pop
    return "%d%s" % (round(value, 0), suffix)
1299 9fbfbb7b Iustin Pop
1300 9fbfbb7b Iustin Pop
  elif units == 'g' or (units == 'h' and value < (1024 * 1024)):
1301 9fbfbb7b Iustin Pop
    if units == 'h':
1302 9fbfbb7b Iustin Pop
      suffix = 'G'
1303 9fbfbb7b Iustin Pop
    return "%0.1f%s" % (round(float(value) / 1024, 1), suffix)
1304 a8083063 Iustin Pop
1305 a8083063 Iustin Pop
  else:
1306 9fbfbb7b Iustin Pop
    if units == 'h':
1307 9fbfbb7b Iustin Pop
      suffix = 'T'
1308 9fbfbb7b Iustin Pop
    return "%0.1f%s" % (round(float(value) / 1024 / 1024, 1), suffix)
1309 a8083063 Iustin Pop
1310 a8083063 Iustin Pop
1311 a8083063 Iustin Pop
def ParseUnit(input_string):
1312 a8083063 Iustin Pop
  """Tries to extract number and scale from the given string.
1313 a8083063 Iustin Pop

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

1318 a8083063 Iustin Pop
  """
1319 9939547b Iustin Pop
  m = re.match('^([.\d]+)\s*([a-zA-Z]+)?$', str(input_string))
1320 a8083063 Iustin Pop
  if not m:
1321 3ecf6786 Iustin Pop
    raise errors.UnitParseError("Invalid format")
1322 a8083063 Iustin Pop
1323 a8083063 Iustin Pop
  value = float(m.groups()[0])
1324 a8083063 Iustin Pop
1325 a8083063 Iustin Pop
  unit = m.groups()[1]
1326 a8083063 Iustin Pop
  if unit:
1327 a8083063 Iustin Pop
    lcunit = unit.lower()
1328 a8083063 Iustin Pop
  else:
1329 a8083063 Iustin Pop
    lcunit = 'm'
1330 a8083063 Iustin Pop
1331 a8083063 Iustin Pop
  if lcunit in ('m', 'mb', 'mib'):
1332 a8083063 Iustin Pop
    # Value already in MiB
1333 a8083063 Iustin Pop
    pass
1334 a8083063 Iustin Pop
1335 a8083063 Iustin Pop
  elif lcunit in ('g', 'gb', 'gib'):
1336 a8083063 Iustin Pop
    value *= 1024
1337 a8083063 Iustin Pop
1338 a8083063 Iustin Pop
  elif lcunit in ('t', 'tb', 'tib'):
1339 a8083063 Iustin Pop
    value *= 1024 * 1024
1340 a8083063 Iustin Pop
1341 a8083063 Iustin Pop
  else:
1342 3ecf6786 Iustin Pop
    raise errors.UnitParseError("Unknown unit: %s" % unit)
1343 a8083063 Iustin Pop
1344 a8083063 Iustin Pop
  # Make sure we round up
1345 a8083063 Iustin Pop
  if int(value) < value:
1346 a8083063 Iustin Pop
    value += 1
1347 a8083063 Iustin Pop
1348 a8083063 Iustin Pop
  # Round up to the next multiple of 4
1349 a8083063 Iustin Pop
  value = int(value)
1350 a8083063 Iustin Pop
  if value % 4:
1351 a8083063 Iustin Pop
    value += 4 - value % 4
1352 a8083063 Iustin Pop
1353 a8083063 Iustin Pop
  return value
1354 a8083063 Iustin Pop
1355 a8083063 Iustin Pop
1356 31155d60 Balazs Lecz
def ParseCpuMask(cpu_mask):
1357 31155d60 Balazs Lecz
  """Parse a CPU mask definition and return the list of CPU IDs.
1358 31155d60 Balazs Lecz

1359 31155d60 Balazs Lecz
  CPU mask format: comma-separated list of CPU IDs
1360 31155d60 Balazs Lecz
  or dash-separated ID ranges
1361 31155d60 Balazs Lecz
  Example: "0-2,5" -> "0,1,2,5"
1362 31155d60 Balazs Lecz

1363 31155d60 Balazs Lecz
  @type cpu_mask: str
1364 31155d60 Balazs Lecz
  @param cpu_mask: CPU mask definition
1365 31155d60 Balazs Lecz
  @rtype: list of int
1366 31155d60 Balazs Lecz
  @return: list of CPU IDs
1367 31155d60 Balazs Lecz

1368 31155d60 Balazs Lecz
  """
1369 31155d60 Balazs Lecz
  if not cpu_mask:
1370 31155d60 Balazs Lecz
    return []
1371 31155d60 Balazs Lecz
  cpu_list = []
1372 31155d60 Balazs Lecz
  for range_def in cpu_mask.split(","):
1373 31155d60 Balazs Lecz
    boundaries = range_def.split("-")
1374 31155d60 Balazs Lecz
    n_elements = len(boundaries)
1375 31155d60 Balazs Lecz
    if n_elements > 2:
1376 31155d60 Balazs Lecz
      raise errors.ParseError("Invalid CPU ID range definition"
1377 31155d60 Balazs Lecz
                              " (only one hyphen allowed): %s" % range_def)
1378 31155d60 Balazs Lecz
    try:
1379 31155d60 Balazs Lecz
      lower = int(boundaries[0])
1380 31155d60 Balazs Lecz
    except (ValueError, TypeError), err:
1381 31155d60 Balazs Lecz
      raise errors.ParseError("Invalid CPU ID value for lower boundary of"
1382 31155d60 Balazs Lecz
                              " CPU ID range: %s" % str(err))
1383 31155d60 Balazs Lecz
    try:
1384 31155d60 Balazs Lecz
      higher = int(boundaries[-1])
1385 31155d60 Balazs Lecz
    except (ValueError, TypeError), err:
1386 31155d60 Balazs Lecz
      raise errors.ParseError("Invalid CPU ID value for higher boundary of"
1387 31155d60 Balazs Lecz
                              " CPU ID range: %s" % str(err))
1388 31155d60 Balazs Lecz
    if lower > higher:
1389 31155d60 Balazs Lecz
      raise errors.ParseError("Invalid CPU ID range definition"
1390 31155d60 Balazs Lecz
                              " (%d > %d): %s" % (lower, higher, range_def))
1391 31155d60 Balazs Lecz
    cpu_list.extend(range(lower, higher + 1))
1392 31155d60 Balazs Lecz
  return cpu_list
1393 31155d60 Balazs Lecz
1394 31155d60 Balazs Lecz
1395 3727671e Renรฉ Nussbaumer
def AddAuthorizedKey(file_obj, key):
1396 a8083063 Iustin Pop
  """Adds an SSH public key to an authorized_keys file.
1397 a8083063 Iustin Pop

1398 3727671e Renรฉ Nussbaumer
  @type file_obj: str or file handle
1399 3727671e Renรฉ Nussbaumer
  @param file_obj: path to authorized_keys file
1400 58885d79 Iustin Pop
  @type key: str
1401 58885d79 Iustin Pop
  @param key: string containing key
1402 58885d79 Iustin Pop

1403 a8083063 Iustin Pop
  """
1404 a8083063 Iustin Pop
  key_fields = key.split()
1405 a8083063 Iustin Pop
1406 3727671e Renรฉ Nussbaumer
  if isinstance(file_obj, basestring):
1407 3727671e Renรฉ Nussbaumer
    f = open(file_obj, 'a+')
1408 3727671e Renรฉ Nussbaumer
  else:
1409 3727671e Renรฉ Nussbaumer
    f = file_obj
1410 3727671e Renรฉ Nussbaumer
1411 a8083063 Iustin Pop
  try:
1412 a8083063 Iustin Pop
    nl = True
1413 a8083063 Iustin Pop
    for line in f:
1414 a8083063 Iustin Pop
      # Ignore whitespace changes
1415 a8083063 Iustin Pop
      if line.split() == key_fields:
1416 a8083063 Iustin Pop
        break
1417 a8083063 Iustin Pop
      nl = line.endswith('\n')
1418 a8083063 Iustin Pop
    else:
1419 a8083063 Iustin Pop
      if not nl:
1420 a8083063 Iustin Pop
        f.write("\n")
1421 a8083063 Iustin Pop
      f.write(key.rstrip('\r\n'))
1422 a8083063 Iustin Pop
      f.write("\n")
1423 a8083063 Iustin Pop
      f.flush()
1424 a8083063 Iustin Pop
  finally:
1425 a8083063 Iustin Pop
    f.close()
1426 a8083063 Iustin Pop
1427 a8083063 Iustin Pop
1428 a8083063 Iustin Pop
def RemoveAuthorizedKey(file_name, key):
1429 a8083063 Iustin Pop
  """Removes an SSH public key from an authorized_keys file.
1430 a8083063 Iustin Pop

1431 58885d79 Iustin Pop
  @type file_name: str
1432 58885d79 Iustin Pop
  @param file_name: path to authorized_keys file
1433 58885d79 Iustin Pop
  @type key: str
1434 58885d79 Iustin Pop
  @param key: string containing key
1435 58885d79 Iustin Pop

1436 a8083063 Iustin Pop
  """
1437 a8083063 Iustin Pop
  key_fields = key.split()
1438 a8083063 Iustin Pop
1439 a8083063 Iustin Pop
  fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name))
1440 a8083063 Iustin Pop
  try:
1441 59f82e3f Michael Hanselmann
    out = os.fdopen(fd, 'w')
1442 a8083063 Iustin Pop
    try:
1443 59f82e3f Michael Hanselmann
      f = open(file_name, 'r')
1444 59f82e3f Michael Hanselmann
      try:
1445 59f82e3f Michael Hanselmann
        for line in f:
1446 59f82e3f Michael Hanselmann
          # Ignore whitespace changes while comparing lines
1447 59f82e3f Michael Hanselmann
          if line.split() != key_fields:
1448 59f82e3f Michael Hanselmann
            out.write(line)
1449 899d2a81 Michael Hanselmann
1450 899d2a81 Michael Hanselmann
        out.flush()
1451 899d2a81 Michael Hanselmann
        os.rename(tmpname, file_name)
1452 899d2a81 Michael Hanselmann
      finally:
1453 899d2a81 Michael Hanselmann
        f.close()
1454 899d2a81 Michael Hanselmann
    finally:
1455 899d2a81 Michael Hanselmann
      out.close()
1456 899d2a81 Michael Hanselmann
  except:
1457 899d2a81 Michael Hanselmann
    RemoveFile(tmpname)
1458 899d2a81 Michael Hanselmann
    raise
1459 899d2a81 Michael Hanselmann
1460 899d2a81 Michael Hanselmann
1461 9440aeab Michael Hanselmann
def SetEtcHostsEntry(file_name, ip, hostname, aliases):
1462 9440aeab Michael Hanselmann
  """Sets the name of an IP address and hostname in /etc/hosts.
1463 899d2a81 Michael Hanselmann

1464 58885d79 Iustin Pop
  @type file_name: str
1465 58885d79 Iustin Pop
  @param file_name: path to the file to modify (usually C{/etc/hosts})
1466 58885d79 Iustin Pop
  @type ip: str
1467 58885d79 Iustin Pop
  @param ip: the IP address
1468 58885d79 Iustin Pop
  @type hostname: str
1469 58885d79 Iustin Pop
  @param hostname: the hostname to be added
1470 58885d79 Iustin Pop
  @type aliases: list
1471 58885d79 Iustin Pop
  @param aliases: the list of aliases to add for the hostname
1472 58885d79 Iustin Pop

1473 899d2a81 Michael Hanselmann
  """
1474 7fbb1f65 Michael Hanselmann
  # Ensure aliases are unique
1475 7fbb1f65 Michael Hanselmann
  aliases = UniqueSequence([hostname] + aliases)[1:]
1476 7fbb1f65 Michael Hanselmann
1477 edcd876b Michael Hanselmann
  def _WriteEtcHosts(fd):
1478 edcd876b Michael Hanselmann
    # Duplicating file descriptor because os.fdopen's result will automatically
1479 edcd876b Michael Hanselmann
    # close the descriptor, but we would still like to have its functionality.
1480 edcd876b Michael Hanselmann
    out = os.fdopen(os.dup(fd), "w")
1481 9440aeab Michael Hanselmann
    try:
1482 edcd876b Michael Hanselmann
      for line in ReadFile(file_name).splitlines(True):
1483 edcd876b Michael Hanselmann
        fields = line.split()
1484 edcd876b Michael Hanselmann
        if fields and not fields[0].startswith("#") and ip == fields[0]:
1485 edcd876b Michael Hanselmann
          continue
1486 edcd876b Michael Hanselmann
        out.write(line)
1487 edcd876b Michael Hanselmann
1488 edcd876b Michael Hanselmann
      out.write("%s\t%s" % (ip, hostname))
1489 edcd876b Michael Hanselmann
      if aliases:
1490 edcd876b Michael Hanselmann
        out.write(" %s" % " ".join(aliases))
1491 edcd876b Michael Hanselmann
      out.write("\n")
1492 edcd876b Michael Hanselmann
      out.flush()
1493 9440aeab Michael Hanselmann
    finally:
1494 9440aeab Michael Hanselmann
      out.close()
1495 edcd876b Michael Hanselmann
1496 edcd876b Michael Hanselmann
  WriteFile(file_name, fn=_WriteEtcHosts, mode=0644)
1497 899d2a81 Michael Hanselmann
1498 899d2a81 Michael Hanselmann
1499 ea8ac9c9 Renรฉ Nussbaumer
def AddHostToEtcHosts(hostname, ip):
1500 d9c02ca6 Michael Hanselmann
  """Wrapper around SetEtcHostsEntry.
1501 d9c02ca6 Michael Hanselmann

1502 58885d79 Iustin Pop
  @type hostname: str
1503 58885d79 Iustin Pop
  @param hostname: a hostname that will be resolved and added to
1504 58885d79 Iustin Pop
      L{constants.ETC_HOSTS}
1505 ea8ac9c9 Renรฉ Nussbaumer
  @type ip: str
1506 ea8ac9c9 Renรฉ Nussbaumer
  @param ip: The ip address of the host
1507 58885d79 Iustin Pop

1508 d9c02ca6 Michael Hanselmann
  """
1509 ea8ac9c9 Renรฉ Nussbaumer
  SetEtcHostsEntry(constants.ETC_HOSTS, ip, hostname, [hostname.split(".")[0]])
1510 d9c02ca6 Michael Hanselmann
1511 d9c02ca6 Michael Hanselmann
1512 899d2a81 Michael Hanselmann
def RemoveEtcHostsEntry(file_name, hostname):
1513 3e1cdf9f Michael Hanselmann
  """Removes a hostname from /etc/hosts.
1514 899d2a81 Michael Hanselmann

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

1517 58885d79 Iustin Pop
  @type file_name: str
1518 58885d79 Iustin Pop
  @param file_name: path to the file to modify (usually C{/etc/hosts})
1519 58885d79 Iustin Pop
  @type hostname: str
1520 58885d79 Iustin Pop
  @param hostname: the hostname to be removed
1521 58885d79 Iustin Pop

1522 899d2a81 Michael Hanselmann
  """
1523 edcd876b Michael Hanselmann
  def _WriteEtcHosts(fd):
1524 edcd876b Michael Hanselmann
    # Duplicating file descriptor because os.fdopen's result will automatically
1525 edcd876b Michael Hanselmann
    # close the descriptor, but we would still like to have its functionality.
1526 edcd876b Michael Hanselmann
    out = os.fdopen(os.dup(fd), "w")
1527 899d2a81 Michael Hanselmann
    try:
1528 edcd876b Michael Hanselmann
      for line in ReadFile(file_name).splitlines(True):
1529 edcd876b Michael Hanselmann
        fields = line.split()
1530 edcd876b Michael Hanselmann
        if len(fields) > 1 and not fields[0].startswith("#"):
1531 edcd876b Michael Hanselmann
          names = fields[1:]
1532 edcd876b Michael Hanselmann
          if hostname in names:
1533 edcd876b Michael Hanselmann
            while hostname in names:
1534 edcd876b Michael Hanselmann
              names.remove(hostname)
1535 edcd876b Michael Hanselmann
            if names:
1536 edcd876b Michael Hanselmann
              out.write("%s %s\n" % (fields[0], " ".join(names)))
1537 edcd876b Michael Hanselmann
            continue
1538 59f82e3f Michael Hanselmann
1539 edcd876b Michael Hanselmann
        out.write(line)
1540 edcd876b Michael Hanselmann
1541 edcd876b Michael Hanselmann
      out.flush()
1542 a8083063 Iustin Pop
    finally:
1543 59f82e3f Michael Hanselmann
      out.close()
1544 edcd876b Michael Hanselmann
1545 edcd876b Michael Hanselmann
  WriteFile(file_name, fn=_WriteEtcHosts, mode=0644)
1546 a8083063 Iustin Pop
1547 a8083063 Iustin Pop
1548 d9c02ca6 Michael Hanselmann
def RemoveHostFromEtcHosts(hostname):
1549 d9c02ca6 Michael Hanselmann
  """Wrapper around RemoveEtcHostsEntry.
1550 d9c02ca6 Michael Hanselmann

1551 58885d79 Iustin Pop
  @type hostname: str
1552 58885d79 Iustin Pop
  @param hostname: hostname that will be resolved and its
1553 58885d79 Iustin Pop
      full and shot name will be removed from
1554 58885d79 Iustin Pop
      L{constants.ETC_HOSTS}
1555 58885d79 Iustin Pop

1556 d9c02ca6 Michael Hanselmann
  """
1557 b705c7a6 Manuel Franceschini
  RemoveEtcHostsEntry(constants.ETC_HOSTS, hostname)
1558 b705c7a6 Manuel Franceschini
  RemoveEtcHostsEntry(constants.ETC_HOSTS, hostname.split(".")[0])
1559 d9c02ca6 Michael Hanselmann
1560 d9c02ca6 Michael Hanselmann
1561 1d466a4f Michael Hanselmann
def TimestampForFilename():
1562 1d466a4f Michael Hanselmann
  """Returns the current time formatted for filenames.
1563 1d466a4f Michael Hanselmann

1564 1d466a4f Michael Hanselmann
  The format doesn't contain colons as some shells and applications them as
1565 1d466a4f Michael Hanselmann
  separators.
1566 1d466a4f Michael Hanselmann

1567 1d466a4f Michael Hanselmann
  """
1568 1d466a4f Michael Hanselmann
  return time.strftime("%Y-%m-%d_%H_%M_%S")
1569 1d466a4f Michael Hanselmann
1570 1d466a4f Michael Hanselmann
1571 a8083063 Iustin Pop
def CreateBackup(file_name):
1572 a8083063 Iustin Pop
  """Creates a backup of a file.
1573 a8083063 Iustin Pop

1574 58885d79 Iustin Pop
  @type file_name: str
1575 58885d79 Iustin Pop
  @param file_name: file to be backed up
1576 58885d79 Iustin Pop
  @rtype: str
1577 58885d79 Iustin Pop
  @return: the path to the newly created backup
1578 58885d79 Iustin Pop
  @raise errors.ProgrammerError: for invalid file names
1579 a8083063 Iustin Pop

1580 a8083063 Iustin Pop
  """
1581 a8083063 Iustin Pop
  if not os.path.isfile(file_name):
1582 3ecf6786 Iustin Pop
    raise errors.ProgrammerError("Can't make a backup of a non-file '%s'" %
1583 3ecf6786 Iustin Pop
                                file_name)
1584 a8083063 Iustin Pop
1585 1d466a4f Michael Hanselmann
  prefix = ("%s.backup-%s." %
1586 1d466a4f Michael Hanselmann
            (os.path.basename(file_name), TimestampForFilename()))
1587 65fe4693 Iustin Pop
  dir_name = os.path.dirname(file_name)
1588 081b1e69 Michael Hanselmann
1589 081b1e69 Michael Hanselmann
  fsrc = open(file_name, 'rb')
1590 081b1e69 Michael Hanselmann
  try:
1591 65fe4693 Iustin Pop
    (fd, backup_name) = tempfile.mkstemp(prefix=prefix, dir=dir_name)
1592 081b1e69 Michael Hanselmann
    fdst = os.fdopen(fd, 'wb')
1593 081b1e69 Michael Hanselmann
    try:
1594 1d466a4f Michael Hanselmann
      logging.debug("Backing up %s at %s", file_name, backup_name)
1595 081b1e69 Michael Hanselmann
      shutil.copyfileobj(fsrc, fdst)
1596 081b1e69 Michael Hanselmann
    finally:
1597 081b1e69 Michael Hanselmann
      fdst.close()
1598 081b1e69 Michael Hanselmann
  finally:
1599 081b1e69 Michael Hanselmann
    fsrc.close()
1600 081b1e69 Michael Hanselmann
1601 a8083063 Iustin Pop
  return backup_name
1602 a8083063 Iustin Pop
1603 a8083063 Iustin Pop
1604 a8083063 Iustin Pop
def ShellQuote(value):
1605 a8083063 Iustin Pop
  """Quotes shell argument according to POSIX.
1606 3ecf6786 Iustin Pop

1607 58885d79 Iustin Pop
  @type value: str
1608 58885d79 Iustin Pop
  @param value: the argument to be quoted
1609 58885d79 Iustin Pop
  @rtype: str
1610 58885d79 Iustin Pop
  @return: the quoted value
1611 58885d79 Iustin Pop

1612 a8083063 Iustin Pop
  """
1613 a8083063 Iustin Pop
  if _re_shell_unquoted.match(value):
1614 a8083063 Iustin Pop
    return value
1615 a8083063 Iustin Pop
  else:
1616 a8083063 Iustin Pop
    return "'%s'" % value.replace("'", "'\\''")
1617 a8083063 Iustin Pop
1618 a8083063 Iustin Pop
1619 a8083063 Iustin Pop
def ShellQuoteArgs(args):
1620 58885d79 Iustin Pop
  """Quotes a list of shell arguments.
1621 58885d79 Iustin Pop

1622 58885d79 Iustin Pop
  @type args: list
1623 58885d79 Iustin Pop
  @param args: list of arguments to be quoted
1624 58885d79 Iustin Pop
  @rtype: str
1625 5bbd3f7f Michael Hanselmann
  @return: the quoted arguments concatenated with spaces
1626 a8083063 Iustin Pop

1627 a8083063 Iustin Pop
  """
1628 a8083063 Iustin Pop
  return ' '.join([ShellQuote(i) for i in args])
1629 88d14415 Michael Hanselmann
1630 88d14415 Michael Hanselmann
1631 858905fb Michael Hanselmann
class ShellWriter:
1632 858905fb Michael Hanselmann
  """Helper class to write scripts with indentation.
1633 858905fb Michael Hanselmann

1634 858905fb Michael Hanselmann
  """
1635 858905fb Michael Hanselmann
  INDENT_STR = "  "
1636 858905fb Michael Hanselmann
1637 858905fb Michael Hanselmann
  def __init__(self, fh):
1638 858905fb Michael Hanselmann
    """Initializes this class.
1639 858905fb Michael Hanselmann

1640 858905fb Michael Hanselmann
    """
1641 858905fb Michael Hanselmann
    self._fh = fh
1642 858905fb Michael Hanselmann
    self._indent = 0
1643 858905fb Michael Hanselmann
1644 858905fb Michael Hanselmann
  def IncIndent(self):
1645 858905fb Michael Hanselmann
    """Increase indentation level by 1.
1646 858905fb Michael Hanselmann

1647 858905fb Michael Hanselmann
    """
1648 858905fb Michael Hanselmann
    self._indent += 1
1649 858905fb Michael Hanselmann
1650 858905fb Michael Hanselmann
  def DecIndent(self):
1651 858905fb Michael Hanselmann
    """Decrease indentation level by 1.
1652 858905fb Michael Hanselmann

1653 858905fb Michael Hanselmann
    """
1654 858905fb Michael Hanselmann
    assert self._indent > 0
1655 858905fb Michael Hanselmann
    self._indent -= 1
1656 858905fb Michael Hanselmann
1657 858905fb Michael Hanselmann
  def Write(self, txt, *args):
1658 858905fb Michael Hanselmann
    """Write line to output file.
1659 858905fb Michael Hanselmann

1660 858905fb Michael Hanselmann
    """
1661 858905fb Michael Hanselmann
    assert self._indent >= 0
1662 858905fb Michael Hanselmann
1663 858905fb Michael Hanselmann
    self._fh.write(self._indent * self.INDENT_STR)
1664 858905fb Michael Hanselmann
1665 858905fb Michael Hanselmann
    if args:
1666 858905fb Michael Hanselmann
      self._fh.write(txt % args)
1667 858905fb Michael Hanselmann
    else:
1668 858905fb Michael Hanselmann
      self._fh.write(txt)
1669 858905fb Michael Hanselmann
1670 858905fb Michael Hanselmann
    self._fh.write("\n")
1671 858905fb Michael Hanselmann
1672 858905fb Michael Hanselmann
1673 b5b8309d Guido Trotter
def ListVisibleFiles(path):
1674 58885d79 Iustin Pop
  """Returns a list of visible files in a directory.
1675 58885d79 Iustin Pop

1676 58885d79 Iustin Pop
  @type path: str
1677 58885d79 Iustin Pop
  @param path: the directory to enumerate
1678 58885d79 Iustin Pop
  @rtype: list
1679 58885d79 Iustin Pop
  @return: the list of all files not starting with a dot
1680 04a69a18 Iustin Pop
  @raise ProgrammerError: if L{path} is not an absolue and normalized path
1681 eedbda4b Michael Hanselmann

1682 eedbda4b Michael Hanselmann
  """
1683 04a69a18 Iustin Pop
  if not IsNormAbsPath(path):
1684 04a69a18 Iustin Pop
    raise errors.ProgrammerError("Path passed to ListVisibleFiles is not"
1685 04a69a18 Iustin Pop
                                 " absolute/normalized: '%s'" % path)
1686 f3299a07 Michael Hanselmann
  files = [i for i in os.listdir(path) if not i.startswith(".")]
1687 f3299a07 Michael Hanselmann
  return files
1688 2f8b60b3 Iustin Pop
1689 2f8b60b3 Iustin Pop
1690 257f4c0a Iustin Pop
def GetHomeDir(user, default=None):
1691 257f4c0a Iustin Pop
  """Try to get the homedir of the given user.
1692 257f4c0a Iustin Pop

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

1697 2f8b60b3 Iustin Pop
  """
1698 2f8b60b3 Iustin Pop
  try:
1699 257f4c0a Iustin Pop
    if isinstance(user, basestring):
1700 257f4c0a Iustin Pop
      result = pwd.getpwnam(user)
1701 257f4c0a Iustin Pop
    elif isinstance(user, (int, long)):
1702 257f4c0a Iustin Pop
      result = pwd.getpwuid(user)
1703 257f4c0a Iustin Pop
    else:
1704 257f4c0a Iustin Pop
      raise errors.ProgrammerError("Invalid type passed to GetHomeDir (%s)" %
1705 257f4c0a Iustin Pop
                                   type(user))
1706 2f8b60b3 Iustin Pop
  except KeyError:
1707 2f8b60b3 Iustin Pop
    return default
1708 2f8b60b3 Iustin Pop
  return result.pw_dir
1709 59072e7e Michael Hanselmann
1710 59072e7e Michael Hanselmann
1711 24818e8f Michael Hanselmann
def NewUUID():
1712 59072e7e Michael Hanselmann
  """Returns a random UUID.
1713 59072e7e Michael Hanselmann

1714 58885d79 Iustin Pop
  @note: This is a Linux-specific method as it uses the /proc
1715 58885d79 Iustin Pop
      filesystem.
1716 58885d79 Iustin Pop
  @rtype: str
1717 58885d79 Iustin Pop

1718 59072e7e Michael Hanselmann
  """
1719 13998ef2 Michael Hanselmann
  return ReadFile(_RANDOM_UUID_FILE, size=128).rstrip("\n")
1720 087b34fe Iustin Pop
1721 087b34fe Iustin Pop
1722 ec2c2bc4 Luca Bigliardi
def GenerateSecret(numbytes=20):
1723 33081d90 Iustin Pop
  """Generates a random secret.
1724 33081d90 Iustin Pop

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

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

1733 33081d90 Iustin Pop
  """
1734 ec2c2bc4 Luca Bigliardi
  return os.urandom(numbytes).encode('hex')
1735 33081d90 Iustin Pop
1736 33081d90 Iustin Pop
1737 9dae41ad Guido Trotter
def EnsureDirs(dirs):
1738 9dae41ad Guido Trotter
  """Make required directories, if they don't exist.
1739 9dae41ad Guido Trotter

1740 9dae41ad Guido Trotter
  @param dirs: list of tuples (dir_name, dir_mode)
1741 9dae41ad Guido Trotter
  @type dirs: list of (string, integer)
1742 9dae41ad Guido Trotter

1743 9dae41ad Guido Trotter
  """
1744 9dae41ad Guido Trotter
  for dir_name, dir_mode in dirs:
1745 9dae41ad Guido Trotter
    try:
1746 1b2c8f85 Iustin Pop
      os.mkdir(dir_name, dir_mode)
1747 9dae41ad Guido Trotter
    except EnvironmentError, err:
1748 9dae41ad Guido Trotter
      if err.errno != errno.EEXIST:
1749 9dae41ad Guido Trotter
        raise errors.GenericError("Cannot create needed directory"
1750 1b2c8f85 Iustin Pop
                                  " '%s': %s" % (dir_name, err))
1751 b73360e3 Balazs Lecz
    try:
1752 b73360e3 Balazs Lecz
      os.chmod(dir_name, dir_mode)
1753 b73360e3 Balazs Lecz
    except EnvironmentError, err:
1754 b73360e3 Balazs Lecz
      raise errors.GenericError("Cannot change directory permissions on"
1755 b73360e3 Balazs Lecz
                                " '%s': %s" % (dir_name, err))
1756 9dae41ad Guido Trotter
    if not os.path.isdir(dir_name):
1757 9dae41ad Guido Trotter
      raise errors.GenericError("%s is not a directory" % dir_name)
1758 9dae41ad Guido Trotter
1759 9dae41ad Guido Trotter
1760 582ed043 Guido Trotter
def ReadFile(file_name, size=-1):
1761 ca0aa6d0 Michael Hanselmann
  """Reads a file.
1762 ca0aa6d0 Michael Hanselmann

1763 016308cb Iustin Pop
  @type size: int
1764 016308cb Iustin Pop
  @param size: Read at most size bytes (if negative, entire file)
1765 58885d79 Iustin Pop
  @rtype: str
1766 5bbd3f7f Michael Hanselmann
  @return: the (possibly partial) content of the file
1767 ca0aa6d0 Michael Hanselmann

1768 ca0aa6d0 Michael Hanselmann
  """
1769 ca0aa6d0 Michael Hanselmann
  f = open(file_name, "r")
1770 ca0aa6d0 Michael Hanselmann
  try:
1771 582ed043 Guido Trotter
    return f.read(size)
1772 ca0aa6d0 Michael Hanselmann
  finally:
1773 ca0aa6d0 Michael Hanselmann
    f.close()
1774 ca0aa6d0 Michael Hanselmann
1775 ca0aa6d0 Michael Hanselmann
1776 087b34fe Iustin Pop
def WriteFile(file_name, fn=None, data=None,
1777 087b34fe Iustin Pop
              mode=None, uid=-1, gid=-1,
1778 71714516 Michael Hanselmann
              atime=None, mtime=None, close=True,
1779 04a8d789 Michael Hanselmann
              dry_run=False, backup=False,
1780 71714516 Michael Hanselmann
              prewrite=None, postwrite=None):
1781 087b34fe Iustin Pop
  """(Over)write a file atomically.
1782 087b34fe Iustin Pop

1783 087b34fe Iustin Pop
  The file_name and either fn (a function taking one argument, the
1784 087b34fe Iustin Pop
  file descriptor, and which should write the data to it) or data (the
1785 087b34fe Iustin Pop
  contents of the file) must be passed. The other arguments are
1786 087b34fe Iustin Pop
  optional and allow setting the file mode, owner and group, and the
1787 087b34fe Iustin Pop
  mtime/atime of the file.
1788 087b34fe Iustin Pop

1789 087b34fe Iustin Pop
  If the function doesn't raise an exception, it has succeeded and the
1790 69efe319 Michael Hanselmann
  target file has the new contents. If the function has raised an
1791 087b34fe Iustin Pop
  exception, an existing target file should be unmodified and the
1792 087b34fe Iustin Pop
  temporary file should be removed.
1793 087b34fe Iustin Pop

1794 58885d79 Iustin Pop
  @type file_name: str
1795 58885d79 Iustin Pop
  @param file_name: the target filename
1796 58885d79 Iustin Pop
  @type fn: callable
1797 58885d79 Iustin Pop
  @param fn: content writing function, called with
1798 58885d79 Iustin Pop
      file descriptor as parameter
1799 69efe319 Michael Hanselmann
  @type data: str
1800 58885d79 Iustin Pop
  @param data: contents of the file
1801 58885d79 Iustin Pop
  @type mode: int
1802 58885d79 Iustin Pop
  @param mode: file mode
1803 58885d79 Iustin Pop
  @type uid: int
1804 58885d79 Iustin Pop
  @param uid: the owner of the file
1805 58885d79 Iustin Pop
  @type gid: int
1806 58885d79 Iustin Pop
  @param gid: the group of the file
1807 58885d79 Iustin Pop
  @type atime: int
1808 58885d79 Iustin Pop
  @param atime: a custom access time to be set on the file
1809 58885d79 Iustin Pop
  @type mtime: int
1810 58885d79 Iustin Pop
  @param mtime: a custom modification time to be set on the file
1811 58885d79 Iustin Pop
  @type close: boolean
1812 58885d79 Iustin Pop
  @param close: whether to close file after writing it
1813 58885d79 Iustin Pop
  @type prewrite: callable
1814 58885d79 Iustin Pop
  @param prewrite: function to be called before writing content
1815 58885d79 Iustin Pop
  @type postwrite: callable
1816 58885d79 Iustin Pop
  @param postwrite: function to be called after writing content
1817 58885d79 Iustin Pop

1818 58885d79 Iustin Pop
  @rtype: None or int
1819 58885d79 Iustin Pop
  @return: None if the 'close' parameter evaluates to True,
1820 58885d79 Iustin Pop
      otherwise the file descriptor
1821 58885d79 Iustin Pop

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

1824 087b34fe Iustin Pop
  """
1825 04a8d789 Michael Hanselmann
  if not os.path.isabs(file_name):
1826 087b34fe Iustin Pop
    raise errors.ProgrammerError("Path passed to WriteFile is not"
1827 087b34fe Iustin Pop
                                 " absolute: '%s'" % file_name)
1828 087b34fe Iustin Pop
1829 087b34fe Iustin Pop
  if [fn, data].count(None) != 1:
1830 087b34fe Iustin Pop
    raise errors.ProgrammerError("fn or data required")
1831 087b34fe Iustin Pop
1832 087b34fe Iustin Pop
  if [atime, mtime].count(None) == 1:
1833 087b34fe Iustin Pop
    raise errors.ProgrammerError("Both atime and mtime must be either"
1834 087b34fe Iustin Pop
                                 " set or None")
1835 087b34fe Iustin Pop
1836 70f4497c Michael Hanselmann
  if backup and not dry_run and os.path.isfile(file_name):
1837 70f4497c Michael Hanselmann
    CreateBackup(file_name)
1838 087b34fe Iustin Pop
1839 087b34fe Iustin Pop
  dir_name, base_name = os.path.split(file_name)
1840 087b34fe Iustin Pop
  fd, new_name = tempfile.mkstemp('.new', base_name, dir_name)
1841 81b7354c Iustin Pop
  do_remove = True
1842 087b34fe Iustin Pop
  # here we need to make sure we remove the temp file, if any error
1843 087b34fe Iustin Pop
  # leaves it in place
1844 087b34fe Iustin Pop
  try:
1845 087b34fe Iustin Pop
    if uid != -1 or gid != -1:
1846 087b34fe Iustin Pop
      os.chown(new_name, uid, gid)
1847 087b34fe Iustin Pop
    if mode:
1848 087b34fe Iustin Pop
      os.chmod(new_name, mode)
1849 71714516 Michael Hanselmann
    if callable(prewrite):
1850 71714516 Michael Hanselmann
      prewrite(fd)
1851 087b34fe Iustin Pop
    if data is not None:
1852 087b34fe Iustin Pop
      os.write(fd, data)
1853 087b34fe Iustin Pop
    else:
1854 087b34fe Iustin Pop
      fn(fd)
1855 71714516 Michael Hanselmann
    if callable(postwrite):
1856 71714516 Michael Hanselmann
      postwrite(fd)
1857 087b34fe Iustin Pop
    os.fsync(fd)
1858 087b34fe Iustin Pop
    if atime is not None and mtime is not None:
1859 087b34fe Iustin Pop
      os.utime(new_name, (atime, mtime))
1860 70f4497c Michael Hanselmann
    if not dry_run:
1861 70f4497c Michael Hanselmann
      os.rename(new_name, file_name)
1862 81b7354c Iustin Pop
      do_remove = False
1863 087b34fe Iustin Pop
  finally:
1864 71714516 Michael Hanselmann
    if close:
1865 71714516 Michael Hanselmann
      os.close(fd)
1866 71714516 Michael Hanselmann
      result = None
1867 71714516 Michael Hanselmann
    else:
1868 71714516 Michael Hanselmann
      result = fd
1869 81b7354c Iustin Pop
    if do_remove:
1870 81b7354c Iustin Pop
      RemoveFile(new_name)
1871 78feb6fb Guido Trotter
1872 71714516 Michael Hanselmann
  return result
1873 71714516 Michael Hanselmann
1874 78feb6fb Guido Trotter
1875 9e100285 Iustin Pop
def GetFileID(path=None, fd=None):
1876 9e100285 Iustin Pop
  """Returns the file 'id', i.e. the dev/inode and mtime information.
1877 9e100285 Iustin Pop

1878 9e100285 Iustin Pop
  Either the path to the file or the fd must be given.
1879 9e100285 Iustin Pop

1880 9e100285 Iustin Pop
  @param path: the file path
1881 9e100285 Iustin Pop
  @param fd: a file descriptor
1882 9e100285 Iustin Pop
  @return: a tuple of (device number, inode number, mtime)
1883 9e100285 Iustin Pop

1884 9e100285 Iustin Pop
  """
1885 9e100285 Iustin Pop
  if [path, fd].count(None) != 1:
1886 9e100285 Iustin Pop
    raise errors.ProgrammerError("One and only one of fd/path must be given")
1887 9e100285 Iustin Pop
1888 9e100285 Iustin Pop
  if fd is None:
1889 9e100285 Iustin Pop
    st = os.stat(path)
1890 9e100285 Iustin Pop
  else:
1891 9e100285 Iustin Pop
    st = os.fstat(fd)
1892 9e100285 Iustin Pop
1893 9e100285 Iustin Pop
  return (st.st_dev, st.st_ino, st.st_mtime)
1894 9e100285 Iustin Pop
1895 9e100285 Iustin Pop
1896 9e100285 Iustin Pop
def VerifyFileID(fi_disk, fi_ours):
1897 9e100285 Iustin Pop
  """Verifies that two file IDs are matching.
1898 9e100285 Iustin Pop

1899 9e100285 Iustin Pop
  Differences in the inode/device are not accepted, but and older
1900 9e100285 Iustin Pop
  timestamp for fi_disk is accepted.
1901 9e100285 Iustin Pop

1902 9e100285 Iustin Pop
  @param fi_disk: tuple (dev, inode, mtime) representing the actual
1903 9e100285 Iustin Pop
      file data
1904 9e100285 Iustin Pop
  @param fi_ours: tuple (dev, inode, mtime) representing the last
1905 9e100285 Iustin Pop
      written file data
1906 9e100285 Iustin Pop
  @rtype: boolean
1907 9e100285 Iustin Pop

1908 9e100285 Iustin Pop
  """
1909 9e100285 Iustin Pop
  (d1, i1, m1) = fi_disk
1910 9e100285 Iustin Pop
  (d2, i2, m2) = fi_ours
1911 9e100285 Iustin Pop
1912 9e100285 Iustin Pop
  return (d1, i1) == (d2, i2) and m1 <= m2
1913 9e100285 Iustin Pop
1914 9e100285 Iustin Pop
1915 4138d39f Iustin Pop
def SafeWriteFile(file_name, file_id, **kwargs):
1916 4138d39f Iustin Pop
  """Wraper over L{WriteFile} that locks the target file.
1917 4138d39f Iustin Pop

1918 4138d39f Iustin Pop
  By keeping the target file locked during WriteFile, we ensure that
1919 4138d39f Iustin Pop
  cooperating writers will safely serialise access to the file.
1920 4138d39f Iustin Pop

1921 4138d39f Iustin Pop
  @type file_name: str
1922 4138d39f Iustin Pop
  @param file_name: the target filename
1923 4138d39f Iustin Pop
  @type file_id: tuple
1924 4138d39f Iustin Pop
  @param file_id: a result from L{GetFileID}
1925 4138d39f Iustin Pop

1926 4138d39f Iustin Pop
  """
1927 4138d39f Iustin Pop
  fd = os.open(file_name, os.O_RDONLY | os.O_CREAT)
1928 4138d39f Iustin Pop
  try:
1929 4138d39f Iustin Pop
    LockFile(fd)
1930 4138d39f Iustin Pop
    if file_id is not None:
1931 4138d39f Iustin Pop
      disk_id = GetFileID(fd=fd)
1932 4138d39f Iustin Pop
      if not VerifyFileID(disk_id, file_id):
1933 4138d39f Iustin Pop
        raise errors.LockError("Cannot overwrite file %s, it has been modified"
1934 4138d39f Iustin Pop
                               " since last written" % file_name)
1935 4138d39f Iustin Pop
    return WriteFile(file_name, **kwargs)
1936 4138d39f Iustin Pop
  finally:
1937 4138d39f Iustin Pop
    os.close(fd)
1938 4138d39f Iustin Pop
1939 4138d39f Iustin Pop
1940 e587b46a Guido Trotter
def ReadOneLineFile(file_name, strict=False):
1941 e587b46a Guido Trotter
  """Return the first non-empty line from a file.
1942 e587b46a Guido Trotter

1943 e587b46a Guido Trotter
  @type strict: boolean
1944 e587b46a Guido Trotter
  @param strict: if True, abort if the file has more than one
1945 e587b46a Guido Trotter
      non-empty line
1946 e587b46a Guido Trotter

1947 e587b46a Guido Trotter
  """
1948 e587b46a Guido Trotter
  file_lines = ReadFile(file_name).splitlines()
1949 e587b46a Guido Trotter
  full_lines = filter(bool, file_lines)
1950 e587b46a Guido Trotter
  if not file_lines or not full_lines:
1951 e587b46a Guido Trotter
    raise errors.GenericError("No data in one-liner file %s" % file_name)
1952 e587b46a Guido Trotter
  elif strict and len(full_lines) > 1:
1953 e587b46a Guido Trotter
    raise errors.GenericError("Too many lines in one-liner file %s" %
1954 e587b46a Guido Trotter
                              file_name)
1955 e587b46a Guido Trotter
  return full_lines[0]
1956 e587b46a Guido Trotter
1957 e587b46a Guido Trotter
1958 7b4126b7 Iustin Pop
def FirstFree(seq, base=0):
1959 7b4126b7 Iustin Pop
  """Returns the first non-existing integer from seq.
1960 7b4126b7 Iustin Pop

1961 7b4126b7 Iustin Pop
  The seq argument should be a sorted list of positive integers. The
1962 7b4126b7 Iustin Pop
  first time the index of an element is smaller than the element
1963 7b4126b7 Iustin Pop
  value, the index will be returned.
1964 7b4126b7 Iustin Pop

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

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

1970 58885d79 Iustin Pop
  @type seq: sequence
1971 58885d79 Iustin Pop
  @param seq: the sequence to be analyzed.
1972 58885d79 Iustin Pop
  @type base: int
1973 58885d79 Iustin Pop
  @param base: use this value as the base index of the sequence
1974 58885d79 Iustin Pop
  @rtype: int
1975 58885d79 Iustin Pop
  @return: the first non-used index in the sequence
1976 7b4126b7 Iustin Pop

1977 7b4126b7 Iustin Pop
  """
1978 7b4126b7 Iustin Pop
  for idx, elem in enumerate(seq):
1979 7b4126b7 Iustin Pop
    assert elem >= base, "Passed element is higher than base offset"
1980 7b4126b7 Iustin Pop
    if elem > idx + base:
1981 7b4126b7 Iustin Pop
      # idx is not used
1982 7b4126b7 Iustin Pop
      return idx + base
1983 7b4126b7 Iustin Pop
  return None
1984 7b4126b7 Iustin Pop
1985 7b4126b7 Iustin Pop
1986 dfdc4060 Guido Trotter
def SingleWaitForFdCondition(fdobj, event, timeout):
1987 dcd511c8 Guido Trotter
  """Waits for a condition to occur on the socket.
1988 dcd511c8 Guido Trotter

1989 dfdc4060 Guido Trotter
  Immediately returns at the first interruption.
1990 dfdc4060 Guido Trotter

1991 dfdc4060 Guido Trotter
  @type fdobj: integer or object supporting a fileno() method
1992 dfdc4060 Guido Trotter
  @param fdobj: entity to wait for events on
1993 dfdc4060 Guido Trotter
  @type event: integer
1994 dcd511c8 Guido Trotter
  @param event: ORed condition (see select module)
1995 dcd511c8 Guido Trotter
  @type timeout: float or None
1996 dcd511c8 Guido Trotter
  @param timeout: Timeout in seconds
1997 dcd511c8 Guido Trotter
  @rtype: int or None
1998 dcd511c8 Guido Trotter
  @return: None for timeout, otherwise occured conditions
1999 dcd511c8 Guido Trotter

2000 dcd511c8 Guido Trotter
  """
2001 dcd511c8 Guido Trotter
  check = (event | select.POLLPRI |
2002 dcd511c8 Guido Trotter
           select.POLLNVAL | select.POLLHUP | select.POLLERR)
2003 dcd511c8 Guido Trotter
2004 dcd511c8 Guido Trotter
  if timeout is not None:
2005 dcd511c8 Guido Trotter
    # Poller object expects milliseconds
2006 dcd511c8 Guido Trotter
    timeout *= 1000
2007 dcd511c8 Guido Trotter
2008 dcd511c8 Guido Trotter
  poller = select.poll()
2009 dfdc4060 Guido Trotter
  poller.register(fdobj, event)
2010 dcd511c8 Guido Trotter
  try:
2011 dfdc4060 Guido Trotter
    # TODO: If the main thread receives a signal and we have no timeout, we
2012 dfdc4060 Guido Trotter
    # could wait forever. This should check a global "quit" flag or something
2013 dfdc4060 Guido Trotter
    # every so often.
2014 dfdc4060 Guido Trotter
    io_events = poller.poll(timeout)
2015 dfdc4060 Guido Trotter
  except select.error, err:
2016 dfdc4060 Guido Trotter
    if err[0] != errno.EINTR:
2017 dfdc4060 Guido Trotter
      raise
2018 dfdc4060 Guido Trotter
    io_events = []
2019 dfdc4060 Guido Trotter
  if io_events and io_events[0][1] & check:
2020 dfdc4060 Guido Trotter
    return io_events[0][1]
2021 dfdc4060 Guido Trotter
  else:
2022 dfdc4060 Guido Trotter
    return None
2023 dfdc4060 Guido Trotter
2024 dfdc4060 Guido Trotter
2025 dfdc4060 Guido Trotter
class FdConditionWaiterHelper(object):
2026 dfdc4060 Guido Trotter
  """Retry helper for WaitForFdCondition.
2027 dfdc4060 Guido Trotter

2028 dfdc4060 Guido Trotter
  This class contains the retried and wait functions that make sure
2029 dfdc4060 Guido Trotter
  WaitForFdCondition can continue waiting until the timeout is actually
2030 dfdc4060 Guido Trotter
  expired.
2031 dfdc4060 Guido Trotter

2032 dfdc4060 Guido Trotter
  """
2033 dfdc4060 Guido Trotter
2034 dfdc4060 Guido Trotter
  def __init__(self, timeout):
2035 dfdc4060 Guido Trotter
    self.timeout = timeout
2036 dfdc4060 Guido Trotter
2037 dfdc4060 Guido Trotter
  def Poll(self, fdobj, event):
2038 dfdc4060 Guido Trotter
    result = SingleWaitForFdCondition(fdobj, event, self.timeout)
2039 dfdc4060 Guido Trotter
    if result is None:
2040 dfdc4060 Guido Trotter
      raise RetryAgain()
2041 dfdc4060 Guido Trotter
    else:
2042 dfdc4060 Guido Trotter
      return result
2043 dfdc4060 Guido Trotter
2044 dfdc4060 Guido Trotter
  def UpdateTimeout(self, timeout):
2045 dfdc4060 Guido Trotter
    self.timeout = timeout
2046 dfdc4060 Guido Trotter
2047 dfdc4060 Guido Trotter
2048 dfdc4060 Guido Trotter
def WaitForFdCondition(fdobj, event, timeout):
2049 dfdc4060 Guido Trotter
  """Waits for a condition to occur on the socket.
2050 dfdc4060 Guido Trotter

2051 dfdc4060 Guido Trotter
  Retries until the timeout is expired, even if interrupted.
2052 dfdc4060 Guido Trotter

2053 dfdc4060 Guido Trotter
  @type fdobj: integer or object supporting a fileno() method
2054 dfdc4060 Guido Trotter
  @param fdobj: entity to wait for events on
2055 dfdc4060 Guido Trotter
  @type event: integer
2056 dfdc4060 Guido Trotter
  @param event: ORed condition (see select module)
2057 dfdc4060 Guido Trotter
  @type timeout: float or None
2058 dfdc4060 Guido Trotter
  @param timeout: Timeout in seconds
2059 dfdc4060 Guido Trotter
  @rtype: int or None
2060 dfdc4060 Guido Trotter
  @return: None for timeout, otherwise occured conditions
2061 dfdc4060 Guido Trotter

2062 dfdc4060 Guido Trotter
  """
2063 dfdc4060 Guido Trotter
  if timeout is not None:
2064 dfdc4060 Guido Trotter
    retrywaiter = FdConditionWaiterHelper(timeout)
2065 1b429e2a Iustin Pop
    try:
2066 1b429e2a Iustin Pop
      result = Retry(retrywaiter.Poll, RETRY_REMAINING_TIME, timeout,
2067 1b429e2a Iustin Pop
                     args=(fdobj, event), wait_fn=retrywaiter.UpdateTimeout)
2068 1b429e2a Iustin Pop
    except RetryTimeout:
2069 1b429e2a Iustin Pop
      result = None
2070 dfdc4060 Guido Trotter
  else:
2071 dfdc4060 Guido Trotter
    result = None
2072 dfdc4060 Guido Trotter
    while result is None:
2073 dfdc4060 Guido Trotter
      result = SingleWaitForFdCondition(fdobj, event, timeout)
2074 dfdc4060 Guido Trotter
  return result
2075 2de64672 Iustin Pop
2076 2de64672 Iustin Pop
2077 f7414041 Michael Hanselmann
def UniqueSequence(seq):
2078 f7414041 Michael Hanselmann
  """Returns a list with unique elements.
2079 f7414041 Michael Hanselmann

2080 f7414041 Michael Hanselmann
  Element order is preserved.
2081 58885d79 Iustin Pop

2082 58885d79 Iustin Pop
  @type seq: sequence
2083 5bbd3f7f Michael Hanselmann
  @param seq: the sequence with the source elements
2084 58885d79 Iustin Pop
  @rtype: list
2085 58885d79 Iustin Pop
  @return: list of unique elements from seq
2086 58885d79 Iustin Pop

2087 f7414041 Michael Hanselmann
  """
2088 f7414041 Michael Hanselmann
  seen = set()
2089 f7414041 Michael Hanselmann
  return [i for i in seq if i not in seen and not seen.add(i)]
2090 1862d460 Alexander Schreiber
2091 1862d460 Alexander Schreiber
2092 82187135 Renรฉ Nussbaumer
def NormalizeAndValidateMac(mac):
2093 82187135 Renรฉ Nussbaumer
  """Normalizes and check if a MAC address is valid.
2094 1862d460 Alexander Schreiber

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

2098 58885d79 Iustin Pop
  @type mac: str
2099 58885d79 Iustin Pop
  @param mac: the MAC to be validated
2100 82187135 Renรฉ Nussbaumer
  @rtype: str
2101 82187135 Renรฉ Nussbaumer
  @return: returns the normalized and validated MAC.
2102 82187135 Renรฉ Nussbaumer

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

2105 1862d460 Alexander Schreiber
  """
2106 8fb00704 Iustin Pop
  if not _MAC_CHECK.match(mac):
2107 82187135 Renรฉ Nussbaumer
    raise errors.OpPrereqError("Invalid MAC address specified: %s" %
2108 82187135 Renรฉ Nussbaumer
                               mac, errors.ECODE_INVAL)
2109 82187135 Renรฉ Nussbaumer
2110 82187135 Renรฉ Nussbaumer
  return mac.lower()
2111 06009e27 Iustin Pop
2112 06009e27 Iustin Pop
2113 06009e27 Iustin Pop
def TestDelay(duration):
2114 06009e27 Iustin Pop
  """Sleep for a fixed amount of time.
2115 06009e27 Iustin Pop

2116 58885d79 Iustin Pop
  @type duration: float
2117 58885d79 Iustin Pop
  @param duration: the sleep duration
2118 58885d79 Iustin Pop
  @rtype: boolean
2119 58885d79 Iustin Pop
  @return: False for negative value, True otherwise
2120 58885d79 Iustin Pop

2121 06009e27 Iustin Pop
  """
2122 06009e27 Iustin Pop
  if duration < 0:
2123 38ea42a1 Iustin Pop
    return False, "Invalid sleep duration"
2124 06009e27 Iustin Pop
  time.sleep(duration)
2125 38ea42a1 Iustin Pop
  return True, None
2126 8f765069 Iustin Pop
2127 8f765069 Iustin Pop
2128 7d88772a Iustin Pop
def _CloseFDNoErr(fd, retries=5):
2129 7d88772a Iustin Pop
  """Close a file descriptor ignoring errors.
2130 8f765069 Iustin Pop

2131 7d88772a Iustin Pop
  @type fd: int
2132 7d88772a Iustin Pop
  @param fd: the file descriptor
2133 7d88772a Iustin Pop
  @type retries: int
2134 7d88772a Iustin Pop
  @param retries: how many retries to make, in case we get any
2135 7d88772a Iustin Pop
      other error than EBADF
2136 7d88772a Iustin Pop

2137 7d88772a Iustin Pop
  """
2138 7d88772a Iustin Pop
  try:
2139 7d88772a Iustin Pop
    os.close(fd)
2140 7d88772a Iustin Pop
  except OSError, err:
2141 7d88772a Iustin Pop
    if err.errno != errno.EBADF:
2142 7d88772a Iustin Pop
      if retries > 0:
2143 7d88772a Iustin Pop
        _CloseFDNoErr(fd, retries - 1)
2144 7d88772a Iustin Pop
    # else either it's closed already or we're out of retries, so we
2145 7d88772a Iustin Pop
    # ignore this and go on
2146 7d88772a Iustin Pop
2147 7d88772a Iustin Pop
2148 7d88772a Iustin Pop
def CloseFDs(noclose_fds=None):
2149 7d88772a Iustin Pop
  """Close file descriptors.
2150 7d88772a Iustin Pop

2151 7d88772a Iustin Pop
  This closes all file descriptors above 2 (i.e. except
2152 7d88772a Iustin Pop
  stdin/out/err).
2153 8f765069 Iustin Pop

2154 58885d79 Iustin Pop
  @type noclose_fds: list or None
2155 58885d79 Iustin Pop
  @param noclose_fds: if given, it denotes a list of file descriptor
2156 58885d79 Iustin Pop
      that should not be closed
2157 58885d79 Iustin Pop

2158 8f765069 Iustin Pop
  """
2159 8f765069 Iustin Pop
  # Default maximum for the number of available file descriptors.
2160 8f765069 Iustin Pop
  if 'SC_OPEN_MAX' in os.sysconf_names:
2161 8f765069 Iustin Pop
    try:
2162 8f765069 Iustin Pop
      MAXFD = os.sysconf('SC_OPEN_MAX')
2163 8f765069 Iustin Pop
      if MAXFD < 0:
2164 8f765069 Iustin Pop
        MAXFD = 1024
2165 8f765069 Iustin Pop
    except OSError:
2166 8f765069 Iustin Pop
      MAXFD = 1024
2167 8f765069 Iustin Pop
  else:
2168 8f765069 Iustin Pop
    MAXFD = 1024
2169 7d88772a Iustin Pop
  maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
2170 7d88772a Iustin Pop
  if (maxfd == resource.RLIM_INFINITY):
2171 7d88772a Iustin Pop
    maxfd = MAXFD
2172 7d88772a Iustin Pop
2173 7d88772a Iustin Pop
  # Iterate through and close all file descriptors (except the standard ones)
2174 7d88772a Iustin Pop
  for fd in range(3, maxfd):
2175 7d88772a Iustin Pop
    if noclose_fds and fd in noclose_fds:
2176 7d88772a Iustin Pop
      continue
2177 7d88772a Iustin Pop
    _CloseFDNoErr(fd)
2178 7d88772a Iustin Pop
2179 7d88772a Iustin Pop
2180 4c32a8bd Luca Bigliardi
def Mlockall(_ctypes=ctypes):
2181 4b6fa0bf Luca Bigliardi
  """Lock current process' virtual address space into RAM.
2182 4b6fa0bf Luca Bigliardi

2183 4b6fa0bf Luca Bigliardi
  This is equivalent to the C call mlockall(MCL_CURRENT|MCL_FUTURE),
2184 4b6fa0bf Luca Bigliardi
  see mlock(2) for more details. This function requires ctypes module.
2185 4b6fa0bf Luca Bigliardi

2186 4c32a8bd Luca Bigliardi
  @raises errors.NoCtypesError: if ctypes module is not found
2187 4c32a8bd Luca Bigliardi

2188 4b6fa0bf Luca Bigliardi
  """
2189 4c32a8bd Luca Bigliardi
  if _ctypes is None:
2190 4c32a8bd Luca Bigliardi
    raise errors.NoCtypesError()
2191 4b6fa0bf Luca Bigliardi
2192 4c32a8bd Luca Bigliardi
  libc = _ctypes.cdll.LoadLibrary("libc.so.6")
2193 4b6fa0bf Luca Bigliardi
  if libc is None:
2194 4b6fa0bf Luca Bigliardi
    logging.error("Cannot set memory lock, ctypes cannot load libc")
2195 4b6fa0bf Luca Bigliardi
    return
2196 4b6fa0bf Luca Bigliardi
2197 4b6fa0bf Luca Bigliardi
  # Some older version of the ctypes module don't have built-in functionality
2198 4b6fa0bf Luca Bigliardi
  # to access the errno global variable, where function error codes are stored.
2199 4b6fa0bf Luca Bigliardi
  # By declaring this variable as a pointer to an integer we can then access
2200 4b6fa0bf Luca Bigliardi
  # its value correctly, should the mlockall call fail, in order to see what
2201 4b6fa0bf Luca Bigliardi
  # the actual error code was.
2202 20601361 Luca Bigliardi
  # pylint: disable-msg=W0212
2203 4c32a8bd Luca Bigliardi
  libc.__errno_location.restype = _ctypes.POINTER(_ctypes.c_int)
2204 4b6fa0bf Luca Bigliardi
2205 4b6fa0bf Luca Bigliardi
  if libc.mlockall(_MCL_CURRENT | _MCL_FUTURE):
2206 20601361 Luca Bigliardi
    # pylint: disable-msg=W0212
2207 6ed0bbce Luca Bigliardi
    logging.error("Cannot set memory lock: %s",
2208 4b6fa0bf Luca Bigliardi
                  os.strerror(libc.__errno_location().contents.value))
2209 4b6fa0bf Luca Bigliardi
    return
2210 4b6fa0bf Luca Bigliardi
2211 4b6fa0bf Luca Bigliardi
  logging.debug("Memory lock set")
2212 4b6fa0bf Luca Bigliardi
2213 4b6fa0bf Luca Bigliardi
2214 0070a462 Renรฉ Nussbaumer
def Daemonize(logfile):
2215 7d88772a Iustin Pop
  """Daemonize the current process.
2216 7d88772a Iustin Pop

2217 7d88772a Iustin Pop
  This detaches the current process from the controlling terminal and
2218 7d88772a Iustin Pop
  runs it in the background as a daemon.
2219 7d88772a Iustin Pop

2220 7d88772a Iustin Pop
  @type logfile: str
2221 7d88772a Iustin Pop
  @param logfile: the logfile to which we should redirect stdout/stderr
2222 7d88772a Iustin Pop
  @rtype: int
2223 5fcc718f Iustin Pop
  @return: the value zero
2224 7d88772a Iustin Pop

2225 7d88772a Iustin Pop
  """
2226 7260cfbe Iustin Pop
  # pylint: disable-msg=W0212
2227 7260cfbe Iustin Pop
  # yes, we really want os._exit
2228 8f765069 Iustin Pop
2229 b78aa8c2 Iustin Pop
  # TODO: do another attempt to merge Daemonize and StartDaemon, or at
2230 b78aa8c2 Iustin Pop
  # least abstract the pipe functionality between them
2231 b78aa8c2 Iustin Pop
2232 b78aa8c2 Iustin Pop
  # Create pipe for sending error messages
2233 b78aa8c2 Iustin Pop
  (rpipe, wpipe) = os.pipe()
2234 b78aa8c2 Iustin Pop
2235 8f765069 Iustin Pop
  # this might fail
2236 8f765069 Iustin Pop
  pid = os.fork()
2237 8f765069 Iustin Pop
  if (pid == 0):  # The first child.
2238 0260032c Iustin Pop
    SetupDaemonEnv()
2239 0260032c Iustin Pop
2240 8f765069 Iustin Pop
    # this might fail
2241 8f765069 Iustin Pop
    pid = os.fork() # Fork a second child.
2242 8f765069 Iustin Pop
    if (pid == 0):  # The second child.
2243 b78aa8c2 Iustin Pop
      _CloseFDNoErr(rpipe)
2244 8f765069 Iustin Pop
    else:
2245 8f765069 Iustin Pop
      # exit() or _exit()?  See below.
2246 8f765069 Iustin Pop
      os._exit(0) # Exit parent (the first child) of the second child.
2247 8f765069 Iustin Pop
  else:
2248 b78aa8c2 Iustin Pop
    _CloseFDNoErr(wpipe)
2249 b78aa8c2 Iustin Pop
    # Wait for daemon to be started (or an error message to
2250 b78aa8c2 Iustin Pop
    # arrive) and read up to 100 KB as an error message
2251 b78aa8c2 Iustin Pop
    errormsg = RetryOnSignal(os.read, rpipe, 100 * 1024)
2252 b78aa8c2 Iustin Pop
    if errormsg:
2253 b78aa8c2 Iustin Pop
      sys.stderr.write("Error when starting daemon process: %r\n" % errormsg)
2254 b78aa8c2 Iustin Pop
      rcode = 1
2255 b78aa8c2 Iustin Pop
    else:
2256 b78aa8c2 Iustin Pop
      rcode = 0
2257 b78aa8c2 Iustin Pop
    os._exit(rcode) # Exit parent of the first child.
2258 8f765069 Iustin Pop
2259 79634555 Iustin Pop
  SetupDaemonFDs(logfile, None)
2260 b78aa8c2 Iustin Pop
  return wpipe
2261 57c177af Iustin Pop
2262 57c177af Iustin Pop
2263 53beffbb Iustin Pop
def DaemonPidFileName(name):
2264 58885d79 Iustin Pop
  """Compute a ganeti pid file absolute path
2265 58885d79 Iustin Pop

2266 58885d79 Iustin Pop
  @type name: str
2267 58885d79 Iustin Pop
  @param name: the daemon name
2268 58885d79 Iustin Pop
  @rtype: str
2269 58885d79 Iustin Pop
  @return: the full path to the pidfile corresponding to the given
2270 58885d79 Iustin Pop
      daemon name
2271 b330ac0b Guido Trotter

2272 b330ac0b Guido Trotter
  """
2273 c4feafe8 Iustin Pop
  return PathJoin(constants.RUN_GANETI_DIR, "%s.pid" % name)
2274 b330ac0b Guido Trotter
2275 b330ac0b Guido Trotter
2276 2826b361 Guido Trotter
def EnsureDaemon(name):
2277 2826b361 Guido Trotter
  """Check for and start daemon if not alive.
2278 2826b361 Guido Trotter

2279 2826b361 Guido Trotter
  """
2280 2826b361 Guido Trotter
  result = RunCmd([constants.DAEMON_UTIL, "check-and-start", name])
2281 2826b361 Guido Trotter
  if result.failed:
2282 2826b361 Guido Trotter
    logging.error("Can't start daemon '%s', failure %s, output: %s",
2283 2826b361 Guido Trotter
                  name, result.fail_reason, result.output)
2284 2826b361 Guido Trotter
    return False
2285 2826b361 Guido Trotter
2286 2826b361 Guido Trotter
  return True
2287 b330ac0b Guido Trotter
2288 b330ac0b Guido Trotter
2289 db147305 Tom Limoncelli
def StopDaemon(name):
2290 db147305 Tom Limoncelli
  """Stop daemon
2291 db147305 Tom Limoncelli

2292 db147305 Tom Limoncelli
  """
2293 db147305 Tom Limoncelli
  result = RunCmd([constants.DAEMON_UTIL, "stop", name])
2294 db147305 Tom Limoncelli
  if result.failed:
2295 db147305 Tom Limoncelli
    logging.error("Can't stop daemon '%s', failure %s, output: %s",
2296 db147305 Tom Limoncelli
                  name, result.fail_reason, result.output)
2297 db147305 Tom Limoncelli
    return False
2298 db147305 Tom Limoncelli
2299 db147305 Tom Limoncelli
  return True
2300 db147305 Tom Limoncelli
2301 db147305 Tom Limoncelli
2302 5c4d37f9 Iustin Pop
def WritePidFile(pidfile):
2303 b330ac0b Guido Trotter
  """Write the current process pidfile.
2304 b330ac0b Guido Trotter

2305 614244bd Iustin Pop
  @type pidfile: sting
2306 614244bd Iustin Pop
  @param pidfile: the path to the file to be written
2307 614244bd Iustin Pop
  @raise errors.LockError: if the pid file already exists and
2308 58885d79 Iustin Pop
      points to a live process
2309 614244bd Iustin Pop
  @rtype: int
2310 614244bd Iustin Pop
  @return: the file descriptor of the lock file; do not close this unless
2311 614244bd Iustin Pop
      you want to unlock the pid file
2312 b330ac0b Guido Trotter

2313 b330ac0b Guido Trotter
  """
2314 5c4d37f9 Iustin Pop
  # We don't rename nor truncate the file to not drop locks under
2315 5c4d37f9 Iustin Pop
  # existing processes
2316 5c4d37f9 Iustin Pop
  fd_pidfile = os.open(pidfile, os.O_WRONLY | os.O_CREAT, 0600)
2317 5c4d37f9 Iustin Pop
2318 5c4d37f9 Iustin Pop
  # Lock the PID file (and fail if not possible to do so). Any code
2319 5c4d37f9 Iustin Pop
  # wanting to send a signal to the daemon should try to lock the PID
2320 5c4d37f9 Iustin Pop
  # file before reading it. If acquiring the lock succeeds, the daemon is
2321 5c4d37f9 Iustin Pop
  # no longer running and the signal should not be sent.
2322 5c4d37f9 Iustin Pop
  LockFile(fd_pidfile)
2323 5c4d37f9 Iustin Pop
2324 5c4d37f9 Iustin Pop
  os.write(fd_pidfile, "%d\n" % os.getpid())
2325 b330ac0b Guido Trotter
2326 5c4d37f9 Iustin Pop
  return fd_pidfile
2327 b330ac0b Guido Trotter
2328 b330ac0b Guido Trotter
2329 b330ac0b Guido Trotter
def RemovePidFile(name):
2330 b330ac0b Guido Trotter
  """Remove the current process pidfile.
2331 b330ac0b Guido Trotter

2332 b330ac0b Guido Trotter
  Any errors are ignored.
2333 b330ac0b Guido Trotter

2334 58885d79 Iustin Pop
  @type name: str
2335 58885d79 Iustin Pop
  @param name: the daemon name used to derive the pidfile name
2336 58885d79 Iustin Pop

2337 b330ac0b Guido Trotter
  """
2338 53beffbb Iustin Pop
  pidfilename = DaemonPidFileName(name)
2339 b330ac0b Guido Trotter
  # TODO: we could check here that the file contains our pid
2340 b330ac0b Guido Trotter
  try:
2341 b330ac0b Guido Trotter
    RemoveFile(pidfilename)
2342 7260cfbe Iustin Pop
  except: # pylint: disable-msg=W0702
2343 b330ac0b Guido Trotter
    pass
2344 b330ac0b Guido Trotter
2345 b330ac0b Guido Trotter
2346 ff5251bc Iustin Pop
def KillProcess(pid, signal_=signal.SIGTERM, timeout=30,
2347 ff5251bc Iustin Pop
                waitpid=False):
2348 b2a1f511 Iustin Pop
  """Kill a process given by its pid.
2349 b2a1f511 Iustin Pop

2350 b2a1f511 Iustin Pop
  @type pid: int
2351 b2a1f511 Iustin Pop
  @param pid: The PID to terminate.
2352 38206f3c Iustin Pop
  @type signal_: int
2353 38206f3c Iustin Pop
  @param signal_: The signal to send, by default SIGTERM
2354 b2a1f511 Iustin Pop
  @type timeout: int
2355 b2a1f511 Iustin Pop
  @param timeout: The timeout after which, if the process is still alive,
2356 b2a1f511 Iustin Pop
                  a SIGKILL will be sent. If not positive, no such checking
2357 b2a1f511 Iustin Pop
                  will be done
2358 ff5251bc Iustin Pop
  @type waitpid: boolean
2359 ff5251bc Iustin Pop
  @param waitpid: If true, we should waitpid on this process after
2360 ff5251bc Iustin Pop
      sending signals, since it's our own child and otherwise it
2361 ff5251bc Iustin Pop
      would remain as zombie
2362 b2a1f511 Iustin Pop

2363 b2a1f511 Iustin Pop
  """
2364 ff5251bc Iustin Pop
  def _helper(pid, signal_, wait):
2365 ff5251bc Iustin Pop
    """Simple helper to encapsulate the kill/waitpid sequence"""
2366 560cbec1 Michael Hanselmann
    if IgnoreProcessNotFound(os.kill, pid, signal_) and wait:
2367 ff5251bc Iustin Pop
      try:
2368 ff5251bc Iustin Pop
        os.waitpid(pid, os.WNOHANG)
2369 ff5251bc Iustin Pop
      except OSError:
2370 ff5251bc Iustin Pop
        pass
2371 ff5251bc Iustin Pop
2372 b2a1f511 Iustin Pop
  if pid <= 0:
2373 b2a1f511 Iustin Pop
    # kill with pid=0 == suicide
2374 b2a1f511 Iustin Pop
    raise errors.ProgrammerError("Invalid pid given '%s'" % pid)
2375 b2a1f511 Iustin Pop
2376 b2a1f511 Iustin Pop
  if not IsProcessAlive(pid):
2377 b2a1f511 Iustin Pop
    return
2378 31892b4c Michael Hanselmann
2379 ff5251bc Iustin Pop
  _helper(pid, signal_, waitpid)
2380 31892b4c Michael Hanselmann
2381 b2a1f511 Iustin Pop
  if timeout <= 0:
2382 b2a1f511 Iustin Pop
    return
2383 7167159a Michael Hanselmann
2384 31892b4c Michael Hanselmann
  def _CheckProcess():
2385 31892b4c Michael Hanselmann
    if not IsProcessAlive(pid):
2386 31892b4c Michael Hanselmann
      return
2387 31892b4c Michael Hanselmann
2388 7167159a Michael Hanselmann
    try:
2389 7167159a Michael Hanselmann
      (result_pid, _) = os.waitpid(pid, os.WNOHANG)
2390 7167159a Michael Hanselmann
    except OSError:
2391 31892b4c Michael Hanselmann
      raise RetryAgain()
2392 31892b4c Michael Hanselmann
2393 31892b4c Michael Hanselmann
    if result_pid > 0:
2394 31892b4c Michael Hanselmann
      return
2395 31892b4c Michael Hanselmann
2396 31892b4c Michael Hanselmann
    raise RetryAgain()
2397 31892b4c Michael Hanselmann
2398 31892b4c Michael Hanselmann
  try:
2399 31892b4c Michael Hanselmann
    # Wait up to $timeout seconds
2400 31892b4c Michael Hanselmann
    Retry(_CheckProcess, (0.01, 1.5, 0.1), timeout)
2401 31892b4c Michael Hanselmann
  except RetryTimeout:
2402 31892b4c Michael Hanselmann
    pass
2403 7167159a Michael Hanselmann
2404 b2a1f511 Iustin Pop
  if IsProcessAlive(pid):
2405 7167159a Michael Hanselmann
    # Kill process if it's still alive
2406 e1bd0072 Iustin Pop
    _helper(pid, signal.SIGKILL, waitpid)
2407 b2a1f511 Iustin Pop
2408 b2a1f511 Iustin Pop
2409 57c177af Iustin Pop
def FindFile(name, search_path, test=os.path.exists):
2410 57c177af Iustin Pop
  """Look for a filesystem object in a given path.
2411 57c177af Iustin Pop

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

2415 58885d79 Iustin Pop
  @type name: str
2416 58885d79 Iustin Pop
  @param name: the name to look for
2417 58885d79 Iustin Pop
  @type search_path: str
2418 58885d79 Iustin Pop
  @param search_path: location to start at
2419 58885d79 Iustin Pop
  @type test: callable
2420 58885d79 Iustin Pop
  @param test: a function taking one argument that should return True
2421 58885d79 Iustin Pop
      if the a given object is valid; the default value is
2422 58885d79 Iustin Pop
      os.path.exists, causing only existing files to be returned
2423 58885d79 Iustin Pop
  @rtype: str or None
2424 58885d79 Iustin Pop
  @return: full path to the object if found, None otherwise
2425 57c177af Iustin Pop

2426 57c177af Iustin Pop
  """
2427 f95c81bf Iustin Pop
  # validate the filename mask
2428 f95c81bf Iustin Pop
  if constants.EXT_PLUGIN_MASK.match(name) is None:
2429 f95c81bf Iustin Pop
    logging.critical("Invalid value passed for external script name: '%s'",
2430 f95c81bf Iustin Pop
                     name)
2431 f95c81bf Iustin Pop
    return None
2432 f95c81bf Iustin Pop
2433 57c177af Iustin Pop
  for dir_name in search_path:
2434 e02b9114 Iustin Pop
    # FIXME: investigate switch to PathJoin
2435 57c177af Iustin Pop
    item_name = os.path.sep.join([dir_name, name])
2436 f95c81bf Iustin Pop
    # check the user test and that we're indeed resolving to the given
2437 f95c81bf Iustin Pop
    # basename
2438 f95c81bf Iustin Pop
    if test(item_name) and os.path.basename(item_name) == name:
2439 57c177af Iustin Pop
      return item_name
2440 57c177af Iustin Pop
  return None
2441 8d1a2a64 Michael Hanselmann
2442 8d1a2a64 Michael Hanselmann
2443 8d1a2a64 Michael Hanselmann
def CheckVolumeGroupSize(vglist, vgname, minsize):
2444 8d1a2a64 Michael Hanselmann
  """Checks if the volume group list is valid.
2445 8d1a2a64 Michael Hanselmann

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

2449 58885d79 Iustin Pop
  @type vglist: dict
2450 58885d79 Iustin Pop
  @param vglist: dictionary of volume group names and their size
2451 58885d79 Iustin Pop
  @type vgname: str
2452 58885d79 Iustin Pop
  @param vgname: the volume group we should check
2453 58885d79 Iustin Pop
  @type minsize: int
2454 58885d79 Iustin Pop
  @param minsize: the minimum size we accept
2455 58885d79 Iustin Pop
  @rtype: None or str
2456 58885d79 Iustin Pop
  @return: None for success, otherwise the error message
2457 8d1a2a64 Michael Hanselmann

2458 8d1a2a64 Michael Hanselmann
  """
2459 8d1a2a64 Michael Hanselmann
  vgsize = vglist.get(vgname, None)
2460 8d1a2a64 Michael Hanselmann
  if vgsize is None:
2461 8d1a2a64 Michael Hanselmann
    return "volume group '%s' missing" % vgname
2462 8d1a2a64 Michael Hanselmann
  elif vgsize < minsize:
2463 8d1a2a64 Michael Hanselmann
    return ("volume group '%s' too small (%s MiB required, %d MiB found)" %
2464 8d1a2a64 Michael Hanselmann
            (vgname, minsize, vgsize))
2465 8d1a2a64 Michael Hanselmann
  return None
2466 7996a135 Iustin Pop
2467 7996a135 Iustin Pop
2468 45bc5e4a Michael Hanselmann
def SplitTime(value):
2469 739be818 Michael Hanselmann
  """Splits time as floating point number into a tuple.
2470 739be818 Michael Hanselmann

2471 45bc5e4a Michael Hanselmann
  @param value: Time in seconds
2472 45bc5e4a Michael Hanselmann
  @type value: int or float
2473 45bc5e4a Michael Hanselmann
  @return: Tuple containing (seconds, microseconds)
2474 739be818 Michael Hanselmann

2475 739be818 Michael Hanselmann
  """
2476 45bc5e4a Michael Hanselmann
  (seconds, microseconds) = divmod(int(value * 1000000), 1000000)
2477 45bc5e4a Michael Hanselmann
2478 45bc5e4a Michael Hanselmann
  assert 0 <= seconds, \
2479 45bc5e4a Michael Hanselmann
    "Seconds must be larger than or equal to 0, but are %s" % seconds
2480 45bc5e4a Michael Hanselmann
  assert 0 <= microseconds <= 999999, \
2481 45bc5e4a Michael Hanselmann
    "Microseconds must be 0-999999, but are %s" % microseconds
2482 45bc5e4a Michael Hanselmann
2483 45bc5e4a Michael Hanselmann
  return (int(seconds), int(microseconds))
2484 739be818 Michael Hanselmann
2485 739be818 Michael Hanselmann
2486 739be818 Michael Hanselmann
def MergeTime(timetuple):
2487 739be818 Michael Hanselmann
  """Merges a tuple into time as a floating point number.
2488 739be818 Michael Hanselmann

2489 45bc5e4a Michael Hanselmann
  @param timetuple: Time as tuple, (seconds, microseconds)
2490 739be818 Michael Hanselmann
  @type timetuple: tuple
2491 739be818 Michael Hanselmann
  @return: Time as a floating point number expressed in seconds
2492 739be818 Michael Hanselmann

2493 739be818 Michael Hanselmann
  """
2494 45bc5e4a Michael Hanselmann
  (seconds, microseconds) = timetuple
2495 739be818 Michael Hanselmann
2496 45bc5e4a Michael Hanselmann
  assert 0 <= seconds, \
2497 45bc5e4a Michael Hanselmann
    "Seconds must be larger than or equal to 0, but are %s" % seconds
2498 45bc5e4a Michael Hanselmann
  assert 0 <= microseconds <= 999999, \
2499 45bc5e4a Michael Hanselmann
    "Microseconds must be 0-999999, but are %s" % microseconds
2500 739be818 Michael Hanselmann
2501 45bc5e4a Michael Hanselmann
  return float(seconds) + (float(microseconds) * 0.000001)
2502 739be818 Michael Hanselmann
2503 739be818 Michael Hanselmann
2504 de3b8e39 Luca Bigliardi
class LogFileHandler(logging.FileHandler):
2505 de3b8e39 Luca Bigliardi
  """Log handler that doesn't fallback to stderr.
2506 de3b8e39 Luca Bigliardi

2507 de3b8e39 Luca Bigliardi
  When an error occurs while writing on the logfile, logging.FileHandler tries
2508 de3b8e39 Luca Bigliardi
  to log on stderr. This doesn't work in ganeti since stderr is redirected to
2509 de3b8e39 Luca Bigliardi
  the logfile. This class avoids failures reporting errors to /dev/console.
2510 de3b8e39 Luca Bigliardi

2511 de3b8e39 Luca Bigliardi
  """
2512 de3b8e39 Luca Bigliardi
  def __init__(self, filename, mode="a", encoding=None):
2513 de3b8e39 Luca Bigliardi
    """Open the specified file and use it as the stream for logging.
2514 de3b8e39 Luca Bigliardi

2515 de3b8e39 Luca Bigliardi
    Also open /dev/console to report errors while logging.
2516 de3b8e39 Luca Bigliardi

2517 de3b8e39 Luca Bigliardi
    """
2518 de3b8e39 Luca Bigliardi
    logging.FileHandler.__init__(self, filename, mode, encoding)
2519 de3b8e39 Luca Bigliardi
    self.console = open(constants.DEV_CONSOLE, "a")
2520 de3b8e39 Luca Bigliardi
2521 20601361 Luca Bigliardi
  def handleError(self, record): # pylint: disable-msg=C0103
2522 de3b8e39 Luca Bigliardi
    """Handle errors which occur during an emit() call.
2523 de3b8e39 Luca Bigliardi

2524 de3b8e39 Luca Bigliardi
    Try to handle errors with FileHandler method, if it fails write to
2525 de3b8e39 Luca Bigliardi
    /dev/console.
2526 de3b8e39 Luca Bigliardi

2527 de3b8e39 Luca Bigliardi
    """
2528 de3b8e39 Luca Bigliardi
    try:
2529 05b35f15 Luca Bigliardi
      logging.FileHandler.handleError(self, record)
2530 20601361 Luca Bigliardi
    except Exception: # pylint: disable-msg=W0703
2531 de3b8e39 Luca Bigliardi
      try:
2532 de3b8e39 Luca Bigliardi
        self.console.write("Cannot log message:\n%s\n" % self.format(record))
2533 20601361 Luca Bigliardi
      except Exception: # pylint: disable-msg=W0703
2534 de3b8e39 Luca Bigliardi
        # Log handler tried everything it could, now just give up
2535 de3b8e39 Luca Bigliardi
        pass
2536 de3b8e39 Luca Bigliardi
2537 de3b8e39 Luca Bigliardi
2538 ea34193f Iustin Pop
def SetupLogging(logfile, debug=0, stderr_logging=False, program="",
2539 49e60a28 Luca Bigliardi
                 multithreaded=False, syslog=constants.SYSLOG_USAGE,
2540 49e60a28 Luca Bigliardi
                 console_logging=False):
2541 82d9caef Iustin Pop
  """Configures the logging module.
2542 82d9caef Iustin Pop

2543 58885d79 Iustin Pop
  @type logfile: str
2544 58885d79 Iustin Pop
  @param logfile: the filename to which we should log
2545 ea34193f Iustin Pop
  @type debug: integer
2546 ea34193f Iustin Pop
  @param debug: if greater than zero, enable debug messages, otherwise
2547 58885d79 Iustin Pop
      only those at C{INFO} and above level
2548 58885d79 Iustin Pop
  @type stderr_logging: boolean
2549 58885d79 Iustin Pop
  @param stderr_logging: whether we should also log to the standard error
2550 58885d79 Iustin Pop
  @type program: str
2551 58885d79 Iustin Pop
  @param program: the name under which we should log messages
2552 d21d09d6 Iustin Pop
  @type multithreaded: boolean
2553 d21d09d6 Iustin Pop
  @param multithreaded: if True, will add the thread name to the log file
2554 551b6283 Iustin Pop
  @type syslog: string
2555 551b6283 Iustin Pop
  @param syslog: one of 'no', 'yes', 'only':
2556 551b6283 Iustin Pop
      - if no, syslog is not used
2557 551b6283 Iustin Pop
      - if yes, syslog is used (in addition to file-logging)
2558 551b6283 Iustin Pop
      - if only, only syslog is used
2559 49e60a28 Luca Bigliardi
  @type console_logging: boolean
2560 49e60a28 Luca Bigliardi
  @param console_logging: if True, will use a FileHandler which falls back to
2561 49e60a28 Luca Bigliardi
      the system console if logging fails
2562 58885d79 Iustin Pop
  @raise EnvironmentError: if we can't open the log file and
2563 551b6283 Iustin Pop
      syslog/stderr logging is disabled
2564 58885d79 Iustin Pop

2565 82d9caef Iustin Pop
  """
2566 d21d09d6 Iustin Pop
  fmt = "%(asctime)s: " + program + " pid=%(process)d"
2567 551b6283 Iustin Pop
  sft = program + "[%(process)d]:"
2568 d21d09d6 Iustin Pop
  if multithreaded:
2569 d21d09d6 Iustin Pop
    fmt += "/%(threadName)s"
2570 551b6283 Iustin Pop
    sft += " (%(threadName)s)"
2571 82d9caef Iustin Pop
  if debug:
2572 d21d09d6 Iustin Pop
    fmt += " %(module)s:%(lineno)s"
2573 551b6283 Iustin Pop
    # no debug info for syslog loggers
2574 d21d09d6 Iustin Pop
  fmt += " %(levelname)s %(message)s"
2575 551b6283 Iustin Pop
  # yes, we do want the textual level, as remote syslog will probably
2576 551b6283 Iustin Pop
  # lose the error level, and it's easier to grep for it
2577 551b6283 Iustin Pop
  sft += " %(levelname)s %(message)s"
2578 82d9caef Iustin Pop
  formatter = logging.Formatter(fmt)
2579 551b6283 Iustin Pop
  sys_fmt = logging.Formatter(sft)
2580 82d9caef Iustin Pop
2581 82d9caef Iustin Pop
  root_logger = logging.getLogger("")
2582 82d9caef Iustin Pop
  root_logger.setLevel(logging.NOTSET)
2583 82d9caef Iustin Pop
2584 6346a9e5 Michael Hanselmann
  # Remove all previously setup handlers
2585 6346a9e5 Michael Hanselmann
  for handler in root_logger.handlers:
2586 7d88772a Iustin Pop
    handler.close()
2587 6346a9e5 Michael Hanselmann
    root_logger.removeHandler(handler)
2588 6346a9e5 Michael Hanselmann
2589 82d9caef Iustin Pop
  if stderr_logging:
2590 82d9caef Iustin Pop
    stderr_handler = logging.StreamHandler()
2591 82d9caef Iustin Pop
    stderr_handler.setFormatter(formatter)
2592 82d9caef Iustin Pop
    if debug:
2593 82d9caef Iustin Pop
      stderr_handler.setLevel(logging.NOTSET)
2594 82d9caef Iustin Pop
    else:
2595 82d9caef Iustin Pop
      stderr_handler.setLevel(logging.CRITICAL)
2596 82d9caef Iustin Pop
    root_logger.addHandler(stderr_handler)
2597 82d9caef Iustin Pop
2598 551b6283 Iustin Pop
  if syslog in (constants.SYSLOG_YES, constants.SYSLOG_ONLY):
2599 551b6283 Iustin Pop
    facility = logging.handlers.SysLogHandler.LOG_DAEMON
2600 551b6283 Iustin Pop
    syslog_handler = logging.handlers.SysLogHandler(constants.SYSLOG_SOCKET,
2601 551b6283 Iustin Pop
                                                    facility)
2602 551b6283 Iustin Pop
    syslog_handler.setFormatter(sys_fmt)
2603 551b6283 Iustin Pop
    # Never enable debug over syslog
2604 551b6283 Iustin Pop
    syslog_handler.setLevel(logging.INFO)
2605 551b6283 Iustin Pop
    root_logger.addHandler(syslog_handler)
2606 551b6283 Iustin Pop
2607 551b6283 Iustin Pop
  if syslog != constants.SYSLOG_ONLY:
2608 551b6283 Iustin Pop
    # this can fail, if the logging directories are not setup or we have
2609 551b6283 Iustin Pop
    # a permisssion problem; in this case, it's best to log but ignore
2610 551b6283 Iustin Pop
    # the error if stderr_logging is True, and if false we re-raise the
2611 551b6283 Iustin Pop
    # exception since otherwise we could run but without any logs at all
2612 551b6283 Iustin Pop
    try:
2613 49e60a28 Luca Bigliardi
      if console_logging:
2614 49e60a28 Luca Bigliardi
        logfile_handler = LogFileHandler(logfile)
2615 49e60a28 Luca Bigliardi
      else:
2616 49e60a28 Luca Bigliardi
        logfile_handler = logging.FileHandler(logfile)
2617 551b6283 Iustin Pop
      logfile_handler.setFormatter(formatter)
2618 551b6283 Iustin Pop
      if debug:
2619 551b6283 Iustin Pop
        logfile_handler.setLevel(logging.DEBUG)
2620 551b6283 Iustin Pop
      else:
2621 551b6283 Iustin Pop
        logfile_handler.setLevel(logging.INFO)
2622 551b6283 Iustin Pop
      root_logger.addHandler(logfile_handler)
2623 551b6283 Iustin Pop
    except EnvironmentError:
2624 551b6283 Iustin Pop
      if stderr_logging or syslog == constants.SYSLOG_YES:
2625 551b6283 Iustin Pop
        logging.exception("Failed to enable logging to file '%s'", logfile)
2626 551b6283 Iustin Pop
      else:
2627 551b6283 Iustin Pop
        # we need to re-raise the exception
2628 551b6283 Iustin Pop
        raise
2629 82d9caef Iustin Pop
2630 016d04b3 Michael Hanselmann
2631 da961187 Guido Trotter
def IsNormAbsPath(path):
2632 17c61836 Guido Trotter
  """Check whether a path is absolute and also normalized
2633 da961187 Guido Trotter

2634 da961187 Guido Trotter
  This avoids things like /dir/../../other/path to be valid.
2635 da961187 Guido Trotter

2636 da961187 Guido Trotter
  """
2637 da961187 Guido Trotter
  return os.path.normpath(path) == path and os.path.isabs(path)
2638 82d9caef Iustin Pop
2639 016d04b3 Michael Hanselmann
2640 4bb678e9 Iustin Pop
def PathJoin(*args):
2641 4bb678e9 Iustin Pop
  """Safe-join a list of path components.
2642 4bb678e9 Iustin Pop

2643 4bb678e9 Iustin Pop
  Requirements:
2644 4bb678e9 Iustin Pop
      - the first argument must be an absolute path
2645 4bb678e9 Iustin Pop
      - no component in the path must have backtracking (e.g. /../),
2646 4bb678e9 Iustin Pop
        since we check for normalization at the end
2647 4bb678e9 Iustin Pop

2648 4bb678e9 Iustin Pop
  @param args: the path components to be joined
2649 4bb678e9 Iustin Pop
  @raise ValueError: for invalid paths
2650 4bb678e9 Iustin Pop

2651 4bb678e9 Iustin Pop
  """
2652 4bb678e9 Iustin Pop
  # ensure we're having at least one path passed in
2653 4bb678e9 Iustin Pop
  assert args
2654 4bb678e9 Iustin Pop
  # ensure the first component is an absolute and normalized path name
2655 4bb678e9 Iustin Pop
  root = args[0]
2656 4bb678e9 Iustin Pop
  if not IsNormAbsPath(root):
2657 4bb678e9 Iustin Pop
    raise ValueError("Invalid parameter to PathJoin: '%s'" % str(args[0]))
2658 4bb678e9 Iustin Pop
  result = os.path.join(*args)
2659 4bb678e9 Iustin Pop
  # ensure that the whole path is normalized
2660 4bb678e9 Iustin Pop
  if not IsNormAbsPath(result):
2661 4bb678e9 Iustin Pop
    raise ValueError("Invalid parameters to PathJoin: '%s'" % str(args))
2662 4bb678e9 Iustin Pop
  # check that we're still under the original prefix
2663 4bb678e9 Iustin Pop
  prefix = os.path.commonprefix([root, result])
2664 4bb678e9 Iustin Pop
  if prefix != root:
2665 4bb678e9 Iustin Pop
    raise ValueError("Error: path joining resulted in different prefix"
2666 4bb678e9 Iustin Pop
                     " (%s != %s)" % (prefix, root))
2667 4bb678e9 Iustin Pop
  return result
2668 4bb678e9 Iustin Pop
2669 4bb678e9 Iustin Pop
2670 f65f63ef Iustin Pop
def TailFile(fname, lines=20):
2671 f65f63ef Iustin Pop
  """Return the last lines from a file.
2672 f65f63ef Iustin Pop

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

2677 f65f63ef Iustin Pop
  @param fname: the file name
2678 f65f63ef Iustin Pop
  @type lines: int
2679 f65f63ef Iustin Pop
  @param lines: the (maximum) number of lines to return
2680 f65f63ef Iustin Pop

2681 f65f63ef Iustin Pop
  """
2682 f65f63ef Iustin Pop
  fd = open(fname, "r")
2683 f65f63ef Iustin Pop
  try:
2684 f65f63ef Iustin Pop
    fd.seek(0, 2)
2685 f65f63ef Iustin Pop
    pos = fd.tell()
2686 f65f63ef Iustin Pop
    pos = max(0, pos-4096)
2687 f65f63ef Iustin Pop
    fd.seek(pos, 0)
2688 f65f63ef Iustin Pop
    raw_data = fd.read()
2689 f65f63ef Iustin Pop
  finally:
2690 f65f63ef Iustin Pop
    fd.close()
2691 f65f63ef Iustin Pop
2692 f65f63ef Iustin Pop
  rows = raw_data.splitlines()
2693 f65f63ef Iustin Pop
  return rows[-lines:]
2694 f65f63ef Iustin Pop
2695 f65f63ef Iustin Pop
2696 24d70417 Michael Hanselmann
def FormatTimestampWithTZ(secs):
2697 24d70417 Michael Hanselmann
  """Formats a Unix timestamp with the local timezone.
2698 24d70417 Michael Hanselmann

2699 24d70417 Michael Hanselmann
  """
2700 24d70417 Michael Hanselmann
  return time.strftime("%F %T %Z", time.gmtime(secs))
2701 24d70417 Michael Hanselmann
2702 24d70417 Michael Hanselmann
2703 27e46076 Michael Hanselmann
def _ParseAsn1Generalizedtime(value):
2704 27e46076 Michael Hanselmann
  """Parses an ASN1 GENERALIZEDTIME timestamp as used by pyOpenSSL.
2705 27e46076 Michael Hanselmann

2706 27e46076 Michael Hanselmann
  @type value: string
2707 27e46076 Michael Hanselmann
  @param value: ASN1 GENERALIZEDTIME timestamp
2708 27e46076 Michael Hanselmann

2709 27e46076 Michael Hanselmann
  """
2710 27e46076 Michael Hanselmann
  m = re.match(r"^(\d+)([-+]\d\d)(\d\d)$", value)
2711 27e46076 Michael Hanselmann
  if m:
2712 27e46076 Michael Hanselmann
    # We have an offset
2713 27e46076 Michael Hanselmann
    asn1time = m.group(1)
2714 27e46076 Michael Hanselmann
    hours = int(m.group(2))
2715 27e46076 Michael Hanselmann
    minutes = int(m.group(3))
2716 27e46076 Michael Hanselmann
    utcoffset = (60 * hours) + minutes
2717 27e46076 Michael Hanselmann
  else:
2718 27e46076 Michael Hanselmann
    if not value.endswith("Z"):
2719 27e46076 Michael Hanselmann
      raise ValueError("Missing timezone")
2720 27e46076 Michael Hanselmann
    asn1time = value[:-1]
2721 27e46076 Michael Hanselmann
    utcoffset = 0
2722 27e46076 Michael Hanselmann
2723 27e46076 Michael Hanselmann
  parsed = time.strptime(asn1time, "%Y%m%d%H%M%S")
2724 27e46076 Michael Hanselmann
2725 27e46076 Michael Hanselmann
  tt = datetime.datetime(*(parsed[:7])) - datetime.timedelta(minutes=utcoffset)
2726 27e46076 Michael Hanselmann
2727 27e46076 Michael Hanselmann
  return calendar.timegm(tt.utctimetuple())
2728 27e46076 Michael Hanselmann
2729 27e46076 Michael Hanselmann
2730 27e46076 Michael Hanselmann
def GetX509CertValidity(cert):
2731 27e46076 Michael Hanselmann
  """Returns the validity period of the certificate.
2732 27e46076 Michael Hanselmann

2733 27e46076 Michael Hanselmann
  @type cert: OpenSSL.crypto.X509
2734 27e46076 Michael Hanselmann
  @param cert: X509 certificate object
2735 27e46076 Michael Hanselmann

2736 27e46076 Michael Hanselmann
  """
2737 27e46076 Michael Hanselmann
  # The get_notBefore and get_notAfter functions are only supported in
2738 27e46076 Michael Hanselmann
  # pyOpenSSL 0.7 and above.
2739 27e46076 Michael Hanselmann
  try:
2740 27e46076 Michael Hanselmann
    get_notbefore_fn = cert.get_notBefore
2741 27e46076 Michael Hanselmann
  except AttributeError:
2742 27e46076 Michael Hanselmann
    not_before = None
2743 27e46076 Michael Hanselmann
  else:
2744 27e46076 Michael Hanselmann
    not_before_asn1 = get_notbefore_fn()
2745 27e46076 Michael Hanselmann
2746 27e46076 Michael Hanselmann
    if not_before_asn1 is None:
2747 27e46076 Michael Hanselmann
      not_before = None
2748 27e46076 Michael Hanselmann
    else:
2749 27e46076 Michael Hanselmann
      not_before = _ParseAsn1Generalizedtime(not_before_asn1)
2750 27e46076 Michael Hanselmann
2751 27e46076 Michael Hanselmann
  try:
2752 27e46076 Michael Hanselmann
    get_notafter_fn = cert.get_notAfter
2753 27e46076 Michael Hanselmann
  except AttributeError:
2754 27e46076 Michael Hanselmann
    not_after = None
2755 27e46076 Michael Hanselmann
  else:
2756 27e46076 Michael Hanselmann
    not_after_asn1 = get_notafter_fn()
2757 27e46076 Michael Hanselmann
2758 27e46076 Michael Hanselmann
    if not_after_asn1 is None:
2759 27e46076 Michael Hanselmann
      not_after = None
2760 27e46076 Michael Hanselmann
    else:
2761 27e46076 Michael Hanselmann
      not_after = _ParseAsn1Generalizedtime(not_after_asn1)
2762 27e46076 Michael Hanselmann
2763 27e46076 Michael Hanselmann
  return (not_before, not_after)
2764 27e46076 Michael Hanselmann
2765 27e46076 Michael Hanselmann
2766 24d70417 Michael Hanselmann
def _VerifyCertificateInner(expired, not_before, not_after, now,
2767 24d70417 Michael Hanselmann
                            warn_days, error_days):
2768 24d70417 Michael Hanselmann
  """Verifies certificate validity.
2769 24d70417 Michael Hanselmann

2770 24d70417 Michael Hanselmann
  @type expired: bool
2771 24d70417 Michael Hanselmann
  @param expired: Whether pyOpenSSL considers the certificate as expired
2772 24d70417 Michael Hanselmann
  @type not_before: number or None
2773 24d70417 Michael Hanselmann
  @param not_before: Unix timestamp before which certificate is not valid
2774 24d70417 Michael Hanselmann
  @type not_after: number or None
2775 24d70417 Michael Hanselmann
  @param not_after: Unix timestamp after which certificate is invalid
2776 24d70417 Michael Hanselmann
  @type now: number
2777 24d70417 Michael Hanselmann
  @param now: Current time as Unix timestamp
2778 24d70417 Michael Hanselmann
  @type warn_days: number or None
2779 24d70417 Michael Hanselmann
  @param warn_days: How many days before expiration a warning should be reported
2780 24d70417 Michael Hanselmann
  @type error_days: number or None
2781 24d70417 Michael Hanselmann
  @param error_days: How many days before expiration an error should be reported
2782 24d70417 Michael Hanselmann

2783 24d70417 Michael Hanselmann
  """
2784 24d70417 Michael Hanselmann
  if expired:
2785 24d70417 Michael Hanselmann
    msg = "Certificate is expired"
2786 24d70417 Michael Hanselmann
2787 24d70417 Michael Hanselmann
    if not_before is not None and not_after is not None:
2788 24d70417 Michael Hanselmann
      msg += (" (valid from %s to %s)" %
2789 24d70417 Michael Hanselmann
              (FormatTimestampWithTZ(not_before),
2790 24d70417 Michael Hanselmann
               FormatTimestampWithTZ(not_after)))
2791 24d70417 Michael Hanselmann
    elif not_before is not None:
2792 24d70417 Michael Hanselmann
      msg += " (valid from %s)" % FormatTimestampWithTZ(not_before)
2793 24d70417 Michael Hanselmann
    elif not_after is not None:
2794 24d70417 Michael Hanselmann
      msg += " (valid until %s)" % FormatTimestampWithTZ(not_after)
2795 24d70417 Michael Hanselmann
2796 24d70417 Michael Hanselmann
    return (CERT_ERROR, msg)
2797 24d70417 Michael Hanselmann
2798 24d70417 Michael Hanselmann
  elif not_before is not None and not_before > now:
2799 24d70417 Michael Hanselmann
    return (CERT_WARNING,
2800 24d70417 Michael Hanselmann
            "Certificate not yet valid (valid from %s)" %
2801 24d70417 Michael Hanselmann
            FormatTimestampWithTZ(not_before))
2802 24d70417 Michael Hanselmann
2803 24d70417 Michael Hanselmann
  elif not_after is not None:
2804 24d70417 Michael Hanselmann
    remaining_days = int((not_after - now) / (24 * 3600))
2805 24d70417 Michael Hanselmann
2806 24d70417 Michael Hanselmann
    msg = "Certificate expires in about %d days" % remaining_days
2807 24d70417 Michael Hanselmann
2808 24d70417 Michael Hanselmann
    if error_days is not None and remaining_days <= error_days:
2809 24d70417 Michael Hanselmann
      return (CERT_ERROR, msg)
2810 24d70417 Michael Hanselmann
2811 24d70417 Michael Hanselmann
    if warn_days is not None and remaining_days <= warn_days:
2812 24d70417 Michael Hanselmann
      return (CERT_WARNING, msg)
2813 24d70417 Michael Hanselmann
2814 24d70417 Michael Hanselmann
  return (None, None)
2815 24d70417 Michael Hanselmann
2816 24d70417 Michael Hanselmann
2817 24d70417 Michael Hanselmann
def VerifyX509Certificate(cert, warn_days, error_days):
2818 24d70417 Michael Hanselmann
  """Verifies a certificate for LUVerifyCluster.
2819 24d70417 Michael Hanselmann

2820 24d70417 Michael Hanselmann
  @type cert: OpenSSL.crypto.X509
2821 24d70417 Michael Hanselmann
  @param cert: X509 certificate object
2822 24d70417 Michael Hanselmann
  @type warn_days: number or None
2823 24d70417 Michael Hanselmann
  @param warn_days: How many days before expiration a warning should be reported
2824 24d70417 Michael Hanselmann
  @type error_days: number or None
2825 24d70417 Michael Hanselmann
  @param error_days: How many days before expiration an error should be reported
2826 24d70417 Michael Hanselmann

2827 24d70417 Michael Hanselmann
  """
2828 24d70417 Michael Hanselmann
  # Depending on the pyOpenSSL version, this can just return (None, None)
2829 24d70417 Michael Hanselmann
  (not_before, not_after) = GetX509CertValidity(cert)
2830 24d70417 Michael Hanselmann
2831 24d70417 Michael Hanselmann
  return _VerifyCertificateInner(cert.has_expired(), not_before, not_after,
2832 24d70417 Michael Hanselmann
                                 time.time(), warn_days, error_days)
2833 24d70417 Michael Hanselmann
2834 24d70417 Michael Hanselmann
2835 68857643 Michael Hanselmann
def SignX509Certificate(cert, key, salt):
2836 68857643 Michael Hanselmann
  """Sign a X509 certificate.
2837 68857643 Michael Hanselmann

2838 68857643 Michael Hanselmann
  An RFC822-like signature header is added in front of the certificate.
2839 68857643 Michael Hanselmann

2840 68857643 Michael Hanselmann
  @type cert: OpenSSL.crypto.X509
2841 68857643 Michael Hanselmann
  @param cert: X509 certificate object
2842 68857643 Michael Hanselmann
  @type key: string
2843 68857643 Michael Hanselmann
  @param key: Key for HMAC
2844 68857643 Michael Hanselmann
  @type salt: string
2845 68857643 Michael Hanselmann
  @param salt: Salt for HMAC
2846 68857643 Michael Hanselmann
  @rtype: string
2847 68857643 Michael Hanselmann
  @return: Serialized and signed certificate in PEM format
2848 68857643 Michael Hanselmann

2849 68857643 Michael Hanselmann
  """
2850 68857643 Michael Hanselmann
  if not VALID_X509_SIGNATURE_SALT.match(salt):
2851 68857643 Michael Hanselmann
    raise errors.GenericError("Invalid salt: %r" % salt)
2852 68857643 Michael Hanselmann
2853 68857643 Michael Hanselmann
  # Dumping as PEM here ensures the certificate is in a sane format
2854 68857643 Michael Hanselmann
  cert_pem = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
2855 68857643 Michael Hanselmann
2856 68857643 Michael Hanselmann
  return ("%s: %s/%s\n\n%s" %
2857 68857643 Michael Hanselmann
          (constants.X509_CERT_SIGNATURE_HEADER, salt,
2858 3718bf6d Michael Hanselmann
           Sha1Hmac(key, cert_pem, salt=salt),
2859 68857643 Michael Hanselmann
           cert_pem))
2860 68857643 Michael Hanselmann
2861 68857643 Michael Hanselmann
2862 68857643 Michael Hanselmann
def _ExtractX509CertificateSignature(cert_pem):
2863 68857643 Michael Hanselmann
  """Helper function to extract signature from X509 certificate.
2864 68857643 Michael Hanselmann

2865 68857643 Michael Hanselmann
  """
2866 68857643 Michael Hanselmann
  # Extract signature from original PEM data
2867 68857643 Michael Hanselmann
  for line in cert_pem.splitlines():
2868 68857643 Michael Hanselmann
    if line.startswith("---"):
2869 68857643 Michael Hanselmann
      break
2870 68857643 Michael Hanselmann
2871 68857643 Michael Hanselmann
    m = X509_SIGNATURE.match(line.strip())
2872 68857643 Michael Hanselmann
    if m:
2873 68857643 Michael Hanselmann
      return (m.group("salt"), m.group("sign"))
2874 68857643 Michael Hanselmann
2875 68857643 Michael Hanselmann
  raise errors.GenericError("X509 certificate signature is missing")
2876 68857643 Michael Hanselmann
2877 68857643 Michael Hanselmann
2878 68857643 Michael Hanselmann
def LoadSignedX509Certificate(cert_pem, key):
2879 68857643 Michael Hanselmann
  """Verifies a signed X509 certificate.
2880 68857643 Michael Hanselmann

2881 68857643 Michael Hanselmann
  @type cert_pem: string
2882 68857643 Michael Hanselmann
  @param cert_pem: Certificate in PEM format and with signature header
2883 68857643 Michael Hanselmann
  @type key: string
2884 68857643 Michael Hanselmann
  @param key: Key for HMAC
2885 68857643 Michael Hanselmann
  @rtype: tuple; (OpenSSL.crypto.X509, string)
2886 68857643 Michael Hanselmann
  @return: X509 certificate object and salt
2887 68857643 Michael Hanselmann

2888 68857643 Michael Hanselmann
  """
2889 68857643 Michael Hanselmann
  (salt, signature) = _ExtractX509CertificateSignature(cert_pem)
2890 68857643 Michael Hanselmann
2891 68857643 Michael Hanselmann
  # Load certificate
2892 68857643 Michael Hanselmann
  cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert_pem)
2893 68857643 Michael Hanselmann
2894 68857643 Michael Hanselmann
  # Dump again to ensure it's in a sane format
2895 68857643 Michael Hanselmann
  sane_pem = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
2896 68857643 Michael Hanselmann
2897 3718bf6d Michael Hanselmann
  if not VerifySha1Hmac(key, sane_pem, signature, salt=salt):
2898 68857643 Michael Hanselmann
    raise errors.GenericError("X509 certificate signature is invalid")
2899 68857643 Michael Hanselmann
2900 68857643 Michael Hanselmann
  return (cert, salt)
2901 68857643 Michael Hanselmann
2902 68857643 Michael Hanselmann
2903 3718bf6d Michael Hanselmann
def Sha1Hmac(key, text, salt=None):
2904 615aaaba Michael Hanselmann
  """Calculates the HMAC-SHA1 digest of a text.
2905 615aaaba Michael Hanselmann

2906 615aaaba Michael Hanselmann
  HMAC is defined in RFC2104.
2907 615aaaba Michael Hanselmann

2908 615aaaba Michael Hanselmann
  @type key: string
2909 615aaaba Michael Hanselmann
  @param key: Secret key
2910 615aaaba Michael Hanselmann
  @type text: string
2911 615aaaba Michael Hanselmann

2912 615aaaba Michael Hanselmann
  """
2913 3718bf6d Michael Hanselmann
  if salt:
2914 3718bf6d Michael Hanselmann
    salted_text = salt + text
2915 3718bf6d Michael Hanselmann
  else:
2916 3718bf6d Michael Hanselmann
    salted_text = text
2917 3718bf6d Michael Hanselmann
2918 716a32cb Guido Trotter
  return hmac.new(key, salted_text, compat.sha1).hexdigest()
2919 615aaaba Michael Hanselmann
2920 615aaaba Michael Hanselmann
2921 3718bf6d Michael Hanselmann
def VerifySha1Hmac(key, text, digest, salt=None):
2922 615aaaba Michael Hanselmann
  """Verifies the HMAC-SHA1 digest of a text.
2923 615aaaba Michael Hanselmann

2924 615aaaba Michael Hanselmann
  HMAC is defined in RFC2104.
2925 615aaaba Michael Hanselmann

2926 615aaaba Michael Hanselmann
  @type key: string
2927 615aaaba Michael Hanselmann
  @param key: Secret key
2928 615aaaba Michael Hanselmann
  @type text: string
2929 615aaaba Michael Hanselmann
  @type digest: string
2930 615aaaba Michael Hanselmann
  @param digest: Expected digest
2931 615aaaba Michael Hanselmann
  @rtype: bool
2932 615aaaba Michael Hanselmann
  @return: Whether HMAC-SHA1 digest matches
2933 615aaaba Michael Hanselmann

2934 615aaaba Michael Hanselmann
  """
2935 3718bf6d Michael Hanselmann
  return digest.lower() == Sha1Hmac(key, text, salt=salt).lower()
2936 615aaaba Michael Hanselmann
2937 615aaaba Michael Hanselmann
2938 26f15862 Iustin Pop
def SafeEncode(text):
2939 26f15862 Iustin Pop
  """Return a 'safe' version of a source string.
2940 26f15862 Iustin Pop

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

2950 26f15862 Iustin Pop
  @type text: str or unicode
2951 26f15862 Iustin Pop
  @param text: input data
2952 26f15862 Iustin Pop
  @rtype: str
2953 26f15862 Iustin Pop
  @return: a safe version of text
2954 26f15862 Iustin Pop

2955 26f15862 Iustin Pop
  """
2956 d392fa34 Iustin Pop
  if isinstance(text, unicode):
2957 5bbd3f7f Michael Hanselmann
    # only if unicode; if str already, we handle it below
2958 d392fa34 Iustin Pop
    text = text.encode('ascii', 'backslashreplace')
2959 d392fa34 Iustin Pop
  resu = ""
2960 d392fa34 Iustin Pop
  for char in text:
2961 d392fa34 Iustin Pop
    c = ord(char)
2962 d392fa34 Iustin Pop
    if char  == '\t':
2963 d392fa34 Iustin Pop
      resu += r'\t'
2964 d392fa34 Iustin Pop
    elif char == '\n':
2965 d392fa34 Iustin Pop
      resu += r'\n'
2966 d392fa34 Iustin Pop
    elif char == '\r':
2967 d392fa34 Iustin Pop
      resu += r'\'r'
2968 d392fa34 Iustin Pop
    elif c < 32 or c >= 127: # non-printable
2969 d392fa34 Iustin Pop
      resu += "\\x%02x" % (c & 0xff)
2970 d392fa34 Iustin Pop
    else:
2971 d392fa34 Iustin Pop
      resu += char
2972 d392fa34 Iustin Pop
  return resu
2973 26f15862 Iustin Pop
2974 26f15862 Iustin Pop
2975 5b69bc7c Iustin Pop
def UnescapeAndSplit(text, sep=","):
2976 5b69bc7c Iustin Pop
  """Split and unescape a string based on a given separator.
2977 5b69bc7c Iustin Pop

2978 5b69bc7c Iustin Pop
  This function splits a string based on a separator where the
2979 5b69bc7c Iustin Pop
  separator itself can be escape in order to be an element of the
2980 5b69bc7c Iustin Pop
  elements. The escaping rules are (assuming coma being the
2981 5b69bc7c Iustin Pop
  separator):
2982 5b69bc7c Iustin Pop
    - a plain , separates the elements
2983 5b69bc7c Iustin Pop
    - a sequence \\\\, (double backslash plus comma) is handled as a
2984 5b69bc7c Iustin Pop
      backslash plus a separator comma
2985 5b69bc7c Iustin Pop
    - a sequence \, (backslash plus comma) is handled as a
2986 5b69bc7c Iustin Pop
      non-separator comma
2987 5b69bc7c Iustin Pop

2988 5b69bc7c Iustin Pop
  @type text: string
2989 5b69bc7c Iustin Pop
  @param text: the string to split
2990 5b69bc7c Iustin Pop
  @type sep: string
2991 5b69bc7c Iustin Pop
  @param text: the separator
2992 5b69bc7c Iustin Pop
  @rtype: string
2993 5b69bc7c Iustin Pop
  @return: a list of strings
2994 5b69bc7c Iustin Pop

2995 5b69bc7c Iustin Pop
  """
2996 5b69bc7c Iustin Pop
  # we split the list by sep (with no escaping at this stage)
2997 5b69bc7c Iustin Pop
  slist = text.split(sep)
2998 5b69bc7c Iustin Pop
  # next, we revisit the elements and if any of them ended with an odd
2999 5b69bc7c Iustin Pop
  # number of backslashes, then we join it with the next
3000 5b69bc7c Iustin Pop
  rlist = []
3001 5b69bc7c Iustin Pop
  while slist:
3002 5b69bc7c Iustin Pop
    e1 = slist.pop(0)
3003 5b69bc7c Iustin Pop
    if e1.endswith("\\"):
3004 5b69bc7c Iustin Pop
      num_b = len(e1) - len(e1.rstrip("\\"))
3005 5b69bc7c Iustin Pop
      if num_b % 2 == 1:
3006 5b69bc7c Iustin Pop
        e2 = slist.pop(0)
3007 5b69bc7c Iustin Pop
        # here the backslashes remain (all), and will be reduced in
3008 5b69bc7c Iustin Pop
        # the next step
3009 5b69bc7c Iustin Pop
        rlist.append(e1 + sep + e2)
3010 5b69bc7c Iustin Pop
        continue
3011 5b69bc7c Iustin Pop
    rlist.append(e1)
3012 5b69bc7c Iustin Pop
  # finally, replace backslash-something with something
3013 5b69bc7c Iustin Pop
  rlist = [re.sub(r"\\(.)", r"\1", v) for v in rlist]
3014 5b69bc7c Iustin Pop
  return rlist
3015 5b69bc7c Iustin Pop
3016 5b69bc7c Iustin Pop
3017 ab3e6da8 Iustin Pop
def CommaJoin(names):
3018 ab3e6da8 Iustin Pop
  """Nicely join a set of identifiers.
3019 ab3e6da8 Iustin Pop

3020 ab3e6da8 Iustin Pop
  @param names: set, list or tuple
3021 ab3e6da8 Iustin Pop
  @return: a string with the formatted results
3022 ab3e6da8 Iustin Pop

3023 ab3e6da8 Iustin Pop
  """
3024 1f864b60 Iustin Pop
  return ", ".join([str(val) for val in names])
3025 ab3e6da8 Iustin Pop
3026 ab3e6da8 Iustin Pop
3027 691c81b7 Michael Hanselmann
def FindMatch(data, name):
3028 691c81b7 Michael Hanselmann
  """Tries to find an item in a dictionary matching a name.
3029 691c81b7 Michael Hanselmann

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

3034 691c81b7 Michael Hanselmann
  @type data: dict
3035 691c81b7 Michael Hanselmann
  @param data: Dictionary containing data
3036 691c81b7 Michael Hanselmann
  @type name: string
3037 691c81b7 Michael Hanselmann
  @param name: Name to look for
3038 691c81b7 Michael Hanselmann
  @rtype: tuple; (value in dictionary, matched groups as list)
3039 691c81b7 Michael Hanselmann

3040 691c81b7 Michael Hanselmann
  """
3041 691c81b7 Michael Hanselmann
  if name in data:
3042 691c81b7 Michael Hanselmann
    return (data[name], [])
3043 691c81b7 Michael Hanselmann
3044 691c81b7 Michael Hanselmann
  for key, value in data.items():
3045 691c81b7 Michael Hanselmann
    # Regex objects
3046 691c81b7 Michael Hanselmann
    if hasattr(key, "match"):
3047 691c81b7 Michael Hanselmann
      m = key.match(name)
3048 691c81b7 Michael Hanselmann
      if m:
3049 691c81b7 Michael Hanselmann
        return (value, list(m.groups()))
3050 691c81b7 Michael Hanselmann
3051 691c81b7 Michael Hanselmann
  return None
3052 691c81b7 Michael Hanselmann
3053 691c81b7 Michael Hanselmann
3054 3f6a47a8 Michael Hanselmann
def BytesToMebibyte(value):
3055 3f6a47a8 Michael Hanselmann
  """Converts bytes to mebibytes.
3056 3f6a47a8 Michael Hanselmann

3057 3f6a47a8 Michael Hanselmann
  @type value: int
3058 3f6a47a8 Michael Hanselmann
  @param value: Value in bytes
3059 3f6a47a8 Michael Hanselmann
  @rtype: int
3060 3f6a47a8 Michael Hanselmann
  @return: Value in mebibytes
3061 3f6a47a8 Michael Hanselmann

3062 3f6a47a8 Michael Hanselmann
  """
3063 3f6a47a8 Michael Hanselmann
  return int(round(value / (1024.0 * 1024.0), 0))
3064 3f6a47a8 Michael Hanselmann
3065 3f6a47a8 Michael Hanselmann
3066 3f6a47a8 Michael Hanselmann
def CalculateDirectorySize(path):
3067 3f6a47a8 Michael Hanselmann
  """Calculates the size of a directory recursively.
3068 3f6a47a8 Michael Hanselmann

3069 3f6a47a8 Michael Hanselmann
  @type path: string
3070 3f6a47a8 Michael Hanselmann
  @param path: Path to directory
3071 3f6a47a8 Michael Hanselmann
  @rtype: int
3072 3f6a47a8 Michael Hanselmann
  @return: Size in mebibytes
3073 3f6a47a8 Michael Hanselmann

3074 3f6a47a8 Michael Hanselmann
  """
3075 3f6a47a8 Michael Hanselmann
  size = 0
3076 3f6a47a8 Michael Hanselmann
3077 3f6a47a8 Michael Hanselmann
  for (curpath, _, files) in os.walk(path):
3078 2a887df9 Michael Hanselmann
    for filename in files:
3079 c4feafe8 Iustin Pop
      st = os.lstat(PathJoin(curpath, filename))
3080 3f6a47a8 Michael Hanselmann
      size += st.st_size
3081 3f6a47a8 Michael Hanselmann
3082 3f6a47a8 Michael Hanselmann
  return BytesToMebibyte(size)
3083 3f6a47a8 Michael Hanselmann
3084 3f6a47a8 Michael Hanselmann
3085 1b045f5d Balazs Lecz
def GetMounts(filename=constants.PROC_MOUNTS):
3086 1b045f5d Balazs Lecz
  """Returns the list of mounted filesystems.
3087 1b045f5d Balazs Lecz

3088 1b045f5d Balazs Lecz
  This function is Linux-specific.
3089 1b045f5d Balazs Lecz

3090 1b045f5d Balazs Lecz
  @param filename: path of mounts file (/proc/mounts by default)
3091 1b045f5d Balazs Lecz
  @rtype: list of tuples
3092 1b045f5d Balazs Lecz
  @return: list of mount entries (device, mountpoint, fstype, options)
3093 1b045f5d Balazs Lecz

3094 1b045f5d Balazs Lecz
  """
3095 1b045f5d Balazs Lecz
  # TODO(iustin): investigate non-Linux options (e.g. via mount output)
3096 1b045f5d Balazs Lecz
  data = []
3097 1b045f5d Balazs Lecz
  mountlines = ReadFile(filename).splitlines()
3098 1b045f5d Balazs Lecz
  for line in mountlines:
3099 1b045f5d Balazs Lecz
    device, mountpoint, fstype, options, _ = line.split(None, 4)
3100 1b045f5d Balazs Lecz
    data.append((device, mountpoint, fstype, options))
3101 1b045f5d Balazs Lecz
3102 1b045f5d Balazs Lecz
  return data
3103 1b045f5d Balazs Lecz
3104 1b045f5d Balazs Lecz
3105 620a85fd Iustin Pop
def GetFilesystemStats(path):
3106 620a85fd Iustin Pop
  """Returns the total and free space on a filesystem.
3107 3f6a47a8 Michael Hanselmann

3108 3f6a47a8 Michael Hanselmann
  @type path: string
3109 3f6a47a8 Michael Hanselmann
  @param path: Path on filesystem to be examined
3110 3f6a47a8 Michael Hanselmann
  @rtype: int
3111 620a85fd Iustin Pop
  @return: tuple of (Total space, Free space) in mebibytes
3112 3f6a47a8 Michael Hanselmann

3113 3f6a47a8 Michael Hanselmann
  """
3114 3f6a47a8 Michael Hanselmann
  st = os.statvfs(path)
3115 3f6a47a8 Michael Hanselmann
3116 620a85fd Iustin Pop
  fsize = BytesToMebibyte(st.f_bavail * st.f_frsize)
3117 620a85fd Iustin Pop
  tsize = BytesToMebibyte(st.f_blocks * st.f_frsize)
3118 620a85fd Iustin Pop
  return (tsize, fsize)
3119 3f6a47a8 Michael Hanselmann
3120 3f6a47a8 Michael Hanselmann
3121 bdefe5dd Michael Hanselmann
def RunInSeparateProcess(fn, *args):
3122 eb58f7bd Michael Hanselmann
  """Runs a function in a separate process.
3123 eb58f7bd Michael Hanselmann

3124 eb58f7bd Michael Hanselmann
  Note: Only boolean return values are supported.
3125 eb58f7bd Michael Hanselmann

3126 eb58f7bd Michael Hanselmann
  @type fn: callable
3127 eb58f7bd Michael Hanselmann
  @param fn: Function to be called
3128 bdefe5dd Michael Hanselmann
  @rtype: bool
3129 bdefe5dd Michael Hanselmann
  @return: Function's result
3130 eb58f7bd Michael Hanselmann

3131 eb58f7bd Michael Hanselmann
  """
3132 eb58f7bd Michael Hanselmann
  pid = os.fork()
3133 eb58f7bd Michael Hanselmann
  if pid == 0:
3134 eb58f7bd Michael Hanselmann
    # Child process
3135 eb58f7bd Michael Hanselmann
    try:
3136 82869978 Michael Hanselmann
      # In case the function uses temporary files
3137 82869978 Michael Hanselmann
      ResetTempfileModule()
3138 82869978 Michael Hanselmann
3139 eb58f7bd Michael Hanselmann
      # Call function
3140 bdefe5dd Michael Hanselmann
      result = int(bool(fn(*args)))
3141 eb58f7bd Michael Hanselmann
      assert result in (0, 1)
3142 eb58f7bd Michael Hanselmann
    except: # pylint: disable-msg=W0702
3143 eb58f7bd Michael Hanselmann
      logging.exception("Error while calling function in separate process")
3144 eb58f7bd Michael Hanselmann
      # 0 and 1 are reserved for the return value
3145 eb58f7bd Michael Hanselmann
      result = 33
3146 eb58f7bd Michael Hanselmann
3147 eb58f7bd Michael Hanselmann
    os._exit(result) # pylint: disable-msg=W0212
3148 eb58f7bd Michael Hanselmann
3149 eb58f7bd Michael Hanselmann
  # Parent process
3150 eb58f7bd Michael Hanselmann
3151 eb58f7bd Michael Hanselmann
  # Avoid zombies and check exit code
3152 eb58f7bd Michael Hanselmann
  (_, status) = os.waitpid(pid, 0)
3153 eb58f7bd Michael Hanselmann
3154 eb58f7bd Michael Hanselmann
  if os.WIFSIGNALED(status):
3155 eb58f7bd Michael Hanselmann
    exitcode = None
3156 eb58f7bd Michael Hanselmann
    signum = os.WTERMSIG(status)
3157 eb58f7bd Michael Hanselmann
  else:
3158 eb58f7bd Michael Hanselmann
    exitcode = os.WEXITSTATUS(status)
3159 eb58f7bd Michael Hanselmann
    signum = None
3160 eb58f7bd Michael Hanselmann
3161 eb58f7bd Michael Hanselmann
  if not (exitcode in (0, 1) and signum is None):
3162 eb58f7bd Michael Hanselmann
    raise errors.GenericError("Child program failed (code=%s, signal=%s)" %
3163 eb58f7bd Michael Hanselmann
                              (exitcode, signum))
3164 eb58f7bd Michael Hanselmann
3165 eb58f7bd Michael Hanselmann
  return bool(exitcode)
3166 eb58f7bd Michael Hanselmann
3167 eb58f7bd Michael Hanselmann
3168 560cbec1 Michael Hanselmann
def IgnoreProcessNotFound(fn, *args, **kwargs):
3169 560cbec1 Michael Hanselmann
  """Ignores ESRCH when calling a process-related function.
3170 560cbec1 Michael Hanselmann

3171 560cbec1 Michael Hanselmann
  ESRCH is raised when a process is not found.
3172 560cbec1 Michael Hanselmann

3173 560cbec1 Michael Hanselmann
  @rtype: bool
3174 560cbec1 Michael Hanselmann
  @return: Whether process was found
3175 560cbec1 Michael Hanselmann

3176 560cbec1 Michael Hanselmann
  """
3177 560cbec1 Michael Hanselmann
  try:
3178 560cbec1 Michael Hanselmann
    fn(*args, **kwargs)
3179 560cbec1 Michael Hanselmann
  except EnvironmentError, err:
3180 560cbec1 Michael Hanselmann
    # Ignore ESRCH
3181 560cbec1 Michael Hanselmann
    if err.errno == errno.ESRCH:
3182 560cbec1 Michael Hanselmann
      return False
3183 560cbec1 Michael Hanselmann
    raise
3184 560cbec1 Michael Hanselmann
3185 560cbec1 Michael Hanselmann
  return True
3186 560cbec1 Michael Hanselmann
3187 560cbec1 Michael Hanselmann
3188 232144d0 Guido Trotter
def IgnoreSignals(fn, *args, **kwargs):
3189 232144d0 Guido Trotter
  """Tries to call a function ignoring failures due to EINTR.
3190 232144d0 Guido Trotter

3191 232144d0 Guido Trotter
  """
3192 232144d0 Guido Trotter
  try:
3193 232144d0 Guido Trotter
    return fn(*args, **kwargs)
3194 965d0e5b Guido Trotter
  except EnvironmentError, err:
3195 2fd7f564 Guido Trotter
    if err.errno == errno.EINTR:
3196 2fd7f564 Guido Trotter
      return None
3197 2fd7f564 Guido Trotter
    else:
3198 232144d0 Guido Trotter
      raise
3199 965d0e5b Guido Trotter
  except (select.error, socket.error), err:
3200 965d0e5b Guido Trotter
    # In python 2.6 and above select.error is an IOError, so it's handled
3201 965d0e5b Guido Trotter
    # above, in 2.5 and below it's not, and it's handled here.
3202 2fd7f564 Guido Trotter
    if err.args and err.args[0] == errno.EINTR:
3203 2fd7f564 Guido Trotter
      return None
3204 2fd7f564 Guido Trotter
    else:
3205 232144d0 Guido Trotter
      raise
3206 232144d0 Guido Trotter
3207 232144d0 Guido Trotter
3208 eb0f0ce0 Michael Hanselmann
def LockFile(fd):
3209 eb0f0ce0 Michael Hanselmann
  """Locks a file using POSIX locks.
3210 eb0f0ce0 Michael Hanselmann

3211 58885d79 Iustin Pop
  @type fd: int
3212 58885d79 Iustin Pop
  @param fd: the file descriptor we need to lock
3213 58885d79 Iustin Pop

3214 eb0f0ce0 Michael Hanselmann
  """
3215 eb0f0ce0 Michael Hanselmann
  try:
3216 eb0f0ce0 Michael Hanselmann
    fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
3217 eb0f0ce0 Michael Hanselmann
  except IOError, err:
3218 eb0f0ce0 Michael Hanselmann
    if err.errno == errno.EAGAIN:
3219 eb0f0ce0 Michael Hanselmann
      raise errors.LockError("File already locked")
3220 eb0f0ce0 Michael Hanselmann
    raise
3221 de499029 Michael Hanselmann
3222 de499029 Michael Hanselmann
3223 3b813dd2 Iustin Pop
def FormatTime(val):
3224 3b813dd2 Iustin Pop
  """Formats a time value.
3225 3b813dd2 Iustin Pop

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

3230 3b813dd2 Iustin Pop
  """
3231 3b813dd2 Iustin Pop
  if val is None or not isinstance(val, (int, float)):
3232 3b813dd2 Iustin Pop
    return "N/A"
3233 3b813dd2 Iustin Pop
  # these two codes works on Linux, but they are not guaranteed on all
3234 3b813dd2 Iustin Pop
  # platforms
3235 3b813dd2 Iustin Pop
  return time.strftime("%F %T", time.localtime(val))
3236 3b813dd2 Iustin Pop
3237 3b813dd2 Iustin Pop
3238 f8ea4ada Michael Hanselmann
def FormatSeconds(secs):
3239 f8ea4ada Michael Hanselmann
  """Formats seconds for easier reading.
3240 f8ea4ada Michael Hanselmann

3241 f8ea4ada Michael Hanselmann
  @type secs: number
3242 f8ea4ada Michael Hanselmann
  @param secs: Number of seconds
3243 f8ea4ada Michael Hanselmann
  @rtype: string
3244 f8ea4ada Michael Hanselmann
  @return: Formatted seconds (e.g. "2d 9h 19m 49s")
3245 f8ea4ada Michael Hanselmann

3246 f8ea4ada Michael Hanselmann
  """
3247 f8ea4ada Michael Hanselmann
  parts = []
3248 f8ea4ada Michael Hanselmann
3249 f8ea4ada Michael Hanselmann
  secs = round(secs, 0)
3250 f8ea4ada Michael Hanselmann
3251 f8ea4ada Michael Hanselmann
  if secs > 0:
3252 f8ea4ada Michael Hanselmann
    # Negative values would be a bit tricky
3253 f8ea4ada Michael Hanselmann
    for unit, one in [("d", 24 * 60 * 60), ("h", 60 * 60), ("m", 60)]:
3254 f8ea4ada Michael Hanselmann
      (complete, secs) = divmod(secs, one)
3255 f8ea4ada Michael Hanselmann
      if complete or parts:
3256 f8ea4ada Michael Hanselmann
        parts.append("%d%s" % (complete, unit))
3257 f8ea4ada Michael Hanselmann
3258 f8ea4ada Michael Hanselmann
  parts.append("%ds" % secs)
3259 f8ea4ada Michael Hanselmann
3260 f8ea4ada Michael Hanselmann
  return " ".join(parts)
3261 f8ea4ada Michael Hanselmann
3262 f8ea4ada Michael Hanselmann
3263 5cbe43a5 Michael Hanselmann
def ReadWatcherPauseFile(filename, now=None, remove_after=3600):
3264 05e50653 Michael Hanselmann
  """Reads the watcher pause file.
3265 05e50653 Michael Hanselmann

3266 5cbe43a5 Michael Hanselmann
  @type filename: string
3267 5cbe43a5 Michael Hanselmann
  @param filename: Path to watcher pause file
3268 5cbe43a5 Michael Hanselmann
  @type now: None, float or int
3269 5cbe43a5 Michael Hanselmann
  @param now: Current time as Unix timestamp
3270 5cbe43a5 Michael Hanselmann
  @type remove_after: int
3271 5cbe43a5 Michael Hanselmann
  @param remove_after: Remove watcher pause file after specified amount of
3272 5cbe43a5 Michael Hanselmann
    seconds past the pause end time
3273 5cbe43a5 Michael Hanselmann

3274 05e50653 Michael Hanselmann
  """
3275 05e50653 Michael Hanselmann
  if now is None:
3276 05e50653 Michael Hanselmann
    now = time.time()
3277 05e50653 Michael Hanselmann
3278 05e50653 Michael Hanselmann
  try:
3279 05e50653 Michael Hanselmann
    value = ReadFile(filename)
3280 05e50653 Michael Hanselmann
  except IOError, err:
3281 05e50653 Michael Hanselmann
    if err.errno != errno.ENOENT:
3282 05e50653 Michael Hanselmann
      raise
3283 05e50653 Michael Hanselmann
    value = None
3284 05e50653 Michael Hanselmann
3285 05e50653 Michael Hanselmann
  if value is not None:
3286 05e50653 Michael Hanselmann
    try:
3287 05e50653 Michael Hanselmann
      value = int(value)
3288 05e50653 Michael Hanselmann
    except ValueError:
3289 5cbe43a5 Michael Hanselmann
      logging.warning(("Watcher pause file (%s) contains invalid value,"
3290 5cbe43a5 Michael Hanselmann
                       " removing it"), filename)
3291 5cbe43a5 Michael Hanselmann
      RemoveFile(filename)
3292 05e50653 Michael Hanselmann
      value = None
3293 05e50653 Michael Hanselmann
3294 05e50653 Michael Hanselmann
    if value is not None:
3295 5cbe43a5 Michael Hanselmann
      # Remove file if it's outdated
3296 5cbe43a5 Michael Hanselmann
      if now > (value + remove_after):
3297 5cbe43a5 Michael Hanselmann
        RemoveFile(filename)
3298 5cbe43a5 Michael Hanselmann
        value = None
3299 5cbe43a5 Michael Hanselmann
3300 5cbe43a5 Michael Hanselmann
      elif now > value:
3301 05e50653 Michael Hanselmann
        value = None
3302 05e50653 Michael Hanselmann
3303 05e50653 Michael Hanselmann
  return value
3304 05e50653 Michael Hanselmann
3305 05e50653 Michael Hanselmann
3306 de0ea66b Michael Hanselmann
class RetryTimeout(Exception):
3307 de0ea66b Michael Hanselmann
  """Retry loop timed out.
3308 de0ea66b Michael Hanselmann

3309 40bc67e1 Guido Trotter
  Any arguments which was passed by the retried function to RetryAgain will be
3310 40bc67e1 Guido Trotter
  preserved in RetryTimeout, if it is raised. If such argument was an exception
3311 40bc67e1 Guido Trotter
  the RaiseInner helper method will reraise it.
3312 40bc67e1 Guido Trotter

3313 de0ea66b Michael Hanselmann
  """
3314 506be7c5 Guido Trotter
  def RaiseInner(self):
3315 506be7c5 Guido Trotter
    if self.args and isinstance(self.args[0], Exception):
3316 506be7c5 Guido Trotter
      raise self.args[0]
3317 506be7c5 Guido Trotter
    else:
3318 506be7c5 Guido Trotter
      raise RetryTimeout(*self.args)
3319 de0ea66b Michael Hanselmann
3320 de0ea66b Michael Hanselmann
3321 de0ea66b Michael Hanselmann
class RetryAgain(Exception):
3322 de0ea66b Michael Hanselmann
  """Retry again.
3323 de0ea66b Michael Hanselmann

3324 40bc67e1 Guido Trotter
  Any arguments passed to RetryAgain will be preserved, if a timeout occurs, as
3325 40bc67e1 Guido Trotter
  arguments to RetryTimeout. If an exception is passed, the RaiseInner() method
3326 40bc67e1 Guido Trotter
  of the RetryTimeout() method can be used to reraise it.
3327 40bc67e1 Guido Trotter

3328 de0ea66b Michael Hanselmann
  """
3329 de0ea66b Michael Hanselmann
3330 de0ea66b Michael Hanselmann
3331 de0ea66b Michael Hanselmann
class _RetryDelayCalculator(object):
3332 de0ea66b Michael Hanselmann
  """Calculator for increasing delays.
3333 de0ea66b Michael Hanselmann

3334 de0ea66b Michael Hanselmann
  """
3335 de0ea66b Michael Hanselmann
  __slots__ = [
3336 de0ea66b Michael Hanselmann
    "_factor",
3337 de0ea66b Michael Hanselmann
    "_limit",
3338 de0ea66b Michael Hanselmann
    "_next",
3339 de0ea66b Michael Hanselmann
    "_start",
3340 de0ea66b Michael Hanselmann
    ]
3341 de0ea66b Michael Hanselmann
3342 de0ea66b Michael Hanselmann
  def __init__(self, start, factor, limit):
3343 de0ea66b Michael Hanselmann
    """Initializes this class.
3344 de0ea66b Michael Hanselmann

3345 de0ea66b Michael Hanselmann
    @type start: float
3346 de0ea66b Michael Hanselmann
    @param start: Initial delay
3347 de0ea66b Michael Hanselmann
    @type factor: float
3348 de0ea66b Michael Hanselmann
    @param factor: Factor for delay increase
3349 de0ea66b Michael Hanselmann
    @type limit: float or None
3350 de0ea66b Michael Hanselmann
    @param limit: Upper limit for delay or None for no limit
3351 de0ea66b Michael Hanselmann

3352 de0ea66b Michael Hanselmann
    """
3353 de0ea66b Michael Hanselmann
    assert start > 0.0
3354 de0ea66b Michael Hanselmann
    assert factor >= 1.0
3355 de0ea66b Michael Hanselmann
    assert limit is None or limit >= 0.0
3356 de0ea66b Michael Hanselmann
3357 de0ea66b Michael Hanselmann
    self._start = start
3358 de0ea66b Michael Hanselmann
    self._factor = factor
3359 de0ea66b Michael Hanselmann
    self._limit = limit
3360 de0ea66b Michael Hanselmann
3361 de0ea66b Michael Hanselmann
    self._next = start
3362 de0ea66b Michael Hanselmann
3363 de0ea66b Michael Hanselmann
  def __call__(self):
3364 de0ea66b Michael Hanselmann
    """Returns current delay and calculates the next one.
3365 de0ea66b Michael Hanselmann

3366 de0ea66b Michael Hanselmann
    """
3367 de0ea66b Michael Hanselmann
    current = self._next
3368 de0ea66b Michael Hanselmann
3369 de0ea66b Michael Hanselmann
    # Update for next run
3370 de0ea66b Michael Hanselmann
    if self._limit is None or self._next < self._limit:
3371 26751075 Michael Hanselmann
      self._next = min(self._limit, self._next * self._factor)
3372 de0ea66b Michael Hanselmann
3373 de0ea66b Michael Hanselmann
    return current
3374 de0ea66b Michael Hanselmann
3375 de0ea66b Michael Hanselmann
3376 de0ea66b Michael Hanselmann
#: Special delay to specify whole remaining timeout
3377 de0ea66b Michael Hanselmann
RETRY_REMAINING_TIME = object()
3378 de0ea66b Michael Hanselmann
3379 de0ea66b Michael Hanselmann
3380 de0ea66b Michael Hanselmann
def Retry(fn, delay, timeout, args=None, wait_fn=time.sleep,
3381 de0ea66b Michael Hanselmann
          _time_fn=time.time):
3382 de0ea66b Michael Hanselmann
  """Call a function repeatedly until it succeeds.
3383 de0ea66b Michael Hanselmann

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

3388 de0ea66b Michael Hanselmann
  C{delay} can be one of the following:
3389 de0ea66b Michael Hanselmann
    - callable returning the delay length as a float
3390 de0ea66b Michael Hanselmann
    - Tuple of (start, factor, limit)
3391 de0ea66b Michael Hanselmann
    - L{RETRY_REMAINING_TIME} to sleep until the timeout expires (this is
3392 de0ea66b Michael Hanselmann
      useful when overriding L{wait_fn} to wait for an external event)
3393 de0ea66b Michael Hanselmann
    - A static delay as a number (int or float)
3394 de0ea66b Michael Hanselmann

3395 de0ea66b Michael Hanselmann
  @type fn: callable
3396 de0ea66b Michael Hanselmann
  @param fn: Function to be called
3397 de0ea66b Michael Hanselmann
  @param delay: Either a callable (returning the delay), a tuple of (start,
3398 de0ea66b Michael Hanselmann
                factor, limit) (see L{_RetryDelayCalculator}),
3399 de0ea66b Michael Hanselmann
                L{RETRY_REMAINING_TIME} or a number (int or float)
3400 de0ea66b Michael Hanselmann
  @type timeout: float
3401 de0ea66b Michael Hanselmann
  @param timeout: Total timeout
3402 de0ea66b Michael Hanselmann
  @type wait_fn: callable
3403 de0ea66b Michael Hanselmann
  @param wait_fn: Waiting function
3404 de0ea66b Michael Hanselmann
  @return: Return value of function
3405 de0ea66b Michael Hanselmann

3406 de0ea66b Michael Hanselmann
  """
3407 de0ea66b Michael Hanselmann
  assert callable(fn)
3408 de0ea66b Michael Hanselmann
  assert callable(wait_fn)
3409 de0ea66b Michael Hanselmann
  assert callable(_time_fn)
3410 de0ea66b Michael Hanselmann
3411 de0ea66b Michael Hanselmann
  if args is None:
3412 de0ea66b Michael Hanselmann
    args = []
3413 de0ea66b Michael Hanselmann
3414 de0ea66b Michael Hanselmann
  end_time = _time_fn() + timeout
3415 de0ea66b Michael Hanselmann
3416 de0ea66b Michael Hanselmann
  if callable(delay):
3417 de0ea66b Michael Hanselmann
    # External function to calculate delay
3418 de0ea66b Michael Hanselmann
    calc_delay = delay
3419 de0ea66b Michael Hanselmann
3420 de0ea66b Michael Hanselmann
  elif isinstance(delay, (tuple, list)):
3421 de0ea66b Michael Hanselmann
    # Increasing delay with optional upper boundary
3422 de0ea66b Michael Hanselmann
    (start, factor, limit) = delay
3423 de0ea66b Michael Hanselmann
    calc_delay = _RetryDelayCalculator(start, factor, limit)
3424 de0ea66b Michael Hanselmann
3425 de0ea66b Michael Hanselmann
  elif delay is RETRY_REMAINING_TIME:
3426 de0ea66b Michael Hanselmann
    # Always use the remaining time
3427 de0ea66b Michael Hanselmann
    calc_delay = None
3428 de0ea66b Michael Hanselmann
3429 de0ea66b Michael Hanselmann
  else:
3430 de0ea66b Michael Hanselmann
    # Static delay
3431 de0ea66b Michael Hanselmann
    calc_delay = lambda: delay
3432 de0ea66b Michael Hanselmann
3433 de0ea66b Michael Hanselmann
  assert calc_delay is None or callable(calc_delay)
3434 de0ea66b Michael Hanselmann
3435 de0ea66b Michael Hanselmann
  while True:
3436 506be7c5 Guido Trotter
    retry_args = []
3437 de0ea66b Michael Hanselmann
    try:
3438 7260cfbe Iustin Pop
      # pylint: disable-msg=W0142
3439 de0ea66b Michael Hanselmann
      return fn(*args)
3440 506be7c5 Guido Trotter
    except RetryAgain, err:
3441 506be7c5 Guido Trotter
      retry_args = err.args
3442 1b429e2a Iustin Pop
    except RetryTimeout:
3443 1b429e2a Iustin Pop
      raise errors.ProgrammerError("Nested retry loop detected that didn't"
3444 1b429e2a Iustin Pop
                                   " handle RetryTimeout")
3445 de0ea66b Michael Hanselmann
3446 de0ea66b Michael Hanselmann
    remaining_time = end_time - _time_fn()
3447 de0ea66b Michael Hanselmann
3448 de0ea66b Michael Hanselmann
    if remaining_time < 0.0:
3449 506be7c5 Guido Trotter
      # pylint: disable-msg=W0142
3450 506be7c5 Guido Trotter
      raise RetryTimeout(*retry_args)
3451 de0ea66b Michael Hanselmann
3452 de0ea66b Michael Hanselmann
    assert remaining_time >= 0.0
3453 de0ea66b Michael Hanselmann
3454 de0ea66b Michael Hanselmann
    if calc_delay is None:
3455 de0ea66b Michael Hanselmann
      wait_fn(remaining_time)
3456 de0ea66b Michael Hanselmann
    else:
3457 de0ea66b Michael Hanselmann
      current_delay = calc_delay()
3458 de0ea66b Michael Hanselmann
      if current_delay > 0.0:
3459 de0ea66b Michael Hanselmann
        wait_fn(current_delay)
3460 de0ea66b Michael Hanselmann
3461 de0ea66b Michael Hanselmann
3462 bdd5e420 Michael Hanselmann
def GetClosedTempfile(*args, **kwargs):
3463 bdd5e420 Michael Hanselmann
  """Creates a temporary file and returns its path.
3464 a55474c7 Michael Hanselmann

3465 bdd5e420 Michael Hanselmann
  """
3466 bdd5e420 Michael Hanselmann
  (fd, path) = tempfile.mkstemp(*args, **kwargs)
3467 bdd5e420 Michael Hanselmann
  _CloseFDNoErr(fd)
3468 bdd5e420 Michael Hanselmann
  return path
3469 bdd5e420 Michael Hanselmann
3470 bdd5e420 Michael Hanselmann
3471 bdd5e420 Michael Hanselmann
def GenerateSelfSignedX509Cert(common_name, validity):
3472 bdd5e420 Michael Hanselmann
  """Generates a self-signed X509 certificate.
3473 bdd5e420 Michael Hanselmann

3474 bdd5e420 Michael Hanselmann
  @type common_name: string
3475 bdd5e420 Michael Hanselmann
  @param common_name: commonName value
3476 a55474c7 Michael Hanselmann
  @type validity: int
3477 bdd5e420 Michael Hanselmann
  @param validity: Validity for certificate in seconds
3478 a55474c7 Michael Hanselmann

3479 a55474c7 Michael Hanselmann
  """
3480 bdd5e420 Michael Hanselmann
  # Create private and public key
3481 bdd5e420 Michael Hanselmann
  key = OpenSSL.crypto.PKey()
3482 bdd5e420 Michael Hanselmann
  key.generate_key(OpenSSL.crypto.TYPE_RSA, constants.RSA_KEY_BITS)
3483 bdd5e420 Michael Hanselmann
3484 bdd5e420 Michael Hanselmann
  # Create self-signed certificate
3485 bdd5e420 Michael Hanselmann
  cert = OpenSSL.crypto.X509()
3486 bdd5e420 Michael Hanselmann
  if common_name:
3487 bdd5e420 Michael Hanselmann
    cert.get_subject().CN = common_name
3488 bdd5e420 Michael Hanselmann
  cert.set_serial_number(1)
3489 bdd5e420 Michael Hanselmann
  cert.gmtime_adj_notBefore(0)
3490 bdd5e420 Michael Hanselmann
  cert.gmtime_adj_notAfter(validity)
3491 bdd5e420 Michael Hanselmann
  cert.set_issuer(cert.get_subject())
3492 bdd5e420 Michael Hanselmann
  cert.set_pubkey(key)
3493 bdd5e420 Michael Hanselmann
  cert.sign(key, constants.X509_CERT_SIGN_DIGEST)
3494 bdd5e420 Michael Hanselmann
3495 bdd5e420 Michael Hanselmann
  key_pem = OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key)
3496 bdd5e420 Michael Hanselmann
  cert_pem = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
3497 bdd5e420 Michael Hanselmann
3498 bdd5e420 Michael Hanselmann
  return (key_pem, cert_pem)
3499 bdd5e420 Michael Hanselmann
3500 bdd5e420 Michael Hanselmann
3501 600535f0 Manuel Franceschini
def GenerateSelfSignedSslCert(filename, common_name=constants.X509_CERT_CN,
3502 600535f0 Manuel Franceschini
                              validity=constants.X509_CERT_DEFAULT_VALIDITY):
3503 bdd5e420 Michael Hanselmann
  """Legacy function to generate self-signed X509 certificate.
3504 bdd5e420 Michael Hanselmann

3505 2ea65c7d Manuel Franceschini
  @type filename: str
3506 2ea65c7d Manuel Franceschini
  @param filename: path to write certificate to
3507 600535f0 Manuel Franceschini
  @type common_name: string
3508 600535f0 Manuel Franceschini
  @param common_name: commonName value
3509 600535f0 Manuel Franceschini
  @type validity: int
3510 600535f0 Manuel Franceschini
  @param validity: validity of certificate in number of days
3511 600535f0 Manuel Franceschini

3512 bdd5e420 Michael Hanselmann
  """
3513 600535f0 Manuel Franceschini
  # TODO: Investigate using the cluster name instead of X505_CERT_CN for
3514 600535f0 Manuel Franceschini
  # common_name, as cluster-renames are very seldom, and it'd be nice if RAPI
3515 600535f0 Manuel Franceschini
  # and node daemon certificates have the proper Subject/Issuer.
3516 600535f0 Manuel Franceschini
  (key_pem, cert_pem) = GenerateSelfSignedX509Cert(common_name,
3517 bdd5e420 Michael Hanselmann
                                                   validity * 24 * 60 * 60)
3518 bdd5e420 Michael Hanselmann
3519 bdd5e420 Michael Hanselmann
  WriteFile(filename, mode=0400, data=key_pem + cert_pem)
3520 a55474c7 Michael Hanselmann
3521 a55474c7 Michael Hanselmann
3522 a87b4824 Michael Hanselmann
class FileLock(object):
3523 a87b4824 Michael Hanselmann
  """Utility class for file locks.
3524 a87b4824 Michael Hanselmann

3525 a87b4824 Michael Hanselmann
  """
3526 b4478d34 Michael Hanselmann
  def __init__(self, fd, filename):
3527 58885d79 Iustin Pop
    """Constructor for FileLock.
3528 58885d79 Iustin Pop

3529 b4478d34 Michael Hanselmann
    @type fd: file
3530 b4478d34 Michael Hanselmann
    @param fd: File object
3531 58885d79 Iustin Pop
    @type filename: str
3532 b4478d34 Michael Hanselmann
    @param filename: Path of the file opened at I{fd}
3533 58885d79 Iustin Pop

3534 58885d79 Iustin Pop
    """
3535 b4478d34 Michael Hanselmann
    self.fd = fd
3536 a87b4824 Michael Hanselmann
    self.filename = filename
3537 b4478d34 Michael Hanselmann
3538 b4478d34 Michael Hanselmann
  @classmethod
3539 b4478d34 Michael Hanselmann
  def Open(cls, filename):
3540 b4478d34 Michael Hanselmann
    """Creates and opens a file to be used as a file-based lock.
3541 b4478d34 Michael Hanselmann

3542 b4478d34 Michael Hanselmann
    @type filename: string
3543 b4478d34 Michael Hanselmann
    @param filename: path to the file to be locked
3544 b4478d34 Michael Hanselmann

3545 b4478d34 Michael Hanselmann
    """
3546 b4478d34 Michael Hanselmann
    # Using "os.open" is necessary to allow both opening existing file
3547 b4478d34 Michael Hanselmann
    # read/write and creating if not existing. Vanilla "open" will truncate an
3548 b4478d34 Michael Hanselmann
    # existing file -or- allow creating if not existing.
3549 b4478d34 Michael Hanselmann
    return cls(os.fdopen(os.open(filename, os.O_RDWR | os.O_CREAT), "w+"),
3550 b4478d34 Michael Hanselmann
               filename)
3551 a87b4824 Michael Hanselmann
3552 a87b4824 Michael Hanselmann
  def __del__(self):
3553 a87b4824 Michael Hanselmann
    self.Close()
3554 a87b4824 Michael Hanselmann
3555 a87b4824 Michael Hanselmann
  def Close(self):
3556 58885d79 Iustin Pop
    """Close the file and release the lock.
3557 58885d79 Iustin Pop

3558 58885d79 Iustin Pop
    """
3559 aac3fbf0 Iustin Pop
    if hasattr(self, "fd") and self.fd:
3560 a87b4824 Michael Hanselmann
      self.fd.close()
3561 a87b4824 Michael Hanselmann
      self.fd = None
3562 a87b4824 Michael Hanselmann
3563 aa74b828 Michael Hanselmann
  def _flock(self, flag, blocking, timeout, errmsg):
3564 aa74b828 Michael Hanselmann
    """Wrapper for fcntl.flock.
3565 aa74b828 Michael Hanselmann

3566 aa74b828 Michael Hanselmann
    @type flag: int
3567 58885d79 Iustin Pop
    @param flag: operation flag
3568 aa74b828 Michael Hanselmann
    @type blocking: bool
3569 58885d79 Iustin Pop
    @param blocking: whether the operation should be done in blocking mode.
3570 aa74b828 Michael Hanselmann
    @type timeout: None or float
3571 58885d79 Iustin Pop
    @param timeout: for how long the operation should be retried (implies
3572 aa74b828 Michael Hanselmann
                    non-blocking mode).
3573 aa74b828 Michael Hanselmann
    @type errmsg: string
3574 58885d79 Iustin Pop
    @param errmsg: error message in case operation fails.
3575 aa74b828 Michael Hanselmann

3576 aa74b828 Michael Hanselmann
    """
3577 a87b4824 Michael Hanselmann
    assert self.fd, "Lock was closed"
3578 aa74b828 Michael Hanselmann
    assert timeout is None or timeout >= 0, \
3579 aa74b828 Michael Hanselmann
      "If specified, timeout must be positive"
3580 cc4c9b91 Michael Hanselmann
    assert not (flag & fcntl.LOCK_NB), "LOCK_NB must not be set"
3581 a87b4824 Michael Hanselmann
3582 cc4c9b91 Michael Hanselmann
    # When a timeout is used, LOCK_NB must always be set
3583 cc4c9b91 Michael Hanselmann
    if not (timeout is None and blocking):
3584 a87b4824 Michael Hanselmann
      flag |= fcntl.LOCK_NB
3585 a87b4824 Michael Hanselmann
3586 cc4c9b91 Michael Hanselmann
    if timeout is None:
3587 cc4c9b91 Michael Hanselmann
      self._Lock(self.fd, flag, timeout)
3588 cc4c9b91 Michael Hanselmann
    else:
3589 cc4c9b91 Michael Hanselmann
      try:
3590 cc4c9b91 Michael Hanselmann
        Retry(self._Lock, (0.1, 1.2, 1.0), timeout,
3591 cc4c9b91 Michael Hanselmann
              args=(self.fd, flag, timeout))
3592 cc4c9b91 Michael Hanselmann
      except RetryTimeout:
3593 cc4c9b91 Michael Hanselmann
        raise errors.LockError(errmsg)
3594 aa74b828 Michael Hanselmann
3595 cc4c9b91 Michael Hanselmann
  @staticmethod
3596 cc4c9b91 Michael Hanselmann
  def _Lock(fd, flag, timeout):
3597 cc4c9b91 Michael Hanselmann
    try:
3598 cc4c9b91 Michael Hanselmann
      fcntl.flock(fd, flag)
3599 cc4c9b91 Michael Hanselmann
    except IOError, err:
3600 cc4c9b91 Michael Hanselmann
      if timeout is not None and err.errno == errno.EAGAIN:
3601 cc4c9b91 Michael Hanselmann
        raise RetryAgain()
3602 31892b4c Michael Hanselmann
3603 cc4c9b91 Michael Hanselmann
      logging.exception("fcntl.flock failed")
3604 cc4c9b91 Michael Hanselmann
      raise
3605 aa74b828 Michael Hanselmann
3606 aa74b828 Michael Hanselmann
  def Exclusive(self, blocking=False, timeout=None):
3607 a87b4824 Michael Hanselmann
    """Locks the file in exclusive mode.
3608 a87b4824 Michael Hanselmann

3609 58885d79 Iustin Pop
    @type blocking: boolean
3610 58885d79 Iustin Pop
    @param blocking: whether to block and wait until we
3611 58885d79 Iustin Pop
        can lock the file or return immediately
3612 58885d79 Iustin Pop
    @type timeout: int or None
3613 58885d79 Iustin Pop
    @param timeout: if not None, the duration to wait for the lock
3614 58885d79 Iustin Pop
        (in blocking mode)
3615 58885d79 Iustin Pop

3616 a87b4824 Michael Hanselmann
    """
3617 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_EX, blocking, timeout,
3618 a87b4824 Michael Hanselmann
                "Failed to lock %s in exclusive mode" % self.filename)
3619 a87b4824 Michael Hanselmann
3620 aa74b828 Michael Hanselmann
  def Shared(self, blocking=False, timeout=None):
3621 a87b4824 Michael Hanselmann
    """Locks the file in shared mode.
3622 a87b4824 Michael Hanselmann

3623 58885d79 Iustin Pop
    @type blocking: boolean
3624 58885d79 Iustin Pop
    @param blocking: whether to block and wait until we
3625 58885d79 Iustin Pop
        can lock the file or return immediately
3626 58885d79 Iustin Pop
    @type timeout: int or None
3627 58885d79 Iustin Pop
    @param timeout: if not None, the duration to wait for the lock
3628 58885d79 Iustin Pop
        (in blocking mode)
3629 58885d79 Iustin Pop

3630 a87b4824 Michael Hanselmann
    """
3631 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_SH, blocking, timeout,
3632 a87b4824 Michael Hanselmann
                "Failed to lock %s in shared mode" % self.filename)
3633 a87b4824 Michael Hanselmann
3634 aa74b828 Michael Hanselmann
  def Unlock(self, blocking=True, timeout=None):
3635 a87b4824 Michael Hanselmann
    """Unlocks the file.
3636 a87b4824 Michael Hanselmann

3637 58885d79 Iustin Pop
    According to C{flock(2)}, unlocking can also be a nonblocking
3638 58885d79 Iustin Pop
    operation::
3639 58885d79 Iustin Pop

3640 58885d79 Iustin Pop
      To make a non-blocking request, include LOCK_NB with any of the above
3641 58885d79 Iustin Pop
      operations.
3642 58885d79 Iustin Pop

3643 58885d79 Iustin Pop
    @type blocking: boolean
3644 58885d79 Iustin Pop
    @param blocking: whether to block and wait until we
3645 58885d79 Iustin Pop
        can lock the file or return immediately
3646 58885d79 Iustin Pop
    @type timeout: int or None
3647 58885d79 Iustin Pop
    @param timeout: if not None, the duration to wait for the lock
3648 58885d79 Iustin Pop
        (in blocking mode)
3649 a87b4824 Michael Hanselmann

3650 a87b4824 Michael Hanselmann
    """
3651 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_UN, blocking, timeout,
3652 a87b4824 Michael Hanselmann
                "Failed to unlock %s" % self.filename)
3653 a87b4824 Michael Hanselmann
3654 a87b4824 Michael Hanselmann
3655 339be5a8 Michael Hanselmann
class LineSplitter:
3656 339be5a8 Michael Hanselmann
  """Splits data chunks into lines separated by newline.
3657 339be5a8 Michael Hanselmann

3658 339be5a8 Michael Hanselmann
  Instances provide a file-like interface.
3659 339be5a8 Michael Hanselmann

3660 339be5a8 Michael Hanselmann
  """
3661 339be5a8 Michael Hanselmann
  def __init__(self, line_fn, *args):
3662 339be5a8 Michael Hanselmann
    """Initializes this class.
3663 339be5a8 Michael Hanselmann

3664 339be5a8 Michael Hanselmann
    @type line_fn: callable
3665 339be5a8 Michael Hanselmann
    @param line_fn: Function called for each line, first parameter is line
3666 339be5a8 Michael Hanselmann
    @param args: Extra arguments for L{line_fn}
3667 339be5a8 Michael Hanselmann

3668 339be5a8 Michael Hanselmann
    """
3669 339be5a8 Michael Hanselmann
    assert callable(line_fn)
3670 339be5a8 Michael Hanselmann
3671 339be5a8 Michael Hanselmann
    if args:
3672 339be5a8 Michael Hanselmann
      # Python 2.4 doesn't have functools.partial yet
3673 339be5a8 Michael Hanselmann
      self._line_fn = \
3674 339be5a8 Michael Hanselmann
        lambda line: line_fn(line, *args) # pylint: disable-msg=W0142
3675 339be5a8 Michael Hanselmann
    else:
3676 339be5a8 Michael Hanselmann
      self._line_fn = line_fn
3677 339be5a8 Michael Hanselmann
3678 339be5a8 Michael Hanselmann
    self._lines = collections.deque()
3679 339be5a8 Michael Hanselmann
    self._buffer = ""
3680 339be5a8 Michael Hanselmann
3681 339be5a8 Michael Hanselmann
  def write(self, data):
3682 339be5a8 Michael Hanselmann
    parts = (self._buffer + data).split("\n")
3683 339be5a8 Michael Hanselmann
    self._buffer = parts.pop()
3684 339be5a8 Michael Hanselmann
    self._lines.extend(parts)
3685 339be5a8 Michael Hanselmann
3686 339be5a8 Michael Hanselmann
  def flush(self):
3687 339be5a8 Michael Hanselmann
    while self._lines:
3688 339be5a8 Michael Hanselmann
      self._line_fn(self._lines.popleft().rstrip("\r\n"))
3689 339be5a8 Michael Hanselmann
3690 339be5a8 Michael Hanselmann
  def close(self):
3691 339be5a8 Michael Hanselmann
    self.flush()
3692 339be5a8 Michael Hanselmann
    if self._buffer:
3693 339be5a8 Michael Hanselmann
      self._line_fn(self._buffer)
3694 339be5a8 Michael Hanselmann
3695 339be5a8 Michael Hanselmann
3696 451575de Guido Trotter
def SignalHandled(signums):
3697 451575de Guido Trotter
  """Signal Handled decoration.
3698 451575de Guido Trotter

3699 451575de Guido Trotter
  This special decorator installs a signal handler and then calls the target
3700 451575de Guido Trotter
  function. The function must accept a 'signal_handlers' keyword argument,
3701 451575de Guido Trotter
  which will contain a dict indexed by signal number, with SignalHandler
3702 451575de Guido Trotter
  objects as values.
3703 451575de Guido Trotter

3704 451575de Guido Trotter
  The decorator can be safely stacked with iself, to handle multiple signals
3705 451575de Guido Trotter
  with different handlers.
3706 451575de Guido Trotter

3707 451575de Guido Trotter
  @type signums: list
3708 451575de Guido Trotter
  @param signums: signals to intercept
3709 451575de Guido Trotter

3710 451575de Guido Trotter
  """
3711 451575de Guido Trotter
  def wrap(fn):
3712 451575de Guido Trotter
    def sig_function(*args, **kwargs):
3713 451575de Guido Trotter
      assert 'signal_handlers' not in kwargs or \
3714 451575de Guido Trotter
             kwargs['signal_handlers'] is None or \
3715 451575de Guido Trotter
             isinstance(kwargs['signal_handlers'], dict), \
3716 451575de Guido Trotter
             "Wrong signal_handlers parameter in original function call"
3717 451575de Guido Trotter
      if 'signal_handlers' in kwargs and kwargs['signal_handlers'] is not None:
3718 451575de Guido Trotter
        signal_handlers = kwargs['signal_handlers']
3719 451575de Guido Trotter
      else:
3720 451575de Guido Trotter
        signal_handlers = {}
3721 451575de Guido Trotter
        kwargs['signal_handlers'] = signal_handlers
3722 451575de Guido Trotter
      sighandler = SignalHandler(signums)
3723 451575de Guido Trotter
      try:
3724 451575de Guido Trotter
        for sig in signums:
3725 451575de Guido Trotter
          signal_handlers[sig] = sighandler
3726 451575de Guido Trotter
        return fn(*args, **kwargs)
3727 451575de Guido Trotter
      finally:
3728 451575de Guido Trotter
        sighandler.Reset()
3729 451575de Guido Trotter
    return sig_function
3730 451575de Guido Trotter
  return wrap
3731 451575de Guido Trotter
3732 451575de Guido Trotter
3733 b9768937 Michael Hanselmann
class SignalWakeupFd(object):
3734 b9768937 Michael Hanselmann
  try:
3735 b9768937 Michael Hanselmann
    # This is only supported in Python 2.5 and above (some distributions
3736 b9768937 Michael Hanselmann
    # backported it to Python 2.4)
3737 b9768937 Michael Hanselmann
    _set_wakeup_fd_fn = signal.set_wakeup_fd
3738 b9768937 Michael Hanselmann
  except AttributeError:
3739 b9768937 Michael Hanselmann
    # Not supported
3740 b9768937 Michael Hanselmann
    def _SetWakeupFd(self, _): # pylint: disable-msg=R0201
3741 b9768937 Michael Hanselmann
      return -1
3742 b9768937 Michael Hanselmann
  else:
3743 b9768937 Michael Hanselmann
    def _SetWakeupFd(self, fd):
3744 b9768937 Michael Hanselmann
      return self._set_wakeup_fd_fn(fd)
3745 b9768937 Michael Hanselmann
3746 b9768937 Michael Hanselmann
  def __init__(self):
3747 b9768937 Michael Hanselmann
    """Initializes this class.
3748 b9768937 Michael Hanselmann

3749 b9768937 Michael Hanselmann
    """
3750 b9768937 Michael Hanselmann
    (read_fd, write_fd) = os.pipe()
3751 b9768937 Michael Hanselmann
3752 b9768937 Michael Hanselmann
    # Once these succeeded, the file descriptors will be closed automatically.
3753 b9768937 Michael Hanselmann
    # Buffer size 0 is important, otherwise .read() with a specified length
3754 b9768937 Michael Hanselmann
    # might buffer data and the file descriptors won't be marked readable.
3755 b9768937 Michael Hanselmann
    self._read_fh = os.fdopen(read_fd, "r", 0)
3756 b9768937 Michael Hanselmann
    self._write_fh = os.fdopen(write_fd, "w", 0)
3757 b9768937 Michael Hanselmann
3758 b9768937 Michael Hanselmann
    self._previous = self._SetWakeupFd(self._write_fh.fileno())
3759 b9768937 Michael Hanselmann
3760 b9768937 Michael Hanselmann
    # Utility functions
3761 b9768937 Michael Hanselmann
    self.fileno = self._read_fh.fileno
3762 b9768937 Michael Hanselmann
    self.read = self._read_fh.read
3763 b9768937 Michael Hanselmann
3764 b9768937 Michael Hanselmann
  def Reset(self):
3765 b9768937 Michael Hanselmann
    """Restores the previous wakeup file descriptor.
3766 b9768937 Michael Hanselmann

3767 b9768937 Michael Hanselmann
    """
3768 b9768937 Michael Hanselmann
    if hasattr(self, "_previous") and self._previous is not None:
3769 b9768937 Michael Hanselmann
      self._SetWakeupFd(self._previous)
3770 b9768937 Michael Hanselmann
      self._previous = None
3771 b9768937 Michael Hanselmann
3772 b9768937 Michael Hanselmann
  def Notify(self):
3773 b9768937 Michael Hanselmann
    """Notifies the wakeup file descriptor.
3774 b9768937 Michael Hanselmann

3775 b9768937 Michael Hanselmann
    """
3776 b9768937 Michael Hanselmann
    self._write_fh.write("\0")
3777 b9768937 Michael Hanselmann
3778 b9768937 Michael Hanselmann
  def __del__(self):
3779 b9768937 Michael Hanselmann
    """Called before object deletion.
3780 b9768937 Michael Hanselmann

3781 b9768937 Michael Hanselmann
    """
3782 b9768937 Michael Hanselmann
    self.Reset()
3783 b9768937 Michael Hanselmann
3784 b9768937 Michael Hanselmann
3785 de499029 Michael Hanselmann
class SignalHandler(object):
3786 de499029 Michael Hanselmann
  """Generic signal handler class.
3787 de499029 Michael Hanselmann

3788 58885d79 Iustin Pop
  It automatically restores the original handler when deconstructed or
3789 58885d79 Iustin Pop
  when L{Reset} is called. You can either pass your own handler
3790 58885d79 Iustin Pop
  function in or query the L{called} attribute to detect whether the
3791 58885d79 Iustin Pop
  signal was sent.
3792 58885d79 Iustin Pop

3793 58885d79 Iustin Pop
  @type signum: list
3794 58885d79 Iustin Pop
  @ivar signum: the signals we handle
3795 58885d79 Iustin Pop
  @type called: boolean
3796 58885d79 Iustin Pop
  @ivar called: tracks whether any of the signals have been raised
3797 de499029 Michael Hanselmann

3798 de499029 Michael Hanselmann
  """
3799 b9768937 Michael Hanselmann
  def __init__(self, signum, handler_fn=None, wakeup=None):
3800 de499029 Michael Hanselmann
    """Constructs a new SignalHandler instance.
3801 de499029 Michael Hanselmann

3802 58885d79 Iustin Pop
    @type signum: int or list of ints
3803 de499029 Michael Hanselmann
    @param signum: Single signal number or set of signal numbers
3804 92b61ec7 Michael Hanselmann
    @type handler_fn: callable
3805 92b61ec7 Michael Hanselmann
    @param handler_fn: Signal handling function
3806 de499029 Michael Hanselmann

3807 de499029 Michael Hanselmann
    """
3808 92b61ec7 Michael Hanselmann
    assert handler_fn is None or callable(handler_fn)
3809 92b61ec7 Michael Hanselmann
3810 6c52849e Guido Trotter
    self.signum = set(signum)
3811 de499029 Michael Hanselmann
    self.called = False
3812 de499029 Michael Hanselmann
3813 92b61ec7 Michael Hanselmann
    self._handler_fn = handler_fn
3814 b9768937 Michael Hanselmann
    self._wakeup = wakeup
3815 92b61ec7 Michael Hanselmann
3816 de499029 Michael Hanselmann
    self._previous = {}
3817 de499029 Michael Hanselmann
    try:
3818 de499029 Michael Hanselmann
      for signum in self.signum:
3819 de499029 Michael Hanselmann
        # Setup handler
3820 de499029 Michael Hanselmann
        prev_handler = signal.signal(signum, self._HandleSignal)
3821 de499029 Michael Hanselmann
        try:
3822 de499029 Michael Hanselmann
          self._previous[signum] = prev_handler
3823 de499029 Michael Hanselmann
        except:
3824 de499029 Michael Hanselmann
          # Restore previous handler
3825 de499029 Michael Hanselmann
          signal.signal(signum, prev_handler)
3826 de499029 Michael Hanselmann
          raise
3827 de499029 Michael Hanselmann
    except:
3828 de499029 Michael Hanselmann
      # Reset all handlers
3829 de499029 Michael Hanselmann
      self.Reset()
3830 de499029 Michael Hanselmann
      # Here we have a race condition: a handler may have already been called,
3831 de499029 Michael Hanselmann
      # but there's not much we can do about it at this point.
3832 de499029 Michael Hanselmann
      raise
3833 de499029 Michael Hanselmann
3834 de499029 Michael Hanselmann
  def __del__(self):
3835 de499029 Michael Hanselmann
    self.Reset()
3836 de499029 Michael Hanselmann
3837 de499029 Michael Hanselmann
  def Reset(self):
3838 de499029 Michael Hanselmann
    """Restore previous handler.
3839 de499029 Michael Hanselmann

3840 58885d79 Iustin Pop
    This will reset all the signals to their previous handlers.
3841 58885d79 Iustin Pop

3842 de499029 Michael Hanselmann
    """
3843 de499029 Michael Hanselmann
    for signum, prev_handler in self._previous.items():
3844 de499029 Michael Hanselmann
      signal.signal(signum, prev_handler)
3845 de499029 Michael Hanselmann
      # If successful, remove from dict
3846 de499029 Michael Hanselmann
      del self._previous[signum]
3847 de499029 Michael Hanselmann
3848 de499029 Michael Hanselmann
  def Clear(self):
3849 58885d79 Iustin Pop
    """Unsets the L{called} flag.
3850 de499029 Michael Hanselmann

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

3853 de499029 Michael Hanselmann
    """
3854 de499029 Michael Hanselmann
    self.called = False
3855 de499029 Michael Hanselmann
3856 92b61ec7 Michael Hanselmann
  def _HandleSignal(self, signum, frame):
3857 de499029 Michael Hanselmann
    """Actual signal handling function.
3858 de499029 Michael Hanselmann

3859 de499029 Michael Hanselmann
    """
3860 de499029 Michael Hanselmann
    # This is not nice and not absolutely atomic, but it appears to be the only
3861 de499029 Michael Hanselmann
    # solution in Python -- there are no atomic types.
3862 de499029 Michael Hanselmann
    self.called = True
3863 a2d2e1a7 Iustin Pop
3864 b9768937 Michael Hanselmann
    if self._wakeup:
3865 b9768937 Michael Hanselmann
      # Notify whoever is interested in signals
3866 b9768937 Michael Hanselmann
      self._wakeup.Notify()
3867 b9768937 Michael Hanselmann
3868 92b61ec7 Michael Hanselmann
    if self._handler_fn:
3869 92b61ec7 Michael Hanselmann
      self._handler_fn(signum, frame)
3870 92b61ec7 Michael Hanselmann
3871 a2d2e1a7 Iustin Pop
3872 a2d2e1a7 Iustin Pop
class FieldSet(object):
3873 a2d2e1a7 Iustin Pop
  """A simple field set.
3874 a2d2e1a7 Iustin Pop

3875 a2d2e1a7 Iustin Pop
  Among the features are:
3876 a2d2e1a7 Iustin Pop
    - checking if a string is among a list of static string or regex objects
3877 a2d2e1a7 Iustin Pop
    - checking if a whole list of string matches
3878 a2d2e1a7 Iustin Pop
    - returning the matching groups from a regex match
3879 a2d2e1a7 Iustin Pop

3880 a2d2e1a7 Iustin Pop
  Internally, all fields are held as regular expression objects.
3881 a2d2e1a7 Iustin Pop

3882 a2d2e1a7 Iustin Pop
  """
3883 a2d2e1a7 Iustin Pop
  def __init__(self, *items):
3884 a2d2e1a7 Iustin Pop
    self.items = [re.compile("^%s$" % value) for value in items]
3885 a2d2e1a7 Iustin Pop
3886 a2d2e1a7 Iustin Pop
  def Extend(self, other_set):
3887 a2d2e1a7 Iustin Pop
    """Extend the field set with the items from another one"""
3888 a2d2e1a7 Iustin Pop
    self.items.extend(other_set.items)
3889 a2d2e1a7 Iustin Pop
3890 a2d2e1a7 Iustin Pop
  def Matches(self, field):
3891 a2d2e1a7 Iustin Pop
    """Checks if a field matches the current set
3892 a2d2e1a7 Iustin Pop

3893 a2d2e1a7 Iustin Pop
    @type field: str
3894 a2d2e1a7 Iustin Pop
    @param field: the string to match
3895 6c881c52 Iustin Pop
    @return: either None or a regular expression match object
3896 a2d2e1a7 Iustin Pop

3897 a2d2e1a7 Iustin Pop
    """
3898 a2d2e1a7 Iustin Pop
    for m in itertools.ifilter(None, (val.match(field) for val in self.items)):
3899 a2d2e1a7 Iustin Pop
      return m
3900 6c881c52 Iustin Pop
    return None
3901 a2d2e1a7 Iustin Pop
3902 a2d2e1a7 Iustin Pop
  def NonMatching(self, items):
3903 a2d2e1a7 Iustin Pop
    """Returns the list of fields not matching the current set
3904 a2d2e1a7 Iustin Pop

3905 a2d2e1a7 Iustin Pop
    @type items: list
3906 a2d2e1a7 Iustin Pop
    @param items: the list of fields to check
3907 a2d2e1a7 Iustin Pop
    @rtype: list
3908 a2d2e1a7 Iustin Pop
    @return: list of non-matching fields
3909 a2d2e1a7 Iustin Pop

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