mirror of https://github.com/tp4a/teleport
修正:MySQL长时间未通讯会丢失连接;改进:导入导出数据库时增加对数据库版本的检查;改进:页面上总是显示teleport服务器的时间(配合检查身份认证器的时间是否同步);
parent
1a3f7f3378
commit
7208f39aa0
|
@ -156,11 +156,12 @@ class BaseAppConfig(dict):
|
|||
self._on_init()
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name in self['_kvs']:
|
||||
return self['_kvs'][name]
|
||||
_name = name.replace('-', '_')
|
||||
if _name in self['_kvs']:
|
||||
return self['_kvs'][_name]
|
||||
else:
|
||||
if name in self['_kvs']['_']:
|
||||
return self['_kvs']['_'][name]
|
||||
if _name in self['_kvs']['_']:
|
||||
return self['_kvs']['_'][_name]
|
||||
else:
|
||||
return AttrDict()
|
||||
|
||||
|
@ -168,7 +169,7 @@ class BaseAppConfig(dict):
|
|||
x = key.split('::')
|
||||
if 1 == len(x):
|
||||
_sec = '_'
|
||||
_key = x[0]
|
||||
_key = x[0].replace('-', '_')
|
||||
elif 2 == len(x):
|
||||
_sec = x[0].replace('-', '_')
|
||||
_key = x[1].replace('-', '_')
|
||||
|
@ -199,7 +200,7 @@ class BaseAppConfig(dict):
|
|||
x = key.split('::')
|
||||
if 1 == len(x):
|
||||
_sec = '_'
|
||||
_key = x[0]
|
||||
_key = x[0].replace('-', '_')
|
||||
elif 2 == len(x):
|
||||
_sec = x[0].replace('-', '_')
|
||||
_key = x[1].replace('-', '_')
|
||||
|
@ -215,7 +216,7 @@ class BaseAppConfig(dict):
|
|||
x = key.split('::')
|
||||
if 1 == len(x):
|
||||
_sec = '_'
|
||||
_key = x[0]
|
||||
_key = x[0].replace('-', '_')
|
||||
elif 2 == len(x):
|
||||
_sec = x[0].replace('-', '_')
|
||||
_key = x[1].replace('-', '_')
|
||||
|
@ -311,10 +312,10 @@ class BaseAppConfig(dict):
|
|||
x = key.split('::')
|
||||
if 1 == len(x):
|
||||
_sec = '_'
|
||||
_key = x[0]
|
||||
_key = x[0].replace('-', '_')
|
||||
elif 2 == len(x):
|
||||
_sec = x[0]
|
||||
_key = x[1]
|
||||
_sec = x[0].replace('-', '_')
|
||||
_key = x[1].replace('-', '_')
|
||||
else:
|
||||
return def_value, False
|
||||
|
||||
|
@ -322,16 +323,20 @@ class BaseAppConfig(dict):
|
|||
return def_value, False
|
||||
if _key not in self['_kvs'][_sec]:
|
||||
return def_value, False
|
||||
|
||||
if self['_kvs'][_sec][_key] is None:
|
||||
return def_value, False
|
||||
|
||||
return str(self['_kvs'][_sec][_key]), True
|
||||
|
||||
def get_int(self, key, def_value=-1):
|
||||
x = key.split('::')
|
||||
if 1 == len(x):
|
||||
_sec = '_'
|
||||
_key = x[0]
|
||||
_key = x[0].replace('-', '_')
|
||||
elif 2 == len(x):
|
||||
_sec = x[0]
|
||||
_key = x[1]
|
||||
_sec = x[0].replace('-', '_')
|
||||
_key = x[1].replace('-', '_')
|
||||
else:
|
||||
return def_value, False
|
||||
|
||||
|
@ -340,6 +345,9 @@ class BaseAppConfig(dict):
|
|||
if _key not in self['_kvs'][_sec]:
|
||||
return def_value, False
|
||||
|
||||
if self['_kvs'][_sec][_key] is None:
|
||||
return def_value, False
|
||||
|
||||
try:
|
||||
return int(self['_kvs'][_sec][_key]), True
|
||||
except ValueError as e:
|
||||
|
@ -350,10 +358,10 @@ class BaseAppConfig(dict):
|
|||
x = key.split('::')
|
||||
if 1 == len(x):
|
||||
_sec = '_'
|
||||
_key = x[0]
|
||||
_key = x[0].replace('-', '_')
|
||||
elif 2 == len(x):
|
||||
_sec = x[0]
|
||||
_key = x[1]
|
||||
_sec = x[0].replace('-', '_')
|
||||
_key = x[1].replace('-', '_')
|
||||
else:
|
||||
return def_value, False
|
||||
|
||||
|
@ -362,6 +370,9 @@ class BaseAppConfig(dict):
|
|||
if _key not in self['_kvs'][_sec]:
|
||||
return def_value, False
|
||||
|
||||
if self['_kvs'][_sec][_key] is None:
|
||||
return def_value, False
|
||||
|
||||
tmp = str(self['_kvs'][_sec][_key]).lower()
|
||||
|
||||
if tmp in ['yes', 'true', '1']:
|
||||
|
@ -415,14 +426,6 @@ class AppConfig(BaseAppConfig):
|
|||
self.set_default('database::sqlite-file', None,
|
||||
'sqlite-file=/var/lib/teleport/data/ts_db.db'
|
||||
)
|
||||
# self.set_default('database::mysql-host', None,
|
||||
# 'mysql-host=127.0.0.1\n'
|
||||
# 'mysql-port=3306\n'
|
||||
# 'mysql-db=teleport\n'
|
||||
# 'mysql-prefix=tp_\n'
|
||||
# 'mysql-user=teleport\n'
|
||||
# 'mysql-password=password'
|
||||
# )
|
||||
self.set_default('database::mysql-host', '127.0.0.1', 'mysql-host=127.0.0.1')
|
||||
self.set_default('database::mysql-port', 3306, 'mysql-port=3306')
|
||||
self.set_default('database::mysql-db', 'teleport', 'mysql-db=teleport')
|
||||
|
@ -507,7 +510,7 @@ class AppConfig(BaseAppConfig):
|
|||
self.set_kv('database::mysql-password', _tmp_str)
|
||||
|
||||
_log_file, ok = self.get_str('common::log-file')
|
||||
if ok:
|
||||
if ok and _log_file:
|
||||
self.log_path = os.path.abspath(os.path.dirname(_log_file))
|
||||
else:
|
||||
_log_file = os.path.join(self.log_path, 'tpweb.log')
|
||||
|
|
|
@ -101,7 +101,8 @@ class WebServerCore:
|
|||
'static_hash_cache': False,
|
||||
}
|
||||
|
||||
from eom_app.controller import controllers
|
||||
from eom_app.controller import controllers, fix_controller
|
||||
fix_controller()
|
||||
web_app = tornado.web.Application(controllers, **settings)
|
||||
|
||||
server = tornado.httpserver.HTTPServer(web_app)
|
||||
|
@ -118,9 +119,12 @@ class WebServerCore:
|
|||
|
||||
# 启动session超时管理
|
||||
web_session().start()
|
||||
# 启动数据库定时事务(例如MySQL防丢失连接)
|
||||
get_db().start_keep_alive()
|
||||
|
||||
tornado.ioloop.IOLoop.instance().start()
|
||||
|
||||
get_db().stop_keep_alive()
|
||||
web_session().stop()
|
||||
|
||||
return 0
|
||||
|
|
|
@ -46,7 +46,13 @@ def export_database(db):
|
|||
elif db.db_type == db.DB_TYPE_MYSQL:
|
||||
ret.append('-- export from MySQL Database')
|
||||
else:
|
||||
return 'Unknown Database Type'
|
||||
return '未知的数据库类型', False
|
||||
|
||||
db_ret = db.query('SELECT `value` FROM `{}config` WHERE `name`="db_ver";'.format(db.table_prefix))
|
||||
if db_ret is None or 0 == len(db_ret):
|
||||
return '无法获取数据库版本', False
|
||||
else:
|
||||
ret.append('-- DATABASE VERSION {}'.format(db_ret[0][0]))
|
||||
|
||||
_fields = ['account_id', 'account_type', 'account_name', 'account_pwd', 'account_status', 'account_lock', 'account_desc', 'oath_secret']
|
||||
ret.append(_export_table(db, 'account', _fields))
|
||||
|
@ -65,4 +71,4 @@ def export_database(db):
|
|||
_fields = ['id', 'session_id', 'account_name', 'host_ip', 'host_port', 'sys_type', 'auth_type', 'protocol', 'user_name', 'ret_code', 'begin_time', 'end_time', 'log_time']
|
||||
ret.append(_export_table(db, 'log', _fields))
|
||||
|
||||
return '\r\n'.join(ret)
|
||||
return '\r\n'.join(ret), True
|
||||
|
|
|
@ -530,14 +530,14 @@ class DatabaseUpgrade:
|
|||
def _upgrade_to_v6(self):
|
||||
_step = self.step_begin('检查数据库版本v6...')
|
||||
|
||||
# 服务端升级到版本2.2.9.1时,为增加双因子认证,为account表增加oath_secret字段
|
||||
# db_ret = self.db.is_field_exists('{}account'.format(self.db.table_prefix), 'oath_secret')
|
||||
# if db_ret is None:
|
||||
# self.step_end(_step, -1, '无法连接到数据库')
|
||||
# return False
|
||||
# if db_ret:
|
||||
# self.step_end(_step, 0, '跳过 v5 到 v6 的升级操作')
|
||||
# return True
|
||||
# 服务端升级到版本2.2.9时,为增加双因子认证,为account表增加oath_secret字段
|
||||
db_ret = self.db.is_field_exists('{}account'.format(self.db.table_prefix), 'oath_secret')
|
||||
if db_ret is None:
|
||||
self.step_end(_step, -1, '无法连接到数据库')
|
||||
return False
|
||||
if db_ret:
|
||||
self.step_end(_step, 0, '跳过 v5 到 v6 的升级操作')
|
||||
return True
|
||||
|
||||
self.step_end(_step, 0, '需要升级到v6')
|
||||
|
||||
|
@ -556,7 +556,6 @@ class DatabaseUpgrade:
|
|||
self.step_end(_step, 0)
|
||||
return True
|
||||
|
||||
|
||||
except:
|
||||
log.e('failed.\n')
|
||||
self.step_end(_step, -1)
|
||||
|
|
|
@ -46,6 +46,10 @@ class TPDatabase:
|
|||
self._table_prefix = ''
|
||||
self._conn_pool = None
|
||||
|
||||
self._stop_flag = False
|
||||
self._thread_keep_alive_handle = None
|
||||
self._thread_keep_alive_cond = threading.Condition()
|
||||
|
||||
@property
|
||||
def table_prefix(self):
|
||||
return self._table_prefix
|
||||
|
@ -91,6 +95,30 @@ class TPDatabase:
|
|||
|
||||
return True
|
||||
|
||||
def start_keep_alive(self):
|
||||
self._thread_keep_alive_handle = threading.Thread(target=self._thread_keep_alive)
|
||||
self._thread_keep_alive_handle.start()
|
||||
|
||||
def stop_keep_alive(self):
|
||||
self._stop_flag = True
|
||||
self._thread_keep_alive_cond.acquire()
|
||||
self._thread_keep_alive_cond.notify()
|
||||
self._thread_keep_alive_cond.release()
|
||||
if self._thread_keep_alive_handle is not None:
|
||||
self._thread_keep_alive_handle.join()
|
||||
log.v('database-keep-alive-thread stopped.\n')
|
||||
|
||||
def _thread_keep_alive(self):
|
||||
while True:
|
||||
self._thread_keep_alive_cond.acquire()
|
||||
# 每一小时醒来执行一次查询,避免连接丢失
|
||||
self._thread_keep_alive_cond.wait(3600)
|
||||
self._thread_keep_alive_cond.release()
|
||||
if self._stop_flag:
|
||||
break
|
||||
|
||||
self.query('SELECT `value` FROM `{}config` WHERE `name`="db_ver";'.format(self._table_prefix))
|
||||
|
||||
def _init_sqlite(self, db_file):
|
||||
self.db_type = self.DB_TYPE_SQLITE
|
||||
self.auto_increment = 'AUTOINCREMENT'
|
||||
|
@ -121,49 +149,6 @@ class TPDatabase:
|
|||
|
||||
return True
|
||||
|
||||
# def init__(self, db_source):
|
||||
# self.db_source = db_source
|
||||
#
|
||||
# if db_source['type'] == self.DB_TYPE_MYSQL:
|
||||
# log.e('MySQL not supported yet.')
|
||||
# return False
|
||||
# elif db_source['type'] == self.DB_TYPE_SQLITE:
|
||||
# self._table_prefix = 'ts_'
|
||||
# self._conn_pool = TPSqlitePool(db_source['file'])
|
||||
#
|
||||
# if not os.path.exists(db_source['file']):
|
||||
# log.w('database need create.\n')
|
||||
# self.need_create = True
|
||||
# return True
|
||||
# else:
|
||||
# log.e('Unknown database type: {}'.format(db_source['type']))
|
||||
# return False
|
||||
#
|
||||
# # 看看数据库中是否存在指定的数据表(如果不存在,可能是一个空数据库文件),则可能是一个新安装的系统
|
||||
# # ret = self.query('SELECT COUNT(*) FROM `sqlite_master` WHERE `type`="table" AND `name`="{}account";'.format(self._table_prefix))
|
||||
# ret = self.is_table_exists('{}group'.format(self._table_prefix))
|
||||
# if ret is None or not ret:
|
||||
# log.w('database need create.\n')
|
||||
# self.need_create = True
|
||||
# return True
|
||||
#
|
||||
# # 尝试从配置表中读取当前数据库版本号(如果不存在,说明是比较旧的版本了)
|
||||
# ret = self.query('SELECT `value` FROM `{}config` WHERE `name`="db_ver";'.format(self._table_prefix))
|
||||
# if ret is None or 0 == len(ret):
|
||||
# self.current_ver = 1
|
||||
# else:
|
||||
# self.current_ver = int(ret[0][0])
|
||||
#
|
||||
# if self.current_ver < self.DB_VERSION:
|
||||
# log.w('database need upgrade.\n')
|
||||
# self.need_upgrade = True
|
||||
# return True
|
||||
#
|
||||
# # DO TEST
|
||||
# # self.alter_table('ts_account', [['account_id', 'id'], ['account_type', 'type']])
|
||||
#
|
||||
# return True
|
||||
|
||||
def is_table_exists(self, table_name):
|
||||
"""
|
||||
判断指定的表是否存在
|
||||
|
@ -180,7 +165,6 @@ class TPDatabase:
|
|||
return False
|
||||
return True
|
||||
elif self.db_type == self.DB_TYPE_MYSQL:
|
||||
# select TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='dbname' and TABLE_NAME='tablename' ;
|
||||
ret = self.query('SELECT TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA="{}" and TABLE_NAME="{}";'.format(self.mysql_db, table_name))
|
||||
if ret is None:
|
||||
return None
|
||||
|
|
|
@ -1,112 +1,122 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# import pickle
|
||||
import time
|
||||
import datetime
|
||||
import threading
|
||||
|
||||
# from pymemcache.client.base import Client as mem_client
|
||||
from .configs import app_cfg
|
||||
from eom_common.eomcore.logger import log
|
||||
|
||||
cfg = app_cfg()
|
||||
|
||||
SESSION_EXPIRE = 3600 # 60*60 默认超时时间为1小时
|
||||
|
||||
|
||||
class WebSession(threading.Thread):
|
||||
"""
|
||||
:type _mem_client: pymemcache.client.base.Client
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name='session-manager-thread')
|
||||
|
||||
import builtins
|
||||
if '__web_session__' in builtins.__dict__:
|
||||
raise RuntimeError('WebSession object exists, you can not create more than one instance.')
|
||||
|
||||
# session表,session_id为索引,每个项为一个字典,包括 v(Value), t(Timestamp when add or modify), e(Expire seconds)
|
||||
self._session_dict = dict()
|
||||
|
||||
self._lock = threading.RLock()
|
||||
self._stop_flag = False
|
||||
|
||||
def init(self):
|
||||
return True
|
||||
|
||||
def stop(self):
|
||||
self._stop_flag = True
|
||||
self.join()
|
||||
log.v('{} stopped.'.format(self.name))
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
_now = int(datetime.datetime.utcnow().timestamp())
|
||||
with self._lock:
|
||||
_keys = [k for k in self._session_dict]
|
||||
for k in _keys:
|
||||
if self._session_dict[k]['e'] == 0:
|
||||
continue
|
||||
if _now - self._session_dict[k]['t'] > self._session_dict[k]['e']:
|
||||
del self._session_dict[k]
|
||||
|
||||
# 每隔一分钟检查一次超时的会话
|
||||
for i in range(60):
|
||||
if not self._stop_flag:
|
||||
time.sleep(1)
|
||||
|
||||
def set(self, s_id, value, expire=SESSION_EXPIRE):
|
||||
"""
|
||||
设置一个会话数据,如果expire为负数,则立即删除已经存在的名为s_id的会话,如果expire为0,则此会话数据永不过期。expire的单位为秒。
|
||||
@param s_id: string
|
||||
@param value: string
|
||||
@param expire: integer
|
||||
@return: None
|
||||
"""
|
||||
if expire < 0:
|
||||
with self._lock:
|
||||
if s_id in self._session_dict:
|
||||
del self._session_dict[s_id]
|
||||
else:
|
||||
self._session_dict[s_id] = {'v': value, 't': int(datetime.datetime.utcnow().timestamp()), 'e': expire}
|
||||
|
||||
def get(self, s_id, _default=None):
|
||||
# 从session中获取一个数据(读取并更新最后访问时间)
|
||||
with self._lock:
|
||||
if s_id in self._session_dict:
|
||||
if self._session_dict[s_id]['e'] == 0:
|
||||
return self._session_dict[s_id]['v']
|
||||
else:
|
||||
if int(datetime.datetime.utcnow().timestamp()) - self._session_dict[s_id]['t'] > self._session_dict[s_id]['e']:
|
||||
del self._session_dict[s_id]
|
||||
return _default
|
||||
else:
|
||||
self._session_dict[s_id]['t'] = int(datetime.datetime.utcnow().timestamp())
|
||||
return self._session_dict[s_id]['v']
|
||||
|
||||
else:
|
||||
return _default
|
||||
|
||||
def taken(self, s_id, _default=None):
|
||||
# 从session中取走一个数据(读取并删除)
|
||||
with self._lock:
|
||||
if s_id in self._session_dict:
|
||||
ret = self._session_dict[s_id]['v']
|
||||
del self._session_dict[s_id]
|
||||
return ret
|
||||
else:
|
||||
return _default
|
||||
|
||||
|
||||
def web_session():
|
||||
"""
|
||||
取得Session管理器的唯一实例
|
||||
|
||||
:rtype : WebSession
|
||||
"""
|
||||
|
||||
import builtins
|
||||
if '__web_session__' not in builtins.__dict__:
|
||||
builtins.__dict__['__web_session__'] = WebSession()
|
||||
return builtins.__dict__['__web_session__']
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# import pickle
|
||||
import time
|
||||
import datetime
|
||||
import threading
|
||||
|
||||
# from pymemcache.client.base import Client as mem_client
|
||||
from .configs import app_cfg
|
||||
from eom_common.eomcore.logger import log
|
||||
|
||||
cfg = app_cfg()
|
||||
|
||||
SESSION_EXPIRE = 3600 # 60*60 默认超时时间为1小时
|
||||
|
||||
|
||||
class WebSession(threading.Thread):
|
||||
"""
|
||||
:type _mem_client: pymemcache.client.base.Client
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name='session-manager-thread')
|
||||
|
||||
import builtins
|
||||
if '__web_session__' in builtins.__dict__:
|
||||
raise RuntimeError('WebSession object exists, you can not create more than one instance.')
|
||||
|
||||
# session表,session_id为索引,每个项为一个字典,包括 v(Value), t(Timestamp when add or modify), e(Expire seconds)
|
||||
self._session_dict = dict()
|
||||
|
||||
self._lock = threading.RLock()
|
||||
self._stop_flag = False
|
||||
self._timer_cond = threading.Condition()
|
||||
|
||||
def init(self):
|
||||
return True
|
||||
|
||||
def stop(self):
|
||||
self._stop_flag = True
|
||||
self._timer_cond.acquire()
|
||||
self._timer_cond.notify()
|
||||
self._timer_cond.release()
|
||||
self.join()
|
||||
log.v('{} stopped.\n'.format(self.name))
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
self._timer_cond.acquire()
|
||||
# 每隔一分钟醒来检查一次超时的会话
|
||||
self._timer_cond.wait(60)
|
||||
self._timer_cond.release()
|
||||
if self._stop_flag:
|
||||
break
|
||||
|
||||
_now = int(datetime.datetime.utcnow().timestamp())
|
||||
with self._lock:
|
||||
_keys = [k for k in self._session_dict]
|
||||
for k in _keys:
|
||||
if self._session_dict[k]['e'] == 0:
|
||||
continue
|
||||
if _now - self._session_dict[k]['t'] > self._session_dict[k]['e']:
|
||||
del self._session_dict[k]
|
||||
|
||||
# for i in range(60):
|
||||
# if not self._stop_flag:
|
||||
# time.sleep(1)
|
||||
|
||||
def set(self, s_id, value, expire=SESSION_EXPIRE):
|
||||
"""
|
||||
设置一个会话数据,如果expire为负数,则立即删除已经存在的名为s_id的会话,如果expire为0,则此会话数据永不过期。expire的单位为秒。
|
||||
@param s_id: string
|
||||
@param value: string
|
||||
@param expire: integer
|
||||
@return: None
|
||||
"""
|
||||
if expire < 0:
|
||||
with self._lock:
|
||||
if s_id in self._session_dict:
|
||||
del self._session_dict[s_id]
|
||||
else:
|
||||
self._session_dict[s_id] = {'v': value, 't': int(datetime.datetime.utcnow().timestamp()), 'e': expire}
|
||||
|
||||
def get(self, s_id, _default=None):
|
||||
# 从session中获取一个数据(读取并更新最后访问时间)
|
||||
with self._lock:
|
||||
if s_id in self._session_dict:
|
||||
if self._session_dict[s_id]['e'] == 0:
|
||||
return self._session_dict[s_id]['v']
|
||||
else:
|
||||
if int(datetime.datetime.utcnow().timestamp()) - self._session_dict[s_id]['t'] > self._session_dict[s_id]['e']:
|
||||
del self._session_dict[s_id]
|
||||
return _default
|
||||
else:
|
||||
self._session_dict[s_id]['t'] = int(datetime.datetime.utcnow().timestamp())
|
||||
return self._session_dict[s_id]['v']
|
||||
|
||||
else:
|
||||
return _default
|
||||
|
||||
def taken(self, s_id, _default=None):
|
||||
# 从session中取走一个数据(读取并删除)
|
||||
with self._lock:
|
||||
if s_id in self._session_dict:
|
||||
ret = self._session_dict[s_id]['v']
|
||||
del self._session_dict[s_id]
|
||||
return ret
|
||||
else:
|
||||
return _default
|
||||
|
||||
|
||||
def web_session():
|
||||
"""
|
||||
取得Session管理器的唯一实例
|
||||
|
||||
:rtype : WebSession
|
||||
"""
|
||||
|
||||
import builtins
|
||||
if '__web_session__' not in builtins.__dict__:
|
||||
builtins.__dict__['__web_session__'] = WebSession()
|
||||
return builtins.__dict__['__web_session__']
|
||||
|
|
|
@ -7,24 +7,21 @@ from . import auth
|
|||
from . import host
|
||||
from . import cert
|
||||
from . import user
|
||||
from . import pwd
|
||||
from . import config
|
||||
from . import group
|
||||
from . import index
|
||||
from . import record
|
||||
from . import maintenance
|
||||
# import tornado.web
|
||||
|
||||
from eom_app.app.configs import app_cfg
|
||||
|
||||
cfg = app_cfg()
|
||||
|
||||
__all__ = ['controllers']
|
||||
__all__ = ['controllers', 'fix_controller']
|
||||
|
||||
controllers = [
|
||||
(r'/dashboard', dashboard.IndexHandler),
|
||||
|
||||
(r'/', index.IndexHandler),
|
||||
(r'/dashboard', dashboard.IndexHandler),
|
||||
|
||||
(r'/maintenance/install', maintenance.InstallHandler),
|
||||
(r'/maintenance/upgrade', maintenance.UpgradeHandler),
|
||||
|
@ -53,7 +50,6 @@ controllers = [
|
|||
(r'/cert/', cert.IndexHandler),
|
||||
(r'/cert', cert.IndexHandler),
|
||||
|
||||
# (r'/pwd', pwd.IndexHandler),
|
||||
(r'/user', user.IndexHandler),
|
||||
(r'/user/list', user.GetListHandler),
|
||||
(r'/user/personal', user.PersonalHandler),
|
||||
|
@ -71,8 +67,6 @@ controllers = [
|
|||
(r'/log/', record.LogHandler),
|
||||
(r'/log', record.LogHandler),
|
||||
|
||||
(r'/exit', auth.LogoutHandler),
|
||||
|
||||
(r'/user/delete-user', user.DeleteUser),
|
||||
(r'/user/modify-user', user.ModifyUser),
|
||||
(r'/user/add-user', user.AddUser),
|
||||
|
@ -114,19 +108,17 @@ controllers = [
|
|||
(r'/host/sys-user/update', host.SysUserUpdate),
|
||||
(r'/host/sys-user/delete', host.SysUserDelete),
|
||||
|
||||
# (r'/set/update-config', set.UpdateConfig),
|
||||
# (r'/set/os-operator', set.OsOperator),
|
||||
# (r'/set/info', config.InfoHandler),
|
||||
# (r'/set/db', config.DatabaseHandler),
|
||||
(r'/config/export-database', config.ExportDatabaseHandler),
|
||||
(r'/config/import-database', config.ImportDatabaseHandler),
|
||||
(r'/config/', config.IndexHandler),
|
||||
(r'/config', config.IndexHandler),
|
||||
|
||||
(r'/uidesign', index.UIDesignHandler),
|
||||
(r'/uidesign/without-sidebar', index.UIDesignWithoutSidebarHandler),
|
||||
(r'/uidesign/table', index.UIDesignTableHandler),
|
||||
|
||||
# (r'/test/oath-code', index.OathCodeHandler)
|
||||
|
||||
]
|
||||
|
||||
|
||||
def fix_controller():
|
||||
dbg_mode, _ = cfg.get_bool('common::debug-mode', False)
|
||||
if dbg_mode:
|
||||
controllers.append((r'/exit/9E37CBAEE2294D9D9965112025CEE87F', index.ExitHandler))
|
||||
controllers.append((r'/uidesign', index.UIDesignHandler))
|
||||
controllers.append((r'/uidesign/without-sidebar', index.UIDesignWithoutSidebarHandler))
|
||||
controllers.append((r'/uidesign/table', index.UIDesignTableHandler))
|
||||
|
|
|
@ -57,16 +57,17 @@ class IndexHandler(TPBaseAdminAuthHandler):
|
|||
|
||||
class ExportDatabaseHandler(TPBaseAdminAuthHandler):
|
||||
def get(self):
|
||||
now = time.localtime(time.time())
|
||||
dt = '{:04d}{:02d}{:02d}-{:02d}{:02d}{:02d}'.format(now.tm_year, now.tm_mon, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec)
|
||||
sql, ret = get_db().export_to_sql()
|
||||
if ret:
|
||||
now = time.localtime(time.time())
|
||||
dt = '{:04d}{:02d}{:02d}-{:02d}{:02d}{:02d}'.format(now.tm_year, now.tm_mon, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec)
|
||||
|
||||
self.set_header('Content-Type', 'application/octet-stream')
|
||||
self.set_header('Content-Disposition', 'attachment; filename=teleport-database-export-{}.sql'.format(dt))
|
||||
self.set_header('Content-Type', 'application/octet-stream')
|
||||
self.set_header('Content-Disposition', 'attachment; filename=teleport-database-export-{}.sql'.format(dt))
|
||||
self.write(sql)
|
||||
else:
|
||||
self.write('<h1>错误</h1>导出数据时发生错误:{}'.format(sql))
|
||||
|
||||
sql = get_db().export_to_sql()
|
||||
|
||||
# self.write("分组ID, 操作系统, IP地址, 端口, 协议, 状态, 描述, 系统用户, 系统密码, 是否加密, 附加参数, 密钥ID, 认证类型\n".encode('gbk'))
|
||||
self.write(sql)
|
||||
self.finish()
|
||||
|
||||
|
||||
|
@ -82,8 +83,7 @@ class ImportDatabaseHandler(TPBaseAdminAuthHandler):
|
|||
ret = dict()
|
||||
ret['code'] = 0
|
||||
ret['message'] = ''
|
||||
# ret['data'] = {}
|
||||
# ret['data']['msg'] = list() # 记录跳过的行(格式不正确,或者数据重复等)
|
||||
|
||||
sql_filename = ''
|
||||
|
||||
try:
|
||||
|
@ -114,23 +114,39 @@ class ImportDatabaseHandler(TPBaseAdminAuthHandler):
|
|||
ret['message'] = 'upload sql file is not utf8 encode.'
|
||||
return self.write(json.dumps(ret).encode('utf8'))
|
||||
|
||||
db_ver_checked = False
|
||||
with open(sql_filename, encoding=file_encode) as f:
|
||||
db = get_db()
|
||||
sql = []
|
||||
lines = f.readlines()
|
||||
for line in lines:
|
||||
line = line.strip('\r\n')
|
||||
if line.startswith('-- DATABASE VERSION '):
|
||||
x = line.split(' ')
|
||||
if len(x) != 4:
|
||||
ret['code'] = -1
|
||||
ret['message'] = 'SQL文件格式错误,无法解析数据库版本'
|
||||
return self.write(json.dumps(ret).encode('utf8'))
|
||||
db_ver_sql = int(x[3].strip())
|
||||
if db.DB_VERSION != db_ver_sql:
|
||||
ret['code'] = -1
|
||||
ret['message'] = 'SQL文件数据库版本为 {},当前数据版本为 {},不允许导入!'.format(db_ver_sql, db.DB_VERSION)
|
||||
return self.write(json.dumps(ret).encode('utf8'))
|
||||
db_ver_checked = True
|
||||
continue
|
||||
|
||||
if not db_ver_checked:
|
||||
continue
|
||||
|
||||
if line .startswith('TRUNCATE TABLE '):
|
||||
x = line.split(' ', 2)
|
||||
_table_name = '`{}{}`'.format(get_db().table_prefix, x[2][1:-2])
|
||||
_table_name = '`{}{}`'.format(db.table_prefix, x[2][1:-2])
|
||||
if db.db_type == db.DB_TYPE_MYSQL:
|
||||
x[2] = _table_name
|
||||
line = ' '.join(x)
|
||||
line += ';'
|
||||
sql.append(line)
|
||||
elif db.db_type == db.DB_TYPE_SQLITE:
|
||||
#delete from TableName; //清空数据
|
||||
# update sqlite_sequence SET seq = 0 where name ='TableName';//自增长ID为0
|
||||
sql.append('DELETE FROM {};'.format(_table_name))
|
||||
sql.append('UPDATE `sqlite_sequence` SET `seq`=0 WHERE `name`="{}";'.format(_table_name[1:-1]))
|
||||
|
||||
|
@ -139,22 +155,19 @@ class ImportDatabaseHandler(TPBaseAdminAuthHandler):
|
|||
_table_name = '`{}{}`'.format(db.table_prefix, x[2][1:-1])
|
||||
x[2] = _table_name
|
||||
line = ' '.join(x)
|
||||
# print(line)
|
||||
sql.append(line)
|
||||
|
||||
if not db_ver_checked:
|
||||
ret['code'] = -1
|
||||
ret['message'] = 'SQL文件格式错误,未能确定数据库版本'
|
||||
return self.write(json.dumps(ret).encode('utf8'))
|
||||
|
||||
db_ret = db.transaction(sql)
|
||||
if not db_ret:
|
||||
ret['code'] = -1
|
||||
ret['message'] = 'SQL语句执行出错'
|
||||
return self.write(json.dumps(ret).encode('utf8'))
|
||||
|
||||
# for line in sql:
|
||||
# db_ret = get_db().exec(line)
|
||||
# if not db_ret:
|
||||
# ret['code'] = -1
|
||||
# ret['message'] = 'SQL语句执行出错: {}'.format(line)
|
||||
# return self.write(json.dumps(ret).encode('utf8'))
|
||||
|
||||
ret['code'] = 0
|
||||
return self.write(json.dumps(ret).encode('utf8'))
|
||||
except:
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from .base import TPBaseUserAuthHandler
|
||||
|
||||
|
||||
class IndexHandler(TPBaseUserAuthHandler):
|
||||
def get(self):
|
||||
self.render('pwd/index.mako')
|
|
@ -11,14 +11,9 @@ from eom_app.app.oath import verify_oath_code
|
|||
|
||||
def verify_user(name, password, oath_code):
|
||||
cfg = app_cfg()
|
||||
|
||||
if cfg.app_mode == APP_MODE_MAINTENANCE:
|
||||
if name == 'admin' and password == 'admin':
|
||||
return 1, 100, '系统管理员', 0
|
||||
|
||||
db = get_db()
|
||||
|
||||
sql = 'SELECT `account_id`, `account_type`, `account_desc`, `account_pwd`, `account_lock`, `oath_secret` FROM `{}account` WHERE `account_name`="{}";'.format(db.table_prefix, name)
|
||||
sql = 'SELECT `account_id`, `account_type`, `account_desc`, `account_pwd`, `account_lock` FROM `{}account` WHERE `account_name`="{}";'.format(db.table_prefix, name)
|
||||
db_ret = db.query(sql)
|
||||
if db_ret is None:
|
||||
# 特别地,如果无法取得数据库连接,有可能是新安装的系统,尚未建立数据库,此时应该处于维护模式
|
||||
|
@ -35,7 +30,6 @@ def verify_user(name, password, oath_code):
|
|||
account_type = db_ret[0][1]
|
||||
desc = db_ret[0][2]
|
||||
locked = db_ret[0][4]
|
||||
oath_secret = db_ret[0][5]
|
||||
if locked == 1:
|
||||
return 0, 0, '', locked
|
||||
|
||||
|
@ -50,7 +44,7 @@ def verify_user(name, password, oath_code):
|
|||
db.exec(sql)
|
||||
|
||||
if oath_code is not None:
|
||||
if not verify_oath_code(oath_secret, oath_code):
|
||||
if not verify_oath(user_id, oath_code):
|
||||
return 0, 0, '', 0
|
||||
|
||||
return user_id, account_type, desc, locked
|
||||
|
|
|
@ -111,24 +111,9 @@ ywl.do_upload_sql_file = function () {
|
|||
$('#upload-file').remove();
|
||||
var ret = JSON.parse(data);
|
||||
if (ret.code === TPE_OK) {
|
||||
// g_host_table.reload();
|
||||
ywl.notify_success('导入sql成功!');
|
||||
// if (ret.data.msg.length > 0) {
|
||||
// var html = [];
|
||||
// html.push('<ul>');
|
||||
// for (var i = 0, cnt = ret.data.msg.length; i < cnt; ++i) {
|
||||
// html.push('<li>');
|
||||
// html.push('<span style="font-weight:bold;color:#993333;">' + ret.data.msg[i].reason + '</span><br/>');
|
||||
// html.push(ret.data.msg[i].line);
|
||||
// html.push('</li>');
|
||||
// }
|
||||
// html.push('</ul>');
|
||||
//
|
||||
// // $('#batch_add_host_result').html(html.join(''));
|
||||
//// $('#dialog_batch_add_host').modal({backdrop: 'static'});
|
||||
// }
|
||||
} else {
|
||||
ywl.notify_error('导入sql失败! 错误号:' + ret.code);
|
||||
ywl.notify_error('导入sql失败!<br/>[' + ret.code+'] '+ret.message);
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
|
@ -141,7 +126,6 @@ ywl.do_upload_sql_file = function () {
|
|||
ywl._make_protocol_info = function (name, p) {
|
||||
if (_.isUndefined(p))
|
||||
return ywl._make_info(name, '未能检测到');
|
||||
// <tr><td class="key">RDP 端口:</td><td class="value">52089</td></tr>
|
||||
var val = p.port;
|
||||
if (!p.enable) {
|
||||
val = '<span class="disabled">' + val + '(未启用)</span>';
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<%!
|
||||
import time
|
||||
page_title_ = ''
|
||||
page_menu_ = []
|
||||
time_now = int(time.time())
|
||||
%>
|
||||
<!--[if IE 8]> <html lang="en" class="ie8"> <![endif]-->
|
||||
<!--[if !IE]><!-->
|
||||
|
@ -38,6 +40,9 @@
|
|||
<div class="breadcrumb-container">
|
||||
<%block name="breadcrumb" />
|
||||
</div>
|
||||
<div style="display:inline-block;float:right;padding-top:12px;">
|
||||
系统时间:<span id="system-timer">111</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end #header -->
|
||||
|
@ -81,8 +86,6 @@
|
|||
</div>
|
||||
|
||||
<%block name="extend_content" />
|
||||
## <script type="text/javascript" src="${ static_url('js/var.js') }"></script>
|
||||
|
||||
<script type="text/javascript" src="${ static_url('plugins/underscore/underscore.js') }"></script>
|
||||
<script type="text/javascript" src="${ static_url('plugins/jquery/jquery.min.js') }"></script>
|
||||
<script type="text/javascript" src="${ static_url('plugins/jquery/ajaxfileupload.js') }"></script>
|
||||
|
@ -102,7 +105,6 @@
|
|||
|
||||
<%block name="extend_js"/>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
ywl.add_page_options({
|
||||
## 有些参数由后台python脚本生成到模板中,无法直接生成到js文件中,所以必须通过这种方式传递参数到js脚本中。
|
||||
|
@ -110,10 +112,15 @@
|
|||
});
|
||||
|
||||
$(document).ready(function () {
|
||||
// once page ready, init ywl object.
|
||||
## var teleport_ip_info = "请核对您的堡垒机IP地址,当前为 " + teleport_ip;
|
||||
## $("#teleport-server-ip").text(teleport_ip_info);
|
||||
ywl.init();
|
||||
|
||||
var g_time_now = ${time_now};
|
||||
var g_dom_timer = $('#system-timer');
|
||||
g_dom_timer.text(format_datetime(g_time_now));
|
||||
setInterval(function(){
|
||||
g_dom_timer.text(format_datetime(g_time_now));
|
||||
g_time_now += 1;
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
|
Loading…
Reference in New Issue