Statistics
| Branch: | Tag: | Revision:

root / lib / utils.py @ ca0aa6d0

History | View | Annotate | Download (35.6 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 a8083063 Iustin Pop
"""Ganeti small utilities
23 899d2a81 Michael Hanselmann

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

62 a8083063 Iustin Pop
  Instance variables:
63 a8083063 Iustin Pop
    exit_code: the exit code of the program, or None (if the program
64 a8083063 Iustin Pop
               didn't exit())
65 a8083063 Iustin Pop
    signal: numeric signal that caused the program to finish, or None
66 a8083063 Iustin Pop
            (if the program wasn't terminated by a signal)
67 a8083063 Iustin Pop
    stdout: the standard output of the program
68 a8083063 Iustin Pop
    stderr: the standard error of the program
69 a8083063 Iustin Pop
    failed: a Boolean value which is True in case the program was
70 a8083063 Iustin Pop
            terminated by a signal or exited with a non-zero exit code
71 a8083063 Iustin Pop
    fail_reason: a string detailing the termination reason
72 a8083063 Iustin Pop

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

100 a8083063 Iustin Pop
    """
101 a8083063 Iustin Pop
    return self.stdout + self.stderr
102 a8083063 Iustin Pop
103 a8083063 Iustin Pop
  output = property(_GetOutput, None, None, "Return full output")
104 a8083063 Iustin Pop
105 a8083063 Iustin Pop
106 2557ff82 Guido Trotter
def RunCmd(cmd, env=None):
107 a8083063 Iustin Pop
  """Execute a (shell) command.
108 a8083063 Iustin Pop

109 a8083063 Iustin Pop
  The command should not read from its standard input, as it will be
110 a8083063 Iustin Pop
  closed.
111 a8083063 Iustin Pop

112 e326d4e5 Guido Trotter
  @param cmd: Command to run
113 e326d4e5 Guido Trotter
  @type  cmd: string or list
114 2557ff82 Guido Trotter
  @param env: Additional environment
115 2557ff82 Guido Trotter
  @type env: dict
116 e326d4e5 Guido Trotter
  @return: `RunResult` instance
117 e326d4e5 Guido Trotter
  @rtype: RunResult
118 a8083063 Iustin Pop

119 a8083063 Iustin Pop
  """
120 b74159ee Iustin Pop
  if no_fork:
121 b74159ee Iustin Pop
    raise errors.ProgrammerError("utils.RunCmd() called with fork() disabled")
122 b74159ee Iustin Pop
123 a8083063 Iustin Pop
  if isinstance(cmd, list):
124 a8083063 Iustin Pop
    cmd = [str(val) for val in cmd]
125 113b55aa Iustin Pop
    strcmd = " ".join(cmd)
126 113b55aa Iustin Pop
    shell = False
127 113b55aa Iustin Pop
  else:
128 113b55aa Iustin Pop
    strcmd = cmd
129 113b55aa Iustin Pop
    shell = True
130 bb698c1f Iustin Pop
  logging.debug("RunCmd '%s'", strcmd)
131 2557ff82 Guido Trotter
132 2557ff82 Guido Trotter
  cmd_env = os.environ.copy()
133 2557ff82 Guido Trotter
  cmd_env["LC_ALL"] = "C"
134 2557ff82 Guido Trotter
  if env is not None:
135 2557ff82 Guido Trotter
    cmd_env.update(env)
136 2557ff82 Guido Trotter
137 9c233417 Iustin Pop
  poller = select.poll()
138 113b55aa Iustin Pop
  child = subprocess.Popen(cmd, shell=shell,
139 113b55aa Iustin Pop
                           stderr=subprocess.PIPE,
140 113b55aa Iustin Pop
                           stdout=subprocess.PIPE,
141 113b55aa Iustin Pop
                           stdin=subprocess.PIPE,
142 2557ff82 Guido Trotter
                           close_fds=True, env=cmd_env)
143 113b55aa Iustin Pop
144 113b55aa Iustin Pop
  child.stdin.close()
145 9c233417 Iustin Pop
  poller.register(child.stdout, select.POLLIN)
146 9c233417 Iustin Pop
  poller.register(child.stderr, select.POLLIN)
147 9c233417 Iustin Pop
  out = StringIO()
148 9c233417 Iustin Pop
  err = StringIO()
149 9c233417 Iustin Pop
  fdmap = {
150 9c233417 Iustin Pop
    child.stdout.fileno(): (out, child.stdout),
151 9c233417 Iustin Pop
    child.stderr.fileno(): (err, child.stderr),
152 9c233417 Iustin Pop
    }
153 9c233417 Iustin Pop
  for fd in fdmap:
154 9c233417 Iustin Pop
    status = fcntl.fcntl(fd, fcntl.F_GETFL)
155 9c233417 Iustin Pop
    fcntl.fcntl(fd, fcntl.F_SETFL, status | os.O_NONBLOCK)
156 9c233417 Iustin Pop
157 9c233417 Iustin Pop
  while fdmap:
158 9c233417 Iustin Pop
    for fd, event in poller.poll():
159 9c233417 Iustin Pop
      if event & select.POLLIN or event & select.POLLPRI:
160 9c233417 Iustin Pop
        data = fdmap[fd][1].read()
161 9c233417 Iustin Pop
        # no data from read signifies EOF (the same as POLLHUP)
162 9c233417 Iustin Pop
        if not data:
163 9c233417 Iustin Pop
          poller.unregister(fd)
164 9c233417 Iustin Pop
          del fdmap[fd]
165 9c233417 Iustin Pop
          continue
166 9c233417 Iustin Pop
        fdmap[fd][0].write(data)
167 9c233417 Iustin Pop
      if (event & select.POLLNVAL or event & select.POLLHUP or
168 9c233417 Iustin Pop
          event & select.POLLERR):
169 9c233417 Iustin Pop
        poller.unregister(fd)
170 9c233417 Iustin Pop
        del fdmap[fd]
171 9c233417 Iustin Pop
172 9c233417 Iustin Pop
  out = out.getvalue()
173 9c233417 Iustin Pop
  err = err.getvalue()
174 a8083063 Iustin Pop
175 a8083063 Iustin Pop
  status = child.wait()
176 113b55aa Iustin Pop
  if status >= 0:
177 113b55aa Iustin Pop
    exitcode = status
178 38206f3c Iustin Pop
    signal_ = None
179 a8083063 Iustin Pop
  else:
180 a8083063 Iustin Pop
    exitcode = None
181 38206f3c Iustin Pop
    signal_ = -status
182 a8083063 Iustin Pop
183 38206f3c Iustin Pop
  return RunResult(exitcode, signal_, out, err, strcmd)
184 a8083063 Iustin Pop
185 a8083063 Iustin Pop
186 a8083063 Iustin Pop
def RemoveFile(filename):
187 a8083063 Iustin Pop
  """Remove a file ignoring some errors.
188 a8083063 Iustin Pop

189 a8083063 Iustin Pop
  Remove a file, ignoring non-existing ones or directories. Other
190 a8083063 Iustin Pop
  errors are passed.
191 a8083063 Iustin Pop

192 a8083063 Iustin Pop
  """
193 a8083063 Iustin Pop
  try:
194 a8083063 Iustin Pop
    os.unlink(filename)
195 a8083063 Iustin Pop
  except OSError, err:
196 4ca1b175 Alexander Schreiber
    if err.errno not in (errno.ENOENT, errno.EISDIR):
197 a8083063 Iustin Pop
      raise
198 a8083063 Iustin Pop
199 a8083063 Iustin Pop
200 a8083063 Iustin Pop
def _FingerprintFile(filename):
201 a8083063 Iustin Pop
  """Compute the fingerprint of a file.
202 a8083063 Iustin Pop

203 a8083063 Iustin Pop
  If the file does not exist, a None will be returned
204 a8083063 Iustin Pop
  instead.
205 a8083063 Iustin Pop

206 a8083063 Iustin Pop
  Args:
207 a8083063 Iustin Pop
    filename - Filename (str)
208 a8083063 Iustin Pop

209 a8083063 Iustin Pop
  """
210 a8083063 Iustin Pop
  if not (os.path.exists(filename) and os.path.isfile(filename)):
211 a8083063 Iustin Pop
    return None
212 a8083063 Iustin Pop
213 a8083063 Iustin Pop
  f = open(filename)
214 a8083063 Iustin Pop
215 a8083063 Iustin Pop
  fp = sha.sha()
216 a8083063 Iustin Pop
  while True:
217 a8083063 Iustin Pop
    data = f.read(4096)
218 a8083063 Iustin Pop
    if not data:
219 a8083063 Iustin Pop
      break
220 a8083063 Iustin Pop
221 a8083063 Iustin Pop
    fp.update(data)
222 a8083063 Iustin Pop
223 a8083063 Iustin Pop
  return fp.hexdigest()
224 a8083063 Iustin Pop
225 a8083063 Iustin Pop
226 a8083063 Iustin Pop
def FingerprintFiles(files):
227 a8083063 Iustin Pop
  """Compute fingerprints for a list of files.
228 a8083063 Iustin Pop

229 a8083063 Iustin Pop
  Args:
230 a8083063 Iustin Pop
    files - array of filenames.  ( [str, ...] )
231 a8083063 Iustin Pop

232 a8083063 Iustin Pop
  Return value:
233 a8083063 Iustin Pop
    dictionary of filename: fingerprint for the files that exist
234 a8083063 Iustin Pop

235 a8083063 Iustin Pop
  """
236 a8083063 Iustin Pop
  ret = {}
237 a8083063 Iustin Pop
238 a8083063 Iustin Pop
  for filename in files:
239 a8083063 Iustin Pop
    cksum = _FingerprintFile(filename)
240 a8083063 Iustin Pop
    if cksum:
241 a8083063 Iustin Pop
      ret[filename] = cksum
242 a8083063 Iustin Pop
243 a8083063 Iustin Pop
  return ret
244 a8083063 Iustin Pop
245 a8083063 Iustin Pop
246 a8083063 Iustin Pop
def CheckDict(target, template, logname=None):
247 a8083063 Iustin Pop
  """Ensure a dictionary has a required set of keys.
248 a8083063 Iustin Pop

249 a8083063 Iustin Pop
  For the given dictionaries `target` and `template`, ensure target
250 a8083063 Iustin Pop
  has all the keys from template. Missing keys are added with values
251 a8083063 Iustin Pop
  from template.
252 a8083063 Iustin Pop

253 a8083063 Iustin Pop
  Args:
254 a8083063 Iustin Pop
    target   - the dictionary to check
255 a8083063 Iustin Pop
    template - template dictionary
256 a8083063 Iustin Pop
    logname  - a caller-chosen string to identify the debug log
257 a8083063 Iustin Pop
               entry; if None, no logging will be done
258 a8083063 Iustin Pop

259 a8083063 Iustin Pop
  Returns value:
260 a8083063 Iustin Pop
    None
261 a8083063 Iustin Pop

262 a8083063 Iustin Pop
  """
263 a8083063 Iustin Pop
  missing = []
264 a8083063 Iustin Pop
  for k in template:
265 a8083063 Iustin Pop
    if k not in target:
266 a8083063 Iustin Pop
      missing.append(k)
267 a8083063 Iustin Pop
      target[k] = template[k]
268 a8083063 Iustin Pop
269 a8083063 Iustin Pop
  if missing and logname:
270 bb698c1f Iustin Pop
    logging.warning('%s missing keys %s', logname, ', '.join(missing))
271 a8083063 Iustin Pop
272 a8083063 Iustin Pop
273 a8083063 Iustin Pop
def IsProcessAlive(pid):
274 a8083063 Iustin Pop
  """Check if a given pid exists on the system.
275 a8083063 Iustin Pop

276 a8083063 Iustin Pop
  Returns: true or false, depending on if the pid exists or not
277 a8083063 Iustin Pop

278 d9f311d7 Iustin Pop
  Remarks: zombie processes treated as not alive, and giving a pid <=
279 d9f311d7 Iustin Pop
  0 makes the function to return False.
280 a8083063 Iustin Pop

281 a8083063 Iustin Pop
  """
282 d9f311d7 Iustin Pop
  if pid <= 0:
283 d9f311d7 Iustin Pop
    return False
284 d9f311d7 Iustin Pop
285 a8083063 Iustin Pop
  try:
286 a8083063 Iustin Pop
    f = open("/proc/%d/status" % pid)
287 a8083063 Iustin Pop
  except IOError, err:
288 4ca1b175 Alexander Schreiber
    if err.errno in (errno.ENOENT, errno.ENOTDIR):
289 a8083063 Iustin Pop
      return False
290 a8083063 Iustin Pop
291 a8083063 Iustin Pop
  alive = True
292 a8083063 Iustin Pop
  try:
293 a8083063 Iustin Pop
    data = f.readlines()
294 a8083063 Iustin Pop
    if len(data) > 1:
295 a8083063 Iustin Pop
      state = data[1].split()
296 a8083063 Iustin Pop
      if len(state) > 1 and state[1] == "Z":
297 a8083063 Iustin Pop
        alive = False
298 a8083063 Iustin Pop
  finally:
299 a8083063 Iustin Pop
    f.close()
300 a8083063 Iustin Pop
301 a8083063 Iustin Pop
  return alive
302 a8083063 Iustin Pop
303 a8083063 Iustin Pop
304 d9f311d7 Iustin Pop
def ReadPidFile(pidfile):
305 d9f311d7 Iustin Pop
  """Read the pid from a file.
306 fee80e90 Guido Trotter

307 d9f311d7 Iustin Pop
  @param pidfile: Path to a file containing the pid to be checked
308 d9f311d7 Iustin Pop
  @type  pidfile: string (filename)
309 d9f311d7 Iustin Pop
  @return: The process id, if the file exista and contains a valid PID,
310 d9f311d7 Iustin Pop
           otherwise 0
311 d9f311d7 Iustin Pop
  @rtype: int
312 fee80e90 Guido Trotter

313 fee80e90 Guido Trotter
  """
314 fee80e90 Guido Trotter
  try:
315 fee80e90 Guido Trotter
    pf = open(pidfile, 'r')
316 d9f311d7 Iustin Pop
  except EnvironmentError, err:
317 d9f311d7 Iustin Pop
    if err.errno != errno.ENOENT:
318 d9f311d7 Iustin Pop
      logging.exception("Can't read pid file?!")
319 d9f311d7 Iustin Pop
    return 0
320 fee80e90 Guido Trotter
321 fee80e90 Guido Trotter
  try:
322 fee80e90 Guido Trotter
    pid = int(pf.read())
323 d9f311d7 Iustin Pop
  except ValueError, err:
324 8161a646 Iustin Pop
    logging.info("Can't parse pid file contents", exc_info=True)
325 d9f311d7 Iustin Pop
    return 0
326 fee80e90 Guido Trotter
327 d9f311d7 Iustin Pop
  return pid
328 fee80e90 Guido Trotter
329 fee80e90 Guido Trotter
330 a8083063 Iustin Pop
def MatchNameComponent(key, name_list):
331 a8083063 Iustin Pop
  """Try to match a name against a list.
332 a8083063 Iustin Pop

333 a8083063 Iustin Pop
  This function will try to match a name like test1 against a list
334 a8083063 Iustin Pop
  like ['test1.example.com', 'test2.example.com', ...]. Against this
335 a8083063 Iustin Pop
  list, 'test1' as well as 'test1.example' will match, but not
336 a8083063 Iustin Pop
  'test1.ex'. A multiple match will be considered as no match at all
337 a8083063 Iustin Pop
  (e.g. 'test1' against ['test1.example.com', 'test1.example.org']).
338 a8083063 Iustin Pop

339 a8083063 Iustin Pop
  Args:
340 a8083063 Iustin Pop
    key: the name to be searched
341 a8083063 Iustin Pop
    name_list: the list of strings against which to search the key
342 a8083063 Iustin Pop

343 a8083063 Iustin Pop
  Returns:
344 a8083063 Iustin Pop
    None if there is no match *or* if there are multiple matches
345 a8083063 Iustin Pop
    otherwise the element from the list which matches
346 a8083063 Iustin Pop

347 a8083063 Iustin Pop
  """
348 a8083063 Iustin Pop
  mo = re.compile("^%s(\..*)?$" % re.escape(key))
349 a8083063 Iustin Pop
  names_filtered = [name for name in name_list if mo.match(name) is not None]
350 a8083063 Iustin Pop
  if len(names_filtered) != 1:
351 a8083063 Iustin Pop
    return None
352 a8083063 Iustin Pop
  return names_filtered[0]
353 a8083063 Iustin Pop
354 a8083063 Iustin Pop
355 bcf043c9 Iustin Pop
class HostInfo:
356 89e1fc26 Iustin Pop
  """Class implementing resolver and hostname functionality
357 bcf043c9 Iustin Pop

358 bcf043c9 Iustin Pop
  """
359 89e1fc26 Iustin Pop
  def __init__(self, name=None):
360 bcf043c9 Iustin Pop
    """Initialize the host name object.
361 bcf043c9 Iustin Pop

362 89e1fc26 Iustin Pop
    If the name argument is not passed, it will use this system's
363 89e1fc26 Iustin Pop
    name.
364 bcf043c9 Iustin Pop

365 bcf043c9 Iustin Pop
    """
366 89e1fc26 Iustin Pop
    if name is None:
367 89e1fc26 Iustin Pop
      name = self.SysName()
368 89e1fc26 Iustin Pop
369 89e1fc26 Iustin Pop
    self.query = name
370 89e1fc26 Iustin Pop
    self.name, self.aliases, self.ipaddrs = self.LookupHostname(name)
371 bcf043c9 Iustin Pop
    self.ip = self.ipaddrs[0]
372 bcf043c9 Iustin Pop
373 c8a0948f Michael Hanselmann
  def ShortName(self):
374 c8a0948f Michael Hanselmann
    """Returns the hostname without domain.
375 c8a0948f Michael Hanselmann

376 c8a0948f Michael Hanselmann
    """
377 c8a0948f Michael Hanselmann
    return self.name.split('.')[0]
378 c8a0948f Michael Hanselmann
379 89e1fc26 Iustin Pop
  @staticmethod
380 89e1fc26 Iustin Pop
  def SysName():
381 89e1fc26 Iustin Pop
    """Return the current system's name.
382 bcf043c9 Iustin Pop

383 89e1fc26 Iustin Pop
    This is simply a wrapper over socket.gethostname()
384 a8083063 Iustin Pop

385 89e1fc26 Iustin Pop
    """
386 89e1fc26 Iustin Pop
    return socket.gethostname()
387 a8083063 Iustin Pop
388 89e1fc26 Iustin Pop
  @staticmethod
389 89e1fc26 Iustin Pop
  def LookupHostname(hostname):
390 89e1fc26 Iustin Pop
    """Look up hostname
391 a8083063 Iustin Pop

392 89e1fc26 Iustin Pop
    Args:
393 89e1fc26 Iustin Pop
      hostname: hostname to look up
394 89e1fc26 Iustin Pop

395 89e1fc26 Iustin Pop
    Returns:
396 89e1fc26 Iustin Pop
      a tuple (name, aliases, ipaddrs) as returned by socket.gethostbyname_ex
397 89e1fc26 Iustin Pop
      in case of errors in resolving, we raise a ResolverError
398 89e1fc26 Iustin Pop

399 89e1fc26 Iustin Pop
    """
400 89e1fc26 Iustin Pop
    try:
401 89e1fc26 Iustin Pop
      result = socket.gethostbyname_ex(hostname)
402 89e1fc26 Iustin Pop
    except socket.gaierror, err:
403 89e1fc26 Iustin Pop
      # hostname not found in DNS
404 89e1fc26 Iustin Pop
      raise errors.ResolverError(hostname, err.args[0], err.args[1])
405 a8083063 Iustin Pop
406 89e1fc26 Iustin Pop
    return result
407 a8083063 Iustin Pop
408 a8083063 Iustin Pop
409 a8083063 Iustin Pop
def ListVolumeGroups():
410 a8083063 Iustin Pop
  """List volume groups and their size
411 a8083063 Iustin Pop

412 a8083063 Iustin Pop
  Returns:
413 a8083063 Iustin Pop
     Dictionary with keys volume name and values the size of the volume
414 a8083063 Iustin Pop

415 a8083063 Iustin Pop
  """
416 a8083063 Iustin Pop
  command = "vgs --noheadings --units m --nosuffix -o name,size"
417 a8083063 Iustin Pop
  result = RunCmd(command)
418 a8083063 Iustin Pop
  retval = {}
419 a8083063 Iustin Pop
  if result.failed:
420 a8083063 Iustin Pop
    return retval
421 a8083063 Iustin Pop
422 a8083063 Iustin Pop
  for line in result.stdout.splitlines():
423 a8083063 Iustin Pop
    try:
424 a8083063 Iustin Pop
      name, size = line.split()
425 a8083063 Iustin Pop
      size = int(float(size))
426 a8083063 Iustin Pop
    except (IndexError, ValueError), err:
427 bb698c1f Iustin Pop
      logging.error("Invalid output from vgs (%s): %s", err, line)
428 a8083063 Iustin Pop
      continue
429 a8083063 Iustin Pop
430 a8083063 Iustin Pop
    retval[name] = size
431 a8083063 Iustin Pop
432 a8083063 Iustin Pop
  return retval
433 a8083063 Iustin Pop
434 a8083063 Iustin Pop
435 a8083063 Iustin Pop
def BridgeExists(bridge):
436 a8083063 Iustin Pop
  """Check whether the given bridge exists in the system
437 a8083063 Iustin Pop

438 a8083063 Iustin Pop
  Returns:
439 a8083063 Iustin Pop
     True if it does, false otherwise.
440 a8083063 Iustin Pop

441 a8083063 Iustin Pop
  """
442 a8083063 Iustin Pop
  return os.path.isdir("/sys/class/net/%s/bridge" % bridge)
443 a8083063 Iustin Pop
444 a8083063 Iustin Pop
445 a8083063 Iustin Pop
def NiceSort(name_list):
446 a8083063 Iustin Pop
  """Sort a list of strings based on digit and non-digit groupings.
447 a8083063 Iustin Pop

448 a8083063 Iustin Pop
  Given a list of names ['a1', 'a10', 'a11', 'a2'] this function will
449 a8083063 Iustin Pop
  sort the list in the logical order ['a1', 'a2', 'a10', 'a11'].
450 a8083063 Iustin Pop

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

455 a8083063 Iustin Pop
  Return value
456 a8083063 Iustin Pop
    - a copy of the list sorted according to our algorithm
457 a8083063 Iustin Pop

458 a8083063 Iustin Pop
  """
459 a8083063 Iustin Pop
  _SORTER_BASE = "(\D+|\d+)"
460 a8083063 Iustin Pop
  _SORTER_FULL = "^%s%s?%s?%s?%s?%s?%s?%s?.*$" % (_SORTER_BASE, _SORTER_BASE,
461 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE,
462 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE,
463 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE)
464 a8083063 Iustin Pop
  _SORTER_RE = re.compile(_SORTER_FULL)
465 a8083063 Iustin Pop
  _SORTER_NODIGIT = re.compile("^\D*$")
466 a8083063 Iustin Pop
  def _TryInt(val):
467 a8083063 Iustin Pop
    """Attempts to convert a variable to integer."""
468 a8083063 Iustin Pop
    if val is None or _SORTER_NODIGIT.match(val):
469 a8083063 Iustin Pop
      return val
470 a8083063 Iustin Pop
    rval = int(val)
471 a8083063 Iustin Pop
    return rval
472 a8083063 Iustin Pop
473 a8083063 Iustin Pop
  to_sort = [([_TryInt(grp) for grp in _SORTER_RE.match(name).groups()], name)
474 a8083063 Iustin Pop
             for name in name_list]
475 a8083063 Iustin Pop
  to_sort.sort()
476 a8083063 Iustin Pop
  return [tup[1] for tup in to_sort]
477 a8083063 Iustin Pop
478 a8083063 Iustin Pop
479 a8083063 Iustin Pop
def TryConvert(fn, val):
480 a8083063 Iustin Pop
  """Try to convert a value ignoring errors.
481 a8083063 Iustin Pop

482 a8083063 Iustin Pop
  This function tries to apply function `fn` to `val`. If no
483 a8083063 Iustin Pop
  ValueError or TypeError exceptions are raised, it will return the
484 a8083063 Iustin Pop
  result, else it will return the original value. Any other exceptions
485 a8083063 Iustin Pop
  are propagated to the caller.
486 a8083063 Iustin Pop

487 a8083063 Iustin Pop
  """
488 a8083063 Iustin Pop
  try:
489 a8083063 Iustin Pop
    nv = fn(val)
490 a8083063 Iustin Pop
  except (ValueError, TypeError), err:
491 a8083063 Iustin Pop
    nv = val
492 a8083063 Iustin Pop
  return nv
493 a8083063 Iustin Pop
494 a8083063 Iustin Pop
495 a8083063 Iustin Pop
def IsValidIP(ip):
496 a8083063 Iustin Pop
  """Verifies the syntax of an IP address.
497 a8083063 Iustin Pop

498 a8083063 Iustin Pop
  This function checks if the ip address passes is valid or not based
499 a8083063 Iustin Pop
  on syntax (not ip range, class calculations or anything).
500 a8083063 Iustin Pop

501 a8083063 Iustin Pop
  """
502 a8083063 Iustin Pop
  unit = "(0|[1-9]\d{0,2})"
503 a8083063 Iustin Pop
  return re.match("^%s\.%s\.%s\.%s$" % (unit, unit, unit, unit), ip)
504 a8083063 Iustin Pop
505 a8083063 Iustin Pop
506 a8083063 Iustin Pop
def IsValidShellParam(word):
507 a8083063 Iustin Pop
  """Verifies is the given word is safe from the shell's p.o.v.
508 a8083063 Iustin Pop

509 a8083063 Iustin Pop
  This means that we can pass this to a command via the shell and be
510 a8083063 Iustin Pop
  sure that it doesn't alter the command line and is passed as such to
511 a8083063 Iustin Pop
  the actual command.
512 a8083063 Iustin Pop

513 a8083063 Iustin Pop
  Note that we are overly restrictive here, in order to be on the safe
514 a8083063 Iustin Pop
  side.
515 a8083063 Iustin Pop

516 a8083063 Iustin Pop
  """
517 a8083063 Iustin Pop
  return bool(re.match("^[-a-zA-Z0-9._+/:%@]+$", word))
518 a8083063 Iustin Pop
519 a8083063 Iustin Pop
520 a8083063 Iustin Pop
def BuildShellCmd(template, *args):
521 a8083063 Iustin Pop
  """Build a safe shell command line from the given arguments.
522 a8083063 Iustin Pop

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

528 a8083063 Iustin Pop
  """
529 a8083063 Iustin Pop
  for word in args:
530 a8083063 Iustin Pop
    if not IsValidShellParam(word):
531 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Shell argument '%s' contains"
532 3ecf6786 Iustin Pop
                                   " invalid characters" % word)
