1. 修正mysql中varchar用作索引字段时,长度必须小于等于255;

2. temp: 配置页面加入导入导出按钮。
pull/32/head
Apex Liu 2017-05-26 02:18:01 +08:00
parent c5859cdce6
commit 428dc323f3
8 changed files with 221 additions and 154 deletions

View File

@ -29,7 +29,7 @@ def create_and_init(db, step_begin, step_end):
_db_exec(db, step_begin, step_end, '创建表 auth', """CREATE TABLE `{}auth`( _db_exec(db, step_begin, step_end, '创建表 auth', """CREATE TABLE `{}auth`(
`auth_id` INTEGER PRIMARY KEY {}, `auth_id` INTEGER PRIMARY KEY {},
`account_name` varchar(256), `account_name` varchar(255),
`host_id` INTEGER, `host_id` INTEGER,
`host_auth_id` int(11) NOT NULL `host_auth_id` int(11) NOT NULL
);""".format(db.table_prefix, db.auto_increment)) );""".format(db.table_prefix, db.auto_increment))
@ -38,16 +38,16 @@ def create_and_init(db, step_begin, step_end):
# 这也是升级到数据库版本5的标志 # 这也是升级到数据库版本5的标志
_db_exec(db, step_begin, step_end, '创建表 key', """CREATE TABLE `{}key` ( _db_exec(db, step_begin, step_end, '创建表 key', """CREATE TABLE `{}key` (
`cert_id` integer PRIMARY KEY {}, `cert_id` integer PRIMARY KEY {},
`cert_name` varchar(256), `cert_name` varchar(255),
`cert_pub` varchar(2048) DEFAULT '', `cert_pub` varchar(2048) DEFAULT '',
`cert_pri` varchar(4096) DEFAULT '', `cert_pri` varchar(4096) DEFAULT '',
`cert_desc` varchar(256) `cert_desc` varchar(255)
); );
""".format(db.table_prefix, db.auto_increment)) """.format(db.table_prefix, db.auto_increment))
_db_exec(db, step_begin, step_end, '创建表 config', """CREATE TABLE `{}config` ( _db_exec(db, step_begin, step_end, '创建表 config', """CREATE TABLE `{}config` (
`name` varchar(256) NOT NULL, `name` varchar(128) NOT NULL,
`value` varchar(256), `value` varchar(255),
PRIMARY KEY (`name` ASC) PRIMARY KEY (`name` ASC)
);""".format(db.table_prefix)) );""".format(db.table_prefix))
@ -64,16 +64,16 @@ PRIMARY KEY (`name` ASC)
`host_port` int(11) DEFAULT 0, `host_port` int(11) DEFAULT 0,
`protocol` int(11) DEFAULT 0, `protocol` int(11) DEFAULT 0,
`host_lock` int(11) DEFAULT 0, `host_lock` int(11) DEFAULT 0,
`host_desc` varchar(256) DEFAULT '' `host_desc` varchar(255) DEFAULT ''
);""".format(db.table_prefix, db.auto_increment)) );""".format(db.table_prefix, db.auto_increment))
_db_exec(db, step_begin, step_end, '创建表 auth_info', """CREATE TABLE `{}auth_info`( _db_exec(db, step_begin, step_end, '创建表 auth_info', """CREATE TABLE `{}auth_info`(
`id` INTEGER PRIMARY KEY {}, `id` INTEGER PRIMARY KEY {},
`host_id` INTEGER, `host_id` INTEGER,
`auth_mode` INTEGER, `auth_mode` INTEGER,
`user_name` varchar(256), `user_name` varchar(255),
`user_pswd` varchar(256), `user_pswd` varchar(255),
`user_param` varchar(256), `user_param` varchar(255),
`cert_id` INTEGER, `cert_id` INTEGER,
`encrypt` INTEGER, `encrypt` INTEGER,
`log_time` varchar(60) `log_time` varchar(60)

View File

@ -149,7 +149,7 @@ class DatabaseUpgrade:
`group_id` int(11) DEFAULT 0, `group_id` int(11) DEFAULT 0,
`host_sys_type` int(11) DEFAULT 1, `host_sys_type` int(11) DEFAULT 1,
`host_ip` varchar(32) DEFAULT '', `host_ip` varchar(32) DEFAULT '',
`pro_port` varchar(256) NULL, `pro_port` varchar(255) NULL,
`host_lock` int(11) DEFAULT 0, `host_lock` int(11) DEFAULT 0,
`host_desc` varchar(128) DEFAULT '' `host_desc` varchar(128) DEFAULT ''
);""".format(self.db.table_prefix, self.db.auto_increment)): );""".format(self.db.table_prefix, self.db.auto_increment)):
@ -161,8 +161,8 @@ class DatabaseUpgrade:
`host_id` INTEGER, `host_id` INTEGER,
`pro_type` INTEGER, `pro_type` INTEGER,
`auth_mode` INTEGER, `auth_mode` INTEGER,
`user_name` varchar(256), `user_name` varchar(255),
`user_pswd` varchar(256), `user_pswd` varchar(255),
`cert_id` INTEGER, `cert_id` INTEGER,
`encrypt` INTEGER, `encrypt` INTEGER,
`log_time` varchar(60) `log_time` varchar(60)
@ -381,7 +381,7 @@ class DatabaseUpgrade:
# 先创建三个临时表 # 先创建三个临时表
if not self.db.exec("""CREATE TABLE `{}auth_tmp` ( if not self.db.exec("""CREATE TABLE `{}auth_tmp` (
`auth_id` INTEGER PRIMARY KEY {}, `auth_id` INTEGER PRIMARY KEY {},
`account_name` varchar(256), `account_name` varchar(255),
`host_id` INTEGER, `host_id` INTEGER,
`host_auth_id` int(11) NOT NULL `host_auth_id` int(11) NOT NULL
);""".format(self.db.table_prefix, self.db.auto_increment)): );""".format(self.db.table_prefix, self.db.auto_increment)):
@ -405,9 +405,9 @@ class DatabaseUpgrade:
`id` INTEGER PRIMARY KEY {}, `id` INTEGER PRIMARY KEY {},
`host_id` INTEGER, `host_id` INTEGER,
`auth_mode` INTEGER, `auth_mode` INTEGER,
`user_name` varchar(256), `user_name` varchar(255),
`user_pswd` varchar(256), `user_pswd` varchar(255),
`user_param` varchar(256), `user_param` varchar(255),
`cert_id` INTEGER, `cert_id` INTEGER,
`encrypt` INTEGER, `encrypt` INTEGER,
`log_time` varchar(60) `log_time` varchar(60)
@ -492,8 +492,8 @@ class DatabaseUpgrade:
if not self.db.is_table_exists('{}config'.format(self.db.table_prefix)): if not self.db.is_table_exists('{}config'.format(self.db.table_prefix)):
if not self.db.exec("""CREATE TABLE `{}config` ( if not self.db.exec("""CREATE TABLE `{}config` (
`name` varchar(256) NOT NULL, `name` varchar(128) NOT NULL,
`value` varchar(256), `value` varchar(255),
PRIMARY KEY (`name` ASC) PRIMARY KEY (`name` ASC)
);""".format(self.db.table_prefix)): );""".format(self.db.table_prefix)):
self.step_end(_step, -1, 'config表不存在且无法创建') self.step_end(_step, -1, 'config表不存在且无法创建')

