diff --git a/lib/daemon.py b/lib/daemon.py index 21aab9227c42a49c3542421535d9ad31c3a3b719..e386d8c4eee0a3ff2cc6ef60b24b521708d4a793 100644 --- a/lib/daemon.py +++ b/lib/daemon.py @@ -112,10 +112,12 @@ class AsyncUDPSocket(GanetiBaseAsyncoreDispatcher): # this method is overriding an asyncore.dispatcher method def handle_read(self): - payload, address = utils.IgnoreSignals(self.recvfrom, - constants.MAX_UDP_DATA_SIZE) - ip, port = address - self.handle_datagram(payload, ip, port) + recv_result = utils.IgnoreSignals(self.recvfrom, + constants.MAX_UDP_DATA_SIZE) + if recv_result is not None: + payload, address = recv_result + ip, port = address + self.handle_datagram(payload, ip, port) def handle_datagram(self, payload, ip, port): """Handle an already read udp datagram diff --git a/lib/utils.py b/lib/utils.py index 216a9eaa96c264e53b98586745105f11ec4f3387..70f5b41fa545d7457ef88adbd9a33008ba3bccae 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -3104,12 +3104,16 @@ def IgnoreSignals(fn, *args, **kwargs): try: return fn(*args, **kwargs) except EnvironmentError, err: - if err.errno != errno.EINTR: + 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 not (err.args and err.args[0] == errno.EINTR): + if err.args and err.args[0] == errno.EINTR: + return None + else: raise diff --git a/man/gnt-instance.sgml b/man/gnt-instance.sgml index 9e10af9917858ce736df2593605185935e556a28..9d2a9fef6331b932324d4f8b6fdb5256536b6daf 100644 --- a/man/gnt-instance.sgml +++ b/man/gnt-instance.sgml @@ -690,7 +690,24 @@ <simpara>This option is only effective with kvm versions >= 87 and qemu-kvm versions >= 0.11.0. </simpara> + </listitem> + </varlistentry> + <varlistentry> + <term>use_chroot</term> + <listitem> + <simpara>Valid for the KVM hypervisor.</simpara> + + <simpara>This boolean option determines wether to run the KVM + instance in a chroot directory. + </simpara> + <para>If it is set to <quote>true</quote>, an empty directory + is created before starting the instance and its path is passed via + the -chroot flag to kvm. + The directory is removed when the instance is stopped. + </para> + + <simpara>It is set to <quote>false</quote> by default.</simpara> </listitem> </varlistentry> diff --git a/test/ganeti.compat_unittest.py b/test/ganeti.compat_unittest.py index dbe9940e71403666d44c1d7f94f216a50b01172b..54a1c626f93ca9139b9d368a1028cf4fd7426af1 100755 --- a/test/ganeti.compat_unittest.py +++ b/test/ganeti.compat_unittest.py @@ -61,11 +61,31 @@ class TestPartial(testutils.GanetiTestCase): class TestTryToRoman(testutils.GanetiTestCase): """test the compat.TryToRoman function""" + def setUp(self): + testutils.GanetiTestCase.setUp(self) + # Save the compat.roman module so we can alter it with a fake... + self.compat_roman_module = compat.roman + + def tearDown(self): + # ...and restore it at the end of the test + compat.roman = self.compat_roman_module + testutils.GanetiTestCase.tearDown(self) + def testAFewIntegers(self): + # This test only works is the roman module is installed + if compat.roman is not None: + self.assertEquals(compat.TryToRoman(0), 0) + self.assertEquals(compat.TryToRoman(1), "I") + self.assertEquals(compat.TryToRoman(4), "IV") + self.assertEquals(compat.TryToRoman(5), "V") + + def testWithNoRoman(self): + # compat.roman is saved/restored in setUp/tearDown + compat.roman = None self.assertEquals(compat.TryToRoman(0), 0) - self.assertEquals(compat.TryToRoman(1), "I") - self.assertEquals(compat.TryToRoman(4), "IV") - self.assertEquals(compat.TryToRoman(5), "V") + self.assertEquals(compat.TryToRoman(1), 1) + self.assertEquals(compat.TryToRoman(4), 4) + self.assertEquals(compat.TryToRoman(5), 5) def testStrings(self): self.assertEquals(compat.TryToRoman("astring"), "astring") diff --git a/test/ganeti.daemon_unittest.py b/test/ganeti.daemon_unittest.py index 143be9d4c23fd7661ae28a907b335d4a8bb2f447..977a073f9d36188f902de153e2862e06aceb4847 100755 --- a/test/ganeti.daemon_unittest.py +++ b/test/ganeti.daemon_unittest.py @@ -29,6 +29,7 @@ import time from ganeti import daemon from ganeti import errors +from ganeti import utils import testutils @@ -172,10 +173,14 @@ class TestAsyncUDPSocket(testutils.GanetiTestCase): self.client = _MyAsyncUDPSocket() self.server.bind(("127.0.0.1", 0)) self.port = self.server.getsockname()[1] + # Save utils.IgnoreSignals so we can do evil things to it... + self.saved_utils_ignoresignals = utils.IgnoreSignals def tearDown(self): self.server.close() self.client.close() + # ...and restore it as well + utils.IgnoreSignals = self.saved_utils_ignoresignals testutils.GanetiTestCase.tearDown(self) def testNoDoubleBind(self): @@ -229,6 +234,17 @@ class TestAsyncUDPSocket(testutils.GanetiTestCase): ["p1", "p2", "error", "p3", "error", "terminate"]) self.assertEquals(self.server.error_count, 2) + def testSignaledWhileReceiving(self): + utils.IgnoreSignals = lambda fn, *args, **kwargs: None + self.client.enqueue_send("127.0.0.1", self.port, "p1") + self.client.enqueue_send("127.0.0.1", self.port, "p2") + self.server.handle_read() + self.assertEquals(self.server.received, []) + self.client.enqueue_send("127.0.0.1", self.port, "terminate") + utils.IgnoreSignals = self.saved_utils_ignoresignals + self.mainloop.Run() + self.assertEquals(self.server.received, ["p1", "p2", "terminate"]) + if __name__ == "__main__": testutils.GanetiTestProgram()