Commit 7831fc5f authored by Michael Hanselmann's avatar Michael Hanselmann

utils: Move wrappers into separate file

Signed-off-by: default avatarMichael Hanselmann <hansmi@google.com>
Reviewed-by: default avatarIustin Pop <iustin@google.com>
parent 7b4baeb1
......@@ -218,7 +218,8 @@ utils_PYTHON = \
lib/utils/log.py \
lib/utils/mlock.py \
lib/utils/retry.py \
lib/utils/text.py
lib/utils/text.py \
lib/utils/wrapper.py
docrst = \
doc/admin.rst \
......@@ -489,6 +490,7 @@ python_tests = \
test/ganeti.utils.mlock_unittest.py \
test/ganeti.utils.retry_unittest.py \
test/ganeti.utils.text_unittest.py \
test/ganeti.utils.wrapper_unittest.py \
test/ganeti.utils_unittest.py \
test/ganeti.workerpool_unittest.py \
test/cfgupgrade_unittest.py \
......
......@@ -59,6 +59,7 @@ from ganeti.utils.text import * # pylint: disable-msg=W0401
from ganeti.utils.mlock import * # pylint: disable-msg=W0401
from ganeti.utils.log import * # pylint: disable-msg=W0401
from ganeti.utils.hash import * # pylint: disable-msg=W0401
from ganeti.utils.wrapper import * # pylint: disable-msg=W0401
#: when set to True, L{RunCmd} is disabled
......@@ -662,61 +663,6 @@ def _RunCmdFile(cmd, env, via_shell, output, cwd):
return status
def SetCloseOnExecFlag(fd, enable):
"""Sets or unsets the close-on-exec flag on a file descriptor.
@type fd: int
@param fd: File descriptor
@type enable: bool
@param enable: Whether to set or unset it.
"""
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
if enable:
flags |= fcntl.FD_CLOEXEC
else:
flags &= ~fcntl.FD_CLOEXEC
fcntl.fcntl(fd, fcntl.F_SETFD, flags)
def SetNonblockFlag(fd, enable):
"""Sets or unsets the O_NONBLOCK flag on on a file descriptor.
@type fd: int
@param fd: File descriptor
@type enable: bool
@param enable: Whether to set or unset it
"""
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
if enable:
flags |= os.O_NONBLOCK
else:
flags &= ~os.O_NONBLOCK
fcntl.fcntl(fd, fcntl.F_SETFL, flags)
def RetryOnSignal(fn, *args, **kwargs):
"""Calls a function again if it failed due to EINTR.
"""
while True:
try:
return fn(*args, **kwargs)
except EnvironmentError, err:
if err.errno != errno.EINTR:
raise
except (socket.error, select.error), err:
# In python 2.6 and above select.error is an IOError, so it's handled
# above, in 2.5 and below it's not, and it's handled here.
if not (err.args and err.args[0] == errno.EINTR):
raise
def RunParts(dir_name, env=None, reset_env=False):
"""Run Scripts or programs in a directory
......@@ -1876,41 +1822,6 @@ def WaitForFdCondition(fdobj, event, timeout):
return result
def TestDelay(duration):
"""Sleep for a fixed amount of time.
@type duration: float
@param duration: the sleep duration
@rtype: boolean
@return: False for negative value, True otherwise
"""
if duration < 0:
return False, "Invalid sleep duration"
time.sleep(duration)
return True, None
def CloseFdNoError(fd, retries=5):
"""Close a file descriptor ignoring errors.
@type fd: int
@param fd: the file descriptor
@type retries: int
@param retries: how many retries to make, in case we get any
other error than EBADF
"""
try:
os.close(fd)
except OSError, err:
if err.errno != errno.EBADF:
if retries > 0:
CloseFdNoError(fd, retries - 1)
# else either it's closed already or we're out of retries, so we
# ignore this and go on
def CloseFDs(noclose_fds=None):
"""Close file descriptors.
......@@ -2638,46 +2549,6 @@ def RunInSeparateProcess(fn, *args):
return bool(exitcode)
def IgnoreProcessNotFound(fn, *args, **kwargs):
"""Ignores ESRCH when calling a process-related function.
ESRCH is raised when a process is not found.
@rtype: bool
@return: Whether process was found
"""
try:
fn(*args, **kwargs)
except EnvironmentError, err:
# Ignore ESRCH
if err.errno == errno.ESRCH:
return False
raise
return True
def IgnoreSignals(fn, *args, **kwargs):
"""Tries to call a function ignoring failures due to EINTR.
"""
try:
return fn(*args, **kwargs)
except EnvironmentError, err:
if err.errno == errno.EINTR:
return None
else:
raise
except (select.error, socket.error), err:
# In python 2.6 and above select.error is an IOError, so it's handled
# above, in 2.5 and below it's not, and it's handled here.
if err.args and err.args[0] == errno.EINTR:
return None
else:
raise
def LockFile(fd):
"""Locks a file using POSIX locks.
......@@ -2736,15 +2607,6 @@ def ReadWatcherPauseFile(filename, now=None, remove_after=3600):
return value
def GetClosedTempfile(*args, **kwargs):
"""Creates a temporary file and returns its path.
"""
(fd, path) = tempfile.mkstemp(*args, **kwargs)
CloseFdNoError(fd)
return path
def GenerateSelfSignedX509Cert(common_name, validity):
"""Generates a self-signed X509 certificate.
......
#
#
# Copyright (C) 2006, 2007, 2010, 2011 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
"""Utility functions wrapping other functions.
"""
import time
import socket
import errno
import tempfile
import fcntl
import os
import select
def TestDelay(duration):
"""Sleep for a fixed amount of time.
@type duration: float
@param duration: the sleep duration
@rtype: boolean
@return: False for negative value, True otherwise
"""
if duration < 0:
return False, "Invalid sleep duration"
time.sleep(duration)
return True, None
def CloseFdNoError(fd, retries=5):
"""Close a file descriptor ignoring errors.
@type fd: int
@param fd: the file descriptor
@type retries: int
@param retries: how many retries to make, in case we get any
other error than EBADF
"""
try:
os.close(fd)
except OSError, err:
if err.errno != errno.EBADF:
if retries > 0:
CloseFdNoError(fd, retries - 1)
# else either it's closed already or we're out of retries, so we
# ignore this and go on
def SetCloseOnExecFlag(fd, enable):
"""Sets or unsets the close-on-exec flag on a file descriptor.
@type fd: int
@param fd: File descriptor
@type enable: bool
@param enable: Whether to set or unset it.
"""
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
if enable:
flags |= fcntl.FD_CLOEXEC
else:
flags &= ~fcntl.FD_CLOEXEC
fcntl.fcntl(fd, fcntl.F_SETFD, flags)
def SetNonblockFlag(fd, enable):
"""Sets or unsets the O_NONBLOCK flag on on a file descriptor.
@type fd: int
@param fd: File descriptor
@type enable: bool
@param enable: Whether to set or unset it
"""
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
if enable:
flags |= os.O_NONBLOCK
else:
flags &= ~os.O_NONBLOCK
fcntl.fcntl(fd, fcntl.F_SETFL, flags)
def RetryOnSignal(fn, *args, **kwargs):
"""Calls a function again if it failed due to EINTR.
"""
while True:
try:
return fn(*args, **kwargs)
except EnvironmentError, err:
if err.errno != errno.EINTR:
raise
except (socket.error, select.error), err:
# In python 2.6 and above select.error is an IOError, so it's handled
# above, in 2.5 and below it's not, and it's handled here.
if not (err.args and err.args[0] == errno.EINTR):
raise
def IgnoreProcessNotFound(fn, *args, **kwargs):
"""Ignores ESRCH when calling a process-related function.
ESRCH is raised when a process is not found.
@rtype: bool
@return: Whether process was found
"""
try:
fn(*args, **kwargs)
except EnvironmentError, err:
# Ignore ESRCH
if err.errno == errno.ESRCH:
return False
raise
return True
def IgnoreSignals(fn, *args, **kwargs):
"""Tries to call a function ignoring failures due to EINTR.
"""
try:
return fn(*args, **kwargs)
except EnvironmentError, err:
if err.errno == errno.EINTR:
return None
else:
raise
except (select.error, socket.error), err:
# In python 2.6 and above select.error is an IOError, so it's handled
# above, in 2.5 and below it's not, and it's handled here.
if err.args and err.args[0] == errno.EINTR:
return None
else:
raise
def GetClosedTempfile(*args, **kwargs):
"""Creates a temporary file and returns its path.
"""
(fd, path) = tempfile.mkstemp(*args, **kwargs)
CloseFdNoError(fd)
return path
#!/usr/bin/python
#
# Copyright (C) 2006, 2007, 2010, 2011 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
"""Script for testing ganeti.utils.wrapper"""
import errno
import fcntl
import os
import socket
import tempfile
import unittest
from ganeti import constants
from ganeti import utils
import testutils
class TestSetCloseOnExecFlag(unittest.TestCase):
"""Tests for SetCloseOnExecFlag"""
def setUp(self):
self.tmpfile = tempfile.TemporaryFile()
def testEnable(self):
utils.SetCloseOnExecFlag(self.tmpfile.fileno(), True)
self.failUnless(fcntl.fcntl(self.tmpfile.fileno(), fcntl.F_GETFD) &
fcntl.FD_CLOEXEC)
def testDisable(self):
utils.SetCloseOnExecFlag(self.tmpfile.fileno(), False)
self.failIf(fcntl.fcntl(self.tmpfile.fileno(), fcntl.F_GETFD) &
fcntl.FD_CLOEXEC)
class TestSetNonblockFlag(unittest.TestCase):
def setUp(self):
self.tmpfile = tempfile.TemporaryFile()
def testEnable(self):
utils.SetNonblockFlag(self.tmpfile.fileno(), True)
self.failUnless(fcntl.fcntl(self.tmpfile.fileno(), fcntl.F_GETFL) &
os.O_NONBLOCK)
def testDisable(self):
utils.SetNonblockFlag(self.tmpfile.fileno(), False)
self.failIf(fcntl.fcntl(self.tmpfile.fileno(), fcntl.F_GETFL) &
os.O_NONBLOCK)
class TestIgnoreProcessNotFound(unittest.TestCase):
@staticmethod
def _WritePid(fd):
os.write(fd, str(os.getpid()))
os.close(fd)
return True
def test(self):
(pid_read_fd, pid_write_fd) = os.pipe()
# Start short-lived process which writes its PID to pipe
self.assert_(utils.RunInSeparateProcess(self._WritePid, pid_write_fd))
os.close(pid_write_fd)
# Read PID from pipe
pid = int(os.read(pid_read_fd, 1024))
os.close(pid_read_fd)
# Try to send signal to process which exited recently
self.assertFalse(utils.IgnoreProcessNotFound(os.kill, pid, 0))
class TestIgnoreSignals(unittest.TestCase):
"""Test the IgnoreSignals decorator"""
@staticmethod
def _Raise(exception):
raise exception
@staticmethod
def _Return(rval):
return rval
def testIgnoreSignals(self):
sock_err_intr = socket.error(errno.EINTR, "Message")
sock_err_inval = socket.error(errno.EINVAL, "Message")
env_err_intr = EnvironmentError(errno.EINTR, "Message")
env_err_inval = EnvironmentError(errno.EINVAL, "Message")
self.assertRaises(socket.error, self._Raise, sock_err_intr)
self.assertRaises(socket.error, self._Raise, sock_err_inval)
self.assertRaises(EnvironmentError, self._Raise, env_err_intr)
self.assertRaises(EnvironmentError, self._Raise, env_err_inval)
self.assertEquals(utils.IgnoreSignals(self._Raise, sock_err_intr), None)
self.assertEquals(utils.IgnoreSignals(self._Raise, env_err_intr), None)
self.assertRaises(socket.error, utils.IgnoreSignals, self._Raise,
sock_err_inval)
self.assertRaises(EnvironmentError, utils.IgnoreSignals, self._Raise,
env_err_inval)
self.assertEquals(utils.IgnoreSignals(self._Return, True), True)
self.assertEquals(utils.IgnoreSignals(self._Return, 33), 33)
if __name__ == "__main__":
testutils.GanetiTestProgram()
#!/usr/bin/python
#
# Copyright (C) 2006, 2007, 2010 Google Inc.
# Copyright (C) 2006, 2007, 2010, 2011 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
......@@ -627,38 +627,6 @@ class TestStartDaemon(testutils.GanetiTestCase):
os.close(fd)
class TestSetCloseOnExecFlag(unittest.TestCase):
"""Tests for SetCloseOnExecFlag"""
def setUp(self):
self.tmpfile = tempfile.TemporaryFile()
def testEnable(self):
utils.SetCloseOnExecFlag(self.tmpfile.fileno(), True)
self.failUnless(fcntl.fcntl(self.tmpfile.fileno(), fcntl.F_GETFD) &
fcntl.FD_CLOEXEC)
def testDisable(self):
utils.SetCloseOnExecFlag(self.tmpfile.fileno(), False)
self.failIf(fcntl.fcntl(self.tmpfile.fileno(), fcntl.F_GETFD) &
fcntl.FD_CLOEXEC)
class TestSetNonblockFlag(unittest.TestCase):
def setUp(self):
self.tmpfile = tempfile.TemporaryFile()
def testEnable(self):
utils.SetNonblockFlag(self.tmpfile.fileno(), True)
self.failUnless(fcntl.fcntl(self.tmpfile.fileno(), fcntl.F_GETFL) &
os.O_NONBLOCK)
def testDisable(self):
utils.SetNonblockFlag(self.tmpfile.fileno(), False)
self.failIf(fcntl.fcntl(self.tmpfile.fileno(), fcntl.F_GETFL) &
os.O_NONBLOCK)
class TestRemoveFile(unittest.TestCase):
"""Test case for the RemoveFile function"""
......@@ -1801,40 +1769,6 @@ class TestVerifyCertificateInner(unittest.TestCase):
self.assertEqual(errcode, utils.CERT_ERROR)
class TestIgnoreSignals(unittest.TestCase):
"""Test the IgnoreSignals decorator"""
@staticmethod
def _Raise(exception):
raise exception
@staticmethod
def _Return(rval):
return rval
def testIgnoreSignals(self):
sock_err_intr = socket.error(errno.EINTR, "Message")
sock_err_inval = socket.error(errno.EINVAL, "Message")
env_err_intr = EnvironmentError(errno.EINTR, "Message")
env_err_inval = EnvironmentError(errno.EINVAL, "Message")
self.assertRaises(socket.error, self._Raise, sock_err_intr)
self.assertRaises(socket.error, self._Raise, sock_err_inval)
self.assertRaises(EnvironmentError, self._Raise, env_err_intr)
self.assertRaises(EnvironmentError, self._Raise, env_err_inval)
self.assertEquals(utils.IgnoreSignals(self._Raise, sock_err_intr), None)
self.assertEquals(utils.IgnoreSignals(self._Raise, env_err_intr), None)
self.assertRaises(socket.error, utils.IgnoreSignals, self._Raise,
sock_err_inval)
self.assertRaises(EnvironmentError, utils.IgnoreSignals, self._Raise,
env_err_inval)
self.assertEquals(utils.IgnoreSignals(self._Return, True), True)
self.assertEquals(utils.IgnoreSignals(self._Return, 33), 33)
class TestEnsureDirs(unittest.TestCase):
"""Tests for EnsureDirs"""
......@@ -1857,28 +1791,6 @@ class TestEnsureDirs(unittest.TestCase):
os.umask(self.old_umask)
class TestIgnoreProcessNotFound(unittest.TestCase):
@staticmethod
def _WritePid(fd):
os.write(fd, str(os.getpid()))
os.close(fd)
return True
def test(self):
(pid_read_fd, pid_write_fd) = os.pipe()
# Start short-lived process which writes its PID to pipe
self.assert_(utils.RunInSeparateProcess(self._WritePid, pid_write_fd))
os.close(pid_write_fd)
# Read PID from pipe
pid = int(os.read(pid_read_fd, 1024))
os.close(pid_read_fd)
# Try to send signal to process which exited recently
self.assertFalse(utils.IgnoreProcessNotFound(os.kill, pid, 0))
class TestFindMatch(unittest.TestCase):
def test(self):
data = {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment