Statistics
| Branch: | Tag: | Revision:

root / lib / utils.py @ 90eb468c

History | View | Annotate | Download (50.1 kB)

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

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

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

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

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

109 a8083063 Iustin Pop
    """
110 a8083063 Iustin Pop
    return self.stdout + self.stderr
111 a8083063 Iustin Pop
112 a8083063 Iustin Pop
  output = property(_GetOutput, None, None, "Return full output")
113 a8083063 Iustin Pop
114 a8083063 Iustin Pop
115 8797df43 Iustin Pop
def RunCmd(cmd, env=None, output=None, cwd='/'):
116 a8083063 Iustin Pop
  """Execute a (shell) command.
117 a8083063 Iustin Pop

118 a8083063 Iustin Pop
  The command should not read from its standard input, as it will be
119 a8083063 Iustin Pop
  closed.
120 a8083063 Iustin Pop

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

136 a8083063 Iustin Pop
  """
137 b74159ee Iustin Pop
  if no_fork:
138 b74159ee Iustin Pop
    raise errors.ProgrammerError("utils.RunCmd() called with fork() disabled")
139 b74159ee Iustin Pop
140 a8083063 Iustin Pop
  if isinstance(cmd, list):
141 a8083063 Iustin Pop
    cmd = [str(val) for val in cmd]
142 113b55aa Iustin Pop
    strcmd = " ".join(cmd)
143 113b55aa Iustin Pop
    shell = False
144 113b55aa Iustin Pop
  else:
145 113b55aa Iustin Pop
    strcmd = cmd
146 113b55aa Iustin Pop
    shell = True
147 bb698c1f Iustin Pop
  logging.debug("RunCmd '%s'", strcmd)
148 2557ff82 Guido Trotter
149 2557ff82 Guido Trotter
  cmd_env = os.environ.copy()
150 2557ff82 Guido Trotter
  cmd_env["LC_ALL"] = "C"
151 2557ff82 Guido Trotter
  if env is not None:
152 2557ff82 Guido Trotter
    cmd_env.update(env)
153 2557ff82 Guido Trotter
154 36117c2b Iustin Pop
  if output is None:
155 8797df43 Iustin Pop
    out, err, status = _RunCmdPipe(cmd, cmd_env, shell, cwd)
156 36117c2b Iustin Pop
  else:
157 8797df43 Iustin Pop
    status = _RunCmdFile(cmd, cmd_env, shell, output, cwd)
158 36117c2b Iustin Pop
    out = err = ""
159 36117c2b Iustin Pop
160 36117c2b Iustin Pop
  if status >= 0:
161 36117c2b Iustin Pop
    exitcode = status
162 36117c2b Iustin Pop
    signal_ = None
163 36117c2b Iustin Pop
  else:
164 36117c2b Iustin Pop
    exitcode = None
165 36117c2b Iustin Pop
    signal_ = -status
166 36117c2b Iustin Pop
167 36117c2b Iustin Pop
  return RunResult(exitcode, signal_, out, err, strcmd)
168 36117c2b Iustin Pop
169 8797df43 Iustin Pop
def _RunCmdPipe(cmd, env, via_shell, cwd):
170 36117c2b Iustin Pop
  """Run a command and return its output.
171 36117c2b Iustin Pop

172 36117c2b Iustin Pop
  @type  cmd: string or list
173 36117c2b Iustin Pop
  @param cmd: Command to run
174 36117c2b Iustin Pop
  @type env: dict
175 36117c2b Iustin Pop
  @param env: The environment to use
176 36117c2b Iustin Pop
  @type via_shell: bool
177 36117c2b Iustin Pop
  @param via_shell: if we should run via the shell
178 8797df43 Iustin Pop
  @type cwd: string
179 8797df43 Iustin Pop
  @param cwd: the working directory for the program
180 36117c2b Iustin Pop
  @rtype: tuple
181 36117c2b Iustin Pop
  @return: (out, err, status)
182 36117c2b Iustin Pop

183 36117c2b Iustin Pop
  """
184 9c233417 Iustin Pop
  poller = select.poll()
185 36117c2b Iustin Pop
  child = subprocess.Popen(cmd, shell=via_shell,
186 113b55aa Iustin Pop
                           stderr=subprocess.PIPE,
187 113b55aa Iustin Pop
                           stdout=subprocess.PIPE,
188 113b55aa Iustin Pop
                           stdin=subprocess.PIPE,
189 8797df43 Iustin Pop
                           close_fds=True, env=env,
190 8797df43 Iustin Pop
                           cwd=cwd)
191 113b55aa Iustin Pop
192 113b55aa Iustin Pop
  child.stdin.close()
193 9c233417 Iustin Pop
  poller.register(child.stdout, select.POLLIN)
194 9c233417 Iustin Pop
  poller.register(child.stderr, select.POLLIN)
195 9c233417 Iustin Pop
  out = StringIO()
196 9c233417 Iustin Pop
  err = StringIO()
197 9c233417 Iustin Pop
  fdmap = {
198 9c233417 Iustin Pop
    child.stdout.fileno(): (out, child.stdout),
199 9c233417 Iustin Pop
    child.stderr.fileno(): (err, child.stderr),
200 9c233417 Iustin Pop
    }
201 9c233417 Iustin Pop
  for fd in fdmap:
202 9c233417 Iustin Pop
    status = fcntl.fcntl(fd, fcntl.F_GETFL)
203 9c233417 Iustin Pop
    fcntl.fcntl(fd, fcntl.F_SETFL, status | os.O_NONBLOCK)
204 9c233417 Iustin Pop
205 9c233417 Iustin Pop
  while fdmap:
206 9c233417 Iustin Pop
    for fd, event in poller.poll():
207 9c233417 Iustin Pop
      if event & select.POLLIN or event & select.POLLPRI:
208 9c233417 Iustin Pop
        data = fdmap[fd][1].read()
209 9c233417 Iustin Pop
        # no data from read signifies EOF (the same as POLLHUP)
210 9c233417 Iustin Pop
        if not data:
211 9c233417 Iustin Pop
          poller.unregister(fd)
212 9c233417 Iustin Pop
          del fdmap[fd]
213 9c233417 Iustin Pop
          continue
214 9c233417 Iustin Pop
        fdmap[fd][0].write(data)
215 9c233417 Iustin Pop
      if (event & select.POLLNVAL or event & select.POLLHUP or
216 9c233417 Iustin Pop
          event & select.POLLERR):
217 9c233417 Iustin Pop
        poller.unregister(fd)
218 9c233417 Iustin Pop
        del fdmap[fd]
219 9c233417 Iustin Pop
220 9c233417 Iustin Pop
  out = out.getvalue()
221 9c233417 Iustin Pop
  err = err.getvalue()
222 a8083063 Iustin Pop
223 a8083063 Iustin Pop
  status = child.wait()
224 36117c2b Iustin Pop
  return out, err, status
225 a8083063 Iustin Pop
226 36117c2b Iustin Pop
227 8797df43 Iustin Pop
def _RunCmdFile(cmd, env, via_shell, output, cwd):
228 36117c2b Iustin Pop
  """Run a command and save its output to a file.
229 36117c2b Iustin Pop

230 36117c2b Iustin Pop
  @type  cmd: string or list
231 36117c2b Iustin Pop
  @param cmd: Command to run
232 36117c2b Iustin Pop
  @type env: dict
233 36117c2b Iustin Pop
  @param env: The environment to use
234 36117c2b Iustin Pop
  @type via_shell: bool
235 36117c2b Iustin Pop
  @param via_shell: if we should run via the shell
236 36117c2b Iustin Pop
  @type output: str
237 36117c2b Iustin Pop
  @param output: the filename in which to save the output
238 8797df43 Iustin Pop
  @type cwd: string
239 8797df43 Iustin Pop
  @param cwd: the working directory for the program
240 36117c2b Iustin Pop
  @rtype: int
241 36117c2b Iustin Pop
  @return: the exit status
242 36117c2b Iustin Pop

243 36117c2b Iustin Pop
  """
244 36117c2b Iustin Pop
  fh = open(output, "a")
245 36117c2b Iustin Pop
  try:
246 36117c2b Iustin Pop
    child = subprocess.Popen(cmd, shell=via_shell,
247 36117c2b Iustin Pop
                             stderr=subprocess.STDOUT,
248 36117c2b Iustin Pop
                             stdout=fh,
249 36117c2b Iustin Pop
                             stdin=subprocess.PIPE,
250 8797df43 Iustin Pop
                             close_fds=True, env=env,
251 8797df43 Iustin Pop
                             cwd=cwd)
252 36117c2b Iustin Pop
253 36117c2b Iustin Pop
    child.stdin.close()
254 36117c2b Iustin Pop
    status = child.wait()
255 36117c2b Iustin Pop
  finally:
256 36117c2b Iustin Pop
    fh.close()
257 36117c2b Iustin Pop
  return status
258 a8083063 Iustin Pop
259 a8083063 Iustin Pop
260 a8083063 Iustin Pop
def RemoveFile(filename):
261 a8083063 Iustin Pop
  """Remove a file ignoring some errors.
262 a8083063 Iustin Pop

263 a8083063 Iustin Pop
  Remove a file, ignoring non-existing ones or directories. Other
264 a8083063 Iustin Pop
  errors are passed.
265 a8083063 Iustin Pop

266 58885d79 Iustin Pop
  @type filename: str
267 58885d79 Iustin Pop
  @param filename: the file to be removed
268 58885d79 Iustin Pop

269 a8083063 Iustin Pop
  """
270 a8083063 Iustin Pop
  try:
271 a8083063 Iustin Pop
    os.unlink(filename)
272 a8083063 Iustin Pop
  except OSError, err:
273 4ca1b175 Alexander Schreiber
    if err.errno not in (errno.ENOENT, errno.EISDIR):
274 a8083063 Iustin Pop
      raise
275 a8083063 Iustin Pop
276 a8083063 Iustin Pop
277 a8083063 Iustin Pop
def _FingerprintFile(filename):
278 a8083063 Iustin Pop
  """Compute the fingerprint of a file.
279 a8083063 Iustin Pop

280 a8083063 Iustin Pop
  If the file does not exist, a None will be returned
281 a8083063 Iustin Pop
  instead.
282 a8083063 Iustin Pop

283 58885d79 Iustin Pop
  @type filename: str
284 58885d79 Iustin Pop
  @param filename: the filename to checksum
285 58885d79 Iustin Pop
  @rtype: str
286 58885d79 Iustin Pop
  @return: the hex digest of the sha checksum of the contents
287 58885d79 Iustin Pop
      of the file
288 a8083063 Iustin Pop

289 a8083063 Iustin Pop
  """
290 a8083063 Iustin Pop
  if not (os.path.exists(filename) and os.path.isfile(filename)):
291 a8083063 Iustin Pop
    return None
292 a8083063 Iustin Pop
293 a8083063 Iustin Pop
  f = open(filename)
294 a8083063 Iustin Pop
295 a8083063 Iustin Pop
  fp = sha.sha()
296 a8083063 Iustin Pop
  while True:
297 a8083063 Iustin Pop
    data = f.read(4096)
298 a8083063 Iustin Pop
    if not data:
299 a8083063 Iustin Pop
      break
300 a8083063 Iustin Pop
301 a8083063 Iustin Pop
    fp.update(data)
302 a8083063 Iustin Pop
303 a8083063 Iustin Pop
  return fp.hexdigest()
304 a8083063 Iustin Pop
305 a8083063 Iustin Pop
306 a8083063 Iustin Pop
def FingerprintFiles(files):
307 a8083063 Iustin Pop
  """Compute fingerprints for a list of files.
308 a8083063 Iustin Pop

309 58885d79 Iustin Pop
  @type files: list
310 58885d79 Iustin Pop
  @param files: the list of filename to fingerprint
311 58885d79 Iustin Pop
  @rtype: dict
312 58885d79 Iustin Pop
  @return: a dictionary filename: fingerprint, holding only
313 58885d79 Iustin Pop
      existing files
314 a8083063 Iustin Pop

315 a8083063 Iustin Pop
  """
316 a8083063 Iustin Pop
  ret = {}
317 a8083063 Iustin Pop
318 a8083063 Iustin Pop
  for filename in files:
319 a8083063 Iustin Pop
    cksum = _FingerprintFile(filename)
320 a8083063 Iustin Pop
    if cksum:
321 a8083063 Iustin Pop
      ret[filename] = cksum
322 a8083063 Iustin Pop
323 a8083063 Iustin Pop
  return ret
324 a8083063 Iustin Pop
325 a8083063 Iustin Pop
326 a8083063 Iustin Pop
def CheckDict(target, template, logname=None):
327 a8083063 Iustin Pop
  """Ensure a dictionary has a required set of keys.
328 a8083063 Iustin Pop

329 58885d79 Iustin Pop
  For the given dictionaries I{target} and I{template}, ensure
330 58885d79 Iustin Pop
  I{target} has all the keys from I{template}. Missing keys are added
331 58885d79 Iustin Pop
  with values from template.
332 a8083063 Iustin Pop

333 58885d79 Iustin Pop
  @type target: dict
334 58885d79 Iustin Pop
  @param target: the dictionary to update
335 58885d79 Iustin Pop
  @type template: dict
336 58885d79 Iustin Pop
  @param template: the dictionary holding the default values
337 58885d79 Iustin Pop
  @type logname: str or None
338 58885d79 Iustin Pop
  @param logname: if not None, causes the missing keys to be
339 58885d79 Iustin Pop
      logged with this name
340 a8083063 Iustin Pop

341 a8083063 Iustin Pop
  """
342 a8083063 Iustin Pop
  missing = []
343 a8083063 Iustin Pop
  for k in template:
344 a8083063 Iustin Pop
    if k not in target:
345 a8083063 Iustin Pop
      missing.append(k)
346 a8083063 Iustin Pop
      target[k] = template[k]
347 a8083063 Iustin Pop
348 a8083063 Iustin Pop
  if missing and logname:
349 bb698c1f Iustin Pop
    logging.warning('%s missing keys %s', logname, ', '.join(missing))
350 a8083063 Iustin Pop
351 a8083063 Iustin Pop
352 a8083063 Iustin Pop
def IsProcessAlive(pid):
353 a8083063 Iustin Pop
  """Check if a given pid exists on the system.
