diff --git a/plugins/walle/ico.png b/plugins/walle/ico.png new file mode 100644 index 000000000..c44b9dc4b Binary files /dev/null and b/plugins/walle/ico.png differ diff --git a/plugins/walle/index.html b/plugins/walle/index.html new file mode 100755 index 000000000..3a87c684a --- /dev/null +++ b/plugins/walle/index.html @@ -0,0 +1,20 @@ +
+
+
+

服务

+

自启动

+

日志

+

说明

+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/plugins/walle/index.py b/plugins/walle/index.py new file mode 100755 index 000000000..ad820116d --- /dev/null +++ b/plugins/walle/index.py @@ -0,0 +1,190 @@ +# coding: utf-8 + +import time +import random +import os +import json +import re +import sys +import subprocess + +sys.path.append(os.getcwd() + "/class/core") +import public + +app_debug = False +if public.isAppleSystem(): + app_debug = True + + +def getPluginName(): + return 'walle' + + +def getPluginDir(): + return public.getPluginDir() + '/' + getPluginName() + + +def getServerDir(): + return public.getServerDir() + '/' + getPluginName() + + +def getInitDFile(): + if app_debug: + return '/tmp/' + getPluginName() + return '/etc/init.d/' + getPluginName() + + +def getInitDTpl(): + return getPluginDir() + "/init.d/" + getPluginName() + ".tpl" + + +def getLog(): + return getServerDir() + "/code/logs/error.log" + + +def getArgs(): + args = sys.argv[2:] + tmp = {} + args_len = len(args) + + if args_len == 1: + t = args[0].strip('{').strip('}') + t = t.split(':') + 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, public.returnJson(False, '参数:(' + ck[i] + ')没有!')) + return (True, public.returnJson(True, 'ok')) + + +def status(): + pn = getPluginName() + cmd = "ps -ef|grep 'waller.py' | grep -v grep | awk '{print $2}'" + data = public.execShell(cmd) + if data[0] == '': + return 'stop' + return 'start' + + +def initDreplace(): + + file_tpl = getInitDTpl() + service_path = os.path.dirname(os.getcwd()) + + initD_path = getServerDir() + '/init.d' + if not os.path.exists(initD_path): + os.mkdir(initD_path) + + file_bin = initD_path + '/' + getPluginName() + if not os.path.exists(file_bin): + content = public.readFile(file_tpl) + content = content.replace('{$SERVER_PATH}', service_path) + public.writeFile(file_bin, content) + public.execShell('chmod +x ' + file_bin) + + return file_bin + + +def runShell(shell): + data = public.execShell(shell) + return data + + +def start(): + file = initDreplace() + cmd = file + ' start' + data = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + return 'ok' + + +def stop(): + file = initDreplace() + data = runShell(file + ' stop') + if data[1] == '': + return 'ok' + return 'fail' + + +def restart(): + file = initDreplace() + data = runShell(file + ' restart') + if data[1] == '': + return 'ok' + return 'fail' + + +def reload(): + file = initDreplace() + data = runShell(file + ' reload') + + solr_log = getServerDir() + "/code/logs/walle.log" + public.writeFile(solr_log, "") + + if data[1] == '': + return 'ok' + return 'fail' + + +def initdStatus(): + initd_bin = getInitDFile() + if os.path.exists(initd_bin): + return 'ok' + return 'fail' + + +def initdInstall(): + import shutil + + source_bin = initDreplace() + initd_bin = getInitDFile() + shutil.copyfile(source_bin, initd_bin) + public.execShell('chmod +x ' + initd_bin) + + if not app_debug: + public.execShell('chkconfig --add ' + getPluginName()) + return 'ok' + + +def initdUinstall(): + if not app_debug: + public.execShell('chkconfig --del ' + getPluginName()) + + initd_bin = getInitDFile() + + if os.path.exists(initd_bin): + os.remove(initd_bin) + return 'ok' + +# rsyncdReceive +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 == 'initd_status': + print initdStatus() + elif func == 'initd_install': + print initdInstall() + elif func == 'initd_uninstall': + print initdUinstall() + elif func == 'run_log': + print getLog() + else: + print 'error' diff --git a/plugins/walle/info.json b/plugins/walle/info.json new file mode 100644 index 000000000..b3eb2643d --- /dev/null +++ b/plugins/walle/info.json @@ -0,0 +1,16 @@ +{ + "id":12, + "title":"walle", + "tip":"soft", + "name":"walle", + "type":"扩展", + "ps":"一款开源的代码部署管理工具", + "versions":"1.0", + "shell":"install.sh", + "checks":"server/walle", + "path": "server/walle", + "author":"midoks", + "home":"", + "date":"2019-12-05", + "pid":"3" +} \ No newline at end of file diff --git a/plugins/walle/init.d/walle.tpl b/plugins/walle/init.d/walle.tpl new file mode 100644 index 000000000..4e6523266 --- /dev/null +++ b/plugins/walle/init.d/walle.tpl @@ -0,0 +1,114 @@ +#!/bin/bash +# chkconfig: 2345 55 25 +# description: Walle Service + +### BEGIN INIT INFO +# Provides: bt +# Required-Start: $all +# Required-Stop: $all +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: starts walle +# Description: starts the walle +### END INIT INFO + + +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin + +app_path={$SERVER_PATH}/walle/code + + +walle_start(){ + isStart=`ps aux | grep 'waller.py'| grep -v grep | awk '{print $2}'` + if [ "$isStart" == '' ];then + echo -e "Starting walle... \c" + cd $app_path && python waller.py >> $app_path/logs/walle.log 2>&1 & + sleep 0.3 + isStart=`ps aux | grep 'waller.py' | grep -v grep | awk '{print $2}'` + sleep 0.2 + if [ "$isStart" == '' ];then + echo -e "\033[31mfailed\033[0m" + echo '------------------------------------------------------' + tail -n 20 $app_path/logs/walle.log + echo '------------------------------------------------------' + echo -e "\033[31mError: walle service startup failed.\033[0m" + return + fi + echo -e "\033[32mdone\033[0m" + else + echo "Starting ... walle (pid $isStart) already running" + fi +} + + +walle_stop() +{ + echo -e "Stopping walle... \c"; + pids=$(ps aux | grep 'waller.py'|grep -v grep|awk '{print $2}') + arr=($pids) + + for p in ${arr[@]} + do + kill -9 $p + done + echo -e "\033[32mdone\033[0m" + + echo -e "Stopping walle... \c"; + arr=`ps aux | grep 'waller.py' | grep -v grep | awk '{print $2}'` + for p in ${arr[@]} + do + kill -9 $p &>/dev/null + done + + if [ -f $pidfile ];then + rm -f $pidfile + fi + echo -e "\033[32mdone\033[0m" +} + + + +walle_reload() +{ + isStart=$(ps aux | grep 'waller.py' | grep -v grep | awk '{print $2}') + + if [ "$isStart" != '' ];then + echo -e "Reload walle... \c"; + arr=`ps aux|grep 'waller.py' |grep -v grep|awk '{print $2}'` + for p in ${arr[@]} + do + kill -9 $p + done + cd $app_path && nohup python waller.py >> $app_path/logs/walle.log 2>&1 & + isStart=`ps aux | grep 'waller.py' | grep -v grep | awk '{print $2}'` + if [ "$isStart" == '' ];then + echo -e "\033[31mfailed\033[0m" + echo '------------------------------------------------------' + tail -n 20 $app_path/logs/walle.log + echo '------------------------------------------------------' + echo -e "\033[31mError: walle service startup failed.\033[0m" + return + fi + echo -e "\033[32mdone\033[0m" + else + echo -e "\033[31m walle not running\033[0m" + mw_start + fi +} + + +error_logs() +{ + tail -n 100 ${app_path}/logs/walle.log +} + +case "$1" in + 'start') walle_start;; + 'stop') walle_stop;; + 'reload') walle_reload;; + 'restart') + walle_stop + walle_start;; + 'logs') error_logs;; +esac + diff --git a/plugins/walle/install.sh b/plugins/walle/install.sh new file mode 100644 index 000000000..5b95fb50b --- /dev/null +++ b/plugins/walle/install.sh @@ -0,0 +1,51 @@ +#!/bin/bash +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin +export PATH + + +curPath=`pwd` +rootPath=$(dirname "$curPath") +rootPath=$(dirname "$rootPath") +serverPath=$(dirname "$rootPath") + + +install_tmp=${rootPath}/tmp/mw_install.pl + + +Install_walle() +{ + echo '正在安装脚本文件...' > $install_tmp + mkdir -p $serverPath/walle + echo '1.0' > $serverPath/walle/version.pl + + if [ ! -f $serverPath/source/v2.0.1.tar.gz ];then + wget -O $serverPath/source/v2.0.1.tar.gz https://github.com/meolu/walle-web/archive/v2.0.1.tar.gz + fi + + if [ ! -d $serverPath/source/walle-web-2.0.1 ];then + cd $serverPath/source && tar -zxvf v2.0.1.tar.gz + fi + + if [ ! -d $serverPath/walle/code ];then + mkdir -p $serverPath/walle/code + cp -rf $serverPath/source/walle-web-2.0.1/ $serverPath/walle/code + fi + + cd $serverPath/walle/code && pip install -r $serverPath/walle/code/requirements/prod.txt + + echo '安装完成' > $install_tmp + +} + +Uninstall_walle() +{ + rm -rf $serverPath/walle + echo "卸载完成" > $install_tmp +} + +action=$1 +if [ "${1}" == 'install' ];then + Install_walle +else + Uninstall_walle +fi \ No newline at end of file diff --git a/plugins/walle/js/walle.js b/plugins/walle/js/walle.js new file mode 100755 index 000000000..505727477 --- /dev/null +++ b/plugins/walle/js/walle.js @@ -0,0 +1,71 @@ +function str2Obj(str){ + var data = {}; + kv = str.split('&'); + for(i in kv){ + v = kv[i].split('='); + data[v[0]] = v[1]; + } + return data; +} + +function pPost(method,args,callback, title){ + var _args = null; + if (typeof(args) == 'string'){ + _args = JSON.stringify(str2Obj(args)); + } else { + _args = JSON.stringify(args); + } + + var _title = '正在获取...'; + if (typeof(title) != 'undefined'){ + _title = title; + } + + var loadT = layer.msg(_title, { icon: 16, time: 0, shade: 0.3 }); + $.post('/plugins/run', {name:'walle', func:method, args:_args}, function(data) { + layer.close(loadT); + if (!data.status){ + layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']}); + return; + } + if(typeof(callback) == 'function'){ + callback(data); + } + },'json'); +} + +function pPostCallbak(method, version, args,callback){ + var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 }); + + var req_data = {}; + req_data['name'] = 'walle'; + req_data['func'] = method; + args['version'] = version; + + if (typeof(args) == 'string'){ + req_data['args'] = JSON.stringify(str2Obj(args)); + } else { + req_data['args'] = JSON.stringify(args); + } + + $.post('/plugins/callback', req_data, function(data) { + layer.close(loadT); + if (!data.status){ + layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']}); + return; + } + + if(typeof(callback) == 'function'){ + callback(data); + } + },'json'); +} + + +function pRead(){ + var readme = ''; + + $('.soft-man-con').html(readme); +} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index e18a8bf4c..18e4970f0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,6 +3,7 @@ wheel flask==1.0 flask-session flask-socketio==3.3.2 +flask-helper=0.19 gunicorn==19.9 gevent==1.3.3 gevent-websocket==0.10.1 @@ -11,4 +12,5 @@ pillow chardet flask-sqlalchemy ConfigParser -MySQL-python \ No newline at end of file +MySQL-python +pytest-shutil \ No newline at end of file diff --git a/rewrite/nginx/walle.conf b/rewrite/nginx/walle.conf new file mode 100755 index 000000000..b2f5e1321 --- /dev/null +++ b/rewrite/nginx/walle.conf @@ -0,0 +1,34 @@ + +#upstream webservers { +# server 127.0.0.1:5000; +#} + +location / { + try_files $uri $uri/ /index.html; + add_header access-control-allow-origin *; +} + +location ^~ /api/ { + add_header access-control-allow-origin *; + proxy_pass http://webservers; + proxy_set_header X-Forwarded-Host $host:$server_port; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Origin $host:$server_port; + proxy_set_header Referer $host:$server_port; +} + +location ^~ /socket.io/ { + add_header access-control-allow-origin *; + proxy_pass http://webservers; + proxy_set_header X-Forwarded-Host $host:$server_port; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Origin $host:$server_port; + proxy_set_header Referer $host:$server_port; + proxy_set_header Host $http_host; + proxy_set_header X-NginX-Proxy true; + + # WebScoket Support + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; +} \ No newline at end of file