View File

@ -302,6 +302,13 @@ class TPDatabase:
log.e('Unknown database type.\n') log.e('Unknown database type.\n')
return False return False
def export_to_sql(self):
# TODO: not implement.
ret = []
ret.append('{}'.format(self.db_type))
ret.append('export to sql not implement.')
return '\n'.join(ret)
class TPDatabasePool: class TPDatabasePool:
def __init__(self): def __init__(self):
@ -350,6 +357,7 @@ class TPDatabasePool:
def _last_insert_id(self, conn): def _last_insert_id(self, conn):
return -1 return -1
class TPSqlitePool(TPDatabasePool): class TPSqlitePool(TPDatabasePool):
def __init__(self, db_file): def __init__(self, db_file):
super().__init__() super().__init__()

View File

@ -113,6 +113,8 @@ controllers = [
# (r'/set/os-operator', set.OsOperator), # (r'/set/os-operator', set.OsOperator),
# (r'/set/info', config.InfoHandler), # (r'/set/info', config.InfoHandler),
# (r'/set/db', config.DatabaseHandler), # (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'/config', config.IndexHandler), (r'/config', config.IndexHandler),

View File

@ -1,5 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os
import time
import json import json
import tornado.gen import tornado.gen
import tornado.httpclient import tornado.httpclient
@ -8,6 +10,7 @@ from eom_ver import *
from eom_app.app.db import get_db from eom_app.app.db import get_db
from eom_app.app.configs import app_cfg from eom_app.app.configs import app_cfg
from eom_app.app.util import * from eom_app.app.util import *
from eom_common.eomcore.logger import log
from .base import TPBaseAdminAuthHandler, TPBaseAdminAuthJsonHandler from .base import TPBaseAdminAuthHandler, TPBaseAdminAuthJsonHandler
cfg = app_cfg() cfg = app_cfg()
@ -24,7 +27,6 @@ class IndexHandler(TPBaseAdminAuthHandler):
if 'code' in return_data: if 'code' in return_data:
_code = return_data['code'] _code = return_data['code']
if _code == 0: if _code == 0:
# core['detected'] = True
cfg.update_core(return_data['data']) cfg.update_core(return_data['data'])
core_detected = True core_detected = True
@ -52,138 +54,77 @@ class IndexHandler(TPBaseAdminAuthHandler):
} }
self.render('config/index.mako', page_param=json.dumps(param)) self.render('config/index.mako', page_param=json.dumps(param))
# class InfoHandler(TPBaseAdminAuthHandler):
# @tornado.gen.coroutine class ExportDatabaseHandler(TPBaseAdminAuthHandler):
# def get(self): def get(self):
# core_detected = False self.set_header('Content-Type', 'application/octet-stream')
# req = {'method': 'get_config', 'param': []} self.set_header('Content-Disposition', 'attachment; filename=teleport-database-export.sql')
# _yr = async_post_http(req)
# return_data = yield _yr sql = get_db().export_to_sql()
# if return_data is not None:
# if 'code' in return_data: # self.write("分组ID, 操作系统, IP地址, 端口, 协议, 状态, 描述, 系统用户, 系统密码, 是否加密, 附加参数, 密钥ID, 认证类型\n".encode('gbk'))
# _code = return_data['code'] self.write(sql)
# if _code == 0: self.finish()
# # core['detected'] = True
# cfg.update_core(return_data['data'])
# core_detected = True
#
# if not core_detected:
# cfg.update_core(None)
#
# _db = get_db()
# database = '未知'
# if _db.db_source['type'] == _db.DB_TYPE_SQLITE:
# database = 'SQLite{}'.format(_db.db_source['file'])
# elif _db.db_source['type'] == _db.DB_TYPE_MYSQL:
# database = 'MySQL'
#
# param = {
# 'core': cfg.core,
# 'web': {
# 'version': TS_VER,
# 'core_server_rpc': cfg['core_server_rpc'],
# 'database': database
# }
# }
# self.render('set/info.mako', page_param=json.dumps(param))
# class DatabaseHandler(TPBaseAdminAuthHandler): class ImportDatabaseHandler(TPBaseAdminAuthHandler):
# def get(self): # TODO: 导入操作可能会比较耗时,应该分离导入和获取导入状态两个过程,在页面上可以呈现导入进度,并列出导出成功/失败的项
# _db = get_db()
# # database = '未知'
# # if _db.db_source['type'] == _db.DB_TYPE_SQLITE:
# # database = 'SQLite{}'.format(_db.db_source['file'])
# # elif _db.db_source['type'] == _db.DB_TYPE_MYSQL:
# # database = 'MySQL'
#
# param = {'db': _db.db_source}
# self.render('set/database.mako', page_param=json.dumps(param))
# def _restart_func(): @tornado.gen.coroutine
# time.sleep(1) def post(self):
# """
# PLATFORM = platform.system().lower() sql导入规则
# 以事务方式执行sql语句
# if PLATFORM == 'windows': """
# sf = os.path.join(cfg.app_path, 'tools', 'restart.bat') ret = dict()
# os.system('cmd.exe /c "{}"'.format(sf)) ret['code'] = 0
# else: ret['message'] = ''
# # sf = os.path.join(cfg.app_path, 'tools', 'restart.sh') # ret['data'] = {}
# # os.system(sf) # ret['data']['msg'] = list() # 记录跳过的行(格式不正确,或者数据重复等)
# os.system('service eom_ts restart') sql_filename = ''
#
# # os.system(sf)
try:
upload_path = os.path.join(cfg.data_path, 'tmp') # 文件的暂存路径
if not os.path.exists(upload_path):
os.mkdir(upload_path)
file_metas = self.request.files['sqlfile'] # 提取表单中namefile的文件元数据
for meta in file_metas:
now = time.localtime(time.time())
tmp_name = 'upload-{:04d}{:02d}{:02d}{:02d}{:02d}{:02d}.sql'.format(now.tm_year, now.tm_mon, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec)
sql_filename = os.path.join(upload_path, tmp_name)
with open(sql_filename, 'wb') as f:
f.write(meta['body'])
# def restart_service(): # file encode maybe utf8 or gbk... check it out.
# # todo: 使用eom_ts.exe运行脚本的方式新进程来重启服务避免正在运行的本服务未退出的影响 file_encode = None
# with open(sql_filename, encoding='utf8') as f:
# t = threading.Thread(target=_restart_func) try:
# t.start() f.readlines()
# file_encode = 'utf8'
except:
pass
# class UpdateConfig(TPBaseAdminAuthJsonHandler): if file_encode is None:
# def post(self): os.remove(sql_filename)
# args = self.get_argument('args', None) log.e('file `{}` unknown encode, neither GBK nor UTF8.\n'.format(sql_filename))
# if args is not None: ret['code'] = -2
# args = json.loads(args) ret['message'] = 'upload sql file is not utf8 encode.'
# else: return self.write(json.dumps(ret).encode('utf8'))
# self.write_json(-1)
# return
#
# change_list = args['cfg']
# reboot = args['reboot']
#
# try:
# ret = set.set_config(change_list)
# if ret:
# for i in range(len(change_list)):
# if change_list[i]['name'] == 'ts_server_ip':
# # static_path = cfg.static_path
# var_js = os.path.join(cfg.static_path, 'js', 'var.js')
# f = None
# try:
# f = open(var_js, 'w')
# # config_list = host.get_config_list()
# # ts_server = dict()
# # ts_server['ip'] = config_list['ts_server_ip']
# # ts_server['ssh_port'] = config_list['ts_server_ssh_port']
# # ts_server['rdp_port'] = config_list['ts_server_rdp_port']
# # f.write("\"use strict\";\nvar teleport_ip = \"{}\";\n".format(ts_server['ip']))
# f.write("\"use strict\";\nvar teleport_ip = \"{}\";\n".format(change_list[i]['value']))
# break
# except Exception:
# return self.write(-1)
# finally:
# if f is not None:
# f.close()
#
# if reboot:
# restart_service()
#
# self.write_json(0)
# else:
# self.write_json(-1)
# except:
# self.write_json(-2)
# class OsOperator(TPBaseUserAuthJsonHandler): with open(sql_filename, encoding=file_encode) as f:
# def post(self): lines = f.readlines()
# args = self.get_argument('args', None) for line in lines:
# if args is not None: print(line)
# args = json.loads(args) pass
# else:
# self.write_json(-1) ret['code'] = 0
# return return self.write(json.dumps(ret).encode('utf8'))
# _OP = int(args['OP']) except:
# try: log.e('error\n')
# if _OP == 1: ret['code'] = -6
# os.system('reboot') ret['message'] = '发生异常.'
# else: return self.write(json.dumps(ret).encode('utf8'))
# os.system('shutdown -h now')
# # 重新启动 finally:
# self.write_json(0) if os.path.exists(sql_filename):
# except: os.remove(sql_filename)
# self.write_json(-2)
#

