X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/de0ea66b3a256ecd23ef48316f2168eefda5b3b5..d24cb69273e4b03ffcd4e4768d95841b5570e264:/lib/utils.py diff --git a/lib/utils.py b/lib/utils.py index e324dfe..f08e75c 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -42,7 +42,6 @@ import fcntl import resource import logging import signal -import string from cStringIO import StringIO @@ -320,8 +319,17 @@ def RenameFile(old, new, mkdir=False, mkdir_mode=0750): # as efficient. if mkdir and err.errno == errno.ENOENT: # Create directory and try again - os.makedirs(os.path.dirname(new), mkdir_mode) + dirname = os.path.dirname(new) + try: + os.makedirs(dirname, mode=mkdir_mode) + except OSError, err: + # Ignore EEXIST. This is only handled in os.makedirs as included in + # Python 2.5 and above. + if err.errno != errno.EEXIST or not os.path.exists(dirname): + raise + return os.rename(old, new) + raise @@ -519,14 +527,14 @@ def MatchNameComponent(key, name_list, case_sensitive=True): re_flags = 0 if not case_sensitive: re_flags |= re.IGNORECASE - key = string.upper(key) + key = key.upper() mo = re.compile("^%s(\..*)?$" % re.escape(key), re_flags) names_filtered = [] string_matches = [] for name in name_list: if mo.match(name) is not None: names_filtered.append(name) - if not case_sensitive and key == string.upper(name): + if not case_sensitive and key == name.upper(): string_matches.append(name) if len(string_matches) == 1: @@ -591,6 +599,16 @@ class HostInfo: return result +def GetHostInfo(name=None): + """Lookup host name and raise an OpPrereqError for failures""" + + try: + return HostInfo(name) + except errors.ResolverError, err: + raise errors.OpPrereqError("The given name (%s) does not resolve: %s" % + (err[0], err[2]), errors.ECODE_RESOLVER) + + def ListVolumeGroups(): """List volume groups and their size @@ -1107,7 +1125,7 @@ def TcpPing(target, port, timeout=10, live_port_needed=False, source=None): success = True except socket.timeout: success = False - except socket.error, (errcode, errstring): + except socket.error, (errcode, _): success = (not live_port_needed) and (errcode == errno.ECONNREFUSED) return success @@ -1208,21 +1226,18 @@ def EnsureDirs(dirs): raise errors.GenericError("%s is not a directory" % dir_name) -def ReadFile(file_name, size=None): +def ReadFile(file_name, size=-1): """Reads a file. - @type size: None or int - @param size: Read at most size bytes + @type size: int + @param size: Read at most size bytes (if negative, entire file) @rtype: str @return: the (possibly partial) content of the file """ f = open(file_name, "r") try: - if size is None: - return f.read() - else: - return f.read(size) + return f.read(size) finally: f.close() @@ -1589,24 +1604,31 @@ def KillProcess(pid, signal_=signal.SIGTERM, timeout=30, if not IsProcessAlive(pid): return + _helper(pid, signal_, waitpid) + if timeout <= 0: return - # Wait up to $timeout seconds - end = time.time() + timeout - wait = 0.01 - while time.time() < end and IsProcessAlive(pid): + def _CheckProcess(): + if not IsProcessAlive(pid): + return + try: (result_pid, _) = os.waitpid(pid, os.WNOHANG) - if result_pid > 0: - break except OSError: - pass - time.sleep(wait) - # Make wait time longer for next try - if wait < 0.1: - wait *= 1.5 + raise RetryAgain() + + if result_pid > 0: + return + + raise RetryAgain() + + try: + # Wait up to $timeout seconds + Retry(_CheckProcess, (0.01, 1.5, 0.1), timeout) + except RetryTimeout: + pass if IsProcessAlive(pid): # Kill process if it's still alive @@ -1859,6 +1881,16 @@ def SafeEncode(text): return resu +def CommaJoin(names): + """Nicely join a set of identifiers. + + @param names: set, list or tuple + @return: a string with the formatted results + + """ + return ", ".join([str(val) for val in names]) + + def BytesToMebibyte(value): """Converts bytes to mebibytes. @@ -2197,6 +2229,8 @@ class FileLock(object): flag |= fcntl.LOCK_NB timeout_end = None + # TODO: Convert to utils.Retry + retry = True while retry: try: @@ -2395,12 +2429,12 @@ class FieldSet(object): @type field: str @param field: the string to match - @return: either False or a regular expression match object + @return: either None or a regular expression match object """ for m in itertools.ifilter(None, (val.match(field) for val in self.items)): return m - return False + return None def NonMatching(self, items): """Returns the list of fields not matching the current set