Statistics
| Branch: | Tag: | Revision:

root / lib / utils.py @ 5661b908

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
        for line in f:
838 9440aeab Michael Hanselmann
          fields = line.split()
839 7e3dbb94 Iustin Pop
          if fields and not fields[0].startswith('#') and ip == fields[0]:
840 9440aeab Michael Hanselmann
            continue
841 9440aeab Michael Hanselmann
          out.write(line)
842 9440aeab Michael Hanselmann
843 7e3dbb94 Iustin Pop
        out.write("%s\t%s" % (ip, hostname))
844 9440aeab Michael Hanselmann
        if aliases:
845 9440aeab Michael Hanselmann
          out.write(" %s" % ' '.join(aliases))
846 9440aeab Michael Hanselmann
        out.write('\n')
847 9440aeab Michael Hanselmann
848 9440aeab Michael Hanselmann
        out.flush()
849 2e3e75b7 Michael Hanselmann
        os.fsync(out)
850 9440aeab Michael Hanselmann
        os.rename(tmpname, file_name)
851 9440aeab Michael Hanselmann
      finally:
852 9440aeab Michael Hanselmann
        f.close()
853 9440aeab Michael Hanselmann
    finally:
854 9440aeab Michael Hanselmann
      out.close()
855 9440aeab Michael Hanselmann
  except:
856 9440aeab Michael Hanselmann
    RemoveFile(tmpname)
857 9440aeab Michael Hanselmann
    raise
858 899d2a81 Michael Hanselmann
859 899d2a81 Michael Hanselmann
860 d9c02ca6 Michael Hanselmann
def AddHostToEtcHosts(hostname):
861 d9c02ca6 Michael Hanselmann
  """Wrapper around SetEtcHostsEntry.
862 d9c02ca6 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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