View File

@ -4,8 +4,10 @@ ywl.on_init = function (cb_stack, cb_args) {
console.log(ywl.page_options); console.log(ywl.page_options);
var dom = { var dom = {
info: $('#info-kv') info: $('#info-kv'),
// , btn_maintance: $('#btn_maintenance') // , btn_maintance: $('#btn_maintenance')
btn_db_export: $('#btn-db-export'),
btn_db_import: $('#btn-db-import'),
}; };
var html = []; var html = [];
@ -66,9 +68,79 @@ ywl.on_init = function (cb_stack, cb_args) {
// }); // });
// }); // });
// //
dom.btn_db_export.click(function () {
alert('not implement.');
window.location.href = '/config/export-database'
});
dom.btn_db_import.click(function () {
alert('not implement.');
var _fn_sure = function (cb_stack, cb_args) {
var html = '<input id="upload-file" type="file" name="sqlfile" class="hidden" value="" style="display: none;"/>';
dom.btn_db_import.after($(html));
var update_file = $("#upload-file");
update_file.change(function () {
var file_path = $(this).val();
if (file_path === null || file_path === undefined || file_path === '') {
return;
}
ywl.do_upload_sql_file();
});
update_file.trigger('click');
};
var cb_stack = CALLBACK_STACK.create();
ywl.dlg_confirm(cb_stack, {
msg: '<p><strong>注意:操作不可恢复!!</strong></p><p>您确定要清除所有现有数据然后导入sql文件吗</p>',
fn_yes: _fn_sure
});
});
cb_stack.exec(); cb_stack.exec();
}; };
ywl.do_upload_sql_file = function () {
var param = {};
$.ajaxFileUpload({
url: "/config/import-database",// 需要链接到服务器地址
secureuri: false,
fileElementId: "upload-file", // 文件选择框的id属性
dataType: 'text', // 服务器返回的格式可以是json
data: param,
success: function (data) {
$('#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);
}
},
error: function () {
$('#upload-file').remove();
ywl.notify_error('网络故障导入sql失败');
}
});
};
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, '未能检测到');

