Commit 44201856 authored by Rodolfo Alonso Hernandez's avatar Rodolfo Alonso Hernandez Committed by Peter V. Saveliev

Stop NetNS server gracefully

This patch changes the way of stopping the NetNS server, by sending
a SIGTERM signal and waiting for the server loop to finish. When the
signal is received, the loop control flag is inverted. Once the loop
is finished, the server process ends.

This patch also modifies the Transport class receiver function loops.
When the Transport object is closed, the receiver loops are stopped but
not the file descriptors. Those file descriptors, created in the NetNS
parent class, are closed at the end of the NetNS.close function, once
the child process (Server) is finished and the Transport receiver loops
are stopped. At this point, the file descriptors are not in use and can
be closed.

closes #578
parent cb43cdf3
......@@ -167,6 +167,8 @@ class NetNS(RTNL_API, RemoteSocket):
os._exit(0)
try:
self.remote_trnsp_in.close()
self.remote_trnsp_out.close()
super(NetNS, self).__init__(trnsp_in, trnsp_out)
except Exception:
self.close()
......@@ -197,18 +199,9 @@ class NetNS(RTNL_API, RemoteSocket):
except Exception:
pass
log.error('forced shutdown procedure, clean up netns manually')
# force cleanup command channels
for close in (self.trnsp_in.close,
self.trnsp_out.close,
self.remote_trnsp_in.close,
self.remote_trnsp_out.close):
try:
close()
except Exception:
pass # Maybe already closed in remote.Client.close
try:
os.kill(self.child, signal.SIGKILL)
os.kill(self.child, signal.SIGTERM)
os.waitpid(self.child, 0)
except OSError:
pass
......
......@@ -4,6 +4,7 @@ import pickle
import select
import struct
import logging
import signal
import threading
import traceback
from io import BytesIO
......@@ -33,6 +34,7 @@ class Transport(object):
self.lock = threading.Lock()
self.cmd_queue = queue.Queue()
self.brd_queue = queue.Queue()
self.run = True
def fileno(self):
return self.file_obj.fileno()
......@@ -54,7 +56,7 @@ class Transport(object):
return ret
def recv(self):
while True:
while self.run:
with self.lock:
if not self.brd_queue.empty():
return self.brd_queue.get()
......@@ -70,7 +72,7 @@ class Transport(object):
self.cmd_queue.put(ret)
def recv_cmd(self):
while True:
while self.run:
with self.lock:
if not self.cmd_queue.empty():
return self.cmd_queue.get()
......@@ -80,7 +82,7 @@ class Transport(object):
self.brd_queue.put(ret)
def close(self):
self.file_obj.close()
self.run = False
class ProxyChannel(object):
......@@ -97,6 +99,12 @@ class ProxyChannel(object):
def Server(trnsp_in, trnsp_out):
def stop_server(signum, frame):
Server.run = False
Server.run = True
signal.signal(signal.SIGTERM, stop_server)
try:
ipr = IPRoute()
lock = ipr._sproxy.lock
......@@ -116,7 +124,7 @@ def Server(trnsp_in, trnsp_out):
'error': None})
# 8<-------------------------------------------------------------
while True:
while Server.run:
try:
events, _, _ = select.select(inputs, outputs, inputs)
except:
......@@ -253,16 +261,25 @@ class RemoteSocket(NetlinkMixin):
'error': None})
with self.trnsp_in.lock:
pass
for trnsp in (self.trnsp_out,
self.trnsp_in,
self.remote_trnsp_in,
self.remote_trnsp_out):
transport_objs = (self.trnsp_out, self.trnsp_in,
self.remote_trnsp_in, self.remote_trnsp_out)
# Stop the transport objects.
for trnsp in transport_objs:
try:
if hasattr(trnsp, 'close'):
trnsp.close()
except Exception:
pass
# Close the file descriptors.
for trnsp in transport_objs:
try:
trnsp.file_obj.close()
except Exception:
pass
def proxy(self, cmd, *argv, **kwarg):
with self.cmdlock:
self.trnsp_out.send({'stage': 'command',
......
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