533 a8083063 Iustin Pop
  return template % args
534 a8083063 Iustin Pop
535 a8083063 Iustin Pop
536 a8083063 Iustin Pop
def FormatUnit(value):
537 a8083063 Iustin Pop
  """Formats an incoming number of MiB with the appropriate unit.
538 a8083063 Iustin Pop

539 a8083063 Iustin Pop
  Value needs to be passed as a numeric type. Return value is always a string.
540 a8083063 Iustin Pop

541 a8083063 Iustin Pop
  """
542 a8083063 Iustin Pop
  if value < 1024:
543 a8083063 Iustin Pop
    return "%dM" % round(value, 0)
544 a8083063 Iustin Pop
545 a8083063 Iustin Pop
  elif value < (1024 * 1024):
546 a8083063 Iustin Pop
    return "%0.1fG" % round(float(value) / 1024, 1)
547 a8083063 Iustin Pop
548 a8083063 Iustin Pop
  else:
549 a8083063 Iustin Pop
    return "%0.1fT" % round(float(value) / 1024 / 1024, 1)
550 a8083063 Iustin Pop
551 a8083063 Iustin Pop
552 a8083063 Iustin Pop
def ParseUnit(input_string):
553 a8083063 Iustin Pop
  """Tries to extract number and scale from the given string.
554 a8083063 Iustin Pop

555 a8083063 Iustin Pop
  Input must be in the format NUMBER+ [DOT NUMBER+] SPACE* [UNIT]. If no unit
556 a8083063 Iustin Pop
  is specified, it defaults to MiB. Return value is always an int in MiB.
557 a8083063 Iustin Pop

558 a8083063 Iustin Pop
  """
559 a8083063 Iustin Pop
  m = re.match('^([.\d]+)\s*([a-zA-Z]+)?$', input_string)
560 a8083063 Iustin Pop
  if not m:
561 3ecf6786 Iustin Pop
    raise errors.UnitParseError("Invalid format")
562 a8083063 Iustin Pop
563 a8083063 Iustin Pop
  value = float(m.groups()[0])
564 a8083063 Iustin Pop
565 a8083063 Iustin Pop
  unit = m.groups()[1]
566 a8083063 Iustin Pop
  if unit:
567 a8083063 Iustin Pop
    lcunit = unit.lower()
568 a8083063 Iustin Pop
  else:
569 a8083063 Iustin Pop
    lcunit = 'm'
570 a8083063 Iustin Pop
571 a8083063 Iustin Pop
  if lcunit in ('m', 'mb', 'mib'):
572 a8083063 Iustin Pop
    # Value already in MiB
573 a8083063 Iustin Pop
    pass
574 a8083063 Iustin Pop
575 a8083063 Iustin Pop
  elif lcunit in ('g', 'gb', 'gib'):
576 a8083063 Iustin Pop
    value *= 1024
577 a8083063 Iustin Pop
578 a8083063 Iustin Pop
  elif lcunit in ('t', 'tb', 'tib'):
579 a8083063 Iustin Pop
    value *= 1024 * 1024
580 a8083063 Iustin Pop
581 a8083063 Iustin Pop
  else:
582 3ecf6786 Iustin Pop
    raise errors.UnitParseError("Unknown unit: %s" % unit)
583 a8083063 Iustin Pop
584 a8083063 Iustin Pop
  # Make sure we round up
585 a8083063 Iustin Pop
  if int(value) < value:
586 a8083063 Iustin Pop
    value += 1
587 a8083063 Iustin Pop
588 a8083063 Iustin Pop
  # Round up to the next multiple of 4
589 a8083063 Iustin Pop
  value = int(value)
590 a8083063 Iustin Pop
  if value % 4:
591 a8083063 Iustin Pop
    value += 4 - value % 4
592 a8083063 Iustin Pop
593 a8083063 Iustin Pop
  return value
594 a8083063 Iustin Pop
595 a8083063 Iustin Pop
596 a8083063 Iustin Pop
def AddAuthorizedKey(file_name, key):
597 a8083063 Iustin Pop
  """Adds an SSH public key to an authorized_keys file.
598 a8083063 Iustin Pop

599 a8083063 Iustin Pop
  Args:
600 a8083063 Iustin Pop
    file_name: Path to authorized_keys file
601 a8083063 Iustin Pop
    key: String containing key
602 a8083063 Iustin Pop
  """
603 a8083063 Iustin Pop
  key_fields = key.split()
604 a8083063 Iustin Pop
605 a8083063 Iustin Pop
  f = open(file_name, 'a+')
606 a8083063 Iustin Pop
  try:
607 a8083063 Iustin Pop
    nl = True
608 a8083063 Iustin Pop
    for line in f:
609 a8083063 Iustin Pop
      # Ignore whitespace changes
610 a8083063 Iustin Pop
      if line.split() == key_fields:
611 a8083063 Iustin Pop
        break
612 a8083063 Iustin Pop
      nl = line.endswith('\n')
613 a8083063 Iustin Pop
    else:
614 a8083063 Iustin Pop
      if not nl:
615 a8083063 Iustin Pop
        f.write("\n")
616 a8083063 Iustin Pop
      f.write(key.rstrip('\r\n'))
617 a8083063 Iustin Pop
      f.write("\n")
618 a8083063 Iustin Pop
      f.flush()
619 a8083063 Iustin Pop
  finally:
620 a8083063 Iustin Pop
    f.close()
621 a8083063 Iustin Pop
622 a8083063 Iustin Pop
623 a8083063 Iustin Pop
def RemoveAuthorizedKey(file_name, key):
624 a8083063 Iustin Pop
  """Removes an SSH public key from an authorized_keys file.
625 a8083063 Iustin Pop

626 a8083063 Iustin Pop
  Args:
627 a8083063 Iustin Pop
    file_name: Path to authorized_keys file
628 a8083063 Iustin Pop
    key: String containing key
629 a8083063 Iustin Pop
  """
630 a8083063 Iustin Pop
  key_fields = key.split()
631 a8083063 Iustin Pop
632 a8083063 Iustin Pop
  fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name))
633 a8083063 Iustin Pop
  try:
634 59f82e3f Michael Hanselmann
    out = os.fdopen(fd, 'w')
635 a8083063 Iustin Pop
    try:
636 59f82e3f Michael Hanselmann
      f = open(file_name, 'r')
637 59f82e3f Michael Hanselmann
      try:
638 59f82e3f Michael Hanselmann
        for line in f:
639 59f82e3f Michael Hanselmann
          # Ignore whitespace changes while comparing lines
640 59f82e3f Michael Hanselmann
          if line.split() != key_fields:
641 59f82e3f Michael Hanselmann
            out.write(line)
642 899d2a81 Michael Hanselmann
643 899d2a81 Michael Hanselmann
        out.flush()
644 899d2a81 Michael Hanselmann
        os.rename(tmpname, file_name)
645 899d2a81 Michael Hanselmann
      finally:
646 899d2a81 Michael Hanselmann
        f.close()
647 899d2a81 Michael Hanselmann
    finally:
648 899d2a81 Michael Hanselmann
      out.close()
649 899d2a81 Michael Hanselmann
  except:
650 899d2a81 Michael Hanselmann
    RemoveFile(tmpname)
651 899d2a81 Michael Hanselmann
    raise
652 899d2a81 Michael Hanselmann
653 899d2a81 Michael Hanselmann
654 9440aeab Michael Hanselmann
def SetEtcHostsEntry(file_name, ip, hostname, aliases):
655 9440aeab Michael Hanselmann
  """Sets the name of an IP address and hostname in /etc/hosts.
656 899d2a81 Michael Hanselmann

657 899d2a81 Michael Hanselmann
  """
658 7fbb1f65 Michael Hanselmann
  # Ensure aliases are unique
659 7fbb1f65 Michael Hanselmann
  aliases = UniqueSequence([hostname] + aliases)[1:]
660 7fbb1f65 Michael Hanselmann
661 9440aeab Michael Hanselmann
  fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name))
662 899d2a81 Michael Hanselmann
  try:
663 9440aeab Michael Hanselmann
    out = os.fdopen(fd, 'w')
664 9440aeab Michael Hanselmann
    try:
665 9440aeab Michael Hanselmann
      f = open(file_name, 'r')
666 9440aeab Michael Hanselmann
      try:
667 9440aeab Michael Hanselmann
        written = False
668 9440aeab Michael Hanselmann
        for line in f:
669 9440aeab Michael Hanselmann
          fields = line.split()
670 7e3dbb94 Iustin Pop
          if fields and not fields[0].startswith('#') and ip == fields[0]:
671 9440aeab Michael Hanselmann
            continue
672 9440aeab Michael Hanselmann
          out.write(line)
673 9440aeab Michael Hanselmann
674 7e3dbb94 Iustin Pop
        out.write("%s\t%s" % (ip, hostname))
675 9440aeab Michael Hanselmann
        if aliases:
676 9440aeab Michael Hanselmann
          out.write(" %s" % ' '.join(aliases))
677 9440aeab Michael Hanselmann
        out.write('\n')
678 9440aeab Michael Hanselmann
679 9440aeab Michael Hanselmann
        out.flush()
680 2e3e75b7 Michael Hanselmann
        os.fsync(out)
681 9440aeab Michael Hanselmann
        os.rename(tmpname, file_name)
682 9440aeab Michael Hanselmann
      finally:
683 9440aeab Michael Hanselmann
        f.close()
684 9440aeab Michael Hanselmann
    finally:
685 9440aeab Michael Hanselmann
      out.close()
686 9440aeab Michael Hanselmann
  except:
687 9440aeab Michael Hanselmann
    RemoveFile(tmpname)
688 9440aeab Michael Hanselmann
    raise
689 899d2a81 Michael Hanselmann
690 899d2a81 Michael Hanselmann
691 d9c02ca6 Michael Hanselmann
def AddHostToEtcHosts(hostname):
692 d9c02ca6 Michael Hanselmann
  """Wrapper around SetEtcHostsEntry.
693 d9c02ca6 Michael Hanselmann

694 d9c02ca6 Michael Hanselmann
  """
695 d9c02ca6 Michael Hanselmann
  hi = HostInfo(name=hostname)
696 d9c02ca6 Michael Hanselmann
  SetEtcHostsEntry(constants.ETC_HOSTS, hi.ip, hi.name, [hi.ShortName()])
697 d9c02ca6 Michael Hanselmann
698 d9c02ca6 Michael Hanselmann
699 899d2a81 Michael Hanselmann
def RemoveEtcHostsEntry(file_name, hostname):
700 3e1cdf9f Michael Hanselmann
  """Removes a hostname from /etc/hosts.
701 899d2a81 Michael Hanselmann

702 9440aeab Michael Hanselmann
  IP addresses without names are removed from the file.
703 899d2a81 Michael Hanselmann
  """
704 899d2a81 Michael Hanselmann
  fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name))
705 899d2a81 Michael Hanselmann
  try:
706 899d2a81 Michael Hanselmann
    out = os.fdopen(fd, 'w')
707 899d2a81 Michael Hanselmann
    try:
708 899d2a81 Michael Hanselmann
      f = open(file_name, 'r')
709 899d2a81 Michael Hanselmann
      try:
710 899d2a81 Michael Hanselmann
        for line in f:
711 899d2a81 Michael Hanselmann
          fields = line.split()
712 899d2a81 Michael Hanselmann
          if len(fields) > 1 and not fields[0].startswith('#'):
713 899d2a81 Michael Hanselmann
            names = fields[1:]
714 899d2a81 Michael Hanselmann
            if hostname in names:
715 899d2a81 Michael Hanselmann
              while hostname in names:
716 899d2a81 Michael Hanselmann
                names.remove(hostname)
717 899d2a81 Michael Hanselmann
              if names:
718 9440aeab Michael Hanselmann
                out.write("%s %s\n" % (fields[0], ' '.join(names)))
719 899d2a81 Michael Hanselmann
              continue
720 899d2a81 Michael Hanselmann
721 899d2a81 Michael Hanselmann
          out.write(line)
722 59f82e3f Michael Hanselmann
723 59f82e3f Michael Hanselmann
        out.flush()
724 2e3e75b7 Michael Hanselmann
        os.fsync(out)
725 59f82e3f Michael Hanselmann
        os.rename(tmpname, file_name)
726 59f82e3f Michael Hanselmann
      finally:
727 59f82e3f Michael Hanselmann
        f.close()
728 a8083063 Iustin Pop
    finally:
729 59f82e3f Michael Hanselmann
      out.close()
730 59f82e3f Michael Hanselmann
  except:
731 59f82e3f Michael Hanselmann
    RemoveFile(tmpname)
732 59f82e3f Michael Hanselmann
    raise
733 a8083063 Iustin Pop
734 a8083063 Iustin Pop
735 d9c02ca6 Michael Hanselmann
def RemoveHostFromEtcHosts(hostname):
736 d9c02ca6 Michael Hanselmann
  """Wrapper around RemoveEtcHostsEntry.
737 d9c02ca6 Michael Hanselmann

738 d9c02ca6 Michael Hanselmann
  """
739 d9c02ca6 Michael Hanselmann
  hi = HostInfo(name=hostname)
740 d9c02ca6 Michael Hanselmann
  RemoveEtcHostsEntry(constants.ETC_HOSTS, hi.name)
741 d9c02ca6 Michael Hanselmann
  RemoveEtcHostsEntry(constants.ETC_HOSTS, hi.ShortName())
742 d9c02ca6 Michael Hanselmann
743 d9c02ca6 Michael Hanselmann
744 a8083063 Iustin Pop
def CreateBackup(file_name):
745 a8083063 Iustin Pop
  """Creates a backup of a file.
746 a8083063 Iustin Pop

747 a8083063 Iustin Pop
  Returns: the path to the newly created backup file.
748 a8083063 Iustin Pop

749 a8083063 Iustin Pop
  """
750 a8083063 Iustin Pop
  if not os.path.isfile(file_name):
751 3ecf6786 Iustin Pop
    raise errors.ProgrammerError("Can't make a backup of a non-file '%s'" %
752 3ecf6786 Iustin Pop
                                file_name)
753 a8083063 Iustin Pop
754 081b1e69 Michael Hanselmann
  prefix = '%s.backup-%d.' % (os.path.basename(file_name), int(time.time()))
755 65fe4693 Iustin Pop
  dir_name = os.path.dirname(file_name)
756 081b1e69 Michael Hanselmann
757 081b1e69 Michael Hanselmann
  fsrc = open(file_name, 'rb')
758 081b1e69 Michael Hanselmann
  try:
759 65fe4693 Iustin Pop
    (fd, backup_name) = tempfile.mkstemp(prefix=prefix, dir=dir_name)
760 081b1e69 Michael Hanselmann
    fdst = os.fdopen(fd, 'wb')
761 081b1e69 Michael Hanselmann
    try:
762 081b1e69 Michael Hanselmann
      shutil.copyfileobj(fsrc, fdst)
763 081b1e69 Michael Hanselmann
    finally:
764 081b1e69 Michael Hanselmann
      fdst.close()
765 081b1e69 Michael Hanselmann
  finally:
766 081b1e69 Michael Hanselmann
    fsrc.close()
767 081b1e69 Michael Hanselmann
768 a8083063 Iustin Pop
  return backup_name
769 a8083063 Iustin Pop
770 a8083063 Iustin Pop
771 a8083063 Iustin Pop
def ShellQuote(value):
772 a8083063 Iustin Pop
  """Quotes shell argument according to POSIX.
773 3ecf6786 Iustin Pop

774 a8083063 Iustin Pop
  """
