def NSPopenServer(nsname, flags, channel_in, channel_out, argv, kwarg): # set netns try: setns(nsname, flags=flags, libc=kwarg.pop('libc', None)) except Exception as e: channel_out.put(e) return # create the Popen object child = subprocess.Popen(*argv, **kwarg) for fname in ['stdout', 'stderr', 'stdin']: obj = getattr(child, fname) if obj is not None: fproxy = NSPopenFile(obj) setattr(child, fname, fproxy) # send the API map channel_out.put(None) while True: # synchronous mode # 1. get the command from the API try: call = channel_in.get() except: (et, ev, tb) = sys.exc_info() try: channel_out.put({'code': 500, 'data': ev}) except: pass break # 2. stop? if call['name'] == 'release': break # 3. run the call try: # get the object namespace ns = call.get('namespace') obj = child if ns: for step in ns.split('.'): obj = getattr(obj, step) attr = getattr(obj, call['name']) if isinstance(attr, (types.MethodType, types.FunctionType, types.BuiltinMethodType)): result = attr(*call['argv'], **call['kwarg']) else: result = attr channel_out.put({'code': 200, 'data': result}) except: (et, ev, tb) = sys.exc_info() channel_out.put({'code': 500, 'data': ev}) child.wait()
def __init__(self, netns, flags=os.O_CREAT, target=None, libc=None): self.netns = netns self.flags = flags target = target or netns trnsp_in, self.remote_trnsp_out = [Transport(FD(x)) for x in os.pipe()] self.remote_trnsp_in, trnsp_out = [Transport(FD(x)) for x in os.pipe()] self.child = os.fork() if self.child == 0: # child process trnsp_in.close() trnsp_out.close() trnsp_in.file_obj.close() trnsp_out.file_obj.close() try: setns(self.netns, self.flags, libc=libc) except OSError as e: (self .remote_trnsp_out .send({'stage': 'init', 'error': e})) os._exit(e.errno) except Exception as e: (self. remote_trnsp_out .send({'stage': 'init', 'error': OSError(errno.ECOMM, str(e), self.netns)})) os._exit(255) try: Server(self.remote_trnsp_in, self.remote_trnsp_out, target=target) finally: os._exit(0) try: self.remote_trnsp_in.close() self.remote_trnsp_out.close() super(NetNS, self).__init__(trnsp_in, trnsp_out) self.target = target except Exception: self.close() raise atexit.register(self.close) self.marshal = MarshalRtnl()
def Server(trnsp_in, trnsp_out, netns=None, target='localhost'): def stop_server(signum, frame): Server.run = False Server.run = True signal.signal(signal.SIGTERM, stop_server) try: if netns is not None: netnsmod.setns(netns) ipr = IPRoute(target=target) lock = ipr._sproxy.lock ipr._s_channel = ProxyChannel(trnsp_out, 'broadcast') except Exception as e: trnsp_out.send({'stage': 'init', 'error': e}) return 255 inputs = [ipr.fileno(), trnsp_in.fileno()] broadcasts = {ipr.fileno(): ipr} outputs = [] # all is OK so far trnsp_out.send({'stage': 'init', 'uname': config.uname, 'error': None}) # 8<------------------------------------------------------------- while Server.run: try: events, _, _ = select.select(inputs, outputs, inputs) except: continue for fd in events: if fd in broadcasts: sock = broadcasts[fd] bufsize = sock.getsockopt(SOL_SOCKET, SO_RCVBUF) // 2 with lock: error = None data = None try: data = sock.recv(bufsize) except Exception as e: error = e error.tb = traceback.format_exc() trnsp_out.send( {'stage': 'broadcast', 'data': data, 'error': error} ) elif fd == trnsp_in.fileno(): cmd = trnsp_in.recv_cmd() if cmd['stage'] == 'shutdown': ipr.close() data = struct.pack('IHHQIQQ', 28, 2, 0, 0, 104, 0, 0) trnsp_out.send( {'stage': 'broadcast', 'data': data, 'error': None} ) return elif cmd['stage'] == 'reconstruct': error = None try: msg = cmd['argv'][0]() msg.load(pickle.loads(cmd['argv'][1])) ipr.sendto_gate(msg, cmd['argv'][2]) except Exception as e: error = e error.tb = traceback.format_exc() trnsp_out.send( { 'stage': 'reconstruct', 'error': error, 'return': None, 'cookie': cmd['cookie'], } ) elif cmd['stage'] == 'command': error = None try: ret = getattr(ipr, cmd['name'])( *cmd['argv'], **cmd['kwarg'] ) if ( cmd['name'] == 'bind' and ipr._brd_socket is not None ): inputs.append(ipr._brd_socket.fileno()) broadcasts[ ipr._brd_socket.fileno() ] = ipr._brd_socket except Exception as e: ret = None error = e error.tb = traceback.format_exc() trnsp_out.send( { 'stage': 'command', 'error': error, 'return': ret, 'cookie': cmd['cookie'], } )