359 lines
13 KiB
Python
359 lines
13 KiB
Python
#coding: utf-8
|
||
# +-------------------------------------------------------------------
|
||
# | YakPanel
|
||
# +-------------------------------------------------------------------
|
||
# | Copyright (c) 2015-2020 YakPanel(https://www.yakpanel.com) All rights reserved.
|
||
# +-------------------------------------------------------------------
|
||
# | Author: 沐落 <cjx@yakpanel.com>
|
||
# | Author: lx
|
||
# +-------------------------------------------------------------------
|
||
import sys,os,time,psutil,re
|
||
panelPath = "/www/server/panel"
|
||
os.chdir(panelPath)
|
||
sys.path.insert(0, "class/")
|
||
import public,time,panelPush,public
|
||
|
||
try:
|
||
from YakPanel import cache
|
||
except :
|
||
from cachelib import SimpleCache
|
||
cache = SimpleCache()
|
||
|
||
class panel_push:
|
||
|
||
__push = None
|
||
pids = None
|
||
def __init__(self):
|
||
self.__push = panelPush.panelPush()
|
||
|
||
#-----------------------------------------------------------start 添加推送 ------------------------------------------------------
|
||
def get_version_info(self,get):
|
||
"""
|
||
获取版本信息
|
||
"""
|
||
data = {}
|
||
data['ps'] = ''
|
||
data['version'] = '1.2'
|
||
data['date'] = '2022-09-20'
|
||
data['author'] = 'YakPanel'
|
||
data['help'] = 'https://www.yakpanel.com/forum'
|
||
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 True
|
||
|
||
#检测指定进程是否存活
|
||
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 check_run(self,name):
|
||
if name == "php-fpm":
|
||
status = False
|
||
base_path = "/www/server/php"
|
||
if not os.path.exists(base_path):
|
||
return status
|
||
for p in os.listdir(base_path):
|
||
pid_file = os.path.join(base_path, p, "var/run/php-fpm.pid")
|
||
if os.path.exists(pid_file):
|
||
php_pid = int(public.readFile(pid_file))
|
||
status = self.checkProcess(php_pid)
|
||
if status:
|
||
return status
|
||
return status
|
||
elif name == 'nginx':
|
||
status = False
|
||
if os.path.exists('/etc/init.d/nginx'):
|
||
pidf = '/www/server/nginx/logs/nginx.pid'
|
||
if os.path.exists(pidf):
|
||
try:
|
||
pid = public.readFile(pidf)
|
||
status = self.checkProcess(pid)
|
||
except:
|
||
pass
|
||
return status
|
||
elif name == 'apache':
|
||
status = False
|
||
if os.path.exists('/etc/init.d/httpd'):
|
||
pidf = '/www/server/apache/logs/httpd.pid'
|
||
if os.path.exists(pidf):
|
||
pid = public.readFile(pidf)
|
||
status = self.checkProcess(pid)
|
||
return status
|
||
elif name == 'mysql':
|
||
res = public.ExecShell("service mysqld status")
|
||
if res and not re.search(r"not\s+running", res[0]):
|
||
return True
|
||
return False
|
||
elif name == 'tomcat':
|
||
status = False
|
||
if os.path.exists('/www/server/tomcat/logs/catalina-daemon.pid'):
|
||
if self.getPid('jsvc'): status = True
|
||
if not status:
|
||
if self.getPid('java'): status = True
|
||
return status
|
||
elif name == 'pure-ftpd':
|
||
pidf = '/var/run/pure-ftpd.pid'
|
||
status = False
|
||
if os.path.exists(pidf):
|
||
pid = public.readFile(pidf)
|
||
status = self.checkProcess(pid)
|
||
return status
|
||
elif name == 'redis':
|
||
status = False
|
||
pidf = '/www/server/redis/redis.pid'
|
||
if os.path.exists(pidf):
|
||
pid = public.readFile(pidf)
|
||
status = self.checkProcess(pid)
|
||
return status
|
||
elif name == 'memcached':
|
||
status = False
|
||
pidf = '/var/run/memcached.pid'
|
||
if os.path.exists(pidf):
|
||
pid = public.readFile(pidf)
|
||
status = self.checkProcess(pid)
|
||
return status
|
||
return True
|
||
|
||
def get_server_status(self, server_name):
|
||
status = self.check_run(server_name)
|
||
if status:
|
||
return 1
|
||
return 0
|
||
|
||
"""
|
||
@获取推送模块配置
|
||
"""
|
||
def get_module_config(self,get):
|
||
|
||
data = []
|
||
|
||
item = self.__push.format_push_data(push = ["mail",'dingding','weixin',"feishu"],project = 'ssl',type = 'ssl')
|
||
item['cycle'] = 30
|
||
item['title'] = 'SSL到期提醒'
|
||
item['helps'] = ['SSL到期提醒一天只发送一次','证书夹内【剩余天数不足30天】的所有证书.']
|
||
data.append(item)
|
||
|
||
item = self.__push.format_push_data(push = ["mail",'dingding','weixin',"feishu"],project = 'endtime',type = 'endtime')
|
||
item['cycle'] = 5
|
||
item['title'] = '专业版/企业版到期提醒'
|
||
item['helps'] = ['']
|
||
data.append(item)
|
||
|
||
services = ['nginx','apache',"pure-ftpd",'mysql','php-fpm','memcached','redis']
|
||
channels = ['mail', 'dingding','weixin','sms',"feishu"]
|
||
for x in services:
|
||
item = {}
|
||
item['project'] = x
|
||
item['title'] = '{}服务停止通知'.format(x)
|
||
|
||
if x == 'other':
|
||
item['title'] = '自定义服务停止通知'
|
||
else:
|
||
ser_name = self.__get_service_name(x)
|
||
if self.get_server_status(ser_name) == -1: continue
|
||
|
||
item['type'] = 'services'
|
||
item['keys'] = []
|
||
item['interval'] = 300
|
||
for x in ['stop']:
|
||
item['keys'].append({'key':x,'val':'停止'})
|
||
|
||
item['push'] = channels
|
||
item['helps'] = ['部分服务停止可能会造成业务中断.','短信推送需提前购买,如需帮助请联系 [<a href="https://www.yakpanel.com/forum" target="_blank" class="btlink">YakPanel 社区</a>]']
|
||
data.append(item)
|
||
import json
|
||
public.writeFile('data/push/config/panel_push.json',json.dumps(data))
|
||
return data
|
||
|
||
def get_push_cycle(self,data):
|
||
"""
|
||
@获取执行周期
|
||
"""
|
||
result = {}
|
||
for skey in data:
|
||
result[skey] = data[skey]
|
||
|
||
m_cycle =[]
|
||
m_type = data[skey]['type']
|
||
if m_type in ['endtime','ssl']:
|
||
m_cycle.append('剩余{}天时,每天1次'.format(data[skey]['cycle']))
|
||
elif m_type in ['services']:
|
||
m_cycle.append('服务停止时,每{}秒1次'.format(data[skey]['interval']))
|
||
if len(m_cycle) > 0:
|
||
result[skey]['m_cycle'] = ''.join(m_cycle)
|
||
return result
|
||
|
||
#-----------------------------------------------------------end 添加推送 ------------------------------------------------------
|
||
"""
|
||
@获取服务真实名称
|
||
"""
|
||
def __get_service_name(self,name):
|
||
slist = {"FTP服务端":'pure-ftpd'}
|
||
if name in slist: name = slist[name]
|
||
|
||
return name
|
||
"""
|
||
@获取推送栏目
|
||
"""
|
||
def get_total(self):
|
||
return True;
|
||
|
||
def get_push_data(self,data,total):
|
||
if data['type'] == 'services':
|
||
ser_name = data['project']
|
||
ser_name = self.__get_service_name(ser_name)
|
||
|
||
status = self.get_server_status(ser_name)
|
||
if status > 0:
|
||
return public.returnMsg(False, public.lang("状态正常,跳过."))
|
||
else:
|
||
if status == 0:
|
||
return self.__get_service_result(data)
|
||
return public.returnMsg(False, public.lang("服务未安装,跳过."))
|
||
|
||
elif data['type'] in ['ssl']:
|
||
|
||
if time.time() < data['index'] + 86400:
|
||
return public.returnMsg(False, public.lang("一天推送一次,跳过."))
|
||
|
||
import panelSSL
|
||
ssl = panelSSL.panelSSL()
|
||
clist = []
|
||
for x in ssl.GetCertList(None):
|
||
timeArray = time.strptime(x['notAfter'], "%Y-%m-%d")
|
||
endtime = time.mktime(timeArray)
|
||
day = int((endtime - time.time()) / 86400)
|
||
if day > data['cycle']: continue
|
||
clist.append(x)
|
||
|
||
return self.__get_ssl_result(data,clist)
|
||
|
||
elif data['type'] in ['endtime']:
|
||
if time.time() < data['index'] + 86400:
|
||
return public.returnMsg(False, public.lang("一天推送一次,跳过."))
|
||
|
||
from pluginAuth import Plugin
|
||
softs = Plugin(False).get_plugin_list(True)
|
||
if softs['pro'] == 0: return public.returnMsg(False, public.lang("永久专业版,跳过."))
|
||
|
||
if softs['ltd'] == -2 and softs['pro'] == -2:
|
||
pass
|
||
else:
|
||
pro_data = {}
|
||
if softs['ltd'] > 0:
|
||
pro_data['endtime'] = softs['ltd']
|
||
pro_data['name'] = "Linux企业版"
|
||
pro_data['affect'] = '全部企业版插件'
|
||
elif softs['pro'] > 0:
|
||
pro_data['endtime'] = softs['pro']
|
||
pro_data['name'] = "Linux专业版"
|
||
pro_data['affect'] = '全部专业版插件'
|
||
|
||
pro_data['day'] = int((pro_data['endtime'] - time.time()) / 86400)
|
||
|
||
if pro_data['day'] <= data['cycle']:
|
||
return self.__get_ltd_result(data,pro_data)
|
||
|
||
return public.returnMsg(False, public.lang("未达到阈值,跳过."))
|
||
|
||
"""
|
||
@企业版到期提醒
|
||
"""
|
||
def __get_ltd_result(self,data,pro_data):
|
||
result = {'index':time.time()}
|
||
|
||
for m_module in data['module'].split(','):
|
||
result[m_module] = self.__push.format_msg_data()
|
||
newline = ""
|
||
if m_module in ['dingding','weixin',"feishu","mail"]:
|
||
if m_module in ["mail"]:
|
||
newline="<br/>"
|
||
result[m_module]["title"] = "YakPanel 业务到期提醒"
|
||
else:
|
||
newline = "\n\n"
|
||
result[m_module]['msg'] = "".join((
|
||
"#### YakPanel 业务到期提醒"+newline,
|
||
">服务器 :"+ public.GetLocalIp() + newline,
|
||
">剩余天数:"+ str(pro_data['day'] + 1) +" 天"+newline,
|
||
">到期产品:"+ pro_data['name'] +newline,
|
||
">到期时间:"+ public.format_date(times =pro_data['endtime']) +newline,
|
||
">影响业务:"+ pro_data['affect'] +newline,
|
||
">通知时间:" + public.format_date() + newline))
|
||
return result
|
||
|
||
"""
|
||
@ssl到期返回
|
||
"""
|
||
def __get_ssl_result(self,data,clist):
|
||
if len(clist) == 0:
|
||
return public.returnMsg(False, public.lang("未找到到期证书,跳过."))
|
||
|
||
result = {'index':time.time() }
|
||
for m_module in data['module'].split(','):
|
||
|
||
result[m_module] = self.__push.format_msg_data()
|
||
newline = ""
|
||
if m_module in ['dingding','weixin',"feishu","mail"]:
|
||
if m_module in ["mail"]:
|
||
newline="<br/>"
|
||
result[m_module]["title"] = "YakPanel SSL到期提醒"
|
||
else:
|
||
newline = "\n\n"
|
||
|
||
p_msg = "";
|
||
for x in clist: p_msg+= " 到期:{} 域名:{}".format(x['notAfter'],x['subject']) + newline
|
||
|
||
result[m_module]['msg'] ="".join((
|
||
"#### YakPanel SSL到期提醒" + newline,
|
||
">服务器 :"+ public.GetLocalIp() +newline,
|
||
">检测时间:" + public.format_date() +newline,
|
||
">About to expire: "+ str(len(clist)) +" "+newline,
|
||
p_msg))
|
||
return result
|
||
|
||
"""
|
||
@服务停止返回
|
||
"""
|
||
def __get_service_result(self,data):
|
||
|
||
s_idx = int(time.time())
|
||
if s_idx < data['index'] + data['interval']:
|
||
return public.returnMsg(False, public.lang("The interval is not reached, skip."))
|
||
|
||
result = {'index':s_idx}
|
||
|
||
for m_module in data['module'].split(','):
|
||
result[m_module] = self.__push.format_msg_data()
|
||
newline = ""
|
||
if m_module in ['dingding','weixin',"feishu","mail"]:
|
||
if m_module in ["mail"]:
|
||
newline="<br/>"
|
||
result[m_module]["title"] = "堡塔服务停止告警"
|
||
else:
|
||
newline = "\n\n"
|
||
result[m_module]['msg'] = "".join((
|
||
"#### 堡塔服务停止告警" + newline,
|
||
">服务器 :"+ public.GetLocalIp() +newline + " ",
|
||
">Type of service: "+ data["project"] +newline + " ",
|
||
">Service state: 已停止"+newline+" ",
|
||
">检测时间:"+ public.format_date()))
|
||
elif m_module in ['sms']:
|
||
result[m_module]['sm_type'] = 'servcies'
|
||
result[m_module]['sm_args'] = { 'name':'{}'.format(public.GetConfigValue('title')), 'product':data["project"],'product1':data["project"]}
|
||
return result
|
||
|
||
|
||
|