775 a8083063 Iustin Pop
  if _re_shell_unquoted.match(value):
776 a8083063 Iustin Pop
    return value
777 a8083063 Iustin Pop
  else:
778 a8083063 Iustin Pop
    return "'%s'" % value.replace("'", "'\\''")
779 a8083063 Iustin Pop
780 a8083063 Iustin Pop
781 a8083063 Iustin Pop
def ShellQuoteArgs(args):
782 a8083063 Iustin Pop
  """Quotes all given shell arguments and concatenates using spaces.
783 a8083063 Iustin Pop

784 a8083063 Iustin Pop
  """
785 a8083063 Iustin Pop
  return ' '.join([ShellQuote(i) for i in args])
786 88d14415 Michael Hanselmann
787 88d14415 Michael Hanselmann
788 b15d625f Iustin Pop
def TcpPing(target, port, timeout=10, live_port_needed=False, source=None):
789 2c30e9d7 Alexander Schreiber
  """Simple ping implementation using TCP connect(2).
790 2c30e9d7 Alexander Schreiber

791 b15d625f Iustin Pop
  Try to do a TCP connect(2) from an optional source IP to the
792 b15d625f Iustin Pop
  specified target IP and the specified target port. If the optional
793 b15d625f Iustin Pop
  parameter live_port_needed is set to true, requires the remote end
794 b15d625f Iustin Pop
  to accept the connection. The timeout is specified in seconds and
795 b15d625f Iustin Pop
  defaults to 10 seconds. If the source optional argument is not
796 b15d625f Iustin Pop
  passed, the source address selection is left to the kernel,
797 b15d625f Iustin Pop
  otherwise we try to connect using the passed address (failures to
798 b15d625f Iustin Pop
  bind other than EADDRNOTAVAIL will be ignored).
799 2c30e9d7 Alexander Schreiber

800 2c30e9d7 Alexander Schreiber
  """
801 2c30e9d7 Alexander Schreiber
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
802 2c30e9d7 Alexander Schreiber
803 2c30e9d7 Alexander Schreiber
  sucess = False
804 2c30e9d7 Alexander Schreiber
805 b15d625f Iustin Pop
  if source is not None:
806 b15d625f Iustin Pop
    try:
807 b15d625f Iustin Pop
      sock.bind((source, 0))
808 b15d625f Iustin Pop
    except socket.error, (errcode, errstring):
809 b15d625f Iustin Pop
      if errcode == errno.EADDRNOTAVAIL:
810 b15d625f Iustin Pop
        success = False
811 2c30e9d7 Alexander Schreiber
812 2c30e9d7 Alexander Schreiber
  sock.settimeout(timeout)
813 2c30e9d7 Alexander Schreiber
814 2c30e9d7 Alexander Schreiber
  try:
815 2c30e9d7 Alexander Schreiber
    sock.connect((target, port))
816 2c30e9d7 Alexander Schreiber
    sock.close()
817 2c30e9d7 Alexander Schreiber
    success = True
818 2c30e9d7 Alexander Schreiber
  except socket.timeout:
819 2c30e9d7 Alexander Schreiber
    success = False
820 2c30e9d7 Alexander Schreiber
  except socket.error, (errcode, errstring):
821 4ca1b175 Alexander Schreiber
    success = (not live_port_needed) and (errcode == errno.ECONNREFUSED)
822 2c30e9d7 Alexander Schreiber
823 2c30e9d7 Alexander Schreiber
  return success
824 eedbda4b Michael Hanselmann
825 eedbda4b Michael Hanselmann
826 eedbda4b Michael Hanselmann
def ListVisibleFiles(path):
827 eedbda4b Michael Hanselmann
  """Returns a list of all visible files in a directory.
828 eedbda4b Michael Hanselmann

829 eedbda4b Michael Hanselmann
  """
830 f3299a07 Michael Hanselmann
  files = [i for i in os.listdir(path) if not i.startswith(".")]
831 f3299a07 Michael Hanselmann
  files.sort()
832 f3299a07 Michael Hanselmann
  return files
833 2f8b60b3 Iustin Pop
834 2f8b60b3 Iustin Pop
835 257f4c0a Iustin Pop
def GetHomeDir(user, default=None):
836 257f4c0a Iustin Pop
  """Try to get the homedir of the given user.
837 257f4c0a Iustin Pop

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

842 2f8b60b3 Iustin Pop
  """
843 2f8b60b3 Iustin Pop
  try:
844 257f4c0a Iustin Pop
    if isinstance(user, basestring):
845 257f4c0a Iustin Pop
      result = pwd.getpwnam(user)
846 257f4c0a Iustin Pop
    elif isinstance(user, (int, long)):
847 257f4c0a Iustin Pop
      result = pwd.getpwuid(user)
848 257f4c0a Iustin Pop
    else:
849 257f4c0a Iustin Pop
      raise errors.ProgrammerError("Invalid type passed to GetHomeDir (%s)" %
850 257f4c0a Iustin Pop
                                   type(user))
851 2f8b60b3 Iustin Pop
  except KeyError:
852 2f8b60b3 Iustin Pop
    return default
853 2f8b60b3 Iustin Pop
  return result.pw_dir
854 59072e7e Michael Hanselmann
855 59072e7e Michael Hanselmann
856 24818e8f Michael Hanselmann
def NewUUID():
857 59072e7e Michael Hanselmann
  """Returns a random UUID.
858 59072e7e Michael Hanselmann

859 59072e7e Michael Hanselmann
  """
860 59072e7e Michael Hanselmann
  f = open("/proc/sys/kernel/random/uuid", "r")
861 59072e7e Michael Hanselmann
  try:
862 59072e7e Michael Hanselmann
    return f.read(128).rstrip("\n")
863 59072e7e Michael Hanselmann
  finally:
864 59072e7e Michael Hanselmann
    f.close()
865 087b34fe Iustin Pop
866 087b34fe Iustin Pop
867 ca0aa6d0 Michael Hanselmann
def ReadFile(file_name, size=None):
868 ca0aa6d0 Michael Hanselmann
  """Reads a file.
869 ca0aa6d0 Michael Hanselmann

870 ca0aa6d0 Michael Hanselmann
  @type size: None or int
871 ca0aa6d0 Michael Hanselmann
  @param size: Read at most size bytes
872 ca0aa6d0 Michael Hanselmann

873 ca0aa6d0 Michael Hanselmann
  """
874 ca0aa6d0 Michael Hanselmann
  f = open(file_name, "r")
875 ca0aa6d0 Michael Hanselmann
  try:
876 ca0aa6d0 Michael Hanselmann
    if size is None:
877 ca0aa6d0 Michael Hanselmann
      return f.read()
878 ca0aa6d0 Michael Hanselmann
    else:
879 ca0aa6d0 Michael Hanselmann
      return f.read(size)
880 ca0aa6d0 Michael Hanselmann
  finally:
881 ca0aa6d0 Michael Hanselmann
    f.close()
882 ca0aa6d0 Michael Hanselmann
883 ca0aa6d0 Michael Hanselmann
884 087b34fe Iustin Pop
def WriteFile(file_name, fn=None, data=None,
885 087b34fe Iustin Pop
              mode=None, uid=-1, gid=-1,
886 71714516 Michael Hanselmann
              atime=None, mtime=None, close=True,
887 04a8d789 Michael Hanselmann
              dry_run=False, backup=False,
888 71714516 Michael Hanselmann
              prewrite=None, postwrite=None):
889 087b34fe Iustin Pop
  """(Over)write a file atomically.
890 087b34fe Iustin Pop

891 087b34fe Iustin Pop
  The file_name and either fn (a function taking one argument, the
892 087b34fe Iustin Pop
  file descriptor, and which should write the data to it) or data (the
893 087b34fe Iustin Pop
  contents of the file) must be passed. The other arguments are
894 087b34fe Iustin Pop
  optional and allow setting the file mode, owner and group, and the
895 087b34fe Iustin Pop
  mtime/atime of the file.
896 087b34fe Iustin Pop

897 087b34fe Iustin Pop
  If the function doesn't raise an exception, it has succeeded and the
898 087b34fe Iustin Pop
  target file has the new contents. If the file has raised an
899 087b34fe Iustin Pop
  exception, an existing target file should be unmodified and the
900 087b34fe Iustin Pop
  temporary file should be removed.
901 087b34fe Iustin Pop

902 71714516 Michael Hanselmann
  Args:
903 71714516 Michael Hanselmann
    file_name: New filename
904 71714516 Michael Hanselmann
    fn: Content writing function, called with file descriptor as parameter
905 71714516 Michael Hanselmann
    data: Content as string
906 71714516 Michael Hanselmann
    mode: File mode
907 71714516 Michael Hanselmann
    uid: Owner
908 71714516 Michael Hanselmann
    gid: Group
909 71714516 Michael Hanselmann
    atime: Access time
910 71714516 Michael Hanselmann
    mtime: Modification time
911 71714516 Michael Hanselmann
    close: Whether to close file after writing it
912 71714516 Michael Hanselmann
    prewrite: Function object called before writing content
913 71714516 Michael Hanselmann
    postwrite: Function object called after writing content
914 71714516 Michael Hanselmann

915 71714516 Michael Hanselmann
  Returns:
916 71714516 Michael Hanselmann
    None if "close" parameter evaluates to True, otherwise file descriptor.
917 71714516 Michael Hanselmann

918 087b34fe Iustin Pop
  """
919 04a8d789 Michael Hanselmann
  if not os.path.isabs(file_name):
920 087b34fe Iustin Pop
    raise errors.ProgrammerError("Path passed to WriteFile is not"
921 087b34fe Iustin Pop
                                 " absolute: '%s'" % file_name)
922 087b34fe Iustin Pop
923 087b34fe Iustin Pop
  if [fn, data].count(None) != 1:
924 087b34fe Iustin Pop
    raise errors.ProgrammerError("fn or data required")
925 087b34fe Iustin Pop
926 087b34fe Iustin Pop
  if [atime, mtime].count(None) == 1:
927 087b34fe Iustin Pop
    raise errors.ProgrammerError("Both atime and mtime must be either"
928 087b34fe Iustin Pop
                                 " set or None")
929 087b34fe Iustin Pop
930 70f4497c Michael Hanselmann
  if backup and not dry_run and os.path.isfile(file_name):
931 70f4497c Michael Hanselmann
    CreateBackup(file_name)
932 087b34fe Iustin Pop
933 087b34fe Iustin Pop
  dir_name, base_name = os.path.split(file_name)
934 087b34fe Iustin Pop
  fd, new_name = tempfile.mkstemp('.new', base_name, dir_name)
935 087b34fe Iustin Pop
  # here we need to make sure we remove the temp file, if any error
936 087b34fe Iustin Pop
  # leaves it in place
