From f0f63a622f89cfd195e8802d0704a87d0b5a7fb4 Mon Sep 17 00:00:00 2001 From: Mr Chen Date: Fri, 25 Jan 2019 18:10:33 +0800 Subject: [PATCH] update --- class/core/crontab_api.py | 329 +++++++++++++++++++++++++- route/static/app/crontab.js | 334 ++++++++++++++++++++++++++- route/templates/default/crontab.html | 70 ++---- 3 files changed, 669 insertions(+), 64 deletions(-) diff --git a/class/core/crontab_api.py b/class/core/crontab_api.py index fbf8fd84b..cbaeae3e6 100755 --- a/class/core/crontab_api.py +++ b/class/core/crontab_api.py @@ -14,12 +14,14 @@ from flask import request class crontab_api: + field = 'id,name,type,where1,where_hour,where_minute,echo,addtime,status,save,backup_to,stype,sname,sbody,urladdress' + def __init__(self): pass ##### ----- start ----- ### def listApi(self): - _list = public.M('crontab').where('', ()).field('id,name,type,where1,where_hour,where_minute,echo,addtime,status,save,backup_to,stype,sname,sbody,urladdress').limit( + _list = public.M('crontab').where('', ()).field(self.field).limit( '0,5').order('id desc').select() data = [] @@ -71,12 +73,83 @@ class crontab_api: _ret['page'] = public.getPage(_page) return public.getJson(_ret) + # 获取指定任务数据 + def getCrondFindApi(self): + sid = request.form.get('id', '') + data = public.M('crontab').where( + 'id=?', (sid,)).field(self.field).find() + return public.getJson(data) + + def modifyCrondApi(self): + sid = request.form.get('id', '') + iname = request.form.get('name', '') + stype = request.form.get('type', '') + week = request.form.get('week', '') + where1 = request.form.get('where1', '') + hour = request.form.get('hour', '') + minute = request.form.get('minute', '') + save = request.form.get('save', '') + backup_to = request.form.get('backup_to', '') + stype = request.form.get('stype', '') + sname = request.form.get('sname', '') + sbody = request.form.get('sbody', '') + urladdress = request.form.get('urladdress', '') + + if len(iname) < 1: + return public.returnJson(False, '任务名称不能为空!') + + params = { + 'name': iname, + 'type': stype, + 'week': week, + 'where1': where1, + 'hour': hour, + 'minute': minute, + 'save': save, + 'backup_to': backup_to, + 'stype': stype, + 'sname': sname, + 'sbody': sbody, + 'urladdress': urladdress, + } + cuonConfig, get, name = self.getCrondCycle(params) + cronInfo = public.M('crontab').where( + 'id=?', (sid,)).field(self.field).find() + del(cronInfo['id']) + del(cronInfo['addtime']) + cronInfo['name'] = get['name'] + cronInfo['type'] = get['type'] + cronInfo['where1'] = get['where1'] + cronInfo['where_hour'] = get['hour'] + cronInfo['where_minute'] = get['minute'] + cronInfo['save'] = get['save'] + cronInfo['backup_to'] = get['backup_to'] + cronInfo['sbody'] = get['sbody'] + cronInfo['urladdress'] = get['urladdress'] + + addData = public.M('crontab').where('id=?', (sid,)).save('name,type,where1,where_hour,where_minute,save,backup_to,sbody,urladdress', (get[ + 'name'], get['type'], get['where1'], get['hour'], get['minute'], get['save'], get['backup_to'], get['sbody'], get['urladdress'])) + + self.removeForCrond(cronInfo['echo']) + self.syncToCrond(cronInfo) + public.writeLog('计划任务', '修改计划任务[' + cronInfo['name'] + ']成功') + return public.returnJson(True, '修改成功') + def logsApi(self): - return public.returnJson(False, '添加失败') + sid = request.form.get('id', '') + echo = public.M('crontab').where("id=?", (sid,)).field('echo').find() + print echo + logFile = public.getServerDir() + '/cron/' + echo['echo'] + '.log' + print logFile + if not os.path.exists(logFile): + return public.returnJson(False, '当前日志为空!') + log = public.getNumLines(logFile, 2000) + return public.returnJson(True, log) def addApi(self): - name = request.form.get('name', '') - type = request.form.get('type', '') + iname = request.form.get('name', '') + stype = request.form.get('type', '') + week = request.form.get('week', '') where1 = request.form.get('where1', '') hour = request.form.get('hour', '') minute = request.form.get('minute', '') @@ -87,12 +160,45 @@ class crontab_api: sBody = request.form.get('sBody', '') urladdress = request.form.get('urladdress', '') - if len(name) < 1: + if len(iname) < 1: return public.returnJson(False, '任务名称不能为空!') - addData = public.M('crontab').add('name,type,where1,where_hour,where_minute,echo,addtime,status,save,backup_to,stype,sname,sbody,urladdress', - (name, type, where1, hour, minute, name, - time.strftime('%Y-%m-%d %X', time.localtime()), 1, save, backupTo, sType, sName, sBody, urladdress)) + params = { + 'name': iname, + 'type': stype, + 'week': week, + 'where1': where1, + 'hour': hour, + 'minute': minute, + 'save': save, + 'backupTo': backupTo, + 'sType': sType, + 'sName': sName, + 'sBody': sBody, + 'urladdress': urladdress, + } + + # print params + cuonConfig, _params, name = self.getCrondCycle(params) + cronPath = public.getServerDir() + '/cron' + + cronName = self.getShell(params) + # print cuonConfig, _params, name + # print cronPath, cronName + + if type(cronName) == dict: + return cronName + + cuonConfig += ' ' + cronPath + '/' + cronName + \ + ' >> ' + cronPath + '/' + cronName + '.log 2>&1' + wRes = self.writeShell(cuonConfig) + + if type(wRes) != bool: + return wRes + + self.crondReload() + addData = public.M('crontab').add(self.field, (iname, stype, where1, hour, minute, cronName, time.strftime( + '%Y-%m-%d %X', time.localtime()), 1, save, backupTo, sType, sName, sBody, urladdress)) if addData > 0: return public.returnJson(True, '添加成功') return public.returnJson(False, '添加失败') @@ -104,6 +210,9 @@ class crontab_api: return public.returnJson(True, '添加成功') except Exception as e: return public.returnJson(False, '删除失败') + + def delLogsApi(self): + return public.returnJson(True, '删除成功') ##### ----- start ----- ### # 转换大写星期 @@ -121,3 +230,207 @@ class crontab_api: return wheres[num] except: return '' + + def getCrondCycle(self, params): + cuonConfig = '' + name = '' + if params['type'] == "day": + cuonConfig = self.getDay(params) + name = '每天' + elif params['type'] == "day-n": + cuonConfig = self.getDay_N(params) + name = public.getInfo('每{1}天', (params['where1'],)) + elif params['type'] == "hour": + cuonConfig = self.getHour(params) + name = '每小时' + elif params['type'] == "hour-n": + cuonConfig = self.getHour_N(params) + name = '每小时' + elif params['type'] == "minute-n": + cuonConfig = self.minute_N(params) + elif params['type'] == "week": + params['where1'] = params['week'] + cuonConfig = self.week(params) + elif params['type'] == "month": + cuonConfig = self.month(params) + return cuonConfig, params, name + + # 取任务构造Day + def getDay(self, param): + cuonConfig = "{0} {1} * * * ".format(param['minute'], param['hour']) + return cuonConfig + # 取任务构造Day_n + + def getDay_N(self, param): + cuonConfig = "{0} {1} */{2} * * ".format( + param['minute'], param['hour'], param['where1']) + return cuonConfig + + # 取任务构造Hour + def getHour(self, param): + cuonConfig = "{0} * * * * ".format(param['minute']) + return cuonConfig + + # 取任务构造Hour-N + def getHour_N(self, param): + cuonConfig = "{0} */{1} * * * ".format( + param['minute'], param['where1']) + return cuonConfig + + # 取任务构造Minute-N + def minute_N(self, param): + cuonConfig = "*/{0} * * * * ".format(param['where1']) + return cuonConfig + + # 取任务构造week + def week(self, param): + cuonConfig = "{0} {1} * * {2}".format( + param['minute'], param['hour'], param['week']) + return cuonConfig + + # 取任务构造Month + def month(self, param): + cuonConfig = "{0} {1} {2} * * ".format( + param['minute'], param['hour'], param['where1']) + return cuonConfig + + # 取执行脚本 + def getShell(self, param): + # try: + stype = param['stype'] + if stype == 'toFile': + shell = param.sFile + else: + head = "#!/bin/bash\nPATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin\nexport PATH\n" + log = '.log' + + wheres = { + 'path': head + "python " + public.getServerDir() + "/panel/script/backup.py path " + param['sname'] + " " + str(param['save']), + 'site': head + "python " + public.getServerDir() + "/panel/script/backup.py site " + param['sname'] + " " + str(param['save']), + 'database': head + "python " + public.getServerDir() + "/panel/script/backup.py database " + param['sname'] + " " + str(param['save']), + 'logs': head + "python " + public.getServerDir() + "/panel/script/logsBackup " + param['sname'] + log + " " + str(param['save']), + 'rememory': head + "/bin/bash " + public.getServerDir() + '/panel/script/rememory.sh' + } + if param['backup_to'] != 'localhost': + cfile = public.getServerDir() + "/panel/plugin/" + param[ + 'backup_to'] + "/" + param['backup_to'] + "_main.py" + if not os.path.exists(cfile): + cfile = public.getServerDir() + "/panel/script/backup_" + \ + param['backup_to'] + ".py" + wheres = { + 'path': head + "python " + cfile + " path " + param['sname'] + " " + str(param['save']), + 'site': head + "python " + cfile + " site " + param['sname'] + " " + str(param['save']), + 'database': head + "python " + cfile + " database " + param['sname'] + " " + str(param['save']), + 'logs': head + "python " + public.getServerDir() + "/panel/script/logsBackup " + param['sname'] + log + " " + str(param['save']), + 'rememory': head + "/bin/bash " + public.getServerDir() + '/panel/script/rememory.sh' + } + + try: + shell = wheres[stype] + except: + if stype == 'toUrl': + shell = head + "curl -sS --connect-timeout 10 -m 60 '" + \ + param['urladdress'] + "'" + else: + shell = head + param['sBody'].replace("\r\n", "\n") + + shell += ''' +echo "----------------------------------------------------------------------------" +endDate=`date +"%Y-%m-%d %H:%M:%S"` +echo "★[$endDate] Successful" +echo "----------------------------------------------------------------------------" +''' + cronPath = public.getServerDir() + '/cron' + if not os.path.exists(cronPath): + public.execShell('mkdir -p ' + cronPath) + if not 'echo' in param: + cronName = public.md5(public.md5(str(time.time()) + '_mw')) + else: + cronName = param['echo'] + file = cronPath + '/' + cronName + public.writeFile(file, self.checkScript(shell)) + public.execShell('chmod 750 ' + file) + return cronName + + # 检查脚本 + def checkScript(self, shell): + keys = ['shutdown', 'init 0', 'mkfs', 'passwd', + 'chpasswd', '--stdin', 'mkfs.ext', 'mke2fs'] + for key in keys: + shell = shell.replace(key, '[***]') + return shell + + # 将Shell脚本写到文件 + def writeShell(self, config): + u_file = '/var/spool/cron/crontabs/root' + if not os.path.exists(u_file): + file = '/var/spool/cron/root' + if public.isAppleSystem(): + file = '/etc/crontab' + else: + file = u_file + + if not os.path.exists(file): + public.writeFile(file, '') + conf = public.readFile(file) + conf += config + "\n" + if public.writeFile(file, conf): + if not os.path.exists(u_file): + public.execShell("chmod 600 '" + file + + "' && chown root.root " + file) + else: + public.execShell("chmod 600 '" + file + + "' && chown root.crontab " + file) + return True + return public.returnJson(False, '文件写入失败,请检查是否开启系统加固功能!') + + # 重载配置 + def crondReload(self): + if public.isAppleSystem(): + if os.path.exists('/etc/crontab'): + pass + # public.execShell('/usr/sbin/cron restart') + else: + if os.path.exists('/etc/init.d/crond'): + public.execShell('/etc/init.d/crond reload') + elif os.path.exists('/etc/init.d/cron'): + public.execShell('service cron restart') + else: + public.execShell("systemctl reload crond") + + # 从crond删除 + def removeForCrond(self, echo): + u_file = '/var/spool/cron/crontabs/root' + if not os.path.exists(u_file): + file = '/var/spool/cron/root' + if public.isAppleSystem(): + file = '/etc/crontab' + else: + file = u_file + conf = public.readFile(file) + rep = ".+" + str(echo) + ".+\n" + conf = re.sub(rep, "", conf) + if not public.writeFile(file, conf): + return False + self.crondReload() + return True + + def syncToCrond(self, cronInfo): + if 'status' in cronInfo: + if cronInfo['status'] == 0: + return False + if 'where_hour' in cronInfo: + cronInfo['hour'] = cronInfo['where_hour'] + cronInfo['minute'] = cronInfo['where_minute'] + cronInfo['week'] = cronInfo['where1'] + cuonConfig, cronInfo, name = self.getCrondCycle(cronInfo) + cronPath = public.getServerDir() + '/cron' + cronName = self.getShell(cronInfo) + if type(cronName) == dict: + return cronName + cuonConfig += ' ' + cronPath + '/' + cronName + \ + ' >> ' + cronPath + '/' + cronName + '.log 2>&1' + wRes = self.writeShell(cuonConfig) + if type(wRes) != bool: + return False + self.crondReload() diff --git a/route/static/app/crontab.js b/route/static/app/crontab.js index 8a0273fee..df26ba71c 100755 --- a/route/static/app/crontab.js +++ b/route/static/app/crontab.js @@ -1,3 +1,13 @@ +function isURL(str_url){ + var strRegex = '^(https|http|ftp|rtsp|mms)?://.+'; + var re=new RegExp(strRegex); + if (re.test(str_url)){ + return (true); + }else{ + return (false); + } +} + var num = 0; //查看任务日志 function getLogs(id){ @@ -6,7 +16,7 @@ function getLogs(id){ $.post('/crontab/logs', data, function(rdata){ layer.closeAll(); if(!rdata.status) { - layer.msg(rdata.msg,{icon:2}); + layer.msg(rdata.msg,{icon:2, time:2000}); return; }; layer.open({ @@ -16,9 +26,9 @@ function getLogs(id){ shadeClose:false, closeBtn:2, content:'
' - +'
'
+					+'
'
 					+'
