Merge branch 'feature/upgrade-db' into dev

hotfix/3.2.2-secure-fix
Apex Liu 2019-01-23 02:38:22 +08:00
commit 2414d143ff
8 changed files with 610 additions and 184 deletions

View File

@ -1060,6 +1060,8 @@ def disk_io_counters(perdisk=False):
# ...unless (Linux 2.6) the line refers to a partition instead
# of a disk, in which case the line has less fields (7):
# "3 1 hda1 8 8 8 8"
# 4.18+ has 4 fields added:
# "3 0 hda 8 8 8 8 8 8 8 8 8 8 8 0 0 0 0"
# See:
# https://www.kernel.org/doc/Documentation/iostats.txt
# https://www.kernel.org/doc/Documentation/ABI/testing/procfs-diskstats
@ -1074,7 +1076,7 @@ def disk_io_counters(perdisk=False):
reads = int(fields[2])
(reads_merged, rbytes, rtime, writes, writes_merged,
wbytes, wtime, _, busy_time, _) = map(int, fields[4:14])
elif flen == 14:
elif flen == 14 or flen == 18:
# Linux 2.6+, line referring to a disk
name = fields[2]
(reads, reads_merged, rbytes, rtime, writes, writes_merged,

View File

@ -0,0 +1,317 @@
"use strict";
$app.on_init = function (cb_stack, cb_args) {
$app.dom = {
btn_upgrade: $('#btn-upgrade'),
steps_detail: $('#steps-detail'),
// db_info: $('#db-info'),
// account: $('#sysadmin-account'),
// email: $('#sysadmin-email'),
// password: $('#password'),
// password2: $('#password-again'),
message: $('#message'),
step2: $('#step2')
};
$app._make_info = function (key, value) {
return '<tr><td class="key">' + key + '</td><td class="value">' + value + '</td></tr>';
};
// var html = [];
// if ($app.options.db.type === DB_TYPE_SQLITE) {
// html.push($app._make_info('数据库类型', 'SQLite'));
// html.push($app._make_info('数据库文件', $app.options.db.sqlite_file));
// } else if ($app.options.db.type === DB_TYPE_MYSQL) {
// html.push($app._make_info('数据库类型', 'MySQL'));
// html.push($app._make_info('MySQL主机', $app.options.db.mysql_host));
// html.push($app._make_info('MySQL端口', $app.options.db.mysql_port));
// html.push($app._make_info('数据库名称', $app.options.db.mysql_db));
// html.push($app._make_info('用户名', $app.options.db.mysql_user));
//
// var _t = [];
// _t.push('<div class="alert alert-warning">');
// _t.push('<i class="fas fa-exclamation-triangle"></i> 注意请确保您在执行后续创建操作之前已经在MySQL中使用 <span class="bold">UTF8字符集</span> 创建了库“');
// _t.push($app.options.db.mysql_db);
// _t.push('”,并且用户“');
// _t.push($app.options.db.mysql_user);
// _t.push('”拥有在此库创建表的权限!');
// _t.push('</div>');
// $app.dom.db_info.after(_t.join(''));
// } else {
// html.push($app._make_info('数据库类型', '<span class="error">未知的数据库类型,请检查您的配置文件!</span>'));
// $app.dom.btn_upgrade.attr('disabled', 'disabled').hide();
// }
// $app.dom.db_info.append(html.join(''));
$app.hide_op_box = function () {
$app.dom.message.hide();
};
$app.show_op_box = function (op_type, op_msg) {
$app.dom.message.html(op_msg);
$app.dom.message.removeClass().addClass('op_box op_' + op_type);
$app.dom.message.show();
};
$app.dom.btn_upgrade.click(function () {
// var str_account = $app.dom.account.val();
// var str_email = $app.dom.email.val();
// var str_password = $app.dom.password.val();
// var str_password2 = $app.dom.password2.val();
//
// if (str_account.length === 0) {
// $app.show_op_box('error', '请填写系统管理员登录账号名称!');
// $app.dom.account.focus();
// return;
// }
// if (str_email.length === 0) {
// $app.show_op_box('error', '请填写系统管理员的电子邮件地址!');
// $app.dom.email.focus();
// return;
// }
// if (!tp_is_email(str_email)) {
// $app.show_op_box('error', '电子邮件地址格式错啦,你会收不到邮件的!');
// $app.dom.email.focus();
// return;
// }
// if (str_password.length === 0) {
// $app.show_op_box('error', '请设置系统管理员登录密码!');
// $app.dom.password.focus();
// return;
// }
// if (str_password2.length === 0) {
// $app.show_op_box('error', '请再次输入系统管理员登录密码!');
// $app.dom.password.focus();
// return;
// }
// if (str_password !== str_password2) {
// $app.show_op_box('error', '两次输入的密码不一致!');
// $app.dom.password2.focus().select();
// return;
// }
$app.dom.btn_upgrade.attr('disabled', 'disabled').hide();
$app.hide_op_box();
$app.dom.steps_detail.show();
$tp.ajax_post_json('/maintenance/rpc', {cmd: 'upgrade_db'},
function (ret) {
if (ret.code === TPE_OK) {
var cb_stack = CALLBACK_STACK.create();
cb_stack
.add_delay(500, $app.get_task_ret, {task_id: ret.data.task_id})
.exec();
}
},
function () {
// $app.show_message('error', '无法连接到服务器!');
$app.show_op_box('error', '无法连接到服务器!');
}
);
});
$app.get_task_ret = function (cb_stack, cb_args) {
var task_id = cb_args.task_id || 0;
if (task_id === 0) {
console.log('task-id', task_id);
return;
}
$tp.ajax_post_json('/maintenance/rpc', {cmd: 'get_task_ret', 'tid': task_id},
function (ret) {
if (ret.code === TPE_OK) {
// show step progress.
var all_ok = true;
var steps = ret.data.steps;
$app.dom.steps_detail.empty();
var html = [];
var icon_class = '';
var err_class = '';
for (var i = 0; i < steps.length; ++i) {
if (steps[i].stat === 0)
icon_class = 'fa-check';
else
icon_class = 'fa-cog fa-spin';
if (steps[i].code !== 0) {
icon_class = 'fa-exclamation-circle';
err_class = ' class="error"';
steps[i].msg += ' 失败!';
all_ok = false;
}
else {
err_class = '';
}
html.push('<p');
html.push(err_class);
html.push('><i class="fa ');
html.push(icon_class);
html.push('"></i> ');
html.push(steps[i].msg);
html.push('</p>')
}
$app.dom.steps_detail.html(html.join(''));
$('html').animate({scrollTop: $(document).height()}, 300);
if (!ret.data.running) {
if (all_ok) {
$tp.ajax_post_json('/auth/do-logout', {},
function () {
},
function () {
}
);
$app.dom.step2.show('fast', function () {
// 确保页面滚动到最低端,使得下一步提示能够被看到。
$('html').animate({scrollTop: $(document).height()}, 300);
});
}
return;
}
cb_stack
.add_delay(500, $app.get_task_ret, {task_id: task_id})
.exec();
}
},
function () {
$app.show_op_box('error', '无法连接到服务器!');
}
);
};
cb_stack.exec();
};
ywl.on_init = function (cb_stack, cb_args) {
ywl.dom = {
btn_upgrade_db: $('#btn-upgrade-db'),
steps_detail: $('#steps-detail')
};
ywl.dom.btn_upgrade_db.click(function () {
ywl.dom.btn_upgrade_db.attr('disabled', 'disabled').hide();
ywl.dom.steps_detail.show();
console.log('upgrade-db-click');
ywl.ajax_post_json('/maintenance/rpc', {cmd: 'upgrade_db'},
function (ret) {
console.log('upgrade-db:', ret);
if (ret.code === 0) {
var cb_stack = CALLBACK_STACK.create();
cb_stack
.add(ywl.get_task_ret, {task_id: ret.data.task_id})
.add(ywl.delay_exec, {delay_ms: 500})
.exec();
}
},
function () {
ywl.show_message('error', '无法连接到服务器!');
}
);
});
ywl.get_task_ret = function (cb_stack, cb_args) {
var task_id = cb_args.task_id || 0;
if (task_id === 0) {
console.log('task-id', task_id);
return;
}
ywl.ajax_post_json('/maintenance/rpc', {cmd: 'get_task_ret', 'tid': task_id},
function (ret) {
console.log('get_task_ret:', ret);
if (ret.code === 0) {
// show step progress.
var steps = ret.data.steps;
ywl.dom.steps_detail.empty();
var html = [];
var icon_class = '';
var err_class = '';
for(var i = 0; i < steps.length; ++i) {
if(steps[i].code !== 0) {
err_class = ' class="error"';
icon_class = 'fa-times-circle';
}
else {
err_class = '';
icon_class = 'fa-check';
}
if(steps[i].stat === 0)
;//icon_class = 'fa-check';
else
icon_class = 'fa-cog fa-spin';
html.push('<p');
html.push(err_class);
html.push('><i class="fa ');
html.push(icon_class);
html.push('"></i> ');
html.push(steps[i].msg);
html.push('</p>')
}
ywl.dom.steps_detail.html(html.join(''));
if (!ret.data.running) {
$('#step2').show('fast');
return;
}
cb_stack
.add(ywl.get_task_ret, {task_id: task_id})
.add(ywl.delay_exec, {delay_ms: 500})
.exec();
}
},
function () {
ywl.show_message('error', '无法连接到服务器!');
}
);
};
cb_stack.exec();
};

View File

@ -1,180 +1,43 @@
<%!
import app.app_ver as app_ver
page_title_ = '升级TELEPORT服务'
%>
<%inherit file="../page_maintenance_base.mako"/>
<%block name="breadcrumb">
<%inherit file="../page_single_base.mako"/>
<%block name="extend_js_file">
<script type="text/javascript" src="${ static_url('js/maintenance/upgrade.js') }"></script>
</%block>
<%block name="page_header">
<div class="container-fluid top-navbar">
<div class="brand"><a href="/" target="_blank"><span class="site-logo"></span></a></div>
<div class="breadcrumb-container">
<ol class="breadcrumb">
<li><i class="fa fa-cog fa-fw"></i> ${self.attr.page_title_}</li>
</ol>
</div>
</div>
</%block>
<%block name="embed_css">
<style type="text/css">
.container {
background-color: #fff;
padding-bottom: 20px;
}
h1 {
font-size: 200%;
}
h2 {
font-size: 160%;
}
.steps-detail {
display: none;
margin:10px;
padding:10px;
border:1px solid #b4b4b4;
background-color: #dcdcdc;
}
.steps-detail p {
padding-left:5px;
margin:2px 0 2px 1px;
}
.steps-detail p.error {
color:#ffffff;
margin:2px 0 2px 0;
background-color: #cc3632;
border:1px solid #9c2a26;
}
</style>
</%block>
## Begin Main Body.
<div class="page-content">
<div class="content-box">
<p class="welcome-message"><i class="fa fa-heart"></i> <span>欢迎升级到 TELEPORT v${app_ver.TP_SERVER_VER} 社区版!现在还剩下一点点操作需要执行!</span></p>
<div class="content_box">
<div class="container">
<h1>升级TELEPORT服务</h1>
<hr/>
<h2>第一步:升级数据库</h2>
<div>
<div>
<button id="btn-upgrade-db" type="button" class="btn btn-primary"><i class="fa fa-wrench fa-fw"></i> 开始升级</button>
</div>
<h2><i class="fa fa-chevron-right"></i> 第一步:升级数据库</h2>
<button id="btn-upgrade" type="button" class="btn btn-primary"><i class="fa fa-wrench fa-fw"></i> 执行</button>
<div id="steps-detail" class="steps-detail"></div>
</div>
<div><p id="message" class="op_box" style="display:none;"></p></div>
<div id="step2" style="display:none;">
<hr/>
<h2>已完成!</h2>
<p>是的没有第二步了升级操作已经完成了刷新页面即可进入Teleport主界面啦~~</p>
<h2><i class="fa fa-chevron-right"></i> 已完成!</h2>
<p>是的,没有第二步啦,升级已经完成!刷新页面即可登录 TELEPORT 啦~~</p>
</div>
</div>
</div>
</div>
<%block name="embed_js">
<script type="text/javascript">
"use strict";
ywl.on_init = function (cb_stack, cb_args) {
ywl.dom = {
btn_upgrade_db: $('#btn-upgrade-db'),
steps_detail: $('#steps-detail')
};
ywl.dom.btn_upgrade_db.click(function () {
ywl.dom.btn_upgrade_db.attr('disabled', 'disabled').hide();
ywl.dom.steps_detail.show();
console.log('upgrade-db-click');
ywl.ajax_post_json('/maintenance/rpc', {cmd: 'upgrade_db'},
function (ret) {
console.log('upgrade-db:', ret);
if (ret.code === 0) {
var cb_stack = CALLBACK_STACK.create();
cb_stack
.add(ywl.get_task_ret, {task_id: ret.data.task_id})
.add(ywl.delay_exec, {delay_ms: 500})
.exec();
}
},
function () {
ywl.show_message('error', '无法连接到服务器!');
}
);
});
ywl.get_task_ret = function (cb_stack, cb_args) {
var task_id = cb_args.task_id || 0;
if (task_id === 0) {
console.log('task-id', task_id);
return;
}
ywl.ajax_post_json('/maintenance/rpc', {cmd: 'get_task_ret', 'tid': task_id},
function (ret) {
console.log('get_task_ret:', ret);
if (ret.code === 0) {
// show step progress.
var steps = ret.data.steps;
ywl.dom.steps_detail.empty();
var html = [];
var icon_class = '';
var err_class = '';
for(var i = 0; i < steps.length; ++i) {
if(steps[i].code !== 0) {
err_class = ' class="error"';
icon_class = 'fa-times-circle';
}
else {
err_class = '';
icon_class = 'fa-check';
}
if(steps[i].stat === 0)
;//icon_class = 'fa-check';
else
icon_class = 'fa-cog fa-spin';
html.push('<p');
html.push(err_class);
html.push('><i class="fa ');
html.push(icon_class);
html.push('"></i> ');
html.push(steps[i].msg);
html.push('</p>')
}
ywl.dom.steps_detail.html(html.join(''));
if (!ret.data.running) {
$('#step2').show('fast');
return;
}
cb_stack
.add(ywl.get_task_ret, {task_id: task_id})
.add(ywl.delay_exec, {delay_ms: 500})
.exec();
}
},
function () {
ywl.show_message('error', '无法连接到服务器!');
}
);
};
cb_stack.exec();
};
</script>
</%block>

View File

@ -82,6 +82,7 @@ class DatabaseInit:
def _create_core_server(self):
""" 核心服务(为分布式准备)
v7 新增
特别注意分布式部署时核心服务的RPC通讯端口仅允许来自web服务的IP访问
"""
@ -152,7 +153,7 @@ class DatabaseInit:
f.append('`surname` varchar(64) DEFAULT ""')
# type 1=本地账号2=LDAP待扩展
f.append('`type` int(11) DEFAULT 1')
# ldap_dn: 用户的ldap全路径名称仅用于LDAP导入的用户
# ldap_dn: 用户的ldap全路径名称仅用于LDAP导入的用户v7版新增
f.append('`ldap_dn` varchar(128) DEFAULT ""')
# avatar: 用户头像图片地址
f.append('`avatar` varchar(64) DEFAULT ""')
@ -186,6 +187,11 @@ class DatabaseInit:
# last_ip: 最近一次成功登录IP
f.append('`last_ip` varchar(40) DEFAULT ""')
# valid_from: 有效期起始时间为0则不限v7版新增
f.append('`valid_from` int(11) DEFAULT 0')
# valid_to: 有效期终止时间为0则不限v7版新增
f.append('`valid_to` int(11) DEFAULT 0')
# creator_id: 创建者的用户id0=系统默认创建
f.append('`creator_id` int(11) DEFAULT 0')
# create_time: 创建时间
@ -321,11 +327,11 @@ class DatabaseInit:
# 下面三个主机相关字段用于显示注意更新host表时同步更新此字段
# host_ip: 主机IP地址
# host_ip: 主机IP地址v7版新增
f.append('`host_ip` varchar(40) NOT NULL')
# router_ip: 路由IP
# router_ip: 路由IPv7版新增
f.append('`router_ip` varchar(40) DEFAULT ""')
# router_port: 路由端口
# router_port: 路由端口v7版新增
f.append('`router_port` int(11) DEFAULT 0')
# protocol_type: 协议类型0=1=SSH2=RDP3=TELNET
@ -737,13 +743,13 @@ class DatabaseInit:
# id: 自增主键
f.append('`id` integer PRIMARY KEY {}'.format(self.db.auto_increment))
# core_uuid:
# core_sn:v7版新增
f.append('`core_sn` varchar(5) DEFAULT "0000"')
# flag: 是否已审查/是否要永久保留异或方式设置0=初始1=已审查2=要永久保留
f.append('`flag` int(11) DEFAULT 0')
# reason: 本次运维的原因
# reason: 本次运维的原因v7版新增
f.append('`reason` varchar(255) DEFAULT ""')
# sid: 会话ID

View File

@ -0,0 +1,223 @@
# -*- coding: utf-8 -*-
# from app.const import *
# from app.logic.auth.password import tp_password_generate_secret
# from app.base.utils import tp_timestamp_utc_now
from app.base.logger import log
# import shutil
class DatabaseUpgrade:
def __init__(self, db, step_begin, step_end):
self.db = db
self.step_begin = step_begin
self.step_end = step_end
def do_upgrade(self):
for i in range(self.db.DB_VERSION):
if self.db.current_ver < i + 1:
_f_name = '_upgrade_to_v{}'.format(i + 1)
if _f_name in dir(self):
if self.__getattribute__(_f_name)():
self.db.current_ver = i + 1
else:
return False
return True
def _db_exec(self, msg, sql):
_step = self.step_begin(msg)
ret = False
if type(sql) == str:
ret = self.db.exec(sql)
elif type(sql) == list or type(sql) == set:
for s in sql:
ret = self.db.exec(s)
if not ret:
break
else:
raise RuntimeError('[FAILED] internal error.')
if not ret:
self.step_end(_step, -1)
raise RuntimeError('[FAILED] {}'.format(sql))
else:
self.step_end(_step, 0)
def _upgrade_to_v7(self):
# 注意v2.x的最后版本时数据库版本号为v6但是v3.0.0技术预览版未升级数据库版本号仍然为v6
# 因此升级时要做检查如果是当前数据库版本号为v6要进一步判断是否为v2.x系列的数据库。
# 服务端升级到v3.2.2时,数据库有部分调整
_step = self.step_begin('检查数据库版本 v7...')
try:
# 检查是否是 v2.x 版本的数据库也是v6版数据库
# 依据为v3.x的服务端开始数据库中有 tp_role 数据表。
ret = self.db.is_table_exists('{}role'.format(self.db.table_prefix))
if ret is None:
self.step_end(_step, -1, '无法连接到数据库')
return False
elif not ret:
self.step_end(_step, -1, '抱歉不支持从v2.x升级到v3.x数据库不兼容请卸载旧版本全新安装新版本')
return True
except:
log.e('failed.\n')
self.step_end(_step, -1)
return False
self.step_end(_step, 0, '需要升级')
try:
# 1. 创建缺失的 core_server 表
_step = self.step_begin(' - 检查 core_server 数据表...')
ret = self.db.is_table_exists('{}core_server'.format(self.db.table_prefix))
if ret is None:
self.step_end(_step, -1, '无法连接到数据库')
return False
elif not ret:
_step = self.step_begin(' - 创建数据表 core_server...')
self._v7_create_core_server()
self._db_exec(
' - 设置本机核心服务配置项...',
'INSERT INTO `{}core_server` (`sn`, `secret`, `ip`, `port`, `state`) VALUES '
'("0000", "", "127.0.0.1", 52080, 1);'
''.format(self.db.table_prefix)
)
self.step_end(_step, 0)
# 2. 检查 user 表中是否有 ldap_dn/valid_from/valid_to 字段
_step = self.step_begin(' - 检查 user 数据表 ldap_dn 字段...')
ret = self.db.is_field_exists('{}user'.format(self.db.table_prefix), 'ldap_dn')
if ret is None:
self.step_end(_step, -1, '无法连接到数据库')
return False
elif not ret:
if not self.db.exec('ALTER TABLE `{}user` ADD `ldap_dn` VARCHAR(128) DEFAULT ""'.format(self.db.table_prefix)):
self.step_end(_step, -1, '失败')
return False
else:
self.step_end(_step, 0)
_step = self.step_begin(' - 检查 user 数据表 valid_from 字段...')
ret = self.db.is_field_exists('{}user'.format(self.db.table_prefix), 'valid_from')
if ret is None:
self.step_end(_step, -1, '无法连接到数据库')
return False
elif not ret:
if not self.db.exec('ALTER TABLE `{}user` ADD `valid_from` INT(11) DEFAULT 0'.format(self.db.table_prefix)):
self.step_end(_step, -1, '失败')
return False
else:
self.step_end(_step, 0)
_step = self.step_begin(' - 检查 user 数据表 valid_to 字段...')
ret = self.db.is_field_exists('{}user'.format(self.db.table_prefix), 'valid_to')
if ret is None:
self.step_end(_step, -1, '无法连接到数据库')
return False
elif not ret:
if not self.db.exec('ALTER TABLE `{}user` ADD `valid_to` INT(11) DEFAULT 0'.format(self.db.table_prefix)):
self.step_end(_step, -1, '失败')
return False
else:
self.step_end(_step, 0)
# 3. 检查 acc 表中是否有 host_ip/router_ip/router_port 字段
_step = self.step_begin(' - 检查 acc 数据表 host_ip 字段...')
ret = self.db.is_field_exists('{}acc'.format(self.db.table_prefix), 'host_ip')
if ret is None:
self.step_end(_step, -1, '无法连接到数据库')
return False
elif not ret:
if not self.db.exec('ALTER TABLE `{}acc` ADD `host_ip` VARCHAR(40) DEFAULT ""'.format(self.db.table_prefix)):
self.step_end(_step, -1, '失败')
return False
self.step_end(_step, 0)
_step = self.step_begin(' - 检查 acc 数据表 router_ip 字段...')
ret = self.db.is_field_exists('{}acc'.format(self.db.table_prefix), 'router_ip')
if ret is None:
self.step_end(_step, -1, '无法连接到数据库')
return False
elif not ret:
if not self.db.exec('ALTER TABLE `{}acc` ADD `router_ip` VARCHAR(40) DEFAULT ""'.format(self.db.table_prefix)):
self.step_end(_step, -1, '失败')
return False
self.step_end(_step, 0)
_step = self.step_begin(' - 检查 acc 数据表 router_port 字段...')
ret = self.db.is_field_exists('{}acc'.format(self.db.table_prefix), 'router_port')
if ret is None:
self.step_end(_step, -1, '无法连接到数据库')
return False
elif not ret:
if not self.db.exec('ALTER TABLE `{}acc` ADD `router_port` INT(11) DEFAULT 0'.format(self.db.table_prefix)):
self.step_end(_step, -1, '失败')
return False
self.step_end(_step, 0)
# 4. 检查 record 表中是否有 core_sn/reason 字段
_step = self.step_begin(' - 检查 record 数据表 core_sn 字段...')
ret = self.db.is_field_exists('{}record'.format(self.db.table_prefix), 'core_sn')
if ret is None:
self.step_end(_step, -1, '无法连接到数据库')
return False
elif not ret:
if not self.db.exec('ALTER TABLE `{}record` ADD `core_sn` VARCHAR(5) DEFAULT "0000"'.format(self.db.table_prefix)):
self.step_end(_step, -1, '失败')
return False
self.step_end(_step, 0)
_step = self.step_begin(' - 检查 record 数据表 reason 字段...')
ret = self.db.is_field_exists('{}record'.format(self.db.table_prefix), 'reason')
if ret is None:
self.step_end(_step, -1, '无法连接到数据库')
return False
elif not ret:
if not self.db.exec('ALTER TABLE `{}record` ADD `reason` VARCHAR(255) DEFAULT ""'.format(self.db.table_prefix)):
self.step_end(_step, -1, '失败')
return False
self.step_end(_step, 0)
_step = self.step_begin(' - 更新数据库版本号...')
if not self.db.exec('UPDATE `{}config` SET `value`="7" WHERE `name`="db_ver";'.format(self.db.table_prefix)):
self.step_end(_step, -1, '无法更新数据库版本号')
return False
self.step_end(_step, 0)
_step = self.step_begin('升级到 v7 完成')
self.step_end(_step, 0)
return True
except:
log.e('failed.\n')
self.step_end(_step, -1)
return False
def _v7_create_core_server(self):
""" 核心服务(为分布式准备)
v7 新增
特别注意分布式部署时核心服务的RPC通讯端口仅允许来自web服务的IP访问
"""
f = list()
# id: 自增主键
f.append('`id` integer PRIMARY KEY {}'.format(self.db.auto_increment))
# sn: 核心服务主机编号4位数字构成的字符串全0表示运行在与web服务同一台主机上
f.append('`sn` varchar(5) NOT NULL')
# desc: 核心服务主机描述
f.append('`desc` varchar(255) DEFAULT ""')
# secret: 核心服务主机密钥核心服务主机需要配置此密钥才能连接web服务
f.append('`secret` varchar(64) DEFAULT ""')
# ip: 核心服务主机的RPC服务IP和端口用于合成RPC访问地址例如 http://127.0.0.1:52080/rpc
f.append('`ip` varchar(128) NOT NULL')
f.append('`port` int(11) DEFAULT 0')
# state: 状态1=正常2=禁用3=离线4=重启中5=版本不匹配
f.append('`state` int(3) DEFAULT 1')
self._db_exec(
' - 创建核心服务器表...',
'CREATE TABLE `{}core_server` ({});'.format(self.db.table_prefix, ','.join(f))
)

View File

@ -12,7 +12,7 @@ from app.base.configs import tp_cfg
from app.base.utils import AttrDict, tp_make_dir
from app.base.logger import log
from .database.create import DatabaseInit
# from .database.upgrade import DatabaseUpgrade
from .database.upgrade import DatabaseUpgrade
from .database.export import export_database
__all__ = ['get_db', 'SQL']
@ -23,7 +23,8 @@ __all__ = ['get_db', 'SQL']
class TPDatabase:
# 注意,每次调整数据库结构,必须增加版本号,并且在升级接口中编写对应的升级操作
DB_VERSION = 6
# 20190123: server-v3.2.2, db-v7
DB_VERSION = 7
DB_TYPE_UNKNOWN = 0
DB_TYPE_SQLITE = 1
@ -267,15 +268,15 @@ class TPDatabase:
log.e('database create and initialize failed.\n')
return False
# def upgrade_database(self, step_begin, step_end):
# log.v('start database upgrade process.\n')
# if DatabaseUpgrade(self, step_begin, step_end).do_upgrade():
# log.v('database upgraded.\n')
# self.need_upgrade = False
# return True
# else:
# log.e('database upgrade failed.\n')
# return False
def upgrade_database(self, step_begin, step_end):
log.v('start database upgrade process.\n')
if DatabaseUpgrade(self, step_begin, step_end).do_upgrade():
log.v('database upgraded.\n')
self.need_upgrade = False
return True
else:
log.e('database upgrade failed.\n')
return False
def alter_table(self, table_names, field_names=None):
"""

View File

@ -276,7 +276,7 @@ controllers = [
# - 初始安装设置(新安装,未创建数据库时自动跳转到此页面)
(r'/maintenance/install', maintenance.InstallHandler),
# - 升级(数据库版本发生变化时跳转到此页面)
# (r'/maintenance/upgrade', maintenance.UpgradeHandler),
(r'/maintenance/upgrade', maintenance.UpgradeHandler),
# - [json] 维护过程中页面与后台的通讯接口
(r'/maintenance/rpc', maintenance.RpcHandler),

View File

@ -17,8 +17,8 @@ class LoginHandler(TPBaseHandler):
if tp_cfg().app_mode == APP_MODE_MAINTENANCE and get_db().need_create:
_user = {
'id': 0,
'username': 'installer',
'surname': '安装程序',
'username': 'maintainer',
'surname': '系统维护-安装',
'role_id': 0,
'role': '',
'privilege': TP_PRIVILEGE_SYS_CONFIG,
@ -28,6 +28,20 @@ class LoginHandler(TPBaseHandler):
self.redirect('/maintenance/install')
return
if tp_cfg().app_mode == APP_MODE_MAINTENANCE and get_db().need_upgrade:
_user = {
'id': 0,
'username': 'maintainer',
'surname': '系统维护-升级',
'role_id': 0,
'role': '',
'privilege': TP_PRIVILEGE_SYS_CONFIG,
'_is_login': True
}
self.set_session('user', _user)
self.redirect('/maintenance/upgrade')
return
_user = self.get_current_user()
_ref = quote(self.get_argument('ref', '/'))