Statistics
| Branch: | Tag: | Revision:

root / lib / utils.py @ 9ff7e35c

History | View | Annotate | Download (21.1 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
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 a8083063 Iustin Pop
"""
24 a8083063 Iustin Pop
25 a8083063 Iustin Pop
26 a8083063 Iustin Pop
import sys
27 a8083063 Iustin Pop
import os
28 a8083063 Iustin Pop
import sha
29 a8083063 Iustin Pop
import time
30 113b55aa Iustin Pop
import subprocess
31 a8083063 Iustin Pop
import re
32 a8083063 Iustin Pop
import socket
33 a8083063 Iustin Pop
import tempfile
34 a8083063 Iustin Pop
import shutil
35 4ca1b175 Alexander Schreiber
import errno
36 a8083063 Iustin Pop
37 a8083063 Iustin Pop
from ganeti import logger
38 a8083063 Iustin Pop
from ganeti import errors
39 a8083063 Iustin Pop
40 a8083063 Iustin Pop
_locksheld = []
41 a8083063 Iustin Pop
_re_shell_unquoted = re.compile('^[-.,=:/_+@A-Za-z0-9]+$')
42 a8083063 Iustin Pop
43 a8083063 Iustin Pop
class RunResult(object):
44 a8083063 Iustin Pop
  """Simple class for holding the result of running external programs.
45 a8083063 Iustin Pop

46 a8083063 Iustin Pop
  Instance variables:
47 a8083063 Iustin Pop
    exit_code: the exit code of the program, or None (if the program
48 a8083063 Iustin Pop
               didn't exit())
49 a8083063 Iustin Pop
    signal: numeric signal that caused the program to finish, or None
50 a8083063 Iustin Pop
            (if the program wasn't terminated by a signal)
51 a8083063 Iustin Pop
    stdout: the standard output of the program
52 a8083063 Iustin Pop
    stderr: the standard error of the program
53 a8083063 Iustin Pop
    failed: a Boolean value which is True in case the program was
54 a8083063 Iustin Pop
            terminated by a signal or exited with a non-zero exit code
55 a8083063 Iustin Pop
    fail_reason: a string detailing the termination reason
56 a8083063 Iustin Pop

57 a8083063 Iustin Pop
  """
58 a8083063 Iustin Pop
  __slots__ = ["exit_code", "signal", "stdout", "stderr",
59 a8083063 Iustin Pop
               "failed", "fail_reason", "cmd"]
60 a8083063 Iustin Pop
61 a8083063 Iustin Pop
62 a8083063 Iustin Pop
  def __init__(self, exit_code, signal, stdout, stderr, cmd):
63 a8083063 Iustin Pop
    self.cmd = cmd
64 a8083063 Iustin Pop
    self.exit_code = exit_code
65 a8083063 Iustin Pop
    self.signal = signal
66 a8083063 Iustin Pop
    self.stdout = stdout
67 a8083063 Iustin Pop
    self.stderr = stderr
68 a8083063 Iustin Pop
    self.failed = (signal is not None or exit_code != 0)
69 a8083063 Iustin Pop
70 a8083063 Iustin Pop
    if self.signal is not None:
71 a8083063 Iustin Pop
      self.fail_reason = "terminated by signal %s" % self.signal
72 a8083063 Iustin Pop
    elif self.exit_code is not None:
73 a8083063 Iustin Pop
      self.fail_reason = "exited with exit code %s" % self.exit_code
74 a8083063 Iustin Pop
    else:
75 a8083063 Iustin Pop
      self.fail_reason = "unable to determine termination reason"
76 a8083063 Iustin Pop
77 a8083063 Iustin Pop
  def _GetOutput(self):
78 a8083063 Iustin Pop
    """Returns the combined stdout and stderr for easier usage.
79 a8083063 Iustin Pop

80 a8083063 Iustin Pop
    """
81 a8083063 Iustin Pop
    return self.stdout + self.stderr
82 a8083063 Iustin Pop
83 a8083063 Iustin Pop
  output = property(_GetOutput, None, None, "Return full output")
84 a8083063 Iustin Pop
85 a8083063 Iustin Pop
86 a8083063 Iustin Pop
def _GetLockFile(subsystem):
87 a8083063 Iustin Pop
  """Compute the file name for a given lock name."""
88 a8083063 Iustin Pop
  return "/var/lock/ganeti_lock_%s" % subsystem
89 a8083063 Iustin Pop
90 a8083063 Iustin Pop
91 a8083063 Iustin Pop
def Lock(name, max_retries=None, debug=False):
92 a8083063 Iustin Pop
  """Lock a given subsystem.
93 a8083063 Iustin Pop

94 a8083063 Iustin Pop
  In case the lock is already held by an alive process, the function
95 a8083063 Iustin Pop
  will sleep indefintely and poll with a one second interval.
96 a8083063 Iustin Pop

97 a8083063 Iustin Pop
  When the optional integer argument 'max_retries' is passed with a
98 a8083063 Iustin Pop
  non-zero value, the function will sleep only for this number of
99 a8083063 Iustin Pop
  times, and then it will will raise a LockError if the lock can't be
100 a8083063 Iustin Pop
  acquired. Passing in a negative number will cause only one try to
101 a8083063 Iustin Pop
  get the lock. Passing a positive number will make the function retry
102 a8083063 Iustin Pop
  for approximately that number of seconds.
103 a8083063 Iustin Pop

104 a8083063 Iustin Pop
  """
105 a8083063 Iustin Pop
  lockfile = _GetLockFile(name)
106 a8083063 Iustin Pop
107 a8083063 Iustin Pop
  if name in _locksheld:
108 a8083063 Iustin Pop
    raise errors.LockError('Lock "%s" already held!' % (name,))
109 a8083063 Iustin Pop
110 a8083063 Iustin Pop
  errcount = 0
111 a8083063 Iustin Pop
112 a8083063 Iustin Pop
  retries = 0
113 a8083063 Iustin Pop
  while True:
114 a8083063 Iustin Pop
    try:
115 a8083063 Iustin Pop
      fd = os.open(lockfile, os.O_CREAT | os.O_EXCL | os.O_RDWR | os.O_SYNC)
116 a8083063 Iustin Pop
      break
117 a8083063 Iustin Pop
    except OSError, creat_err:
118 4ca1b175 Alexander Schreiber
      if creat_err.errno != errno.EEXIST:
119 3ecf6786 Iustin Pop
        raise errors.LockError("Can't create the lock file. Error '%s'." %
120 3ecf6786 Iustin Pop
                               str(creat_err))
121 a8083063 Iustin Pop
122 a8083063 Iustin Pop
      try:
123 a8083063 Iustin Pop
        pf = open(lockfile, 'r')
124 a8083063 Iustin Pop
      except IOError, open_err:
125 a8083063 Iustin Pop
        errcount += 1
126 a8083063 Iustin Pop
        if errcount >= 5:
127 3ecf6786 Iustin Pop
          raise errors.LockError("Lock file exists but cannot be opened."
128 3ecf6786 Iustin Pop
                                 " Error: '%s'." % str(open_err))
129 a8083063 Iustin Pop
        time.sleep(1)
130 a8083063 Iustin Pop
        continue
131 a8083063 Iustin Pop
132 a8083063 Iustin Pop
      try:
133 a8083063 Iustin Pop
        pid = int(pf.read())
134 a8083063 Iustin Pop
      except ValueError:
135 3ecf6786 Iustin Pop
        raise errors.LockError("Invalid pid string in %s" %
136 a8083063 Iustin Pop
                               (lockfile,))
137 a8083063 Iustin Pop
138 a8083063 Iustin Pop
      if not IsProcessAlive(pid):
139 3ecf6786 Iustin Pop
        raise errors.LockError("Stale lockfile %s for pid %d?" %
140 3ecf6786 Iustin Pop
                               (lockfile, pid))
141 a8083063 Iustin Pop
142 a8083063 Iustin Pop
      if max_retries and max_retries <= retries:
143 3ecf6786 Iustin Pop
        raise errors.LockError("Can't acquire lock during the specified"
144 3ecf6786 Iustin Pop
                               " time, aborting.")
145 a8083063 Iustin Pop
      if retries == 5 and (debug or sys.stdin.isatty()):
146 a8083063 Iustin Pop
        logger.ToStderr("Waiting for '%s' lock from pid %d..." % (name, pid))
147 a8083063 Iustin Pop
148 a8083063 Iustin Pop
      time.sleep(1)
149 a8083063 Iustin Pop
      retries += 1
150 a8083063 Iustin Pop
      continue
151 a8083063 Iustin Pop
152 a8083063 Iustin Pop
  os.write(fd, '%d\n' % (os.getpid(),))
153 a8083063 Iustin Pop
  os.close(fd)
154 a8083063 Iustin Pop
155 a8083063 Iustin Pop
  _locksheld.append(name)
156 a8083063 Iustin Pop
157 a8083063 Iustin Pop
158 a8083063 Iustin Pop
def Unlock(name):
159 098c0958 Michael Hanselmann
  """Unlock a given subsystem.
160 a8083063 Iustin Pop

161 098c0958 Michael Hanselmann
  """
162 a8083063 Iustin Pop
  lockfile = _GetLockFile(name)
163 a8083063 Iustin Pop
164 a8083063 Iustin Pop
  try:
165 a8083063 Iustin Pop
    fd = os.open(lockfile, os.O_RDONLY)
166 a8083063 Iustin Pop
  except OSError:
167 a8083063 Iustin Pop
    raise errors.LockError('Lock "%s" not held.' % (name,))
168 a8083063 Iustin Pop
169 a8083063 Iustin Pop
  f = os.fdopen(fd, 'r')
170 a8083063 Iustin Pop
  pid_str = f.read()
171 a8083063 Iustin Pop
172 a8083063 Iustin Pop
  try:
173 a8083063 Iustin Pop
    pid = int(pid_str)
174 a8083063 Iustin Pop
  except ValueError:
175 a8083063 Iustin Pop
    raise errors.LockError('Unable to determine PID of locking process.')
176 a8083063 Iustin Pop
177 a8083063 Iustin Pop
  if pid != os.getpid():
178 a8083063 Iustin Pop
    raise errors.LockError('Lock not held by me (%d != %d)' %
179 a8083063 Iustin Pop
                           (os.getpid(), pid,))
180 a8083063 Iustin Pop
181 a8083063 Iustin Pop
  os.unlink(lockfile)
182 a8083063 Iustin Pop
  _locksheld.remove(name)
183 a8083063 Iustin Pop
184 a8083063 Iustin Pop
185 a8083063 Iustin Pop
def LockCleanup():
186 098c0958 Michael Hanselmann
  """Remove all locks.
187 a8083063 Iustin Pop

188 098c0958 Michael Hanselmann
  """
189 a8083063 Iustin Pop
  for lock in _locksheld:
190 a8083063 Iustin Pop
    Unlock(lock)
191 a8083063 Iustin Pop
192 a8083063 Iustin Pop
193 a8083063 Iustin Pop
def RunCmd(cmd):
194 a8083063 Iustin Pop
  """Execute a (shell) command.
195 a8083063 Iustin Pop

196 a8083063 Iustin Pop
  The command should not read from its standard input, as it will be
197 a8083063 Iustin Pop
  closed.
198 a8083063 Iustin Pop

199 a8083063 Iustin Pop
  Args:
200 a8083063 Iustin Pop
    cmd: command to run. (str)
201 a8083063 Iustin Pop

202 a8083063 Iustin Pop
  Returns: `RunResult` instance
203 a8083063 Iustin Pop

204 a8083063 Iustin Pop
  """
205 a8083063 Iustin Pop
  if isinstance(cmd, list):
206 a8083063 Iustin Pop
    cmd = [str(val) for val in cmd]
207 113b55aa Iustin Pop
    strcmd = " ".join(cmd)
208 113b55aa Iustin Pop
    shell = False
209 113b55aa Iustin Pop
  else:
210 113b55aa Iustin Pop
    strcmd = cmd
211 113b55aa Iustin Pop
    shell = True
212 23f41a3e Michael Hanselmann
  env = os.environ.copy()
213 23f41a3e Michael Hanselmann
  env["LC_ALL"] = "C"
214 113b55aa Iustin Pop
  child = subprocess.Popen(cmd, shell=shell,
215 113b55aa Iustin Pop
                           stderr=subprocess.PIPE,
216 113b55aa Iustin Pop
                           stdout=subprocess.PIPE,
217 113b55aa Iustin Pop
                           stdin=subprocess.PIPE,
218 23f41a3e Michael Hanselmann
                           close_fds=True, env=env)
219 113b55aa Iustin Pop
220 113b55aa Iustin Pop
  child.stdin.close()
221 113b55aa Iustin Pop
  out = child.stdout.read()
222 113b55aa Iustin Pop
  err = child.stderr.read()
223 a8083063 Iustin Pop
224 a8083063 Iustin Pop
  status = child.wait()
225 113b55aa Iustin Pop
  if status >= 0:
226 113b55aa Iustin Pop
    exitcode = status
227 a8083063 Iustin Pop
    signal = None
228 a8083063 Iustin Pop
  else:
229 a8083063 Iustin Pop
    exitcode = None
230 113b55aa Iustin Pop
    signal = -status
231 a8083063 Iustin Pop
232 a8083063 Iustin Pop
  return RunResult(exitcode, signal, out, err, strcmd)
233 a8083063 Iustin Pop
234 a8083063 Iustin Pop
235 a8083063 Iustin Pop
def RunCmdUnlocked(cmd):
236 a8083063 Iustin Pop
  """Execute a shell command without the 'cmd' lock.
237 a8083063 Iustin Pop

238 a8083063 Iustin Pop
  This variant of `RunCmd()` drops the 'cmd' lock before running the
239 a8083063 Iustin Pop
  command and re-aquires it afterwards, thus it can be used to call
240 a8083063 Iustin Pop
  other ganeti commands.
241 a8083063 Iustin Pop

242 a8083063 Iustin Pop
  The argument and return values are the same as for the `RunCmd()`
243 a8083063 Iustin Pop
  function.
244 a8083063 Iustin Pop

245 a8083063 Iustin Pop
  Args:
246 a8083063 Iustin Pop
    cmd - command to run. (str)
247 a8083063 Iustin Pop

248 a8083063 Iustin Pop
  Returns:
249 a8083063 Iustin Pop
    `RunResult`
250 a8083063 Iustin Pop

251 a8083063 Iustin Pop
  """
252 a8083063 Iustin Pop
  Unlock('cmd')
253 a8083063 Iustin Pop
  ret = RunCmd(cmd)
254 a8083063 Iustin Pop
  Lock('cmd')
255 a8083063 Iustin Pop
256 a8083063 Iustin Pop
  return ret
257 a8083063 Iustin Pop
258 a8083063 Iustin Pop
259 a8083063 Iustin Pop
def RemoveFile(filename):
260 a8083063 Iustin Pop
  """Remove a file ignoring some errors.
261 a8083063 Iustin Pop

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

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

276 a8083063 Iustin Pop
  If the file does not exist, a None will be returned
277 a8083063 Iustin Pop
  instead.
278 a8083063 Iustin Pop

279 a8083063 Iustin Pop
  Args:
280 a8083063 Iustin Pop
    filename - Filename (str)
281 a8083063 Iustin Pop

282 a8083063 Iustin Pop
  """
283 a8083063 Iustin Pop
  if not (os.path.exists(filename) and os.path.isfile(filename)):
284 a8083063 Iustin Pop
    return None
285 a8083063 Iustin Pop
286 a8083063 Iustin Pop
  f = open(filename)
287 a8083063 Iustin Pop
288 a8083063 Iustin Pop
  fp = sha.sha()
289 a8083063 Iustin Pop
  while True:
290 a8083063 Iustin Pop
    data = f.read(4096)
291 a8083063 Iustin Pop
    if not data:
292 a8083063 Iustin Pop
      break
293 a8083063 Iustin Pop
294 a8083063 Iustin Pop
    fp.update(data)
295 a8083063 Iustin Pop
296 a8083063 Iustin Pop
  return fp.hexdigest()
297 a8083063 Iustin Pop
298 a8083063 Iustin Pop
299 a8083063 Iustin Pop
def FingerprintFiles(files):
300 a8083063 Iustin Pop
  """Compute fingerprints for a list of files.
301 a8083063 Iustin Pop

302 a8083063 Iustin Pop
  Args:
303 a8083063 Iustin Pop
    files - array of filenames.  ( [str, ...] )
304 a8083063 Iustin Pop

305 a8083063 Iustin Pop
  Return value:
306 a8083063 Iustin Pop
    dictionary of filename: fingerprint for the files that exist
307 a8083063 Iustin Pop

308 a8083063 Iustin Pop
  """
309 a8083063 Iustin Pop
  ret = {}
310 a8083063 Iustin Pop
311 a8083063 Iustin Pop
  for filename in files:
312 a8083063 Iustin Pop
    cksum = _FingerprintFile(filename)
313 a8083063 Iustin Pop
    if cksum:
314 a8083063 Iustin Pop
      ret[filename] = cksum
315 a8083063 Iustin Pop
316 a8083063 Iustin Pop
  return ret
317 a8083063 Iustin Pop
318 a8083063 Iustin Pop
319 a8083063 Iustin Pop
def CheckDict(target, template, logname=None):
320 a8083063 Iustin Pop
  """Ensure a dictionary has a required set of keys.
321 a8083063 Iustin Pop

322 a8083063 Iustin Pop
  For the given dictionaries `target` and `template`, ensure target
323 a8083063 Iustin Pop
  has all the keys from template. Missing keys are added with values
324 a8083063 Iustin Pop
  from template.
325 a8083063 Iustin Pop

326 a8083063 Iustin Pop
  Args:
327 a8083063 Iustin Pop
    target   - the dictionary to check
328 a8083063 Iustin Pop
    template - template dictionary
329 a8083063 Iustin Pop
    logname  - a caller-chosen string to identify the debug log
330 a8083063 Iustin Pop
               entry; if None, no logging will be done
331 a8083063 Iustin Pop

332 a8083063 Iustin Pop
  Returns value:
333 a8083063 Iustin Pop
    None
334 a8083063 Iustin Pop

335 a8083063 Iustin Pop
  """
336 a8083063 Iustin Pop
  missing = []
337 a8083063 Iustin Pop
  for k in template:
338 a8083063 Iustin Pop
    if k not in target:
339 a8083063 Iustin Pop
      missing.append(k)
340 a8083063 Iustin Pop
      target[k] = template[k]
341 a8083063 Iustin Pop
342 a8083063 Iustin Pop
  if missing and logname:
343 a8083063 Iustin Pop
    logger.Debug('%s missing keys %s' %
344 a8083063 Iustin Pop
                 (logname, ', '.join(missing)))
345 a8083063 Iustin Pop
346 a8083063 Iustin Pop
347 a8083063 Iustin Pop
def IsProcessAlive(pid):
348 a8083063 Iustin Pop
  """Check if a given pid exists on the system.
349 a8083063 Iustin Pop

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

352 a8083063 Iustin Pop
  Remarks: zombie processes treated as not alive
353 a8083063 Iustin Pop

354 a8083063 Iustin Pop
  """
355 a8083063 Iustin Pop
  try:
356 a8083063 Iustin Pop
    f = open("/proc/%d/status" % pid)
357 a8083063 Iustin Pop
  except IOError, err:
358 4ca1b175 Alexander Schreiber
    if err.errno in (errno.ENOENT, errno.ENOTDIR):
359 a8083063 Iustin Pop
      return False
360 a8083063 Iustin Pop
361 a8083063 Iustin Pop
  alive = True
362 a8083063 Iustin Pop
  try:
363 a8083063 Iustin Pop
    data = f.readlines()
364 a8083063 Iustin Pop
    if len(data) > 1:
365 a8083063 Iustin Pop
      state = data[1].split()
366 a8083063 Iustin Pop
      if len(state) > 1 and state[1] == "Z":
367 a8083063 Iustin Pop
        alive = False
368 a8083063 Iustin Pop
  finally:
369 a8083063 Iustin Pop
    f.close()
370 a8083063 Iustin Pop
371 a8083063 Iustin Pop
  return alive
372 a8083063 Iustin Pop
373 a8083063 Iustin Pop
374 a8083063 Iustin Pop
def MatchNameComponent(key, name_list):
375 a8083063 Iustin Pop
  """Try to match a name against a list.
376 a8083063 Iustin Pop

377 a8083063 Iustin Pop
  This function will try to match a name like test1 against a list
378 a8083063 Iustin Pop
  like ['test1.example.com', 'test2.example.com', ...]. Against this
379 a8083063 Iustin Pop
  list, 'test1' as well as 'test1.example' will match, but not
380 a8083063 Iustin Pop
  'test1.ex'. A multiple match will be considered as no match at all
381 a8083063 Iustin Pop
  (e.g. 'test1' against ['test1.example.com', 'test1.example.org']).
382 a8083063 Iustin Pop

383 a8083063 Iustin Pop
  Args:
384 a8083063 Iustin Pop
    key: the name to be searched
385 a8083063 Iustin Pop
    name_list: the list of strings against which to search the key
386 a8083063 Iustin Pop

387 a8083063 Iustin Pop
  Returns:
388 a8083063 Iustin Pop
    None if there is no match *or* if there are multiple matches
389 a8083063 Iustin Pop
    otherwise the element from the list which matches
390 a8083063 Iustin Pop

391 a8083063 Iustin Pop
  """
392 a8083063 Iustin Pop
  mo = re.compile("^%s(\..*)?$" % re.escape(key))
393 a8083063 Iustin Pop
  names_filtered = [name for name in name_list if mo.match(name) is not None]
394 a8083063 Iustin Pop
  if len(names_filtered) != 1:
395 a8083063 Iustin Pop
    return None
396 a8083063 Iustin Pop
  return names_filtered[0]
397 a8083063 Iustin Pop
398 a8083063 Iustin Pop
399 bcf043c9 Iustin Pop
class HostInfo:
400 89e1fc26 Iustin Pop
  """Class implementing resolver and hostname functionality
401 bcf043c9 Iustin Pop

402 bcf043c9 Iustin Pop
  """
403 89e1fc26 Iustin Pop
  def __init__(self, name=None):
404 bcf043c9 Iustin Pop
    """Initialize the host name object.
405 bcf043c9 Iustin Pop

406 89e1fc26 Iustin Pop
    If the name argument is not passed, it will use this system's
407 89e1fc26 Iustin Pop
    name.
408 bcf043c9 Iustin Pop

409 bcf043c9 Iustin Pop
    """
410 89e1fc26 Iustin Pop
    if name is None:
411 89e1fc26 Iustin Pop
      name = self.SysName()
412 89e1fc26 Iustin Pop
413 89e1fc26 Iustin Pop
    self.query = name
414 89e1fc26 Iustin Pop
    self.name, self.aliases, self.ipaddrs = self.LookupHostname(name)
415 bcf043c9 Iustin Pop
    self.ip = self.ipaddrs[0]
416 bcf043c9 Iustin Pop
417 89e1fc26 Iustin Pop
  @staticmethod
418 89e1fc26 Iustin Pop
  def SysName():
419 89e1fc26 Iustin Pop
    """Return the current system's name.
420 bcf043c9 Iustin Pop

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

423 89e1fc26 Iustin Pop
    """
424 89e1fc26 Iustin Pop
    return socket.gethostname()
425 a8083063 Iustin Pop
426 89e1fc26 Iustin Pop
  @staticmethod
427 89e1fc26 Iustin Pop
  def LookupHostname(hostname):
428 89e1fc26 Iustin Pop
    """Look up hostname
429 a8083063 Iustin Pop

430 89e1fc26 Iustin Pop
    Args:
431 89e1fc26 Iustin Pop
      hostname: hostname to look up
432 89e1fc26 Iustin Pop

433 89e1fc26 Iustin Pop
    Returns:
434 89e1fc26 Iustin Pop
      a tuple (name, aliases, ipaddrs) as returned by socket.gethostbyname_ex
435 89e1fc26 Iustin Pop
      in case of errors in resolving, we raise a ResolverError
436 89e1fc26 Iustin Pop

437 89e1fc26 Iustin Pop
    """
438 89e1fc26 Iustin Pop
    try:
439 89e1fc26 Iustin Pop
      result = socket.gethostbyname_ex(hostname)
440 89e1fc26 Iustin Pop
    except socket.gaierror, err:
441 89e1fc26 Iustin Pop
      # hostname not found in DNS
442 89e1fc26 Iustin Pop
      raise errors.ResolverError(hostname, err.args[0], err.args[1])
443 a8083063 Iustin Pop
444 89e1fc26 Iustin Pop
    return result
445 a8083063 Iustin Pop
446 a8083063 Iustin Pop
447 a8083063 Iustin Pop
def ListVolumeGroups():
448 a8083063 Iustin Pop
  """List volume groups and their size
449 a8083063 Iustin Pop

450 a8083063 Iustin Pop
  Returns:
451 a8083063 Iustin Pop
     Dictionary with keys volume name and values the size of the volume
452 a8083063 Iustin Pop

453 a8083063 Iustin Pop
  """
454 a8083063 Iustin Pop
  command = "vgs --noheadings --units m --nosuffix -o name,size"
455 a8083063 Iustin Pop
  result = RunCmd(command)
456 a8083063 Iustin Pop
  retval = {}
457 a8083063 Iustin Pop
  if result.failed:
458 a8083063 Iustin Pop
    return retval
459 a8083063 Iustin Pop
460 a8083063 Iustin Pop
  for line in result.stdout.splitlines():
461 a8083063 Iustin Pop
    try:
462 a8083063 Iustin Pop
      name, size = line.split()
463 a8083063 Iustin Pop
      size = int(float(size))
464 a8083063 Iustin Pop
    except (IndexError, ValueError), err:
465 a8083063 Iustin Pop
      logger.Error("Invalid output from vgs (%s): %s" % (err, line))
466 a8083063 Iustin Pop
      continue
467 a8083063 Iustin Pop
468 a8083063 Iustin Pop
    retval[name] = size
469 a8083063 Iustin Pop
470 a8083063 Iustin Pop
  return retval
471 a8083063 Iustin Pop
472 a8083063 Iustin Pop
473 a8083063 Iustin Pop
def BridgeExists(bridge):
474 a8083063 Iustin Pop
  """Check whether the given bridge exists in the system
475 a8083063 Iustin Pop

476 a8083063 Iustin Pop
  Returns:
477 a8083063 Iustin Pop
     True if it does, false otherwise.
478 a8083063 Iustin Pop

479 a8083063 Iustin Pop
  """
480 a8083063 Iustin Pop
  return os.path.isdir("/sys/class/net/%s/bridge" % bridge)
481 a8083063 Iustin Pop
482 a8083063 Iustin Pop
483 a8083063 Iustin Pop
def NiceSort(name_list):
484 a8083063 Iustin Pop
  """Sort a list of strings based on digit and non-digit groupings.
485 a8083063 Iustin Pop

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

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

493 a8083063 Iustin Pop
  Return value
494 a8083063 Iustin Pop
    - a copy of the list sorted according to our algorithm
495 a8083063 Iustin Pop

496 a8083063 Iustin Pop
  """
497 a8083063 Iustin Pop
  _SORTER_BASE = "(\D+|\d+)"
498 a8083063 Iustin Pop
  _SORTER_FULL = "^%s%s?%s?%s?%s?%s?%s?%s?.*$" % (_SORTER_BASE, _SORTER_BASE,
499 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE,
500 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE,
501 a8083063 Iustin Pop
                                                  _SORTER_BASE, _SORTER_BASE)
502 a8083063 Iustin Pop
  _SORTER_RE = re.compile(_SORTER_FULL)
503 a8083063 Iustin Pop
  _SORTER_NODIGIT = re.compile("^\D*$")
504 a8083063 Iustin Pop
  def _TryInt(val):
505 a8083063 Iustin Pop
    """Attempts to convert a variable to integer."""
506 a8083063 Iustin Pop
    if val is None or _SORTER_NODIGIT.match(val):
507 a8083063 Iustin Pop
      return val
508 a8083063 Iustin Pop
    rval = int(val)
509 a8083063 Iustin Pop
    return rval
510 a8083063 Iustin Pop
511 a8083063 Iustin Pop
  to_sort = [([_TryInt(grp) for grp in _SORTER_RE.match(name).groups()], name)
512 a8083063 Iustin Pop
             for name in name_list]
513 a8083063 Iustin Pop
  to_sort.sort()
514 a8083063 Iustin Pop
  return [tup[1] for tup in to_sort]
515 a8083063 Iustin Pop
516 a8083063 Iustin Pop
517 a8083063 Iustin Pop
def CheckDaemonAlive(pid_file, process_string):
518 a8083063 Iustin Pop
  """Check wether the specified daemon is alive.
519 a8083063 Iustin Pop

520 a8083063 Iustin Pop
  Args:
521 a8083063 Iustin Pop
   - pid_file: file to read the daemon pid from, the file is
522 a8083063 Iustin Pop
               expected to contain only a single line containing
523 a8083063 Iustin Pop
               only the PID
524 a8083063 Iustin Pop
   - process_string: a substring that we expect to find in
525 a8083063 Iustin Pop
                     the command line of the daemon process
526 a8083063 Iustin Pop

527 a8083063 Iustin Pop
  Returns:
528 a8083063 Iustin Pop
   - True if the daemon is judged to be alive (that is:
529 a8083063 Iustin Pop
      - the PID file exists, is readable and contains a number
530 a8083063 Iustin Pop
      - a process of the specified PID is running
531 a8083063 Iustin Pop
      - that process contains the specified string in its
532 a8083063 Iustin Pop
        command line
533 a8083063 Iustin Pop
      - the process is not in state Z (zombie))
534 a8083063 Iustin Pop
   - False otherwise
535 a8083063 Iustin Pop

536 a8083063 Iustin Pop
  """
537 a8083063 Iustin Pop
  try:
538 a8083063 Iustin Pop
    pid_file = file(pid_file, 'r')
539 a8083063 Iustin Pop
    try:
540 a8083063 Iustin Pop
      pid = int(pid_file.readline())
541 a8083063 Iustin Pop
    finally:
542 a8083063 Iustin Pop
      pid_file.close()
543 a8083063 Iustin Pop
544 a8083063 Iustin Pop
    cmdline_file_path = "/proc/%s/cmdline" % (pid)
545 a8083063 Iustin Pop
    cmdline_file = open(cmdline_file_path, 'r')
546 a8083063 Iustin Pop
    try:
547 a8083063 Iustin Pop
      cmdline = cmdline_file.readline()
548 a8083063 Iustin Pop
    finally:
549 a8083063 Iustin Pop
      cmdline_file.close()
550 a8083063 Iustin Pop
551 a8083063 Iustin Pop
    if not process_string in cmdline:
552 a8083063 Iustin Pop
      return False
553 a8083063 Iustin Pop
554 a8083063 Iustin Pop
    stat_file_path =  "/proc/%s/stat" % (pid)
555 a8083063 Iustin Pop
    stat_file = open(stat_file_path, 'r')
556 a8083063 Iustin Pop
    try:
557 a8083063 Iustin Pop
      process_state = stat_file.readline().split()[2]
558 a8083063 Iustin Pop
    finally:
559 a8083063 Iustin Pop
      stat_file.close()
560 a8083063 Iustin Pop
561 a8083063 Iustin Pop
    if process_state == 'Z':
562 a8083063 Iustin Pop
      return False
563 a8083063 Iustin Pop
564 a8083063 Iustin Pop
  except (IndexError, IOError, ValueError):
565 a8083063 Iustin Pop
    return False
566 a8083063 Iustin Pop
567 a8083063 Iustin Pop
  return True
568 a8083063 Iustin Pop
569 a8083063 Iustin Pop
570 a8083063 Iustin Pop
def TryConvert(fn, val):
571 a8083063 Iustin Pop
  """Try to convert a value ignoring errors.
572 a8083063 Iustin Pop

573 a8083063 Iustin Pop
  This function tries to apply function `fn` to `val`. If no
574 a8083063 Iustin Pop
  ValueError or TypeError exceptions are raised, it will return the
575 a8083063 Iustin Pop
  result, else it will return the original value. Any other exceptions
576 a8083063 Iustin Pop
  are propagated to the caller.
577 a8083063 Iustin Pop

578 a8083063 Iustin Pop
  """
579 a8083063 Iustin Pop
  try:
580 a8083063 Iustin Pop
    nv = fn(val)
581 a8083063 Iustin Pop
  except (ValueError, TypeError), err:
582 a8083063 Iustin Pop
    nv = val
583 a8083063 Iustin Pop
  return nv
584 a8083063 Iustin Pop
585 a8083063 Iustin Pop
586 a8083063 Iustin Pop
def IsValidIP(ip):
587 a8083063 Iustin Pop
  """Verifies the syntax of an IP address.
588 a8083063 Iustin Pop

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

592 a8083063 Iustin Pop
  """
593 a8083063 Iustin Pop
  unit = "(0|[1-9]\d{0,2})"
594 a8083063 Iustin Pop
  return re.match("^%s\.%s\.%s\.%s$" % (unit, unit, unit, unit), ip)
595 a8083063 Iustin Pop
596 a8083063 Iustin Pop
597 a8083063 Iustin Pop
def IsValidShellParam(word):
598 a8083063 Iustin Pop
  """Verifies is the given word is safe from the shell's p.o.v.
599 a8083063 Iustin Pop

600 a8083063 Iustin Pop
  This means that we can pass this to a command via the shell and be
601 a8083063 Iustin Pop
  sure that it doesn't alter the command line and is passed as such to
602 a8083063 Iustin Pop
  the actual command.
603 a8083063 Iustin Pop

604 a8083063 Iustin Pop
  Note that we are overly restrictive here, in order to be on the safe
605 a8083063 Iustin Pop
  side.
606 a8083063 Iustin Pop

607 a8083063 Iustin Pop
  """
608 a8083063 Iustin Pop
  return bool(re.match("^[-a-zA-Z0-9._+/:%@]+$", word))
609 a8083063 Iustin Pop
610 a8083063 Iustin Pop
611 a8083063 Iustin Pop
def BuildShellCmd(template, *args):
612 a8083063 Iustin Pop
  """Build a safe shell command line from the given arguments.
613 a8083063 Iustin Pop

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

619 a8083063 Iustin Pop
  """
620 a8083063 Iustin Pop
  for word in args:
621 a8083063 Iustin Pop
    if not IsValidShellParam(word):
622 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Shell argument '%s' contains"
623 3ecf6786 Iustin Pop
                                   " invalid characters" % word)
624 a8083063 Iustin Pop
  return template % args
625 a8083063 Iustin Pop
626 a8083063 Iustin Pop
627 a8083063 Iustin Pop
def FormatUnit(value):
628 a8083063 Iustin Pop
  """Formats an incoming number of MiB with the appropriate unit.
629 a8083063 Iustin Pop

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

632 a8083063 Iustin Pop
  """
633 a8083063 Iustin Pop
  if value < 1024:
634 a8083063 Iustin Pop
    return "%dM" % round(value, 0)
635 a8083063 Iustin Pop
636 a8083063 Iustin Pop
  elif value < (1024 * 1024):
637 a8083063 Iustin Pop
    return "%0.1fG" % round(float(value) / 1024, 1)
638 a8083063 Iustin Pop
639 a8083063 Iustin Pop
  else:
640 a8083063 Iustin Pop
    return "%0.1fT" % round(float(value) / 1024 / 1024, 1)
641 a8083063 Iustin Pop
642 a8083063 Iustin Pop
643 a8083063 Iustin Pop
def ParseUnit(input_string):
644 a8083063 Iustin Pop
  """Tries to extract number and scale from the given string.
645 a8083063 Iustin Pop

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

649 a8083063 Iustin Pop
  """
650 a8083063 Iustin Pop
  m = re.match('^([.\d]+)\s*([a-zA-Z]+)?$', input_string)
651 a8083063 Iustin Pop
  if not m:
652 3ecf6786 Iustin Pop
    raise errors.UnitParseError("Invalid format")
653 a8083063 Iustin Pop
654 a8083063 Iustin Pop
  value = float(m.groups()[0])
655 a8083063 Iustin Pop
656 a8083063 Iustin Pop
  unit = m.groups()[1]
657 a8083063 Iustin Pop
  if unit:
658 a8083063 Iustin Pop
    lcunit = unit.lower()
659 a8083063 Iustin Pop
  else:
660 a8083063 Iustin Pop
    lcunit = 'm'
661 a8083063 Iustin Pop
662 a8083063 Iustin Pop
  if lcunit in ('m', 'mb', 'mib'):
663 a8083063 Iustin Pop
    # Value already in MiB
664 a8083063 Iustin Pop
    pass
665 a8083063 Iustin Pop
666 a8083063 Iustin Pop
  elif lcunit in ('g', 'gb', 'gib'):
667 a8083063 Iustin Pop
    value *= 1024
668 a8083063 Iustin Pop
669 a8083063 Iustin Pop
  elif lcunit in ('t', 'tb', 'tib'):
670 a8083063 Iustin Pop
    value *= 1024 * 1024
671 a8083063 Iustin Pop
672 a8083063 Iustin Pop
  else:
673 3ecf6786 Iustin Pop
    raise errors.UnitParseError("Unknown unit: %s" % unit)
674 a8083063 Iustin Pop
675 a8083063 Iustin Pop
  # Make sure we round up
676 a8083063 Iustin Pop
  if int(value) < value:
677 a8083063 Iustin Pop
    value += 1
678 a8083063 Iustin Pop
679 a8083063 Iustin Pop
  # Round up to the next multiple of 4
680 a8083063 Iustin Pop
  value = int(value)
681 a8083063 Iustin Pop
  if value % 4:
682 a8083063 Iustin Pop
    value += 4 - value % 4
683 a8083063 Iustin Pop
684 a8083063 Iustin Pop
  return value
685 a8083063 Iustin Pop
686 a8083063 Iustin Pop
687 a8083063 Iustin Pop
def AddAuthorizedKey(file_name, key):
688 a8083063 Iustin Pop
  """Adds an SSH public key to an authorized_keys file.
689 a8083063 Iustin Pop

690 a8083063 Iustin Pop
  Args:
691 a8083063 Iustin Pop
    file_name: Path to authorized_keys file
692 a8083063 Iustin Pop
    key: String containing key
693 a8083063 Iustin Pop
  """
694 a8083063 Iustin Pop
  key_fields = key.split()
695 a8083063 Iustin Pop
696 a8083063 Iustin Pop
  f = open(file_name, 'a+')
697 a8083063 Iustin Pop
  try:
698 a8083063 Iustin Pop
    nl = True
699 a8083063 Iustin Pop
    for line in f:
700 a8083063 Iustin Pop
      # Ignore whitespace changes
701 a8083063 Iustin Pop
      if line.split() == key_fields:
702 a8083063 Iustin Pop
        break
703 a8083063 Iustin Pop
      nl = line.endswith('\n')
704 a8083063 Iustin Pop
    else:
705 a8083063 Iustin Pop
      if not nl:
706 a8083063 Iustin Pop
        f.write("\n")
707 a8083063 Iustin Pop
      f.write(key.rstrip('\r\n'))
708 a8083063 Iustin Pop
      f.write("\n")
709 a8083063 Iustin Pop
      f.flush()
710 a8083063 Iustin Pop
  finally:
711 a8083063 Iustin Pop
    f.close()
712 a8083063 Iustin Pop
713 a8083063 Iustin Pop
714 a8083063 Iustin Pop
def RemoveAuthorizedKey(file_name, key):
715 a8083063 Iustin Pop
  """Removes an SSH public key from an authorized_keys file.
716 a8083063 Iustin Pop

717 a8083063 Iustin Pop
  Args:
718 a8083063 Iustin Pop
    file_name: Path to authorized_keys file
719 a8083063 Iustin Pop
    key: String containing key
720 a8083063 Iustin Pop
  """
721 a8083063 Iustin Pop
  key_fields = key.split()
722 a8083063 Iustin Pop
723 a8083063 Iustin Pop
  fd, tmpname = tempfile.mkstemp(dir=os.path.dirname(file_name))
724 a8083063 Iustin Pop
  out = os.fdopen(fd, 'w')
725 a8083063 Iustin Pop
  try:
726 a8083063 Iustin Pop
    f = open(file_name, 'r')
727 a8083063 Iustin Pop
    try:
728 a8083063 Iustin Pop
      for line in f:
729 a8083063 Iustin Pop
        # Ignore whitespace changes while comparing lines
730 a8083063 Iustin Pop
        if line.split() != key_fields:
731 a8083063 Iustin Pop
          out.write(line)
732 a8083063 Iustin Pop
733 a8083063 Iustin Pop
      out.flush()
734 a8083063 Iustin Pop
      os.rename(tmpname, file_name)
735 a8083063 Iustin Pop
    finally:
736 a8083063 Iustin Pop
      f.close()
737 a8083063 Iustin Pop
  finally:
738 a8083063 Iustin Pop
    out.close()
739 a8083063 Iustin Pop
740 a8083063 Iustin Pop
741 a8083063 Iustin Pop
def CreateBackup(file_name):
742 a8083063 Iustin Pop
  """Creates a backup of a file.
743 a8083063 Iustin Pop

744 a8083063 Iustin Pop
  Returns: the path to the newly created backup file.
745 a8083063 Iustin Pop

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

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

781 a8083063 Iustin Pop
  """
782 a8083063 Iustin Pop
  return ' '.join([ShellQuote(i) for i in args])
783 88d14415 Michael Hanselmann
784 88d14415 Michael Hanselmann
785 88d14415 Michael Hanselmann
def _ParseIpOutput(output):
786 88d14415 Michael Hanselmann
  """Parsing code for GetLocalIPAddresses().
787 88d14415 Michael Hanselmann

788 88d14415 Michael Hanselmann
  This function is split out, so we can unit test it.
789 88d14415 Michael Hanselmann

790 88d14415 Michael Hanselmann
  """
791 88d14415 Michael Hanselmann
  re_ip = re.compile('^(\d+\.\d+\.\d+\.\d+)(?:/\d+)$')
792 88d14415 Michael Hanselmann
793 88d14415 Michael Hanselmann
  ips = []
794 88d14415 Michael Hanselmann
  for line in output.splitlines(False):
795 88d14415 Michael Hanselmann
    fields = line.split()
796 88d14415 Michael Hanselmann
    if len(line) < 4:
797 88d14415 Michael Hanselmann
      continue
798 88d14415 Michael Hanselmann
    m = re_ip.match(fields[3])
799 88d14415 Michael Hanselmann
    if m:
800 88d14415 Michael Hanselmann
      ips.append(m.group(1))
801 88d14415 Michael Hanselmann
802 88d14415 Michael Hanselmann
  return ips
803 88d14415 Michael Hanselmann
804 88d14415 Michael Hanselmann
805 88d14415 Michael Hanselmann
def GetLocalIPAddresses():
806 88d14415 Michael Hanselmann
  """Gets a list of all local IP addresses.
807 88d14415 Michael Hanselmann

808 88d14415 Michael Hanselmann
  Should this break one day, a small Python module written in C could
809 88d14415 Michael Hanselmann
  use the API call getifaddrs().
810 88d14415 Michael Hanselmann

811 88d14415 Michael Hanselmann
  """
812 88d14415 Michael Hanselmann
  result = RunCmd(["ip", "-family", "inet", "-oneline", "addr", "show"])
813 88d14415 Michael Hanselmann
  if result.failed:
814 88d14415 Michael Hanselmann
    raise errors.OpExecError("Command '%s' failed, error: %s,"
815 88d14415 Michael Hanselmann
      " output: %s" % (result.cmd, result.fail_reason, result.output))
816 88d14415 Michael Hanselmann
817 88d14415 Michael Hanselmann
  return _ParseIpOutput(result.output)
818 2c30e9d7 Alexander Schreiber
819 2c30e9d7 Alexander Schreiber
820 2c30e9d7 Alexander Schreiber
def TcpPing(source, target, port, timeout=10, live_port_needed=True):
821 2c30e9d7 Alexander Schreiber
  """Simple ping implementation using TCP connect(2).
822 2c30e9d7 Alexander Schreiber

823 2c30e9d7 Alexander Schreiber
  Try to do a TCP connect(2) from the specified source IP to the specified
824 2c30e9d7 Alexander Schreiber
  target IP and the specified target port. If live_port_needed is set to true,
825 2c30e9d7 Alexander Schreiber
  requires the remote end to accept the connection. The timeout is specified
826 2c30e9d7 Alexander Schreiber
  in seconds and defaults to 10 seconds
827 2c30e9d7 Alexander Schreiber

828 2c30e9d7 Alexander Schreiber
  """
829 2c30e9d7 Alexander Schreiber
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
830 2c30e9d7 Alexander Schreiber
831 2c30e9d7 Alexander Schreiber
  sucess = False
832 2c30e9d7 Alexander Schreiber
833 2c30e9d7 Alexander Schreiber
  try:
834 2c30e9d7 Alexander Schreiber
    sock.bind((source, 0))
835 2c30e9d7 Alexander Schreiber
  except socket.error, (errcode, errstring):
836 4ca1b175 Alexander Schreiber
    if errcode == errno.EADDRNOTAVAIL:
837 2c30e9d7 Alexander Schreiber
      success = False
838 2c30e9d7 Alexander Schreiber
839 2c30e9d7 Alexander Schreiber
  sock.settimeout(timeout)
840 2c30e9d7 Alexander Schreiber
841 2c30e9d7 Alexander Schreiber
  try:
842 2c30e9d7 Alexander Schreiber
    sock.connect((target, port))
843 2c30e9d7 Alexander Schreiber
    sock.close()
844 2c30e9d7 Alexander Schreiber
    success = True
845 2c30e9d7 Alexander Schreiber
  except socket.timeout:
846 2c30e9d7 Alexander Schreiber
    success = False
847 2c30e9d7 Alexander Schreiber
  except socket.error, (errcode, errstring):
848 4ca1b175 Alexander Schreiber
    success = (not live_port_needed) and (errcode == errno.ECONNREFUSED)
849 2c30e9d7 Alexander Schreiber
850 2c30e9d7 Alexander Schreiber
  return success
851 eedbda4b Michael Hanselmann
852 eedbda4b Michael Hanselmann
853 eedbda4b Michael Hanselmann
def ListVisibleFiles(path):
854 eedbda4b Michael Hanselmann
  """Returns a list of all visible files in a directory.
855 eedbda4b Michael Hanselmann

856 eedbda4b Michael Hanselmann
  """
857 eedbda4b Michael Hanselmann
  return [i for i in os.listdir(path) if not i.startswith(".")]