' - +'' + +'' +'' +'
' +'
' @@ -27,7 +37,7 @@ function getLogs(id){ setTimeout(function(){ $("#crontab-log").text(rdata.msg); },200); - }); + },'json'); } function getCronData(){ @@ -54,7 +64,7 @@ function getCronData(){ "+rdata.data[i].addtime+"\ \ 执行 | \ - 脚本 | \ + 编辑 | \ 日志 | \ 删除\ \ @@ -67,12 +77,12 @@ function getCronData(){ //执行任务脚本 function startTask(id){ - layer.msg(lan.public.the,{icon:16,time:0,shade: [0.3, '#000']}); + layer.msg('正在处理,请稍候...',{icon:16,time:0,shade: [0.3, '#000']}); var data='id='+id; - $.post('/crontab?action=StartTask',data,function(rdata){ + $.post('/crontab/start_task',data,function(rdata){ layer.closeAll(); layer.msg(rdata.msg,{icon:rdata.status?1:2}); - }); + },'json'); } @@ -80,7 +90,7 @@ function startTask(id){ function closeLogs(id){ layer.msg(lan.public.the,{icon:16,time:0,shade: [0.3, '#000']}); var data='id='+id; - $.post('/crontab?action=DelLogs',data,function(rdata){ + $.post('/crontab/del_logs',data,function(rdata){ layer.closeAll(); layer.msg(rdata.msg,{icon:rdata.status?1:2}); }); @@ -244,7 +254,7 @@ function planAdd(){ var urladdress = $("#urladdress").val(); if(sType == 'toUrl'){ - if(!IsURL(urladdress)){ + if(!isURL(urladdress)){ layer.msg(lan.crontab.input_url_err,{icon:2}); $("implement textarea[name='urladdress']").focus(); return; @@ -283,6 +293,10 @@ function planAdd(){ layer.msg(lan.public.the_add,{icon:16,time:0,shade: [0.3, '#000']}); var data= $("#set-Config").serialize() + '&sBody='+sBody + '&urladdress=' + urladdress; $.post('/crontab/add',data,function(rdata){ + if(!rdata.status) { + layer.msg(rdata.msg,{icon:2, time:2000}); + return; + } layer.closeAll(); layer.msg(rdata.msg,{icon:rdata.status?1:2}); getCronData(); @@ -479,6 +493,306 @@ function toBackup(type){ } +// 编辑计划任务 +function editTaskInfo(id){ + layer.msg('正在获取,请稍候...',{icon:16,time:0,shade: [0.3, '#000']}); + $.post('/crontab/get_crond_find',{id:id},function(rdata){ + layer.closeAll(); + var sTypeName = '',sTypeDom = '',cycleName = '',cycleDom = '',weekName = '',weekDom = '',sNameName ='',sNameDom = '',backupsName = '',backupsDom =''; + obj = { + from:{ + id:rdata.id, + name: rdata.name, + type: rdata.type, + where1: rdata.where1, + hour: rdata.where_hour, + minute: rdata.where_minute, + week: rdata.where1, + stype: rdata.stype, + sbody: rdata.sbody, + sname: rdata.sname, + backup_to: rdata.backup_to, + save: rdata.save, + urladdress: rdata.urladdress, + }, + sTypeArray:[['toShell','Shell脚本'],['site','备份网站'],['database','备份数据库'],['logs','日志切割'],['path','备份目录'],['rememory','释放内存'],['toUrl','访问URL']], + cycleArray:[['day','每天'],['day-n','N天'],['hour','每小时'],['hour-n','N小时'],['minute-n','N分钟'],['week','每星期'],['month','每月']], + weekArray:[[1,'周一'],[2,'周二'],[3,'周三'],[4,'周四'],[5,'周五'],[6,'周六'],[7,'周日']], + sNameArray:[], + backupsArray:[], + create:function(callback){ + console.log(obj); + for(var i = 0; i '+ obj['sTypeArray'][i][1] +''; + } + + for(var i = 0; i '+ obj['cycleArray'][i][1] +''; + } + + for(var i = 0; i '+ obj['weekArray'][i][1] +''; + } + + if(obj.from.stype == 'site' || obj.from.stype == 'database' || obj.from.stype == 'path' || obj.from.stype == 'logs'){ + $.post('/crontab?action=GetDataList',{type:obj.from.stype == 'databases'?'database':'sites'},function(rdata){ + obj.sNameArray = rdata.data; + obj.sNameArray.unshift({name:'ALL',ps:'所有'}); + obj.backupsArray = rdata.orderOpt; + obj.backupsArray.unshift({name:'服务器磁盘',value:'localhost'}); + for(var i = 0; i '+ obj['sNameArray'][i]['ps'] +''; + } + for(var i = 0; i '+ obj['backupsArray'][i]['name'] +''; + } + callback(); + }); + }else{ + callback(); + } + } + }; + obj.create(function(){ + layer.open({ + type:1, + title:'编辑计划任务-['+rdata.name+']', + area: ['850px','450px'], + skin:'layer-create-content', + shadeClose:false, + closeBtn:2, + content:'
\ +
\ + 任务类型\ + \ +
\ +
\ + 任务名称\ +
\ +
\ +
\ + 执行周期\ + \ +
\ + \ +
\ +
\ +
\ +
\ +
\ + \ +
\ + 脚本内容\ +
\ +
\ +
\ + 提示\ +
释放PHP、MYSQL、PURE-FTPD、APACHE、NGINX的内存占用,建议在每天半夜执行!
\ +
\ +
\ + URL地址\ +
\ +
\ +
\ +
保存编辑
\ +
\ +
' + }); + setTimeout(function(){ + if(obj.from.stype == 'toShell'){ + $('.site_list').hide(); + }else if(obj.from.stype == 'rememory'){ + $('.site_list').hide(); + }else if( obj.from.stype == 'toUrl'){ + $('.site_list').hide(); + }else{ + $('.site_list').show(); + } + + $('.sName_create').blur(function () { + obj.from.name = $(this).val(); + }); + $('.where1_create').blur(function () { + obj.from.where1 = $(this).val(); + }); + + $('.hour_create').blur(function () { + obj.from.hour = $(this).val(); + }); + + $('.minute_create').blur(function () { + obj.from.minute = $(this).val(); + }); + + $('.save_create').blur(function () { + obj.from.save = $(this).val(); + }); + + $('.sBody_create').blur(function () { + obj.from.sBody = $(this).val(); + }); + $('.url_create').blur(function () { + obj.from.urladdress = $(this).val(); + }); + + $('[aria-labelledby="cycle"] a').unbind().click(function () { + $('.cycle_btn').find('b').attr('val',$(this).attr('value')).html($(this).html()); + var type = $(this).attr('value'); + switch(type){ + case 'day': + $('.week_btn').hide(); + $('.where1_input').hide(); + $('.hour_input').show().find('input').val('1'); + $('.minute_input').show().find('input').val('30'); + obj.from.week = ''; + obj.from.type = ''; + obj.from.hour = 1; + obj.from.minute = 30; + break; + case 'day-n': + $('.week_btn').hide(); + $('.where1_input').show().find('input').val('1'); + $('.hour_input').show().find('input').val('1'); + $('.minute_input').show().find('input').val('30'); + obj.from.week = ''; + obj.from.where1 = 1; + obj.from.hour = 1; + obj.from.minute = 30; + break; + case 'hour': + $('.week_btn').hide(); + $('.where1_input').hide(); + $('.hour_input').hide(); + $('.minute_input').show().find('input').val('30'); + obj.from.week = ''; + obj.from.where1 = ''; + obj.from.hour = ''; + obj.from.minute = 30; + break; + case 'hour-n': + $('.week_btn').hide(); + $('.where1_input').hide(); + $('.hour_input').show().find('input').val('1'); + $('.minute_input').show().find('input').val('30'); + obj.from.week = ''; + obj.from.where1 = ''; + obj.from.hour = 1; + obj.from.minute = 30; + break; + case 'minute-n': + $('.week_btn').hide(); + $('.where1_input').hide(); + $('.hour_input').hide(); + $('.minute_input').show(); + obj.from.week = ''; + obj.from.where1 = ''; + obj.from.hour = ''; + obj.from.minute = 30; + break; + case 'week': + $('.week_btn').show(); + $('.where1_input').hide(); + $('.hour_input').show(); + $('.minute_input').show(); + obj.from.week = 1; + obj.from.where1 = ''; + obj.from.hour = 1; + obj.from.minute = 30; + break; + case 'month': + $('.week_btn').hide(); + $('.where1_input').show(); + $('.hour_input').show(); + $('.minute_input').show(); + obj.from.week = ''; + obj.from.where1 = 1; + obj.from.hour = 1; + obj.from.minute = 30; + break; + } + obj.from.type = $(this).attr('value'); + }); + + $('[aria-labelledby="week"] a').unbind().click(function () { + $('.week_btn').find('b').attr('val',$(this).attr('value')).html($(this).html()); + obj.from.week = $(this).attr('value'); + }); + + $('[aria-labelledby="backupTo"] a').unbind().click(function () { + $('.backup_btn').find('b').attr('val',$(this).attr('value')).html($(this).html()); + obj.from.backupTo = $(this).attr('value'); + }); + $('.plan-submits').unbind().click(function(){ + if(obj.from.type == 'hour-n'){ + obj.from.where1 = obj.from.hour; + obj.from.hour = ''; + }else if(obj.from.type == 'minute-n'){ + obj.from.where1 = obj.from.minute; + obj.from.minute = ''; + } + layer.msg('正在保存编辑内容,请稍后...',{icon:16,time:0,shade: [0.3, '#000']}); + $.post('/crontab/modify_crond',obj.from,function(rdata){ + layer.closeAll(); + getCronData(); + layer.msg(rdata.msg,{icon:rdata.status?1:2}); + },'json'); + }); + },100); + }); + },'json'); +} + + //下拉菜单名称 function getselectname(){ $(".dropdown ul li a").click(function(){ diff --git a/route/templates/default/crontab.html b/route/templates/default/crontab.html index 27c8baa10..04c25c996 100755 --- a/route/templates/default/crontab.html +++ b/route/templates/default/crontab.html @@ -50,58 +50,36 @@
-
小时
-
分钟
+
+ + 小时 +
+
+ + 分钟 +
@@ -109,7 +87,7 @@
-
添加任务
+
添加任务
  • 当添加完备份任务,应该手动运行一次,并检查备份包是否完整
  • @@ -137,7 +115,7 @@

    任务列表