354 a8083063 Iustin Pop

355 44bf25ff Iustin Pop
  @note: zombie status is not handled, so zombie processes
356 44bf25ff Iustin Pop
      will be returned as alive
357 58885d79 Iustin Pop
  @type pid: int
358 58885d79 Iustin Pop
  @param pid: the process ID to check
359 58885d79 Iustin Pop
  @rtype: boolean
360 58885d79 Iustin Pop
  @return: True if the process exists
361 a8083063 Iustin Pop

362 a8083063 Iustin Pop
  """
363 d9f311d7 Iustin Pop
  if pid <= 0:
364 d9f311d7 Iustin Pop
    return False
365 d9f311d7 Iustin Pop
366 a8083063 Iustin Pop
  try:
367 44bf25ff Iustin Pop
    os.stat("/proc/%d/status" % pid)
368 44bf25ff Iustin Pop
    return True
369 44bf25ff Iustin Pop
  except EnvironmentError, err:
370 4ca1b175 Alexander Schreiber
    if err.errno in (errno.ENOENT, errno.ENOTDIR):
371 a8083063 Iustin Pop
      return False
372 44bf25ff Iustin Pop
    raise
373 a8083063 Iustin Pop
374 a8083063 Iustin Pop
375 d9f311d7 Iustin Pop
def ReadPidFile(pidfile):
376 58885d79 Iustin Pop
  """Read a pid from a file.
377 fee80e90 Guido Trotter

378 58885d79 Iustin Pop
  @type  pidfile: string
379 58885d79 Iustin Pop
  @param pidfile: path to the file containing the pid
380 58885d79 Iustin Pop
  @rtype: int
381 d9f311d7 Iustin Pop
  @return: The process id, if the file exista and contains a valid PID,
382 d9f311d7 Iustin Pop
           otherwise 0
383 fee80e90 Guido Trotter

384 fee80e90 Guido Trotter
  """
385 fee80e90 Guido Trotter
  try:
386 fee80e90 Guido Trotter
    pf = open(pidfile, 'r')
387 d9f311d7 Iustin Pop
  except EnvironmentError, err:
388 d9f311d7 Iustin Pop
    if err.errno != errno.ENOENT:
389 d9f311d7 Iustin Pop
      logging.exception("Can't read pid file?!")
390 d9f311d7 Iustin Pop
    return 0
391 fee80e90 Guido Trotter
392 fee80e90 Guido Trotter
  try:
393 fee80e90 Guido Trotter
    pid = int(pf.read())
394 d9f311d7 Iustin Pop
  except ValueError, err:
395 8161a646 Iustin Pop
    logging.info("Can't parse pid file contents", exc_info=True)
396 d9f311d7 Iustin Pop
    return 0
397 fee80e90 Guido Trotter
398 d9f311d7 Iustin Pop
  return pid
399 fee80e90 Guido Trotter
400 fee80e90 Guido Trotter
401 a8083063 Iustin Pop
def MatchNameComponent(key, name_list):
402 a8083063 Iustin Pop
  """Try to match a name against a list.
403 a8083063 Iustin Pop

404 a8083063 Iustin Pop
  This function will try to match a name like test1 against a list
405 58885d79 Iustin Pop
  like C{['test1.example.com', 'test2.example.com', ...]}. Against
406 58885d79 Iustin Pop
  this list, I{'test1'} as well as I{'test1.example'} will match, but
407 58885d79 Iustin Pop
  not I{'test1.ex'}. A multiple match will be considered as no match
408 58885d79 Iustin Pop
  at all (e.g. I{'test1'} against C{['test1.example.com',
409 58885d79 Iustin Pop
  'test1.example.org']}).
410 a8083063 Iustin Pop

411 58885d79 Iustin Pop
  @type key: str
412 58885d79 Iustin Pop
  @param key: the name to be searched
413 58885d79 Iustin Pop
  @type name_list: list
414 58885d79 Iustin Pop
  @param name_list: the list of strings against which to search the key
415 a8083063 Iustin Pop

416 58885d79 Iustin Pop
  @rtype: None or str
417 58885d79 Iustin Pop
  @return: None if there is no match I{or} if there are multiple matches,
418 58885d79 Iustin Pop
      otherwise the element from the list which matches
419 a8083063 Iustin Pop

420 a8083063 Iustin Pop
  """
421 a8083063 Iustin Pop
  mo = re.compile("^%s(\..*)?$" % re.escape(key))
422 a8083063 Iustin Pop
  names_filtered = [name for name in name_list if mo.match(name) is not None]
423 a8083063 Iustin Pop
  if len(names_filtered) != 1:
424 a8083063 Iustin Pop
    return None
425 a8083063 Iustin Pop
  return names_filtered[0]
426 a8083063 Iustin Pop
427 a8083063 Iustin Pop
428 bcf043c9 Iustin Pop
class HostInfo:
429 89e1fc26 Iustin Pop
  """Class implementing resolver and hostname functionality
430 bcf043c9 Iustin Pop

431 bcf043c9 Iustin Pop
  """
432 89e1fc26 Iustin Pop
  def __init__(self, name=None):
433 bcf043c9 Iustin Pop
    """Initialize the host name object.
434 bcf043c9 Iustin Pop

435 89e1fc26 Iustin Pop
    If the name argument is not passed, it will use this system's
436 89e1fc26 Iustin Pop
    name.
437 bcf043c9 Iustin Pop

438 bcf043c9 Iustin Pop
    """
439 89e1fc26 Iustin Pop
    if name is None:
440 89e1fc26 Iustin Pop
      name = self.SysName()
441 89e1fc26 Iustin Pop
442 89e1fc26 Iustin Pop
    self.query = name
443 89e1fc26 Iustin Pop
    self.name, self.aliases, self.ipaddrs = self.LookupHostname(name)
444 bcf043c9 Iustin Pop
    self.ip = self.ipaddrs[0]
445 bcf043c9 Iustin Pop
446 c8a0948f Michael Hanselmann
  def ShortName(self):
447 c8a0948f Michael Hanselmann
    """Returns the hostname without domain.
448 c8a0948f Michael Hanselmann

449 c8a0948f Michael Hanselmann
    """
450 c8a0948f Michael Hanselmann
    return self.name.split('.')[0]
451 c8a0948f Michael Hanselmann
452 89e1fc26 Iustin Pop
  @staticmethod
453 89e1fc26 Iustin Pop
  def SysName():
454 89e1fc26 Iustin Pop
    """Return the current system's name.
455 bcf043c9 Iustin Pop

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

458 89e1fc26 Iustin Pop
    """
459 89e1fc26 Iustin Pop
    return socket.gethostname()
460 a8083063 Iustin Pop
461 89e1fc26 Iustin Pop
  @staticmethod
462 89e1fc26 Iustin Pop
  def LookupHostname(hostname):
463 89e1fc26 Iustin Pop
    """Look up hostname
464 a8083063 Iustin Pop

465 58885d79 Iustin Pop
    @type hostname: str
466 58885d79 Iustin Pop
    @param hostname: hostname to look up
467 89e1fc26 Iustin Pop

468 58885d79 Iustin Pop
    @rtype: tuple
469 58885d79 Iustin Pop
    @return: a tuple (name, aliases, ipaddrs) as returned by
470 58885d79 Iustin Pop
        C{socket.gethostbyname_ex}
471 58885d79 Iustin Pop
    @raise errors.ResolverError: in case of errors in resolving
472 89e1fc26 Iustin Pop

473 89e1fc26 Iustin Pop
    """
474 89e1fc26 Iustin Pop
    try:
475 89e1fc26 Iustin Pop
      result = socket.gethostbyname_ex(hostname)
476 89e1fc26 Iustin Pop
    except socket.gaierror, err:
477 89e1fc26 Iustin Pop
      # hostname not found in DNS
478 89e1fc26 Iustin Pop
      raise errors.ResolverError(hostname, err.args[0], err.args[1])
479 a8083063 Iustin Pop
480 89e1fc26 Iustin Pop
    return result
481 a8083063 Iustin Pop
482 a8083063 Iustin Pop
483 a8083063 Iustin Pop
def ListVolumeGroups():
484 a8083063 Iustin Pop
  """List volume groups and their size
485 a8083063 Iustin Pop

486 58885d79 Iustin Pop
  @rtype: dict
487 58885d79 Iustin Pop
  @return:
488 58885d79 Iustin Pop
       Dictionary with keys volume name and values
489 58885d79 Iustin Pop
       the size of the volume
490 a8083063 Iustin Pop

491 a8083063 Iustin Pop
  """
492 a8083063 Iustin Pop
  command = "vgs --noheadings --units m --nosuffix -o name,size"
493 a8083063 Iustin Pop
  result = RunCmd(command)
494 a8083063 Iustin Pop
  retval = {}
495 a8083063 Iustin Pop
  if result.failed:
496 a8083063 Iustin Pop
    return retval
497 a8083063 Iustin Pop
498 a8083063 Iustin Pop
  for line in result.stdout.splitlines():
499 a8083063 Iustin Pop
    try:
500 a8083063 Iustin Pop
      name, size = line.split()
501 a8083063 Iustin Pop
      size = int(float(size))
502 a8083063 Iustin Pop
    except (IndexError, ValueError), err:
503 bb698c1f Iustin Pop
      logging.error("Invalid output from vgs (%s): %s", err, line)
504 a8083063 Iustin Pop
      continue
505 a8083063 Iustin Pop
506 a8083063 Iustin Pop
    retval[name] = size
507 a8083063 Iustin Pop
508 a8083063 Iustin Pop
  return retval
509 a8083063 Iustin Pop
510 a8083063 Iustin Pop
511 a8083063 Iustin Pop
def BridgeExists(bridge):
512 a8083063 Iustin Pop
  """Check whether the given bridge exists in the system
513 a8083063 Iustin Pop

514 58885d79 Iustin Pop
  @type bridge: str
515 58885d79 Iustin Pop
  @param bridge: the bridge name to check
516 58885d79 Iustin Pop
  @rtype: boolean
517 58885d79 Iustin Pop
  @return: True if it does
518 a8083063 Iustin Pop

519 a8083063 Iustin Pop
  """
520 a8083063 Iustin Pop
  return os.path.isdir("/sys/class/net/%s/bridge" % bridge)
521 a8083063 Iustin Pop
522 a8083063 Iustin Pop
523 42ce2e13 Guido Trotter
def CheckBEParams(beparams):
524 42ce2e13 Guido Trotter
  """Checks whether the user-supplied be-params are valid,
525 42ce2e13 Guido Trotter
  and converts them from string format where appropriate.
526 42ce2e13 Guido Trotter

527 42ce2e13 Guido Trotter
  @type beparams: dict
528 42ce2e13 Guido Trotter
  @param beparams: new params dict
529 42ce2e13 Guido Trotter

530 42ce2e13 Guido Trotter
  """
531 42ce2e13 Guido Trotter
  if beparams:
532 42ce2e13 Guido Trotter
    for item in beparams:
533 42ce2e13 Guido Trotter
      if item not in constants.BES_PARAMETERS:
534 42ce2e13 Guido Trotter
        raise errors.OpPrereqError("Unknown backend parameter %s" % item)
535 42ce2e13 Guido Trotter
      if item in (constants.BE_MEMORY, constants.BE_VCPUS):
536 42ce2e13 Guido Trotter
        val = beparams[item]
537 42ce2e13 Guido Trotter
        if val != constants.VALUE_DEFAULT:
538 42ce2e13 Guido Trotter
          try:
539 42ce2e13 Guido Trotter
            val = int(val)
540 42ce2e13 Guido Trotter
          except ValueError, err:
541 42ce2e13 Guido Trotter
            raise errors.OpPrereqError("Invalid %s size: %s" % (item, str(err)))
542 42ce2e13 Guido Trotter
          beparams[item] = val
543 42ce2e13 Guido Trotter
      if item in (constants.BE_AUTO_BALANCE):
544 42ce2e13 Guido Trotter
        val = beparams[item]
545 90eb468c Guido Trotter
        if not isinstance(val, bool):
546 90eb468c Guido Trotter
          if val == constants.VALUE_TRUE:
547 90eb468c Guido Trotter
            beparams[item] = True
548 90eb468c Guido Trotter
          elif val == constants.VALUE_FALSE:
549 90eb468c Guido Trotter
            beparams[item] = False
550 90eb468c Guido Trotter
          else:
551 90eb468c Guido Trotter
            raise errors.OpPrereqError("Invalid %s value: %s" % (item, val))
552 42ce2e13 Guido Trotter
553 42ce2e13 Guido Trotter
554 a8083063 Iustin Pop
def NiceSort(name_list):
555 a8083063 Iustin Pop
  """Sort a list of strings based on digit and non-digit groupings.
556 a8083063 Iustin Pop

557 58885d79 Iustin Pop
  Given a list of names C{['a1', 'a10', 'a11', 'a2']} this function
558 58885d79 Iustin Pop
  will sort the list in the logical order C{['a1', 'a2', 'a10',
559 58885d79 Iustin Pop
  'a11']}.
560 a8083063 Iustin Pop

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

565 58885d79 Iustin Pop
  @type name_list: list
566 58885d79 Iustin Pop
  @param name_list: the names to be sorted
567 58885d79 Iustin Pop
  @rtype: list
568 58885d79 Iustin Pop
  @return: a copy of the name list sorted with our algorithm
569 a8083063 Iustin Pop

570 a8083063 Iustin Pop
  """
571 a8083063 Iustin Pop
  _SORTER_BASE = "(\D+|\d+)"
572 a8083063 Iustin Pop
  _SORTER_FULL = "^%s%s?%s?%s?%s?%s?%s?%s?.*$" % (_SORTER_BASE, _SORTER_BASE,
573 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE,
574 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE,
575 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE)
576 a8083063 Iustin Pop
  _SORTER_RE = re.compile(_SORTER_FULL)
577 a8083063 Iustin Pop
  _SORTER_NODIGIT = re.compile("^\D*$")
578 a8083063 Iustin Pop
  def _TryInt(val):
579 a8083063 Iustin Pop
    """Attempts to convert a variable to integer."""
580 a8083063 Iustin Pop
    if val is None or _SORTER_NODIGIT.match(val):
581 a8083063 Iustin Pop
      return val
582 a8083063 Iustin Pop
    rval = int(val)
583 a8083063 Iustin Pop
    return rval
584 a8083063 Iustin Pop
585 a8083063 Iustin Pop
  to_sort = [([_TryInt(grp) for grp in _SORTER_RE.match(name).groups()], name)
586 a8083063 Iustin Pop
             for name in name_list]
587 a8083063 Iustin Pop
  to_sort.sort()
588 a8083063 Iustin Pop
  return [tup[1] for tup in to_sort]
589 a8083063 Iustin Pop
590 a8083063 Iustin Pop
591 a8083063 Iustin Pop
def TryConvert(fn, val):
592 a8083063 Iustin Pop
  """Try to convert a value ignoring errors.
