Commit c2a1312f authored by ibuler's avatar ibuler

[Update] Debug gc

parents a2059cf9 1ee793fa
...@@ -8,7 +8,9 @@ import time ...@@ -8,7 +8,9 @@ import time
import threading import threading
import socket import socket
import json import json
import tracemalloc
import gc
from jms.service import AppService from jms.service import AppService
from .config import Config from .config import Config
...@@ -66,6 +68,8 @@ class Coco: ...@@ -66,6 +68,8 @@ class Coco:
self.replay_recorder_class = None self.replay_recorder_class = None
self.command_recorder_class = None self.command_recorder_class = None
self._task_handler = None self._task_handler = None
tracemalloc.start()
self.snapshot = tracemalloc.take_snapshot()
@property @property
def name(self): def name(self):
...@@ -130,6 +134,16 @@ class Coco: ...@@ -130,6 +134,16 @@ class Coco:
def heartbeat(self): def heartbeat(self):
_sessions = [s.to_json() for s in self.sessions] _sessions = [s.to_json() for s in self.sessions]
tasks = self.service.terminal_heartbeat(_sessions) tasks = self.service.terminal_heartbeat(_sessions)
gc.collect()
snapshort2 = tracemalloc.take_snapshot()
top_stats = snapshort2.compare_to(self.snapshot, 'traceback')
print("[ Top 10 differences ]")
for stat in top_stats[:10]:
print(stat.count_diff)
# gc.collect()
# print(objgraph.show_most_common_types())
# for i in ("User", "Client", "Session", "ProxyServer", "Transport", "Channel", "InteractiveServer", "SSHInterface", "Server", "Asset"):
# print("{} objects: {}".format(i, len(objgraph.by_type(i))))
if tasks: if tasks:
self.handle_task(tasks) self.handle_task(tasks)
if tasks is False: if tasks is False:
...@@ -222,7 +236,6 @@ class Coco: ...@@ -222,7 +236,6 @@ class Coco:
self.clients.remove(client) self.clients.remove(client)
logger.info("Client {} leave, total {} now".format(client, len(self.clients))) logger.info("Client {} leave, total {} now".format(client, len(self.clients)))
client.close() client.close()
del client
except: except:
pass pass
......
...@@ -83,7 +83,6 @@ class InteractiveServer: ...@@ -83,7 +83,6 @@ class InteractiveServer:
while True: while True:
data = self.client.recv(10) data = self.client.recv(10)
logger.debug(data)
if len(data) == 0: if len(data) == 0:
self.app.remove_client(self.client) self.app.remove_client(self.client)
break break
...@@ -300,9 +299,6 @@ class InteractiveServer: ...@@ -300,9 +299,6 @@ class InteractiveServer:
forwarder = ProxyServer(self.app, self.client) forwarder = ProxyServer(self.app, self.client)
forwarder.proxy(asset, system_user) forwarder.proxy(asset, system_user)
def replay_session(self, session_id):
pass
def interact(self): def interact(self):
self.display_banner() self.display_banner()
while True: while True:
...@@ -322,4 +318,6 @@ class InteractiveServer: ...@@ -322,4 +318,6 @@ class InteractiveServer:
def close(self): def close(self):
self.app.remove_client(self.client) self.app.remove_client(self.client)
logger.info("Exit interactive server")
# def __del__(self):
# print("GC: Interactive class been gc")
...@@ -21,7 +21,7 @@ class SSHInterface(paramiko.ServerInterface): ...@@ -21,7 +21,7 @@ class SSHInterface(paramiko.ServerInterface):
def __init__(self, app, request): def __init__(self, app, request):
self._app = weakref.ref(app) self._app = weakref.ref(app)
self.request = request self._request = weakref.ref(request)
self.event = threading.Event() self.event = threading.Event()
self.auth_valid = False self.auth_valid = False
...@@ -29,6 +29,10 @@ class SSHInterface(paramiko.ServerInterface): ...@@ -29,6 +29,10 @@ class SSHInterface(paramiko.ServerInterface):
def app(self): def app(self):
return self._app() return self._app()
@property
def request(self):
return self._request()
def check_auth_interactive(self, username, submethods): def check_auth_interactive(self, username, submethods):
logger.info("Check auth interactive: %s %s" % (username, submethods)) logger.info("Check auth interactive: %s %s" % (username, submethods))
return paramiko.AUTH_FAILED return paramiko.AUTH_FAILED
...@@ -177,6 +181,9 @@ class SSHInterface(paramiko.ServerInterface): ...@@ -177,6 +181,9 @@ class SSHInterface(paramiko.ServerInterface):
def get_banner(self): def get_banner(self):
return None, None return None, None
# def __del__(self):
# print("GC: SSH interface gc")
......
...@@ -21,6 +21,9 @@ class Request: ...@@ -21,6 +21,9 @@ class Request:
self.change_size_event = threading.Event() self.change_size_event = threading.Event()
self.date_start = datetime.datetime.now() self.date_start = datetime.datetime.now()
# def __del__(self):
# print("GC: Request object gc")
class SizedList(list): class SizedList(list):
def __init__(self, maxsize=0): def __init__(self, maxsize=0):
...@@ -74,8 +77,8 @@ class Client: ...@@ -74,8 +77,8 @@ class Client:
def __str__(self): def __str__(self):
return "<%s from %s:%s>" % (self.user, self.addr[0], self.addr[1]) return "<%s from %s:%s>" % (self.user, self.addr[0], self.addr[1])
def __del__(self): # def __del__(self):
print("GC: client object has been gc") # print("GC: Client object has been gc")
class Server: class Server:
...@@ -157,9 +160,9 @@ class Server: ...@@ -157,9 +160,9 @@ class Server:
def close(self): def close(self):
logger.info("Closed server {}".format(self)) logger.info("Closed server {}".format(self))
self.parse(b'') self.parse(b'')
self.chan.close()
self.stop_evt.set() self.stop_evt.set()
self.chan.close() self.chan.close()
self.chan.transport.close()
@staticmethod @staticmethod
def _have_enter_char(s): def _have_enter_char(s):
...@@ -186,8 +189,8 @@ class Server: ...@@ -186,8 +189,8 @@ class Server:
def __str__(self): def __str__(self):
return "<To: {}>".format(str(self.asset)) return "<To: {}>".format(str(self.asset))
def __del__(self): # def __del__(self):
print("GC: Server object has been gc") # print("GC: Server object has been gc")
class WSProxy: class WSProxy:
......
...@@ -24,9 +24,9 @@ class ProxyServer: ...@@ -24,9 +24,9 @@ class ProxyServer:
def __init__(self, app, client): def __init__(self, app, client):
self._app = weakref.ref(app) self._app = weakref.ref(app)
self.client = client self.client = client
self.request = client.request
self.server = None self.server = None
self.connecting = True self.connecting = True
self.stop_event = threading.Event()
@property @property
def app(self): def app(self):
...@@ -47,6 +47,8 @@ class ProxyServer: ...@@ -47,6 +47,8 @@ class ProxyServer:
self.app.add_session(session) self.app.add_session(session)
self.watch_win_size_change_async() self.watch_win_size_change_async()
session.bridge() session.bridge()
self.stop_event.set()
self.end_watch_win_size_change()
self.app.remove_session(session) self.app.remove_session(session)
def validate_permission(self, asset, system_user): def validate_permission(self, asset, system_user):
...@@ -117,17 +119,20 @@ class ProxyServer: ...@@ -117,17 +119,20 @@ class ProxyServer:
self.connecting = False self.connecting = False
self.client.send(b'\r\n') self.client.send(b'\r\n')
term = self.request.meta.get('term', 'xterm') request = self.client.request
width = self.request.meta.get('width', 80) term = request.meta.get('term', 'xterm')
height = self.request.meta.get('height', 24) width = request.meta.get('width', 80)
height = request.meta.get('height', 24)
chan = ssh.invoke_shell(term, width=width, height=height) chan = ssh.invoke_shell(term, width=width, height=height)
return Server(chan, asset, system_user) return Server(chan, asset, system_user)
def watch_win_size_change(self): def watch_win_size_change(self):
while self.request.change_size_event.wait(): while self.client.request.change_size_event.wait():
self.request.change_size_event.clear() if self.stop_event.is_set():
width = self.request.meta.get('width', 80) break
height = self.request.meta.get('height', 24) self.client.request.change_size_event.clear()
width = self.client.request.meta.get('width', 80)
height = self.client.request.meta.get('height', 24)
logger.debug("Change win size: %s - %s" % (width, height)) logger.debug("Change win size: %s - %s" % (width, height))
try: try:
self.server.chan.resize_pty(width=width, height=height) self.server.chan.resize_pty(width=width, height=height)
...@@ -139,6 +144,9 @@ class ProxyServer: ...@@ -139,6 +144,9 @@ class ProxyServer:
thread.daemon = True thread.daemon = True
thread.start() thread.start()
def end_watch_win_size_change(self):
self.client.request.change_size_event.set()
def send_connecting_message(self, asset, system_user): def send_connecting_message(self, asset, system_user):
def func(): def func():
delay = 0.0 delay = 0.0
...@@ -149,5 +157,3 @@ class ProxyServer: ...@@ -149,5 +157,3 @@ class ProxyServer:
delay += 0.1 delay += 0.1
thread = threading.Thread(target=func) thread = threading.Thread(target=func)
thread.start() thread.start()
...@@ -178,9 +178,9 @@ class ServerReplayRecorder(ReplayRecorder): ...@@ -178,9 +178,9 @@ class ServerReplayRecorder(ReplayRecorder):
logger.error("failed report session {}'s replay log".format(session_id)) logger.error("failed report session {}'s replay log".format(session_id))
return False return False
def __del__(self): # def __del__(self):
print("Server replay recorder has been gc") # print("GC: Server replay recorder has been gc")
del self.file # del self.file
class ServerCommandRecorder(CommandRecorder, metaclass=Singleton): class ServerCommandRecorder(CommandRecorder, metaclass=Singleton):
...@@ -226,8 +226,8 @@ class ServerCommandRecorder(CommandRecorder, metaclass=Singleton): ...@@ -226,8 +226,8 @@ class ServerCommandRecorder(CommandRecorder, metaclass=Singleton):
def session_end(self, session_id): def session_end(self, session_id):
pass pass
def __del__(self): # def __del__(self):
print("GC: Session command storage has been gc") # print("GC: Session command storage has been gc")
class ESCommandRecorder(CommandRecorder, metaclass=Singleton): class ESCommandRecorder(CommandRecorder, metaclass=Singleton):
...@@ -279,8 +279,8 @@ class ESCommandRecorder(CommandRecorder, metaclass=Singleton): ...@@ -279,8 +279,8 @@ class ESCommandRecorder(CommandRecorder, metaclass=Singleton):
def session_end(self, session_id): def session_end(self, session_id):
pass pass
def __del__(self): # def __del__(self):
print("ES command storage has been gc".format(self)) # print("GC: ES command storage has been gc".format(self))
def get_command_recorder_class(config): def get_command_recorder_class(config):
......
...@@ -107,7 +107,10 @@ class Session: ...@@ -107,7 +107,10 @@ class Session:
def terminate(self): def terminate(self):
msg = b"Terminate by administrator\r\n" msg = b"Terminate by administrator\r\n"
self.client.send(msg) try:
self.client.send(msg)
except OSError:
pass
self.close() self.close()
def bridge(self): def bridge(self):
...@@ -185,5 +188,5 @@ class Session: ...@@ -185,5 +188,5 @@ class Session:
def __repr__(self): def __repr__(self):
return self.id return self.id
def __del__(self): # def __del__(self):
print("GC: Session object has been GC") # print("GC: Session object has been GC")
...@@ -72,10 +72,16 @@ class SSHServer: ...@@ -72,10 +72,16 @@ class SSHServer:
return return
while True: while True:
if not transport.is_active():
transport.close()
sock.close()
break
chan = transport.accept() chan = transport.accept()
server.event.wait(5)
if chan is None: if chan is None:
continue continue
server.event.wait(5)
if not server.event.is_set(): if not server.event.is_set():
logger.warning("Client not request a valid request, exiting") logger.warning("Client not request a valid request, exiting")
return return
......
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