diff --git a/data/db.py b/class/db.py similarity index 100% rename from data/db.py rename to class/db.py diff --git a/class/public.py b/class/public.py index 32eade083..82f170058 100755 --- a/class/public.py +++ b/class/public.py @@ -13,16 +13,15 @@ import re import hashlib -def getRunDir(): - return os.getcwd() - -runDir = getRunDir() -print runDir + "/class/" -sys.path.append(runDir + "/class/") +sys.path.append(os.getcwd() + "/class/") import db from random import Random -from flask import jsonify +# from flask import jsonify + + +def getRunDir(): + return os.getcwd() def M(table): diff --git a/class/system.py b/class/system.py new file mode 100755 index 000000000..99e6d55cd --- /dev/null +++ b/class/system.py @@ -0,0 +1,634 @@ +#coding: utf-8 +# +------------------------------------------------------------------- +# | 宝塔Linux面板 x3 +# +------------------------------------------------------------------- +# | Copyright (c) 2015-2016 宝塔软件(http://bt.cn) All rights reserved. +# +------------------------------------------------------------------- +# | Author: 黄文良 <287962566@qq.com> +# +------------------------------------------------------------------- +import psutil,web,time,os,public,re +class system: + setupPath = None; + pids = None + def __init__(self): + self.setupPath = '/www/server'; + + def GetConcifInfo(self,get=None): + #取环境配置信息 + if not hasattr(web.ctx.session, 'config'): + web.ctx.session.config = public.M('config').where("id=?",('1',)).field('webserver,sites_path,backup_path,status,mysql_root').find(); + if not hasattr(web.ctx.session.config,'email'): + web.ctx.session.config['email'] = public.M('users').where("id=?",('1',)).getField('email'); + data = {} + data = web.ctx.session.config + data['webserver'] = web.ctx.session.config['webserver'] + #PHP版本 + phpVersions = ('52','53','54','55','56','70','71','72','73','74') + + data['php'] = [] + + for version in phpVersions: + tmp = {} + tmp['setup'] = os.path.exists(self.setupPath + '/php/'+version+'/bin/php'); + if tmp['setup']: + phpConfig = self.GetPHPConfig(version) + tmp['version'] = version + tmp['max'] = phpConfig['max'] + tmp['maxTime'] = phpConfig['maxTime'] + tmp['pathinfo'] = phpConfig['pathinfo'] + tmp['status'] = os.path.exists('/tmp/php-cgi-'+version+'.sock') + data['php'].append(tmp) + + tmp = {} + data['webserver'] = '' + serviceName = 'nginx' + tmp['setup'] = False + phpversion = "54" + phpport = '888'; + pstatus = False; + pauth = False; + if os.path.exists(self.setupPath+'/nginx'): + data['webserver'] = 'nginx' + serviceName = 'nginx' + tmp['setup'] = os.path.exists(self.setupPath +'/nginx/sbin/nginx'); + configFile = self.setupPath + '/nginx/conf/nginx.conf'; + try: + if os.path.exists(configFile): + conf = public.readFile(configFile); + rep = "listen\s+([0-9]+)\s*;"; + rtmp = re.search(rep,conf); + if rtmp: + phpport = rtmp.groups()[0]; + + if conf.find('AUTH_START') != -1: pauth = True; + if conf.find(self.setupPath + '/stop') == -1: pstatus = True; + configFile = self.setupPath + '/nginx/conf/enable-php.conf'; + conf = public.readFile(configFile); + rep = "php-cgi-([0-9]+)\.sock"; + rtmp = re.search(rep,conf); + if rtmp: + phpversion = rtmp.groups()[0]; + except: + pass; + + elif os.path.exists(self.setupPath+'/apache'): + data['webserver'] = 'apache' + serviceName = 'httpd' + tmp['setup'] = os.path.exists(self.setupPath +'/apache/bin/httpd'); + configFile = self.setupPath + '/apache/conf/extra/httpd-vhosts.conf'; + try: + if os.path.exists(configFile): + conf = public.readFile(configFile); + rep = "php-cgi-([0-9]+)\.sock"; + rtmp = re.search(rep,conf); + if rtmp: + phpversion = rtmp.groups()[0]; + rep = "Listen\s+([0-9]+)\s*\n"; + rtmp = re.search(rep,conf); + if rtmp: + phpport = rtmp.groups()[0]; + if conf.find('AUTH_START') != -1: pauth = True; + if conf.find(self.setupPath + '/stop') == -1: pstatus = True; + except: + pass + + + tmp['type'] = data['webserver'] + tmp['version'] = public.readFile(self.setupPath + '/'+data['webserver']+'/version.pl'); + tmp['status'] = False + result = public.ExecShell('/etc/init.d/' + serviceName + ' status') + if result[0].find('running') != -1: tmp['status'] = True + data['web'] = tmp + + tmp = {} + vfile = self.setupPath + '/phpmyadmin/version.pl'; + tmp['version'] = public.readFile(vfile); + tmp['setup'] = os.path.exists(vfile); + tmp['status'] = pstatus; + tmp['phpversion'] = phpversion; + tmp['port'] = phpport; + tmp['auth'] = pauth; + data['phpmyadmin'] = tmp; + + tmp = {} + tmp['setup'] = os.path.exists('/etc/init.d/tomcat'); + tmp['status'] = False + if tmp['setup']: + if os.path.exists('/www/server/tomcat/logs/catalina-daemon.pid'): + tmp['status'] = self.getPid('jsvc') + if not tmp['status']: + tmp['status'] = self.getPid('java') + tmp['version'] = public.readFile(self.setupPath + '/tomcat/version.pl'); + data['tomcat'] = tmp; + + tmp = {} + tmp['setup'] = os.path.exists(self.setupPath +'/mysql/bin/mysql'); + tmp['version'] = public.readFile(self.setupPath + '/mysql/version.pl'); + tmp['status'] = os.path.exists('/tmp/mysql.sock') + data['mysql'] = tmp + + tmp = {} + tmp['setup'] = os.path.exists(self.setupPath +'/redis/runtest'); + tmp['status'] = os.path.exists('/var/run/redis_6379.pid'); + data['redis'] = tmp; + + tmp = {} + tmp['setup'] = os.path.exists('/usr/local/memcached/bin/memcached'); + tmp['status'] = os.path.exists('/var/run/memcached.pid'); + data['memcached'] = tmp; + + tmp = {} + tmp['setup'] = os.path.exists(self.setupPath +'/pure-ftpd/bin/pure-pw'); + tmp['version'] = public.readFile(self.setupPath + '/pure-ftpd/version.pl'); + tmp['status'] = os.path.exists('/var/run/pure-ftpd.pid') + data['pure-ftpd'] = tmp + data['panel'] = self.GetPanelInfo() + data['systemdate'] = public.ExecShell('date +"%Y-%m-%d %H:%M:%S %Z %z"')[0].strip(); + + return data + + + #名取PID + def getPid(self,pname): + try: + if not self.pids: self.pids = psutil.pids() + for pid in self.pids: + if psutil.Process(pid).name() == pname: return True; + return False + except: return False + + #检测指定进程是否存活 + def checkProcess(self,pid): + try: + if not self.pids: self.pids = psutil.pids() + if int(pid) in self.pids: return True + return False; + except: return False + + + def GetPanelInfo(self,get=None): + #取面板配置 + address = public.GetLocalIp() + try: + try: + port = web.ctx.host.split(':')[1] + except: + port = public.readFile('data/port.pl') + except: + port = '8888'; + domain = '' + if os.path.exists('data/domain.conf'): + domain = public.readFile('data/domain.conf'); + + autoUpdate = '' + if os.path.exists('data/autoUpdate.pl'): autoUpdate = 'checked'; + limitip = '' + if os.path.exists('data/limitip.conf'): limitip = public.readFile('data/limitip.conf'); + + templates = [] + for template in os.listdir('templates/'): + if os.path.isdir('templates/' + template): templates.append(template); + template = public.readFile('data/templates.pl'); + + check502 = ''; + if os.path.exists('data/502Task.pl'): check502 = 'checked'; + return {'port':port,'address':address,'domain':domain,'auto':autoUpdate,'502':check502,'limitip':limitip,'templates':templates,'template':template} + + def GetPHPConfig(self,version): + #取PHP配置 + file = self.setupPath + "/php/"+version+"/etc/php.ini" + phpini = public.readFile(file) + file = self.setupPath + "/php/"+version+"/etc/php-fpm.conf" + phpfpm = public.readFile(file) + data = {} + try: + rep = "upload_max_filesize\s*=\s*([0-9]+)M" + tmp = re.search(rep,phpini).groups() + data['max'] = tmp[0] + except: + data['max'] = '50' + try: + rep = "request_terminate_timeout\s*=\s*([0-9]+)\n" + tmp = re.search(rep,phpfpm).groups() + data['maxTime'] = tmp[0] + except: + data['maxTime'] = 0 + + try: + rep = ur"\n;*\s*cgi\.fix_pathinfo\s*=\s*([0-9]+)\s*\n" + tmp = re.search(rep,phpini).groups() + + if tmp[0] == '1': + data['pathinfo'] = True + else: + data['pathinfo'] = False + except: + data['pathinfo'] = False + + return data + + + def GetSystemTotal(self,get,interval = 1): + #取系统统计信息 + data = self.GetMemInfo(); + cpu = self.GetCpuInfo(interval); + data['cpuNum'] = cpu[1]; + data['cpuRealUsed'] = cpu[0]; + data['time'] = self.GetBootTime(); + data['system'] = self.GetSystemVersion(); + data['isuser'] = public.M('users').where('username=?',('admin',)).count(); + data['version'] = web.ctx.session.version; + return data + + def GetLoadAverage(self,get): + c = os.getloadavg() + data = {}; + data['one'] = float(c[0]); + data['five'] = float(c[1]); + data['fifteen'] = float(c[2]); + data['max'] = psutil.cpu_count() * 2; + data['limit'] = data['max']; + data['safe'] = data['max'] * 0.75; + return data; + + def GetAllInfo(self,get): + data = {} + data['load_average'] = self.GetLoadAverage(get); + data['title'] = self.GetTitle(); + data['network'] = self.GetNetWorkApi(get); + data['panel_status'] = not os.path.exists('/www/server/panel/data/close.pl'); + import firewalls + ssh_info = firewalls.firewalls().GetSshInfo(None) + data['enable_ssh_status'] = ssh_info['status'] + data['disable_ping_status'] = not ssh_info['ping'] + data['time'] = self.GetBootTime(); + #data['system'] = self.GetSystemVersion(); + #data['mem'] = self.GetMemInfo(); + data['version'] = web.ctx.session.version; + return data; + + def GetTitle(self): + titlePl = 'data/title.pl'; + title = '宝塔Linux面板'; + if os.path.exists(titlePl): title = public.readFile(titlePl).strip(); + return title; + + def GetSystemVersion(self): + #取操作系统版本 + import public + version = public.readFile('/etc/redhat-release') + if not version: + version = public.readFile('/etc/issue').strip().split("\n")[0].replace('\\n','').replace('\l','').strip(); + else: + version = version.replace('release ','').strip(); + return version + + def GetBootTime(self): + #取系统启动时间 + import public,math + conf = public.readFile('/proc/uptime').split() + tStr = float(conf[0]) + min = tStr / 60; + hours = min / 60; + days = math.floor(hours / 24); + hours = math.floor(hours - (days * 24)); + min = math.floor(min - (days * 60 * 24) - (hours * 60)); + return public.getMsg('SYS_BOOT_TIME',(str(int(days)),str(int(hours)),str(int(min)))) + + def GetCpuInfo(self,interval = 1): + #取CPU信息 + cpuCount = psutil.cpu_count() + used = psutil.cpu_percent(interval=interval) + return used,cpuCount + + def GetMemInfo(self,get=None): + #取内存信息 + mem = psutil.virtual_memory() + memInfo = {'memTotal':mem.total/1024/1024,'memFree':mem.free/1024/1024,'memBuffers':mem.buffers/1024/1024,'memCached':mem.cached/1024/1024} + memInfo['memRealUsed'] = memInfo['memTotal'] - memInfo['memFree'] - memInfo['memBuffers'] - memInfo['memCached'] + return memInfo + + def GetDiskInfo(self,get=None): + return self.GetDiskInfo2(); + #取磁盘分区信息 + diskIo = psutil.disk_partitions(); + diskInfo = [] + + for disk in diskIo: + if disk[1] == '/mnt/cdrom':continue; + if disk[1] == '/boot':continue; + tmp = {} + tmp['path'] = disk[1] + tmp['size'] = psutil.disk_usage(disk[1]) + diskInfo.append(tmp) + return diskInfo + + def GetDiskInfo2(self): + #取磁盘分区信息 + temp = public.ExecShell("df -h -P|grep '/'|grep -v tmpfs")[0]; + tempInodes = public.ExecShell("df -i -P|grep '/'|grep -v tmpfs")[0]; + temp1 = temp.split('\n'); + tempInodes1 = tempInodes.split('\n'); + diskInfo = []; + n = 0 + cuts = ['/mnt/cdrom','/boot','/boot/efi','/dev','/dev/shm','/run/lock','/run','/run/shm','/run/user']; + for tmp in temp1: + n += 1 + inodes = tempInodes1[n-1].split(); + disk = tmp.split(); + if len(disk) < 5: continue; + if disk[1].find('M') != -1: continue; + if disk[1].find('K') != -1: continue; + if len(disk[5].split('/')) > 4: continue; + if disk[5] in cuts: continue; + arr = {} + arr['path'] = disk[5]; + tmp1 = [disk[1],disk[2],disk[3],disk[4]]; + arr['size'] = tmp1; + arr['inodes'] = [inodes[1],inodes[2],inodes[3],inodes[4]] + if disk[5] == '/': + bootLog = '/tmp/panelBoot.pl'; + if disk[2].find('M') != -1: + if os.path.exists(bootLog): os.system('rm -f ' + bootLog); + else: + if not os.path.exists(bootLog): os.system('sleep 1 && /etc/init.d/bt reload &'); + diskInfo.append(arr); + return diskInfo; + + #清理系统垃圾 + def ClearSystem(self,get): + count = total = 0; + tmp_total,tmp_count = self.ClearMail(); + count += tmp_count; + total += tmp_total; + tmp_total,tmp_count = self.ClearOther(); + count += tmp_count; + total += tmp_total; + return count,total + + #清理邮件日志 + def ClearMail(self): + rpath = '/var/spool'; + total = count = 0; + import shutil + con = ['cron','anacron','mail']; + for d in os.listdir(rpath): + if d in con: continue; + dpath = rpath + '/' + d + time.sleep(0.2); + num = size = 0; + for n in os.listdir(dpath): + filename = dpath + '/' + n + fsize = os.path.getsize(filename); + size += fsize + if os.path.isdir(filename): + shutil.rmtree(filename) + else: + os.remove(filename) + print '\t\033[1;32m[OK]\033[0m' + num += 1 + total += size; + count += num; + return total,count + + #清理其它 + def ClearOther(self): + clearPath = [ + {'path':'/www/server/panel','find':'testDisk_'}, + {'path':'/www/wwwlogs','find':'log'}, + {'path':'/tmp','find':'panelBoot.pl'}, + {'path':'/www/server/panel/install','find':'.rpm'} + ] + + total = count = 0; + for c in clearPath: + for d in os.listdir(c['path']): + if d.find(c['find']) == -1: continue; + filename = c['path'] + '/' + d; + fsize = os.path.getsize(filename); + total += fsize + if os.path.isdir(filename): + shutil.rmtree(filename) + else: + os.remove(filename) + count += 1; + public.serviceReload(); + os.system('echo > /tmp/panelBoot.pl'); + return total,count + + def GetNetWork(self,get=None): + #return self.GetNetWorkApi(get); + #取网络流量信息 + try: + networkIo = psutil.net_io_counters()[:4] + if not hasattr(web.ctx.session,'otime'): + web.ctx.session.up = networkIo[0] + web.ctx.session.down = networkIo[1] + web.ctx.session.otime = time.time(); + + ntime = time.time(); + networkInfo = {} + networkInfo['upTotal'] = networkIo[0] + networkInfo['downTotal'] = networkIo[1] + networkInfo['up'] = round(float(networkIo[0] - web.ctx.session.up) / 1024 / (ntime - web.ctx.session.otime),2) + networkInfo['down'] = round(float(networkIo[1] - web.ctx.session.down) / 1024 / (ntime - web.ctx.session.otime),2) + networkInfo['downPackets'] =networkIo[3] + networkInfo['upPackets'] =networkIo[2] + + web.ctx.session.up = networkIo[0] + web.ctx.session.down = networkIo[1] + web.ctx.session.otime = ntime; + + networkInfo['cpu'] = self.GetCpuInfo() + networkInfo['load'] = self.GetLoadAverage(get); + return networkInfo + except: + return None + + + def GetNetWorkApi(self,get=None): + #取网络流量信息 + try: + tmpfile = 'data/network.temp'; + networkIo = psutil.net_io_counters()[:4] + + if not os.path.exists(tmpfile): + public.writeFile(tmpfile,str(networkIo[0])+'|'+str(networkIo[1])+'|' + str(int(time.time()))); + + lastValue = public.readFile(tmpfile).split('|'); + + ntime = time.time(); + networkInfo = {} + networkInfo['upTotal'] = networkIo[0] + networkInfo['downTotal'] = networkIo[1] + networkInfo['up'] = round(float(networkIo[0] - int(lastValue[0])) / 1024 / (ntime - int(lastValue[2])),2) + networkInfo['down'] = round(float(networkIo[1] - int(lastValue[1])) / 1024 / (ntime - int(lastValue[2])),2) + networkInfo['downPackets'] =networkIo[3] + networkInfo['upPackets'] =networkIo[2] + + public.writeFile(tmpfile,str(networkIo[0])+'|'+str(networkIo[1])+'|' + str(int(time.time()))); + + #networkInfo['cpu'] = self.GetCpuInfo(0.1) + return networkInfo + except: + return None + + def GetNetWorkOld(self): + #取网络流量信息 + import time; + pnet = public.readFile('/proc/net/dev'); + rep = '([^\s]+):[\s]{0,}(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)'; + pnetall = re.findall(rep,pnet); + networkInfo = {} + networkInfo['upTotal'] = networkInfo['downTotal'] = networkInfo['up'] = networkInfo['down'] = networkInfo['downPackets'] = networkInfo['upPackets'] = 0; + for pnetInfo in pnetall: + if pnetInfo[0] == 'io': continue; + networkInfo['downTotal'] += int(pnetInfo[1]); + networkInfo['downPackets'] += int(pnetInfo[2]); + networkInfo['upTotal'] += int(pnetInfo[9]); + networkInfo['upPackets'] += int(pnetInfo[10]); + + if not hasattr(web.ctx.session,'otime'): + web.ctx.session.up = networkInfo['upTotal'] + web.ctx.session.down = networkInfo['downTotal'] + web.ctx.session.otime = time.time(); + ntime = time.time(); + tmpDown = networkInfo['downTotal'] - web.ctx.session.down; + tmpUp = networkInfo['upTotal'] - web.ctx.session.up; + networkInfo['down'] = str(round(float(tmpDown) / 1024 / (ntime - web.ctx.session.otime),2)); + networkInfo['up'] = str(round(float(tmpUp) / 1024 / (ntime - web.ctx.session.otime),2)); + if networkInfo['down'] < 0: networkInfo['down'] = 0; + if networkInfo['up'] < 0: networkInfo['up'] = 0; + + web.ctx.session.up = networkInfo['upTotal']; + web.ctx.session.down = networkInfo['downTotal']; + web.ctx.session.otime = ntime; + networkInfo['cpu'] = self.GetCpuInfo() + return networkInfo; + + def ServiceAdmin(self,get=None): + #服务管理 + + if get.name == 'mysqld': public.CheckMyCnf(); + + if get.name == 'phpmyadmin': + import ajax + get.status = 'True'; + ajax.ajax().setPHPMyAdmin(get); + return public.returnMsg(True,'SYS_EXEC_SUCCESS'); + + #检查httpd配置文件 + if get.name == 'apache' or get.name == 'httpd': + get.name = 'httpd'; + if not os.path.exists(self.setupPath+'/apache/bin/apachectl'): return public.returnMsg(True,'SYS_NOT_INSTALL_APACHE'); + vhostPath = self.setupPath + '/panel/vhost/apache' + if not os.path.exists(vhostPath): + public.ExecShell('mkdir ' + vhostPath); + public.ExecShell('/etc/init.d/httpd start'); + + if get.type == 'start': + public.ExecShell('/etc/init.d/httpd stop'); + public.ExecShell('pkill -9 httpd'); + + result = public.ExecShell('ulimit -n 10240 && ' + self.setupPath+'/apache/bin/apachectl -t'); + if result[1].find('Syntax OK') == -1: + public.WriteLog("TYPE_SOFT",'SYS_EXEC_ERR', (str(result),)); + return public.returnMsg(False,'SYS_CONF_APACHE_ERR',(result[1].replace("\n",'
'),)); + + if get.type == 'restart': + public.ExecShell('pkill -9 httpd'); + public.ExecShell('/etc/init.d/httpd start'); + + #检查nginx配置文件 + elif get.name == 'nginx': + vhostPath = self.setupPath + '/panel/vhost/rewrite' + if not os.path.exists(vhostPath): public.ExecShell('mkdir ' + vhostPath); + vhostPath = self.setupPath + '/panel/vhost/nginx' + if not os.path.exists(vhostPath): + public.ExecShell('mkdir ' + vhostPath); + public.ExecShell('/etc/init.d/nginx start'); + + result = public.ExecShell('ulimit -n 10240 && nginx -t -c '+self.setupPath+'/nginx/conf/nginx.conf'); + if result[1].find('perserver') != -1: + limit = self.setupPath + '/nginx/conf/nginx.conf'; + nginxConf = public.readFile(limit); + limitConf = "limit_conn_zone $binary_remote_addr zone=perip:10m;\n\t\tlimit_conn_zone $server_name zone=perserver:10m;"; + nginxConf = nginxConf.replace("#limit_conn_zone $binary_remote_addr zone=perip:10m;",limitConf); + public.writeFile(limit,nginxConf) + public.ExecShell('/etc/init.d/nginx start'); + return public.returnMsg(True,'SYS_CONF_NGINX_REP'); + + if result[1].find('proxy') != -1: + import panelSite + panelSite.panelSite().CheckProxy(get); + public.ExecShell('/etc/init.d/nginx start'); + return public.returnMsg(True,'SYS_CONF_NGINX_REP'); + + #return result + if result[1].find('successful') == -1: + public.WriteLog("TYPE_SOFT",'SYS_EXEC_ERR', (str(result),)); + return public.returnMsg(False,'SYS_CONF_NGINX_ERR',(result[1].replace("\n",'
'),)); + + #执行 + execStr = "/etc/init.d/"+get.name+" "+get.type + if execStr == '/etc/init.d/pure-ftpd reload': execStr = self.setupPath+'/pure-ftpd/bin/pure-pw mkdb '+self.setupPath+'/pure-ftpd/etc/pureftpd.pdb' + if execStr == '/etc/init.d/pure-ftpd start': os.system('pkill -9 pure-ftpd'); + if execStr == '/etc/init.d/tomcat reload': execStr = '/etc/init.d/tomcat stop && /etc/init.d/tomcat start'; + if execStr == '/etc/init.d/tomcat restart': execStr = '/etc/init.d/tomcat stop && /etc/init.d/tomcat start'; + + if get.name != 'mysqld': + result = public.ExecShell(execStr); + else: + os.system(execStr); + result = []; + result.append(''); + result.append(''); + + if result[1].find('nginx.pid') != -1: + public.ExecShell('pkill -9 nginx && sleep 1'); + public.ExecShell('/etc/init.d/nginx start'); + if get.type != 'test': + public.WriteLog("TYPE_SOFT", 'SYS_EXEC_SUCCESS',(execStr,)); + + if len(result[1]) > 1 and get.name != 'pure-ftpd': return public.returnMsg(False, '

