mirror of
https://github.com/midoks/mdserver-web.git
synced 2026-10-10 01:29:26 +08:00
up
This commit is contained in:
@@ -987,6 +987,33 @@ class files_api:
|
||||
|
||||
return mw.getJson(data)
|
||||
|
||||
def execShellApi(self, get):
|
||||
# 执行SHELL命令
|
||||
shell = request.form.get('shell', '').strip()
|
||||
path = request.form.get('path', '').strip()
|
||||
disabled = ['vi', 'vim', 'top', 'passwd', 'su']
|
||||
tmp = shell.split(' ')
|
||||
if tmp[0] in disabled:
|
||||
return mw.returnJson(False, '禁止执行[{}]'.format(tmp[0]))
|
||||
shellStr = '''#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
cd %s
|
||||
%s
|
||||
''' % (path, shell)
|
||||
mw.writeFile('/tmp/panelShell.sh', shellStr)
|
||||
mw.execShell(
|
||||
'nohup bash /tmp/panelShell.sh > /tmp/panelShell.pl 2>&1 &')
|
||||
return mw.returnJson(True, 'ok')
|
||||
|
||||
def getExecShellMsgApi(self, get):
|
||||
# 取SHELL执行结果
|
||||
fileName = '/tmp/panelShell.pl'
|
||||
if not os.path.exists(fileName):
|
||||
return ''
|
||||
status = not mw.processExists('bash', None, '/tmp/panelShell.sh')
|
||||
return mw.returnJson(status, mw.getNumLines(fileName, 200))
|
||||
|
||||
def __get_stats(self, filename, path=None):
|
||||
filename = filename.replace('//', '/')
|
||||
try:
|
||||
|
||||
@@ -1631,6 +1631,31 @@ def getSshDir():
|
||||
return '/root/.ssh'
|
||||
|
||||
|
||||
def processExists(pname, exe=None, cmdline=None):
|
||||
# 进程是否存在
|
||||
try:
|
||||
import psutil
|
||||
pids = psutil.pids()
|
||||
for pid in pids:
|
||||
try:
|
||||
p = psutil.Process(pid)
|
||||
if p.name() == pname:
|
||||
if not exe and not cmdline:
|
||||
return True
|
||||
else:
|
||||
if exe:
|
||||
if p.exe() == exe:
|
||||
return True
|
||||
if cmdline:
|
||||
if cmdline in p.cmdline():
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
except:
|
||||
return True
|
||||
|
||||
|
||||
def createRsa():
|
||||
# ssh-keygen -t rsa -P "" -C "midoks@163.com"
|
||||
ssh_dir = getSshDir()
|
||||
|
||||
+454
-38
@@ -8,6 +8,8 @@ import re
|
||||
import hashlib
|
||||
import json
|
||||
|
||||
from requests_toolbelt import MultipartEncoder
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
@@ -20,8 +22,12 @@ class classApi:
|
||||
__MW_KEY = 'app'
|
||||
__MW_PANEL = 'http://127.0.0.1:7200'
|
||||
|
||||
_buff_size = 1024 * 1024 * 2
|
||||
|
||||
_REQUESTS = None
|
||||
_SPEED_FILE = None
|
||||
_INFO_FILE = None
|
||||
_SYNC_INFO = None
|
||||
|
||||
# 如果希望多台面板,可以在实例化对象时,将面板地址与密钥传入
|
||||
def __init__(self, mw_panel=None, mw_key=None):
|
||||
@@ -34,6 +40,8 @@ class classApi:
|
||||
self._REQUESTS = requests.session()
|
||||
|
||||
self._SPEED_FILE = getServerDir() + '/config/speed.json'
|
||||
self._INFO_FILE = getServerDir() + '/config/sync_info.json'
|
||||
self._SYNC_INFO = self.get_sync_info(None)
|
||||
|
||||
# 计算MD5
|
||||
def __get_md5(self, s):
|
||||
@@ -63,6 +71,25 @@ class classApi:
|
||||
return mw.returnJson(False, '连接超时!')
|
||||
return mw.returnJson(False, '连接服务器失败!')
|
||||
|
||||
def get_sync_info(self, args):
|
||||
# 获取要被迁移的网站、数据库
|
||||
if not os.path.exists(self._INFO_FILE):
|
||||
return mw.returnJson(False, '迁移信息不存在!')
|
||||
sync_info = json.loads(mw.readFile(self._INFO_FILE))
|
||||
if not args:
|
||||
return sync_info
|
||||
result = []
|
||||
for i in sync_info['sites']:
|
||||
i['type'] = "网站"
|
||||
result.append(i)
|
||||
for i in sync_info['databases']:
|
||||
i['type'] = "数据库"
|
||||
result.append(i)
|
||||
for i in sync_info['paths']:
|
||||
i['type'] = "目录"
|
||||
result.append(i)
|
||||
return result
|
||||
|
||||
def write_speed(self, key, value):
|
||||
# 写进度
|
||||
if os.path.exists(self._SPEED_FILE):
|
||||
@@ -96,6 +123,15 @@ class classApi:
|
||||
except Exception as e:
|
||||
return result
|
||||
|
||||
def sendPlugins(self, name, func, args):
|
||||
url = '/plugins/run'
|
||||
|
||||
data = {}
|
||||
data['name'] = name
|
||||
data['func'] = func
|
||||
data['args'] = json.dumps(args).replace(": ", ":").replace(", ", ",")
|
||||
return self.send(url, data)
|
||||
|
||||
def get_mode_and_user(self, path):
|
||||
'''取文件或目录权限信息'''
|
||||
data = {}
|
||||
@@ -109,39 +145,166 @@ class classApi:
|
||||
data['user'] = str(stat.st_uid)
|
||||
return data
|
||||
|
||||
def error(self, error_msg, is_exit=False):
|
||||
# 发生错误
|
||||
write_log("=" * 50)
|
||||
write_log("|-发生时间: {}".format(mw.formatDate()))
|
||||
write_log("|-错误信息: {}".format(error_msg))
|
||||
if is_exit:
|
||||
write_log("|-处理结果: 终止迁移任务")
|
||||
sys.exit(0)
|
||||
write_log("|-处理结果: 忽略错误, 继续执行")
|
||||
|
||||
def upload_file(self, sfile, dfile, chmod=None):
|
||||
# 上传文件
|
||||
if not os.path.exists(sfile):
|
||||
write_log("|-指定目录不存在{}".format(sfile))
|
||||
return False
|
||||
pdata = self.__get_key_data()
|
||||
pdata['f_name'] = os.path.basename(dfile)
|
||||
pdata['f_path'] = os.path.dirname(dfile)
|
||||
pdata['f_size'] = os.path.getsize(sfile)
|
||||
pdata['f_start'] = 0
|
||||
pdata['name'] = os.path.basename(dfile)
|
||||
pdata['path'] = os.path.dirname(dfile)
|
||||
pdata['size'] = os.path.getsize(sfile)
|
||||
pdata['start'] = 0
|
||||
if chmod:
|
||||
mode_user = self.get_mode_and_user(os.path.dirname(sfile))
|
||||
pdata['dir_mode'] = mode_user['mode'] + ',' + mode_user['user']
|
||||
mode_user = self.get_mode_and_user(sfile)
|
||||
pdata['file_mode'] = mode_user['mode'] + ',' + mode_user['user']
|
||||
f = open(sfile, 'rb')
|
||||
|
||||
return self.send_file(pdata, f)
|
||||
|
||||
def send_file(self, f):
|
||||
pass
|
||||
def close_sync(self, args):
|
||||
# 取消迁移
|
||||
mw.execShell("kill -9 {}".format(self.get_pid()))
|
||||
mw.execShell(
|
||||
"kill -9 $(ps aux|grep index.py|grep -v grep|awk '{print $2}')")
|
||||
# 删除迁移配置
|
||||
time.sleep(1)
|
||||
if os.path.exists(self._INFO_FILE):
|
||||
os.remove(self._INFO_FILE)
|
||||
if os.path.exists(self._SPEED_FILE):
|
||||
os.remove(self._SPEED_FILE)
|
||||
return mw.returnJson(True, '已取消迁移任务!')
|
||||
|
||||
def send_file(self, pdata, f):
|
||||
success_num = 0 # 连续发送成功次数
|
||||
max_buff_size = int(1024 * 1024 * 2) # 最大分片大小
|
||||
min_buff_size = int(1024 * 32) # 最小分片大小
|
||||
err_num = 0 # 连接错误计数
|
||||
max_err_num = 10 # 最大连接错误重试次数
|
||||
up_buff_num = 5 # 调整分片的触发次数
|
||||
timeout = 60 # 每次发送分片的超时时间
|
||||
split_num = 0
|
||||
split_done = 0
|
||||
total_time = 0
|
||||
self.write_speed('done', "正在传输文件")
|
||||
self.write_speed('size', pdata['size'])
|
||||
self.write_speed('used', 0)
|
||||
self.write_speed('speed', 0)
|
||||
write_log("|-上传文件[{}], 总大小:{}, 当前分片大小为:{}".format(pdata['name'],
|
||||
toSize(pdata['size']), toSize(self._buff_size)))
|
||||
while True:
|
||||
buff_size = self._buff_size
|
||||
max_buff = int(pdata['size'] - pdata['start'])
|
||||
if max_buff < buff_size:
|
||||
buff_size = max_buff
|
||||
files = {"blob": f.read(buff_size)}
|
||||
start_time = time.time()
|
||||
|
||||
try:
|
||||
url = self.__MW_PANEL + '/api/files/upload_segment'
|
||||
res = self._REQUESTS.post(
|
||||
url, data=pdata, files=files, timeout=30000)
|
||||
|
||||
success_num += 1
|
||||
err_num = 0
|
||||
# 连续5次分片发送成功的情况下尝试调整分片大小, 以提升上传效率
|
||||
if success_num > up_buff_num and self._buff_size < max_buff_size:
|
||||
self._buff_size = int(self._buff_size * 2)
|
||||
success_num = up_buff_num - 3 # 如再顺利发送3次则继续提升分片大小
|
||||
if self._buff_size > max_buff_size:
|
||||
self._buff_size = max_buff_size
|
||||
write_log(
|
||||
"|-发送顺利, 尝试调整分片大小为: {}".format(toSize(self._buff_size)))
|
||||
except Exception as e:
|
||||
times = time.time() - start_time
|
||||
total_time += times
|
||||
ex = str(ex)
|
||||
if ex.find('Read timed out') != -1 or ex.find('Connection aborted') != -1:
|
||||
# 发生超时的时候尝试调整分片大小, 以确保网络情况不好的时候能继续上传
|
||||
self._buff_size = int(self._buff_size / 2)
|
||||
if self._buff_size < min_buff_size:
|
||||
self._buff_size = min_buff_size
|
||||
success_num = 0
|
||||
write_log(
|
||||
"|-发送超时, 尝试调整分片大小为: {}".format(toSize(self._buff_size)))
|
||||
continue
|
||||
|
||||
# 如果连接超时
|
||||
if ex.find('Max retries exceeded with') != -1 and err_num <= max_err_num:
|
||||
err_num += 1
|
||||
write_log("|-连接超时, 第{}次重试".format(err_num))
|
||||
time.sleep(1)
|
||||
continue
|
||||
|
||||
# 超过重试次数
|
||||
write_log("|-上传失败, 跳过本次上传任务")
|
||||
write_log(mw.getTracebackInfo())
|
||||
return False
|
||||
|
||||
result = res.json()
|
||||
times = time.time() - start_time
|
||||
total_time += times
|
||||
|
||||
if type(result) == int:
|
||||
if result == split_done:
|
||||
split_num += 1
|
||||
else:
|
||||
split_num = 0
|
||||
split_done = result
|
||||
if split_num > 10:
|
||||
write_log("|-上传失败, 跳过本次上传任务")
|
||||
return False
|
||||
if result > pdata['size']:
|
||||
write_log("|-上传失败, 跳过本次上传任务")
|
||||
return False
|
||||
self.write_speed('used', result)
|
||||
self.write_speed('speed', int(buff_size / times))
|
||||
write_log("|-已上传 {},上传速度 {}/s, 共用时 {}分{:.2f}秒, {:.2f}%".format(toSize(float(result)), toSize(
|
||||
buff_size / times), int(total_time // 60), total_time % 60, (float(result) / float(pdata['size']) * 100)))
|
||||
pdata['start'] = result # 设置断点
|
||||
else:
|
||||
if not result['status']: # 如果服务器响应上传失败
|
||||
write_log(result['msg'])
|
||||
return False
|
||||
|
||||
if pdata['size']:
|
||||
self.write_speed('used', pdata['size'])
|
||||
self.write_speed('speed', int(buff_size / times))
|
||||
write_log("|-已上传 {},上传速度 {}/s, 共用时 {}分{:.2f}秒, {:.2f}%".format(toSize(float(pdata['size'])), toSize(
|
||||
buff_size / times), int(total_time // 60), total_time % 60, (float(pdata['size']) / float(pdata['size']) * 100)))
|
||||
break
|
||||
|
||||
self.write_speed('total_size', pdata['size'])
|
||||
self.write_speed('end_time', int(time.time()))
|
||||
write_log("|-总耗时:{} 分钟, {:.2f} 秒, 平均速度:{}/s".format(int(total_time //
|
||||
60), total_time % 60, toSize(pdata['size'] / total_time)))
|
||||
return True
|
||||
|
||||
def state(self, stype, index, state, error=''):
|
||||
# 设置状态
|
||||
# print(self._SYNC_INFO)
|
||||
# self._SYNC_INFO[stype][index]['state'] = state
|
||||
# self._SYNC_INFO[stype][index]['error'] = error
|
||||
# if self._SYNC_INFO[stype][index]['state'] != 1:
|
||||
# self._SYNC_INFO['speed'] += 1
|
||||
self.save()
|
||||
|
||||
def save(self):
|
||||
# 保存迁移配置
|
||||
mw.writeFile(self._INFO_FILE, json.dumps(self._SYNC_INFO))
|
||||
|
||||
def state(self, stype, index, state, error=''):
|
||||
# 设置状态
|
||||
self._SYNC_INFO[stype][index]['state'] = state
|
||||
self._SYNC_INFO[stype][index]['error'] = error
|
||||
if self._SYNC_INFO[stype][index]['state'] != 1:
|
||||
self._SYNC_INFO['speed'] += 1
|
||||
self.save()
|
||||
|
||||
def format_domain(self, domain):
|
||||
# 格式化域名
|
||||
domains = []
|
||||
@@ -167,8 +330,8 @@ class classApi:
|
||||
result = self.send('/site/add', pdata)
|
||||
if not result['status']:
|
||||
err_msg = '站点[{}]创建失败, {}'.format(siteInfo['name'], result['msg'])
|
||||
# self.state('sites', index, -1, err_msg)
|
||||
# self.error(err_msg)
|
||||
self.state('sites', index, -1, err_msg)
|
||||
self.error(err_msg)
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -185,43 +348,286 @@ class classApi:
|
||||
data = getCfgData()
|
||||
sites = data['ready']['sites']
|
||||
for i in range(len(sites)):
|
||||
siteInfo = mw.M('sites').where('name=?', (sites[i],)).field(
|
||||
'id,name,path,ps,status,edate,addtime').find()
|
||||
try:
|
||||
siteInfo = mw.M('sites').where('name=?', (sites[i],)).field(
|
||||
'id,name,path,ps,status,edate,addtime').find()
|
||||
|
||||
if not siteInfo:
|
||||
err_msg = "指定站点[{}]不存在!".format(sites[i])
|
||||
# self.state('sites', i, -1, err_msg)
|
||||
# self.error(err_msg)
|
||||
continue
|
||||
pid = siteInfo['id']
|
||||
if not siteInfo:
|
||||
err_msg = "指定站点[{}]不存在!".format(sites[i])
|
||||
self.state('sites', i, -1, err_msg)
|
||||
self.error(err_msg)
|
||||
continue
|
||||
pid = siteInfo['id']
|
||||
|
||||
siteInfo['port'] = mw.M('domain').where(
|
||||
'pid=? and name=?', (pid, sites[i],)).getField('port')
|
||||
siteInfo['port'] = mw.M('domain').where(
|
||||
'pid=? and name=?', (pid, sites[i],)).getField('port')
|
||||
|
||||
siteInfo['domain'] = mw.M('domain').where(
|
||||
'pid=? and name!=?', (pid, sites[i])).field('name,port').select()
|
||||
siteInfo['domain'] = mw.M('domain').where(
|
||||
'pid=? and name!=?', (pid, sites[i])).field('name,port').select()
|
||||
|
||||
print(sites[i])
|
||||
print("dd:", mw.M('domain').where(
|
||||
'pid=? and name!=?', (pid, sites[i])).field('name,port').select())
|
||||
if self.send_site(siteInfo, i):
|
||||
self.state('sites', i, 2)
|
||||
write_log("=" * 50)
|
||||
except Exception as e:
|
||||
self.error(mw.getTracebackInfo())
|
||||
|
||||
if self.send_site(siteInfo, i):
|
||||
self.state('sites', i, 2)
|
||||
write_log("=" * 50)
|
||||
print(sites)
|
||||
def getConf(self, mtype='mysql'):
|
||||
path = mw.getServerDir() + '/' + mtype + '/etc/my.cnf'
|
||||
return path
|
||||
|
||||
def getSocketFile(self, mtype='mysql'):
|
||||
file = self.getConf(mtype)
|
||||
content = mw.readFile(file)
|
||||
rep = 'socket\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
return tmp.groups()[0].strip()
|
||||
|
||||
def getDbPort(self, mtype='mysql'):
|
||||
file = self.getConf(mtype)
|
||||
content = mw.readFile(file)
|
||||
rep = 'port\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
return tmp.groups()[0].strip()
|
||||
|
||||
def getDbConn(self, mtype='mysql', db='databases'):
|
||||
my_db_pos = mw.getServerDir() + '/' + mtype
|
||||
conn = mw.M(db).dbPos(my_db_pos, 'mysql')
|
||||
return conn
|
||||
|
||||
def getMyConn(self, mtype='mysql'):
|
||||
# pymysql
|
||||
db = mw.getMyORM()
|
||||
|
||||
db.setPort(self.getDbPort(mtype))
|
||||
db.setSocket(self.getSocketFile(mtype))
|
||||
pwd = self.getDbConn(mtype, 'config').where(
|
||||
'id=?', (1,)).getField('mysql_root')
|
||||
db.setPwd(pwd)
|
||||
return db
|
||||
|
||||
def getDbList(self):
|
||||
conn = self.getDbConn()
|
||||
alist = conn.field(
|
||||
'id,name,username,password,ps').order("id desc").select()
|
||||
return alist
|
||||
|
||||
def getDbInfo(self, name):
|
||||
conn = self.getDbConn()
|
||||
info = conn.field(
|
||||
'id,name,username,password,ps').where('name=?', (name,)).find()
|
||||
return info
|
||||
|
||||
def mapToList(self, map_obj):
|
||||
# map to list
|
||||
try:
|
||||
if type(map_obj) != list and type(map_obj) != str:
|
||||
map_obj = list(map_obj)
|
||||
return map_obj
|
||||
except:
|
||||
return []
|
||||
|
||||
# 取数据库权限
|
||||
def getDatabaseAccess(self, name):
|
||||
return '127.0.0.1'
|
||||
try:
|
||||
conn = self.getMyConn()
|
||||
users = conn.query(
|
||||
"select Host from mysql.user where User='" + name + "' AND Host!='localhost'")
|
||||
users = self.mapToList(users)
|
||||
if len(users) < 1:
|
||||
return "127.0.0.1"
|
||||
accs = []
|
||||
for c in users:
|
||||
accs.append(c[0])
|
||||
userStr = ','.join(accs)
|
||||
return userStr
|
||||
except:
|
||||
return '127.0.0.1'
|
||||
|
||||
def isSqlError(self, mysqlMsg):
|
||||
# 检测数据库执行错误
|
||||
mysqlMsg = str(mysqlMsg)
|
||||
if "MySQLdb" in mysqlMsg:
|
||||
return mw.returnData(False, 'DATABASE_ERR_MYSQLDB')
|
||||
if "2002," in mysqlMsg or '2003,' in mysqlMsg:
|
||||
return mw.returnData(False, 'DATABASE_ERR_CONNECT')
|
||||
if "using password:" in mysqlMsg:
|
||||
return mw.returnData(False, 'DATABASE_ERR_PASS')
|
||||
if "Connection refused" in mysqlMsg:
|
||||
return mw.returnData(False, 'DATABASE_ERR_CONNECT')
|
||||
if "1133" in mysqlMsg:
|
||||
return mw.returnData(False, 'DATABASE_ERR_NOT_EXISTS')
|
||||
return None
|
||||
|
||||
def getDatabaseCharacter(self, db_name):
|
||||
try:
|
||||
conn = self.getMyConn()
|
||||
tmp = conn.query("show create database `%s`" % db_name.strip(), ())
|
||||
# print(tmp)
|
||||
c_type = str(re.findall(r"SET\s+([\w\d-]+)\s", tmp[0][1])[0])
|
||||
c_types = ['utf8', 'utf-8', 'gbk', 'big5', 'utf8mb4']
|
||||
if not c_type.lower() in c_types:
|
||||
return 'utf8'
|
||||
return c_type
|
||||
except Exception as e:
|
||||
# print(str(e))
|
||||
return 'utf8'
|
||||
|
||||
# 创建远程数据库
|
||||
def create_database(self, dbInfo, index):
|
||||
pdata = {}
|
||||
pdata['name'] = dbInfo['name']
|
||||
pdata['db_user'] = dbInfo['username']
|
||||
pdata['password'] = dbInfo['password']
|
||||
pdata['dataAccess'] = dbInfo['accept']
|
||||
if dbInfo['accept'] != '%' and dbInfo['accept'] != '127.0.0.1':
|
||||
pdata['dataAccess'] = '127.0.0.1'
|
||||
pdata['address'] = dbInfo['accept']
|
||||
pdata['ps'] = dbInfo['ps']
|
||||
pdata['codeing'] = dbInfo['character']
|
||||
|
||||
result = self.sendPlugins('mysql', 'add_db', pdata)
|
||||
rdata = json.loads(result['data'])
|
||||
|
||||
if rdata['status']:
|
||||
return True
|
||||
err_msg = '数据库[{}]创建失败,{}'.format(dbInfo['name'], rdata['msg'])
|
||||
self.state('databases', index, -1, err_msg)
|
||||
self.error(err_msg)
|
||||
return False
|
||||
|
||||
# 数据库密码处理
|
||||
def mypass(self, act, root):
|
||||
# conf_file = '/etc/my.cnf'
|
||||
conf_file = self.getConf('mysql')
|
||||
mw.execShell("sed -i '/user=root/d' {}".format(conf_file))
|
||||
mw.execShell("sed -i '/password=/d' {}".format(conf_file))
|
||||
if act:
|
||||
mycnf = mw.readFile(conf_file)
|
||||
src_dump = "[mysqldump]\n"
|
||||
sub_dump = src_dump + "user=root\npassword=\"{}\"\n".format(root)
|
||||
if not mycnf:
|
||||
return False
|
||||
mycnf = mycnf.replace(src_dump, sub_dump)
|
||||
if len(mycnf) > 100:
|
||||
mw.writeFile(conf_file, mycnf)
|
||||
return True
|
||||
return True
|
||||
|
||||
def export_database(self, name, index):
|
||||
self.write_speed('done', '正在导出数据库')
|
||||
write_log("|-正在导出数据库{}...".format(name))
|
||||
conn = self.getMyConn()
|
||||
result = conn.execute("show databases")
|
||||
isError = self.isSqlError(result)
|
||||
if isError:
|
||||
err_msg = '数据库[{}]导出失败,{}!'.format(name, isError['msg'])
|
||||
self.state('databases', index, -1, err_msg)
|
||||
self.error(err_msg)
|
||||
return None
|
||||
|
||||
root = self.getDbConn('mysql', 'config').where(
|
||||
'id=?', (1,)).getField('mysql_root')
|
||||
|
||||
backup_path = mw.getRootDir() + '/backup'
|
||||
if not os.path.exists(backup_path):
|
||||
os.makedirs(backup_path, 384)
|
||||
|
||||
backup_name = backup_path + '/psync_import.sql.gz'
|
||||
if os.path.exists(backup_name):
|
||||
os.remove(backup_name)
|
||||
|
||||
root_dir = mw.getServerDir() + '/mysql'
|
||||
my_cnf = self.getConf('mysql')
|
||||
cmd = root_dir + "/bin/mysqldump --defaults-file=" + my_cnf + " --default-character-set=" + \
|
||||
self.getDatabaseCharacter(
|
||||
name) + " --force --opt \"" + name + "\" | gzip > " + backup_name
|
||||
mw.execShell(cmd)
|
||||
|
||||
self.mypass(False, root)
|
||||
if not os.path.exists(backup_name) or os.path.getsize(backup_name) < 30:
|
||||
if os.path.exists(backup_name):
|
||||
os.remove(backup_name)
|
||||
err_msg = '数据库[{}]导出失败!'.format(name)
|
||||
self.state('databases', index, -1, err_msg)
|
||||
self.error(err_msg)
|
||||
write_log("失败")
|
||||
return None
|
||||
write_log("成功")
|
||||
return backup_name
|
||||
|
||||
def send_database(self, dbInfo, index):
|
||||
# print(dbInfo)
|
||||
# 创建远程库
|
||||
# if not self.create_database(dbInfo, index):
|
||||
# return False
|
||||
|
||||
self.create_database(dbInfo, index)
|
||||
filename = self.export_database(dbInfo['name'], index)
|
||||
if not filename:
|
||||
return False
|
||||
|
||||
db_dir = '/www/backup/database'
|
||||
upload_file = db_dir + '/psync_import_{}.sql.gz'.format(dbInfo['name'])
|
||||
d = self.send('/files/exec_shell',
|
||||
{"shell": "rm -f " + upload_file, "path": "/www"}, 30)
|
||||
|
||||
print(d)
|
||||
if self.upload_file(filename, upload_file):
|
||||
|
||||
self.write_speed('done', '正在导入数据库')
|
||||
write_log("|-正在导入数据库{}...".format(dbInfo['name']))
|
||||
print(filename)
|
||||
|
||||
self.state('databases', index, -1, "数据传输失败")
|
||||
|
||||
def sync_database(self):
|
||||
data = getCfgData()
|
||||
databases = data['ready']['databases']
|
||||
for i in range(len(databases)):
|
||||
try:
|
||||
self.state('databases', i, 1)
|
||||
db = databases[i]
|
||||
|
||||
sp_msg = "|-迁移数据库: [{}]".format(db)
|
||||
self.write_speed('action', sp_msg)
|
||||
write_log(sp_msg)
|
||||
dbInfo = self.getDbInfo(db)
|
||||
dbInfo['accept'] = self.getDatabaseAccess(db)
|
||||
dbInfo['character'] = self.getDatabaseCharacter(db)
|
||||
print(dbInfo)
|
||||
if self.send_database(dbInfo, i):
|
||||
self.state('databases', i, 2)
|
||||
write_log("=" * 50)
|
||||
except:
|
||||
self.error(mw.getTracebackInfo())
|
||||
|
||||
def run(self):
|
||||
# 开始迁移
|
||||
# self.upload_file(
|
||||
# "/Users/midoks/Desktop/mwdev/backup/mysql-boost-5.7.39.tar.gz", "/tmp/mysql-boost-5.7.39.tar.gz")
|
||||
|
||||
# mw.CheckMyCnf()
|
||||
# self.sync_other()
|
||||
self.sync_site()
|
||||
# self.sync_database()
|
||||
# self.sync_ftp()
|
||||
self.sync_database()
|
||||
# self.sync_path()
|
||||
# self.write_speed('action', 'True')
|
||||
self.write_speed('action', 'True')
|
||||
write_log('|-所有项目迁移完成!')
|
||||
|
||||
|
||||
# 字节单位转换
|
||||
def toSize(size):
|
||||
d = ('b', 'KB', 'MB', 'GB', 'TB')
|
||||
s = d[0]
|
||||
for b in d:
|
||||
if size < 1024:
|
||||
return ("%.2f" % size) + ' ' + b
|
||||
size = size / 1024
|
||||
s = b
|
||||
return ("%.2f" % size) + ' ' + b
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'migration_api'
|
||||
|
||||
@@ -290,6 +696,9 @@ def checkArgs(data, ck=[]):
|
||||
|
||||
|
||||
def status():
|
||||
path = getServerDir() + '/config'
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
return 'start'
|
||||
|
||||
|
||||
@@ -417,6 +826,8 @@ def write_log(log_str):
|
||||
log_file = getServerDir() + '/sync.log'
|
||||
f = open(log_file, 'ab+')
|
||||
log_str += "\n"
|
||||
if __name__ == '__main__':
|
||||
print(log_str)
|
||||
f.write(log_str.encode('utf-8'))
|
||||
f.close()
|
||||
return True
|
||||
@@ -424,6 +835,10 @@ def write_log(log_str):
|
||||
|
||||
def bgProcessRun():
|
||||
data = getCfgData()
|
||||
|
||||
demo_url = 'http://127.0.0.1:7200'
|
||||
demo_key = 'HfJNKGP5RPqGvhIOyrwpXG4A2fTjSh9B'
|
||||
# api = classApi(demo_url, demo_key)
|
||||
api = classApi(data['url'], data['token'])
|
||||
api.run()
|
||||
return ''
|
||||
@@ -486,6 +901,7 @@ def getSpeed():
|
||||
except:
|
||||
return mw.returnJson(False, '正在准备..')
|
||||
sync_info = self.get_sync_info(None)
|
||||
print(sync_info)
|
||||
speed_info['all_total'] = sync_info['total']
|
||||
speed_info['all_speed'] = sync_info['speed']
|
||||
speed_info['total_time'] = speed_info['end_time'] - speed_info['time']
|
||||
|
||||
@@ -843,7 +843,6 @@ def setDbBackup():
|
||||
return data[1]
|
||||
|
||||
scDir = mw.getRunDir() + '/scripts/backup.py'
|
||||
|
||||
cmd = 'python3 ' + scDir + ' database ' + args['name'] + ' 3'
|
||||
os.system(cmd)
|
||||
return mw.returnJson(True, 'ok')
|
||||
@@ -904,10 +903,12 @@ def importDbExternal():
|
||||
sock = getSocketFile()
|
||||
|
||||
os.environ["MYSQL_PWD"] = pwd
|
||||
mysql_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p' + \
|
||||
pwd + ' ' + name + ' < ' + import_sql
|
||||
mysql_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p\"' + \
|
||||
pwd + '\" ' + name + ' < ' + import_sql
|
||||
|
||||
# print(mysql_cmd)
|
||||
rdata = mw.execShell(mysql_cmd)
|
||||
# print(rdata)
|
||||
if ext != 'sql':
|
||||
os.remove(import_sql)
|
||||
|
||||
|
||||
+29
-15
@@ -5,6 +5,7 @@
|
||||
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
|
||||
if sys.platform != 'darwin':
|
||||
os.chdir('/www/server/mdserver-web')
|
||||
@@ -50,7 +51,6 @@ class backupTools:
|
||||
mw.execShell(cmd)
|
||||
|
||||
endDate = time.strftime('%Y/%m/%d %X', time.localtime())
|
||||
|
||||
print(filename)
|
||||
if not os.path.exists(filename):
|
||||
log = "网站[" + name + "]备份失败!"
|
||||
@@ -83,6 +83,27 @@ class backupTools:
|
||||
if num < 1:
|
||||
break
|
||||
|
||||
def getConf(self, mtype='mysql'):
|
||||
path = mw.getServerDir() + '/' + mtype + '/etc/my.cnf'
|
||||
return path
|
||||
|
||||
# 数据库密码处理
|
||||
def mypass(self, act, root):
|
||||
conf_file = self.getConf('mysql')
|
||||
mw.execShell("sed -i '/user=root/d' {}".format(conf_file))
|
||||
mw.execShell("sed -i '/password=/d' {}".format(conf_file))
|
||||
if act:
|
||||
mycnf = mw.readFile(conf_file)
|
||||
src_dump = "[mysqldump]\n"
|
||||
sub_dump = src_dump + "user=root\npassword=\"{}\"\n".format(root)
|
||||
if not mycnf:
|
||||
return False
|
||||
mycnf = mycnf.replace(src_dump, sub_dump)
|
||||
if len(mycnf) > 100:
|
||||
mw.writeFile(conf_file, mycnf)
|
||||
return True
|
||||
return True
|
||||
|
||||
def backupDatabase(self, name, count):
|
||||
db_path = mw.getServerDir() + '/mysql'
|
||||
db_name = 'mysql'
|
||||
@@ -104,17 +125,11 @@ class backupTools:
|
||||
filename = backup_path + "/db_" + name + "_" + \
|
||||
time.strftime('%Y%m%d_%H%M%S', time.localtime()) + ".sql.gz"
|
||||
|
||||
import re
|
||||
mysql_root = mw.M('config').dbPos(db_path, db_name).where(
|
||||
"id=?", (1,)).getField('mysql_root')
|
||||
|
||||
mycnf = mw.readFile(db_path + '/etc/my.cnf')
|
||||
rep = "\[mysqldump\]\nuser=root"
|
||||
sea = "[mysqldump]\n"
|
||||
subStr = sea + "user=root\npassword=" + mysql_root + "\n"
|
||||
mycnf = mycnf.replace(sea, subStr)
|
||||
if len(mycnf) > 100:
|
||||
mw.writeFile(db_path + '/etc/my.cnf', mycnf)
|
||||
my_cnf = self.getConf('mysql')
|
||||
self.mypass(True, mysql_root)
|
||||
|
||||
# mw.execShell(db_path + "/bin/mysqldump --opt --default-character-set=utf8 " +
|
||||
# name + " | gzip > " + filename)
|
||||
@@ -125,8 +140,10 @@ class backupTools:
|
||||
# mw.execShell(db_path + "/bin/mysqldump --single-transaction --quick --default-character-set=utf8 " +
|
||||
# name + " | gzip > " + filename)
|
||||
|
||||
mw.execShell(db_path + "/bin/mysqldump --force --opt --default-character-set=utf8 " +
|
||||
name + " | gzip > " + filename)
|
||||
cmd = db_path + "/bin/mysqldump --defaults-file=" + my_cnf + " --force --opt --default-character-set=utf8 " + \
|
||||
name + " | gzip > " + filename
|
||||
# print(cmd)
|
||||
mw.execShell(cmd)
|
||||
|
||||
if not os.path.exists(filename):
|
||||
endDate = time.strftime('%Y/%m/%d %X', time.localtime())
|
||||
@@ -136,10 +153,7 @@ class backupTools:
|
||||
"----------------------------------------------------------------------------")
|
||||
return
|
||||
|
||||
mycnf = mw.readFile(db_path + '/etc/my.cnf')
|
||||
mycnf = mycnf.replace(subStr, sea)
|
||||
if len(mycnf) > 100:
|
||||
mw.writeFile(db_path + '/etc/my.cnf', mycnf)
|
||||
self.mypass(False, mysql_root)
|
||||
|
||||
endDate = time.strftime('%Y/%m/%d %X', time.localtime())
|
||||
outTime = time.time() - startTime
|
||||
|
||||
Reference in New Issue
Block a user