937 087b34fe Iustin Pop
  try:
938 087b34fe Iustin Pop
    if uid != -1 or gid != -1:
939 087b34fe Iustin Pop
      os.chown(new_name, uid, gid)
940 087b34fe Iustin Pop
    if mode:
941 087b34fe Iustin Pop
      os.chmod(new_name, mode)
942 71714516 Michael Hanselmann
    if callable(prewrite):
943 71714516 Michael Hanselmann
      prewrite(fd)
944 087b34fe Iustin Pop
    if data is not None:
945 087b34fe Iustin Pop
      os.write(fd, data)
946 087b34fe Iustin Pop
    else:
947 087b34fe Iustin Pop
      fn(fd)
948 71714516 Michael Hanselmann
    if callable(postwrite):
949 71714516 Michael Hanselmann
      postwrite(fd)
950 087b34fe Iustin Pop
    os.fsync(fd)
951 087b34fe Iustin Pop
    if atime is not None and mtime is not None:
952 087b34fe Iustin Pop
      os.utime(new_name, (atime, mtime))
953 70f4497c Michael Hanselmann
    if not dry_run:
954 70f4497c Michael Hanselmann
      os.rename(new_name, file_name)
955 087b34fe Iustin Pop
  finally:
956 71714516 Michael Hanselmann
    if close:
957 71714516 Michael Hanselmann
      os.close(fd)
958 71714516 Michael Hanselmann
      result = None
959 71714516 Michael Hanselmann
    else:
960 71714516 Michael Hanselmann
      result = fd
961 087b34fe Iustin Pop
    RemoveFile(new_name)
962 78feb6fb Guido Trotter
963 71714516 Michael Hanselmann
  return result
964 71714516 Michael Hanselmann
965 78feb6fb Guido Trotter
966 7b4126b7 Iustin Pop
def FirstFree(seq, base=0):
967 7b4126b7 Iustin Pop
  """Returns the first non-existing integer from seq.
968 7b4126b7 Iustin Pop

969 7b4126b7 Iustin Pop
  The seq argument should be a sorted list of positive integers. The
970 7b4126b7 Iustin Pop
  first time the index of an element is smaller than the element
971 7b4126b7 Iustin Pop
  value, the index will be returned.
972 7b4126b7 Iustin Pop

973 7b4126b7 Iustin Pop
  The base argument is used to start at a different offset,
974 7b4126b7 Iustin Pop
  i.e. [3, 4, 6] with offset=3 will return 5.
975 7b4126b7 Iustin Pop

976 7b4126b7 Iustin Pop
  Example: [0, 1, 3] will return 2.
977 7b4126b7 Iustin Pop

978 7b4126b7 Iustin Pop
  """
979 7b4126b7 Iustin Pop
  for idx, elem in enumerate(seq):
980 7b4126b7 Iustin Pop
    assert elem >= base, "Passed element is higher than base offset"
981 7b4126b7 Iustin Pop
    if elem > idx + base:
982 7b4126b7 Iustin Pop
      # idx is not used
983 7b4126b7 Iustin Pop
      return idx + base
984 7b4126b7 Iustin Pop
  return None
985 7b4126b7 Iustin Pop
986 7b4126b7 Iustin Pop
987 78feb6fb Guido Trotter
def all(seq, pred=bool):
988 78feb6fb Guido Trotter
  "Returns True if pred(x) is True for every element in the iterable"
989 78feb6fb Guido Trotter
  for elem in itertools.ifilterfalse(pred, seq):
990 78feb6fb Guido Trotter
    return False
991 78feb6fb Guido Trotter
  return True
992 78feb6fb Guido Trotter
993 78feb6fb Guido Trotter
994 78feb6fb Guido Trotter
def any(seq, pred=bool):
995 78feb6fb Guido Trotter
  "Returns True if pred(x) is True for at least one element in the iterable"
996 78feb6fb Guido Trotter
  for elem in itertools.ifilter(pred, seq):
997 78feb6fb Guido Trotter
    return True
998 78feb6fb Guido Trotter
  return False
999 f7414041 Michael Hanselmann
1000 f7414041 Michael Hanselmann
1001 f7414041 Michael Hanselmann
def UniqueSequence(seq):
1002 f7414041 Michael Hanselmann
  """Returns a list with unique elements.
1003 f7414041 Michael Hanselmann

1004 f7414041 Michael Hanselmann
  Element order is preserved.
1005 f7414041 Michael Hanselmann
  """
1006 f7414041 Michael Hanselmann
  seen = set()
1007 f7414041 Michael Hanselmann
  return [i for i in seq if i not in seen and not seen.add(i)]
1008 1862d460 Alexander Schreiber
1009 1862d460 Alexander Schreiber
1010 1862d460 Alexander Schreiber
def IsValidMac(mac):
1011 1862d460 Alexander Schreiber
  """Predicate to check if a MAC address is valid.
1012 1862d460 Alexander Schreiber

1013 1862d460 Alexander Schreiber
  Checks wether the supplied MAC address is formally correct, only
1014 1862d460 Alexander Schreiber
  accepts colon separated format.
1015 1862d460 Alexander Schreiber
  """
1016 1862d460 Alexander Schreiber
  mac_check = re.compile("^([0-9a-f]{2}(:|$)){6}$")
1017 1862d460 Alexander Schreiber
  return mac_check.match(mac) is not None
1018 06009e27 Iustin Pop
1019 06009e27 Iustin Pop
1020 06009e27 Iustin Pop
def TestDelay(duration):
1021 06009e27 Iustin Pop
  """Sleep for a fixed amount of time.
1022 06009e27 Iustin Pop

1023 06009e27 Iustin Pop
  """
1024 06009e27 Iustin Pop
  if duration < 0:
1025 06009e27 Iustin Pop
    return False
1026 06009e27 Iustin Pop
  time.sleep(duration)
1027 06009e27 Iustin Pop
  return True
1028 8f765069 Iustin Pop
1029 8f765069 Iustin Pop
1030 8ff612c2 Iustin Pop
def Daemonize(logfile, noclose_fds=None):
1031 8f765069 Iustin Pop
  """Daemonize the current process.
1032 8f765069 Iustin Pop

1033 8f765069 Iustin Pop
  This detaches the current process from the controlling terminal and
1034 8f765069 Iustin Pop
  runs it in the background as a daemon.
1035 8f765069 Iustin Pop

1036 8f765069 Iustin Pop
  """
1037 8f765069 Iustin Pop
  UMASK = 077
1038 8f765069 Iustin Pop
  WORKDIR = "/"
1039 8f765069 Iustin Pop
  # Default maximum for the number of available file descriptors.
1040 8f765069 Iustin Pop
  if 'SC_OPEN_MAX' in os.sysconf_names:
1041 8f765069 Iustin Pop
    try:
1042 8f765069 Iustin Pop
      MAXFD = os.sysconf('SC_OPEN_MAX')
1043 8f765069 Iustin Pop
      if MAXFD < 0:
1044 8f765069 Iustin Pop
        MAXFD = 1024
1045 8f765069 Iustin Pop
    except OSError:
1046 8f765069 Iustin Pop
      MAXFD = 1024
1047 8f765069 Iustin Pop
  else:
1048 8f765069 Iustin Pop
    MAXFD = 1024
1049 8f765069 Iustin Pop
1050 8f765069 Iustin Pop
  # this might fail
1051 8f765069 Iustin Pop
  pid = os.fork()
1052 8f765069 Iustin Pop
  if (pid == 0):  # The first child.
1053 8f765069 Iustin Pop
    os.setsid()
1054 8f765069 Iustin Pop
    # this might fail
1055 8f765069 Iustin Pop
    pid = os.fork() # Fork a second child.
1056 8f765069 Iustin Pop
    if (pid == 0):  # The second child.
1057 8f765069 Iustin Pop
      os.chdir(WORKDIR)
1058 8f765069 Iustin Pop
      os.umask(UMASK)
1059 8f765069 Iustin Pop
    else:
1060 8f765069 Iustin Pop
      # exit() or _exit()?  See below.
1061 8f765069 Iustin Pop
      os._exit(0) # Exit parent (the first child) of the second child.
1062 8f765069 Iustin Pop
  else:
1063 8f765069 Iustin Pop
    os._exit(0) # Exit parent of the first child.
1064 8f765069 Iustin Pop
  maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
1065 8f765069 Iustin Pop
  if (maxfd == resource.RLIM_INFINITY):
1066 8f765069 Iustin Pop
    maxfd = MAXFD
1067 8f765069 Iustin Pop
1068 8f765069 Iustin Pop
  # Iterate through and close all file descriptors.
1069 8f765069 Iustin Pop
  for fd in range(0, maxfd):
1070 8ff612c2 Iustin Pop
    if noclose_fds and fd in noclose_fds:
1071 8ff612c2 Iustin Pop
      continue
1072 8f765069 Iustin Pop
    try:
1073 8f765069 Iustin Pop
      os.close(fd)
1074 8f765069 Iustin Pop
    except OSError: # ERROR, fd wasn't open to begin with (ignored)
1075 8f765069 Iustin Pop
      pass
1076 8f765069 Iustin Pop
  os.open(logfile, os.O_RDWR|os.O_CREAT|os.O_APPEND, 0600)
1077 8f765069 Iustin Pop
  # Duplicate standard input to standard output and standard error.
1078 8f765069 Iustin Pop
  os.dup2(0, 1)     # standard output (1)
1079 8f765069 Iustin Pop
  os.dup2(0, 2)     # standard error (2)
1080 8f765069 Iustin Pop
  return 0
1081 57c177af Iustin Pop
1082 57c177af Iustin Pop
1083 53beffbb Iustin Pop
def DaemonPidFileName(name):
1084 b330ac0b Guido Trotter
  """Compute a ganeti pid file absolute path, given the daemon name.
1085 b330ac0b Guido Trotter

1086 b330ac0b Guido Trotter
  """
1087 b330ac0b Guido Trotter
  return os.path.join(constants.RUN_GANETI_DIR, "%s.pid" % name)
1088 b330ac0b Guido Trotter
1089 b330ac0b Guido Trotter
1090 b330ac0b Guido Trotter
def WritePidFile(name):
1091 b330ac0b Guido Trotter
  """Write the current process pidfile.
1092 b330ac0b Guido Trotter

1093 b330ac0b Guido Trotter
  The file will be written to constants.RUN_GANETI_DIR/name.pid
1094 b330ac0b Guido Trotter

1095 b330ac0b Guido Trotter
  """
1096 b330ac0b Guido Trotter
  pid = os.getpid()
1097 53beffbb Iustin Pop
  pidfilename = DaemonPidFileName(name)
1098 d9f311d7 Iustin Pop
  if IsProcessAlive(ReadPidFile(pidfilename)):
