修正:MySQL长时间未通讯会丢失连接;改进:导入导出数据库时增加对数据库版本的检查;改进:页面上总是显示teleport服务器的时间(配合检查身份认证器的时间是否同步);

pull/32/merge
Apex Liu 2017-06-04 18:07:50 +08:00
parent 1a3f7f3378
commit 7208f39aa0
12 changed files with 260 additions and 272 deletions

View File

@ -156,11 +156,12 @@ class BaseAppConfig(dict):
self._on_init() self._on_init()
def __getattr__(self, name): def __getattr__(self, name):
if name in self['_kvs']: _name = name.replace('-', '_')
return self['_kvs'][name] if _name in self['_kvs']:
return self['_kvs'][_name]
else: else:
if name in self['_kvs']['_']: if _name in self['_kvs']['_']:
return self['_kvs']['_'][name] return self['_kvs']['_'][_name]
else: else:
return AttrDict() return AttrDict()
@ -168,7 +169,7 @@ class BaseAppConfig(dict):
x = key.split('::') x = key.split('::')
if 1 == len(x): if 1 == len(x):
_sec = '_' _sec = '_'
_key = x[0] _key = x[0].replace('-', '_')
elif 2 == len(x): elif 2 == len(x):
_sec = x[0].replace('-', '_') _sec = x[0].replace('-', '_')
_key = x[1].replace('-', '_') _key = x[1].replace('-', '_')
@ -199,7 +200,7 @@ class BaseAppConfig(dict):
x = key.split('::') x = key.split('::')
if 1 == len(x): if 1 == len(x):
_sec = '_' _sec = '_'
_key = x[0] _key = x[0].replace('-', '_')
elif 2 == len(x): elif 2 == len(x):
_sec = x[0].replace('-', '_') _sec = x[0].replace('-', '_')
_key = x[1].replace('-', '_') _key = x[1].replace('-', '_')
@ -215,7 +216,7 @@ class BaseAppConfig(dict):
x = key.split('::') x = key.split('::')
if 1 == len(x): if 1 == len(x):
_sec = '_' _sec = '_'
_key = x[0] _key = x[0].replace('-', '_')
elif 2 == len(x): elif 2 == len(x):
_sec = x[0].replace('-', '_') _sec = x[0].replace('-', '_')
_key = x[1].replace('-', '_') _key = x[1].replace('-', '_')
@ -311,10 +312,10 @@ class BaseAppConfig(dict):
x = key.split('::') x = key.split('::')
if 1 == len(x): if 1 == len(x):
_sec = '_' _sec = '_'
_key = x[0] _key = x[0].replace('-', '_')
elif 2 == len(x): elif 2 == len(x):
_sec = x[0] _sec = x[0].replace('-', '_')
_key = x[1] _key = x[1].replace('-', '_')
else: else:
return def_value, False return def_value, False
@ -322,16 +323,20 @@ class BaseAppConfig(dict):
return def_value, False return def_value, False
if _key not in self['_kvs'][_sec]: if _key not in self['_kvs'][_sec]:
return def_value, False return def_value, False
if self['_kvs'][_sec][_key] is None:
return def_value, False
return str(self['_kvs'][_sec][_key]), True return str(self['_kvs'][_sec][_key]), True
def get_int(self, key, def_value=-1): def get_int(self, key, def_value=-1):
x = key.split('::') x = key.split('::')
if 1 == len(x): if 1 == len(x):
_sec = '_' _sec = '_'
_key = x[0] _key = x[0].replace('-', '_')
elif 2 == len(x): elif 2 == len(x):
_sec = x[0] _sec = x[0].replace('-', '_')
_key = x[1] _key = x[1].replace('-', '_')
else: else:
return def_value, False return def_value, False
@ -340,6 +345,9 @@ class BaseAppConfig(dict):
if _key not in self['_kvs'][_sec]: if _key not in self['_kvs'][_sec]:
return def_value, False return def_value, False
if self['_kvs'][_sec][_key] is None:
return def_value, False
try: try:
return int(self['_kvs'][_sec][_key]), True return int(self['_kvs'][_sec][_key]), True
except ValueError as e: except ValueError as e:
@ -350,10 +358,10 @@ class BaseAppConfig(dict):
x = key.split('::') x = key.split('::')
if 1 == len(x): if 1 == len(x):
_sec = '_' _sec = '_'
_key = x[0] _key = x[0].replace('-', '_')
elif 2 == len(x): elif 2 == len(x):
_sec = x[0] _sec = x[0].replace('-', '_')
_key = x[1] _key = x[1].replace('-', '_')
else: else:
return def_value, False return def_value, False
@ -362,6 +370,9 @@ class BaseAppConfig(dict):
if _key not in self['_kvs'][_sec]: if _key not in self['_kvs'][_sec]:
return def_value, False return def_value, False
if self['_kvs'][_sec][_key] is None:
return def_value, False
tmp = str(self['_kvs'][_sec][_key]).lower() tmp = str(self['_kvs'][_sec][_key]).lower()
if tmp in ['yes', 'true', '1']: if tmp in ['yes', 'true', '1']:
@ -415,14 +426,6 @@ class AppConfig(BaseAppConfig):
self.set_default('database::sqlite-file', None, self.set_default('database::sqlite-file', None,
'sqlite-file=/var/lib/teleport/data/ts_db.db' '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-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-port', 3306, 'mysql-port=3306')
self.set_default('database::mysql-db', 'teleport', 'mysql-db=teleport') 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) self.set_kv('database::mysql-password', _tmp_str)
_log_file, ok = self.get_str('common::log-file') _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)) self.log_path = os.path.abspath(os.path.dirname(_log_file))
else: else:
_log_file = os.path.join(self.log_path, 'tpweb.log') _log_file = os.path.join(self.log_path, 'tpweb.log')

