+
+
+
+def TcpPing(source, target, port, timeout=10, live_port_needed=False):
+ """Simple ping implementation using TCP connect(2).
+
+ Try to do a TCP connect(2) from the specified source IP to the specified
+ target IP and the specified target port. If live_port_needed is set to true,
+ requires the remote end to accept the connection. The timeout is specified
+ in seconds and defaults to 10 seconds
+
+ """
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+ sucess = False
+
+ try:
+ sock.bind((source, 0))
+ except socket.error, (errcode, errstring):
+ if errcode == errno.EADDRNOTAVAIL:
+ success = False
+
+ sock.settimeout(timeout)
+
+ try:
+ sock.connect((target, port))
+ sock.close()
+ success = True
+ except socket.timeout:
+ success = False
+ except socket.error, (errcode, errstring):
+ success = (not live_port_needed) and (errcode == errno.ECONNREFUSED)
+
+ return success
+
+
+def ListVisibleFiles(path):
+ """Returns a list of all visible files in a directory.
+
+ """
+ files = [i for i in os.listdir(path) if not i.startswith(".")]
+ files.sort()
+ return files
+
+
+def GetHomeDir(user, default=None):
+ """Try to get the homedir of the given user.
+
+ The user can be passed either as a string (denoting the name) or as
+ an integer (denoting the user id). If the user is not found, the
+ 'default' argument is returned, which defaults to None.
+
+ """
+ try:
+ if isinstance(user, basestring):
+ result = pwd.getpwnam(user)
+ elif isinstance(user, (int, long)):
+ result = pwd.getpwuid(user)
+ else:
+ raise errors.ProgrammerError("Invalid type passed to GetHomeDir (%s)" %
+ type(user))
+ except KeyError:
+ return default
+ return result.pw_dir
+
+
+def NewUUID():
+ """Returns a random UUID.
+
+ """
+ f = open("/proc/sys/kernel/random/uuid", "r")
+ try:
+ return f.read(128).rstrip("\n")
+ finally:
+ f.close()
+
+
+def WriteFile(file_name, fn=None, data=None,
+ mode=None, uid=-1, gid=-1,
+ atime=None, mtime=None):
+ """(Over)write a file atomically.
+
+ The file_name and either fn (a function taking one argument, the
+ file descriptor, and which should write the data to it) or data (the
+ contents of the file) must be passed. The other arguments are
+ optional and allow setting the file mode, owner and group, and the
+ mtime/atime of the file.
+
+ If the function doesn't raise an exception, it has succeeded and the
+ target file has the new contents. If the file has raised an
+ exception, an existing target file should be unmodified and the
+ temporary file should be removed.
+
+ """
+ if not os.path.isabs(file_name):
+ raise errors.ProgrammerError("Path passed to WriteFile is not"
+ " absolute: '%s'" % file_name)
+
+ if [fn, data].count(None) != 1:
+ raise errors.ProgrammerError("fn or data required")
+
+ if [atime, mtime].count(None) == 1:
+ raise errors.ProgrammerError("Both atime and mtime must be either"
+ " set or None")
+
+
+ dir_name, base_name = os.path.split(file_name)
+ fd, new_name = tempfile.mkstemp('.new', base_name, dir_name)
+ # here we need to make sure we remove the temp file, if any error
+ # leaves it in place
+ try:
+ if uid != -1 or gid != -1:
+ os.chown(new_name, uid, gid)
+ if mode:
+ os.chmod(new_name, mode)
+ if data is not None:
+ os.write(fd, data)
+ else:
+ fn(fd)
+ os.fsync(fd)
+ if atime is not None and mtime is not None:
+ os.utime(new_name, (atime, mtime))
+ os.rename(new_name, file_name)
+ finally:
+ os.close(fd)
+ RemoveFile(new_name)
+
+
+def all(seq, pred=bool):
+ "Returns True if pred(x) is True for every element in the iterable"
+ for elem in itertools.ifilterfalse(pred, seq):
+ return False
+ return True
+
+
+def any(seq, pred=bool):
+ "Returns True if pred(x) is True for at least one element in the iterable"
+ for elem in itertools.ifilter(pred, seq):
+ return True
+ return False
+
+
+def UniqueSequence(seq):
+ """Returns a list with unique elements.
+
+ Element order is preserved.
+ """
+ seen = set()
+ return [i for i in seq if i not in seen and not seen.add(i)]
+
+
+def IsValidMac(mac):
+ """Predicate to check if a MAC address is valid.
+
+ Checks wether the supplied MAC address is formally correct, only
+ accepts colon separated format.
+ """
+ mac_check = re.compile("^([0-9a-f]{2}(:|$)){6}$")
+ return mac_check.match(mac) is not None
+
+
+def TestDelay(duration):
+ """Sleep for a fixed amount of time.
+
+ """
+ if duration < 0:
+ return False
+ time.sleep(duration)
+ return True