mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 12:40:25 +08:00
feat: supervisor plugin and optimize code
This commit is contained in:
@@ -35,8 +35,7 @@ func (c *Php74Controller) Status(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
out := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := strings.TrimSpace(out)
|
||||
status := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
return
|
||||
|
||||
@@ -35,8 +35,7 @@ func (c *Php80Controller) Status(ctx http.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
out := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
status := strings.TrimSpace(out)
|
||||
status := tools.ExecShell("systemctl status php-fpm-" + c.version + " | grep Active | grep -v grep | awk '{print $2}'")
|
||||
if len(status) == 0 {
|
||||
controllers.Error(ctx, http.StatusInternalServerError, "获取PHP-"+c.version+"运行状态失败")
|
||||
return
|
||||
|
||||
390
app/http/controllers/plugins/supervisor/supervisor_controller.go
Normal file
390
app/http/controllers/plugins/supervisor/supervisor_controller.go
Normal file
@@ -0,0 +1,390 @@
|
||||
package supervisor
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
"panel/pkg/tools"
|
||||
|
||||
"panel/app/http/controllers"
|
||||
)
|
||||
|
||||
type SupervisorController struct {
|
||||
ServiceName string
|
||||
}
|
||||
|
||||
func NewSupervisorController() *SupervisorController {
|
||||
var serviceName string
|
||||
if tools.IsRHEL() {
|
||||
serviceName = "supervisord"
|
||||
} else {
|
||||
serviceName = "supervisor"
|
||||
}
|
||||
|
||||
return &SupervisorController{
|
||||
ServiceName: serviceName,
|
||||
}
|
||||
}
|
||||
|
||||
// Status 状态
|
||||
func (r *SupervisorController) Status(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
status := tools.ExecShell(`systemctl status ` + r.ServiceName + ` | grep Active | grep -v grep | awk '{print $2}'`)
|
||||
if status == "active" {
|
||||
controllers.Success(ctx, true)
|
||||
} else {
|
||||
controllers.Success(ctx, false)
|
||||
}
|
||||
}
|
||||
|
||||
// Start 启动
|
||||
func (r *SupervisorController) Start(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell(`systemctl start ` + r.ServiceName)
|
||||
status := tools.ExecShell(`systemctl status ` + r.ServiceName + ` | grep Active | grep -v grep | awk '{print $2}'`)
|
||||
if status == "active" {
|
||||
controllers.Success(ctx, true)
|
||||
} else {
|
||||
controllers.Success(ctx, false)
|
||||
}
|
||||
}
|
||||
|
||||
// Stop 停止
|
||||
func (r *SupervisorController) Stop(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell(`systemctl stop ` + r.ServiceName)
|
||||
status := tools.ExecShell(`systemctl status ` + r.ServiceName + ` | grep Active | grep -v grep | awk '{print $2}'`)
|
||||
if status != "active" {
|
||||
controllers.Success(ctx, true)
|
||||
} else {
|
||||
controllers.Success(ctx, false)
|
||||
}
|
||||
}
|
||||
|
||||
// Restart 重启
|
||||
func (r *SupervisorController) Restart(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell(`systemctl restart ` + r.ServiceName)
|
||||
status := tools.ExecShell(`systemctl status ` + r.ServiceName + ` | grep Active | grep -v grep | awk '{print $2}'`)
|
||||
if status == "active" {
|
||||
controllers.Success(ctx, true)
|
||||
} else {
|
||||
controllers.Success(ctx, false)
|
||||
}
|
||||
}
|
||||
|
||||
// Reload 重载
|
||||
func (r *SupervisorController) Reload(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell(`systemctl reload ` + r.ServiceName)
|
||||
status := tools.ExecShell(`systemctl status ` + r.ServiceName + ` | grep Active | grep -v grep | awk '{print $2}'`)
|
||||
if status == "active" {
|
||||
controllers.Success(ctx, true)
|
||||
} else {
|
||||
controllers.Success(ctx, false)
|
||||
}
|
||||
}
|
||||
|
||||
// Log 日志
|
||||
func (r *SupervisorController) Log(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
log := tools.ExecShell(`tail -n 200 /var/log/supervisor/supervisord.log`)
|
||||
controllers.Success(ctx, log)
|
||||
}
|
||||
|
||||
// ClearLog 清空日志
|
||||
func (r *SupervisorController) ClearLog(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
tools.ExecShell(`echo "" > /var/log/supervisor/supervisord.log`)
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// Config 获取配置
|
||||
func (r *SupervisorController) Config(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
var config string
|
||||
if tools.IsRHEL() {
|
||||
config = tools.ReadFile(`/etc/supervisord.conf`)
|
||||
} else {
|
||||
config = tools.ReadFile(`/etc/supervisor/supervisord.conf`)
|
||||
}
|
||||
controllers.Success(ctx, config)
|
||||
}
|
||||
|
||||
// SaveConfig 保存配置
|
||||
func (r *SupervisorController) SaveConfig(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
config := ctx.Request().Input("config")
|
||||
if tools.IsRHEL() {
|
||||
tools.WriteFile(`/etc/supervisord.conf`, config, 0644)
|
||||
} else {
|
||||
tools.WriteFile(`/etc/supervisor/supervisord.conf`, config, 0644)
|
||||
}
|
||||
|
||||
tools.ExecShell(`systemctl restart ` + r.ServiceName)
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// Processes 进程列表
|
||||
func (r *SupervisorController) Processes(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
page := ctx.Request().QueryInt("page", 1)
|
||||
limit := ctx.Request().QueryInt("limit", 10)
|
||||
|
||||
type process struct {
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
Pid string `json:"pid"`
|
||||
Uptime string `json:"uptime"`
|
||||
}
|
||||
|
||||
out := tools.ExecShell(`supervisorctl status | awk '{print $1}'`)
|
||||
var processList []process
|
||||
for _, line := range strings.Split(out, "\n") {
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var p process
|
||||
p.Name = line
|
||||
p.Status = tools.ExecShell(`supervisorctl status ` + line + ` | awk '{print $2}'`)
|
||||
if p.Status == "RUNNING" {
|
||||
p.Pid = strings.ReplaceAll(tools.ExecShell(`supervisorctl status `+line+` | awk '{print $4}'`), ",", "")
|
||||
p.Uptime = tools.ExecShell(`supervisorctl status ` + line + ` | awk '{print $6}'`)
|
||||
} else {
|
||||
p.Pid = "-"
|
||||
p.Uptime = "-"
|
||||
}
|
||||
processList = append(processList, p)
|
||||
}
|
||||
|
||||
startIndex := (page - 1) * limit
|
||||
endIndex := page * limit
|
||||
if startIndex > len(processList) {
|
||||
controllers.Success(ctx, http.Json{
|
||||
"total": 0,
|
||||
"items": []process{},
|
||||
})
|
||||
return
|
||||
}
|
||||
if endIndex > len(processList) {
|
||||
endIndex = len(processList)
|
||||
}
|
||||
pagedProcessList := processList[startIndex:endIndex]
|
||||
|
||||
controllers.Success(ctx, http.Json{
|
||||
"total": len(processList),
|
||||
"items": pagedProcessList,
|
||||
})
|
||||
}
|
||||
|
||||
// StartProcess 启动进程
|
||||
func (r *SupervisorController) StartProcess(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
process := ctx.Request().Input("process")
|
||||
tools.ExecShell(`supervisorctl start ` + process)
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// StopProcess 停止进程
|
||||
func (r *SupervisorController) StopProcess(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
process := ctx.Request().Input("process")
|
||||
tools.ExecShell(`supervisorctl stop ` + process)
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// RestartProcess 重启进程
|
||||
func (r *SupervisorController) RestartProcess(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
process := ctx.Request().Input("process")
|
||||
tools.ExecShell(`supervisorctl restart ` + process)
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// ProcessLog 进程日志
|
||||
func (r *SupervisorController) ProcessLog(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
process := ctx.Request().Input("process")
|
||||
var logPath string
|
||||
if tools.IsRHEL() {
|
||||
logPath = tools.ExecShell(`cat '/etc/supervisord.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
|
||||
} else {
|
||||
logPath = tools.ExecShell(`cat '/etc/supervisor/conf.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
|
||||
}
|
||||
|
||||
log := tools.ExecShell(`tail -n 200 ` + logPath)
|
||||
controllers.Success(ctx, log)
|
||||
}
|
||||
|
||||
// ClearProcessLog 清空进程日志
|
||||
func (r *SupervisorController) ClearProcessLog(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
process := ctx.Request().Input("process")
|
||||
var logPath string
|
||||
if tools.IsRHEL() {
|
||||
logPath = tools.ExecShell(`cat '/etc/supervisord.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
|
||||
} else {
|
||||
logPath = tools.ExecShell(`cat '/etc/supervisor/conf.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
|
||||
}
|
||||
|
||||
tools.ExecShell(`echo "" > ` + logPath)
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// ProcessConfig 获取进程配置
|
||||
func (r *SupervisorController) ProcessConfig(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
process := ctx.Request().Query("process")
|
||||
var config string
|
||||
if tools.IsRHEL() {
|
||||
config = tools.ReadFile(`/etc/supervisord.d/` + process + `.conf`)
|
||||
} else {
|
||||
config = tools.ReadFile(`/etc/supervisor/conf.d/` + process + `.conf`)
|
||||
}
|
||||
|
||||
controllers.Success(ctx, config)
|
||||
}
|
||||
|
||||
// SaveProcessConfig 保存进程配置
|
||||
func (r *SupervisorController) SaveProcessConfig(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
process := ctx.Request().Input("process")
|
||||
config := ctx.Request().Input("config")
|
||||
if tools.IsRHEL() {
|
||||
tools.WriteFile(`/etc/supervisord.d/`+process+`.conf`, config, 0644)
|
||||
} else {
|
||||
tools.WriteFile(`/etc/supervisor/conf.d/`+process+`.conf`, config, 0644)
|
||||
}
|
||||
tools.ExecShell(`supervisorctl reread`)
|
||||
tools.ExecShell(`supervisorctl update`)
|
||||
tools.ExecShell(`supervisorctl start ` + process)
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// AddProcess 添加进程
|
||||
func (r *SupervisorController) AddProcess(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
validator, err := ctx.Request().Validate(map[string]string{
|
||||
"name": "required|alpha_dash",
|
||||
"user": "required|alpha_dash",
|
||||
"path": "required",
|
||||
"command": "required",
|
||||
"num": "required",
|
||||
})
|
||||
if err != nil {
|
||||
controllers.Error(ctx, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
if validator.Fails() {
|
||||
controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One())
|
||||
return
|
||||
}
|
||||
|
||||
name := ctx.Request().Input("name")
|
||||
user := ctx.Request().Input("user")
|
||||
path := ctx.Request().Input("path")
|
||||
command := ctx.Request().Input("command")
|
||||
num := ctx.Request().InputInt("num", 1)
|
||||
config := `[program:` + name + `]
|
||||
command=` + command + `
|
||||
process_name=%(program_name)s
|
||||
directory=` + path + `
|
||||
autostart=true
|
||||
autorestart=true
|
||||
user=` + user + `
|
||||
numprocs=` + strconv.Itoa(num) + `
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/var/log/supervisor/` + name + `.log
|
||||
stdout_logfile_maxbytes=2MB
|
||||
`
|
||||
if tools.IsRHEL() {
|
||||
tools.WriteFile(`/etc/supervisord.d/`+name+`.conf`, config, 0644)
|
||||
} else {
|
||||
tools.WriteFile(`/etc/supervisor/conf.d/`+name+`.conf`, config, 0644)
|
||||
}
|
||||
tools.ExecShell(`supervisorctl reread`)
|
||||
tools.ExecShell(`supervisorctl update`)
|
||||
tools.ExecShell(`supervisorctl start ` + name)
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
|
||||
// DeleteProcess 删除进程
|
||||
func (r *SupervisorController) DeleteProcess(ctx http.Context) {
|
||||
if !controllers.Check(ctx, "supervisor") {
|
||||
return
|
||||
}
|
||||
|
||||
process := ctx.Request().Input("process")
|
||||
tools.ExecShell(`supervisorctl stop ` + process)
|
||||
var logPath string
|
||||
if tools.IsRHEL() {
|
||||
logPath = tools.ExecShell(`cat '/etc/supervisord.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
|
||||
tools.RemoveFile(`/etc/supervisord.d/` + process + `.conf`)
|
||||
} else {
|
||||
logPath = tools.ExecShell(`cat '/etc/supervisor/conf.d/` + process + `.conf' | grep stdout_logfile= | awk -F "=" '{print $2}'`)
|
||||
tools.RemoveFile(`/etc/supervisor/conf.d/` + process + `.conf`)
|
||||
}
|
||||
tools.RemoveFile(logPath)
|
||||
tools.ExecShell(`supervisorctl reread`)
|
||||
tools.ExecShell(`supervisorctl update`)
|
||||
|
||||
controllers.Success(ctx, nil)
|
||||
}
|
||||
13
app/plugins/supervisor/supervisor.go
Normal file
13
app/plugins/supervisor/supervisor.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package supervisor
|
||||
|
||||
var (
|
||||
Name = "Supervisor"
|
||||
Description = "Supervisor 是一个客户端/服务器系统,允许用户监视和控制类 UNIX 操作系统上的多个进程。"
|
||||
Slug = "supervisor"
|
||||
Version = "4.2.5"
|
||||
Requires = []string{}
|
||||
Excludes = []string{}
|
||||
Install = `bash /www/panel/scripts/supervisor/install.sh`
|
||||
Uninstall = `bash /www/panel/scripts/supervisor/uninstall.sh`
|
||||
Update = `bash /www/panel/scripts/supervisor/install.sh`
|
||||
)
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"panel/app/plugins/php80"
|
||||
"panel/app/plugins/phpmyadmin"
|
||||
"panel/app/plugins/s3fs"
|
||||
"panel/app/plugins/supervisor"
|
||||
)
|
||||
|
||||
// PanelPlugin 插件元数据结构
|
||||
@@ -132,6 +133,17 @@ func (r *PluginImpl) All() []PanelPlugin {
|
||||
Uninstall: s3fs.Uninstall,
|
||||
Update: s3fs.Update,
|
||||
})
|
||||
p = append(p, PanelPlugin{
|
||||
Name: supervisor.Name,
|
||||
Description: supervisor.Description,
|
||||
Slug: supervisor.Slug,
|
||||
Version: supervisor.Version,
|
||||
Requires: supervisor.Requires,
|
||||
Excludes: supervisor.Excludes,
|
||||
Install: supervisor.Install,
|
||||
Uninstall: supervisor.Uninstall,
|
||||
Update: supervisor.Update,
|
||||
})
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ Date: 2023-07-21
|
||||
if (obj.event === 'log') {
|
||||
// 打开日志弹窗
|
||||
admin.popup({
|
||||
title: '日志'
|
||||
title: '日志 - ' + data.name
|
||||
,
|
||||
area: ['80%', '80%']
|
||||
,
|
||||
@@ -214,10 +214,12 @@ Date: 2023-07-21
|
||||
content: '<pre id="cron-log-view" style="overflow: auto; height: 95%;border: 0 none; line-height:23px; padding: 15px; margin: 0; white-space: pre-wrap; background-color: rgb(51,51,51); color:#f1f1f1; border-radius:0;"></pre>'
|
||||
,
|
||||
success: function (layero, index) {
|
||||
index2 = layer.msg('正在获取日志...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: '/api/panel/cron/log?id=' + data.id
|
||||
, type: 'GET'
|
||||
, success: function (res) {
|
||||
layer.close(index2);
|
||||
if (res.code === 0) {
|
||||
$('#cron-log-view').html(res.data);
|
||||
} else {
|
||||
@@ -236,7 +238,7 @@ Date: 2023-07-21
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
admin.popup({
|
||||
title: '编辑'
|
||||
title: '编辑 - ' + data.name
|
||||
,
|
||||
area: ['80%', '80%']
|
||||
,
|
||||
@@ -258,6 +260,7 @@ Date: 2023-07-21
|
||||
}
|
||||
});
|
||||
$('#cron-edit-' + data.id).click(function () {
|
||||
index2 = layer.msg('正在保存...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: '/api/panel/cron/update'
|
||||
, type: 'POST'
|
||||
@@ -271,6 +274,7 @@ Date: 2023-07-21
|
||||
if (res.code === 0) {
|
||||
layer.msg('保存成功', {icon: 1, time: 1000});
|
||||
table.reload('panel-cron');
|
||||
layer.close(index2);
|
||||
layer.close(index);
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, time: 1000});
|
||||
|
||||
451
public/panel/views/plugins/supervisor.html
Normal file
451
public/panel/views/plugins/supervisor.html
Normal file
@@ -0,0 +1,451 @@
|
||||
<!--
|
||||
Name: Supervisor
|
||||
Author: 耗子
|
||||
Date: 2023-07-26
|
||||
-->
|
||||
<title>Supervisor</title>
|
||||
<div class="layui-fluid" id="component-tabs">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">Supervisor 管理</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">运行状态</li>
|
||||
<li>进程列表</li>
|
||||
<li>配置修改</li>
|
||||
<li>运行日志</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<blockquote id="supervisor-status" class="layui-elem-quote layui-quote-nm">
|
||||
当前状态:<span
|
||||
class="layui-badge layui-bg-black">获取中</span></blockquote>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="supervisor-start" class="layui-btn">启动</button>
|
||||
<button id="supervisor-stop" class="layui-btn layui-btn-danger">停止</button>
|
||||
<button id="supervisor-restart" class="layui-btn layui-btn-warm">重启</button>
|
||||
<button id="supervisor-reload" class="layui-btn layui-btn-normal">重载</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<table class="layui-hide" id="supervisor-list" lay-filter="supervisor-list"></table>
|
||||
<!-- 顶部工具栏 -->
|
||||
<script type="text/html" id="supervisor-list-bar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm" lay-event="add_process">添加进程</button>
|
||||
</div>
|
||||
</script>
|
||||
<!-- 右侧管理 -->
|
||||
<script type="text/html" id="supervisor-list-control">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="log">日志</a>
|
||||
<a class="layui-btn layui-bg-blue layui-btn-xs" lay-event="config">配置</a>
|
||||
<a class="layui-btn layui-border layui-btn-xs" lay-event="start">启动</a>
|
||||
<a class="layui-btn layui-bg-purple layui-btn-xs" lay-event="restart">重启</a>
|
||||
<a class="layui-btn layui-bg-orange layui-btn-xs" lay-event="stop">停止</a>
|
||||
<a class="layui-btn layui-bg-red layui-btn-xs" lay-event="delete">删除</a>
|
||||
</script>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<blockquote class="layui-elem-quote">此处修改的是Supervisor主配置文件,如果你不了解各参数的含义,请不要随意修改!<br>
|
||||
提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换!
|
||||
</blockquote>
|
||||
<div id="supervisor-config-editor"
|
||||
style="height: 600px;"></div>
|
||||
<div class="layui-btn-container" style="padding-top: 30px;">
|
||||
<button id="supervisor-config-save" class="layui-btn">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-btn-container">
|
||||
<button id="supervisor-clear-log" class="layui-btn">清空日志</button>
|
||||
</div>
|
||||
<pre id="supervisor-log" class="layui-code">
|
||||
获取中...
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let supervisor_config_editor;
|
||||
let supervisor_process_config_editor;
|
||||
layui.use(['jquery', 'admin', 'view', 'form', 'code', 'table'], function () {
|
||||
let $ = layui.$
|
||||
, admin = layui.admin
|
||||
, table = layui.table
|
||||
, form = layui.form
|
||||
, view = layui.view
|
||||
, code = layui.code;
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/status"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
if (result.data) {
|
||||
$('#supervisor-status').html('当前状态:<span class="layui-badge layui-bg-green">运行中</span>');
|
||||
} else {
|
||||
$('#supervisor-status').html('当前状态:<span class="layui-badge layui-bg-red">已停止</span>');
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
table.render({
|
||||
elem: '#supervisor-list'
|
||||
, url: '/api/plugins/supervisor/processes'
|
||||
, toolbar: '#supervisor-list-bar'
|
||||
, title: 'Supervisor进程列表'
|
||||
, cols: [[
|
||||
{field: 'name', title: '名称', fixed: 'left', unresize: true, sort: true}
|
||||
, {field: 'status', title: '状态', sort: true}
|
||||
, {field: 'pid', title: 'PID', sort: true}
|
||||
, {field: 'uptime', title: '运行时间(天)', sort: true}
|
||||
, {fixed: 'right', title: '操作', toolbar: '#supervisor-list-control', width: 350}
|
||||
]]
|
||||
, page: true
|
||||
, text: {
|
||||
none: '无进程'
|
||||
}
|
||||
, parseData: function (res) {
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.message,
|
||||
"count": res.data.total,
|
||||
"data": res.data.items
|
||||
};
|
||||
}
|
||||
});
|
||||
// 头工具栏事件
|
||||
table.on('toolbar(supervisor-list)', function (obj) {
|
||||
if (obj.event === 'add_process') {
|
||||
admin.popup({
|
||||
title: '添加进程'
|
||||
, area: ['600px', '600px']
|
||||
, id: 'LAY-popup-supervisor-process-add'
|
||||
, success: function (layer, index) {
|
||||
view(this.id).render('plugins/supervisor/add_process', {}).done(function () {
|
||||
form.render(null, 'LAY-popup-supervisor-process-add');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// 行工具事件
|
||||
table.on('tool(supervisor-list)', function (obj) {
|
||||
let data = obj.data;
|
||||
if (obj.event === 'log') {
|
||||
admin.popup({
|
||||
title: '日志 - ' + data.name
|
||||
,
|
||||
area: ['80%', '80%']
|
||||
,
|
||||
id: 'process-log'
|
||||
,
|
||||
content: '<pre id="process-log-view" style="overflow: auto; height: 95%;border: 0 none; line-height:23px; padding: 15px; margin: 0; white-space: pre-wrap; background-color: rgb(51,51,51); color:#f1f1f1; border-radius:0;"></pre>'
|
||||
,
|
||||
success: function (layero, index) {
|
||||
index2 = layer.msg('正在获取日志...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: '/api/plugins/supervisor/processLog?process=' + data.name
|
||||
, type: 'GET'
|
||||
, success: function (res) {
|
||||
layer.close(index2);
|
||||
if (res.code === 0) {
|
||||
$('#process-log-view').html(res.data);
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
if (obj.event === 'config') {
|
||||
admin.req({
|
||||
url: '/api/plugins/supervisor/processConfig?process=' + data.name
|
||||
, type: 'GET'
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
admin.popup({
|
||||
title: '编辑 - ' + data.name
|
||||
,
|
||||
area: ['80%', '80%']
|
||||
,
|
||||
id: 'process-config'
|
||||
,
|
||||
content: '<div id="process-config-editor" style="height: 80%;">' + res.data + '</div><br><button id="process-config-' + data.name + '" class="layui-btn">保存</button>'
|
||||
,
|
||||
success: function (layero, index) {
|
||||
supervisor_process_config_editor = ace.edit("process-config-editor", {
|
||||
mode: "ace/mode/ini",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
$('#process-config-' + data.name).click(function () {
|
||||
index2 = layer.msg('正在保存配置...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: '/api/plugins/supervisor/processConfig'
|
||||
, type: 'POST'
|
||||
, data: {
|
||||
process: data.name,
|
||||
config: supervisor_process_config_editor.getValue()
|
||||
}
|
||||
, success: function (res) {
|
||||
if (res.code === 0) {
|
||||
layer.msg('保存成功', {icon: 1, time: 1000});
|
||||
table.reload('supervisor-list');
|
||||
layer.close(index2);
|
||||
layer.close(index);
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.message, {icon: 2, time: 1000});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (obj.event === 'start') {
|
||||
index = layer.msg('正在启动进程...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/startProcess"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
process: data.name
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('进程启动成功!');
|
||||
}
|
||||
});
|
||||
}
|
||||
if (obj.event === 'restart') {
|
||||
layer.confirm('确定要重启进程吗?', function (index) {
|
||||
index = layer.msg('请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/restartProcess"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
process: data.name
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('进程重启成功!');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
if (obj.event === 'stop') {
|
||||
layer.confirm('确定要停止进程吗?', function (index) {
|
||||
index = layer.msg('请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/stopProcess"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
process: data.name
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('进程停止成功!');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
if (obj.event === 'delete') {
|
||||
layer.confirm('确定要删除进程吗?', function (index) {
|
||||
index = layer.msg('请稍候...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/deleteProcess"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
process: data.name
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
obj.del();
|
||||
layer.alert('进程删除成功!');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/log"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
$('#supervisor-log').text('Supervisor日志获取失败,请刷新重试!');
|
||||
code({
|
||||
elem: '#supervisor-log'
|
||||
, title: 'supervisor.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
return false;
|
||||
}
|
||||
$('#supervisor-log').text(result.data);
|
||||
code({
|
||||
elem: '#supervisor-log'
|
||||
, title: 'supervisor.log'
|
||||
, encode: true
|
||||
, about: false
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/config"
|
||||
, type: 'get'
|
||||
, success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
$('#supervisor-config-editor').text(result.data);
|
||||
supervisor_config_editor = ace.edit("supervisor-config-editor", {
|
||||
mode: "ace/mode/ini",
|
||||
selectionStyle: "text"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('#supervisor-start').click(function () {
|
||||
layer.confirm('确定要启动Supervisor吗?', {
|
||||
btn: ['启动', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在启动Supervisor...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/start"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('Supervisor启动成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#supervisor-stop').click(function () {
|
||||
layer.confirm('确定要停止Supervisor吗?', {
|
||||
btn: ['停止', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在停止Supervisor...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/stop"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('Supervisor停止成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#supervisor-restart').click(function () {
|
||||
layer.confirm('确定要重启Supervisor吗?', {
|
||||
btn: ['重启', '取消']
|
||||
}, function () {
|
||||
index = layer.msg('正在重启Supervisor...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/restart"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('Supervisor重启成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
$('#supervisor-reload').click(function () {
|
||||
index = layer.msg('正在重载Supervisor...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/reload"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
admin.events.refresh();
|
||||
layer.alert('Supervisor重载成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#supervisor-config-save').click(function () {
|
||||
index = layer.msg('正在保存配置...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/config"
|
||||
, type: 'post'
|
||||
, data: {
|
||||
config: supervisor_config_editor.getValue()
|
||||
}
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.alert('Supervisor配置保存成功!');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#supervisor-clear-log').click(function () {
|
||||
index = layer.msg('正在清空Supervisor日志...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/clearLog"
|
||||
, type: 'post'
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
layer.msg('Supervisor日志已清空!');
|
||||
setTimeout(function () {
|
||||
admin.events.refresh();
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
94
public/panel/views/plugins/supervisor/add_process.html
Normal file
94
public/panel/views/plugins/supervisor/add_process.html
Normal file
@@ -0,0 +1,94 @@
|
||||
<!--
|
||||
Name: Supervisor - 添加进程
|
||||
Author: 耗子
|
||||
Date: 2023-07-26
|
||||
-->
|
||||
<script type="text/html" template lay-done="layui.data.sendParams(d.params)">
|
||||
<form class="layui-form" action="" lay-filter="add-mount-s3fs-form">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="name" lay-verify="required" placeholder="请输入名称" class="layui-input"
|
||||
value="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">名称禁止使用中文</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">启动命令</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="command" lay-verify="required" placeholder="请输入启动命令" class="layui-input"
|
||||
value="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">启动命令中的文件请填写绝对路径</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">运行目录</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="path" lay-verify="required" placeholder="请输入运行目录" class="layui-input"
|
||||
value="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">运行目录请填写绝对路径</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">启动用户</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="user" lay-verify="required" placeholder="请输入启动用户" class="layui-input"
|
||||
value="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">一般情况下填写www即可</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">进程数量</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="num" lay-verify="required" placeholder="请输入进程数量" class="layui-input"
|
||||
value="1" min="1" step="1" lay-affix="number">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">一般情况下填写1即可</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-footer">
|
||||
<button class="layui-btn" lay-submit="" lay-filter="supervisor-add-process-submit">立即提交</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<script>
|
||||
layui.data.sendParams = function (params) {
|
||||
layui.use(['admin', 'form', 'jquery', 'table'], function () {
|
||||
var admin = layui.admin
|
||||
, layer = layui.layer
|
||||
, form = layui.form
|
||||
, table = layui.table;
|
||||
|
||||
form.render();
|
||||
|
||||
form.on('submit(supervisor-add-process-submit)', function (data) {
|
||||
index = layer.msg('正在提交...', {icon: 16, time: 0, shade: 0.3});
|
||||
admin.req({
|
||||
url: "/api/plugins/supervisor/addProcess"
|
||||
, type: 'post'
|
||||
, data: data.field
|
||||
, success: function (result) {
|
||||
layer.close(index);
|
||||
if (result.code !== 0) {
|
||||
return false;
|
||||
}
|
||||
table.reload('supervisor-list');
|
||||
layer.alert('Supervisor进程添加成功!', {
|
||||
icon: 1
|
||||
, title: '提示'
|
||||
, btn: ['确定']
|
||||
, yes: function (index) {
|
||||
layer.closeAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -3,6 +3,7 @@ package routes
|
||||
import (
|
||||
"github.com/goravel/framework/contracts/route"
|
||||
"github.com/goravel/framework/facades"
|
||||
"panel/app/http/controllers/plugins/supervisor"
|
||||
|
||||
"panel/app/http/controllers/plugins/mysql57"
|
||||
"panel/app/http/controllers/plugins/mysql80"
|
||||
@@ -136,4 +137,27 @@ func Plugin() {
|
||||
route.Post("add", s3fsController.Add)
|
||||
route.Post("delete", s3fsController.Delete)
|
||||
})
|
||||
facades.Route().Prefix("api/plugins/supervisor").Middleware(middleware.Jwt()).Group(func(route route.Route) {
|
||||
supervisorController := supervisor.NewSupervisorController()
|
||||
route.Get("status", supervisorController.Status)
|
||||
route.Post("start", supervisorController.Start)
|
||||
route.Post("stop", supervisorController.Stop)
|
||||
route.Post("restart", supervisorController.Restart)
|
||||
route.Post("reload", supervisorController.Reload)
|
||||
route.Get("log", supervisorController.Log)
|
||||
route.Post("clearLog", supervisorController.ClearLog)
|
||||
route.Get("config", supervisorController.Config)
|
||||
route.Post("config", supervisorController.SaveConfig)
|
||||
route.Get("processes", supervisorController.Processes)
|
||||
route.Post("startProcess", supervisorController.StartProcess)
|
||||
route.Post("stopProcess", supervisorController.StopProcess)
|
||||
route.Post("restartProcess", supervisorController.RestartProcess)
|
||||
route.Get("processLog", supervisorController.ProcessLog)
|
||||
route.Post("clearProcessLog", supervisorController.ClearProcessLog)
|
||||
route.Get("processConfig", supervisorController.ProcessConfig)
|
||||
route.Post("processConfig", supervisorController.SaveProcessConfig)
|
||||
route.Post("deleteProcess", supervisorController.DeleteProcess)
|
||||
route.Post("addProcess", supervisorController.AddProcess)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
38
scripts/supervisor/install.sh
Normal file
38
scripts/supervisor/install.sh
Normal file
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
|
||||
|
||||
: '
|
||||
Copyright 2022 HaoZi Technology Co., Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
'
|
||||
|
||||
HR="+----------------------------------------------------"
|
||||
OS=$(source /etc/os-release && { [[ "$ID" == "debian" ]] && echo "debian"; } || { [[ "$ID" == "centos" ]] || [[ "$ID" == "rhel" ]] || [[ "$ID" == "rocky" ]] || [[ "$ID" == "almalinux" ]] && echo "centos"; } || echo "unknown")
|
||||
|
||||
if [ "${OS}" == "centos" ]; then
|
||||
dnf install -y supervisor
|
||||
sed -i 's#files = supervisord.d/\*.ini#files = supervisord.d/*.conf#g' /etc/supervisord.conf
|
||||
systemctl enable supervisord
|
||||
systemctl start supervisord
|
||||
elif [ "${OS}" == "debian" ]; then
|
||||
apt install -y supervisor
|
||||
systemctl enable supervisor
|
||||
systemctl start supervisor
|
||||
else
|
||||
echo -e $HR
|
||||
echo "错误:不支持的操作系统"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
panel writePlugin supervisor 4.2.5
|
||||
33
scripts/supervisor/uninstall.sh
Normal file
33
scripts/supervisor/uninstall.sh
Normal file
@@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
|
||||
|
||||
: '
|
||||
Copyright 2022 HaoZi Technology Co., Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
'
|
||||
|
||||
HR="+----------------------------------------------------"
|
||||
OS=$(source /etc/os-release && { [[ "$ID" == "debian" ]] && echo "debian"; } || { [[ "$ID" == "centos" ]] || [[ "$ID" == "rhel" ]] || [[ "$ID" == "rocky" ]] || [[ "$ID" == "almalinux" ]] && echo "centos"; } || echo "unknown")
|
||||
|
||||
if [ "${OS}" == "centos" ]; then
|
||||
dnf remove -y supervisor
|
||||
elif [ "${OS}" == "debian" ]; then
|
||||
apt remove -y supervisor
|
||||
else
|
||||
echo -e $HR
|
||||
echo "错误:不支持的操作系统"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
panel deletePlugin supervisor
|
||||
Reference in New Issue
Block a user