View File

@ -101,7 +101,8 @@ class WebServerCore:
'static_hash_cache': False, '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) web_app = tornado.web.Application(controllers, **settings)
server = tornado.httpserver.HTTPServer(web_app) server = tornado.httpserver.HTTPServer(web_app)
@ -118,9 +119,12 @@ class WebServerCore:
# 启动session超时管理 # 启动session超时管理
web_session().start() web_session().start()
# 启动数据库定时事务例如MySQL防丢失连接
get_db().start_keep_alive()
tornado.ioloop.IOLoop.instance().start() tornado.ioloop.IOLoop.instance().start()
get_db().stop_keep_alive()
web_session().stop() web_session().stop()
return 0 return 0

View File

@ -46,7 +46,13 @@ def export_database(db):
elif db.db_type == db.DB_TYPE_MYSQL: elif db.db_type == db.DB_TYPE_MYSQL:
ret.append('-- export from MySQL Database') ret.append('-- export from MySQL Database')
else: 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'] _fields = ['account_id', 'account_type', 'account_name', 'account_pwd', 'account_status', 'account_lock', 'account_desc', 'oath_secret']
ret.append(_export_table(db, 'account', _fields)) 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'] _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)) ret.append(_export_table(db, 'log', _fields))
return '\r\n'.join(ret) return '\r\n'.join(ret), True

View File

@ -530,14 +530,14 @@ class DatabaseUpgrade:
def _upgrade_to_v6(self): def _upgrade_to_v6(self):
_step = self.step_begin('检查数据库版本v6...') _step = self.step_begin('检查数据库版本v6...')
# 服务端升级到版本2.2.9.1为增加双因子认证为account表增加oath_secret字段 # 服务端升级到版本2.2.9为增加双因子认证为account表增加oath_secret字段
# db_ret = self.db.is_field_exists('{}account'.format(self.db.table_prefix), 'oath_secret') db_ret = self.db.is_field_exists('{}account'.format(self.db.table_prefix), 'oath_secret')
# if db_ret is None: if db_ret is None:
# self.step_end(_step, -1, '无法连接到数据库') self.step_end(_step, -1, '无法连接到数据库')
# return False return False
# if db_ret: if db_ret:
# self.step_end(_step, 0, '跳过 v5 到 v6 的升级操作') self.step_end(_step, 0, '跳过 v5 到 v6 的升级操作')
# return True return True
self.step_end(_step, 0, '需要升级到v6') self.step_end(_step, 0, '需要升级到v6')
@ -556,7 +556,6 @@ class DatabaseUpgrade:
self.step_end(_step, 0) self.step_end(_step, 0)
return True return True
except: except:
log.e('failed.\n') log.e('failed.\n')
self.step_end(_step, -1) self.step_end(_step, -1)