593 a8083063 Iustin Pop

594 58885d79 Iustin Pop
  This function tries to apply function I{fn} to I{val}. If no
595 58885d79 Iustin Pop
  C{ValueError} or C{TypeError} exceptions are raised, it will return
596 58885d79 Iustin Pop
  the result, else it will return the original value. Any other
597 58885d79 Iustin Pop
  exceptions are propagated to the caller.
598 58885d79 Iustin Pop

599 58885d79 Iustin Pop
  @type fn: callable
600 58885d79 Iustin Pop
  @param fn: function to apply to the value
601 58885d79 Iustin Pop
  @param val: the value to be converted
602 58885d79 Iustin Pop
  @return: The converted value if the conversion was successful,
603 58885d79 Iustin Pop
      otherwise the original value.
604 a8083063 Iustin Pop

605 a8083063 Iustin Pop
  """
606 a8083063 Iustin Pop
  try:
607 a8083063 Iustin Pop
    nv = fn(val)
608 a8083063 Iustin Pop
  except (ValueError, TypeError), err:
609 a8083063 Iustin Pop
    nv = val
610 a8083063 Iustin Pop
  return nv
611 a8083063 Iustin Pop
612 a8083063 Iustin Pop
613 a8083063 Iustin Pop
def IsValidIP(ip):
614 58885d79 Iustin Pop
  """Verifies the syntax of an IPv4 address.
615 a8083063 Iustin Pop

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

619 58885d79 Iustin Pop
  @type ip: str
620 58885d79 Iustin Pop
  @param ip: the address to be checked
621 58885d79 Iustin Pop
  @rtype: a regular expression match object
622 58885d79 Iustin Pop
  @return: a regular epression match object, or None if the
623 58885d79 Iustin Pop
      address is not valid
624 a8083063 Iustin Pop

625 a8083063 Iustin Pop
  """
626 a8083063 Iustin Pop
  unit = "(0|[1-9]\d{0,2})"
627 58885d79 Iustin Pop
  #TODO: convert and return only boolean
628 a8083063 Iustin Pop
  return re.match("^%s\.%s\.%s\.%s$" % (unit, unit, unit, unit), ip)
629 a8083063 Iustin Pop
630 a8083063 Iustin Pop
631 a8083063 Iustin Pop
def IsValidShellParam(word):
632 a8083063 Iustin Pop
  """Verifies is the given word is safe from the shell's p.o.v.
633 a8083063 Iustin Pop

634 a8083063 Iustin Pop
  This means that we can pass this to a command via the shell and be
635 a8083063 Iustin Pop
  sure that it doesn't alter the command line and is passed as such to
636 a8083063 Iustin Pop
  the actual command.
637 a8083063 Iustin Pop

638 a8083063 Iustin Pop
  Note that we are overly restrictive here, in order to be on the safe
639 a8083063 Iustin Pop
  side.
640 a8083063 Iustin Pop

641 58885d79 Iustin Pop
  @type word: str
642 58885d79 Iustin Pop
  @param word: the word to check
643 58885d79 Iustin Pop
  @rtype: boolean
644 58885d79 Iustin Pop
  @return: True if the word is 'safe'
645 58885d79 Iustin Pop

646 a8083063 Iustin Pop
  """
647 a8083063 Iustin Pop
  return bool(re.match("^[-a-zA-Z0-9._+/:%@]+$", word))
648 a8083063 Iustin Pop
649 a8083063 Iustin Pop
650 a8083063 Iustin Pop
def BuildShellCmd(template, *args):
651 a8083063 Iustin Pop
  """Build a safe shell command line from the given arguments.
652 a8083063 Iustin Pop

653 a8083063 Iustin Pop
  This function will check all arguments in the args list so that they
654 a8083063 Iustin Pop
  are valid shell parameters (i.e. they don't contain shell
655 a8083063 Iustin Pop
  metacharaters). If everything is ok, it will return the result of
656 a8083063 Iustin Pop
  template % args.
657 a8083063 Iustin Pop

658 58885d79 Iustin Pop
  @type template: str
659 58885d79 Iustin Pop
  @param template: the string holding the template for the
660 58885d79 Iustin Pop
      string formatting
661 58885d79 Iustin Pop
  @rtype: str
662 58885d79 Iustin Pop
  @return: the expanded command line
663 58885d79 Iustin Pop

664 a8083063 Iustin Pop
  """
665 a8083063 Iustin Pop
  for word in args:
666 a8083063 Iustin Pop
    if not IsValidShellParam(word):
667 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Shell argument '%s' contains"
668 3ecf6786 Iustin Pop
                                   " invalid characters" % word)
669 a8083063 Iustin Pop
  return template % args
670 a8083063 Iustin Pop
671 a8083063 Iustin Pop
672 9fbfbb7b Iustin Pop
def FormatUnit(value, units):
673 a8083063 Iustin Pop
  """Formats an incoming number of MiB with the appropriate unit.
674 a8083063 Iustin Pop

675 58885d79 Iustin Pop
  @type value: int
676 58885d79 Iustin Pop
  @param value: integer representing the value in MiB (1048576)
677 9fbfbb7b Iustin Pop
  @type units: char
678 9fbfbb7b Iustin Pop
  @param units: the type of formatting we should do:
679 9fbfbb7b Iustin Pop
      - 'h' for automatic scaling
680 9fbfbb7b Iustin Pop
      - 'm' for MiBs
681 9fbfbb7b Iustin Pop
      - 'g' for GiBs
682 9fbfbb7b Iustin Pop
      - 't' for TiBs
683 58885d79 Iustin Pop
  @rtype: str
684 58885d79 Iustin Pop
  @return: the formatted value (with suffix)
685 a8083063 Iustin Pop

686 a8083063 Iustin Pop
  """
687 9fbfbb7b Iustin Pop
  if units not in ('m', 'g', 't', 'h'):
688 9fbfbb7b Iustin Pop
    raise errors.ProgrammerError("Invalid unit specified '%s'" % str(units))
689 a8083063 Iustin Pop
690 9fbfbb7b Iustin Pop
  suffix = ''
691 9fbfbb7b Iustin Pop
692 9fbfbb7b Iustin Pop
  if units == 'm' or (units == 'h' and value < 1024):
693 9fbfbb7b Iustin Pop
    if units == 'h':
694 9fbfbb7b Iustin Pop
      suffix = 'M'
695 9fbfbb7b Iustin Pop
    return "%d%s" % (round(value, 0), suffix)
696 9fbfbb7b Iustin Pop
697 9fbfbb7b Iustin Pop
  elif units == 'g' or (units == 'h' and value < (1024 * 1024)):
698 9fbfbb7b Iustin Pop
    if units == 'h':
699 9fbfbb7b Iustin Pop
      suffix = 'G'
700 9fbfbb7b Iustin Pop
    return "%0.1f%s" % (round(float(value) / 1024, 1), suffix)
701 a8083063 Iustin Pop
702 a8083063 Iustin Pop
  else:
703 9fbfbb7b Iustin Pop
    if units == 'h':
704 9fbfbb7b Iustin Pop
      suffix = 'T'
705 9fbfbb7b Iustin Pop
    return "%0.1f%s" % (round(float(value) / 1024 / 1024, 1), suffix)
706 a8083063 Iustin Pop
707 a8083063 Iustin Pop
708 a8083063 Iustin Pop
def ParseUnit(input_string):
709 a8083063 Iustin Pop
  """Tries to extract number and scale from the given string.
710 a8083063 Iustin Pop

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

715 a8083063 Iustin Pop
  """
716 a8083063 Iustin Pop
  m = re.match('^([.\d]+)\s*([a-zA-Z]+)?$', input_string)
717 a8083063 Iustin Pop
  if not m:
718 3ecf6786 Iustin Pop
    raise errors.UnitParseError("Invalid format")
719 a8083063 Iustin Pop
720 a8083063 Iustin Pop
  value = float(m.groups()[0])
721 a8083063 Iustin Pop
722 a8083063 Iustin Pop
  unit = m.groups()[1]
723 a8083063 Iustin Pop
  if unit:
724 a8083063 Iustin Pop
    lcunit = unit.lower()
725 a8083063 Iustin Pop
  else:
726 a8083063 Iustin Pop
    lcunit = 'm'
727 a8083063 Iustin Pop
728 a8083063 Iustin Pop
  if lcunit in ('m', 'mb', 'mib'):
729 a8083063 Iustin Pop
    # Value already in MiB
730 a8083063 Iustin Pop
    pass
731 a8083063 Iustin Pop
732 a8083063 Iustin Pop
  elif lcunit in ('g', 'gb', 'gib'):
733 a8083063 Iustin Pop
    value *= 1024
734 a8083063 Iustin Pop
735 a8083063 Iustin Pop
  elif lcunit in ('t', 'tb', 'tib'):
736 a8083063 Iustin Pop
    value *= 1024 * 1024
737 a8083063 Iustin Pop
738 a8083063 Iustin Pop
  else:
739 3ecf6786 Iustin Pop
    raise errors.UnitParseError("Unknown unit: %s" % unit)
740 a8083063 Iustin Pop
741 a8083063 Iustin Pop
  # Make sure we round up
742 a8083063 Iustin Pop
  if int(value) < value:
743 a8083063 Iustin Pop
    value += 1
744 a8083063 Iustin Pop
745 a8083063 Iustin Pop
  # Round up to the next multiple of 4
746 a8083063 Iustin Pop
  value = int(value)
747 a8083063 Iustin Pop
  if value % 4:
748 a8083063 Iustin Pop
    value += 4 - value % 4
749 a8083063 Iustin Pop
750 a8083063 Iustin Pop
  return value
751 a8083063 Iustin Pop
752 a8083063 Iustin Pop
753 a8083063 Iustin Pop
def AddAuthorizedKey(file_name, key):
754 a8083063 Iustin Pop
  """Adds an SSH public key to an authorized_keys file.
755 a8083063 Iustin Pop

756 58885d79 Iustin Pop
  @type file_name: str
757 58885d79 Iustin Pop
  @param file_name: path to authorized_keys file
758 58885d79 Iustin Pop
  @type key: str
759 58885d79 Iustin Pop
  @param key: string containing key
760 58885d79 Iustin Pop

761 a8083063 Iustin Pop
  """
762 a8083063 Iustin Pop
  key_fields = key.split()
763 a8083063 Iustin Pop
764 a8083063 Iustin Pop
  f = open(file_name, 'a+')
765 a8083063 Iustin Pop
  try:
766 a8083063 Iustin Pop
    nl = True
767 a8083063 Iustin Pop
    for line in f:
768 a8083063 Iustin Pop
      # Ignore whitespace changes
769 a8083063 Iustin Pop
      if line.split() == key_fields:
770 a8083063 Iustin Pop
        break
771 a8083063 Iustin Pop
      nl = line.endswith('\n')
772 a8083063 Iustin Pop
    else:
773 a8083063 Iustin Pop
      if not nl:
774 a8083063 Iustin Pop
        f.write("\n")
775 a8083063 Iustin Pop
      f.write(key.rstrip('\r\n'))
776 a8083063 Iustin Pop
      f.write("\n")
777 a8083063 Iustin Pop
      f.flush()
778 a8083063 Iustin Pop
  finally:
779 a8083063 Iustin Pop
    f.close()
780 a8083063 Iustin Pop
781 a8083063 Iustin Pop
782 a8083063 Iustin Pop
def RemoveAuthorizedKey(file_name, key):
783 a8083063 Iustin Pop
  """Removes an SSH public key from an authorized_keys file.
784 a8083063 Iustin Pop

785 58885d79 Iustin Pop
  @type file_name: str
786 58885d79 Iustin Pop
  @param file_name: path to authorized_keys file
787 58885d79 Iustin Pop
  @type key: str
788 58885d79 Iustin Pop
  @param key: string containing key
789 58885d79 Iustin Pop

790 a8083063 Iustin Pop
  """
791 a8083063 Iustin Pop
  key_fields = key.split()
792 a8083063 Iustin Pop
793 a8083063 Iustin Pop
  fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name))
794 a8083063 Iustin Pop
  try:
795 59f82e3f Michael Hanselmann
    out = os.fdopen(fd, 'w')
796 a8083063 Iustin Pop
    try:
797 59f82e3f Michael Hanselmann
      f = open(file_name, 'r')
798 59f82e3f Michael Hanselmann
      try:
799 59f82e3f Michael Hanselmann
        for line in f:
800 59f82e3f Michael Hanselmann
          # Ignore whitespace changes while comparing lines
801 59f82e3f Michael Hanselmann
          if line.split() != key_fields:
802 59f82e3f Michael Hanselmann
            out.write(line)
803 899d2a81 Michael Hanselmann
804 899d2a81 Michael Hanselmann
        out.flush()
805 899d2a81 Michael Hanselmann
        os.rename(tmpname, file_name)
806 899d2a81 Michael Hanselmann
      finally:
807 899d2a81 Michael Hanselmann
        f.close()
808 899d2a81 Michael Hanselmann
    finally:
809 899d2a81 Michael Hanselmann
      out.close()
810 899d2a81 Michael Hanselmann
  except:
811 899d2a81 Michael Hanselmann
    RemoveFile(tmpname)
812 899d2a81 Michael Hanselmann
    raise
813 899d2a81 Michael Hanselmann
814 899d2a81 Michael Hanselmann
815 9440aeab Michael Hanselmann
def SetEtcHostsEntry(file_name, ip, hostname, aliases):
816 9440aeab Michael Hanselmann
  """Sets the name of an IP address and hostname in /etc/hosts.
817 899d2a81 Michael Hanselmann