1099 533bb4b1 Michael Hanselmann
    raise errors.GenericError("%s contains a live process" % pidfilename)
1100 b330ac0b Guido Trotter
1101 b330ac0b Guido Trotter
  WriteFile(pidfilename, data="%d\n" % pid)
1102 b330ac0b Guido Trotter
1103 b330ac0b Guido Trotter
1104 b330ac0b Guido Trotter
def RemovePidFile(name):
1105 b330ac0b Guido Trotter
  """Remove the current process pidfile.
1106 b330ac0b Guido Trotter

1107 b330ac0b Guido Trotter
  Any errors are ignored.
1108 b330ac0b Guido Trotter

1109 b330ac0b Guido Trotter
  """
1110 b330ac0b Guido Trotter
  pid = os.getpid()
1111 53beffbb Iustin Pop
  pidfilename = DaemonPidFileName(name)
1112 b330ac0b Guido Trotter
  # TODO: we could check here that the file contains our pid
1113 b330ac0b Guido Trotter
  try:
1114 b330ac0b Guido Trotter
    RemoveFile(pidfilename)
1115 b330ac0b Guido Trotter
  except:
1116 b330ac0b Guido Trotter
    pass
1117 b330ac0b Guido Trotter
1118 b330ac0b Guido Trotter
1119 38206f3c Iustin Pop
def KillProcess(pid, signal_=signal.SIGTERM, timeout=30):
1120 b2a1f511 Iustin Pop
  """Kill a process given by its pid.
1121 b2a1f511 Iustin Pop

1122 b2a1f511 Iustin Pop
  @type pid: int
1123 b2a1f511 Iustin Pop
  @param pid: The PID to terminate.
1124 38206f3c Iustin Pop
  @type signal_: int
1125 38206f3c Iustin Pop
  @param signal_: The signal to send, by default SIGTERM
1126 b2a1f511 Iustin Pop
  @type timeout: int
1127 b2a1f511 Iustin Pop
  @param timeout: The timeout after which, if the process is still alive,
1128 b2a1f511 Iustin Pop
                  a SIGKILL will be sent. If not positive, no such checking
1129 b2a1f511 Iustin Pop
                  will be done
1130 b2a1f511 Iustin Pop

1131 b2a1f511 Iustin Pop
  """
1132 b2a1f511 Iustin Pop
  if pid <= 0:
1133 b2a1f511 Iustin Pop
    # kill with pid=0 == suicide
1134 b2a1f511 Iustin Pop
    raise errors.ProgrammerError("Invalid pid given '%s'" % pid)
1135 b2a1f511 Iustin Pop
1136 b2a1f511 Iustin Pop
  if not IsProcessAlive(pid):
1137 b2a1f511 Iustin Pop
    return
1138 38206f3c Iustin Pop
  os.kill(pid, signal_)
1139 b2a1f511 Iustin Pop
  if timeout <= 0:
1140 b2a1f511 Iustin Pop
    return
1141 b2a1f511 Iustin Pop
  end = time.time() + timeout
1142 b2a1f511 Iustin Pop
  while time.time() < end and IsProcessAlive(pid):
1143 b2a1f511 Iustin Pop
    time.sleep(0.1)
1144 b2a1f511 Iustin Pop
  if IsProcessAlive(pid):
1145 b2a1f511 Iustin Pop
    os.kill(pid, signal.SIGKILL)
1146 b2a1f511 Iustin Pop
1147 b2a1f511 Iustin Pop
1148 57c177af Iustin Pop
def FindFile(name, search_path, test=os.path.exists):
1149 57c177af Iustin Pop
  """Look for a filesystem object in a given path.
1150 57c177af Iustin Pop

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

1154 57c177af Iustin Pop
  Args:
1155 57c177af Iustin Pop
    - name: the name to look for
1156 57c177af Iustin Pop
    - search_path: list of directory names
1157 57c177af Iustin Pop
    - test: the test which the full path must satisfy
1158 57c177af Iustin Pop
      (defaults to os.path.exists)
1159 57c177af Iustin Pop

1160 57c177af Iustin Pop
  Returns:
1161 57c177af Iustin Pop
    - full path to the item if found
1162 57c177af Iustin Pop
    - None otherwise
1163 57c177af Iustin Pop

1164 57c177af Iustin Pop
  """
1165 57c177af Iustin Pop
  for dir_name in search_path:
1166 57c177af Iustin Pop
    item_name = os.path.sep.join([dir_name, name])
1167 57c177af Iustin Pop
    if test(item_name):
1168 57c177af Iustin Pop
      return item_name
1169 57c177af Iustin Pop
  return None
1170 8d1a2a64 Michael Hanselmann
1171 8d1a2a64 Michael Hanselmann
1172 8d1a2a64 Michael Hanselmann
def CheckVolumeGroupSize(vglist, vgname, minsize):
1173 8d1a2a64 Michael Hanselmann
  """Checks if the volume group list is valid.
1174 8d1a2a64 Michael Hanselmann

1175 8d1a2a64 Michael Hanselmann
  A non-None return value means there's an error, and the return value
1176 8d1a2a64 Michael Hanselmann
  is the error message.
1177 8d1a2a64 Michael Hanselmann

1178 8d1a2a64 Michael Hanselmann
  """
1179 8d1a2a64 Michael Hanselmann
  vgsize = vglist.get(vgname, None)
1180 8d1a2a64 Michael Hanselmann
  if vgsize is None:
1181 8d1a2a64 Michael Hanselmann
    return "volume group '%s' missing" % vgname
1182 8d1a2a64 Michael Hanselmann
  elif vgsize < minsize:
1183 8d1a2a64 Michael Hanselmann
    return ("volume group '%s' too small (%s MiB required, %d MiB found)" %
1184 8d1a2a64 Michael Hanselmann
            (vgname, minsize, vgsize))
1185 8d1a2a64 Michael Hanselmann
  return None
1186 7996a135 Iustin Pop
1187 7996a135 Iustin Pop
1188 45bc5e4a Michael Hanselmann
def SplitTime(value):
1189 739be818 Michael Hanselmann
  """Splits time as floating point number into a tuple.
1190 739be818 Michael Hanselmann

1191 45bc5e4a Michael Hanselmann
  @param value: Time in seconds
1192 45bc5e4a Michael Hanselmann
  @type value: int or float
1193 45bc5e4a Michael Hanselmann
  @return: Tuple containing (seconds, microseconds)
1194 739be818 Michael Hanselmann

1195 739be818 Michael Hanselmann
  """
1196 45bc5e4a Michael Hanselmann
  (seconds, microseconds) = divmod(int(value * 1000000), 1000000)
1197 45bc5e4a Michael Hanselmann
1198 45bc5e4a Michael Hanselmann
  assert 0 <= seconds, \
1199 45bc5e4a Michael Hanselmann
    "Seconds must be larger than or equal to 0, but are %s" % seconds
1200 45bc5e4a Michael Hanselmann
  assert 0 <= microseconds <= 999999, \
1201 45bc5e4a Michael Hanselmann
    "Microseconds must be 0-999999, but are %s" % microseconds
1202 45bc5e4a Michael Hanselmann
1203 45bc5e4a Michael Hanselmann
  return (int(seconds), int(microseconds))
1204 739be818 Michael Hanselmann
1205 739be818 Michael Hanselmann
1206 739be818 Michael Hanselmann
def MergeTime(timetuple):
1207 739be818 Michael Hanselmann
  """Merges a tuple into time as a floating point number.
1208 739be818 Michael Hanselmann

1209 45bc5e4a Michael Hanselmann
  @param timetuple: Time as tuple, (seconds, microseconds)
1210 739be818 Michael Hanselmann
  @type timetuple: tuple
1211 739be818 Michael Hanselmann
  @return: Time as a floating point number expressed in seconds
1212 739be818 Michael Hanselmann

1213 739be818 Michael Hanselmann
  """
1214 45bc5e4a Michael Hanselmann
  (seconds, microseconds) = timetuple
1215 739be818 Michael Hanselmann
1216 45bc5e4a Michael Hanselmann
  assert 0 <= seconds, \
1217 45bc5e4a Michael Hanselmann
    "Seconds must be larger than or equal to 0, but are %s" % seconds
1218 45bc5e4a Michael Hanselmann
  assert 0 <= microseconds <= 999999, \
1219 45bc5e4a Michael Hanselmann
    "Microseconds must be 0-999999, but are %s" % microseconds
1220 739be818 Michael Hanselmann
1221 45bc5e4a Michael Hanselmann
  return float(seconds) + (float(microseconds) * 0.000001)
1222 739be818 Michael Hanselmann
1223 739be818 Michael Hanselmann
1224 7996a135 Iustin Pop
def LockedMethod(fn):
1225 7996a135 Iustin Pop
  """Synchronized object access decorator.
1226 7996a135 Iustin Pop

1227 7996a135 Iustin Pop
  This decorator is intended to protect access to an object using the
1228 7996a135 Iustin Pop
  object's own lock which is hardcoded to '_lock'.
1229 7996a135 Iustin Pop

1230 7996a135 Iustin Pop
  """
1231 e67bd559 Michael Hanselmann
  def _LockDebug(*args, **kwargs):
1232 e67bd559 Michael Hanselmann
    if debug_locks:
1233 e67bd559 Michael Hanselmann
      logging.debug(*args, **kwargs)
1234 e67bd559 Michael Hanselmann
1235 7996a135 Iustin Pop
  def wrapper(self, *args, **kwargs):
1236 7996a135 Iustin Pop
    assert hasattr(self, '_lock')
1237 7996a135 Iustin Pop
    lock = self._lock
1238 e67bd559 Michael Hanselmann
    _LockDebug("Waiting for %s", lock)
1239 7996a135 Iustin Pop
    lock.acquire()
1240 7996a135 Iustin Pop
    try:
1241 e67bd559 Michael Hanselmann
      _LockDebug("Acquired %s", lock)
1242 7996a135 Iustin Pop
      result = fn(self, *args, **kwargs)
1243 7996a135 Iustin Pop
    finally:
1244 e67bd559 Michael Hanselmann
      _LockDebug("Releasing %s", lock)
1245 7996a135 Iustin Pop
      lock.release()
1246 e67bd559 Michael Hanselmann
      _LockDebug("Released %s", lock)
1247 7996a135 Iustin Pop
    return result
1248 7996a135 Iustin Pop
  return wrapper
1249 eb0f0ce0 Michael Hanselmann
1250 eb0f0ce0 Michael Hanselmann
1251 eb0f0ce0 Michael Hanselmann
def LockFile(fd):
1252 eb0f0ce0 Michael Hanselmann
  """Locks a file using POSIX locks.
1253 eb0f0ce0 Michael Hanselmann

1254 eb0f0ce0 Michael Hanselmann
  """
