def main(): _setup_logging(verbose=True) ws_app = Application() server = tornado.httpserver.HTTPServer(ws_app) server.listen(settings.WEB_CONSOLE_PORT) pod_life_cycle = PodLifeCycle() pod_life_cycle.start() tornado.ioloop.IOLoop.instance().start()
def main(): _setup_logging(verbose=True) ws_app = Application() tornado.locale.load_gettext_translations(settings.LOCALE_PATHS[0], domain='django') server = tornado.httpserver.HTTPServer(ws_app) server.listen(settings.WEB_CONSOLE_PORT) pod_life_cycle = PodLifeCycle() pod_life_cycle.start() tornado.ioloop.IOLoop.instance().start()
def main(): _setup_logging(verbose=True) ws_app = Application() tornado.locale.load_gettext_translations(settings.LOCALE_PATHS[0], domain="django") server = tornado.httpserver.HTTPServer(ws_app) server.listen(settings.WEB_CONSOLE_PORT) # graceful_shutdown signal.signal(signal.SIGTERM, partial(exit_handler, server)) signal.signal(signal.SIGINT, partial(exit_handler, server)) pod_life_cycle = PodLifeCycle() pod_life_cycle.start() tornado.ioloop.IOLoop.instance().start()
def __init__(self, *args, **kwargs): super(BcsWebSocketHandler, self).__init__(*args, **kwargs) self.input_record = [] self.input_buffer = '' self.last_input_ts = IOLoop.current().time() self.record_callback = None self.tick_callback = None self.record_interval = 10 self.heartbeat_callback = None self.auditor = get_auditor() self.pod_life_cycle = PodLifeCycle() self.exit_buffer = '' self.exit_command = 'exit' self.user_pod_name = None
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.input_record = [] self.input_buffer = "" self.last_input_ts = IOLoop.current().time() self.login_ts = IOLoop.current().time() self.record_callback = None self.tick_callback = None self.record_interval = 10 self.heartbeat_callback = None self.auditor = get_auditor() self.pod_life_cycle = PodLifeCycle() self.exit_buffer = "" self.exit_command = "exit" self.user_pod_name = None self.source = None
class BCSWebSocketHandler(LocaleHandlerMixin, tornado.websocket.WebSocketHandler): """WebSocket处理""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.input_record = [] self.input_buffer = "" self.last_input_ts = IOLoop.current().time() self.login_ts = IOLoop.current().time() self.record_callback = None self.tick_callback = None self.record_interval = 10 self.heartbeat_callback = None self.auditor = get_auditor() self.pod_life_cycle = PodLifeCycle() self.exit_buffer = "" self.exit_command = "exit" self.user_pod_name = None self.source = None def check_origin(self, origin): return True @authenticated def get(self, *args, **kwargs): """只鉴权使用""" return super().get(*args, **kwargs) def open(self, project_id, cluster_id, context): self.project_id = project_id self.cluster_id = cluster_id self.context = context self.user_pod_name = context["user_pod_name"] self.source = self.get_argument("source") rows = self.get_argument("rows") rows = utils.format_term_size(rows, constants.DEFAULT_ROWS) cols = self.get_argument("cols") cols = utils.format_term_size(cols, constants.DEFAULT_COLS) mode = context.get("mode") self.bcs_client = bcs_client.factory.create(mode, self, context, rows, cols) WEBSOCKET_HANDLER_SET.add(self) def is_exit_command(self, message): """判断是否主动退出""" # 去除空格 message = message.strip() # 分号表示多个命令执行, 任一一个有exit命令即退出 for i in message.split(";"): if self.exit_command == i.strip(): return True # 空格表示按顺序执行, 第一个是exit命令即退出 for i in message.split(): if self.exit_command == i.strip(): return True break return False def on_message(self, message): self.last_input_ts = IOLoop.current().time() channel = int(message[0]) message = base64.b64decode(message[1:]) if channel == constants.RESIZE_CHANNEL: size = json.loads(message) self.bcs_client.set_pty_size(size["rows"], size["cols"]) else: self.send_message(smart_str(message)) def on_close(self): if self.tick_callback: logger.info("stop tick callback, %s", self.user_pod_name) self.tick_callback.stop() if self.record_callback: logger.info("stop record_callback, %s", self.user_pod_name) self.record_callback.stop() if self.heartbeat_callback: logger.info("stop heartbeat_callback, %s", self.user_pod_name) self.heartbeat_callback.stop() self.bcs_client.close_transmission() WEBSOCKET_HANDLER_SET.remove(self) logger.info("on_close, code: %s, reason: %s, pod: %s", self.close_code, self.close_reason, self.user_pod_name) def flush_input_record(self): """获取输出记录""" record = self.input_record[:] self.input_record = [] return record def tick_timeout(self): """主动停止掉session""" self.tick_callback = PeriodicCallback(self.periodic_tick, self.record_interval * 1000) self.tick_callback.start() def periodic_tick(self): now = IOLoop.current().time() idle_time = now - max(self.bcs_client.last_output_ts, self.last_input_ts) if idle_time > constants.TICK_TIMEOUT: tick_timeout_min = constants.TICK_TIMEOUT // 60 message = _("BCS Console 已经{}分钟无操作").format(tick_timeout_min) self.close_reason = message self.close(reason=message) logger.info("tick timeout, close session %s, idle time, %.2f", self.user_pod_name, idle_time) logger.info("tick active %s, idle time, %.2f", self.user_pod_name, idle_time) login_time = now - self.login_ts if login_time > constants.LOGIN_TIMEOUT: login_timeout = constants.LOGIN_TIMEOUT // (60 * 60) message = _("BCS Console 使用已经超过{}小时,请重新登录").format(login_timeout) self.close_reason = message self.close(reason=message) logger.info("tick timeout, close session %s, login time, %.2f", self.user_pod_name, login_time) logger.info("tick active %s, login time, %.2f", self.user_pod_name, login_time) def heartbeat(self): """每秒钟上报心跳""" self.heartbeat_callback = PeriodicCallback(lambda: self.pod_life_cycle.heartbeat(self.user_pod_name), 1000) self.heartbeat_callback.start() def start_record(self): """操作审计""" self.record_callback = PeriodicCallback(self.periodic_record, self.record_interval * 1000) self.record_callback.start() def periodic_record(self): """周期上报操作记录""" input_record = self.flush_input_record() output_record = self.bcs_client.flush_output_record() if not input_record and not output_record: return # 上报的数据 data = { "input_record": "\r\n".join(input_record), "output_record": "\r\n".join(output_record), "session_id": self.context["session_id"], "context": self.context, "project_id": self.project_id, "cluster_id": self.cluster_id, "user_pod_name": self.user_pod_name, "username": self.context["username"], } self.auditor.emit(data) logger.info(data) def send_message(self, message): if not self.bcs_client.ws or self.bcs_client.ws.stream.closed(): logger.info("session %s, close, message just ignore", self) return self.input_buffer += message if self.input_buffer.endswith(constants.INPUT_LINE_BREAKER): # line_msg = ['command', ''] line_msg = self.input_buffer.split(constants.INPUT_LINE_BREAKER) for i in line_msg[:-1]: record = "%s: %s" % (arrow.now().strftime("%Y-%m-%d %H:%M:%S.%f"), clean_bash_escape(i)) logger.debug(record) self.input_record.append(record) # empty input_buffer self.input_buffer = line_msg[-1] try: self.bcs_client.write_message(message) except Exception as e: logger.exception(e)
class BCSWebSocketHandler(LocaleHandlerMixin, tornado.websocket.WebSocketHandler): """WebSocket处理 """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.input_record = [] self.input_buffer = '' self.last_input_ts = IOLoop.current().time() self.record_callback = None self.tick_callback = None self.record_interval = 10 self.heartbeat_callback = None self.auditor = get_auditor() self.pod_life_cycle = PodLifeCycle() self.exit_buffer = '' self.exit_command = 'exit' self.user_pod_name = None self.source = None def check_origin(self, origin): return True @authenticated def get(self, *args, **kwargs): """只鉴权使用 """ return super().get(*args, **kwargs) def open(self, project_id, cluster_id, context): self.project_id = project_id self.cluster_id = cluster_id self.context = context self.user_pod_name = context['user_pod_name'] self.source = self.get_argument('source') rows = self.get_argument('rows') rows = utils.format_term_size(rows, constants.DEFAULT_ROWS) cols = self.get_argument('cols') cols = utils.format_term_size(cols, constants.DEFAULT_COLS) mode = context.get('mode') self.bcs_client = bcs_client.factory.create(mode, self, context, rows, cols) def on_message(self, message): self.last_input_ts = IOLoop.current().time() channel = int(message[0]) message = message[1:] if channel == constants.RESIZE_CHANNEL: rows, cols = message.split(',') rows = int(rows) cols = int(rows) self.bcs_client.set_pty_size(rows, cols) else: if message == '\r': if self.exit_buffer.lstrip().startswith(self.exit_command): self.write_message({ 'data': _("BCS Console 主动退出"), 'type': "exit_message" }) self.exit_buffer == '' else: self.exit_buffer += message self.send_message(message) def on_close(self): self.send_exit() if self.tick_callback: logger.info('stop tick callback, %s', self.user_pod_name) self.tick_callback.stop() if self.record_callback: logger.info('stop record_callback, %s', self.user_pod_name) self.record_callback.stop() if self.heartbeat_callback: logger.info('stop heartbeat_callback, %s', self.user_pod_name) self.heartbeat_callback.stop() logger.info("on_close") def send_exit(self): exit_msg = '\nexit\n' self.send_message(exit_msg) def flush_input_record(self): """获取输出记录 """ record = self.input_record[:] self.input_record = [] return record def tick_timeout(self): """主动停止掉session """ self.tick_callback = PeriodicCallback(self.periodic_tick, self.record_interval * 1000) self.tick_callback.start() def tick_timeout2client(self): """客户端退出 """ # 下发提示消息 tick_timeout_min = constants.TICK_TIMEOUT // 60 self.write_message({ 'data': _("BCS Console 已经{}分钟无操作").format(tick_timeout_min), 'type': "exit_message" }) # 服务端退出bash, exit self.send_exit() def periodic_tick(self): now = IOLoop.current().time() idle_time = now - max(self.bcs_client.last_output_ts, self.last_input_ts) if idle_time > constants.TICK_TIMEOUT: self.tick_timeout2client() logger.info('tick timeout, close session %s, idle time, %.2f', self.user_pod_name, idle_time) logger.info('tick active %s, idle time, %.2f', self.user_pod_name, idle_time) def heartbeat(self): """每秒钟上报心跳 """ self.heartbeat_callback = PeriodicCallback( lambda: self.pod_life_cycle.heartbeat(self.user_pod_name), 1000) self.heartbeat_callback.start() def start_record(self): """操作审计""" self.record_callback = PeriodicCallback(self.periodic_record, self.record_interval * 1000) self.record_callback.start() def periodic_record(self): """周期上报操作记录 """ input_record = self.flush_input_record() output_record = self.bcs_client.flush_output_record() if not input_record and not output_record: return # 上报的数据 data = { 'input_record': '\r\n'.join(input_record), 'output_record': '\r\n'.join(output_record), 'session_id': self.context['session_id'], 'context': self.context, 'project_id': self.project_id, 'cluster_id': self.cluster_id, 'user_pod_name': self.user_pod_name, 'username': self.context['username'] } self.auditor.emit(data) logger.info(data) def send_message(self, message): if not self.bcs_client.ws or self.bcs_client.ws.stream.closed(): logger.info("session %s, close, message just ignore", self) return self.input_buffer += message if self.input_buffer.endswith(constants.INPUT_LINE_BREAKER): # line_msg = ['command', ''] line_msg = self.input_buffer.split(constants.INPUT_LINE_BREAKER) for i in line_msg[:-1]: record = '%s: %s' % (arrow.now().strftime( "%Y-%m-%d %H:%M:%S.%f"), clean_bash_escape(i)) logger.debug(record) self.input_record.append(record) # empty input_buffer self.input_buffer = line_msg[-1] try: self.bcs_client.write_message(message) except Exception as e: logger.exception(e)