View File

@ -8,7 +8,7 @@ ywl.on_init = function (cb_stack, cb_args) {
//=================================== //===================================
// 表格数据 // 表格数据
var disk_rate = 0; var disk_rate = 0;
if(0 == ywl.page_options.total_size) { if(0 === ywl.page_options.total_size) {
$('#disk-status').text('未能获取到录像文件所在磁盘空间信息'); $('#disk-status').text('未能获取到录像文件所在磁盘空间信息');
} else { } else {
disk_rate = parseInt(ywl.page_options.free_size * 100 / ywl.page_options.total_size); disk_rate = parseInt(ywl.page_options.free_size * 100 / ywl.page_options.total_size);

View File

@ -19,6 +19,24 @@
<%block name="extend_css"> <%block name="extend_css">
<style type="text/css"> <style type="text/css">
.box {
padding-left: 30px;
}
h2 {
margin-left:-20px;
font-size:160%;
}
h3 {
font-size: 120%;
font-weight: bold;
}
.table {
width: auto;
}
.table .key { .table .key {
text-align: right; text-align: right;
} }
@ -35,6 +53,19 @@
.table .value .disabled { .table .value .disabled {
color: #ffa861; color: #ffa861;
} }
.db-box {
margin-bottom: 20px;
}
.notice-box {
border: 1px solid #e2cab4;
background-color: #ffe4cb;
padding: 15px;
color: #000000;
margin-bottom: 10px;
}
</style> </style>
</%block> </%block>
@ -46,14 +77,27 @@
<div class="box"> <div class="box">
<div> <div>
<h4><strong>服务器配置信息</strong></h4> <h2><strong>服务器配置信息</strong></h2>
<table id="info-kv" class="table"></table> <table id="info-kv" class="table"></table>
</div> </div>
## <div> <div>
## <h4><strong>高级设置</strong></h4> <hr/>
## <p><a href="javascript:;" id="btn_maintenance">进入维护模式</a></p> <h2><strong>数据库管理</strong></h2>
## </div>
<div class="db-box">
<h3>导出</h3>
<p>将数据库中所有数据导出到sql文件可用作备份。</p>
<button type="button" id="btn-db-export" class="btn btn-sm btn-primary"><i class="fa fa-sign-out fa-fw"></i> 导出数据库</button>
</div>
<div class="db-box">
<h3>导入</h3>
<p>清空当前数据库中所有数据然后从sql文件中导入数据到数据库中。</p>
<p class="notice-box">注意!导入操作将导致现有数据被清除且无法恢复,请谨慎使用!</p>
<button type="button" id="btn-db-import" class="btn btn-sm btn-danger"><i class="fa fa-sign-in fa-fw"></i> 导入数据库</button>
</div>
</div>
</div> </div>
<!-- end of box --> <!-- end of box -->