818 58885d79 Iustin Pop
  @type file_name: str
819 58885d79 Iustin Pop
  @param file_name: path to the file to modify (usually C{/etc/hosts})
820 58885d79 Iustin Pop
  @type ip: str
821 58885d79 Iustin Pop
  @param ip: the IP address
822 58885d79 Iustin Pop
  @type hostname: str
823 58885d79 Iustin Pop
  @param hostname: the hostname to be added
824 58885d79 Iustin Pop
  @type aliases: list
825 58885d79 Iustin Pop
  @param aliases: the list of aliases to add for the hostname
826 58885d79 Iustin Pop

827 899d2a81 Michael Hanselmann
  """
828 7fbb1f65 Michael Hanselmann
  # Ensure aliases are unique
829 7fbb1f65 Michael Hanselmann
  aliases = UniqueSequence([hostname] + aliases)[1:]
830 7fbb1f65 Michael Hanselmann
831 9440aeab Michael Hanselmann
  fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name))
832 899d2a81 Michael Hanselmann
  try:
833 9440aeab Michael Hanselmann
    out = os.fdopen(fd, 'w')
834 9440aeab Michael Hanselmann
    try:
835 9440aeab Michael Hanselmann
      f = open(file_name, 'r')
836 9440aeab Michael Hanselmann
      try:
837 9440aeab Michael Hanselmann
        written = False
838 9440aeab Michael Hanselmann
        for line in f:
839 9440aeab Michael Hanselmann
          fields = line.split()
840 7e3dbb94 Iustin Pop
          if fields and not fields[0].startswith('#') and ip == fields[0]:
841 9440aeab Michael Hanselmann
            continue
842 9440aeab Michael Hanselmann
          out.write(line)
843 9440aeab Michael Hanselmann
844 7e3dbb94 Iustin Pop
        out.write("%s\t%s" % (ip, hostname))
845 9440aeab Michael Hanselmann
        if aliases:
846 9440aeab Michael Hanselmann
          out.write(" %s" % ' '.join(aliases))
847 9440aeab Michael Hanselmann
        out.write('\n')
848 9440aeab Michael Hanselmann
849 9440aeab Michael Hanselmann
        out.flush()
850 2e3e75b7 Michael Hanselmann
        os.fsync(out)
851 9440aeab Michael Hanselmann
        os.rename(tmpname, file_name)
852 9440aeab Michael Hanselmann
      finally:
853 9440aeab Michael Hanselmann
        f.close()
854 9440aeab Michael Hanselmann
    finally:
855 9440aeab Michael Hanselmann
      out.close()
856 9440aeab Michael Hanselmann
  except:
857 9440aeab Michael Hanselmann
    RemoveFile(tmpname)
858 9440aeab Michael Hanselmann
    raise
859 899d2a81 Michael Hanselmann
860 899d2a81 Michael Hanselmann
861 d9c02ca6 Michael Hanselmann
def AddHostToEtcHosts(hostname):
862 d9c02ca6 Michael Hanselmann
  """Wrapper around SetEtcHostsEntry.
863 d9c02ca6 Michael Hanselmann

864 58885d79 Iustin Pop
  @type hostname: str
865 58885d79 Iustin Pop
  @param hostname: a hostname that will be resolved and added to
866 58885d79 Iustin Pop
      L{constants.ETC_HOSTS}
867 58885d79 Iustin Pop

868 d9c02ca6 Michael Hanselmann
  """
869 d9c02ca6 Michael Hanselmann
  hi = HostInfo(name=hostname)
870 d9c02ca6 Michael Hanselmann
  SetEtcHostsEntry(constants.ETC_HOSTS, hi.ip, hi.name, [hi.ShortName()])
871 d9c02ca6 Michael Hanselmann
872 d9c02ca6 Michael Hanselmann
873 899d2a81 Michael Hanselmann
def RemoveEtcHostsEntry(file_name, hostname):
874 3e1cdf9f Michael Hanselmann
  """Removes a hostname from /etc/hosts.
875 899d2a81 Michael Hanselmann

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

878 58885d79 Iustin Pop
  @type file_name: str
879 58885d79 Iustin Pop
  @param file_name: path to the file to modify (usually C{/etc/hosts})
880 58885d79 Iustin Pop
  @type hostname: str
881 58885d79 Iustin Pop
  @param hostname: the hostname to be removed
882 58885d79 Iustin Pop

883 899d2a81 Michael Hanselmann
  """
884 899d2a81 Michael Hanselmann
  fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name))
885 899d2a81 Michael Hanselmann
  try:
886 899d2a81 Michael Hanselmann
    out = os.fdopen(fd, 'w')
887 899d2a81 Michael Hanselmann
    try:
888 899d2a81 Michael Hanselmann
      f = open(file_name, 'r')
889 899d2a81 Michael Hanselmann
      try:
890 899d2a81 Michael Hanselmann
        for line in f:
891 899d2a81 Michael Hanselmann
          fields = line.split()
892 899d2a81 Michael Hanselmann
          if len(fields) > 1 and not fields[0].startswith('#'):
893 899d2a81 Michael Hanselmann
            names = fields[1:]
894 899d2a81 Michael Hanselmann
            if hostname in names:
895 899d2a81 Michael Hanselmann
              while hostname in names:
896 899d2a81 Michael Hanselmann
                names.remove(hostname)
897 899d2a81 Michael Hanselmann
              if names:
898 9440aeab Michael Hanselmann
                out.write("%s %s\n" % (fields[0], ' '.join(names)))
899 899d2a81 Michael Hanselmann
              continue
900 899d2a81 Michael Hanselmann
901 899d2a81 Michael Hanselmann
          out.write(line)
902 59f82e3f Michael Hanselmann
903 59f82e3f Michael Hanselmann
        out.flush()
904 2e3e75b7 Michael Hanselmann
        os.fsync(out)
905 59f82e3f Michael Hanselmann
        os.rename(tmpname, file_name)
906 59f82e3f Michael Hanselmann
      finally:
907 59f82e3f Michael Hanselmann
        f.close()
908 a8083063 Iustin Pop
    finally:
909 59f82e3f Michael Hanselmann
      out.close()
910 59f82e3f Michael Hanselmann
  except:
911 59f82e3f Michael Hanselmann
    RemoveFile(tmpname)
912 59f82e3f Michael Hanselmann
    raise
913 a8083063 Iustin Pop
914 a8083063 Iustin Pop
915 d9c02ca6 Michael Hanselmann
def RemoveHostFromEtcHosts(hostname):
916 d9c02ca6 Michael Hanselmann
  """Wrapper around RemoveEtcHostsEntry.
917 d9c02ca6 Michael Hanselmann

918 58885d79 Iustin Pop
  @type hostname: str
919 58885d79 Iustin Pop
  @param hostname: hostname that will be resolved and its
920 58885d79 Iustin Pop
      full and shot name will be removed from
921 58885d79 Iustin Pop
      L{constants.ETC_HOSTS}
922 58885d79 Iustin Pop

923 d9c02ca6 Michael Hanselmann
  """
924 d9c02ca6 Michael Hanselmann
  hi = HostInfo(name=hostname)
925 d9c02ca6 Michael Hanselmann
  RemoveEtcHostsEntry(constants.ETC_HOSTS, hi.name)
926 d9c02ca6 Michael Hanselmann
  RemoveEtcHostsEntry(constants.ETC_HOSTS, hi.ShortName())
927 d9c02ca6 Michael Hanselmann
928 d9c02ca6 Michael Hanselmann
929 a8083063 Iustin Pop
def CreateBackup(file_name):
930 a8083063 Iustin Pop
  """Creates a backup of a file.
931 a8083063 Iustin Pop

932 58885d79 Iustin Pop
  @type file_name: str
933 58885d79 Iustin Pop
  @param file_name: file to be backed up
934 58885d79 Iustin Pop
  @rtype: str
935 58885d79 Iustin Pop
  @return: the path to the newly created backup
936 58885d79 Iustin Pop
  @raise errors.ProgrammerError: for invalid file names
937 a8083063 Iustin Pop

938 a8083063 Iustin Pop
  """
939 a8083063 Iustin Pop
  if not os.path.isfile(file_name):
940 3ecf6786 Iustin Pop
    raise errors.ProgrammerError("Can't make a backup of a non-file '%s'" %
941 3ecf6786 Iustin Pop
                                file_name)
942 a8083063 Iustin Pop
943 081b1e69 Michael Hanselmann
  prefix = '%s.backup-%d.' % (os.path.basename(file_name), int(time.time()))
944 65fe4693 Iustin Pop
  dir_name = os.path.dirname(file_name)
945 081b1e69 Michael Hanselmann
946 081b1e69 Michael Hanselmann
  fsrc = open(file_name, 'rb')
947 081b1e69 Michael Hanselmann
  try:
948 65fe4693 Iustin Pop
    (fd, backup_name) = tempfile.mkstemp(prefix=prefix, dir=dir_name)
949 081b1e69 Michael Hanselmann
    fdst = os.fdopen(fd, 'wb')
950 081b1e69 Michael Hanselmann
    try:
951 081b1e69 Michael Hanselmann
      shutil.copyfileobj(fsrc, fdst)
952 081b1e69 Michael Hanselmann
    finally:
953 081b1e69 Michael Hanselmann
      fdst.close()
954 081b1e69 Michael Hanselmann
  finally:
955 081b1e69 Michael Hanselmann
    fsrc.close()
956 081b1e69 Michael Hanselmann
957 a8083063 Iustin Pop
  return backup_name
958 a8083063 Iustin Pop
959 a8083063 Iustin Pop
960 a8083063 Iustin Pop
def ShellQuote(value):
961 a8083063 Iustin Pop
  """Quotes shell argument according to POSIX.
962 3ecf6786 Iustin Pop

963 58885d79 Iustin Pop
  @type value: str
964 58885d79 Iustin Pop
  @param value: the argument to be quoted
965 58885d79 Iustin Pop
  @rtype: str
966 58885d79 Iustin Pop
  @return: the quoted value
967 58885d79 Iustin Pop

968 a8083063 Iustin Pop
  """
969 a8083063 Iustin Pop
  if _re_shell_unquoted.match(value):
970 a8083063 Iustin Pop
    return value
971 a8083063 Iustin Pop
  else:
972 a8083063 Iustin Pop
    return "'%s'" % value.replace("'", "'\\''")
973 a8083063 Iustin Pop
974 a8083063 Iustin Pop
975 a8083063 Iustin Pop
def ShellQuoteArgs(args):
976 58885d79 Iustin Pop
  """Quotes a list of shell arguments.
977 58885d79 Iustin Pop

978 58885d79 Iustin Pop
  @type args: list
979 58885d79 Iustin Pop
  @param args: list of arguments to be quoted
980 58885d79 Iustin Pop
  @rtype: str
981 58885d79 Iustin Pop
  @return: the quoted arguments concatenaned with spaces
982 a8083063 Iustin Pop

983 a8083063 Iustin Pop
  """
984 a8083063 Iustin Pop
  return ' '.join([ShellQuote(i) for i in args])
985 88d14415 Michael Hanselmann
986 88d14415 Michael Hanselmann
987 b15d625f Iustin Pop
def TcpPing(target, port, timeout=10, live_port_needed=False, source=None):
988 2c30e9d7 Alexander Schreiber
  """Simple ping implementation using TCP connect(2).
989 2c30e9d7 Alexander Schreiber

990 58885d79 Iustin Pop
  Check if the given IP is reachable by doing attempting a TCP connect
991 58885d79 Iustin Pop
  to it.
992 58885d79 Iustin Pop

993 58885d79 Iustin Pop
  @type target: str
994 58885d79 Iustin Pop
  @param target: the IP or hostname to ping
995 58885d79 Iustin Pop
  @type port: int
996 58885d79 Iustin Pop
  @param port: the port to connect to
997 58885d79 Iustin Pop
  @type timeout: int
998 58885d79 Iustin Pop
  @param timeout: the timeout on the connection attemp
999 58885d79 Iustin Pop
  @type live_port_needed: boolean
1000 58885d79 Iustin Pop
  @param live_port_needed: whether a closed port will cause the
1001 58885d79 Iustin Pop
      function to return failure, as if there was a timeout
1002 58885d79 Iustin Pop
  @type source: str or None
1003 58885d79 Iustin Pop
  @param source: if specified, will cause the connect to be made
1004 58885d79 Iustin Pop
      from this specific source address; failures to bind other
1005 58885d79 Iustin Pop
      than C{EADDRNOTAVAIL} will be ignored
1006 2c30e9d7 Alexander Schreiber

1007 2c30e9d7 Alexander Schreiber
  """
1008 2c30e9d7 Alexander Schreiber
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1009 2c30e9d7 Alexander Schreiber
1010 2c30e9d7 Alexander Schreiber
  sucess = False
1011 2c30e9d7 Alexander Schreiber
1012 b15d625f Iustin Pop
  if source is not None:
1013 b15d625f Iustin Pop
    try:
1014 b15d625f Iustin Pop
      sock.bind((source, 0))
1015 b15d625f Iustin Pop
    except socket.error, (errcode, errstring):
1016 b15d625f Iustin Pop
      if errcode == errno.EADDRNOTAVAIL:
1017 b15d625f Iustin Pop
        success = False
1018 2c30e9d7 Alexander Schreiber
1019 2c30e9d7 Alexander Schreiber
  sock.settimeout(timeout)
1020 2c30e9d7 Alexander Schreiber
1021 2c30e9d7 Alexander Schreiber
  try:
1022 2c30e9d7 Alexander Schreiber
    sock.connect((target, port))
1023 2c30e9d7 Alexander Schreiber
    sock.close()
1024 2c30e9d7 Alexander Schreiber
    success = True
1025 2c30e9d7 Alexander Schreiber
  except socket.timeout:
1026 2c30e9d7 Alexander Schreiber
    success = False
1027 2c30e9d7 Alexander Schreiber
  except socket.error, (errcode, errstring):
1028 4ca1b175 Alexander Schreiber
    success = (not live_port_needed) and (errcode == errno.ECONNREFUSED)
1029 2c30e9d7 Alexander Schreiber
1030 2c30e9d7 Alexander Schreiber
  return success
1031 eedbda4b Michael Hanselmann
1032 eedbda4b Michael Hanselmann
1033 caad16e2 Iustin Pop
def OwnIpAddress(address):
1034 caad16e2 Iustin Pop
  """Check if the current host has the the given IP address.
