ensure_dirs: Move some useful functions into utils.
[ganeti-local] / lib / utils / wrapper.py
1 #
2 #
3
4 # Copyright (C) 2006, 2007, 2010, 2011 Google Inc.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 # 02110-1301, USA.
20
21 """Utility functions wrapping other functions.
22
23 """
24
25 import time
26 import socket
27 import errno
28 import tempfile
29 import fcntl
30 import os
31 import select
32 import logging
33
34
35 def TestDelay(duration):
36   """Sleep for a fixed amount of time.
37
38   @type duration: float
39   @param duration: the sleep duration
40   @rtype: boolean
41   @return: False for negative value, True otherwise
42
43   """
44   if duration < 0:
45     return False, "Invalid sleep duration"
46   time.sleep(duration)
47   return True, None
48
49
50 def CloseFdNoError(fd, retries=5):
51   """Close a file descriptor ignoring errors.
52
53   @type fd: int
54   @param fd: the file descriptor
55   @type retries: int
56   @param retries: how many retries to make, in case we get any
57       other error than EBADF
58
59   """
60   try:
61     os.close(fd)
62   except OSError, err:
63     if err.errno != errno.EBADF:
64       if retries > 0:
65         CloseFdNoError(fd, retries - 1)
66     # else either it's closed already or we're out of retries, so we
67     # ignore this and go on
68
69
70 def SetCloseOnExecFlag(fd, enable):
71   """Sets or unsets the close-on-exec flag on a file descriptor.
72
73   @type fd: int
74   @param fd: File descriptor
75   @type enable: bool
76   @param enable: Whether to set or unset it.
77
78   """
79   flags = fcntl.fcntl(fd, fcntl.F_GETFD)
80
81   if enable:
82     flags |= fcntl.FD_CLOEXEC
83   else:
84     flags &= ~fcntl.FD_CLOEXEC
85
86   fcntl.fcntl(fd, fcntl.F_SETFD, flags)
87
88
89 def SetNonblockFlag(fd, enable):
90   """Sets or unsets the O_NONBLOCK flag on on a file descriptor.
91
92   @type fd: int
93   @param fd: File descriptor
94   @type enable: bool
95   @param enable: Whether to set or unset it
96
97   """
98   flags = fcntl.fcntl(fd, fcntl.F_GETFL)
99
100   if enable:
101     flags |= os.O_NONBLOCK
102   else:
103     flags &= ~os.O_NONBLOCK
104
105   fcntl.fcntl(fd, fcntl.F_SETFL, flags)
106
107
108 def RetryOnSignal(fn, *args, **kwargs):
109   """Calls a function again if it failed due to EINTR.
110
111   """
112   while True:
113     try:
114       return fn(*args, **kwargs)
115     except EnvironmentError, err:
116       if err.errno != errno.EINTR:
117         raise
118     except (socket.error, select.error), err:
119       # In python 2.6 and above select.error is an IOError, so it's handled
120       # above, in 2.5 and below it's not, and it's handled here.
121       if not (err.args and err.args[0] == errno.EINTR):
122         raise
123
124
125 def IgnoreProcessNotFound(fn, *args, **kwargs):
126   """Ignores ESRCH when calling a process-related function.
127
128   ESRCH is raised when a process is not found.
129
130   @rtype: bool
131   @return: Whether process was found
132
133   """
134   try:
135     fn(*args, **kwargs)
136   except EnvironmentError, err:
137     # Ignore ESRCH
138     if err.errno == errno.ESRCH:
139       return False
140     raise
141
142   return True
143
144
145 def IgnoreSignals(fn, *args, **kwargs):
146   """Tries to call a function ignoring failures due to EINTR.
147
148   """
149   try:
150     return fn(*args, **kwargs)
151   except EnvironmentError, err:
152     if err.errno == errno.EINTR:
153       return None
154     else:
155       raise
156   except (select.error, socket.error), err:
157     # In python 2.6 and above select.error is an IOError, so it's handled
158     # above, in 2.5 and below it's not, and it's handled here.
159     if err.args and err.args[0] == errno.EINTR:
160       return None
161     else:
162       raise
163
164
165 def GetClosedTempfile(*args, **kwargs):
166   """Creates a temporary file and returns its path.
167
168   """
169   (fd, path) = tempfile.mkstemp(*args, **kwargs)
170   CloseFdNoError(fd)
171   return path
172
173
174 def ResetTempfileModule():
175   """Resets the random name generator of the tempfile module.
176
177   This function should be called after C{os.fork} in the child process to
178   ensure it creates a newly seeded random generator. Otherwise it would
179   generate the same random parts as the parent process. If several processes
180   race for the creation of a temporary file, this could lead to one not getting
181   a temporary name.
182
183   """
184   # pylint: disable=W0212
185   if hasattr(tempfile, "_once_lock") and hasattr(tempfile, "_name_sequence"):
186     tempfile._once_lock.acquire()
187     try:
188       # Reset random name generator
189       tempfile._name_sequence = None
190     finally:
191       tempfile._once_lock.release()
192   else:
193     logging.critical("The tempfile module misses at least one of the"
194                      " '_once_lock' and '_name_sequence' attributes")