# coding:utf-8 import sys import io import os import time import subprocess import json import re web_dir = os.getcwd() + "/web" if os.path.exists(web_dir): sys.path.append(web_dir) os.chdir(web_dir) import core.mw as mw app_debug = False if mw.isAppleSystem(): app_debug = True def getPluginName(): return 'op_load_balance' def getPluginDir(): return mw.getPluginDir() + '/' + getPluginName() def getServerDir(): return mw.getServerDir() + '/' + getPluginName() def getArgs(): args = sys.argv[2:] tmp = {} args_len = len(args) if args_len == 1: t = args[0].strip('{').strip('}') if t.strip() == '': tmp = [] else: t = t.split(':') tmp[t[0]] = t[1] tmp[t[0]] = t[1] elif args_len > 1: for i in range(len(args)): t = args[i].split(':') tmp[t[0]] = t[1] return tmp def checkArgs(data, ck=[]): for i in range(len(ck)): if not ck[i] in data: return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!')) return (True, mw.returnJson(True, 'ok')) def getConf(): path = getServerDir() + "/cfg.json" if not os.path.exists(path): mw.writeFile(path, '[]') c = mw.readFile(path) return json.loads(c) def writeConf(data): path = getServerDir() + "/cfg.json" mw.writeFile(path, json.dumps(data)) def contentReplace(content): service_path = mw.getServerDir() content = content.replace('{$ROOT_PATH}', mw.getFatherDir()) content = content.replace('{$SERVER_PATH}', service_path) content = content.replace('{$APP_PATH}', app_path) return content def restartWeb(): mw.opWeb('stop') mw.opWeb('start') def loadBalanceConf(): path = mw.getServerDir() + '/web_conf/nginx/vhost/load_balance.conf' return path def initDreplace(): dst_conf_tpl = getPluginDir() + '/conf/load_balance.conf' dst_conf = loadBalanceConf() if not os.path.exists(dst_conf): con = mw.readFile(dst_conf_tpl) mw.writeFile(dst_conf, con) def status(): if not mw.getWebStatus(): return 'stop' dst_conf = loadBalanceConf() if not os.path.exists(dst_conf): return 'stop' return 'start' def start(): initDreplace() restartWeb() return 'ok' def stop(): dst_conf = loadBalanceConf() os.remove(dst_conf) deleteLoadBalanceAllCfg() restartWeb() return 'ok' def restart(): restartWeb() return 'ok' def reload(): restartWeb() return 'ok' def installPreInspection(): check_op = mw.getServerDir() + "/openresty" if not os.path.exists(check_op): return "请先安装OpenResty" return 'ok' def deleteLoadBalanceAllCfg(): cfg = getConf() upstream_dir = mw.getServerDir() + '/web_conf/nginx/upstream' lua_dir = mw.getServerDir() + '/web_conf/nginx/lua/init_worker_by_lua_file' rewrite_dir = mw.getServerDir() + '/web_conf/nginx/rewrite' vhost_dir = mw.getServerDir() + '/web_conf/nginx/vhost' for conf in cfg: upstream_file = upstream_dir + '/' + conf['upstream_name'] + '.conf' if os.path.exists(upstream_file): os.remove(upstream_file) lua_file = lua_dir + '/' + conf['upstream_name'] + '.lua' if os.path.exists(lua_file): os.remove(lua_file) rewrite_file = rewrite_dir + '/' + conf['domain'] + '.conf' mw.writeFile(rewrite_file, '') path = vhost_dir + '/' + conf['domain'] + '.conf' content = mw.readFile(path) content = re.sub('include ' + upstream_file + ';' + "\n", '', content) mw.writeFile(path, content) mw.opLuaInitWorkerFile() def makeConfServerList(data): slist = '' for x in data: slist += 'server ' slist += x['ip'] + ':' + x['port'] if x['state'] == '0': slist += ' down;\n\t' continue if x['state'] == '2': slist += ' backup;\n\t' continue slist += ' weight=' + x['weight'] slist += ' max_fails=' + x['max_fails'] slist += ' fail_timeout=' + x['fail_timeout'] + "s;\n\t" return slist def makeLoadBalanceAllCfg(row): # 生成所有配置 cfg = getConf() upstream_dir = mw.getServerDir() + '/web_conf/nginx/upstream' rewrite_dir = mw.getServerDir() + '/web_conf/nginx/rewrite' vhost_dir = mw.getServerDir() + '/web_conf/nginx/vhost' upstream_tpl = getPluginDir() + '/conf/upstream.tpl.conf' rewrite_tpl = getPluginDir() + '/conf/rewrite.tpl.conf' if not os.path.exists(upstream_dir): os.makedirs(upstream_dir) conf = cfg[row] # replace vhost start vhost_file = vhost_dir + '/' + conf['domain'] + '.conf' vcontent = mw.readFile(vhost_file) vhost_find_str = 'upstream/' + conf['upstream_name'] + '.conf' vhead = 'include ' + mw.getServerDir() + '/web_conf/nginx/' + \ vhost_find_str + ';' vpos = vcontent.find(vhost_find_str) if vpos < 0: vcontent = vhead + "\n" + vcontent mw.writeFile(vhost_file, vcontent) # replace vhost end # make upstream start upstream_file = upstream_dir + '/' + conf['upstream_name'] + '.conf' content = '' if len(conf['node_list']) > 0: content = mw.readFile(upstream_tpl) slist = makeConfServerList(conf['node_list']) content = content.replace('{$NODE_SERVER_LIST}', slist) content = content.replace('{$UPSTREAM_NAME}', conf['upstream_name']) if conf['node_algo'] != 'polling': content = content.replace('{$NODE_ALGO}', conf['node_algo'] + ';') else: content = content.replace('{$NODE_ALGO}', '') mw.writeFile(upstream_file, content) # make upstream end # make rewrite start rewrite_file = rewrite_dir + '/' + conf['domain'] + '.conf' rcontent = '' if len(conf['node_list']) > 0: rcontent = mw.readFile(rewrite_tpl) rcontent = rcontent.replace('{$UPSTREAM_NAME}', conf['upstream_name']) mw.writeFile(rewrite_file, rcontent) # make rewrite end # health check start lua_dir = mw.getServerDir() + '/web_conf/nginx/lua/init_worker_by_lua_file' lua_init_worker_file = lua_dir + '/' + conf['upstream_name'] + '.lua' if conf['node_health_check'] == 'ok': lua_dir_tpl = getPluginDir() + '/lua/health_check.lua.tpl' content = mw.readFile(lua_dir_tpl) content = content.replace('{$UPSTREAM_NAME}', conf['upstream_name']) content = content.replace('{$DOMAIN}', conf['domain']) mw.writeFile(lua_init_worker_file, content) else: if os.path.exists(lua_init_worker_file): os.remove(lua_init_worker_file) mw.opLuaInitWorkerFile() # health check end return True def add_load_balance(args): data = checkArgs( args, ['domain', 'upstream_name', 'node_algo', 'node_list', 'node_health_check']) if not data[0]: return data[1] domain_json = args['domain'] tmp = json.loads(domain_json) domain = tmp['domain'] cfg = getConf() cfg_len = len(cfg) tmp = {} tmp['domain'] = domain tmp['data'] = args['domain'] tmp['upstream_name'] = args['upstream_name'] tmp['node_algo'] = args['node_algo'] tmp['node_list'] = args['node_list'] tmp['node_health_check'] = args['node_health_check'] cfg.append(tmp) writeConf(cfg) import site_api sobj = site_api.site_api() domain_path = mw.getWwwDir() + '/' + domain ps = '负载均衡[' + domain + ']' data = sobj.add(domain_json, '80', ps, domain_path, '00') makeLoadBalanceAllCfg(cfg_len) mw.restartWeb() return mw.returnJson(True, '添加成功', data) def edit_load_balance(args): data = checkArgs( args, ['row', 'node_algo', 'node_list', 'node_health_check']) if not data[0]: return data[1] row = int(args['row']) cfg = getConf() tmp = cfg[row] tmp['node_algo'] = args['node_algo'] tmp['node_list'] = args['node_list'] tmp['node_health_check'] = args['node_health_check'] cfg[row] = tmp writeConf(cfg) makeLoadBalanceAllCfg(row) mw.restartWeb() return mw.returnJson(True, '修改成功', data) def loadBalanceList(): cfg = getConf() return mw.returnJson(True, 'ok', cfg) def loadBalanceDelete(): args = getArgs() data = checkArgs(args, ['row']) if not data[0]: return data[1] row = int(args['row']) cfg = getConf() data = cfg[row] import site_api sobj = site_api.site_api() sid = mw.M('sites').where('name=?', (data['domain'],)).getField('id') if type(sid) == list: del(cfg[row]) writeConf(cfg) return mw.returnJson(False, '已经删除了!') status = sobj.delete(sid, data['domain'], 1) status_data = json.loads(status) if status_data['status']: del(cfg[row]) writeConf(cfg) upstream_dir = mw.getServerDir() + '/web_conf/nginx/upstream' rewrite_dir = mw.getServerDir() + '/web_conf/nginx/rewrite' upstream_file = upstream_dir + '/' + data['upstream_name'] + '.conf' if os.path.exists(upstream_file): os.remove(upstream_file) rewrite_file = rewrite_dir + '/' + data['domain'] + '.conf' if os.path.exists(rewrite_file): mw.writeFile(rewrite_file, '') return mw.returnJson(status_data['status'], status_data['msg']) def http_get(url): ret = re.search(r'https://', url) if ret: try: from gevent import monkey monkey.patch_ssl() import requests ret = requests.get(url=str(url), verify=False, timeout=10) status = [200, 301, 302, 404, 403] if ret.status_code in status: return True else: return False except: return False else: try: if sys.version_info[0] == 2: import urllib2 rec = urllib2.urlopen(url, timeout=3) else: import urllib.request rec = urllib.request.urlopen(url, timeout=3) status = [200, 301, 302, 404, 403] if rec.getcode() in status: return True return False except: return False def checkUrl(): args = getArgs() data = checkArgs(args, ['ip', 'port', 'path']) if not data[0]: return data[1] ip = args['ip'] port = args['port'] path = args['path'] if port == '443': url = 'https://' + str(ip) + ':' + str(port) + str(path.strip()) else: url = 'http://' + str(ip) + ':' + str(port) + str(path.strip()) ret = http_get(url) if not ret: return mw.returnJson(False, '访问节点[%s]失败' % url) return mw.returnJson(True, '访问节点[%s]成功' % url) def getHealthStatus(): args = getArgs() data = checkArgs(args, ['row']) if not data[0]: return data[1] row = int(args['row']) cfg = getConf() data = cfg[row] url = 'http://' + data['domain'] + \ '/upstream_status_' + data['upstream_name'] url_data = mw.httpGet(url) return mw.returnJson(True, 'ok', json.loads(url_data)) def getLogs(): args = getArgs() data = checkArgs(args, ['domain']) if not data[0]: return data[1] domain = args['domain'] logs = mw.getLogsDir() + '/' + domain + '.log' return logs if __name__ == "__main__": func = sys.argv[1] if func == 'status': print(status()) elif func == 'start': print(start()) elif func == 'stop': print(stop()) elif func == 'restart': print(restart()) elif func == 'reload': print(reload()) elif func == 'install_pre_inspection': print(installPreInspection()) elif func == 'add_load_balance': print(addLoadBalance()) elif func == 'load_balance_list': print(loadBalanceList()) elif func == 'load_balance_delete': print(loadBalanceDelete()) elif func == 'check_url': print(checkUrl()) elif func == 'get_logs': print(getLogs()) elif func == 'get_health_status': print(getHealthStatus()) else: print('error')