1035 caad16e2 Iustin Pop

1036 58885d79 Iustin Pop
  Currently this is done by TCP-pinging the address from the loopback
1037 caad16e2 Iustin Pop
  address.
1038 caad16e2 Iustin Pop

1039 caad16e2 Iustin Pop
  @type address: string
1040 caad16e2 Iustin Pop
  @param address: the addres to check
1041 caad16e2 Iustin Pop
  @rtype: bool
1042 58885d79 Iustin Pop
  @return: True if we own the address
1043 caad16e2 Iustin Pop

1044 caad16e2 Iustin Pop
  """
1045 caad16e2 Iustin Pop
  return TcpPing(address, constants.DEFAULT_NODED_PORT,
1046 caad16e2 Iustin Pop
                 source=constants.LOCALHOST_IP_ADDRESS)
1047 caad16e2 Iustin Pop
1048 caad16e2 Iustin Pop
1049 eedbda4b Michael Hanselmann
def ListVisibleFiles(path):
1050 58885d79 Iustin Pop
  """Returns a list of visible files in a directory.
1051 58885d79 Iustin Pop

1052 58885d79 Iustin Pop
  @type path: str
1053 58885d79 Iustin Pop
  @param path: the directory to enumerate
1054 58885d79 Iustin Pop
  @rtype: list
1055 58885d79 Iustin Pop
  @return: the list of all files not starting with a dot
1056 eedbda4b Michael Hanselmann

1057 eedbda4b Michael Hanselmann
  """
1058 f3299a07 Michael Hanselmann
  files = [i for i in os.listdir(path) if not i.startswith(".")]
1059 f3299a07 Michael Hanselmann
  files.sort()
1060 f3299a07 Michael Hanselmann
  return files
1061 2f8b60b3 Iustin Pop
1062 2f8b60b3 Iustin Pop
1063 257f4c0a Iustin Pop
def GetHomeDir(user, default=None):
1064 257f4c0a Iustin Pop
  """Try to get the homedir of the given user.
1065 257f4c0a Iustin Pop

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

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

1087 58885d79 Iustin Pop
  @note: This is a Linux-specific method as it uses the /proc
1088 58885d79 Iustin Pop
      filesystem.
1089 58885d79 Iustin Pop
  @rtype: str
1090 58885d79 Iustin Pop

1091 59072e7e Michael Hanselmann
  """
1092 59072e7e Michael Hanselmann
  f = open("/proc/sys/kernel/random/uuid", "r")
1093 59072e7e Michael Hanselmann
  try:
1094 59072e7e Michael Hanselmann
    return f.read(128).rstrip("\n")
1095 59072e7e Michael Hanselmann
  finally:
1096 59072e7e Michael Hanselmann
    f.close()
1097 087b34fe Iustin Pop
1098 087b34fe Iustin Pop
1099 33081d90 Iustin Pop
def GenerateSecret():
1100 33081d90 Iustin Pop
  """Generates a random secret.
1101 33081d90 Iustin Pop

1102 33081d90 Iustin Pop
  This will generate a pseudo-random secret, and return its sha digest
1103 33081d90 Iustin Pop
  (so that it can be used where an ASCII string is needed).
1104 33081d90 Iustin Pop

1105 58885d79 Iustin Pop
  @rtype: str
1106 58885d79 Iustin Pop
  @return: a sha1 hexdigest of a block of 64 random bytes
1107 58885d79 Iustin Pop

1108 33081d90 Iustin Pop
  """
1109 33081d90 Iustin Pop
  return sha.new(os.urandom(64)).hexdigest()
1110 33081d90 Iustin Pop
1111 33081d90 Iustin Pop
1112 ca0aa6d0 Michael Hanselmann
def ReadFile(file_name, size=None):
1113 ca0aa6d0 Michael Hanselmann
  """Reads a file.
1114 ca0aa6d0 Michael Hanselmann

1115 ca0aa6d0 Michael Hanselmann
  @type size: None or int
1116 ca0aa6d0 Michael Hanselmann
  @param size: Read at most size bytes
1117 58885d79 Iustin Pop
  @rtype: str
1118 58885d79 Iustin Pop
  @return: the (possibly partial) conent of the file
1119 ca0aa6d0 Michael Hanselmann

1120 ca0aa6d0 Michael Hanselmann
  """
1121 ca0aa6d0 Michael Hanselmann
  f = open(file_name, "r")
1122 ca0aa6d0 Michael Hanselmann
  try:
1123 ca0aa6d0 Michael Hanselmann
    if size is None:
1124 ca0aa6d0 Michael Hanselmann
      return f.read()
1125 ca0aa6d0 Michael Hanselmann
    else:
1126 ca0aa6d0 Michael Hanselmann
      return f.read(size)
1127 ca0aa6d0 Michael Hanselmann
  finally:
1128 ca0aa6d0 Michael Hanselmann
    f.close()
1129 ca0aa6d0 Michael Hanselmann
1130 ca0aa6d0 Michael Hanselmann
1131 087b34fe Iustin Pop
def WriteFile(file_name, fn=None, data=None,
1132 087b34fe Iustin Pop
              mode=None, uid=-1, gid=-1,
1133 71714516 Michael Hanselmann
              atime=None, mtime=None, close=True,
1134 04a8d789 Michael Hanselmann
              dry_run=False, backup=False,
1135 71714516 Michael Hanselmann
              prewrite=None, postwrite=None):
1136 087b34fe Iustin Pop
  """(Over)write a file atomically.
1137 087b34fe Iustin Pop

1138 087b34fe Iustin Pop
  The file_name and either fn (a function taking one argument, the
1139 087b34fe Iustin Pop
  file descriptor, and which should write the data to it) or data (the
1140 087b34fe Iustin Pop
  contents of the file) must be passed. The other arguments are
1141 087b34fe Iustin Pop
  optional and allow setting the file mode, owner and group, and the
1142 087b34fe Iustin Pop
  mtime/atime of the file.
1143 087b34fe Iustin Pop

1144 087b34fe Iustin Pop
  If the function doesn't raise an exception, it has succeeded and the
1145 087b34fe Iustin Pop
  target file has the new contents. If the file has raised an
1146 087b34fe Iustin Pop
  exception, an existing target file should be unmodified and the
1147 087b34fe Iustin Pop
  temporary file should be removed.
1148 087b34fe Iustin Pop

1149 58885d79 Iustin Pop
  @type file_name: str
1150 58885d79 Iustin Pop
  @param file_name: the target filename
1151 58885d79 Iustin Pop
  @type fn: callable
1152 58885d79 Iustin Pop
  @param fn: content writing function, called with
1153 58885d79 Iustin Pop
      file descriptor as parameter
1154 58885d79 Iustin Pop
  @type data: sr
1155 58885d79 Iustin Pop
  @param data: contents of the file
1156 58885d79 Iustin Pop
  @type mode: int
1157 58885d79 Iustin Pop
  @param mode: file mode
1158 58885d79 Iustin Pop
  @type uid: int
1159 58885d79 Iustin Pop
  @param uid: the owner of the file
1160 58885d79 Iustin Pop
  @type gid: int
1161 58885d79 Iustin Pop
  @param gid: the group of the file
1162 58885d79 Iustin Pop
  @type atime: int
1163 58885d79 Iustin Pop
  @param atime: a custom access time to be set on the file
1164 58885d79 Iustin Pop
  @type mtime: int
1165 58885d79 Iustin Pop
  @param mtime: a custom modification time to be set on the file
1166 58885d79 Iustin Pop
  @type close: boolean
1167 58885d79 Iustin Pop
  @param close: whether to close file after writing it
1168 58885d79 Iustin Pop
  @type prewrite: callable
1169 58885d79 Iustin Pop
  @param prewrite: function to be called before writing content
1170 58885d79 Iustin Pop
  @type postwrite: callable
1171 58885d79 Iustin Pop
  @param postwrite: function to be called after writing content
1172 58885d79 Iustin Pop

1173 58885d79 Iustin Pop
  @rtype: None or int
1174 58885d79 Iustin Pop
  @return: None if the 'close' parameter evaluates to True,
1175 58885d79 Iustin Pop
      otherwise the file descriptor
1176 58885d79 Iustin Pop

1177 58885d79 Iustin Pop
  @raise errors.ProgrammerError: if an of the arguments are not valid
1178 71714516 Michael Hanselmann

1179 087b34fe Iustin Pop
  """
1180 04a8d789 Michael Hanselmann
  if not os.path.isabs(file_name):
1181 087b34fe Iustin Pop
    raise errors.ProgrammerError("Path passed to WriteFile is not"
1182 087b34fe Iustin Pop
                                 " absolute: '%s'" % file_name)
1183 087b34fe Iustin Pop
1184 087b34fe Iustin Pop
  if [fn, data].count(None) != 1:
1185 087b34fe Iustin Pop
    raise errors.ProgrammerError("fn or data required")
1186 087b34fe Iustin Pop
1187 087b34fe Iustin Pop
  if [atime, mtime].count(None) == 1:
1188 087b34fe Iustin Pop
    raise errors.ProgrammerError("Both atime and mtime must be either"
1189 087b34fe Iustin Pop
                                 " set or None")
1190 087b34fe Iustin Pop
1191 70f4497c Michael Hanselmann
  if backup and not dry_run and os.path.isfile(file_name):
1192 70f4497c Michael Hanselmann
    CreateBackup(file_name)
1193 087b34fe Iustin Pop
1194 087b34fe Iustin Pop
  dir_name, base_name = os.path.split(file_name)
1195 087b34fe Iustin Pop
  fd, new_name = tempfile.mkstemp('.new', base_name, dir_name)
1196 087b34fe Iustin Pop
  # here we need to make sure we remove the temp file, if any error
1197 087b34fe Iustin Pop
  # leaves it in place
1198 087b34fe Iustin Pop
  try:
1199 087b34fe Iustin Pop
    if uid != -1 or gid != -1:
1200 087b34fe Iustin Pop
      os.chown(new_name, uid, gid)
1201 087b34fe Iustin Pop
    if mode:
1202 087b34fe Iustin Pop
      os.chmod(new_name, mode)
1203 71714516 Michael Hanselmann
    if callable(prewrite):
1204 71714516 Michael Hanselmann
      prewrite(fd)
1205 087b34fe Iustin Pop
    if data is not None:
1206 087b34fe Iustin Pop
      os.write(fd, data)
1207 087b34fe Iustin Pop
    else:
1208 087b34fe Iustin Pop
      fn(fd)
1209 71714516 Michael Hanselmann
    if callable(postwrite):
1210 71714516 Michael Hanselmann
      postwrite(fd)
1211 087b34fe Iustin Pop
    os.fsync(fd)
1212 087b34fe Iustin Pop
    if atime is not None and mtime is not None:
1213 087b34fe Iustin Pop
      os.utime(new_name, (atime, mtime))
1214 70f4497c Michael Hanselmann
    if not dry_run:
1215 70f4497c Michael Hanselmann
      os.rename(new_name, file_name)
1216 087b34fe Iustin Pop
  finally:
1217 71714516 Michael Hanselmann
    if close:
1218 71714516 Michael Hanselmann
      os.close(fd)
1219 71714516 Michael Hanselmann
      result = None
1220 71714516 Michael Hanselmann
    else:
1221 71714516 Michael Hanselmann
      result = fd
1222 087b34fe Iustin Pop
    RemoveFile(new_name)
1223 78feb6fb Guido Trotter
1224 71714516 Michael Hanselmann
  return result
1225 71714516 Michael Hanselmann
1226 78feb6fb Guido Trotter
1227 7b4126b7 Iustin Pop
def FirstFree(seq, base=0):
1228 7b4126b7 Iustin Pop
  """Returns the first non-existing integer from seq.
1229 7b4126b7 Iustin Pop

1230 7b4126b7 Iustin Pop
  The seq argument should be a sorted list of positive integers. The
1231 7b4126b7 Iustin Pop
  first time the index of an element is smaller than the element
1232 7b4126b7 Iustin Pop
  value, the index will be returned.
1233 7b4126b7 Iustin Pop

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

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

1239 58885d79 Iustin Pop
  @type seq: sequence
1240 58885d79 Iustin Pop
  @param seq: the sequence to be analyzed.
1241 58885d79 Iustin Pop
  @type base: int
1242 58885d79 Iustin Pop
  @param base: use this value as the base index of the sequence
1243 58885d79 Iustin Pop
  @rtype: int
1244 58885d79 Iustin Pop
  @return: the first non-used index in the sequence
1245 7b4126b7 Iustin Pop

1246 7b4126b7 Iustin Pop
  """
1247 7b4126b7 Iustin Pop
  for idx, elem in enumerate(seq):
1248 7b4126b7 Iustin Pop
    assert elem >= base, "Passed element is higher than base offset"
1249 7b4126b7 Iustin Pop
    if elem > idx + base:
1250 7b4126b7 Iustin Pop
      # idx is not used
1251 7b4126b7 Iustin Pop
      return idx + base
1252 7b4126b7 Iustin Pop
  return None
1253 7b4126b7 Iustin Pop
1254 7b4126b7 Iustin Pop
1255 78feb6fb Guido Trotter
def all(seq, pred=bool):
1256 78feb6fb Guido Trotter
  "Returns True if pred(x) is True for every element in the iterable"
1257 78feb6fb Guido Trotter
  for elem in itertools.ifilterfalse(pred, seq):
1258 78feb6fb Guido Trotter
    return False
1259 78feb6fb Guido Trotter
  return True
1260 78feb6fb Guido Trotter
1261 78feb6fb Guido Trotter
1262 78feb6fb Guido Trotter
def any(seq, pred=bool):
1263 78feb6fb Guido Trotter
  "Returns True if pred(x) is True for at least one element in the iterable"
1264 78feb6fb Guido Trotter
  for elem in itertools.ifilter(pred, seq):
1265 78feb6fb Guido Trotter
    return True
1266 78feb6fb Guido Trotter
  return False
1267 f7414041 Michael Hanselmann
1268 f7414041 Michael Hanselmann
1269 f7414041 Michael Hanselmann
def UniqueSequence(seq):
1270 f7414041 Michael Hanselmann
  """Returns a list with unique elements.
