From c0bfcd2226d08cc36416a2d5408541b40f502989 Mon Sep 17 00:00:00 2001 From: Apex Liu Date: Mon, 27 Nov 2017 18:54:10 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E4=BF=AE=E6=AD=A3=E6=89=B9=E9=87=8F?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=E6=A8=A1=E6=9D=BF=E5=9C=A8excel=E4=B8=AD?= =?UTF-8?q?=E6=89=93=E5=BC=80=E6=98=AF=E4=B9=B1=E7=A0=81=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98=EF=BC=88=E5=BF=85=E9=A1=BB=E4=BD=BF=E7=94=A8utf8-BOM?= =?UTF-8?q?=EF=BC=89=EF=BC=9B2.=20dashboard=E9=A1=B5=E9=9D=A2=E5=8F=AF?= =?UTF-8?q?=E4=BB=A5=E6=98=BE=E7=A4=BA=E5=9F=BA=E6=9C=AC=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E6=95=B0=E9=87=8F=E4=BA=86=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + build/builder/build-installer.py | 4 + build/builder/core/utils.py | 11 + .../download/teleport-example-asset.csv | 13 +- .../static/download/teleport-example-user.csv | 12 +- .../teleport/static/js/dashboard/dashboard.js | 42 ++ server/www/teleport/view/dashboard/index.mako | 14 +- server/www/teleport/view/system/config.mako | 2 +- server/www/teleport/webroot/app/base/db.py | 24 +- .../webroot/app/controller/__init__.py | 2 + .../webroot/app/controller/dashboard.py | 22 +- .../teleport/webroot/app/controller/host.py | 632 +----------------- .../teleport/webroot/app/controller/user.py | 5 +- server/www/teleport/webroot/app/model/host.py | 22 +- server/www/teleport/webroot/app/model/stat.py | 88 +++ 15 files changed, 225 insertions(+), 669 deletions(-) create mode 100644 server/www/teleport/static/js/dashboard/dashboard.js create mode 100644 server/www/teleport/webroot/app/model/stat.py diff --git a/.gitignore b/.gitignore index 8098c97..657852c 100644 --- a/.gitignore +++ b/.gitignore @@ -93,3 +93,4 @@ build/* xcuserdata profile *.moved-aside +/server/share/tmp diff --git a/build/builder/build-installer.py b/build/builder/build-installer.py index 70789cc..f332791 100644 --- a/build/builder/build-installer.py +++ b/build/builder/build-installer.py @@ -122,6 +122,10 @@ class BuilderLinux(BuilderBase): utils.copy_file(os.path.join(env.root_path, 'server', 'share', 'etc'), os.path.join(self.path_tmp_data, 'tmp', 'etc'), ('core.ini.in', 'core.ini')) utils.copy_file(os.path.join(env.root_path, 'server', 'share', 'etc'), os.path.join(self.path_tmp_data, 'tmp', 'etc'), 'tp_ssh_server.key') + # fix new line flag + utils.fix_new_line_flag(os.path.join(self.path_tmp_data, 'tmp', 'etc', 'web.ini')) + utils.fix_new_line_flag(os.path.join(self.path_tmp_data, 'tmp', 'etc', 'core.ini')) + # out_path = os.path.join(env.root_path, 'out', 'eom_ts', ctx.target_path, ctx.dist_path) # out_path = os.path.join(env.root_path, 'out', 'eom_ts', ctx.bits_path, 'bin') # bin_path = os.path.join(self.tmp_path, 'bin') diff --git a/build/builder/core/utils.py b/build/builder/core/utils.py index 5ddd8e6..0866dbe 100644 --- a/build/builder/core/utils.py +++ b/build/builder/core/utils.py @@ -355,6 +355,17 @@ def strip(filename): return True +def fix_new_line_flag(filename): + cc.n('fix new line flag to CR for text file', filename) + if not os.path.exists(filename): + return False + cmd = 'dos2unix {}'.format(filename) + ret, _ = sys_exec(cmd, direct_output=True) + if ret != 0: + raise RuntimeError('failed to dos2unix file [{}], ret={}.'.format(filename, ret)) + return True + + def make_zip(src_path, to_file, from_parent=True): cc.v('compress folder into .zip...') diff --git a/server/www/teleport/static/download/teleport-example-asset.csv b/server/www/teleport/static/download/teleport-example-asset.csv index 42c0bb1..98355c8 100644 --- a/server/www/teleport/static/download/teleport-example-asset.csv +++ b/server/www/teleport/static/download/teleport-example-asset.csv @@ -1,5 +1,8 @@ -#用户账号,用户姓名,登录认证方式,EMail,Mobile,QQ,微信,所属组,描述 -zhangsan,张三,1,zhangsan@domain.tld,,12345678,112233,运维人员|审计员, -lisi,李四,1,lisi@domain.tld,,,,审计员, -wangwu,王五,1,wangwu@domain.tld,,,,, -bai.lee,李白,1,bai.lee@domain.tld,,10086,bai.lee,审计管理员,著名诗人、剑客 +#IP,操作系统类型(linux/win),名称,路由IP,路由端口,资产编号,账号,协议类型(ssh/rdp/telnet),协议端口,认证类型(no/pw/key),密码或私钥,账号提示(仅telnet),密码提示(仅telnet),分组,描述 +1.2.3.4,linux,数据库,,,DB-0453,,,,,,,,数据库|阿里云-天津机房, +,,,,,,root,ssh,22,pw,abcd1234,,,管理员, +,,,,,,test,ssh,22,pw,abcd1234,,,测试|部署, +1.2.3.5,windows,,192.168.0.5,2054,,,,,,,,,,阿里云,天津机房\naS2n129m +,,,,,,administrator,rdp,,pw,abcd1234,,,管理员, +1.2.3.6,linux,,,,,,,,,,,,, +,,,,,,root,ssh,22,key,abcd1234,,,管理员, diff --git a/server/www/teleport/static/download/teleport-example-user.csv b/server/www/teleport/static/download/teleport-example-user.csv index 7a0f310..b89f003 100644 --- a/server/www/teleport/static/download/teleport-example-user.csv +++ b/server/www/teleport/static/download/teleport-example-user.csv @@ -1,6 +1,6 @@ -#用户账号示例文件,使用CSV格式,每行一个用户,用英文逗号分隔,共8个字段,需要7个英文逗号,,,,,,, -#用户账号,用户姓名,EMail,Mobile,QQ,微信,所属组,描述 -zhangsan,张三,zhangsan@domain.tld,,12345678,112233,运维人员|审计员, -lisi,李四,lisi@domain.tld,,,,审计员, -wangwu,,,,,,, -bai.lee,李白,bai.lee@domain.tld,,10086,bai.lee,审计管理员,著名诗人 +#用户账号示例文件,使用CSV格式,每行一个用户,用英文逗号分隔,共8个字段,需要7个英文逗号,,,,,,, +#用户账号,用户姓名,EMail,Mobile,QQ,微信,所属组,描述 +zhangsan,张三,zhangsan@domain.tld,,12345678,112233,运维人员|审计员, +lisi,李四,lisi@domain.tld,,,,审计员, +wangwu,,,,,,, +bai.lee,李白,bai.lee@domain.tld,,10086,bai.lee,审计管理员,著名诗人 diff --git a/server/www/teleport/static/js/dashboard/dashboard.js b/server/www/teleport/static/js/dashboard/dashboard.js new file mode 100644 index 0000000..5b0a9db --- /dev/null +++ b/server/www/teleport/static/js/dashboard/dashboard.js @@ -0,0 +1,42 @@ +"use strict"; + +$app.on_init = function (cb_stack) { + $app.dom = { + count_user: $('#count-user') + , count_host: $('#count-host') + , count_acc: $('#count-acc') + , count_conn: $('#count-conn') + }; + + // refresh basic info every 1m. + $app.load_basic_info(); + // refresh overload info every 5m. + $app.load_overload_info(); + + cb_stack.exec(); +}; + +$app.load_basic_info = function () { + $tp.ajax_post_json('/dashboard/do-get-basic', {}, + function (ret) { + console.log(ret); + if (ret.code === TPE_OK) { + $app.dom.count_user.text(ret.data.count_user); + $app.dom.count_host.text(ret.data.count_host); + $app.dom.count_acc.text(ret.data.count_acc); + $app.dom.count_conn.text(ret.data.count_conn); + } else { + console.log('do-get-basic failed:' + tp_error_msg(ret.code, ret.message)); + } + + }, + function () { + console.log('can not connect to server.'); + } + ); + + setTimeout($app.load_basic_info, 60*1000); +}; + +$app.load_overload_info = function () { +}; diff --git a/server/www/teleport/view/dashboard/index.mako b/server/www/teleport/view/dashboard/index.mako index 3b3551f..7d8c324 100644 --- a/server/www/teleport/view/dashboard/index.mako +++ b/server/www/teleport/view/dashboard/index.mako @@ -5,9 +5,9 @@ %> <%inherit file="../page_base.mako"/> -## <%block name="extend_js_file"> -## -## +<%block name="extend_js_file"> + + <%block name="extend_css_file"> @@ -27,7 +27,7 @@
用户
-
-
+
-
@@ -38,7 +38,7 @@
主机
-
-
+
-
@@ -49,7 +49,7 @@
主机账号
-
-
+
-
@@ -60,7 +60,7 @@
当前连接
-
-
+
-
diff --git a/server/www/teleport/view/system/config.mako b/server/www/teleport/view/system/config.mako index 1835e13..6882177 100644 --- a/server/www/teleport/view/system/config.mako +++ b/server/www/teleport/view/system/config.mako @@ -70,7 +70,7 @@ WEB会话超时 - 分钟5~1440。超过设定时长无操作,用户将被强制登出。默认为30分钟。 + 分钟5~1440。超过设定时长无操作,用户将被强制登出。默认为60分钟。 diff --git a/server/www/teleport/webroot/app/base/db.py b/server/www/teleport/webroot/app/base/db.py index 4724e29..01c66cd 100644 --- a/server/www/teleport/webroot/app/base/db.py +++ b/server/www/teleport/webroot/app/base/db.py @@ -251,15 +251,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): """ @@ -450,7 +450,7 @@ class TPMysqlPool(TPDatabasePool): def _do_connect(self): try: - return pymysql.connect(host=self._host, + conn = pymysql.connect(host=self._host, user=self._user, passwd=self._password, db=self._db_name, @@ -458,6 +458,10 @@ class TPMysqlPool(TPDatabasePool): autocommit=False, connect_timeout=3.0, charset='utf8') + err = self._do_exec(conn, 'SET SESSION sql_mode=(SELECT REPLACE(@@sql_mode,"ONLY_FULL_GROUP_BY",""));', args=()) + if err is None: + log.e('[mysql] can not disable ONLY_FULL_GROUP_BY flag.\n') + return conn except pymysql.err.OperationalError as e: errno, _ = e.args if 2003 == errno: diff --git a/server/www/teleport/webroot/app/controller/__init__.py b/server/www/teleport/webroot/app/controller/__init__.py index 751d885..23b40b2 100644 --- a/server/www/teleport/webroot/app/controller/__init__.py +++ b/server/www/teleport/webroot/app/controller/__init__.py @@ -24,6 +24,8 @@ controllers = [ # ==================================================== # - 控制台页面 (r'/dashboard', dashboard.IndexHandler), + # - [json] 获取基本信息 + (r'/dashboard/do-get-basic', dashboard.DoGetBasicHandler), # ==================================================== # 外部调用接口 diff --git a/server/www/teleport/webroot/app/controller/dashboard.py b/server/www/teleport/webroot/app/controller/dashboard.py index b3b92b2..c3e9df0 100644 --- a/server/www/teleport/webroot/app/controller/dashboard.py +++ b/server/www/teleport/webroot/app/controller/dashboard.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- from app.const import * -from app.base.controller import TPBaseHandler +from app.base.controller import TPBaseHandler, TPBaseJsonHandler +from app.model import stat class IndexHandler(TPBaseHandler): @@ -11,3 +12,22 @@ class IndexHandler(TPBaseHandler): return self.render('dashboard/index.mako') + + +class DoGetBasicHandler(TPBaseJsonHandler): + def post(self): + ret = self.check_privilege(TP_PRIVILEGE_LOGIN_WEB) + if ret != TPE_OK: + return + + err, info = stat.get_basic() + if err != TPE_OK: + return self.write_json(err) + + # ret = dict() + # ret['count_user'] = 5 + # ret['count_host'] = 5 + # ret['count_acc'] = 5 + # ret['count_conn'] = 5 + self.write_json(TPE_OK, data=info) + diff --git a/server/www/teleport/webroot/app/controller/host.py b/server/www/teleport/webroot/app/controller/host.py index e39d75f..4073296 100644 --- a/server/www/teleport/webroot/app/controller/host.py +++ b/server/www/teleport/webroot/app/controller/host.py @@ -4,6 +4,7 @@ import time import csv import os import json +import codecs import ipaddress import tornado.gen import tornado.httpclient @@ -183,7 +184,7 @@ class DoImportHandler(TPBaseHandler): # file encode maybe utf8 or gbk... check it out. file_encode = None - with open(csv_filename, encoding='gbk') as f: + with codecs.open(csv_filename, 'r', encoding='gbk') as f: try: f.readlines() file_encode = 'gbk' @@ -191,10 +192,11 @@ class DoImportHandler(TPBaseHandler): pass if file_encode is None: - with open(csv_filename, encoding='utf8') as f: + log.v('file `{}` is not gbk, try utf8\n'.format(csv_filename)) + with codecs.open(csv_filename, 'r', encoding='utf_8_sig') as f: try: f.readlines() - file_encode = 'utf8' + file_encode = 'utf_8_sig' except: pass @@ -685,627 +687,3 @@ class DoGetHostGroupWithMemberHandler(TPBaseJsonHandler): ret['total'] = total_count ret['data'] = row_data self.write_json(err, data=ret) - -# class UpdateHandler(TPBaseUserAuthJsonHandler): -# def post(self): -# args = self.get_argument('args', None) -# if args is not None: -# args = json.loads(args) -# else: -# return self.write_json(-1, '参数错误') -# -# if 'host_id' not in args or 'kv' not in args: -# self.write_json(-2, '缺少必要参数') -# -# _ret = host.update(args['host_id'], args['kv']) -# -# if _ret: -# self.write_json(0) -# else: -# self.write_json(-3, '数据库操作失败') -# -# - -# class LockHost(TPBaseUserAuthJsonHandler): -# def post(self): -# args = self.get_argument('args', None) -# if args is not None: -# args = json.loads(args) -# else: -# return self.write_json(-1, '参数错误') -# -# host_id = args['host_id'] -# lock = args['lock'] -# try: -# ret = host.lock_host(host_id, lock) -# if ret: -# return self.write_json(0) -# else: -# return self.write_json(-2, '数据库操作失败,errcode:{}'.format(ret)) -# except: -# log.e('lock host failed.\n') -# return self.write_json(-3, '发生异常') -# -# -# class DeleteHost(TPBaseUserAuthJsonHandler): -# def post(self): -# args = self.get_argument('args', None) -# if args is not None: -# args = json.loads(args) -# else: -# return self.write_json(-1, '参数错误') -# -# host_list = args['host_list'] -# try: -# ret = host.delete_host(host_list) -# if ret: -# return self.write_json(0) -# else: -# return self.write_json(-2, '数据库操作失败,errcode:{}'.format(ret)) -# except: -# log.e('delete host failed.\n') -# return self.write_json(-3, '发生异常') -# -# -# class ExportHostHandler(TPBaseAdminAuthHandler): -# def get(self): -# self.set_header('Content-Type', 'application/octet-stream') -# self.set_header('Content-Disposition', 'attachment; filename=teleport-host-export.csv') -# -# order = dict() -# order['name'] = 'host_id' -# order['asc'] = True -# limit = dict() -# limit['page_index'] = 0 -# limit['per_page'] = 999999 -# _total, _hosts = host.get_all_host_info_list(dict(), order, limit, True) -# -# self.write("分组ID, 操作系统, IP地址, 端口, 协议, 状态, 描述, 系统用户, 系统密码, 是否加密, 附加参数, 密钥ID, 认证类型\n".encode('gbk')) -# -# try: -# -# for h in _hosts: -# auth_list = h['auth_list'] -# # 分组ID, 操作系统, IP地址, 端口, 协议, 状态, 描述, 系统用户, 系统密码, 是否加密,附加参数, 密钥ID, 认证类型 -# for j in auth_list: -# row_string = '' -# # row_string = str(h['host_id']) -# # row_string += ',' -# row_string += str(h['group_id']) -# row_string += ',' -# row_string += str(h['host_sys_type']) -# row_string += ',' -# row_string += h['host_ip'] -# row_string += ',' -# row_string += str(h['host_port']) -# row_string += ',' -# row_string += str(h['protocol']) -# row_string += ',' -# row_string += str(h['host_lock']) -# row_string += ',' -# row_string += h['host_desc'] -# row_string += ',' -# -# # row_string += str(j['host_auth_id']) -# # row_string += ',' -# row_string += j['user_name'] -# row_string += ',' -# row_string += j['user_pswd'] -# row_string += ',' -# row_string += '1' -# row_string += ',' -# user_param = j['user_param'] -# if len(user_param) > 0: -# user_param = user_param.replace('\n', '\\n') -# row_string += user_param -# row_string += ',' -# row_string += str(j['cert_id']) -# row_string += ',' -# row_string += str(j['auth_mode']) -# -# self.write(row_string.encode('gbk')) -# self.write('\n') -# -# except IndexError: -# self.write('**********************************************\n'.encode('gbk')) -# self.write('!!错误!!\n'.encode('gbk')) -# self.write('导出过程中发生了错误!!\n'.encode('gbk')) -# self.write('**********************************************\n'.encode('gbk')) -# log.e('') -# -# self.finish() -# -# -# class GetCertList(TPBaseUserAuthJsonHandler): -# def post(self): -# _certs = host.get_cert_list() -# if _certs is None or len(_certs) == 0: -# return self.write_json(-1, '参数错误') -# else: -# return self.write_json(0, data=_certs) -# -# -# class AddCert(TPBaseUserAuthJsonHandler): -# @tornado.gen.coroutine -# def post(self): -# args = self.get_argument('args', None) -# if args is not None: -# args = json.loads(args) -# else: -# return self.write_json(-1, '参数错误') -# -# cert_pub = args['cert_pub'] -# cert_pri = args['cert_pri'] -# cert_name = args['cert_name'] -# -# if len(cert_pri) == 0: -# return self.write_json(-2, '参数错误,数据不完整') -# -# _yr = async_enc(cert_pri) -# return_data = yield _yr -# if return_data is None: -# return self.write_json(-3, '调用核心服务加密失败') -# -# if 'code' not in return_data or return_data['code'] != 0: -# return self.write_json(-4, '核心服务加密返回错误') -# -# cert_pri = return_data['data'] -# -# try: -# ret = host.add_cert(cert_pub, cert_pri, cert_name) -# if ret: -# return self.write_json(0) -# else: -# return self.write_json(-5, '数据库操作失败,errcode:{}'.format(ret)) -# except: -# log.e('add cert failed.\n') -# return self.write_json(-6, '发生异常') -# -# -# class DeleteCert(TPBaseUserAuthJsonHandler): -# def post(self): -# args = self.get_argument('args', None) -# if args is not None: -# args = json.loads(args) -# else: -# return self.write_json(-1, '参数错误') -# -# cert_id = args['cert_id'] -# -# try: -# ret = host.delete_cert(cert_id) -# if ret: -# return self.write_json(0) -# else: -# if ret == -2: -# return self.write_json(-2, '') -# else: -# return self.write_json(-3, '数据库操作失败,errcode:{}'.format(ret)) -# except: -# log.e('add cert failed.\n') -# return self.write_json(-4, '发生异常') -# -# -# class UpdateCert(TPBaseUserAuthJsonHandler): -# @tornado.gen.coroutine -# def post(self): -# args = self.get_argument('args', None) -# if args is not None: -# args = json.loads(args) -# else: -# return self.write_json(-1, '参数错误') -# -# cert_id = args['cert_id'] -# cert_pub = args['cert_pub'] -# cert_pri = args['cert_pri'] -# cert_name = args['cert_name'] -# -# if len(cert_pri) > 0: -# _yr = async_enc(cert_pri) -# return_data = yield _yr -# if return_data is None: -# return self.write_json(-2, '调用核心服务加密失败') -# -# if 'code' not in return_data or return_data['code'] != 0: -# return self.write_json(-3, '核心服务加密返回错误') -# -# cert_pri = return_data['data'] -# -# try: -# ret = host.update_cert(cert_id, cert_pub, cert_pri, cert_name) -# if ret: -# return self.write_json(0) -# else: -# return self.write_json(-4, '数据库操作失败,errcode:{}'.format(ret)) -# except: -# log.e('update cert failed.\n') -# return self.write_json(-5, '发生异常') -# -# -# class AddGroup(TPBaseUserAuthJsonHandler): -# def post(self): -# args = self.get_argument('args', None) -# if args is not None: -# args = json.loads(args) -# else: -# return self.write_json(-1, '参数错误') -# -# group_name = args['group_name'] -# try: -# ret = host.add_group(group_name) -# if ret: -# return self.write_json(0) -# else: -# return self.write_json(-2, '数据库操作失败,errcode:{}'.format(ret)) -# except: -# log.e('add group failed.\n') -# return self.write_json(-3, '发生异常') -# -# -# class UpdateGroup(TPBaseUserAuthJsonHandler): -# def post(self): -# args = self.get_argument('args', None) -# if args is not None: -# args = json.loads(args) -# else: -# return self.write_json(-1, '参数错误') -# -# group_id = args['group_id'] -# group_name = args['group_name'] -# try: -# ret = host.update_group(group_id, group_name) -# if ret: -# return self.write_json(0) -# else: -# return self.write_json(-2, '数据库操作失败,errcode:{}'.format(ret)) -# except: -# log.e('update group failed.\n') -# return self.write_json(-3, '发生异常') -# -# -# class DeleteGroup(TPBaseUserAuthJsonHandler): -# def post(self): -# args = self.get_argument('args', None) -# if args is not None: -# args = json.loads(args) -# else: -# return self.write_json(-1, '参数错误') -# -# group_id = args['group_id'] -# try: -# ret = host.delete_group(group_id) -# if ret == 0: -# return self.write_json(0) -# else: -# if ret == -2: -# return self.write_json(-2, '') -# else: -# return self.write_json(-3, '数据库操作失败,errcode:{}'.format(ret)) -# except: -# log.e('delete group failed.\n') -# return self.write_json(-4, '发生异常') -# -# -# class AddHostToGroup(TPBaseUserAuthJsonHandler): -# def post(self): -# args = self.get_argument('args', None) -# if args is not None: -# args = json.loads(args) -# else: -# return self.write_json(-1, '参数错误') -# -# host_list = args['host_list'] -# group_id = args['group_id'] -# try: -# ret = host.add_host_to_group(host_list, group_id) -# if ret: -# self.write_json(0) -# else: -# return self.write_json(-2, '数据库操作失败,errcode:{}'.format(ret)) -# return -# except: -# log.e('add host to group failed.\n') -# return self.write_json(-3, '发生异常') -# -# -# class GetSessionId(TPBaseUserAuthJsonHandler): -# @tornado.gen.coroutine -# def post(self, *args, **kwargs): -# args = self.get_argument('args', None) -# if args is not None: -# args = json.loads(args) -# else: -# return self.write_json(-1, '参数错误') -# -# if 'auth_id' not in args: -# return self.write_json(-1, '参数缺失') -# -# auth_id = args['auth_id'] -# -# req = {'method': 'request_session', 'param': {'authid': auth_id}} -# _yr = async_post_http(req) -# return_data = yield _yr -# if return_data is None: -# return self.write_json(-2, '调用核心服务获取会话ID失败') -# -# if 'code' not in return_data: -# return self.write_json(-3, '核心服务获取会话ID时返回错误数据') -# -# _code = return_data['code'] -# if _code != 0: -# return self.write_json(-4, '核心服务获取会话ID时返回错误 {}'.format(_code)) -# -# try: -# session_id = return_data['data']['sid'] -# except IndexError: -# return self.write_json(-5, '核心服务获取会话ID时返回错误数据') -# -# data = dict() -# data['session_id'] = session_id -# -# return self.write_json(0, data=data) -# -# -# class AdminGetSessionId(TPBaseUserAuthJsonHandler): -# @tornado.gen.coroutine -# def post(self, *args, **kwargs): -# args = self.get_argument('args', None) -# if args is not None: -# args = json.loads(args) -# else: -# return self.write_json(-1, '参数错误') -# -# if 'host_auth_id' not in args: -# return self.write_json(-1, '参数缺失') -# -# _host_auth_id = int(args['host_auth_id']) -# -# user = self.get_current_user() -# -# # host_auth_id 对应的是 ts_auth_info 表中的某个条目,含有具体的认证数据,因为管理员无需授权即可访问所有远程主机,因此 -# # 直接给出 host_auth_id,且account直接指明是当前登录用户(其必然是管理员) -# -# tmp_auth_info = host.get_host_auth_info(_host_auth_id) -# if tmp_auth_info is None: -# return self.write_json(-2, '指定数据不存在') -# -# tmp_auth_info['account_lock'] = 0 -# tmp_auth_info['account_name'] = user['name'] -# -# with tmp_auth_id_lock: -# global tmp_auth_id_base -# tmp_auth_id_base -= 1 -# auth_id = tmp_auth_id_base -# -# # 将这个临时认证信息放到session中备后续查找使用(10秒内有效) -# session_manager().set('tmp-auth-info-{}'.format(auth_id), tmp_auth_info, 10) -# -# req = {'method': 'request_session', 'param': {'authid': auth_id}} -# _yr = async_post_http(req) -# return_data = yield _yr -# if return_data is None: -# return self.write_json(-3, '调用核心服务获取会话ID失败') -# -# if 'code' not in return_data: -# return self.write_json(-4, '核心服务获取会话ID时返回错误数据') -# -# _code = return_data['code'] -# if _code != 0: -# return self.write_json(-5, '核心服务获取会话ID时返回错误 {}'.format(_code)) -# -# try: -# session_id = return_data['data']['sid'] -# except IndexError: -# return self.write_json(-5, '核心服务获取会话ID时返回错误数据') -# -# data = dict() -# data['session_id'] = session_id -# -# return self.write_json(0, data=data) -# -# -# class AdminFastGetSessionId(TPBaseAdminAuthJsonHandler): -# @tornado.gen.coroutine -# def post(self, *args, **kwargs): -# args = self.get_argument('args', None) -# if args is not None: -# args = json.loads(args) -# else: -# return self.write_json(-1, '参数错误') -# -# user = self.get_current_user() -# -# tmp_auth_info = dict() -# -# try: -# _host_auth_id = int(args['host_auth_id']) -# _user_pswd = args['user_pswd'] -# _cert_id = int(args['cert_id']) -# -# tmp_auth_info['host_ip'] = args['host_ip'] -# tmp_auth_info['host_port'] = int(args['host_port']) -# tmp_auth_info['sys_type'] = int(args['sys_type']) -# tmp_auth_info['protocol'] = int(args['protocol']) -# tmp_auth_info['user_name'] = args['user_name'] -# tmp_auth_info['auth_mode'] = int(args['auth_mode']) -# tmp_auth_info['user_param'] = args['user_param'] -# tmp_auth_info['encrypt'] = 1 -# tmp_auth_info['account_lock'] = 0 -# tmp_auth_info['account_name'] = user['name'] -# except IndexError: -# return self.write_json(-2, '参数缺失') -# -# if tmp_auth_info['auth_mode'] == 1: -# if len(_user_pswd) == 0: # 修改登录用户信息时可能不会修改密码,因此页面上可能不会传来密码,需要从数据库中直接读取 -# h = host.get_host_auth_info(_host_auth_id) -# tmp_auth_info['user_auth'] = h['user_auth'] -# else: # 如果页面上修改了密码或者新建账号时设定了密码,那么需要先交给core服务进行加密 -# req = {'method': 'enc', 'param': {'p': _user_pswd}} -# _yr = async_post_http(req) -# return_data = yield _yr -# if return_data is None: -# return self.write_json(-3, '调用核心服务加密失败') -# if 'code' not in return_data or return_data['code'] != 0: -# return self.write_json(-3, '核心服务加密返回错误') -# -# tmp_auth_info['user_auth'] = return_data['data']['c'] -# -# elif tmp_auth_info['auth_mode'] == 2: -# tmp_auth_info['user_auth'] = host.get_cert_info(_cert_id) -# if tmp_auth_info['user_auth'] is None: -# self.write_json(-100, '指定私钥不存在') -# return -# elif tmp_auth_info['auth_mode'] == 0: -# tmp_auth_info['user_auth'] = '' -# else: -# self.write_json(-101, '认证类型未知') -# return -# -# with tmp_auth_id_lock: -# global tmp_auth_id_base -# tmp_auth_id_base -= 1 -# auth_id = tmp_auth_id_base -# -# session_manager().set('tmp-auth-info-{}'.format(auth_id), tmp_auth_info, 10) -# -# req = {'method': 'request_session', 'param': {'authid': auth_id}} -# _yr = async_post_http(req) -# return_data = yield _yr -# if return_data is None: -# return self.write_json(-3, '调用核心服务获取会话ID失败') -# -# if 'code' not in return_data: -# return self.write_json(-4, '核心服务获取会话ID时返回错误数据') -# -# _code = return_data['code'] -# if _code != 0: -# return self.write_json(-5, '核心服务获取会话ID时返回错误 {}'.format(_code)) -# -# try: -# session_id = return_data['data']['sid'] -# except IndexError: -# return self.write_json(-5, '核心服务获取会话ID时返回错误数据') -# -# data = dict() -# data['session_id'] = session_id -# -# return self.write_json(0, data=data) -# -# -# class SysUserList(TPBaseUserAuthJsonHandler): -# def post(self, *args, **kwargs): -# args = self.get_argument('args', None) -# if args is not None: -# args = json.loads(args) -# else: -# return self.write_json(-1, '参数错误') -# -# try: -# host_id = args['host_id'] -# except: -# return self.write_json(-1, '参数缺失') -# -# data = host.sys_user_list(host_id) -# return self.write_json(0, data=data) -# -# -# class SysUserAdd(TPBaseUserAuthJsonHandler): -# @tornado.gen.coroutine -# def post(self, *args, **kwargs): -# args = self.get_argument('args', None) -# if args is not None: -# args = json.loads(args) -# else: -# return self.write_json(-1, '参数错误') -# -# try: -# auth_mode = args['auth_mode'] -# user_pswd = args['user_pswd'] -# cert_id = args['cert_id'] -# except: -# return self.write_json(-1, '参数缺失') -# -# if auth_mode == 1: -# if 0 == len(args['user_pswd']): -# return self.write_json(-2, '参数缺失') -# -# _yr = async_enc(user_pswd) -# return_data = yield _yr -# if return_data is None: -# return self.write_json(-3, '调用核心服务加密失败') -# -# if 'code' not in return_data or return_data['code'] != 0: -# return self.write_json(-3, '核心服务加密返回错误') -# -# args['user_pswd'] = return_data['data'] -# -# user_id = host.sys_user_add(args) -# if user_id < 0: -# if user_id == -100: -# return self.write_json(user_id, '同名账户已经存在!') -# else: -# return self.write_json(user_id, '数据库操作失败!') -# -# return self.write_json(0) -# -# -# class SysUserUpdate(TPBaseUserAuthJsonHandler): -# @tornado.gen.coroutine -# def post(self, *args, **kwargs): -# args = self.get_argument('args', None) -# if args is not None: -# args = json.loads(args) -# else: -# return self.write_json(-1, '参数错误') -# -# if 'host_auth_id' not in args or 'kv' not in args: -# return self.write_json(-2, '参数缺失') -# -# kv = args['kv'] -# if 'auth_mode' not in kv or 'user_pswd' not in kv or 'cert_id' not in kv: -# return self.write_json(-3, '参数缺失') -# -# auth_mode = kv['auth_mode'] -# if 'user_pswd' in kv: -# user_pswd = kv['user_pswd'] -# if 0 == len(user_pswd): -# args['kv'].pop('user_pswd') -# user_pswd = None -# else: -# user_pswd = None -# -# cert_id = kv['cert_id'] -# if auth_mode == 1 and user_pswd is not None: -# _yr = async_enc(user_pswd) -# return_data = yield _yr -# if return_data is None: -# return self.write_json(-4, '调用核心服务加密失败') -# -# if 'code' not in return_data or return_data['code'] != 0: -# return self.write_json(-5, '核心服务加密返回错误') -# -# args['kv']['user_pswd'] = return_data['data'] -# -# if host.sys_user_update(args['host_auth_id'], args['kv']): -# return self.write_json(0) -# -# return self.write_json(-6, '数据库操作失败') -# -# -# class SysUserDelete(TPBaseUserAuthJsonHandler): -# def post(self, *args, **kwargs): -# args = self.get_argument('args', None) -# if args is not None: -# args = json.loads(args) -# else: -# return self.write_json(-1, '参数错误') -# -# try: -# host_auth_id = args['host_auth_id'] -# except IndexError: -# return self.write_json(-2, '参数缺失') -# -# if host.sys_user_delete(host_auth_id): -# return self.write_json(0) -# -# return self.write_json(-3, '数据库操作失败') diff --git a/server/www/teleport/webroot/app/controller/user.py b/server/www/teleport/webroot/app/controller/user.py index dcf4ef7..8a26fa1 100644 --- a/server/www/teleport/webroot/app/controller/user.py +++ b/server/www/teleport/webroot/app/controller/user.py @@ -344,10 +344,11 @@ class DoImportHandler(TPBaseHandler): pass if file_encode is None: - with open(csv_filename, encoding='utf8') as f: + log.v('file `{}` is not gbk, try utf8\n'.format(csv_filename)) + with open(csv_filename, encoding='utf_8_sig') as f: try: f.readlines() - file_encode = 'utf8' + file_encode = 'utf_8_sig' except: pass diff --git a/server/www/teleport/webroot/app/model/host.py b/server/www/teleport/webroot/app/model/host.py index 07fa6d1..b39d990 100644 --- a/server/www/teleport/webroot/app/model/host.py +++ b/server/www/teleport/webroot/app/model/host.py @@ -118,6 +118,7 @@ def add_host(handler, args): def remove_hosts(handler, hosts): + print('----', hosts) db = get_db() host_ids = ','.join([str(i) for i in hosts]) @@ -134,36 +135,37 @@ def remove_hosts(handler, hosts): if err != TPE_OK: return err - acc_ids = [] + accs = [] acc_names = [] for acc in s.recorder: - if str(acc['id']) not in acc_ids: - acc_ids.append(str(acc['id'])) + if str(acc['id']) not in accs: + accs.append(str(acc['id'])) acc_name = '{}@{}'.format(acc['username'], acc['host_ip']) if len(acc['router_ip']) > 0: acc_name += '(由{}:{}路由)'.format(acc['router_ip'], acc['router_port']) if acc_name not in acc_names: acc_names.append(acc_name) - if len(acc_ids) > 0: + acc_ids = ','.join([i for i in accs]) + if len(accs) > 0: # 1.2 将账号从所在组中移除 - where = 'mid IN ({})'.format(','.join(acc_ids)) + where = 'mid IN ({})'.format(acc_ids) sql = 'DELETE FROM `{}group_map` WHERE (type={} AND {});'.format(db.table_prefix, TP_GROUP_ACCOUNT, where) sql_list.append(sql) # if not db.exec(sql): # return TPE_DATABASE # 1.3 将账号删除 - where = 'id IN ({})'.format(','.join(acc_ids)) + where = 'id IN ({})'.format(acc_ids) sql = 'DELETE FROM `{}acc` WHERE {};'.format(db.table_prefix, where) sql_list.append(sql) # if not db.exec(sql): # return TPE_DATABASE - sql = 'DELETE FROM `{}ops_auz` WHERE rtype={rtype} AND rid IN ({rid});'.format(db.table_prefix, rtype=TP_ACCOUNT, rid=','.join(acc_ids)) + sql = 'DELETE FROM `{}ops_auz` WHERE rtype={rtype} AND rid IN ({rid});'.format(db.table_prefix, rtype=TP_ACCOUNT, rid=acc_ids) sql_list.append(sql) - sql = 'DELETE FROM `{}ops_map` WHERE a_id IN ({});'.format(db.table_prefix, ','.join(acc_ids)) + sql = 'DELETE FROM `{}ops_map` WHERE a_id IN ({acc_ids});'.format(db.table_prefix, acc_ids=acc_ids) sql_list.append(sql) # step 2. 处理主机 @@ -192,9 +194,9 @@ def remove_hosts(handler, hosts): sql = 'DELETE FROM `{}host` WHERE {};'.format(db.table_prefix, where) sql_list.append(sql) - sql = 'DELETE FROM `{}ops_auz` WHERE rtype={rtype} AND rid IN ({rid});'.format(db.table_prefix, rtype=TP_HOST, rid=','.join(host_ids)) + sql = 'DELETE FROM `{}ops_auz` WHERE rtype={rtype} AND rid IN ({rid});'.format(db.table_prefix, rtype=TP_HOST, rid=host_ids) sql_list.append(sql) - sql = 'DELETE FROM `{}ops_map` WHERE h_id IN ({});'.format(db.table_prefix, ','.join(host_ids)) + sql = 'DELETE FROM `{}ops_map` WHERE h_id IN ({host_ids});'.format(db.table_prefix, host_ids=host_ids) sql_list.append(sql) if not db.transaction(sql_list): diff --git a/server/www/teleport/webroot/app/model/stat.py b/server/www/teleport/webroot/app/model/stat.py new file mode 100644 index 0000000..40460db --- /dev/null +++ b/server/www/teleport/webroot/app/model/stat.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- + +from app.const import * +from app.base.db import get_db, SQL +from app.base.logger import log +from app.base.utils import tp_timestamp_utc_now + + +def get_basic(): + db = get_db() + + ret = {'count_user': 0, + 'count_host': 0, + 'count_acc': 0, + 'count_conn': 0 + } + + sql = 'SELECT COUNT(*) FROM `{tpdb}user`;'.format(tpdb=db.table_prefix) + db_ret = db.query(sql) + if not db_ret or len(db_ret) == 0: + pass + else: + ret['count_user'] = db_ret[0][0] + + sql = 'SELECT COUNT(*) FROM `{tpdb}host`;'.format(tpdb=db.table_prefix) + db_ret = db.query(sql) + if not db_ret or len(db_ret) == 0: + pass + else: + ret['count_host'] = db_ret[0][0] + + sql = 'SELECT COUNT(*) FROM `{tpdb}acc`;'.format(tpdb=db.table_prefix) + db_ret = db.query(sql) + if not db_ret or len(db_ret) == 0: + pass + else: + ret['count_acc'] = db_ret[0][0] + + sql = 'SELECT COUNT(*) FROM `{tpdb}record` WHERE `state` IN ({sess_running},{sess_started});'.format(tpdb=db.table_prefix, sess_running=TP_SESS_STAT_RUNNING, sess_started=TP_SESS_STAT_STARTED) + db_ret = db.query(sql) + if not db_ret or len(db_ret) == 0: + pass + else: + ret['count_conn'] = db_ret[0][0] + + return TPE_OK, ret + + +def get_logs(sql_filter, sql_order, sql_limit): + s = SQL(get_db()) + s.select_from('syslog', ['id', 'user_name', 'user_surname', 'client_ip', 'code', 'log_time', 'message'], alt_name='l') + + str_where = '' + _where = list() + + if len(sql_filter) > 0: + for k in sql_filter: + if k == 'log_user_name': + _where.append('l.user_name="{}"'.format(sql_filter[k])) + # elif k == 'search_record': + # _where.append('(h.name LIKE "%{}%" OR h.ip LIKE "%{}%" OR h.router_addr LIKE "%{}%" OR h.desc LIKE "%{}%" OR h.cid LIKE "%{}%")'.format(sql_filter[k], sql_filter[k], sql_filter[k], sql_filter[k], sql_filter[k])) + + if len(_where) > 0: + str_where = '( {} )'.format(' AND '.join(_where)) + + s.where(str_where) + + if sql_order is not None: + _sort = False if not sql_order['asc'] else True + if 'log_time' == sql_order['name']: + s.order_by('l.log_time', _sort) + # elif 'name' == sql_order['name']: + # s.order_by('h.name', _sort) + # elif 'os_type' == sql_order['name']: + # s.order_by('h.os_type', _sort) + # elif 'cid' == sql_order['name']: + # s.order_by('h.cid', _sort) + # elif 'state' == sql_order['name']: + # s.order_by('h.state', _sort) + else: + log.e('unknown order field: {}\n'.format(sql_order['name'])) + return TPE_PARAM, s.total_count, s.recorder + + if len(sql_limit) > 0: + s.limit(sql_limit['page_index'], sql_limit['per_page']) + + err = s.query() + return err, s.total_count, s.recorder