警告消息:

' + result[1].replace('\n','
')); + return public.returnMsg(True,'SYS_EXEC_SUCCESS'); + + def RestartServer(self,get): + if not public.IsRestart(): return public.returnMsg(False,'EXEC_ERR_TASK'); + public.ExecShell("sync && /etc/init.d/bt stop && init 6 &"); + return public.returnMsg(True,'SYS_REBOOT'); + + #释放内存 + def ReMemory(self,get): + os.system('sync'); + scriptFile = 'script/rememory.sh' + if not os.path.exists(scriptFile): + public.downloadFile(web.ctx.session.home + '/script/rememory.sh',scriptFile); + public.ExecShell("/bin/bash " + self.setupPath + '/panel/' + scriptFile); + return self.GetMemInfo(); + + #重启面板 + def ReWeb(self,get): + #if not public.IsRestart(): return public.returnMsg(False,'EXEC_ERR_TASK'); + public.ExecShell('/etc/init.d/bt restart &'); + return True + + #修复面板 + def RepPanel(self,get): + vp = ''; + if public.readFile('/www/server/panel/class/common.py').find('checkSafe') != -1: vp = '_pro'; + public.ExecShell("wget -O update.sh " + public.get_url() + "/install/update"+vp+".sh && bash update.sh"); + if hasattr(web.ctx.session,'getCloudPlugin'): del(web.ctx.session['getCloudPlugin']); + return True; + + #升级到专业版 + def UpdatePro(self,get): + public.ExecShell("wget -O update.sh " + public.get_url() + "/install/update_pro.sh && bash update.sh pro"); + if hasattr(web.ctx.session,'getCloudPlugin'): del(web.ctx.session['getCloudPlugin']); + return True; + + + + + + \ No newline at end of file diff --git a/data/default.db b/data/default.db index d673496b5..966364cdc 100755 Binary files a/data/default.db and b/data/default.db differ diff --git a/task.py b/task.py new file mode 100755 index 000000000..0700a534d --- /dev/null +++ b/task.py @@ -0,0 +1,526 @@ +# coding: utf-8 + +#------------------------------ +# 计划任务 +#------------------------------ +import sys +import os +import json +# import psutil +import time + +sys.path.append(os.getcwd() + "/class/") +reload(sys) +sys.setdefaultencoding('utf-8') +import db +import public + + +global pre, timeoutCount, logPath, isTask, oldEdate, isCheck +pre = 0 +timeoutCount = 0 +isCheck = 0 +oldEdate = None +logPath = '/tmp/panelExec.log' +isTask = '/tmp/panelTask.pl' + + +class MyBad(): + _msg = None + + def __init__(self, msg): + self._msg = msg + + def __repr__(self): + return self._msg + + +def ExecShell(cmdstring, cwd=None, timeout=None, shell=True): + try: + global logPath + import shlex + import datetime + import subprocess + import time + + if timeout: + end_time = datetime.datetime.now() + datetime.timedelta(seconds=timeout) + + sub = subprocess.Popen(cmdstring + ' > ' + logPath + ' 2>&1', + cwd=cwd, stdin=subprocess.PIPE, shell=shell, bufsize=4096) + + while sub.poll() is None: + time.sleep(0.1) + + return sub.returncode + except: + return None + + +def DownloadFile(url, filename): + # 下载文件 + try: + import urllib + import socket + socket.setdefaulttimeout(10) + urllib.urlretrieve(url, filename=filename, reporthook=DownloadHook) + os.system('chown www.www ' + filename) + WriteLogs('done') + except: + WriteLogs('done') + + +def DownloadHook(count, blockSize, totalSize): + # 下载文件进度回调 + global pre + used = count * blockSize + pre1 = int((100.0 * used / totalSize)) + if pre == pre1: + return + speed = {'total': totalSize, 'used': used, 'pre': pre} + WriteLogs(json.dumps(speed)) + pre = pre1 + + +def WriteLogs(logMsg): + # 写输出日志 + try: + global logPath + fp = open(logPath, 'w+') + fp.write(logMsg) + fp.close() + except: + pass + + +def startTask(): + # 任务队列 + global isTask + # import time + # import public + try: + while True: + try: + if os.path.exists(isTask): + sql = db.Sql() + sql.table('tasks').where( + "status=?", ('-1',)).setField('status', '0') + taskArr = sql.table('tasks').where("status=?", ('0',)).field( + 'id,type,execstr').order("id asc").select() + for value in taskArr: + start = int(time.time()) + if not sql.table('tasks').where("id=?", (value['id'],)).count(): + continue + sql.table('tasks').where("id=?", (value['id'],)).save( + 'status,start', ('-1', start)) + if value['type'] == 'download': + argv = value['execstr'].split('|bt|') + DownloadFile(argv[0], argv[1]) + elif value['type'] == 'execshell': + ExecShell(value['execstr']) + end = int(time.time()) + sql.table('tasks').where("id=?", (value['id'],)).save( + 'status,end', ('1', end)) + if(sql.table('tasks').where("status=?", ('0')).count() < 1): + os.system('rm -f ' + isTask) + except: + pass + siteEdate() + mainSafe() + time.sleep(2) + except: + time.sleep(60) + startTask() + + +def mainSafe(): + global isCheck + try: + if isCheck < 100: + isCheck += 1 + return True + isCheck = 0 + isStart = public.ExecShell( + "ps aux |grep 'python main.py'|grep -v grep|awk '{print $2}'")[0] + if not isStart: + os.system('/etc/init.d/bt start') + isStart = public.ExecShell( + "ps aux |grep 'python main.py'|grep -v grep|awk '{print $2}'")[0] + public.WriteLog('守护程序', '面板服务程序启动成功 -> PID: ' + isStart) + except: + time.sleep(30) + mainSafe() + + +def siteEdate(): + # 网站到期处理 + global oldEdate + try: + if not oldEdate: + oldEdate = public.readFile('data/edate.pl') + if not oldEdate: + oldEdate = '0000-00-00' + mEdate = time.strftime('%Y-%m-%d', time.localtime()) + if oldEdate == mEdate: + return False + edateSites = public.M('sites').where('edate>? AND edate (networkInfo['up'] + networkInfo['down']): + networkInfo = tmp + + # 取磁盘Io + if os.path.exists('/proc/diskstats'): + diskio_2 = psutil.disk_io_counters() + if not diskio_1: + diskio_1 = diskio_2 + tmp = {} + tmp['read_count'] = diskio_2.read_count - diskio_1.read_count + tmp['write_count'] = diskio_2.write_count - diskio_1.write_count + tmp['read_bytes'] = diskio_2.read_bytes - diskio_1.read_bytes + tmp['write_bytes'] = diskio_2.write_bytes - diskio_1.write_bytes + tmp['read_time'] = diskio_2.read_time - diskio_1.read_time + tmp['write_time'] = diskio_2.write_time - diskio_1.write_time + + if not diskInfo: + diskInfo = tmp + else: + diskInfo['read_count'] += tmp['read_count'] + diskInfo['write_count'] += tmp['write_count'] + diskInfo['read_bytes'] += tmp['read_bytes'] + diskInfo['write_bytes'] += tmp['write_bytes'] + diskInfo['read_time'] += tmp['read_time'] + diskInfo['write_time'] += tmp['write_time'] + + diskio_1 = diskio_2 + + # print diskInfo + + if count >= 12: + try: + addtime = int(time.time()) + deltime = addtime - (day * 86400) + + data = (cpuInfo['used'], cpuInfo['mem'], addtime) + sql.table('cpuio').add('pro,mem,addtime', data) + sql.table('cpuio').where("addtime 100: + lpro = 100 + sql.table('load_average').add('pro,one,five,fifteen,addtime', (lpro, load_average[ + 'one'], load_average['five'], load_average['fifteen'], addtime)) + + lpro = None + load_average = None + cpuInfo = None + networkInfo = None + diskInfo = None + count = 0 + reloadNum += 1 + if reloadNum > 1440: + if os.path.exists('data/ssl.pl'): + os.system( + '/etc/init.d/bt restart > /dev/null 2>&1') + reloadNum = 0 + except Exception, ex: + print str(ex) + del(tmp) + + time.sleep(5) + count += 1 + except Exception, ex: + print str(ex) + time.sleep(30) + systemTask() + + +def GetMemUsed(): + # 取内存使用率 + try: + import psutil + mem = psutil.virtual_memory() + memInfo = {'memTotal': mem.total / 1024 / 1024, 'memFree': mem.free / 1024 / 1024, + 'memBuffers': mem.buffers / 1024 / 1024, 'memCached': mem.cached / 1024 / 1024} + tmp = memInfo['memTotal'] - memInfo['memFree'] - \ + memInfo['memBuffers'] - memInfo['memCached'] + tmp1 = memInfo['memTotal'] / 100 + return (tmp / tmp1) + except: + return 1 + +# 检查502错误 + + +def check502(): + try: + phpversions = ['53', '54', '55', '56', '70', '71', '72'] + for version in phpversions: + if not os.path.exists('/etc/init.d/php-fpm-' + version): + continue + if checkPHPVersion(version): + continue + if startPHPVersion(version): + public.WriteLog('PHP守护程序', '检测到PHP-' + version + '处理异常,已自动修复!') + except: + pass + + +def startPHPVersion(version): + # 处理指定PHP版本 + try: + fpm = '/etc/init.d/php-fpm-' + version + if not os.path.exists(fpm): + return False + + # 尝试重载服务 + os.system(fpm + ' reload') + if checkPHPVersion(version): + return True + + # 尝试重启服务 + cgi = '/tmp/php-cgi-' + version + pid = '/www/server/php' + version + '/php-fpm.pid' + os.system('pkill -9 php-fpm-' + version) + time.sleep(0.5) + if not os.path.exists(cgi): + os.system('rm -f ' + cgi) + if not os.path.exists(pid): + os.system('rm -f ' + pid) + os.system(fpm + ' start') + if checkPHPVersion(version): + return True + + # 检查是否正确启动 + if os.path.exists(cgi): + return True + except: + return True + + +def checkPHPVersion(version): + # 检查指定PHP版本 + try: + url = 'http://127.0.0.1/phpfpm_' + version + '_status' + result = public.httpGet(url) + # 检查nginx + if result.find('Bad Gateway') != -1: + return False + # 检查Apache + if result.find('Service Unavailable') != -1: + return False + if result.find('Not Found') != -1: + CheckPHPINFO() + + # 检查Web服务是否启动 + if result.find('Connection refused') != -1: + global isTask + if os.path.exists(isTask): + isStatus = public.readFile(isTask) + if isStatus == 'True': + return True + filename = '/etc/init.d/nginx' + if os.path.exists(filename): + os.system(filename + ' start') + filename = '/etc/init.d/httpd' + if os.path.exists(filename): + os.system(filename + ' start') + + return True + except: + return True + + +def CheckPHPINFO(): + # 检测PHPINFO配置 + php_versions = ['53', '54', '55', '56', '70', '71', '72'] + setupPath = '/www/server' + path = setupPath + '/panel/vhost/nginx/phpinfo.conf' + if not os.path.exists(path): + opt = "" + for version in php_versions: + opt += "\n\tlocation /" + version + \ + " {\n\t\tinclude enable-php-" + version + ".conf;\n\t}" + + phpinfoBody = '''server +{ + listen 80; + server_name 127.0.0.2; + allow 127.0.0.1; + index phpinfo.php index.html index.php; + root /www/server/phpinfo; +%s +}''' % (opt,) + public.writeFile(path, phpinfoBody) + + path = setupPath + '/panel/vhost/apache/phpinfo.conf' + if not os.path.exists(path): + opt = "" + for version in php_versions: + opt += """\n + SetHandler "proxy:unix:/tmp/php-cgi-%s.sock|fcgi://localhost" +""" % (version, version) + + phpinfoBody = ''' + +DocumentRoot "/www/server/phpinfo" +ServerAdmin phpinfo +ServerName 127.0.0.2 +%s + + SetOutputFilter DEFLATE + Options FollowSymLinks + AllowOverride All + Order allow,deny + Allow from all + DirectoryIndex index.php index.html index.htm default.php default.html default.htm + + +''' % (opt,) + public.writeFile(path, phpinfoBody) + +# 502错误检查线程 + + +def check502Task(): + try: + while True: + if os.path.exists('/www/server/panel/data/502Task.pl'): + check502() + time.sleep(600) + except: + time.sleep(600) + check502Task() + +# 自动结束异常进程 + + +def btkill(): + import btkill + b = btkill.btkill() + b.start() + +if __name__ == "__main__": + os.system('rm -rf /www/server/phpinfo/*') + if os.path.exists('/www/server/nginx/sbin/nginx'): + pfile = '/www/server/nginx/conf/enable-php-72.conf' + if not os.path.exists(pfile): + pconf = '''location ~ [^/]\.php(/|$) +{ + try_files $uri =404; + fastcgi_pass unix:/tmp/php-cgi-72.sock; + fastcgi_index index.php; + include fastcgi.conf; + include pathinfo.conf; +}''' + public.writeFile(pfile, pconf) + import threading + t = threading.Thread(target=systemTask) + t.setDaemon(True) + t.start() + + p = threading.Thread(target=check502Task) + p.setDaemon(True) + p.start() + + #p = threading.Thread(target=btkill) + # p.setDaemon(True) + # p.start() + + startTask()