1271 f7414041 Michael Hanselmann

1272 f7414041 Michael Hanselmann
  Element order is preserved.
1273 58885d79 Iustin Pop

1274 58885d79 Iustin Pop
  @type seq: sequence
1275 58885d79 Iustin Pop
  @param seq: the sequence with the source elementes
1276 58885d79 Iustin Pop
  @rtype: list
1277 58885d79 Iustin Pop
  @return: list of unique elements from seq
1278 58885d79 Iustin Pop

1279 f7414041 Michael Hanselmann
  """
1280 f7414041 Michael Hanselmann
  seen = set()
1281 f7414041 Michael Hanselmann
  return [i for i in seq if i not in seen and not seen.add(i)]
1282 1862d460 Alexander Schreiber
1283 1862d460 Alexander Schreiber
1284 1862d460 Alexander Schreiber
def IsValidMac(mac):
1285 1862d460 Alexander Schreiber
  """Predicate to check if a MAC address is valid.
1286 1862d460 Alexander Schreiber

1287 1862d460 Alexander Schreiber
  Checks wether the supplied MAC address is formally correct, only
1288 1862d460 Alexander Schreiber
  accepts colon separated format.
1289 58885d79 Iustin Pop

1290 58885d79 Iustin Pop
  @type mac: str
1291 58885d79 Iustin Pop
  @param mac: the MAC to be validated
1292 58885d79 Iustin Pop
  @rtype: boolean
1293 58885d79 Iustin Pop
  @return: True is the MAC seems valid
1294 58885d79 Iustin Pop

1295 1862d460 Alexander Schreiber
  """
1296 1862d460 Alexander Schreiber
  mac_check = re.compile("^([0-9a-f]{2}(:|$)){6}$")
1297 1862d460 Alexander Schreiber
  return mac_check.match(mac) is not None
1298 06009e27 Iustin Pop
1299 06009e27 Iustin Pop
1300 06009e27 Iustin Pop
def TestDelay(duration):
1301 06009e27 Iustin Pop
  """Sleep for a fixed amount of time.
1302 06009e27 Iustin Pop

1303 58885d79 Iustin Pop
  @type duration: float
1304 58885d79 Iustin Pop
  @param duration: the sleep duration
1305 58885d79 Iustin Pop
  @rtype: boolean
1306 58885d79 Iustin Pop
  @return: False for negative value, True otherwise
1307 58885d79 Iustin Pop

1308 06009e27 Iustin Pop
  """
1309 06009e27 Iustin Pop
  if duration < 0:
1310 06009e27 Iustin Pop
    return False
1311 06009e27 Iustin Pop
  time.sleep(duration)
1312 06009e27 Iustin Pop
  return True
1313 8f765069 Iustin Pop
1314 8f765069 Iustin Pop
1315 8ff612c2 Iustin Pop
def Daemonize(logfile, noclose_fds=None):
1316 8f765069 Iustin Pop
  """Daemonize the current process.
1317 8f765069 Iustin Pop

1318 8f765069 Iustin Pop
  This detaches the current process from the controlling terminal and
1319 8f765069 Iustin Pop
  runs it in the background as a daemon.
1320 8f765069 Iustin Pop

1321 58885d79 Iustin Pop
  @type logfile: str
1322 58885d79 Iustin Pop
  @param logfile: the logfile to which we should redirect stdout/stderr
1323 58885d79 Iustin Pop
  @type noclose_fds: list or None
1324 58885d79 Iustin Pop
  @param noclose_fds: if given, it denotes a list of file descriptor
1325 58885d79 Iustin Pop
      that should not be closed
1326 58885d79 Iustin Pop
  @rtype: int
1327 58885d79 Iustin Pop
  @returns: the value zero
1328 58885d79 Iustin Pop

1329 8f765069 Iustin Pop
  """
1330 8f765069 Iustin Pop
  UMASK = 077
1331 8f765069 Iustin Pop
  WORKDIR = "/"
1332 8f765069 Iustin Pop
  # Default maximum for the number of available file descriptors.
1333 8f765069 Iustin Pop
  if 'SC_OPEN_MAX' in os.sysconf_names:
1334 8f765069 Iustin Pop
    try:
1335 8f765069 Iustin Pop
      MAXFD = os.sysconf('SC_OPEN_MAX')
1336 8f765069 Iustin Pop
      if MAXFD < 0:
1337 8f765069 Iustin Pop
        MAXFD = 1024
1338 8f765069 Iustin Pop
    except OSError:
1339 8f765069 Iustin Pop
      MAXFD = 1024
1340 8f765069 Iustin Pop
  else:
1341 8f765069 Iustin Pop
    MAXFD = 1024
1342 8f765069 Iustin Pop
1343 8f765069 Iustin Pop
  # this might fail
1344 8f765069 Iustin Pop
  pid = os.fork()
1345 8f765069 Iustin Pop
  if (pid == 0):  # The first child.
1346 8f765069 Iustin Pop
    os.setsid()
1347 8f765069 Iustin Pop
    # this might fail
1348 8f765069 Iustin Pop
    pid = os.fork() # Fork a second child.
1349 8f765069 Iustin Pop
    if (pid == 0):  # The second child.
1350 8f765069 Iustin Pop
      os.chdir(WORKDIR)
1351 8f765069 Iustin Pop
      os.umask(UMASK)
1352 8f765069 Iustin Pop
    else:
1353 8f765069 Iustin Pop
      # exit() or _exit()?  See below.
1354 8f765069 Iustin Pop
      os._exit(0) # Exit parent (the first child) of the second child.
1355 8f765069 Iustin Pop
  else:
1356 8f765069 Iustin Pop
    os._exit(0) # Exit parent of the first child.
1357 8f765069 Iustin Pop
  maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
1358 8f765069 Iustin Pop
  if (maxfd == resource.RLIM_INFINITY):
1359 8f765069 Iustin Pop
    maxfd = MAXFD
1360 8f765069 Iustin Pop
1361 8f765069 Iustin Pop
  # Iterate through and close all file descriptors.
1362 8f765069 Iustin Pop
  for fd in range(0, maxfd):
1363 8ff612c2 Iustin Pop
    if noclose_fds and fd in noclose_fds:
1364 8ff612c2 Iustin Pop
      continue
1365 8f765069 Iustin Pop
    try:
1366 8f765069 Iustin Pop
      os.close(fd)
1367 8f765069 Iustin Pop
    except OSError: # ERROR, fd wasn't open to begin with (ignored)
1368 8f765069 Iustin Pop
      pass
1369 8f765069 Iustin Pop
  os.open(logfile, os.O_RDWR|os.O_CREAT|os.O_APPEND, 0600)
1370 8f765069 Iustin Pop
  # Duplicate standard input to standard output and standard error.
1371 8f765069 Iustin Pop
  os.dup2(0, 1)     # standard output (1)
1372 8f765069 Iustin Pop
  os.dup2(0, 2)     # standard error (2)
1373 8f765069 Iustin Pop
  return 0
1374 57c177af Iustin Pop
1375 57c177af Iustin Pop
1376 53beffbb Iustin Pop
def DaemonPidFileName(name):
1377 58885d79 Iustin Pop
  """Compute a ganeti pid file absolute path
1378 58885d79 Iustin Pop

1379 58885d79 Iustin Pop
  @type name: str
1380 58885d79 Iustin Pop
  @param name: the daemon name
1381 58885d79 Iustin Pop
  @rtype: str
1382 58885d79 Iustin Pop
  @return: the full path to the pidfile corresponding to the given
1383 58885d79 Iustin Pop
      daemon name
1384 b330ac0b Guido Trotter

1385 b330ac0b Guido Trotter
  """
1386 b330ac0b Guido Trotter
  return os.path.join(constants.RUN_GANETI_DIR, "%s.pid" % name)
1387 b330ac0b Guido Trotter
1388 b330ac0b Guido Trotter
1389 b330ac0b Guido Trotter
def WritePidFile(name):
1390 b330ac0b Guido Trotter
  """Write the current process pidfile.
1391 b330ac0b Guido Trotter

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

1394 58885d79 Iustin Pop
  @type name: str
1395 58885d79 Iustin Pop
  @param name: the daemon name to use
1396 58885d79 Iustin Pop
  @raise errors.GenericError: if the pid file already exists and
1397 58885d79 Iustin Pop
      points to a live process
1398 b330ac0b Guido Trotter

1399 b330ac0b Guido Trotter
  """
1400 b330ac0b Guido Trotter
  pid = os.getpid()
1401 53beffbb Iustin Pop
  pidfilename = DaemonPidFileName(name)
1402 d9f311d7 Iustin Pop
  if IsProcessAlive(ReadPidFile(pidfilename)):
1403 533bb4b1 Michael Hanselmann
    raise errors.GenericError("%s contains a live process" % pidfilename)
1404 b330ac0b Guido Trotter
1405 b330ac0b Guido Trotter
  WriteFile(pidfilename, data="%d\n" % pid)
1406 b330ac0b Guido Trotter
1407 b330ac0b Guido Trotter
1408 b330ac0b Guido Trotter
def RemovePidFile(name):
1409 b330ac0b Guido Trotter
  """Remove the current process pidfile.
1410 b330ac0b Guido Trotter

1411 b330ac0b Guido Trotter
  Any errors are ignored.
1412 b330ac0b Guido Trotter

1413 58885d79 Iustin Pop
  @type name: str
1414 58885d79 Iustin Pop
  @param name: the daemon name used to derive the pidfile name
1415 58885d79 Iustin Pop

1416 b330ac0b Guido Trotter
  """
1417 b330ac0b Guido Trotter
  pid = os.getpid()
1418 53beffbb Iustin Pop
  pidfilename = DaemonPidFileName(name)
1419 b330ac0b Guido Trotter
  # TODO: we could check here that the file contains our pid
1420 b330ac0b Guido Trotter
  try:
1421 b330ac0b Guido Trotter
    RemoveFile(pidfilename)
1422 b330ac0b Guido Trotter
  except:
1423 b330ac0b Guido Trotter
    pass
1424 b330ac0b Guido Trotter
1425 b330ac0b Guido Trotter
1426 ff5251bc Iustin Pop
def KillProcess(pid, signal_=signal.SIGTERM, timeout=30,
1427 ff5251bc Iustin Pop
                waitpid=False):
1428 b2a1f511 Iustin Pop
  """Kill a process given by its pid.
1429 b2a1f511 Iustin Pop

1430 b2a1f511 Iustin Pop
  @type pid: int
1431 b2a1f511 Iustin Pop
  @param pid: The PID to terminate.
1432 38206f3c Iustin Pop
  @type signal_: int
1433 38206f3c Iustin Pop
  @param signal_: The signal to send, by default SIGTERM
1434 b2a1f511 Iustin Pop
  @type timeout: int
1435 b2a1f511 Iustin Pop
  @param timeout: The timeout after which, if the process is still alive,
1436 b2a1f511 Iustin Pop
                  a SIGKILL will be sent. If not positive, no such checking
1437 b2a1f511 Iustin Pop
                  will be done
1438 ff5251bc Iustin Pop
  @type waitpid: boolean
1439 ff5251bc Iustin Pop
  @param waitpid: If true, we should waitpid on this process after
1440 ff5251bc Iustin Pop
      sending signals, since it's our own child and otherwise it
1441 ff5251bc Iustin Pop
      would remain as zombie
1442 b2a1f511 Iustin Pop

1443 b2a1f511 Iustin Pop
  """
1444 ff5251bc Iustin Pop
  def _helper(pid, signal_, wait):
1445 ff5251bc Iustin Pop
    """Simple helper to encapsulate the kill/waitpid sequence"""
1446 ff5251bc Iustin Pop
    os.kill(pid, signal_)
1447 ff5251bc Iustin Pop
    if wait:
1448 ff5251bc Iustin Pop
      try:
1449 ff5251bc Iustin Pop
        os.waitpid(pid, os.WNOHANG)
1450 ff5251bc Iustin Pop
      except OSError:
1451 ff5251bc Iustin Pop
        pass
1452 ff5251bc Iustin Pop
1453 b2a1f511 Iustin Pop
  if pid <= 0:
1454 b2a1f511 Iustin Pop
    # kill with pid=0 == suicide
1455 b2a1f511 Iustin Pop
    raise errors.ProgrammerError("Invalid pid given '%s'" % pid)
1456 b2a1f511 Iustin Pop
1457 b2a1f511 Iustin Pop
  if not IsProcessAlive(pid):
1458 b2a1f511 Iustin Pop
    return
1459 ff5251bc Iustin Pop
  _helper(pid, signal_, waitpid)
1460 b2a1f511 Iustin Pop
  if timeout <= 0:
1461 b2a1f511 Iustin Pop
    return
1462 b2a1f511 Iustin Pop
  end = time.time() + timeout
1463 b2a1f511 Iustin Pop
  while time.time() < end and IsProcessAlive(pid):
1464 b2a1f511 Iustin Pop
    time.sleep(0.1)
1465 b2a1f511 Iustin Pop
  if IsProcessAlive(pid):
1466 e1bd0072 Iustin Pop
    _helper(pid, signal.SIGKILL, waitpid)
1467 b2a1f511 Iustin Pop
1468 b2a1f511 Iustin Pop
1469 57c177af Iustin Pop
def FindFile(name, search_path, test=os.path.exists):
1470 57c177af Iustin Pop
  """Look for a filesystem object in a given path.
1471 57c177af Iustin Pop

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

1475 58885d79 Iustin Pop
  @type name: str
1476 58885d79 Iustin Pop
  @param name: the name to look for
1477 58885d79 Iustin Pop
  @type search_path: str
1478 58885d79 Iustin Pop
  @param search_path: location to start at
1479 58885d79 Iustin Pop
  @type test: callable
1480 58885d79 Iustin Pop
  @param test: a function taking one argument that should return True
1481 58885d79 Iustin Pop
      if the a given object is valid; the default value is
1482 58885d79 Iustin Pop
      os.path.exists, causing only existing files to be returned
1483 58885d79 Iustin Pop
  @rtype: str or None
1484 58885d79 Iustin Pop
  @return: full path to the object if found, None otherwise
1485 57c177af Iustin Pop

