| Branch: | Tag: | Revision:

root / lib / @ 8b3fd458

History | View | Annotate | Download (36.7 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
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
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
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
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
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
140 113b55aa Iustin Pop
141 113b55aa Iustin Pop
142 2557ff82 Guido Trotter
                           close_fds=True, env=cmd_env)
143 113b55aa Iustin Pop
144 113b55aa Iustin Pop
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
164 9c233417 Iustin Pop
          del fdmap[fd]
165 9c233417 Iustin Pop
166 9c233417 Iustin Pop
167 9c233417 Iustin Pop
      if (event & select.POLLNVAL or event & select.POLLHUP or
168 9c233417 Iustin Pop
          event & select.POLLERR):
169 9c233417 Iustin Pop
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
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
194 a8083063 Iustin Pop
195 a8083063 Iustin Pop
  except OSError, err:
196 4ca1b175 Alexander Schreiber
    if err.errno not in (errno.ENOENT, errno.EISDIR):
197 a8083063 Iustin Pop
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
205 a8083063 Iustin Pop

206 a8083063 Iustin Pop
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 =
218 a8083063 Iustin Pop
    if not data:
219 a8083063 Iustin Pop
220 a8083063 Iustin Pop
221 a8083063 Iustin Pop
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
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
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
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
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
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
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
299 a8083063 Iustin Pop
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
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
322 fee80e90 Guido Trotter
    pid = int(
323 d9f311d7 Iustin Pop
  except ValueError, err:
324 8161a646 Iustin Pop"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 ['', '', ...]. 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 ['', '']).
338 a8083063 Iustin Pop

339 a8083063 Iustin Pop
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
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
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.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
378 c8a0948f Michael Hanselmann
379 89e1fc26 Iustin Pop
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
389 89e1fc26 Iustin Pop
  def LookupHostname(hostname):
390 89e1fc26 Iustin Pop
    """Look up hostname
391 a8083063 Iustin Pop

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

395 89e1fc26 Iustin Pop
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
612 a8083063 Iustin Pop
      nl = line.endswith('\n')
613 a8083063 Iustin Pop
614 a8083063 Iustin Pop
      if not nl:
615 a8083063 Iustin Pop
616 a8083063 Iustin Pop
617 a8083063 Iustin Pop
618 a8083063 Iustin Pop
619 a8083063 Iustin Pop
620 a8083063 Iustin Pop
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
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
634 59f82e3f Michael Hanselmann
    out = os.fdopen(fd, 'w')
635 a8083063 Iustin Pop
636 59f82e3f Michael Hanselmann
      f = open(file_name, 'r')
637 59f82e3f Michael Hanselmann
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
642 899d2a81 Michael Hanselmann
643 899d2a81 Michael Hanselmann
644 899d2a81 Michael Hanselmann
        os.rename(tmpname, file_name)
645 899d2a81 Michael Hanselmann
646 899d2a81 Michael Hanselmann
647 899d2a81 Michael Hanselmann
648 899d2a81 Michael Hanselmann
649 899d2a81 Michael Hanselmann
650 899d2a81 Michael Hanselmann
651 899d2a81 Michael Hanselmann
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
663 9440aeab Michael Hanselmann
    out = os.fdopen(fd, 'w')
664 9440aeab Michael Hanselmann
665 9440aeab Michael Hanselmann
      f = open(file_name, 'r')
666 9440aeab Michael Hanselmann
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
672 9440aeab Michael Hanselmann
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
678 9440aeab Michael Hanselmann
679 9440aeab Michael Hanselmann
680 2e3e75b7 Michael Hanselmann
681 9440aeab Michael Hanselmann
        os.rename(tmpname, file_name)
682 9440aeab Michael Hanselmann
683 9440aeab Michael Hanselmann
684 9440aeab Michael Hanselmann
685 9440aeab Michael Hanselmann
686 9440aeab Michael Hanselmann
687 9440aeab Michael Hanselmann
688 9440aeab Michael Hanselmann
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.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
706 899d2a81 Michael Hanselmann
    out = os.fdopen(fd, 'w')
707 899d2a81 Michael Hanselmann
708 899d2a81 Michael Hanselmann
      f = open(file_name, 'r')
709 899d2a81 Michael Hanselmann
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
717 899d2a81 Michael Hanselmann
              if names:
718 9440aeab Michael Hanselmann
                out.write("%s %s\n" % (fields[0], ' '.join(names)))
719 899d2a81 Michael Hanselmann
720 899d2a81 Michael Hanselmann
721 899d2a81 Michael Hanselmann
722 59f82e3f Michael Hanselmann
723 59f82e3f Michael Hanselmann
724 2e3e75b7 Michael Hanselmann
725 59f82e3f Michael Hanselmann
        os.rename(tmpname, file_name)
726 59f82e3f Michael Hanselmann
727 59f82e3f Michael Hanselmann
728 a8083063 Iustin Pop
729 59f82e3f Michael Hanselmann
730 59f82e3f Michael Hanselmann
731 59f82e3f Michael Hanselmann
732 59f82e3f Michael Hanselmann
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
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
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
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
762 081b1e69 Michael Hanselmann
      shutil.copyfileobj(fsrc, fdst)
763 081b1e69 Michael Hanselmann
764 081b1e69 Michael Hanselmann
765 081b1e69 Michael Hanselmann
766 081b1e69 Michael Hanselmann
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
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
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
813 2c30e9d7 Alexander Schreiber
814 2c30e9d7 Alexander Schreiber
815 2c30e9d7 Alexander Schreiber
    sock.connect((target, port))
816 2c30e9d7 Alexander Schreiber
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 caad16e2 Iustin Pop
def OwnIpAddress(address):
827 caad16e2 Iustin Pop
  """Check if the current host has the the given IP address.
828 caad16e2 Iustin Pop

829 caad16e2 Iustin Pop
  Currently this is done by tcp-pinging the address from the loopback
830 caad16e2 Iustin Pop
831 caad16e2 Iustin Pop

832 caad16e2 Iustin Pop
  @type address: string
833 caad16e2 Iustin Pop
  @param address: the addres to check
834 caad16e2 Iustin Pop
  @rtype: bool
835 caad16e2 Iustin Pop

836 caad16e2 Iustin Pop
837 caad16e2 Iustin Pop
  return TcpPing(address, constants.DEFAULT_NODED_PORT,
838 caad16e2 Iustin Pop
839 caad16e2 Iustin Pop
840 caad16e2 Iustin Pop
841 eedbda4b Michael Hanselmann
def ListVisibleFiles(path):
842 eedbda4b Michael Hanselmann
  """Returns a list of all visible files in a directory.
843 eedbda4b Michael Hanselmann

844 eedbda4b Michael Hanselmann
845 f3299a07 Michael Hanselmann
  files = [i for i in os.listdir(path) if not i.startswith(".")]
846 f3299a07 Michael Hanselmann
847 f3299a07 Michael Hanselmann
  return files
848 2f8b60b3 Iustin Pop
849 2f8b60b3 Iustin Pop
850 257f4c0a Iustin Pop
def GetHomeDir(user, default=None):
851 257f4c0a Iustin Pop
  """Try to get the homedir of the given user.
852 257f4c0a Iustin Pop

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

857 2f8b60b3 Iustin Pop
858 2f8b60b3 Iustin Pop
859 257f4c0a Iustin Pop
    if isinstance(user, basestring):
860 257f4c0a Iustin Pop
      result = pwd.getpwnam(user)
861 257f4c0a Iustin Pop
    elif isinstance(user, (int, long)):
862 257f4c0a Iustin Pop
      result = pwd.getpwuid(user)
863 257f4c0a Iustin Pop
864 257f4c0a Iustin Pop
      raise errors.ProgrammerError("Invalid type passed to GetHomeDir (%s)" %
865 257f4c0a Iustin Pop
866 2f8b60b3 Iustin Pop
  except KeyError:
867 2f8b60b3 Iustin Pop
    return default
868 2f8b60b3 Iustin Pop
  return result.pw_dir
869 59072e7e Michael Hanselmann
870 59072e7e Michael Hanselmann
871 24818e8f Michael Hanselmann
def NewUUID():
872 59072e7e Michael Hanselmann
  """Returns a random UUID.
873 59072e7e Michael Hanselmann

874 59072e7e Michael Hanselmann
875 59072e7e Michael Hanselmann
  f = open("/proc/sys/kernel/random/uuid", "r")
876 59072e7e Michael Hanselmann
877 59072e7e Michael Hanselmann
878 59072e7e Michael Hanselmann
879 59072e7e Michael Hanselmann
880 087b34fe Iustin Pop
881 087b34fe Iustin Pop
882 33081d90 Iustin Pop
def GenerateSecret():
883 33081d90 Iustin Pop
  """Generates a random secret.
884 33081d90 Iustin Pop

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

888 33081d90 Iustin Pop
889 33081d90 Iustin Pop
890 33081d90 Iustin Pop
891 33081d90 Iustin Pop
892 ca0aa6d0 Michael Hanselmann
def ReadFile(file_name, size=None):
893 ca0aa6d0 Michael Hanselmann
  """Reads a file.
894 ca0aa6d0 Michael Hanselmann

895 ca0aa6d0 Michael Hanselmann
  @type size: None or int
896 ca0aa6d0 Michael Hanselmann
  @param size: Read at most size bytes
897 ca0aa6d0 Michael Hanselmann

898 ca0aa6d0 Michael Hanselmann
899 ca0aa6d0 Michael Hanselmann
  f = open(file_name, "r")
900 ca0aa6d0 Michael Hanselmann
901 ca0aa6d0 Michael Hanselmann
    if size is None:
902 ca0aa6d0 Michael Hanselmann
903 ca0aa6d0 Michael Hanselmann
904 ca0aa6d0 Michael Hanselmann
905 ca0aa6d0 Michael Hanselmann
906 ca0aa6d0 Michael Hanselmann
907 ca0aa6d0 Michael Hanselmann
908 ca0aa6d0 Michael Hanselmann
909 087b34fe Iustin Pop
def WriteFile(file_name, fn=None, data=None,
910 087b34fe Iustin Pop
              mode=None, uid=-1, gid=-1,
911 71714516 Michael Hanselmann
              atime=None, mtime=None, close=True,
912 04a8d789 Michael Hanselmann
              dry_run=False, backup=False,
913 71714516 Michael Hanselmann
              prewrite=None, postwrite=None):
914 087b34fe Iustin Pop
  """(Over)write a file atomically.
915 087b34fe Iustin Pop

916 087b34fe Iustin Pop
  The file_name and either fn (a function taking one argument, the
917 087b34fe Iustin Pop
  file descriptor, and which should write the data to it) or data (the
918 087b34fe Iustin Pop
  contents of the file) must be passed. The other arguments are
919 087b34fe Iustin Pop
  optional and allow setting the file mode, owner and group, and the
920 087b34fe Iustin Pop
  mtime/atime of the file.
921 087b34fe Iustin Pop

922 087b34fe Iustin Pop
  If the function doesn't raise an exception, it has succeeded and the
923 087b34fe Iustin Pop
  target file has the new contents. If the file has raised an
924 087b34fe Iustin Pop
  exception, an existing target file should be unmodified and the
925 087b34fe Iustin Pop
  temporary file should be removed.
926 087b34fe Iustin Pop

927 71714516 Michael Hanselmann
928 71714516 Michael Hanselmann
    file_name: New filename
929 71714516 Michael Hanselmann
    fn: Content writing function, called with file descriptor as parameter
930 71714516 Michael Hanselmann
    data: Content as string
931 71714516 Michael Hanselmann
    mode: File mode
932 71714516 Michael Hanselmann
    uid: Owner
933 71714516 Michael Hanselmann
    gid: Group
934 71714516 Michael Hanselmann
    atime: Access time
935 71714516 Michael Hanselmann
    mtime: Modification time
936 71714516 Michael Hanselmann
    close: Whether to close file after writing it
937 71714516 Michael Hanselmann
    prewrite: Function object called before writing content
938 71714516 Michael Hanselmann
    postwrite: Function object called after writing content
939 71714516 Michael Hanselmann

940 71714516 Michael Hanselmann
941 71714516 Michael Hanselmann
    None if "close" parameter evaluates to True, otherwise file descriptor.
942 71714516 Michael Hanselmann

943 087b34fe Iustin Pop
944 04a8d789 Michael Hanselmann
  if not os.path.isabs(file_name):
945 087b34fe Iustin Pop
    raise errors.ProgrammerError("Path passed to WriteFile is not"
946 087b34fe Iustin Pop
                                 " absolute: '%s'" % file_name)
947 087b34fe Iustin Pop
948 087b34fe Iustin Pop
  if [fn, data].count(None) != 1:
949 087b34fe Iustin Pop
    raise errors.ProgrammerError("fn or data required")
950 087b34fe Iustin Pop
951 087b34fe Iustin Pop
  if [atime, mtime].count(None) == 1:
952 087b34fe Iustin Pop
    raise errors.ProgrammerError("Both atime and mtime must be either"
953 087b34fe Iustin Pop
                                 " set or None")
954 087b34fe Iustin Pop
955 70f4497c Michael Hanselmann
  if backup and not dry_run and os.path.isfile(file_name):
956 70f4497c Michael Hanselmann
957 087b34fe Iustin Pop
958 087b34fe Iustin Pop
  dir_name, base_name = os.path.split(file_name)
959 087b34fe Iustin Pop
  fd, new_name = tempfile.mkstemp('.new', base_name, dir_name)
960 087b34fe Iustin Pop
  # here we need to make sure we remove the temp file, if any error
961 087b34fe Iustin Pop
  # leaves it in place
962 087b34fe Iustin Pop
963 087b34fe Iustin Pop
    if uid != -1 or gid != -1:
964 087b34fe Iustin Pop
      os.chown(new_name, uid, gid)
965 087b34fe Iustin Pop
    if mode:
966 087b34fe Iustin Pop
      os.chmod(new_name, mode)
967 71714516 Michael Hanselmann
    if callable(prewrite):
968 71714516 Michael Hanselmann
969 087b34fe Iustin Pop
    if data is not None:
970 087b34fe Iustin Pop
      os.write(fd, data)
971 087b34fe Iustin Pop
972 087b34fe Iustin Pop
973 71714516 Michael Hanselmann
    if callable(postwrite):
974 71714516 Michael Hanselmann
975 087b34fe Iustin Pop
976 087b34fe Iustin Pop
    if atime is not None and mtime is not None:
977 087b34fe Iustin Pop
      os.utime(new_name, (atime, mtime))
978 70f4497c Michael Hanselmann
    if not dry_run:
979 70f4497c Michael Hanselmann
      os.rename(new_name, file_name)
980 087b34fe Iustin Pop
981 71714516 Michael Hanselmann
    if close:
982 71714516 Michael Hanselmann
983 71714516 Michael Hanselmann
      result = None
984 71714516 Michael Hanselmann
985 71714516 Michael Hanselmann
      result = fd
986 087b34fe Iustin Pop
987 78feb6fb Guido Trotter
988 71714516 Michael Hanselmann
  return result
989 71714516 Michael Hanselmann
990 78feb6fb Guido Trotter
991 7b4126b7 Iustin Pop
def FirstFree(seq, base=0):
992 7b4126b7 Iustin Pop
  """Returns the first non-existing integer from seq.
993 7b4126b7 Iustin Pop

994 7b4126b7 Iustin Pop
  The seq argument should be a sorted list of positive integers. The
995 7b4126b7 Iustin Pop
  first time the index of an element is smaller than the element
996 7b4126b7 Iustin Pop
  value, the index will be returned.
997 7b4126b7 Iustin Pop

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

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

1003 7b4126b7 Iustin Pop
1004 7b4126b7 Iustin Pop
  for idx, elem in enumerate(seq):
1005 7b4126b7 Iustin Pop
    assert elem >= base, "Passed element is higher than base offset"
1006 7b4126b7 Iustin Pop
    if elem > idx + base:
1007 7b4126b7 Iustin Pop
      # idx is not used
1008 7b4126b7 Iustin Pop
      return idx + base
1009 7b4126b7 Iustin Pop
  return None
1010 7b4126b7 Iustin Pop
1011 7b4126b7 Iustin Pop
1012 78feb6fb Guido Trotter
def all(seq, pred=bool):
1013 78feb6fb Guido Trotter
  "Returns True if pred(x) is True for every element in the iterable"
1014 78feb6fb Guido Trotter
  for elem in itertools.ifilterfalse(pred, seq):
1015 78feb6fb Guido Trotter
    return False
1016 78feb6fb Guido Trotter
  return True
1017 78feb6fb Guido Trotter
1018 78feb6fb Guido Trotter
1019 78feb6fb Guido Trotter
def any(seq, pred=bool):
1020 78feb6fb Guido Trotter
  "Returns True if pred(x) is True for at least one element in the iterable"
1021 78feb6fb Guido Trotter
  for elem in itertools.ifilter(pred, seq):
1022 78feb6fb Guido Trotter
    return True
1023 78feb6fb Guido Trotter
  return False
1024 f7414041 Michael Hanselmann
1025 f7414041 Michael Hanselmann
1026 f7414041 Michael Hanselmann
def UniqueSequence(seq):
1027 f7414041 Michael Hanselmann
  """Returns a list with unique elements.
1028 f7414041 Michael Hanselmann

1029 f7414041 Michael Hanselmann
  Element order is preserved.
1030 f7414041 Michael Hanselmann
1031 f7414041 Michael Hanselmann
  seen = set()
1032 f7414041 Michael Hanselmann
  return [i for i in seq if i not in seen and not seen.add(i)]
1033 1862d460 Alexander Schreiber
1034 1862d460 Alexander Schreiber
1035 1862d460 Alexander Schreiber
def IsValidMac(mac):
1036 1862d460 Alexander Schreiber
  """Predicate to check if a MAC address is valid.
1037 1862d460 Alexander Schreiber

1038 1862d460 Alexander Schreiber
  Checks wether the supplied MAC address is formally correct, only
1039 1862d460 Alexander Schreiber
  accepts colon separated format.
1040 1862d460 Alexander Schreiber
1041 1862d460 Alexander Schreiber
  mac_check = re.compile("^([0-9a-f]{2}(:|$)){6}$")
1042 1862d460 Alexander Schreiber
  return mac_check.match(mac) is not None
1043 06009e27 Iustin Pop
1044 06009e27 Iustin Pop
1045 06009e27 Iustin Pop
def TestDelay(duration):
1046 06009e27 Iustin Pop
  """Sleep for a fixed amount of time.
1047 06009e27 Iustin Pop

1048 06009e27 Iustin Pop
1049 06009e27 Iustin Pop
  if duration < 0:
1050 06009e27 Iustin Pop
    return False
1051 06009e27 Iustin Pop
1052 06009e27 Iustin Pop
  return True
1053 8f765069 Iustin Pop
1054 8f765069 Iustin Pop
1055 8ff612c2 Iustin Pop
def Daemonize(logfile, noclose_fds=None):
1056 8f765069 Iustin Pop
  """Daemonize the current process.
1057 8f765069 Iustin Pop

1058 8f765069 Iustin Pop
  This detaches the current process from the controlling terminal and
1059 8f765069 Iustin Pop
  runs it in the background as a daemon.
1060 8f765069 Iustin Pop

1061 8f765069 Iustin Pop
1062 8f765069 Iustin Pop
  UMASK = 077
1063 8f765069 Iustin Pop
  WORKDIR = "/"
1064 8f765069 Iustin Pop
  # Default maximum for the number of available file descriptors.
1065 8f765069 Iustin Pop
  if 'SC_OPEN_MAX' in os.sysconf_names:
1066 8f765069 Iustin Pop
1067 8f765069 Iustin Pop
      MAXFD = os.sysconf('SC_OPEN_MAX')
1068 8f765069 Iustin Pop
      if MAXFD < 0:
1069 8f765069 Iustin Pop
        MAXFD = 1024
1070 8f765069 Iustin Pop
    except OSError:
1071 8f765069 Iustin Pop
      MAXFD = 1024
1072 8f765069 Iustin Pop
1073 8f765069 Iustin Pop
    MAXFD = 1024
1074 8f765069 Iustin Pop
1075 8f765069 Iustin Pop
  # this might fail
1076 8f765069 Iustin Pop
  pid = os.fork()
1077 8f765069 Iustin Pop
  if (pid == 0):  # The first child.
1078 8f765069 Iustin Pop
1079 8f765069 Iustin Pop
    # this might fail
1080 8f765069 Iustin Pop
    pid = os.fork() # Fork a second child.
1081 8f765069 Iustin Pop
    if (pid == 0):  # The second child.
1082 8f765069 Iustin Pop
1083 8f765069 Iustin Pop
1084 8f765069 Iustin Pop
1085 8f765069 Iustin Pop
      # exit() or _exit()?  See below.
1086 8f765069 Iustin Pop
      os._exit(0) # Exit parent (the first child) of the second child.
1087 8f765069 Iustin Pop
1088 8f765069 Iustin Pop
    os._exit(0) # Exit parent of the first child.
1089 8f765069 Iustin Pop
  maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
1090 8f765069 Iustin Pop
  if (maxfd == resource.RLIM_INFINITY):
1091 8f765069 Iustin Pop
    maxfd = MAXFD
1092 8f765069 Iustin Pop
1093 8f765069 Iustin Pop
  # Iterate through and close all file descriptors.
1094 8f765069 Iustin Pop
  for fd in range(0, maxfd):
1095 8ff612c2 Iustin Pop
    if noclose_fds and fd in noclose_fds:
1096 8ff612c2 Iustin Pop
1097 8f765069 Iustin Pop
1098 8f765069 Iustin Pop
1099 8f765069 Iustin Pop
    except OSError: # ERROR, fd wasn't open to begin with (ignored)
1100 8f765069 Iustin Pop
1101 8f765069 Iustin Pop, os.O_RDWR|os.O_CREAT|os.O_APPEND, 0600)
1102 8f765069 Iustin Pop
  # Duplicate standard input to standard output and standard error.
1103 8f765069 Iustin Pop
  os.dup2(0, 1)     # standard output (1)
1104 8f765069 Iustin Pop
  os.dup2(0, 2)     # standard error (2)
1105 8f765069 Iustin Pop
  return 0
1106 57c177af Iustin Pop
1107 57c177af Iustin Pop
1108 53beffbb Iustin Pop
def DaemonPidFileName(name):
1109 b330ac0b Guido Trotter
  """Compute a ganeti pid file absolute path, given the daemon name.
1110 b330ac0b Guido Trotter

1111 b330ac0b Guido Trotter
1112 b330ac0b Guido Trotter
  return os.path.join(constants.RUN_GANETI_DIR, "" % name)
1113 b330ac0b Guido Trotter
1114 b330ac0b Guido Trotter
1115 b330ac0b Guido Trotter
def WritePidFile(name):
1116 b330ac0b Guido Trotter
  """Write the current process pidfile.
1117 b330ac0b Guido Trotter

1118 b330ac0b Guido Trotter
  The file will be written to constants.RUN_GANETI_DIR/
1119 b330ac0b Guido Trotter

1120 b330ac0b Guido Trotter
1121 b330ac0b Guido Trotter
  pid = os.getpid()
1122 53beffbb Iustin Pop
  pidfilename = DaemonPidFileName(name)
1123 d9f311d7 Iustin Pop
  if IsProcessAlive(ReadPidFile(pidfilename)):
1124 533bb4b1 Michael Hanselmann
    raise errors.GenericError("%s contains a live process" % pidfilename)
1125 b330ac0b Guido Trotter
1126 b330ac0b Guido Trotter
  WriteFile(pidfilename, data="%d\n" % pid)
1127 b330ac0b Guido Trotter
1128 b330ac0b Guido Trotter
1129 b330ac0b Guido Trotter
def RemovePidFile(name):
1130 b330ac0b Guido Trotter
  """Remove the current process pidfile.
1131 b330ac0b Guido Trotter

1132 b330ac0b Guido Trotter
  Any errors are ignored.
1133 b330ac0b Guido Trotter

1134 b330ac0b Guido Trotter
1135 b330ac0b Guido Trotter
  pid = os.getpid()
1136 53beffbb Iustin Pop
  pidfilename = DaemonPidFileName(name)
1137 b330ac0b Guido Trotter
  # TODO: we could check here that the file contains our pid
1138 b330ac0b Guido Trotter
1139 b330ac0b Guido Trotter
1140 b330ac0b Guido Trotter
1141 b330ac0b Guido Trotter
1142 b330ac0b Guido Trotter
1143 b330ac0b Guido Trotter
1144 38206f3c Iustin Pop
def KillProcess(pid, signal_=signal.SIGTERM, timeout=30):
1145 b2a1f511 Iustin Pop
  """Kill a process given by its pid.
1146 b2a1f511 Iustin Pop

1147 b2a1f511 Iustin Pop
  @type pid: int
1148 b2a1f511 Iustin Pop
  @param pid: The PID to terminate.
1149 38206f3c Iustin Pop
  @type signal_: int
1150 38206f3c Iustin Pop
  @param signal_: The signal to send, by default SIGTERM
1151 b2a1f511 Iustin Pop
  @type timeout: int
1152 b2a1f511 Iustin Pop
  @param timeout: The timeout after which, if the process is still alive,
1153 b2a1f511 Iustin Pop
                  a SIGKILL will be sent. If not positive, no such checking
1154 b2a1f511 Iustin Pop
                  will be done
1155 b2a1f511 Iustin Pop

1156 b2a1f511 Iustin Pop
1157 b2a1f511 Iustin Pop
  if pid <= 0:
1158 b2a1f511 Iustin Pop
    # kill with pid=0 == suicide
1159 b2a1f511 Iustin Pop
    raise errors.ProgrammerError("Invalid pid given '%s'" % pid)
1160 b2a1f511 Iustin Pop
1161 b2a1f511 Iustin Pop
  if not IsProcessAlive(pid):
1162 b2a1f511 Iustin Pop
1163 38206f3c Iustin Pop
  os.kill(pid, signal_)
1164 b2a1f511 Iustin Pop
  if timeout <= 0:
1165 b2a1f511 Iustin Pop
1166 b2a1f511 Iustin Pop
  end = time.time() + timeout
1167 b2a1f511 Iustin Pop
  while time.time() < end and IsProcessAlive(pid):
1168 b2a1f511 Iustin Pop
1169 b2a1f511 Iustin Pop
  if IsProcessAlive(pid):
1170 b2a1f511 Iustin Pop
    os.kill(pid, signal.SIGKILL)
1171 b2a1f511 Iustin Pop
1172 b2a1f511 Iustin Pop
1173 57c177af Iustin Pop
def FindFile(name, search_path, test=os.path.exists):
1174 57c177af Iustin Pop
  """Look for a filesystem object in a given path.
1175 57c177af Iustin Pop

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

1179 57c177af Iustin Pop
1180 57c177af Iustin Pop
    - name: the name to look for
1181 57c177af Iustin Pop
    - search_path: list of directory names
1182 57c177af Iustin Pop
    - test: the test which the full path must satisfy
1183 57c177af Iustin Pop
      (defaults to os.path.exists)
1184 57c177af Iustin Pop

1185 57c177af Iustin Pop
1186 57c177af Iustin Pop
    - full path to the item if found
1187 57c177af Iustin Pop
    - None otherwise
1188 57c177af Iustin Pop

1189 57c177af Iustin Pop
1190 57c177af Iustin Pop
  for dir_name in search_path:
1191 57c177af Iustin Pop
    item_name = os.path.sep.join([dir_name, name])
1192 57c177af Iustin Pop
    if test(item_name):
1193 57c177af Iustin Pop
      return item_name
1194 57c177af Iustin Pop
  return None
1195 8d1a2a64 Michael Hanselmann
1196 8d1a2a64 Michael Hanselmann
1197 8d1a2a64 Michael Hanselmann
def CheckVolumeGroupSize(vglist, vgname, minsize):
1198 8d1a2a64 Michael Hanselmann
  """Checks if the volume group list is valid.
1199 8d1a2a64 Michael Hanselmann

1200 8d1a2a64 Michael Hanselmann
  A non-None return value means there's an error, and the return value
1201 8d1a2a64 Michael Hanselmann
  is the error message.
1202 8d1a2a64 Michael Hanselmann

1203 8d1a2a64 Michael Hanselmann
1204 8d1a2a64 Michael Hanselmann
  vgsize = vglist.get(vgname, None)
1205 8d1a2a64 Michael Hanselmann
  if vgsize is None:
1206 8d1a2a64 Michael Hanselmann
    return "volume group '%s' missing" % vgname
1207 8d1a2a64 Michael Hanselmann
  elif vgsize < minsize:
1208 8d1a2a64 Michael Hanselmann
    return ("volume group '%s' too small (%s MiB required, %d MiB found)" %
1209 8d1a2a64 Michael Hanselmann
            (vgname, minsize, vgsize))
1210 8d1a2a64 Michael Hanselmann
  return None
1211 7996a135 Iustin Pop
1212 7996a135 Iustin Pop
1213 45bc5e4a Michael Hanselmann
def SplitTime(value):
1214 739be818 Michael Hanselmann
  """Splits time as floating point number into a tuple.
1215 739be818 Michael Hanselmann

1216 45bc5e4a Michael Hanselmann
  @param value: Time in seconds
1217 45bc5e4a Michael Hanselmann
  @type value: int or float
1218 45bc5e4a Michael Hanselmann
  @return: Tuple containing (seconds, microseconds)
1219 739be818 Michael Hanselmann

1220 739be818 Michael Hanselmann
1221 45bc5e4a Michael Hanselmann
  (seconds, microseconds) = divmod(int(value * 1000000), 1000000)
1222 45bc5e4a Michael Hanselmann
1223 45bc5e4a Michael Hanselmann
  assert 0 <= seconds, \
1224 45bc5e4a Michael Hanselmann
    "Seconds must be larger than or equal to 0, but are %s" % seconds
1225 45bc5e4a Michael Hanselmann
  assert 0 <= microseconds <= 999999, \
1226 45bc5e4a Michael Hanselmann
    "Microseconds must be 0-999999, but are %s" % microseconds
1227 45bc5e4a Michael Hanselmann
1228 45bc5e4a Michael Hanselmann
  return (int(seconds), int(microseconds))
1229 739be818 Michael Hanselmann
1230 739be818 Michael Hanselmann
1231 739be818 Michael Hanselmann
def MergeTime(timetuple):
1232 739be818 Michael Hanselmann
  """Merges a tuple into time as a floating point number.
1233 739be818 Michael Hanselmann

1234 45bc5e4a Michael Hanselmann
  @param timetuple: Time as tuple, (seconds, microseconds)
1235 739be818 Michael Hanselmann
  @type timetuple: tuple
1236 739be818 Michael Hanselmann
  @return: Time as a floating point number expressed in seconds
1237 739be818 Michael Hanselmann

1238 739be818 Michael Hanselmann
1239 45bc5e4a Michael Hanselmann
  (seconds, microseconds) = timetuple
1240 739be818 Michael Hanselmann
1241 45bc5e4a Michael Hanselmann
  assert 0 <= seconds, \
1242 45bc5e4a Michael Hanselmann
    "Seconds must be larger than or equal to 0, but are %s" % seconds
1243 45bc5e4a Michael Hanselmann
  assert 0 <= microseconds <= 999999, \
1244 45bc5e4a Michael Hanselmann
    "Microseconds must be 0-999999, but are %s" % microseconds
1245 739be818 Michael Hanselmann
1246 45bc5e4a Michael Hanselmann
  return float(seconds) + (float(microseconds) * 0.000001)
1247 739be818 Michael Hanselmann
1248 739be818 Michael Hanselmann
1249 4a8b186a Michael Hanselmann
def GetNodeDaemonPort():
1250 4a8b186a Michael Hanselmann
  """Get the node daemon port for this cluster.
1251 4a8b186a Michael Hanselmann

1252 4a8b186a Michael Hanselmann
  Note that this routine does not read a ganeti-specific file, but
1253 4a8b186a Michael Hanselmann
  instead uses socket.getservbyname to allow pre-customization of
1254 4a8b186a Michael Hanselmann
  this parameter outside of Ganeti.
1255 4a8b186a Michael Hanselmann

1256 4a8b186a Michael Hanselmann
1257 4a8b186a Michael Hanselmann
1258 4a8b186a Michael Hanselmann
    port = socket.getservbyname("ganeti-noded", "tcp")
1259 4a8b186a Michael Hanselmann
  except socket.error:
1260 4a8b186a Michael Hanselmann
    port = constants.DEFAULT_NODED_PORT
1261 4a8b186a Michael Hanselmann
1262 4a8b186a Michael Hanselmann
  return port
1263 4a8b186a Michael Hanselmann
1264 4a8b186a Michael Hanselmann
1265 4a8b186a Michael Hanselmann
def GetNodeDaemonPassword():
1266 4a8b186a Michael Hanselmann
  """Get the node password for the cluster.
1267 4a8b186a Michael Hanselmann

1268 4a8b186a Michael Hanselmann
1269 4a8b186a Michael Hanselmann
  return ReadFile(constants.CLUSTER_PASSWORD_FILE)
1270 4a8b186a Michael Hanselmann
1271 4a8b186a Michael Hanselmann
1272 7996a135 Iustin Pop
def LockedMethod(fn):
1273 7996a135 Iustin Pop
  """Synchronized object access decorator.
1274 7996a135 Iustin Pop

1275 7996a135 Iustin Pop
  This decorator is intended to protect access to an object using the
1276 7996a135 Iustin Pop
  object's own lock which is hardcoded to '_lock'.
1277 7996a135 Iustin Pop

1278 7996a135 Iustin Pop
1279 e67bd559 Michael Hanselmann
  def _LockDebug(*args, **kwargs):
1280 e67bd559 Michael Hanselmann
    if debug_locks:
1281 e67bd559 Michael Hanselmann
      logging.debug(*args, **kwargs)
1282 e67bd559 Michael Hanselmann
1283 7996a135 Iustin Pop
  def wrapper(self, *args, **kwargs):
1284 7996a135 Iustin Pop
    assert hasattr(self, '_lock')
1285 7996a135 Iustin Pop
    lock = self._lock
1286 e67bd559 Michael Hanselmann
    _LockDebug("Waiting for %s", lock)
1287 7996a135 Iustin Pop
1288 7996a135 Iustin Pop
1289 e67bd559 Michael Hanselmann
      _LockDebug("Acquired %s", lock)
1290 7996a135 Iustin Pop
      result = fn(self, *args, **kwargs)
1291 7996a135 Iustin Pop
1292 e67bd559 Michael Hanselmann
      _LockDebug("Releasing %s", lock)
1293 7996a135 Iustin Pop
1294 e67bd559 Michael Hanselmann
      _LockDebug("Released %s", lock)
1295 7996a135 Iustin Pop
    return result
1296 7996a135 Iustin Pop
  return wrapper
1297 eb0f0ce0 Michael Hanselmann
1298 eb0f0ce0 Michael Hanselmann
1299 eb0f0ce0 Michael Hanselmann
def LockFile(fd):
1300 eb0f0ce0 Michael Hanselmann
  """Locks a file using POSIX locks.
1301 eb0f0ce0 Michael Hanselmann

1302 eb0f0ce0 Michael Hanselmann
1303 eb0f0ce0 Michael Hanselmann
1304 eb0f0ce0 Michael Hanselmann
    fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
1305 eb0f0ce0 Michael Hanselmann
  except IOError, err:
1306 eb0f0ce0 Michael Hanselmann
    if err.errno == errno.EAGAIN:
1307 eb0f0ce0 Michael Hanselmann
      raise errors.LockError("File already locked")
1308 eb0f0ce0 Michael Hanselmann
1309 de499029 Michael Hanselmann
1310 de499029 Michael Hanselmann
1311 a87b4824 Michael Hanselmann
class FileLock(object):
1312 a87b4824 Michael Hanselmann
  """Utility class for file locks.
1313 a87b4824 Michael Hanselmann

1314 a87b4824 Michael Hanselmann
1315 a87b4824 Michael Hanselmann
  def __init__(self, filename):
1316 a87b4824 Michael Hanselmann
    self.filename = filename
1317 a87b4824 Michael Hanselmann
    self.fd = open(self.filename, "w")
1318 a87b4824 Michael Hanselmann
1319 a87b4824 Michael Hanselmann
  def __del__(self):
1320 a87b4824 Michael Hanselmann
1321 a87b4824 Michael Hanselmann
1322 a87b4824 Michael Hanselmann
  def Close(self):
1323 a87b4824 Michael Hanselmann
    if self.fd:
1324 a87b4824 Michael Hanselmann
1325 a87b4824 Michael Hanselmann
      self.fd = None
1326 a87b4824 Michael Hanselmann
1327 aa74b828 Michael Hanselmann
  def _flock(self, flag, blocking, timeout, errmsg):
1328 aa74b828 Michael Hanselmann
    """Wrapper for fcntl.flock.
1329 aa74b828 Michael Hanselmann

1330 aa74b828 Michael Hanselmann
    @type flag: int
1331 aa74b828 Michael Hanselmann
    @param flag: Operation flag
1332 aa74b828 Michael Hanselmann
    @type blocking: bool
1333 aa74b828 Michael Hanselmann
    @param blocking: Whether the operation should be done in blocking mode.
1334 aa74b828 Michael Hanselmann
    @type timeout: None or float
1335 aa74b828 Michael Hanselmann
    @param timeout: For how long the operation should be retried (implies
1336 aa74b828 Michael Hanselmann
                    non-blocking mode).
1337 aa74b828 Michael Hanselmann
    @type errmsg: string
1338 aa74b828 Michael Hanselmann
    @param errmsg: Error message in case operation fails.
1339 aa74b828 Michael Hanselmann

1340 aa74b828 Michael Hanselmann
1341 a87b4824 Michael Hanselmann
    assert self.fd, "Lock was closed"
1342 aa74b828 Michael Hanselmann
    assert timeout is None or timeout >= 0, \
1343 aa74b828 Michael Hanselmann
      "If specified, timeout must be positive"
1344 a87b4824 Michael Hanselmann
1345 aa74b828 Michael Hanselmann
    if timeout is not None:
1346 a87b4824 Michael Hanselmann
      flag |= fcntl.LOCK_NB
1347 aa74b828 Michael Hanselmann
      timeout_end = time.time() + timeout
1348 a87b4824 Michael Hanselmann
1349 aa74b828 Michael Hanselmann
    # Blocking doesn't have effect with timeout
1350 aa74b828 Michael Hanselmann
    elif not blocking:
1351 aa74b828 Michael Hanselmann
      flag |= fcntl.LOCK_NB
1352 aa74b828 Michael Hanselmann
      timeout_end = None
1353 aa74b828 Michael Hanselmann
1354 aa74b828 Michael Hanselmann
    retry = True
1355 aa74b828 Michael Hanselmann
    while retry:
1356 aa74b828 Michael Hanselmann
1357 aa74b828 Michael Hanselmann
        fcntl.flock(self.fd, flag)
1358 aa74b828 Michael Hanselmann
        retry = False
1359 aa74b828 Michael Hanselmann
      except IOError, err:
1360 aa74b828 Michael Hanselmann
        if err.errno in (errno.EAGAIN, ):
1361 aa74b828 Michael Hanselmann
          if timeout_end is not None and time.time() < timeout_end:
1362 aa74b828 Michael Hanselmann
            # Wait before trying again
1363 aa74b828 Michael Hanselmann
            time.sleep(max(0.1, min(1.0, timeout)))
1364 aa74b828 Michael Hanselmann
1365 aa74b828 Michael Hanselmann
            raise errors.LockError(errmsg)
1366 aa74b828 Michael Hanselmann
1367 aa74b828 Michael Hanselmann
          logging.exception("fcntl.flock failed")
1368 aa74b828 Michael Hanselmann
1369 aa74b828 Michael Hanselmann
1370 aa74b828 Michael Hanselmann
  def Exclusive(self, blocking=False, timeout=None):
1371 a87b4824 Michael Hanselmann
    """Locks the file in exclusive mode.
1372 a87b4824 Michael Hanselmann

1373 a87b4824 Michael Hanselmann
1374 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_EX, blocking, timeout,
1375 a87b4824 Michael Hanselmann
                "Failed to lock %s in exclusive mode" % self.filename)
1376 a87b4824 Michael Hanselmann
1377 aa74b828 Michael Hanselmann
  def Shared(self, blocking=False, timeout=None):
1378 a87b4824 Michael Hanselmann
    """Locks the file in shared mode.
1379 a87b4824 Michael Hanselmann

1380 a87b4824 Michael Hanselmann
1381 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_SH, blocking, timeout,
1382 a87b4824 Michael Hanselmann
                "Failed to lock %s in shared mode" % self.filename)
1383 a87b4824 Michael Hanselmann
1384 aa74b828 Michael Hanselmann
  def Unlock(self, blocking=True, timeout=None):
1385 a87b4824 Michael Hanselmann
    """Unlocks the file.
1386 a87b4824 Michael Hanselmann

1387 a87b4824 Michael Hanselmann
    According to "man flock", unlocking can also be a nonblocking operation:
1388 a87b4824 Michael Hanselmann
    "To make a non-blocking request, include LOCK_NB with any of the above
1389 a87b4824 Michael Hanselmann
1390 a87b4824 Michael Hanselmann

1391 a87b4824 Michael Hanselmann
1392 aa74b828 Michael Hanselmann
    self._flock(fcntl.LOCK_UN, blocking, timeout,
1393 a87b4824 Michael Hanselmann
                "Failed to unlock %s" % self.filename)
1394 a87b4824 Michael Hanselmann
1395 a87b4824 Michael Hanselmann
1396 de499029 Michael Hanselmann
class SignalHandler(object):
1397 de499029 Michael Hanselmann
  """Generic signal handler class.
1398 de499029 Michael Hanselmann

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

1403 de499029 Michael Hanselmann
1404 de499029 Michael Hanselmann
  def __init__(self, signum):
1405 de499029 Michael Hanselmann
    """Constructs a new SignalHandler instance.
1406 de499029 Michael Hanselmann

1407 de499029 Michael Hanselmann
    @param signum: Single signal number or set of signal numbers
1408 de499029 Michael Hanselmann

1409 de499029 Michael Hanselmann
1410 de499029 Michael Hanselmann
    if isinstance(signum, (int, long)):
1411 de499029 Michael Hanselmann
      self.signum = set([signum])
1412 de499029 Michael Hanselmann
1413 de499029 Michael Hanselmann
      self.signum = set(signum)
1414 de499029 Michael Hanselmann
1415 de499029 Michael Hanselmann
    self.called = False
1416 de499029 Michael Hanselmann
1417 de499029 Michael Hanselmann
    self._previous = {}
1418 de499029 Michael Hanselmann
1419 de499029 Michael Hanselmann
      for signum in self.signum:
1420 de499029 Michael Hanselmann
        # Setup handler
1421 de499029 Michael Hanselmann
        prev_handler = signal.signal(signum, self._HandleSignal)
1422 de499029 Michael Hanselmann
1423 de499029 Michael Hanselmann
          self._previous[signum] = prev_handler
1424 de499029 Michael Hanselmann
1425 de499029 Michael Hanselmann
          # Restore previous handler
1426 de499029 Michael Hanselmann
          signal.signal(signum, prev_handler)
1427 de499029 Michael Hanselmann
1428 de499029 Michael Hanselmann
1429 de499029 Michael Hanselmann
      # Reset all handlers
1430 de499029 Michael Hanselmann
1431 de499029 Michael Hanselmann
      # Here we have a race condition: a handler may have already been called,
1432 de499029 Michael Hanselmann
      # but there's not much we can do about it at this point.
1433 de499029 Michael Hanselmann
1434 de499029 Michael Hanselmann
1435 de499029 Michael Hanselmann
  def __del__(self):
1436 de499029 Michael Hanselmann
1437 de499029 Michael Hanselmann
1438 de499029 Michael Hanselmann
  def Reset(self):
1439 de499029 Michael Hanselmann
    """Restore previous handler.
1440 de499029 Michael Hanselmann

1441 de499029 Michael Hanselmann
1442 de499029 Michael Hanselmann
    for signum, prev_handler in self._previous.items():
1443 de499029 Michael Hanselmann
      signal.signal(signum, prev_handler)
1444 de499029 Michael Hanselmann
      # If successful, remove from dict
1445 de499029 Michael Hanselmann
      del self._previous[signum]
1446 de499029 Michael Hanselmann
1447 de499029 Michael Hanselmann
  def Clear(self):
1448 de499029 Michael Hanselmann
    """Unsets "called" flag.
1449 de499029 Michael Hanselmann

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

1452 de499029 Michael Hanselmann
1453 de499029 Michael Hanselmann
    self.called = False
1454 de499029 Michael Hanselmann
1455 de499029 Michael Hanselmann
  def _HandleSignal(self, signum, frame):
1456 de499029 Michael Hanselmann
    """Actual signal handling function.
1457 de499029 Michael Hanselmann

1458 de499029 Michael Hanselmann
1459 de499029 Michael Hanselmann
    # This is not nice and not absolutely atomic, but it appears to be the only
1460 de499029 Michael Hanselmann
    # solution in Python -- there are no atomic types.
1461 de499029 Michael Hanselmann
    self.called = True