View File

@ -46,6 +46,10 @@ class TPDatabase:
self._table_prefix = '' self._table_prefix = ''
self._conn_pool = None self._conn_pool = None
self._stop_flag = False
self._thread_keep_alive_handle = None
self._thread_keep_alive_cond = threading.Condition()
@property @property
def table_prefix(self): def table_prefix(self):
return self._table_prefix return self._table_prefix
@ -91,6 +95,30 @@ class TPDatabase:
return True 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): def _init_sqlite(self, db_file):
self.db_type = self.DB_TYPE_SQLITE self.db_type = self.DB_TYPE_SQLITE
self.auto_increment = 'AUTOINCREMENT' self.auto_increment = 'AUTOINCREMENT'
@ -121,49 +149,6 @@ class TPDatabase:
return True 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): def is_table_exists(self, table_name):
""" """
判断指定的表是否存在 判断指定的表是否存在
@ -180,7 +165,6 @@ class TPDatabase:
return False return False
return True return True
elif self.db_type == self.DB_TYPE_MYSQL: 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)) 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: if ret is None:
return None return None

View File

@ -31,17 +31,28 @@ class WebSession(threading.Thread):
self._lock = threading.RLock() self._lock = threading.RLock()
self._stop_flag = False self._stop_flag = False
self._timer_cond = threading.Condition()
def init(self): def init(self):
return True return True
def stop(self): def stop(self):
self._stop_flag = True self._stop_flag = True
self._timer_cond.acquire()
self._timer_cond.notify()
self._timer_cond.release()
self.join() self.join()
log.v('{} stopped.'.format(self.name)) log.v('{} stopped.\n'.format(self.name))
def run(self): def run(self):
while True: 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()) _now = int(datetime.datetime.utcnow().timestamp())
with self._lock: with self._lock:
_keys = [k for k in self._session_dict] _keys = [k for k in self._session_dict]
@ -51,10 +62,9 @@ class WebSession(threading.Thread):
if _now - self._session_dict[k]['t'] > self._session_dict[k]['e']: if _now - self._session_dict[k]['t'] > self._session_dict[k]['e']:
del self._session_dict[k] del self._session_dict[k]
# 每隔一分钟检查一次超时的会话 # for i in range(60):
for i in range(60): # if not self._stop_flag:
if not self._stop_flag: # time.sleep(1)
time.sleep(1)
def set(self, s_id, value, expire=SESSION_EXPIRE): def set(self, s_id, value, expire=SESSION_EXPIRE):
""" """

View File