1255 eb0f0ce0 Michael Hanselmann
  try:
1256 eb0f0ce0 Michael Hanselmann
    fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
1257 eb0f0ce0 Michael Hanselmann
  except IOError, err:
1258 eb0f0ce0 Michael Hanselmann
    if err.errno == errno.EAGAIN:
1259 eb0f0ce0 Michael Hanselmann
      raise errors.LockError("File already locked")
1260 eb0f0ce0 Michael Hanselmann
    raise
1261 de499029 Michael Hanselmann
1262 de499029 Michael Hanselmann
1263 a87b4824 Michael Hanselmann
class FileLock(object):
1264 a87b4824 Michael Hanselmann
  """Utility class for file locks.
1265 a87b4824 Michael Hanselmann

1266 a87b4824 Michael Hanselmann
  """
1267 a87b4824 Michael Hanselmann
  def __init__(self, filename):
1268 a87b4824 Michael Hanselmann
    self.filename = filename
1269 a87b4824 Michael Hanselmann
    self.fd = open(self.filename, "w")
1270 a87b4824 Michael Hanselmann
1271 a87b4824 Michael Hanselmann
  def __del__(self):
1272 a87b4824 Michael Hanselmann
    self.Close()
1273 a87b4824 Michael Hanselmann
1274 a87b4824 Michael Hanselmann
  def Close(self):
1275 a87b4824 Michael Hanselmann
    if self.fd:
1276 a87b4824 Michael Hanselmann
      self.fd.close()
1277 a87b4824 Michael Hanselmann
      self.fd = None
1278 a87b4824 Michael Hanselmann
1279 aa74b828 Michael Hanselmann
  def _flock(self, flag, blocking, timeout, errmsg):
1280 aa74b828 Michael Hanselmann
    """Wrapper for fcntl.flock.
1281 aa74b828 Michael Hanselmann

1282 aa74b828 Michael Hanselmann
    @type flag: int
1283 aa74b828 Michael Hanselmann
    @param flag: Operation flag
1284 aa74b828 Michael Hanselmann
    @type blocking: bool
1285 aa74b828 Michael Hanselmann
    @param blocking: Whether the operation should be done in blocking mode.
1286 aa74b828 Michael Hanselmann
    @type timeout: None or float
1287 aa74b828 Michael Hanselmann
    @param timeout: For how long the operation should be retried (implies
1288 aa74b828 Michael Hanselmann
                    non-blocking mode).
1289 aa74b828 Michael Hanselmann
    @type errmsg: string
1290 aa74b828 Michael Hanselmann
    @param errmsg: Error message in case operation fails.
1291 aa74b828 Michael Hanselmann

1292 aa74b828 Michael Hanselmann
    """
1293 a87b4824 Michael Hanselmann
    assert self.fd, "Lock was closed"
1294 aa74b828 Michael Hanselmann
    assert timeout is None or timeout >= 0, \
1295 aa74b828 Michael Hanselmann
      "If specified, timeout must be positive"
1296 a87b4824 Michael Hanselmann
1297 aa74b828 Michael Hanselmann
    if timeout is not None:
1298 a87b4824 Michael Hanselmann
      flag |= fcntl.LOCK_NB
1299 aa74b828 Michael Hanselmann
      timeout_end = time.time() + timeout
1300 a87b4824 Michael Hanselmann
1301 aa74b828 Michael Hanselmann
    # Blocking doesn't have effect with timeout
1302 aa74b828 Michael Hanselmann
    elif not blocking:
1303 aa74b828 Michael Hanselmann
      flag |= fcntl.LOCK_NB
1304 aa74b828 Michael Hanselmann
      timeout_end = None
1305 aa74b828 Michael Hanselmann
1306 aa74b828 Michael Hanselmann
    retry = True
1307 aa74b828 Michael Hanselmann
    while retry:
1308 aa74b828 Michael Hanselmann
      try:
1309 aa74b828 Michael Hanselmann
        fcntl.flock(self.fd, flag)
1310 aa74b828 Michael Hanselmann
        retry = False
1311 aa74b828 Michael Hanselmann
      except IOError, err:
1312 aa74b828 Michael Hanselmann
        if err.errno in (errno.EAGAIN, ):
1313 aa74b828 Michael Hanselmann
          if timeout_end is not None and time.time() < timeout_end:
1314 aa74b828 Michael Hanselmann
            # Wait before trying again
1315 aa74b828 Michael Hanselmann
            time.sleep(max(0.1, min(1.0, timeout)))
1316 aa74b828 Michael Hanselmann
          else:
1317 aa74b828 Michael Hanselmann
            raise errors.LockError(errmsg)
1318 aa74b828 Michael Hanselmann
        else:
1319 aa74b828 Michael Hanselmann
          logging.exception("fcntl.flock failed")
1320 aa74b828 Michael Hanselmann
          raise
1321 aa74b828 Michael Hanselmann
1322 aa74b828 Michael Hanselmann
  def Exclusive(self, blocking=False, timeout=None):
1323 a87b4824 Michael Hanselmann
    """Locks the file in exclusive mode.
1324 a87b4824 Michael Hanselmann

1325 a87b4824 Michael Hanselmann
    """
1326 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_EX, blocking, timeout,
1327 a87b4824 Michael Hanselmann
                "Failed to lock %s in exclusive mode" % self.filename)
1328 a87b4824 Michael Hanselmann
1329 aa74b828 Michael Hanselmann
  def Shared(self, blocking=False, timeout=None):
1330 a87b4824 Michael Hanselmann
    """Locks the file in shared mode.
1331 a87b4824 Michael Hanselmann

1332 a87b4824 Michael Hanselmann
    """
1333 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_SH, blocking, timeout,
1334 a87b4824 Michael Hanselmann
                "Failed to lock %s in shared mode" % self.filename)
1335 a87b4824 Michael Hanselmann
1336 aa74b828 Michael Hanselmann
  def Unlock(self, blocking=True, timeout=None):
1337 a87b4824 Michael Hanselmann
    """Unlocks the file.
1338 a87b4824 Michael Hanselmann

1339 a87b4824 Michael Hanselmann
    According to "man flock", unlocking can also be a nonblocking operation:
1340 a87b4824 Michael Hanselmann
    "To make a non-blocking request, include LOCK_NB with any of the above
1341 a87b4824 Michael Hanselmann
    operations"
1342 a87b4824 Michael Hanselmann

1343 a87b4824 Michael Hanselmann
    """
1344 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_UN, blocking, timeout,
1345 a87b4824 Michael Hanselmann
                "Failed to unlock %s" % self.filename)
1346 a87b4824 Michael Hanselmann
1347 a87b4824 Michael Hanselmann
1348 de499029 Michael Hanselmann
class SignalHandler(object):
1349 de499029 Michael Hanselmann
  """Generic signal handler class.
1350 de499029 Michael Hanselmann

1351 de499029 Michael Hanselmann
  It automatically restores the original handler when deconstructed or when
1352 de499029 Michael Hanselmann
  Reset() is called. You can either pass your own handler function in or query
1353 de499029 Michael Hanselmann
  the "called" attribute to detect whether the signal was sent.
1354 de499029 Michael Hanselmann

1355 de499029 Michael Hanselmann
  """
1356 de499029 Michael Hanselmann
  def __init__(self, signum):
1357 de499029 Michael Hanselmann
    """Constructs a new SignalHandler instance.
1358 de499029 Michael Hanselmann

1359 de499029 Michael Hanselmann
    @param signum: Single signal number or set of signal numbers
1360 de499029 Michael Hanselmann

1361 de499029 Michael Hanselmann
    """
1362 de499029 Michael Hanselmann
    if isinstance(signum, (int, long)):
1363 de499029 Michael Hanselmann
      self.signum = set([signum])
1364 de499029 Michael Hanselmann
    else:
1365 de499029 Michael Hanselmann
      self.signum = set(signum)
1366 de499029 Michael Hanselmann
1367 de499029 Michael Hanselmann
    self.called = False
1368 de499029 Michael Hanselmann
1369 de499029 Michael Hanselmann
    self._previous = {}
1370 de499029 Michael Hanselmann
    try:
1371 de499029 Michael Hanselmann
      for signum in self.signum:
1372 de499029 Michael Hanselmann
        # Setup handler
1373 de499029 Michael Hanselmann
        prev_handler = signal.signal(signum, self._HandleSignal)
1374 de499029 Michael Hanselmann
        try:
1375 de499029 Michael Hanselmann
          self._previous[signum] = prev_handler
1376 de499029 Michael Hanselmann
        except:
1377 de499029 Michael Hanselmann
          # Restore previous handler
1378 de499029 Michael Hanselmann
          signal.signal(signum, prev_handler)
1379 de499029 Michael Hanselmann
          raise
1380 de499029 Michael Hanselmann
    except:
1381 de499029 Michael Hanselmann
      # Reset all handlers
1382 de499029 Michael Hanselmann
      self.Reset()
1383 de499029 Michael Hanselmann
      # Here we have a race condition: a handler may have already been called,
1384 de499029 Michael Hanselmann
      # but there's not much we can do about it at this point.
1385 de499029 Michael Hanselmann
      raise
1386 de499029 Michael Hanselmann
1387 de499029 Michael Hanselmann
  def __del__(self):
1388 de499029 Michael Hanselmann
    self.Reset()
1389 de499029 Michael Hanselmann
1390 de499029 Michael Hanselmann
  def Reset(self):
1391 de499029 Michael Hanselmann
    """Restore previous handler.
1392 de499029 Michael Hanselmann

1393 de499029 Michael Hanselmann
    """
1394 de499029 Michael Hanselmann
    for signum, prev_handler in self._previous.items():
1395 de499029 Michael Hanselmann
      signal.signal(signum, prev_handler)
1396 de499029 Michael Hanselmann
      # If successful, remove from dict
1397 de499029 Michael Hanselmann
      del self._previous[signum]
1398 de499029 Michael Hanselmann
1399 de499029 Michael Hanselmann
  def Clear(self):
1400 de499029 Michael Hanselmann
    """Unsets "called" flag.
1401 de499029 Michael Hanselmann

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

1404 de499029 Michael Hanselmann
    """
1405 de499029 Michael Hanselmann
    self.called = False
1406 de499029 Michael Hanselmann
1407 de499029 Michael Hanselmann
  def _HandleSignal(self, signum, frame):
1408 de499029 Michael Hanselmann
    """Actual signal handling function.
1409 de499029 Michael Hanselmann

1410 de499029 Michael Hanselmann
    """
1411 de499029 Michael Hanselmann
    # This is not nice and not absolutely atomic, but it appears to be the only
1412 de499029 Michael Hanselmann
    # solution in Python -- there are no atomic types.
1413 de499029 Michael Hanselmann
    self.called = True