1486 57c177af Iustin Pop
  """
1487 57c177af Iustin Pop
  for dir_name in search_path:
1488 57c177af Iustin Pop
    item_name = os.path.sep.join([dir_name, name])
1489 57c177af Iustin Pop
    if test(item_name):
1490 57c177af Iustin Pop
      return item_name
1491 57c177af Iustin Pop
  return None
1492 8d1a2a64 Michael Hanselmann
1493 8d1a2a64 Michael Hanselmann
1494 8d1a2a64 Michael Hanselmann
def CheckVolumeGroupSize(vglist, vgname, minsize):
1495 8d1a2a64 Michael Hanselmann
  """Checks if the volume group list is valid.
1496 8d1a2a64 Michael Hanselmann

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

1500 58885d79 Iustin Pop
  @type vglist: dict
1501 58885d79 Iustin Pop
  @param vglist: dictionary of volume group names and their size
1502 58885d79 Iustin Pop
  @type vgname: str
1503 58885d79 Iustin Pop
  @param vgname: the volume group we should check
1504 58885d79 Iustin Pop
  @type minsize: int
1505 58885d79 Iustin Pop
  @param minsize: the minimum size we accept
1506 58885d79 Iustin Pop
  @rtype: None or str
1507 58885d79 Iustin Pop
  @return: None for success, otherwise the error message
1508 8d1a2a64 Michael Hanselmann

1509 8d1a2a64 Michael Hanselmann
  """
1510 8d1a2a64 Michael Hanselmann
  vgsize = vglist.get(vgname, None)
1511 8d1a2a64 Michael Hanselmann
  if vgsize is None:
1512 8d1a2a64 Michael Hanselmann
    return "volume group '%s' missing" % vgname
1513 8d1a2a64 Michael Hanselmann
  elif vgsize < minsize:
1514 8d1a2a64 Michael Hanselmann
    return ("volume group '%s' too small (%s MiB required, %d MiB found)" %
1515 8d1a2a64 Michael Hanselmann
            (vgname, minsize, vgsize))
1516 8d1a2a64 Michael Hanselmann
  return None
1517 7996a135 Iustin Pop
1518 7996a135 Iustin Pop
1519 45bc5e4a Michael Hanselmann
def SplitTime(value):
1520 739be818 Michael Hanselmann
  """Splits time as floating point number into a tuple.
1521 739be818 Michael Hanselmann

1522 45bc5e4a Michael Hanselmann
  @param value: Time in seconds
1523 45bc5e4a Michael Hanselmann
  @type value: int or float
1524 45bc5e4a Michael Hanselmann
  @return: Tuple containing (seconds, microseconds)
1525 739be818 Michael Hanselmann

1526 739be818 Michael Hanselmann
  """
1527 45bc5e4a Michael Hanselmann
  (seconds, microseconds) = divmod(int(value * 1000000), 1000000)
1528 45bc5e4a Michael Hanselmann
1529 45bc5e4a Michael Hanselmann
  assert 0 <= seconds, \
1530 45bc5e4a Michael Hanselmann
    "Seconds must be larger than or equal to 0, but are %s" % seconds
1531 45bc5e4a Michael Hanselmann
  assert 0 <= microseconds <= 999999, \
1532 45bc5e4a Michael Hanselmann
    "Microseconds must be 0-999999, but are %s" % microseconds
1533 45bc5e4a Michael Hanselmann
1534 45bc5e4a Michael Hanselmann
  return (int(seconds), int(microseconds))
1535 739be818 Michael Hanselmann
1536 739be818 Michael Hanselmann
1537 739be818 Michael Hanselmann
def MergeTime(timetuple):
1538 739be818 Michael Hanselmann
  """Merges a tuple into time as a floating point number.
1539 739be818 Michael Hanselmann

1540 45bc5e4a Michael Hanselmann
  @param timetuple: Time as tuple, (seconds, microseconds)
1541 739be818 Michael Hanselmann
  @type timetuple: tuple
1542 739be818 Michael Hanselmann
  @return: Time as a floating point number expressed in seconds
1543 739be818 Michael Hanselmann

1544 739be818 Michael Hanselmann
  """
1545 45bc5e4a Michael Hanselmann
  (seconds, microseconds) = timetuple
1546 739be818 Michael Hanselmann
1547 45bc5e4a Michael Hanselmann
  assert 0 <= seconds, \
1548 45bc5e4a Michael Hanselmann
    "Seconds must be larger than or equal to 0, but are %s" % seconds
1549 45bc5e4a Michael Hanselmann
  assert 0 <= microseconds <= 999999, \
1550 45bc5e4a Michael Hanselmann
    "Microseconds must be 0-999999, but are %s" % microseconds
1551 739be818 Michael Hanselmann
1552 45bc5e4a Michael Hanselmann
  return float(seconds) + (float(microseconds) * 0.000001)
1553 739be818 Michael Hanselmann
1554 739be818 Michael Hanselmann
1555 4a8b186a Michael Hanselmann
def GetNodeDaemonPort():
1556 4a8b186a Michael Hanselmann
  """Get the node daemon port for this cluster.
1557 4a8b186a Michael Hanselmann

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

1562 58885d79 Iustin Pop
  @rtype: int
1563 58885d79 Iustin Pop

1564 4a8b186a Michael Hanselmann
  """
1565 4a8b186a Michael Hanselmann
  try:
1566 4a8b186a Michael Hanselmann
    port = socket.getservbyname("ganeti-noded", "tcp")
1567 4a8b186a Michael Hanselmann
  except socket.error:
1568 4a8b186a Michael Hanselmann
    port = constants.DEFAULT_NODED_PORT
1569 4a8b186a Michael Hanselmann
1570 4a8b186a Michael Hanselmann
  return port
1571 4a8b186a Michael Hanselmann
1572 4a8b186a Michael Hanselmann
1573 82d9caef Iustin Pop
def SetupLogging(logfile, debug=False, stderr_logging=False, program=""):
1574 82d9caef Iustin Pop
  """Configures the logging module.
1575 82d9caef Iustin Pop

1576 58885d79 Iustin Pop
  @type logfile: str
1577 58885d79 Iustin Pop
  @param logfile: the filename to which we should log
1578 58885d79 Iustin Pop
  @type debug: boolean
1579 58885d79 Iustin Pop
  @param debug: whether to enable debug messages too or
1580 58885d79 Iustin Pop
      only those at C{INFO} and above level
1581 58885d79 Iustin Pop
  @type stderr_logging: boolean
1582 58885d79 Iustin Pop
  @param stderr_logging: whether we should also log to the standard error
1583 58885d79 Iustin Pop
  @type program: str
1584 58885d79 Iustin Pop
  @param program: the name under which we should log messages
1585 58885d79 Iustin Pop
  @raise EnvironmentError: if we can't open the log file and
1586 58885d79 Iustin Pop
      stderr logging is disabled
1587 58885d79 Iustin Pop

1588 82d9caef Iustin Pop
  """
1589 82d9caef Iustin Pop
  fmt = "%(asctime)s: " + program + " "
1590 82d9caef Iustin Pop
  if debug:
1591 82d9caef Iustin Pop
    fmt += ("pid=%(process)d/%(threadName)s %(levelname)s"
1592 82d9caef Iustin Pop
           " %(module)s:%(lineno)s %(message)s")
1593 82d9caef Iustin Pop
  else:
1594 82d9caef Iustin Pop
    fmt += "pid=%(process)d %(levelname)s %(message)s"
1595 82d9caef Iustin Pop
  formatter = logging.Formatter(fmt)
1596 82d9caef Iustin Pop
1597 82d9caef Iustin Pop
  root_logger = logging.getLogger("")
1598 82d9caef Iustin Pop
  root_logger.setLevel(logging.NOTSET)
1599 82d9caef Iustin Pop
1600 6346a9e5 Michael Hanselmann
  # Remove all previously setup handlers
1601 6346a9e5 Michael Hanselmann
  for handler in root_logger.handlers:
1602 6346a9e5 Michael Hanselmann
    root_logger.removeHandler(handler)
1603 6346a9e5 Michael Hanselmann
1604 82d9caef Iustin Pop
  if stderr_logging:
1605 82d9caef Iustin Pop
    stderr_handler = logging.StreamHandler()
1606 82d9caef Iustin Pop
    stderr_handler.setFormatter(formatter)
1607 82d9caef Iustin Pop
    if debug:
1608 82d9caef Iustin Pop
      stderr_handler.setLevel(logging.NOTSET)
1609 82d9caef Iustin Pop
    else:
1610 82d9caef Iustin Pop
      stderr_handler.setLevel(logging.CRITICAL)
1611 82d9caef Iustin Pop
    root_logger.addHandler(stderr_handler)
1612 82d9caef Iustin Pop
1613 82d9caef Iustin Pop
  # this can fail, if the logging directories are not setup or we have
1614 82d9caef Iustin Pop
  # a permisssion problem; in this case, it's best to log but ignore
1615 82d9caef Iustin Pop
  # the error if stderr_logging is True, and if false we re-raise the
1616 82d9caef Iustin Pop
  # exception since otherwise we could run but without any logs at all
1617 82d9caef Iustin Pop
  try:
1618 82d9caef Iustin Pop
    logfile_handler = logging.FileHandler(logfile)
1619 82d9caef Iustin Pop
    logfile_handler.setFormatter(formatter)
1620 82d9caef Iustin Pop
    if debug:
1621 82d9caef Iustin Pop
      logfile_handler.setLevel(logging.DEBUG)
1622 82d9caef Iustin Pop
    else:
1623 82d9caef Iustin Pop
      logfile_handler.setLevel(logging.INFO)
1624 82d9caef Iustin Pop
    root_logger.addHandler(logfile_handler)
1625 82d9caef Iustin Pop
  except EnvironmentError, err:
1626 82d9caef Iustin Pop
    if stderr_logging:
1627 82d9caef Iustin Pop
      logging.exception("Failed to enable logging to file '%s'", logfile)
1628 82d9caef Iustin Pop
    else:
1629 82d9caef Iustin Pop
      # we need to re-raise the exception
1630 82d9caef Iustin Pop
      raise
1631 82d9caef Iustin Pop
1632 82d9caef Iustin Pop
1633 7996a135 Iustin Pop
def LockedMethod(fn):
1634 7996a135 Iustin Pop
  """Synchronized object access decorator.
1635 7996a135 Iustin Pop

1636 7996a135 Iustin Pop
  This decorator is intended to protect access to an object using the
1637 7996a135 Iustin Pop
  object's own lock which is hardcoded to '_lock'.
1638 7996a135 Iustin Pop

1639 7996a135 Iustin Pop
  """
1640 e67bd559 Michael Hanselmann
  def _LockDebug(*args, **kwargs):
1641 e67bd559 Michael Hanselmann
    if debug_locks:
1642 e67bd559 Michael Hanselmann
      logging.debug(*args, **kwargs)
1643 e67bd559 Michael Hanselmann
1644 7996a135 Iustin Pop
  def wrapper(self, *args, **kwargs):
1645 7996a135 Iustin Pop
    assert hasattr(self, '_lock')
1646 7996a135 Iustin Pop
    lock = self._lock
1647 e67bd559 Michael Hanselmann
    _LockDebug("Waiting for %s", lock)
1648 7996a135 Iustin Pop
    lock.acquire()
1649 7996a135 Iustin Pop
    try:
1650 e67bd559 Michael Hanselmann
      _LockDebug("Acquired %s", lock)
1651 7996a135 Iustin Pop
      result = fn(self, *args, **kwargs)
1652 7996a135 Iustin Pop
    finally:
1653 e67bd559 Michael Hanselmann
      _LockDebug("Releasing %s", lock)
1654 7996a135 Iustin Pop
      lock.release()
1655 e67bd559 Michael Hanselmann
      _LockDebug("Released %s", lock)
1656 7996a135 Iustin Pop
    return result
1657 7996a135 Iustin Pop
  return wrapper
1658 eb0f0ce0 Michael Hanselmann
1659 eb0f0ce0 Michael Hanselmann
1660 eb0f0ce0 Michael Hanselmann
def LockFile(fd):
1661 eb0f0ce0 Michael Hanselmann
  """Locks a file using POSIX locks.
1662 eb0f0ce0 Michael Hanselmann

1663 58885d79 Iustin Pop
  @type fd: int
1664 58885d79 Iustin Pop
  @param fd: the file descriptor we need to lock
1665 58885d79 Iustin Pop

1666 eb0f0ce0 Michael Hanselmann
  """
1667 eb0f0ce0 Michael Hanselmann
  try:
1668 eb0f0ce0 Michael Hanselmann
    fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
1669 eb0f0ce0 Michael Hanselmann
  except IOError, err:
1670 eb0f0ce0 Michael Hanselmann
    if err.errno == errno.EAGAIN:
1671 eb0f0ce0 Michael Hanselmann
      raise errors.LockError("File already locked")
1672 eb0f0ce0 Michael Hanselmann
    raise
1673 de499029 Michael Hanselmann
1674 de499029 Michael Hanselmann
1675 a87b4824 Michael Hanselmann
class FileLock(object):
1676 a87b4824 Michael Hanselmann
  """Utility class for file locks.
1677 a87b4824 Michael Hanselmann

1678 a87b4824 Michael Hanselmann
  """
1679 a87b4824 Michael Hanselmann
  def __init__(self, filename):
1680 58885d79 Iustin Pop
    """Constructor for FileLock.
1681 58885d79 Iustin Pop

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

1684 58885d79 Iustin Pop
    @type filename: str
1685 58885d79 Iustin Pop
    @param filename: path to the file to be locked
1686 58885d79 Iustin Pop

1687 58885d79 Iustin Pop
    """
1688 a87b4824 Michael Hanselmann
    self.filename = filename
1689 a87b4824 Michael Hanselmann
    self.fd = open(self.filename, "w")
1690 a87b4824 Michael Hanselmann
1691 a87b4824 Michael Hanselmann
  def __del__(self):
1692 a87b4824 Michael Hanselmann
    self.Close()
1693 a87b4824 Michael Hanselmann
1694 a87b4824 Michael Hanselmann
  def Close(self):
1695 58885d79 Iustin Pop
    """Close the file and release the lock.
1696 58885d79 Iustin Pop