@ -7,24 +7,21 @@ from . import auth
from . import host from . import host
from . import cert from . import cert
from . import user from . import user
from . import pwd
from . import config from . import config
from . import group from . import group
from . import index from . import index
from . import record from . import record
from . import maintenance from . import maintenance
# import tornado.web
from eom_app.app.configs import app_cfg from eom_app.app.configs import app_cfg
cfg = app_cfg() cfg = app_cfg()
__all__ = ['controllers'] __all__ = ['controllers', 'fix_controller']
controllers = [ controllers = [
(r'/dashboard', dashboard.IndexHandler),
(r'/', index.IndexHandler), (r'/', index.IndexHandler),
(r'/dashboard', dashboard.IndexHandler),
(r'/maintenance/install', maintenance.InstallHandler), (r'/maintenance/install', maintenance.InstallHandler),
(r'/maintenance/upgrade', maintenance.UpgradeHandler), (r'/maintenance/upgrade', maintenance.UpgradeHandler),
@ -53,7 +50,6 @@ controllers = [
(r'/cert/', cert.IndexHandler), (r'/cert/', cert.IndexHandler),
(r'/cert', cert.IndexHandler), (r'/cert', cert.IndexHandler),
# (r'/pwd', pwd.IndexHandler),
(r'/user', user.IndexHandler), (r'/user', user.IndexHandler),
(r'/user/list', user.GetListHandler), (r'/user/list', user.GetListHandler),
(r'/user/personal', user.PersonalHandler), (r'/user/personal', user.PersonalHandler),
@ -71,8 +67,6 @@ controllers = [
(r'/log/', record.LogHandler), (r'/log/', record.LogHandler),
(r'/log', record.LogHandler), (r'/log', record.LogHandler),
(r'/exit', auth.LogoutHandler),
(r'/user/delete-user', user.DeleteUser), (r'/user/delete-user', user.DeleteUser),
(r'/user/modify-user', user.ModifyUser), (r'/user/modify-user', user.ModifyUser),
(r'/user/add-user', user.AddUser), (r'/user/add-user', user.AddUser),
@ -114,19 +108,17 @@ controllers = [
(r'/host/sys-user/update', host.SysUserUpdate), (r'/host/sys-user/update', host.SysUserUpdate),
(r'/host/sys-user/delete', host.SysUserDelete), (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/export-database', config.ExportDatabaseHandler),
(r'/config/import-database', config.ImportDatabaseHandler), (r'/config/import-database', config.ImportDatabaseHandler),
(r'/config/', config.IndexHandler), (r'/config/', config.IndexHandler),
(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))

View File

@ -57,16 +57,17 @@ class IndexHandler(TPBaseAdminAuthHandler):
class ExportDatabaseHandler(TPBaseAdminAuthHandler): class ExportDatabaseHandler(TPBaseAdminAuthHandler):
def get(self): def get(self):
now = time.localtime(time.time()) sql, ret = get_db().export_to_sql()
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) 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-Type', 'application/octet-stream')
self.set_header('Content-Disposition', 'attachment; filename=teleport-database-export-{}.sql'.format(dt)) 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() self.finish()
@ -82,8 +83,7 @@ class ImportDatabaseHandler(TPBaseAdminAuthHandler):
ret = dict() ret = dict()
ret['code'] = 0 ret['code'] = 0
ret['message'] = '' ret['message'] = ''
# ret['data'] = {}
# ret['data']['msg'] = list() # 记录跳过的行(格式不正确,或者数据重复等)
sql_filename = '' sql_filename = ''
try: try:
@ -114,23 +114,39 @@ class ImportDatabaseHandler(TPBaseAdminAuthHandler):
ret['message'] = 'upload sql file is not utf8 encode.' ret['message'] = 'upload sql file is not utf8 encode.'
return self.write(json.dumps(ret).encode('utf8')) return self.write(json.dumps(ret).encode('utf8'))
db_ver_checked = False
with open(sql_filename, encoding=file_encode) as f: with open(sql_filename, encoding=file_encode) as f:
db = get_db() db = get_db()
sql = [] sql = []
lines = f.readlines() lines = f.readlines()
for line in lines: for line in lines:
line = line.strip('\r\n') 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 '): if line .startswith('TRUNCATE TABLE '):
x = line.split(' ', 2) 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: if db.db_type == db.DB_TYPE_MYSQL:
x[2] = _table_name x[2] = _table_name
line = ' '.join(x) line = ' '.join(x)
line += ';' line += ';'
sql.append(line) sql.append(line)
elif db.db_type == db.DB_TYPE_SQLITE: 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('DELETE FROM {};'.format(_table_name))
sql.append('UPDATE `sqlite_sequence` SET `seq`=0 WHERE `name`="{}";'.format(_table_name[1:-1])) 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]) _table_name = '`{}{}`'.format(db.table_prefix, x[2][1:-1])
x[2] = _table_name x[2] = _table_name
line = ' '.join(x) line = ' '.join(x)
# print(line)
sql.append(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) db_ret = db.transaction(sql)
if not db_ret: if not db_ret:
ret['code'] = -1 ret['code'] = -1
ret['message'] = 'SQL语句执行出错' ret['message'] = 'SQL语句执行出错'
return self.write(json.dumps(ret).encode('utf8')) 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 ret['code'] = 0
return self.write(json.dumps(ret).encode('utf8')) return self.write(json.dumps(ret).encode('utf8'))
except: except:

View File

@ -1,8 +0,0 @@
# -*- coding: utf-8 -*-
from .base import TPBaseUserAuthHandler
class IndexHandler(TPBaseUserAuthHandler):
def get(self):
self.render('pwd/index.mako')

View File

@ -11,14 +11,9 @@ from eom_app.app.oath import verify_oath_code
def verify_user(name, password, oath_code): def verify_user(name, password, oath_code):
cfg = app_cfg() cfg = app_cfg()
if cfg.app_mode == APP_MODE_MAINTENANCE:
if name == 'admin' and password == 'admin':
return 1, 100, '系统管理员', 0
db = get_db() 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) db_ret = db.query(sql)
if db_ret is None: if db_ret is None:
# 特别地,如果无法取得数据库连接,有可能是新安装的系统,尚未建立数据库,此时应该处于维护模式 # 特别地,如果无法取得数据库连接,有可能是新安装的系统,尚未建立数据库,此时应该处于维护模式
@ -35,7 +30,6 @@ def verify_user(name, password, oath_code):
account_type = db_ret[0][1] account_type = db_ret[0][1]
desc = db_ret[0][2] desc = db_ret[0][2]
locked = db_ret[0][4] locked = db_ret[0][4]
oath_secret = db_ret[0][5]
if locked == 1: if locked == 1:
return 0, 0, '', locked return 0, 0, '', locked
@ -50,7 +44,7 @@ def verify_user(name, password, oath_code):
db.exec(sql) db.exec(sql)
if oath_code is not None: 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 0, 0, '', 0
return user_id, account_type, desc, locked return user_id, account_type, desc, locked

View File

@ -111,24 +111,9 @@ ywl.do_upload_sql_file = function () {
$('#upload-file').remove(); $('#upload-file').remove();
var ret = JSON.parse(data); var ret = JSON.parse(data);
if (ret.code === TPE_OK) { if (ret.code === TPE_OK) {
// g_host_table.reload();
ywl.notify_success('导入sql成功'); 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 { } else {
ywl.notify_error('导入sql失败 错误号:' + ret.code); ywl.notify_error('导入sql失败<br/>[' + ret.code+'] '+ret.message);
} }
}, },
error: function () { error: function () {
@ -141,7 +126,6 @@ ywl.do_upload_sql_file = function () {
ywl._make_protocol_info = function (name, p) { ywl._make_protocol_info = function (name, p) {
if (_.isUndefined(p)) if (_.isUndefined(p))
return ywl._make_info(name, '未能检测到'); return ywl._make_info(name, '未能检测到');
// <tr><td class="key">RDP 端口:</td><td class="value">52089</td></tr>
var val = p.port; var val = p.port;
if (!p.enable) { if (!p.enable) {
val = '<span class="disabled">' + val + '(未启用)</span>'; val = '<span class="disabled">' + val + '(未启用)</span>';

View File

@ -1,7 +1,9 @@
<!DOCTYPE html> <!DOCTYPE html>
<%! <%!
import time
page_title_ = '' page_title_ = ''
page_menu_ = [] page_menu_ = []
time_now = int(time.time())
%> %>
<!--[if IE 8]> <html lang="en" class="ie8"> <![endif]--> <!--[if IE 8]> <html lang="en" class="ie8"> <![endif]-->
<!--[if !IE]><!--> <!--[if !IE]><!-->
@ -38,6 +40,9 @@
<div class="breadcrumb-container"> <div class="breadcrumb-container">
<%block name="breadcrumb" /> <%block name="breadcrumb" />
</div> </div>
<div style="display:inline-block;float:right;padding-top:12px;">
系统时间:<span id="system-timer">111</span>
</div>
</div> </div>
</div> </div>
<!-- end #header --> <!-- end #header -->
@ -81,8 +86,6 @@
</div> </div>
<%block name="extend_content" /> <%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/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/jquery.min.js') }"></script>
<script type="text/javascript" src="${ static_url('plugins/jquery/ajaxfileupload.js') }"></script> <script type="text/javascript" src="${ static_url('plugins/jquery/ajaxfileupload.js') }"></script>
@ -102,7 +105,6 @@
<%block name="extend_js"/> <%block name="extend_js"/>
<script type="text/javascript"> <script type="text/javascript">
ywl.add_page_options({ ywl.add_page_options({
## 有些参数由后台python脚本生成到模板中无法直接生成到js文件中所以必须通过这种方式传递参数到js脚本中。 ## 有些参数由后台python脚本生成到模板中无法直接生成到js文件中所以必须通过这种方式传递参数到js脚本中。
@ -110,10 +112,15 @@
}); });
$(document).ready(function () { $(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(); 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> </script>