1697 58885d79 Iustin Pop
    """
1698 a87b4824 Michael Hanselmann
    if self.fd:
1699 a87b4824 Michael Hanselmann
      self.fd.close()
1700 a87b4824 Michael Hanselmann
      self.fd = None
1701 a87b4824 Michael Hanselmann
1702 aa74b828 Michael Hanselmann
  def _flock(self, flag, blocking, timeout, errmsg):
1703 aa74b828 Michael Hanselmann
    """Wrapper for fcntl.flock.
1704 aa74b828 Michael Hanselmann

1705 aa74b828 Michael Hanselmann
    @type flag: int
1706 58885d79 Iustin Pop
    @param flag: operation flag
1707 aa74b828 Michael Hanselmann
    @type blocking: bool
1708 58885d79 Iustin Pop
    @param blocking: whether the operation should be done in blocking mode.
1709 aa74b828 Michael Hanselmann
    @type timeout: None or float
1710 58885d79 Iustin Pop
    @param timeout: for how long the operation should be retried (implies
1711 aa74b828 Michael Hanselmann
                    non-blocking mode).
1712 aa74b828 Michael Hanselmann
    @type errmsg: string
1713 58885d79 Iustin Pop
    @param errmsg: error message in case operation fails.
1714 aa74b828 Michael Hanselmann

1715 aa74b828 Michael Hanselmann
    """
1716 a87b4824 Michael Hanselmann
    assert self.fd, "Lock was closed"
1717 aa74b828 Michael Hanselmann
    assert timeout is None or timeout >= 0, \
1718 aa74b828 Michael Hanselmann
      "If specified, timeout must be positive"
1719 a87b4824 Michael Hanselmann
1720 aa74b828 Michael Hanselmann
    if timeout is not None:
1721 a87b4824 Michael Hanselmann
      flag |= fcntl.LOCK_NB
1722 aa74b828 Michael Hanselmann
      timeout_end = time.time() + timeout
1723 a87b4824 Michael Hanselmann
1724 aa74b828 Michael Hanselmann
    # Blocking doesn't have effect with timeout
1725 aa74b828 Michael Hanselmann
    elif not blocking:
1726 aa74b828 Michael Hanselmann
      flag |= fcntl.LOCK_NB
1727 aa74b828 Michael Hanselmann
      timeout_end = None
1728 aa74b828 Michael Hanselmann
1729 aa74b828 Michael Hanselmann
    retry = True
1730 aa74b828 Michael Hanselmann
    while retry:
1731 aa74b828 Michael Hanselmann
      try:
1732 aa74b828 Michael Hanselmann
        fcntl.flock(self.fd, flag)
1733 aa74b828 Michael Hanselmann
        retry = False
1734 aa74b828 Michael Hanselmann
      except IOError, err:
1735 aa74b828 Michael Hanselmann
        if err.errno in (errno.EAGAIN, ):
1736 aa74b828 Michael Hanselmann
          if timeout_end is not None and time.time() < timeout_end:
1737 aa74b828 Michael Hanselmann
            # Wait before trying again
1738 aa74b828 Michael Hanselmann
            time.sleep(max(0.1, min(1.0, timeout)))
1739 aa74b828 Michael Hanselmann
          else:
1740 aa74b828 Michael Hanselmann
            raise errors.LockError(errmsg)
1741 aa74b828 Michael Hanselmann
        else:
1742 aa74b828 Michael Hanselmann
          logging.exception("fcntl.flock failed")
1743 aa74b828 Michael Hanselmann
          raise
1744 aa74b828 Michael Hanselmann
1745 aa74b828 Michael Hanselmann
  def Exclusive(self, blocking=False, timeout=None):
1746 a87b4824 Michael Hanselmann
    """Locks the file in exclusive mode.
1747 a87b4824 Michael Hanselmann

1748 58885d79 Iustin Pop
    @type blocking: boolean
1749 58885d79 Iustin Pop
    @param blocking: whether to block and wait until we
1750 58885d79 Iustin Pop
        can lock the file or return immediately
1751 58885d79 Iustin Pop
    @type timeout: int or None
1752 58885d79 Iustin Pop
    @param timeout: if not None, the duration to wait for the lock
1753 58885d79 Iustin Pop
        (in blocking mode)
1754 58885d79 Iustin Pop

1755 a87b4824 Michael Hanselmann
    """
1756 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_EX, blocking, timeout,
1757 a87b4824 Michael Hanselmann
                "Failed to lock %s in exclusive mode" % self.filename)
1758 a87b4824 Michael Hanselmann
1759 aa74b828 Michael Hanselmann
  def Shared(self, blocking=False, timeout=None):
1760 a87b4824 Michael Hanselmann
    """Locks the file in shared mode.
1761 a87b4824 Michael Hanselmann

1762 58885d79 Iustin Pop
    @type blocking: boolean
1763 58885d79 Iustin Pop
    @param blocking: whether to block and wait until we
1764 58885d79 Iustin Pop
        can lock the file or return immediately
1765 58885d79 Iustin Pop
    @type timeout: int or None
1766 58885d79 Iustin Pop
    @param timeout: if not None, the duration to wait for the lock
1767 58885d79 Iustin Pop
        (in blocking mode)
1768 58885d79 Iustin Pop

1769 a87b4824 Michael Hanselmann
    """
1770 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_SH, blocking, timeout,
1771 a87b4824 Michael Hanselmann
                "Failed to lock %s in shared mode" % self.filename)
1772 a87b4824 Michael Hanselmann
1773 aa74b828 Michael Hanselmann
  def Unlock(self, blocking=True, timeout=None):
1774 a87b4824 Michael Hanselmann
    """Unlocks the file.
1775 a87b4824 Michael Hanselmann

1776 58885d79 Iustin Pop
    According to C{flock(2)}, unlocking can also be a nonblocking
1777 58885d79 Iustin Pop
    operation::
1778 58885d79 Iustin Pop

1779 58885d79 Iustin Pop
      To make a non-blocking request, include LOCK_NB with any of the above
1780 58885d79 Iustin Pop
      operations.
1781 58885d79 Iustin Pop

1782 58885d79 Iustin Pop
    @type blocking: boolean
1783 58885d79 Iustin Pop
    @param blocking: whether to block and wait until we
1784 58885d79 Iustin Pop
        can lock the file or return immediately
1785 58885d79 Iustin Pop
    @type timeout: int or None
1786 58885d79 Iustin Pop
    @param timeout: if not None, the duration to wait for the lock
1787 58885d79 Iustin Pop
        (in blocking mode)
1788 a87b4824 Michael Hanselmann

1789 a87b4824 Michael Hanselmann
    """
1790 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_UN, blocking, timeout,
1791 a87b4824 Michael Hanselmann
                "Failed to unlock %s" % self.filename)
1792 a87b4824 Michael Hanselmann
1793 a87b4824 Michael Hanselmann
1794 de499029 Michael Hanselmann
class SignalHandler(object):
1795 de499029 Michael Hanselmann
  """Generic signal handler class.
1796 de499029 Michael Hanselmann

1797 58885d79 Iustin Pop
  It automatically restores the original handler when deconstructed or
1798 58885d79 Iustin Pop
  when L{Reset} is called. You can either pass your own handler
1799 58885d79 Iustin Pop
  function in or query the L{called} attribute to detect whether the
1800 58885d79 Iustin Pop
  signal was sent.
1801 58885d79 Iustin Pop

1802 58885d79 Iustin Pop
  @type signum: list
1803 58885d79 Iustin Pop
  @ivar signum: the signals we handle
1804 58885d79 Iustin Pop
  @type called: boolean
1805 58885d79 Iustin Pop
  @ivar called: tracks whether any of the signals have been raised
1806 de499029 Michael Hanselmann

1807 de499029 Michael Hanselmann
  """
1808 de499029 Michael Hanselmann
  def __init__(self, signum):
1809 de499029 Michael Hanselmann
    """Constructs a new SignalHandler instance.
1810 de499029 Michael Hanselmann

1811 58885d79 Iustin Pop
    @type signum: int or list of ints
1812 de499029 Michael Hanselmann
    @param signum: Single signal number or set of signal numbers
1813 de499029 Michael Hanselmann

1814 de499029 Michael Hanselmann
    """
1815 de499029 Michael Hanselmann
    if isinstance(signum, (int, long)):
1816 de499029 Michael Hanselmann
      self.signum = set([signum])
1817 de499029 Michael Hanselmann
    else:
1818 de499029 Michael Hanselmann
      self.signum = set(signum)
1819 de499029 Michael Hanselmann
1820 de499029 Michael Hanselmann
    self.called = False
1821 de499029 Michael Hanselmann
1822 de499029 Michael Hanselmann
    self._previous = {}
1823 de499029 Michael Hanselmann
    try:
1824 de499029 Michael Hanselmann
      for signum in self.signum:
1825 de499029 Michael Hanselmann
        # Setup handler
1826 de499029 Michael Hanselmann
        prev_handler = signal.signal(signum, self._HandleSignal)
1827 de499029 Michael Hanselmann
        try:
1828 de499029 Michael Hanselmann
          self._previous[signum] = prev_handler
1829 de499029 Michael Hanselmann
        except:
1830 de499029 Michael Hanselmann
          # Restore previous handler
1831 de499029 Michael Hanselmann
          signal.signal(signum, prev_handler)
1832 de499029 Michael Hanselmann
          raise
1833 de499029 Michael Hanselmann
    except:
1834 de499029 Michael Hanselmann
      # Reset all handlers
1835 de499029 Michael Hanselmann
      self.Reset()
1836 de499029 Michael Hanselmann
      # Here we have a race condition: a handler may have already been called,
1837 de499029 Michael Hanselmann
      # but there's not much we can do about it at this point.
1838 de499029 Michael Hanselmann
      raise
1839 de499029 Michael Hanselmann
1840 de499029 Michael Hanselmann
  def __del__(self):
1841 de499029 Michael Hanselmann
    self.Reset()
1842 de499029 Michael Hanselmann
1843 de499029 Michael Hanselmann
  def Reset(self):
1844 de499029 Michael Hanselmann
    """Restore previous handler.
1845 de499029 Michael Hanselmann

1846 58885d79 Iustin Pop
    This will reset all the signals to their previous handlers.
1847 58885d79 Iustin Pop

1848 de499029 Michael Hanselmann
    """
1849 de499029 Michael Hanselmann
    for signum, prev_handler in self._previous.items():
1850 de499029 Michael Hanselmann
      signal.signal(signum, prev_handler)
1851 de499029 Michael Hanselmann
      # If successful, remove from dict
1852 de499029 Michael Hanselmann
      del self._previous[signum]
1853 de499029 Michael Hanselmann
1854 de499029 Michael Hanselmann
  def Clear(self):
1855 58885d79 Iustin Pop
    """Unsets the L{called} flag.
1856 de499029 Michael Hanselmann

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

1859 de499029 Michael Hanselmann
    """
1860 de499029 Michael Hanselmann
    self.called = False
1861 de499029 Michael Hanselmann
1862 de499029 Michael Hanselmann
  def _HandleSignal(self, signum, frame):
1863 de499029 Michael Hanselmann
    """Actual signal handling function.
1864 de499029 Michael Hanselmann

1865 de499029 Michael Hanselmann
    """
1866 de499029 Michael Hanselmann
    # This is not nice and not absolutely atomic, but it appears to be the only
1867 de499029 Michael Hanselmann
    # solution in Python -- there are no atomic types.
1868 de499029 Michael Hanselmann
    self.called = True
1869 a2d2e1a7 Iustin Pop
1870 a2d2e1a7 Iustin Pop
1871 a2d2e1a7 Iustin Pop
class FieldSet(object):
1872 a2d2e1a7 Iustin Pop
  """A simple field set.
1873 a2d2e1a7 Iustin Pop

1874 a2d2e1a7 Iustin Pop
  Among the features are:
1875 a2d2e1a7 Iustin Pop
    - checking if a string is among a list of static string or regex objects
1876 a2d2e1a7 Iustin Pop
    - checking if a whole list of string matches
1877 a2d2e1a7 Iustin Pop
    - returning the matching groups from a regex match
1878 a2d2e1a7 Iustin Pop

1879 a2d2e1a7 Iustin Pop
  Internally, all fields are held as regular expression objects.
1880 a2d2e1a7 Iustin Pop

1881 a2d2e1a7 Iustin Pop
  """
1882 a2d2e1a7 Iustin Pop
  def __init__(self, *items):
1883 a2d2e1a7 Iustin Pop
    self.items = [re.compile("^%s$" % value) for value in items]
1884 a2d2e1a7 Iustin Pop
1885 a2d2e1a7 Iustin Pop
  def Extend(self, other_set):
1886 a2d2e1a7 Iustin Pop
    """Extend the field set with the items from another one"""
1887 a2d2e1a7 Iustin Pop
    self.items.extend(other_set.items)
1888 a2d2e1a7 Iustin Pop
1889 a2d2e1a7 Iustin Pop
  def Matches(self, field):
1890 a2d2e1a7 Iustin Pop
    """Checks if a field matches the current set
1891 a2d2e1a7 Iustin Pop

1892 a2d2e1a7 Iustin Pop
    @type field: str
1893 a2d2e1a7 Iustin Pop
    @param field: the string to match
1894 a2d2e1a7 Iustin Pop
    @return: either False or a regular expression match object
1895 a2d2e1a7 Iustin Pop

1896 a2d2e1a7 Iustin Pop
    """
1897 a2d2e1a7 Iustin Pop
    for m in itertools.ifilter(None, (val.match(field) for val in self.items)):
1898 a2d2e1a7 Iustin Pop
      return m
1899 a2d2e1a7 Iustin Pop
    return False
1900 a2d2e1a7 Iustin Pop
1901 a2d2e1a7 Iustin Pop
  def NonMatching(self, items):
1902 a2d2e1a7 Iustin Pop
    """Returns the list of fields not matching the current set
1903 a2d2e1a7 Iustin Pop

1904 a2d2e1a7 Iustin Pop
    @type items: list
1905 a2d2e1a7 Iustin Pop
    @param items: the list of fields to check
1906 a2d2e1a7 Iustin Pop
    @rtype: list
1907 a2d2e1a7 Iustin Pop
    @return: list of non-matching fields
1908 a2d2e1a7 Iustin Pop

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