Compare commits

...
44 Commits
Author SHA1 Message Date
ssongliu 7145d4ca07 fix: 解决概览页流量突增问题 (#2142)
Refs #2073
2023-09-01 17:00:00 +08:00
ali-pay 9683a23fda fix: 解决侧边栏收起状态下菜单长度不一致的问题 (#2137) 2023-09-01 16:59:55 +08:00
ssongliu 5e182d84d0 feat: 防火墙支持删除系统占用端口 (#2116) 2023-09-01 16:59:35 +08:00
ssongliu 9800e7e03d fix: 1pctl 增加非 root 提示信息 (#2112)
Refs #2100
2023-09-01 16:59:30 +08:00
zhengkunwang223 cbf4f8ec36 feat: 修改应用同步方法 2023-08-31 16:21:42 +08:00
ssongliu 3e3b1f2c56 fix: 解决防火墙 ip 规则删除失败的问题 2023-08-31 15:44:11 +08:00
ssongliu e5a7f104f1 fix: 解决版本升级导致无法创建数据库的问题 (#2108) 2023-08-29 17:21:14 +08:00
Allyxandallyxmiko-server 17062da52e fix: 修复压缩包解压时可能的由于父目录不存在导致的解压失败的问题 (#2099)
Co-authored-by: allyxmiko-server <allyxmiko@gmail.com>
2023-08-29 15:50:47 +08:00
zhengkunwang 512c7daeee feat: 修改应用商店版本升级判断条件 (#2089) 2023-08-29 15:50:32 +08:00
zhengkunwang ff120c421e feat: 应用商店增加版本控制 (#2068) 2023-08-29 15:49:58 +08:00
zhengkunwang 4d5993c6ab fix: 解决打开进程守护页面报错的问题 (#2057)
Refs https://github.com/1Panel-dev/1Panel/issues/2051
2023-08-29 15:49:39 +08:00
ssongliu 627e1e3755 feat: 放开 1panel-network 按钮禁用 (#2052) 2023-08-29 15:49:33 +08:00
ssongliu 0eee2d9807 fix: 解决数据库用户名显示错误的问题 (#2028) 2023-08-22 16:33:26 +08:00
zhengkunwang f0e78c4b7c fix: 解决运行环境网站切换PHP版本导致已安装应用消失的问题 (#2026) 2023-08-22 15:42:22 +08:00
ssongliu 6da64f2c8f fix: 解决清空容器日志导致的 CPU 占用异常问题 (#2019)
Refs #1999
2023-08-22 15:42:19 +08:00
ssongliu d572c28d1c fix: 服务器地址支持设置为空 (#2016) 2023-08-22 15:42:13 +08:00
ssongliu 7fac0fcbe8 fix: 解决数据库用户名超长导致用户创建失败的问题 (#2011) 2023-08-22 15:42:09 +08:00
ssongliu cb1b6742d4 fix: 解决防火墙多端口创建失败的问题 (#1988) 2023-08-17 16:59:26 +08:00
ssongliu 27bd4a63ef fix: 延长进程状态获取等待时间 (#1986) 2023-08-17 16:11:11 +08:00
ssongliu 62d628c1aa fix: 解决进程状态一直加载中的问题 (#1983)
Refs #1968
2023-08-17 14:48:09 +08:00
ssongliu 06f81fc7f7 fix: 解决网站反代编辑时回显错误的问题 (#1980)
Refs #1976
2023-08-17 13:55:02 +08:00
wangdan-fit2cloud 23c72c8301 fix: 移动端样式优化 (#1979)
#### What this PR does / why we need it?

#### Summary of your change

#### Please indicate you've done the following:

- [ ] Made sure tests are passing and test coverage is added if needed.
- [ ] Made sure commit message follow the rule of [Conventional Commits specification](https://www.conventionalcommits.org/).
- [ ] Considered the docs impact and opened a new docs issue or PR with docs changes if needed.
2023-08-17 13:54:58 +08:00
ssongliu 280e74e01b fix: 解决 ufw 防火墙创建多端口时无法删除的问题 2023-08-17 10:21:14 +08:00
ssongliu b7dada93da fix: 解决暂停进程被重新拉起的问题 (#1977)
Refs #1964
2023-08-16 23:44:57 +08:00
ssongliu 9447936cc3 fix: 解决获取远程数据库失败的问题 (#1974)
Refs #1925
2023-08-16 23:40:55 +08:00
ssongliu 5e7429cd51 fix: 解决容器编排创建日志加载慢的问题 (#1973)
Refs #1950
2023-08-16 23:40:51 +08:00
ssongliu 7a3716a363 fix: 修改网站重定向列表样式 (#1975)
Refs #1971
2023-08-16 23:40:45 +08:00
wangdan-fit2cloud 5e38723cc1 优化移动端样式 (#1967)
#### What this PR does / why we need it?

#### Summary of your change

#### Please indicate you've done the following:

- [ ] Made sure tests are passing and test coverage is added if needed.
- [ ] Made sure commit message follow the rule of [Conventional Commits specification](https://www.conventionalcommits.org/).
- [ ] Considered the docs impact and opened a new docs issue or PR with docs changes if needed.
2023-08-16 23:40:36 +08:00
ssongliu a0456d0f7a fix: 进程守护区分项目名称和进程名称 (#1952) 2023-08-14 13:38:12 +00:00
ssongliu 35b8532eaa feat: 优化进程守护状态获取方式 (#1943) 2023-08-14 06:02:11 +00:00
zhengkunwang b78b0e67ac fix: 解决登录页切换语言提示信息不更换的问题 (#1939)
Refs https://github.com/1Panel-dev/1Panel/issues/1923
2023-08-14 05:56:11 +00:00
ssongliu 384fc84039 fix: 解决备份压缩报错问题 (#1938) 2023-08-12 22:48:11 +00:00
ssongliu 7ad6e607fe fix: 恢复表格封装代码 (#1937) 2023-08-12 15:24:13 +00:00
ssongliu 27100594a4 fix: 修改 loading (#1936) 2023-08-12 15:12:14 +00:00
ssongliu 0d687daa13 feat: 数据库连接信息增加复制按钮以及超长悬浮显示 (#1935) 2023-08-12 14:36:11 +00:00
ssongliu ad78edda64 fix: 备份文件时忽略文件变化 (#1934) 2023-08-12 13:54:11 +00:00
ssongliu 3e6cd1cab1 feat: 远程数据库增加连接性测试 (#1928)
Refs #1924
2023-08-11 14:20:15 +00:00
ssongliu 98df3806f5 fix: 优化容器清理提示信息 (#1927) 2023-08-11 14:18:17 +00:00
ssongliu 18e8af6234 fix: 容器终端断开连接时,保持抽屉打开 (#1926) 2023-08-11 08:08:14 +00:00
zhengkunwang 5bbda8f842 fix: 解决应用升级镜像拉取失败导致应用服务异常的问题 (#1921) 2023-08-11 07:52:13 +00:00
zhengkunwang 85f8c1e634 feat: 守护进程增加操作列 (#1919) 2023-08-11 07:50:13 +00:00
ssongliu 85c935ee46 fix: 容器创建启动命令提示信息修改 (#1917) 2023-08-11 06:04:12 +00:00
ssongliu b4033471e7 fix: 修改表格分页偶发的数据丢失问题 (#1911)
Refs #1834
2023-08-10 14:36:13 +00:00
ssongliu 8dca519068 feat: 远程数据库地址支持域名 (#1909) 2023-08-10 14:34:23 +00:00
69 changed files with 1180 additions and 544 deletions
+15
View File
@@ -189,6 +189,21 @@ func (b *BaseApi) GetProcess(c *gin.Context) {
helper.SuccessWithData(c, configs)
}
// @Tags Host tool
// @Summary Load Supervisor process status
// @Description 获取 Supervisor 进程状态
// @Success 200 {array} response.ProcessStatus
// @Security ApiKeyAuth
// @Router /host/tool/supervisor/process/load [post]
func (b *BaseApi) LoadProcessStatus(c *gin.Context) {
datas, err := hostToolService.LoadProcessStatus()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, datas)
}
// @Tags Host tool
// @Summary Get Supervisor process config
// @Description 操作 Supervisor 进程文件
+22
View File
@@ -34,6 +34,28 @@ func (b *BaseApi) CreateRemoteDB(c *gin.Context) {
helper.SuccessWithData(c, nil)
}
// @Tags Database
// @Summary Check remote database
// @Description 检测远程数据库连接性
// @Accept json
// @Param request body dto.RemoteDBCreate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/remote/check [post]
// @x-panel-log {"bodyKeys":["name", "type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"检测远程数据库 [name][type] 连接性","formatEN":"check if remote database [name][type] is connectable"}
func (b *BaseApi) CheckeRemoteDB(c *gin.Context) {
var req dto.RemoteDBCreate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
helper.SuccessWithData(c, remoteDBService.CheckeRemoteDB(req))
}
// @Tags Database
// @Summary Page remote databases
// @Description 获取远程数据库列表分页
+2 -1
View File
@@ -67,7 +67,8 @@ type LocalAppInstallDefine struct {
}
type ExtraProperties struct {
Tags []Tag `json:"tags"`
Tags []Tag `json:"tags"`
Version string `json:"version"`
}
type AppProperty struct {
+18 -2
View File
@@ -668,6 +668,21 @@ func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
res.CanUpdate = true
return res, err
}
if err = getAppFromRepo(fmt.Sprintf("%s/%s/1panel.json.zip", global.CONF.System.AppRepo, global.CONF.System.Mode)); err != nil {
return nil, err
}
listFile := path.Join(constant.ResourceDir, "1panel.json")
content, err := os.ReadFile(listFile)
if err != nil {
return nil, err
}
list := &dto.AppList{}
if err = json.Unmarshal(content, list); err != nil {
return nil, err
}
if list.Extra.Version != "" && setting.SystemVersion != list.Extra.Version && !common.CompareVersion(setting.SystemVersion, list.Extra.Version) {
return nil, buserr.New("ErrVersionTooLow")
}
return res, nil
}
@@ -766,7 +781,8 @@ func (a AppService) SyncAppListFromRemote() (err error) {
version := v.Name
detail := detailsMap[version]
dockerComposeUrl := fmt.Sprintf("%s/%s/%s/%s", baseRemoteUrl, app.Key, version, "docker-compose.yml")
remoteVersionUrl := fmt.Sprintf("%s/%s/%s", baseRemoteUrl, app.Key, version)
dockerComposeUrl := fmt.Sprintf("%s/%s", remoteVersionUrl, "docker-compose.yml")
composeRes, err := http.Get(dockerComposeUrl)
if err != nil {
return err
@@ -779,7 +795,7 @@ func (a AppService) SyncAppListFromRemote() (err error) {
paramByte, _ := json.Marshal(v.AppForm)
detail.Params = string(paramByte)
detail.DownloadUrl = v.DownloadUrl
detail.DownloadUrl = fmt.Sprintf("%s/%s", remoteVersionUrl, version+".tar.gz")
detail.DownloadCallBackUrl = v.DownloadCallBackUrl
detail.Update = true
detail.LastModified = v.LastModified
+42
View File
@@ -341,6 +341,24 @@ func upgradeInstall(installId uint, detailId uint, backup bool) error {
install.Version = detail.Version
install.AppDetailId = detailId
images, err := getImages(install)
if err != nil {
upErr = err
return
}
dockerCli, err := composeV2.NewClient()
if err != nil {
upErr = err
return
}
for _, image := range images {
if err = dockerCli.PullImage(image, true); err != nil {
upErr = buserr.WithNameAndErr("ErrDockerPullImage", "", err)
return
}
}
if out, err := compose.Down(install.GetComposePath()); err != nil {
if out != "" {
upErr = errors.New(out)
@@ -398,6 +416,26 @@ func getContainerNames(install model.AppInstall) ([]string, error) {
return containerNames, nil
}
func getImages(install model.AppInstall) ([]string, error) {
envStr, err := coverEnvJsonToStr(install.Env)
if err != nil {
return nil, err
}
project, err := composeV2.GetComposeProject(install.Name, install.GetPath(), []byte(install.DockerCompose), []byte(envStr), true)
if err != nil {
return nil, err
}
imagesMap := make(map[string]struct{})
for _, service := range project.AllServices() {
imagesMap[service.Image] = struct{}{}
}
var images []string
for k := range imagesMap {
images = append(images, k)
}
return images, nil
}
func coverEnvJsonToStr(envJson string) (string, error) {
envMap := make(map[string]interface{})
_ = json.Unmarshal([]byte(envJson), &envMap)
@@ -802,6 +840,10 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool) ([]respons
}
versions = common.GetSortedVersions(versions)
if len(versions) == 0 {
if !updated {
installDTO.CanUpdate = false
res = append(res, installDTO)
}
continue
}
lastVersion := versions[0]
+13 -5
View File
@@ -531,11 +531,15 @@ func (u *ContainerService) ContainerLogClean(req dto.OperationWithName) error {
if err != nil {
return err
}
container, err := client.ContainerInspect(context.Background(), req.Name)
ctx := context.Background()
containerItem, err := client.ContainerInspect(ctx, req.Name)
if err != nil {
return err
}
file, err := os.OpenFile(container.LogPath, os.O_RDWR|os.O_CREATE, 0666)
if err := client.ContainerStop(ctx, containerItem.ID, container.StopOptions{}); err != nil {
return err
}
file, err := os.OpenFile(containerItem.LogPath, os.O_RDWR|os.O_CREATE, 0666)
if err != nil {
return err
}
@@ -545,10 +549,14 @@ func (u *ContainerService) ContainerLogClean(req dto.OperationWithName) error {
}
_, _ = file.Seek(0, 0)
files, _ := filepath.Glob(fmt.Sprintf("%s.*", container.LogPath))
files, _ := filepath.Glob(fmt.Sprintf("%s.*", containerItem.LogPath))
for _, file := range files {
_ = os.Remove(file)
}
if err := client.ContainerStart(ctx, containerItem.ID, types.ContainerStartOptions{}); err != nil {
return err
}
return nil
}
@@ -631,9 +639,9 @@ func (u *ContainerService) ContainerStats(id string) (*dto.ContainerStats, error
func (u *ContainerService) LoadContainerLogs(req dto.OperationWithNameAndType) string {
filePath := ""
switch req.Type {
case "image-pull", "image-push", "image-build":
case "image-pull", "image-push", "image-build", "compose-create":
filePath = path.Join(global.CONF.System.TmpDir, fmt.Sprintf("docker_logs/%s", req.Name))
case "compose-detail", "compose-create":
case "compose-detail":
client, err := docker.NewDockerClient()
if err != nil {
return ""
+10 -3
View File
@@ -159,8 +159,15 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) (string, error)
if req.From == "path" {
req.Name = path.Base(path.Dir(req.Path))
}
logName := path.Dir(req.Path) + "/compose.log"
file, err := os.OpenFile(logName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
dockerLogDir := path.Join(global.CONF.System.TmpDir, "docker_logs")
if _, err := os.Stat(dockerLogDir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(dockerLogDir, os.ModePerm); err != nil {
return "", err
}
}
logItem := fmt.Sprintf("%s/compose_create_%s_%s.log", dockerLogDir, req.Name, time.Now().Format("20060102150405"))
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return "", err
}
@@ -181,7 +188,7 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) (string, error)
_, _ = file.WriteString("docker-compose up successful!")
}()
return req.Name, nil
return path.Base(logItem), nil
}
func (u *ContainerService) ComposeOperation(req dto.ComposeOperation) error {
+5 -3
View File
@@ -221,12 +221,14 @@ func handleTar(sourceDir, targetDir, name, exclusionRules string) error {
path = sourceDir
}
commands := fmt.Sprintf("tar zcvf %s %s %s", targetDir+"/"+name, excludeRules, path)
commands := fmt.Sprintf("tar --warning=no-file-changed -zcf %s %s %s", targetDir+"/"+name, excludeRules, path)
global.LOG.Debug(commands)
stdout, err := cmd.ExecWithTimeOut(commands, 24*time.Hour)
if err != nil {
global.LOG.Errorf("do handle tar failed, stdout: %s, err: %v", stdout, err)
return errors.New(stdout)
if len(stdout) != 0 {
global.LOG.Errorf("do handle tar failed, stdout: %s, err: %v", stdout, err)
return fmt.Errorf("do handle tar failed, stdout: %s, err: %v", stdout, err)
}
}
return nil
}
+32 -39
View File
@@ -166,59 +166,52 @@ func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool)
if err != nil {
return err
}
protos := strings.Split(req.Protocol, "/")
if client.Name() == "ufw" {
req.Port = strings.ReplaceAll(req.Port, "-", ":")
if req.Operation == "remove" && req.Protocol == "tcp/udp" {
req.Protocol = ""
return u.operatePort(client, req)
if len(req.Address) == 0 {
req.Address = "Anywhere"
}
if strings.Contains(req.Port, ",") || strings.Contains(req.Port, "-") {
for _, proto := range protos {
req.Port = strings.ReplaceAll(req.Port, "-", ":")
req.Protocol = proto
if err := u.operatePort(client, req); err != nil {
return err
}
}
return nil
}
if req.Protocol == "tcp/udp" {
req.Protocol = ""
}
if err := u.operatePort(client, req); err != nil {
return err
}
return nil
}
if req.Protocol == "tcp/udp" {
if client.Name() == "firewalld" && strings.Contains(req.Port, ",") {
ports := strings.Split(req.Port, ",")
itemPorts := req.Port
for _, proto := range protos {
if strings.Contains(req.Port, "-") {
req.Protocol = proto
if err := u.operatePort(client, req); err != nil {
return err
}
} else {
ports := strings.Split(itemPorts, ",")
for _, port := range ports {
if len(port) == 0 {
continue
}
req.Port = port
req.Protocol = "tcp"
req.Protocol = proto
if err := u.operatePort(client, req); err != nil {
return err
}
req.Protocol = "udp"
if err := u.operatePort(client, req); err != nil {
return err
}
}
} else {
req.Protocol = "tcp"
if err := u.operatePort(client, req); err != nil {
return err
}
req.Protocol = "udp"
if err := u.operatePort(client, req); err != nil {
return err
}
}
} else {
if strings.Contains(req.Port, ",") {
ports := strings.Split(req.Port, ",")
for _, port := range ports {
req.Port = port
if err := u.operatePort(client, req); err != nil {
return err
}
}
} else {
if err := u.operatePort(client, req); err != nil {
return err
}
}
}
if reload {
return client.Reload()
}
return nil
return client.Reload()
}
func (u *FirewallService) OperateAddressRule(req dto.AddrRuleOperate, reload bool) error {
+71 -35
View File
@@ -3,6 +3,14 @@ package service
import (
"bytes"
"fmt"
"os/exec"
"os/user"
"path"
"strconv"
"strings"
"sync"
"time"
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
"github.com/1Panel-dev/1Panel/backend/buserr"
@@ -14,11 +22,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/utils/systemctl"
"github.com/pkg/errors"
"gopkg.in/ini.v1"
"os/exec"
"os/user"
"path"
"strconv"
"strings"
)
type HostToolService struct{}
@@ -31,6 +34,7 @@ type IHostToolService interface {
GetToolLog(req request.HostToolLogReq) (string, error)
OperateSupervisorProcess(req request.SupervisorProcessConfig) error
GetSupervisorProcessConfig() ([]response.SupervisorProcessConfig, error)
LoadProcessStatus() ([]response.ProcessStatus, error)
OperateSupervisorProcessFile(req request.SupervisorProcessFileReq) (string, error)
}
@@ -323,7 +327,10 @@ func (h *HostToolService) OperateSupervisorProcess(req request.SupervisorProcess
if err = configFile.SaveTo(iniPath); err != nil {
return err
}
return operateSupervisorCtl("reload", "", "")
if err := operateSupervisorCtl("reread", "", ""); err != nil {
return err
}
return operateSupervisorCtl("update", "", "")
case "update":
configFile, err := ini.Load(iniPath)
if err != nil {
@@ -346,7 +353,10 @@ func (h *HostToolService) OperateSupervisorProcess(req request.SupervisorProcess
if err = configFile.SaveTo(iniPath); err != nil {
return err
}
return operateSupervisorCtl("reload", "", "")
if err := operateSupervisorCtl("reread", "", ""); err != nil {
return err
}
return operateSupervisorCtl("update", "", "")
case "restart":
return operateSupervisorCtl("restart", req.Name, "")
case "start":
@@ -358,12 +368,65 @@ func (h *HostToolService) OperateSupervisorProcess(req request.SupervisorProcess
_ = files.NewFileOp().DeleteFile(iniPath)
_ = files.NewFileOp().DeleteFile(outLog)
_ = files.NewFileOp().DeleteFile(errLog)
_ = operateSupervisorCtl("reload", "", "")
if err := operateSupervisorCtl("reread", "", ""); err != nil {
return err
}
return operateSupervisorCtl("update", "", "")
}
return nil
}
func (h *HostToolService) LoadProcessStatus() ([]response.ProcessStatus, error) {
var res []response.ProcessStatus
statusLines, _ := cmd.Exec("supervisorctl status")
if len(statusLines) == 0 {
return res, nil
}
lines := strings.Split(statusLines, "\n")
for _, line := range lines {
fields := strings.Fields(line)
if len(fields) > 1 {
res = append(res, response.ProcessStatus{Name: fields[0]})
}
}
var wg sync.WaitGroup
wg.Add(len(res))
for i := 0; i < len(res); i++ {
go func(index int) {
for t := 0; t < 3; t++ {
status, err := cmd.ExecWithTimeOut(fmt.Sprintf("supervisorctl status %s", res[index].Name), 2*time.Second)
if err != nil {
time.Sleep(2 * time.Second)
continue
}
fields := strings.Fields(status)
if len(fields) < 5 {
time.Sleep(2 * time.Second)
continue
}
res[index].Name = fields[0]
res[index].Status = fields[1]
if fields[1] != "RUNNING" {
res[index].Msg = strings.Join(fields[2:], " ")
break
}
res[index].PID = strings.TrimSuffix(fields[3], ",")
res[index].Uptime = fields[5]
break
}
if len(res[index].Status) == 0 {
res[index].Status = "FATAL"
res[index].Msg = "Timeout for getting process status"
}
wg.Done()
}(i)
}
wg.Wait()
return res, nil
}
func (h *HostToolService) GetSupervisorProcessConfig() ([]response.SupervisorProcessConfig, error) {
var (
result []response.SupervisorProcessConfig
@@ -400,7 +463,6 @@ func (h *HostToolService) GetSupervisorProcessConfig() ([]response.SupervisorPro
if numprocs, _ := section.GetKey("numprocs"); numprocs != nil {
config.Numprocs = numprocs.Value()
}
_ = getProcessStatus(&config)
result = append(result, config)
}
}
@@ -528,29 +590,3 @@ func getProcessName(name, numprocs string) []string {
}
return processNames
}
func getProcessStatus(config *response.SupervisorProcessConfig) error {
var (
processNames = []string{"status"}
)
processNames = append(processNames, getProcessName(config.Name, config.Numprocs)...)
output, _ := exec.Command("supervisorctl", processNames...).Output()
lines := strings.Split(string(output), "\n")
for _, line := range lines {
fields := strings.Fields(line)
if len(fields) >= 5 {
status := response.ProcessStatus{
Name: fields[0],
Status: fields[1],
}
if fields[1] == "RUNNING" {
status.PID = strings.TrimSuffix(fields[3], ",")
status.Uptime = fields[5]
} else {
status.Msg = strings.Join(fields[2:], " ")
}
config.Status = append(config.Status, status)
}
}
return nil
}
+6 -1
View File
@@ -123,7 +123,6 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
return "", err
}
fileName := "Dockerfile"
dockerLogDir := path.Join(global.CONF.System.TmpDir, "docker_logs")
if req.From == "edit" {
dir := fmt.Sprintf("%s/docker/build/%s", constant.DataDir, strings.ReplaceAll(req.Name, ":", "_"))
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
@@ -158,6 +157,12 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
Labels: stringsToMap(req.Tags),
}
dockerLogDir := path.Join(global.CONF.System.TmpDir, "docker_logs")
if _, err := os.Stat(dockerLogDir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(dockerLogDir, os.ModePerm); err != nil {
return "", err
}
}
logItem := fmt.Sprintf("%s/image_build_%s_%s.log", dockerLogDir, strings.ReplaceAll(req.Name, ":", "_"), time.Now().Format("20060102150405"))
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
+16 -1
View File
@@ -16,6 +16,7 @@ type RemoteDBService struct{}
type IRemoteDBService interface {
Get(name string) (dto.RemoteDBInfo, error)
SearchWithPage(search dto.RemoteDBSearch) (int64, interface{}, error)
CheckeRemoteDB(req dto.RemoteDBCreate) bool
Create(req dto.RemoteDBCreate) error
Update(req dto.RemoteDBUpdate) error
Delete(id uint) error
@@ -68,6 +69,20 @@ func (u *RemoteDBService) List(dbType string) ([]dto.RemoteDBOption, error) {
return datas, err
}
func (u *RemoteDBService) CheckeRemoteDB(req dto.RemoteDBCreate) bool {
if _, err := mysql.NewMysqlClient(client.DBInfo{
From: "remote",
Address: req.Address,
Port: req.Port,
Username: req.Username,
Password: req.Password,
Timeout: 6,
}); err != nil {
return false
}
return true
}
func (u *RemoteDBService) Create(req dto.RemoteDBCreate) error {
db, _ := remoteDBRepo.Get(commonRepo.WithByName(req.Name))
if db.ID != 0 {
@@ -79,7 +94,7 @@ func (u *RemoteDBService) Create(req dto.RemoteDBCreate) error {
Port: req.Port,
Username: req.Username,
Password: req.Password,
Timeout: 300,
Timeout: 6,
}); err != nil {
return err
}
+15
View File
@@ -61,3 +61,18 @@ func WithMap(Key string, maps map[string]interface{}, err error) BusinessError {
Err: err,
}
}
func WithNameAndErr(Key string, name string, err error) BusinessError {
paramMap := map[string]interface{}{}
if name != "" {
paramMap["name"] = name
}
if err != nil {
paramMap["err"] = err.Error()
}
return BusinessError{
Msg: Key,
Map: paramMap,
Err: err,
}
}
+2
View File
@@ -45,6 +45,8 @@ ErrImagePullTimeOut: 'Image pull timeout'
ErrContainerNotFound: '{{ .name }} container does not exist'
ErrContainerMsg: '{{ .name }} container is abnormal, please check the log on the container page for details'
ErrAppBackup: '{{ .name }} application backup failed err {{.err}}'
ErrImagePull: '{{ .name }} image pull failed err {{.err}}'
ErrVersionTooLow: 'The current 1Panel version is too low to update the app store, please upgrade the version'
#file
ErrFileCanNotRead: "File can not read"
+2
View File
@@ -45,6 +45,8 @@ ErrImagePullTimeOut: "鏡像拉取超時"
ErrContainerNotFound: '{{ .name }} 容器不存在'
ErrContainerMsg: '{{ .name }} 容器異常,具體請在容器頁面查看日誌'
ErrAppBackup: '{{ .name }} 應用備份失敗 err {{.err}}'
ErrImagePull: '{{ .name }} 鏡像拉取失敗 err {{.err}}'
ErrVersionTooLow: '當前 1Panel 版本過低,無法更新應用商店,請升級版本之後操作'
#file
ErrFileCanNotRead: "此文件不支持預覽"
+2
View File
@@ -45,6 +45,8 @@ ErrImagePullTimeOut: '镜像拉取超时'
ErrContainerNotFound: '{{ .name }} 容器不存在'
ErrContainerMsg: '{{ .name }} 容器异常,具体请在容器页面查看日志'
ErrAppBackup: '{{ .name }} 应用备份失败 err {{.err}}'
ErrImagePull: '镜像拉取失败 {{.err}}'
ErrVersionTooLow: '当前 1Panel 版本过低,无法更新应用商店,请升级版本之后操作'
#file
ErrFileCanNotRead: "此文件不支持预览"
+1
View File
@@ -43,6 +43,7 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) {
cmdRouter.POST("/redis/conffile/update", baseApi.UpdateRedisConfByFile)
cmdRouter.POST("/redis/persistence/update", baseApi.UpdateRedisPersistenceConf)
cmdRouter.POST("/remote/check", baseApi.CheckeRemoteDB)
cmdRouter.POST("/remote", baseApi.CreateRemoteDB)
cmdRouter.GET("/remote/:name", baseApi.GetRemoteDB)
cmdRouter.GET("/remote/list/:type", baseApi.ListRemoteDB)
+1
View File
@@ -54,6 +54,7 @@ func (s *HostRouter) InitHostRouter(Router *gin.RouterGroup) {
hostRouter.POST("/tool/operate", baseApi.OperateTool)
hostRouter.POST("/tool/config", baseApi.OperateToolConfig)
hostRouter.POST("/tool/log", baseApi.GetToolLog)
hostRouter.POST("/tool/supervisor/process/load", baseApi.LoadProcessStatus)
hostRouter.POST("/tool/supervisor/process", baseApi.OperateProcess)
hostRouter.GET("/tool/supervisor/process", baseApi.GetProcess)
hostRouter.POST("/tool/supervisor/process/file", baseApi.GetProcessFile)
-22
View File
@@ -4,11 +4,7 @@ import (
"context"
"github.com/compose-spec/compose-go/loader"
"github.com/compose-spec/compose-go/types"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/flags"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/compose"
"github.com/docker/docker/client"
"github.com/joho/godotenv"
"path"
"regexp"
@@ -21,24 +17,6 @@ type ComposeService struct {
project *types.Project
}
func NewComposeService(ops ...command.DockerCliOption) (*ComposeService, error) {
apiClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return nil, err
}
ops = append(ops, command.WithAPIClient(apiClient), command.WithDefaultContextStoreConfig())
cli, err := command.NewDockerCli(ops...)
if err != nil {
return nil, err
}
cliOp := flags.NewClientOptions()
if err := cli.Initialize(cliOp); err != nil {
return nil, err
}
service := compose.NewComposeService(cli)
return &ComposeService{service, nil}, nil
}
func (s *ComposeService) SetProject(project *types.Project) {
s.project = project
for i, s := range project.Services {
+28
View File
@@ -72,6 +72,22 @@ func (c Client) DeleteImage(imageID string) error {
return nil
}
func (c Client) PullImage(imageName string, force bool) error {
if !force {
exist, err := c.CheckImageExist(imageName)
if err != nil {
return err
}
if exist {
return nil
}
}
if _, err := c.cli.ImagePull(context.Background(), imageName, types.ImagePullOptions{}); err != nil {
return err
}
return nil
}
func (c Client) GetImageIDByName(imageName string) (string, error) {
filter := filters.NewArgs()
filter.Add("reference", imageName)
@@ -87,6 +103,18 @@ func (c Client) GetImageIDByName(imageName string) (string, error) {
return "", nil
}
func (c Client) CheckImageExist(imageName string) (bool, error) {
filter := filters.NewArgs()
filter.Add("reference", imageName)
list, err := c.cli.ImageList(context.Background(), types.ImageListOptions{
Filters: filter,
})
if err != nil {
return false, err
}
return len(list) > 0, nil
}
func (c Client) NetworkExist(name string) bool {
var options types.NetworkListOptions
options.Filters = filters.NewArgs(filters.Arg("name", name))
+7
View File
@@ -518,6 +518,13 @@ func (f FileOp) Decompress(srcFile string, dst string, cType CompressType) error
return err
}
return nil
} else {
parentDir := path.Dir(filePath)
if !f.Stat(parentDir) {
if err := f.Fs.MkdirAll(parentDir, info.Mode()); err != nil {
return err
}
}
}
fr, err := archFile.Open()
if err != nil {
+10 -5
View File
@@ -1,12 +1,13 @@
package mysql
import (
"context"
"database/sql"
"fmt"
"time"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/mysql/client"
)
@@ -26,9 +27,6 @@ type MysqlClient interface {
func NewMysqlClient(conn client.DBInfo) (MysqlClient, error) {
if conn.From == "local" {
if cmd.CheckIllegal(conn.Address, conn.Username, conn.Password) {
return nil, buserr.New(constant.ErrCmdIllegal)
}
connArgs := []string{"exec", conn.Address, "mysql", "-u" + conn.Username, "-p" + conn.Password, "-e"}
return client.NewLocal(connArgs, conn.Address, conn.Password, conn.From), nil
}
@@ -38,9 +36,16 @@ func NewMysqlClient(conn client.DBInfo) (MysqlClient, error) {
if err != nil {
return nil, err
}
if err := db.Ping(); err != nil {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(conn.Timeout)*time.Second)
defer cancel()
if err := db.PingContext(ctx); err != nil {
return nil, err
}
if ctx.Err() == context.DeadlineExceeded {
return nil, buserr.New(constant.ErrExecTimeOut)
}
return client.NewRemote(client.Remote{
Client: db,
From: conn.From,
+19
View File
@@ -1,5 +1,11 @@
package client
import (
"strings"
"github.com/1Panel-dev/1Panel/backend/utils/common"
)
type DBInfo struct {
From string `json:"from"`
Address string `json:"address"`
@@ -85,3 +91,16 @@ var formatMap = map[string]string{
"gbk": "gbk_chinese_ci",
"big5": "big5_chinese_ci",
}
func loadNameByDB(name, version string) string {
if strings.HasPrefix(version, "5.6") {
if len(name) <= 16 {
return name
}
return strings.TrimSuffix(name[:10], "_") + "_" + common.RandStr(5)
}
if len(name) <= 32 {
return name
}
return strings.TrimSuffix(name[:25], "_") + "_" + common.RandStr(5)
}
+8 -8
View File
@@ -38,7 +38,7 @@ func (r *Local) Create(info CreateInfo) error {
return err
}
if err := r.CreateUser(info); err != nil {
if err := r.CreateUser(info, true); err != nil {
_ = r.ExecSQL(fmt.Sprintf("drop database if exists `%s`", info.Name), info.Timeout)
return err
}
@@ -46,7 +46,7 @@ func (r *Local) Create(info CreateInfo) error {
return nil
}
func (r *Local) CreateUser(info CreateInfo) error {
func (r *Local) CreateUser(info CreateInfo, withDeleteDB bool) error {
var userlist []string
if strings.Contains(info.Permission, ",") {
ips := strings.Split(info.Permission, ",")
@@ -147,7 +147,7 @@ func (r *Local) ChangePassword(info PasswordChangeInfo) error {
for _, user := range userlist {
passwordChangeSql := fmt.Sprintf("set password for %s = password('%s')", user, info.Password)
if !strings.HasPrefix(info.Version, "5.7") && !strings.HasPrefix(info.Version, "5.6") {
passwordChangeSql = fmt.Sprintf("ALTER USER %s IDENTIFIED WITH mysql_native_password BY '%s';", user, info.Password)
passwordChangeSql = fmt.Sprintf("alter user %s identified by '%s';", user, info.Password)
}
if err := r.ExecSQL(passwordChangeSql, info.Timeout); err != nil {
return err
@@ -201,7 +201,7 @@ func (r *Local) ChangeAccess(info AccessChangeInfo) error {
Password: info.Password,
Permission: info.Permission,
Timeout: info.Timeout,
}); err != nil {
}, false); err != nil {
return err
}
if err := r.ExecSQL("flush privileges", 300); err != nil {
@@ -276,7 +276,7 @@ func (r *Local) SyncDB(version string) ([]SyncDBInfo, error) {
From: r.From,
Format: parts[1],
}
userLines, err := r.ExecSQLForRows(fmt.Sprintf("SELECT USER,HOST FROM mysql.DB WHERE DB = '%s'", parts[0]), 300)
userLines, err := r.ExecSQLForRows(fmt.Sprintf("select user,host from mysql.db where db = '%s'", parts[0]), 300)
if err != nil {
return datas, err
}
@@ -305,18 +305,18 @@ func (r *Local) SyncDB(version string) ([]SyncDBInfo, error) {
}
}
if len(dataItem.Username) == 0 {
dataItem.Username = loadNameByDB(parts[0], version)
if err := r.CreateUser(CreateInfo{
Name: parts[0],
Format: parts[1],
Version: version,
Username: parts[0],
Username: dataItem.Username,
Password: common.RandStr(16),
Permission: "%",
Timeout: 300,
}); err != nil {
}, false); err != nil {
global.LOG.Errorf("sync from remote server failed, err: create user failed %v", err)
}
dataItem.Username = parts[0]
dataItem.Permission = "%"
} else {
if isLocal {
+29 -25
View File
@@ -39,7 +39,7 @@ func (r *Remote) Create(info CreateInfo) error {
return err
}
if err := r.CreateUser(info); err != nil {
if err := r.CreateUser(info, true); err != nil {
_ = r.ExecSQL(fmt.Sprintf("drop database if exists `%s`", info.Name), info.Timeout)
return err
}
@@ -47,7 +47,7 @@ func (r *Remote) Create(info CreateInfo) error {
return nil
}
func (r *Remote) CreateUser(info CreateInfo) error {
func (r *Remote) CreateUser(info CreateInfo, withDeleteDB bool) error {
var userlist []string
if strings.Contains(info.Permission, ",") {
ips := strings.Split(info.Permission, ",")
@@ -62,15 +62,17 @@ func (r *Remote) CreateUser(info CreateInfo) error {
for _, user := range userlist {
if err := r.ExecSQL(fmt.Sprintf("create user %s identified by '%s';", user, info.Password), info.Timeout); err != nil {
_ = r.Delete(DeleteInfo{
Name: info.Name,
Version: info.Version,
Username: info.Username,
Permission: info.Permission,
ForceDelete: true,
Timeout: 300})
if strings.Contains(err.Error(), "ERROR 1396") {
return buserr.New(constant.ErrUserIsExist)
if withDeleteDB {
_ = r.Delete(DeleteInfo{
Name: info.Name,
Version: info.Version,
Username: info.Username,
Permission: info.Permission,
ForceDelete: true,
Timeout: 300})
if strings.Contains(err.Error(), "ERROR 1396") {
return buserr.New(constant.ErrUserIsExist)
}
}
return err
}
@@ -82,13 +84,15 @@ func (r *Remote) CreateUser(info CreateInfo) error {
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, info.Password)
}
if err := r.ExecSQL(grantStr, info.Timeout); err != nil {
_ = r.Delete(DeleteInfo{
Name: info.Name,
Version: info.Version,
Username: info.Username,
Permission: info.Permission,
ForceDelete: true,
Timeout: 300})
if withDeleteDB {
_ = r.Delete(DeleteInfo{
Name: info.Name,
Version: info.Version,
Username: info.Username,
Permission: info.Permission,
ForceDelete: true,
Timeout: 300})
}
return err
}
}
@@ -202,7 +206,7 @@ func (r *Remote) ChangeAccess(info AccessChangeInfo) error {
Password: info.Password,
Permission: info.Permission,
Timeout: info.Timeout,
}); err != nil {
}, false); err != nil {
return err
}
if err := r.ExecSQL("flush privileges", 300); err != nil {
@@ -263,7 +267,7 @@ func (r *Remote) Recover(info RecoverInfo) error {
func (r *Remote) SyncDB(version string) ([]SyncDBInfo, error) {
var datas []SyncDBInfo
rows, err := r.Client.Query("SELECT SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME FROM information_schema.SCHEMATA")
rows, err := r.Client.Query("select schema_name, default_character_set_name from information_schema.SCHEMATA")
if err != nil {
return datas, err
}
@@ -283,7 +287,7 @@ func (r *Remote) SyncDB(version string) ([]SyncDBInfo, error) {
MysqlName: r.From,
Format: charsetName,
}
userRows, err := r.Client.Query("SELECT USER,HOST FROM mysql.DB WHERE DB = ?", dbName)
userRows, err := r.Client.Query("select user,host from mysql.db where db = ?", dbName)
if err != nil {
return datas, err
}
@@ -312,18 +316,18 @@ func (r *Remote) SyncDB(version string) ([]SyncDBInfo, error) {
i++
}
if len(dataItem.Username) == 0 {
dataItem.Username = loadNameByDB(dbName, version)
if err := r.CreateUser(CreateInfo{
Name: dbName,
Format: charsetName,
Version: version,
Username: dbName,
Username: dataItem.Username,
Password: common.RandStr(16),
Permission: "%",
Timeout: 300,
}); err != nil {
global.LOG.Errorf("sync from remote server failed, err: create user failed %v", err)
}, false); err != nil {
return datas, fmt.Errorf("sync db from remote server failed, err: create user failed %v", err)
}
dataItem.Username = dbName
dataItem.Permission = "%"
} else {
if isLocal {
+6 -1
View File
@@ -3,11 +3,12 @@ package cmd
import (
"bytes"
"fmt"
"io"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"github.com/1Panel-dev/1Panel/cmd/server/app"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"io"
)
var (
@@ -31,6 +32,10 @@ var initCmd = &cobra.Command{
Use: "init",
Short: "初始化应用",
RunE: func(cmd *cobra.Command, args []string) error {
if !isRoot() {
fmt.Println("请使用 sudo 1pctl app init 或者切换到 root 用户")
return nil
}
if len(args) > 0 {
appKey = args[0]
if len(args) > 1 {
+22
View File
@@ -1,6 +1,8 @@
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
@@ -22,6 +24,10 @@ var resetMFACmd = &cobra.Command{
Use: "mfa",
Short: "取消 1Panel 两步验证",
RunE: func(cmd *cobra.Command, args []string) error {
if !isRoot() {
fmt.Println("请使用 sudo 1pctl reset mfa 或者切换到 root 用户")
return nil
}
db, err := loadDBConn()
if err != nil {
return err
@@ -34,6 +40,10 @@ var resetSSLCmd = &cobra.Command{
Use: "https",
Short: "取消 1Panel https 方式登录",
RunE: func(cmd *cobra.Command, args []string) error {
if !isRoot() {
fmt.Println("请使用 sudo 1pctl reset https 或者切换到 root 用户")
return nil
}
db, err := loadDBConn()
if err != nil {
return err
@@ -46,6 +56,10 @@ var resetEntranceCmd = &cobra.Command{
Use: "entrance",
Short: "取消 1Panel 安全入口",
RunE: func(cmd *cobra.Command, args []string) error {
if !isRoot() {
fmt.Println("请使用 sudo 1pctl reset entrance 或者切换到 root 用户")
return nil
}
db, err := loadDBConn()
if err != nil {
return err
@@ -58,6 +72,10 @@ var resetBindIpsCmd = &cobra.Command{
Use: "ips",
Short: "取消 1Panel 授权 IP 限制",
RunE: func(cmd *cobra.Command, args []string) error {
if !isRoot() {
fmt.Println("请使用 sudo 1pctl reset ips 或者切换到 root 用户")
return nil
}
db, err := loadDBConn()
if err != nil {
return err
@@ -70,6 +88,10 @@ var resetDomainCmd = &cobra.Command{
Use: "domain",
Short: "取消 1Panel 访问域名绑定",
RunE: func(cmd *cobra.Command, args []string) error {
if !isRoot() {
fmt.Println("请使用 sudo 1pctl reset domain 或者切换到 root 用户")
return nil
}
db, err := loadDBConn()
if err != nil {
return err
+9
View File
@@ -2,6 +2,7 @@ package cmd
import (
"fmt"
"os/user"
"strings"
"time"
@@ -61,3 +62,11 @@ func getSettingByKey(db *gorm.DB, key string) string {
func setSettingByKey(db *gorm.DB, key, value string) error {
return db.Model(&setting{}).Where("key = ?", key).Updates(map[string]interface{}{"value": value}).Error
}
func isRoot() bool {
currentUser, err := user.Current()
if err != nil {
return false
}
return currentUser.Uid == "0"
}
+4
View File
@@ -16,6 +16,10 @@ var userinfoCmd = &cobra.Command{
Use: "user-info",
Short: "获取用户信息",
RunE: func(cmd *cobra.Command, args []string) error {
if !isRoot() {
fmt.Println("请使用 sudo 1pctl user-info 或者切换到 root 用户")
return nil
}
db, err := loadDBConn()
if err != nil {
return fmt.Errorf("init my db conn failed, err: %v \n", err)
+4
View File
@@ -18,6 +18,10 @@ var versionCmd = &cobra.Command{
Use: "version",
Short: "获取系统版本信息",
RunE: func(cmd *cobra.Command, args []string) error {
if !isRoot() {
fmt.Println("请使用 sudo 1pctl version 或者切换到 root 用户")
return nil
}
db, err := loadDBConn()
if err != nil {
return err
+96 -5
View File
@@ -4410,6 +4410,49 @@ const docTemplate = `{
}
}
},
"/databases/remote/check": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "检测远程数据库连接性",
"consumes": [
"application/json"
],
"tags": [
"Database"
],
"summary": "Check remote database",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.RemoteDBCreate"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFuntions": [],
"bodyKeys": [
"name",
"type"
],
"formatEN": "check if remote database [name][type] is connectable",
"formatZH": "检测远程数据库 [name][type] 连接性",
"paramKeys": []
}
}
},
"/databases/remote/del": {
"post": {
"security": [
@@ -6297,6 +6340,31 @@ const docTemplate = `{
}
}
},
"/host/tool/supervisor/process/load": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取 Supervisor 进程状态",
"tags": [
"Host tool"
],
"summary": "Load Supervisor process status",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/response.ProcessStatus"
}
}
}
}
}
},
"/hosts": {
"post": {
"security": [
@@ -11621,7 +11689,6 @@ const docTemplate = `{
"dto.ChangeDBInfo": {
"type": "object",
"required": [
"from",
"value"
],
"properties": {
@@ -12923,13 +12990,15 @@ const docTemplate = `{
"type": "integer"
},
"password": {
"type": "string"
"type": "string",
"maxLength": 256
},
"protocol": {
"type": "string"
},
"username": {
"type": "string"
"type": "string",
"maxLength": 256
}
}
},
@@ -13776,7 +13845,8 @@ const docTemplate = `{
]
},
"name": {
"type": "string"
"type": "string",
"maxLength": 256
},
"password": {
"type": "string"
@@ -13817,7 +13887,8 @@ const docTemplate = `{
"type": "integer"
},
"name": {
"type": "string"
"type": "string",
"maxLength": 256
},
"password": {
"type": "string"
@@ -16978,6 +17049,26 @@ const docTemplate = `{
}
}
},
"response.ProcessStatus": {
"type": "object",
"properties": {
"PID": {
"type": "string"
},
"msg": {
"type": "string"
},
"name": {
"type": "string"
},
"status": {
"type": "string"
},
"uptime": {
"type": "string"
}
}
},
"response.WebsiteAcmeAccountDTO": {
"type": "object",
"properties": {
+96 -5
View File
@@ -4403,6 +4403,49 @@
}
}
},
"/databases/remote/check": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "检测远程数据库连接性",
"consumes": [
"application/json"
],
"tags": [
"Database"
],
"summary": "Check remote database",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.RemoteDBCreate"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFuntions": [],
"bodyKeys": [
"name",
"type"
],
"formatEN": "check if remote database [name][type] is connectable",
"formatZH": "检测远程数据库 [name][type] 连接性",
"paramKeys": []
}
}
},
"/databases/remote/del": {
"post": {
"security": [
@@ -6290,6 +6333,31 @@
}
}
},
"/host/tool/supervisor/process/load": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取 Supervisor 进程状态",
"tags": [
"Host tool"
],
"summary": "Load Supervisor process status",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/response.ProcessStatus"
}
}
}
}
}
},
"/hosts": {
"post": {
"security": [
@@ -11614,7 +11682,6 @@
"dto.ChangeDBInfo": {
"type": "object",
"required": [
"from",
"value"
],
"properties": {
@@ -12916,13 +12983,15 @@
"type": "integer"
},
"password": {
"type": "string"
"type": "string",
"maxLength": 256
},
"protocol": {
"type": "string"
},
"username": {
"type": "string"
"type": "string",
"maxLength": 256
}
}
},
@@ -13769,7 +13838,8 @@
]
},
"name": {
"type": "string"
"type": "string",
"maxLength": 256
},
"password": {
"type": "string"
@@ -13810,7 +13880,8 @@
"type": "integer"
},
"name": {
"type": "string"
"type": "string",
"maxLength": 256
},
"password": {
"type": "string"
@@ -16971,6 +17042,26 @@
}
}
},
"response.ProcessStatus": {
"type": "object",
"properties": {
"PID": {
"type": "string"
},
"msg": {
"type": "string"
},
"name": {
"type": "string"
},
"status": {
"type": "string"
},
"uptime": {
"type": "string"
}
}
},
"response.WebsiteAcmeAccountDTO": {
"type": "object",
"properties": {
+60 -1
View File
@@ -127,7 +127,6 @@ definitions:
value:
type: string
required:
- from
- value
type: object
dto.ChangeHostGroup:
@@ -1000,10 +999,12 @@ definitions:
id:
type: integer
password:
maxLength: 256
type: string
protocol:
type: string
username:
maxLength: 256
type: string
type: object
dto.ImageSave:
@@ -1565,6 +1566,7 @@ definitions:
- remote
type: string
name:
maxLength: 256
type: string
password:
type: string
@@ -1599,6 +1601,7 @@ definitions:
id:
type: integer
name:
maxLength: 256
type: string
password:
type: string
@@ -3711,6 +3714,19 @@ definitions:
uploadMaxSize:
type: string
type: object
response.ProcessStatus:
properties:
PID:
type: string
msg:
type: string
name:
type: string
status:
type: string
uptime:
type: string
type: object
response.WebsiteAcmeAccountDTO:
properties:
createdAt:
@@ -6648,6 +6664,34 @@ paths:
summary: Get remote databases
tags:
- Database
/databases/remote/check:
post:
consumes:
- application/json
description: 检测远程数据库连接性
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.RemoteDBCreate'
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
summary: Check remote database
tags:
- Database
x-panel-log:
BeforeFuntions: []
bodyKeys:
- name
- type
formatEN: check if remote database [name][type] is connectable
formatZH: 检测远程数据库 [name][type] 连接性
paramKeys: []
/databases/remote/del:
post:
consumes:
@@ -7849,6 +7893,21 @@ paths:
formatEN: '[operate] Supervisor Process Config file'
formatZH: '[operate] Supervisor 进程文件 '
paramKeys: []
/host/tool/supervisor/process/load:
post:
description: 获取 Supervisor 进程状态
responses:
"200":
description: OK
schema:
items:
$ref: '#/definitions/response.ProcessStatus'
type: array
security:
- ApiKeyAuth: []
summary: Load Supervisor process status
tags:
- Host tool
/hosts:
post:
consumes:
+1 -1
View File
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en">
<html>
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/public/favicon.png" />
+5 -2
View File
@@ -100,11 +100,14 @@ export const searchRemoteDBs = (params: Database.SearchRemoteDBPage) => {
export const listRemoteDBs = (type: string) => {
return http.get<Array<Database.RemoteDBOption>>(`/databases/remote/list/${type}`);
};
export const checkRemoteDB = (params: Database.RemoteDBCreate) => {
return http.post<boolean>(`/databases/remote/check`, params, 40000);
};
export const addRemoteDB = (params: Database.RemoteDBCreate) => {
return http.post(`/databases/remote`, params);
return http.post(`/databases/remote`, params, 40000);
};
export const editRemoteDB = (params: Database.RemoteDBUpdate) => {
return http.post(`/databases/remote/update`, params);
return http.post(`/databases/remote/update`, params, 40000);
};
export const deleteRemoteDB = (id: number) => {
return http.post(`/databases/remote/del`, { id: id });
+4
View File
@@ -29,6 +29,10 @@ export const OperateSupervisorProcess = (req: HostTool.ProcessReq) => {
return http.post<any>(`/hosts/tool/supervisor/process`, req, 100000);
};
export const LoadProcessStatus = () => {
return http.post<Array<HostTool.ProcessStatus>>(`/hosts/tool/supervisor/process/load`, {}, 40000);
};
export const GetSupervisorProcess = () => {
return http.get<HostTool.SupersivorProcess>(`/hosts/tool/supervisor/process`);
};
+16 -27
View File
@@ -3,24 +3,10 @@
<div class="complex-table__header" v-if="$slots.header || header">
<slot name="header">{{ header }}</slot>
</div>
<div v-if="$slots.toolbar && !searchConfig" style="margin-bottom: 10px">
<div v-if="$slots.toolbar" style="margin-bottom: 10px">
<slot name="toolbar"></slot>
</div>
<template v-if="searchConfig">
<fu-filter-bar v-bind="searchConfig" @exec="search">
<template #tl>
<slot name="toolbar"></slot>
</template>
<template #default>
<slot name="complex"></slot>
</template>
<template #buttons>
<slot name="buttons"></slot>
</template>
</fu-filter-bar>
</template>
<div class="complex-table__body">
<fu-table v-bind="$attrs" ref="tableRef" @selection-change="handleSelectionChange">
<slot></slot>
@@ -30,13 +16,14 @@
</fu-table>
</div>
<div class="complex-table__pagination" v-if="$slots.pagination || paginationConfig">
<div class="complex-table__pagination" v-if="props.paginationConfig">
<slot name="pagination">
<fu-table-pagination
v-model:current-page="paginationConfig.currentPage"
v-model:page-size="paginationConfig.pageSize"
v-bind="paginationConfig"
@change="search"
:total="paginationConfig.total"
@size-change="sizeChange"
@current-change="currentChange"
:small="mobile"
:layout="mobile ? 'total, prev, pager, next' : 'total, sizes, prev, pager, next, jumper'"
/>
@@ -49,15 +36,15 @@ import { ref, computed } from 'vue';
import { GlobalStore } from '@/store';
defineOptions({ name: 'ComplexTable' });
defineProps({
const props = defineProps({
header: String,
searchConfig: Object,
paginationConfig: {
type: Object,
required: false,
default: () => {},
},
});
const emit = defineEmits(['search', 'update:selects']);
const emit = defineEmits(['search', 'update:selects', 'update:paginationConfig']);
const globalStore = GlobalStore();
@@ -65,13 +52,15 @@ const mobile = computed(() => {
return globalStore.isMobile();
});
const condition = ref({});
const tableRef = ref();
function search(conditions: any, e: any) {
if (conditions) {
condition.value = conditions;
}
emit('search', condition.value, e);
function currentChange() {
emit('search');
}
function sizeChange() {
props.paginationConfig.currentPage = 1;
emit('search');
}
function handleSelectionChange(row: any) {
@@ -1,7 +1,7 @@
<template>
<div>
<div style="display: flex; flex-wrap: wrap">
<el-select @change="searchLogs" v-model="logSearch.mode" style="width: 100px">
<el-select @change="searchLogs" v-model="logSearch.mode" style="width: 150px">
<template #prefix>{{ $t('container.fetch') }}</template>
<el-option v-for="item in timeOptions" :key="item.label" :value="item.value" :label="item.label" />
</el-select>
@@ -130,7 +130,7 @@ const acceptParams = (props: DialogProps): void => {
};
const onClean = async () => {
ElMessageBox.confirm(i18n.global.t('commons.msg.clean'), i18n.global.t('container.cleanLog'), {
ElMessageBox.confirm(i18n.global.t('container.cleanLogHelper'), i18n.global.t('container.cleanLog'), {
confirmButtonText: i18n.global.t('commons.button.confirm'),
cancelButtonText: i18n.global.t('commons.button.cancel'),
type: 'info',
+18 -14
View File
@@ -13,20 +13,7 @@ const terminalElement = ref<HTMLDivElement | null>(null);
const fitAddon = new FitAddon();
const termReady = ref(false);
const webSocketReady = ref(false);
const term = ref(
new Terminal({
lineHeight: 1.2,
fontSize: 12,
fontFamily: "Monaco, Menlo, Consolas, 'Courier New', monospace",
theme: {
background: '#000000',
},
cursorBlink: true,
cursorStyle: 'underline',
scrollback: 100,
tabStopWidth: 4,
}),
);
const term = ref();
const terminalSocket = ref<WebSocket>();
const heartbeatTimer = ref<number>();
const latency = ref(0);
@@ -56,6 +43,21 @@ const acceptParams = (props: WsProps) => {
});
};
const newTerm = () => {
term.value = new Terminal({
lineHeight: 1.2,
fontSize: 12,
fontFamily: "Monaco, Menlo, Consolas, 'Courier New', monospace",
theme: {
background: '#000000',
},
cursorBlink: true,
cursorStyle: 'underline',
scrollback: 100,
tabStopWidth: 4,
});
};
const init = (endpoint: string, args: string) => {
if (initTerminal(true)) {
initWebSocket(endpoint, args);
@@ -78,11 +80,13 @@ function onClose(isKeepShow: boolean = false) {
term.value.dispose();
} catch {}
}
terminalElement.value.innerHTML = '';
}
// terminal 相关代码 start
const initTerminal = (online: boolean = false): boolean => {
newTerm();
if (terminalElement.value) {
term.value.open(terminalElement.value);
term.value.loadAddon(fitAddon);
+23 -9
View File
@@ -479,7 +479,10 @@ const message = {
rename: 'Rename',
remove: 'Remove',
containerPrune: 'Container prune',
containerPruneHelper: 'Remove all stopped containers. Do you want to continue?',
containerPruneHelper1: 'Cleaning containers will delete all containers that are in a stopped state.',
containerPruneHelper2:
'If the containers are from the app store, after performing the cleanup, you need to go to the [Installed] list in the [App Store] and click the [Rebuild] button to reinstall them.',
containerPruneHelper3: 'This operation cannot be rolled back. Do you want to continue?',
imagePrune: 'Image prune',
imagePruneSome: 'Clean unlabeled',
imagePruneSomeHelper: 'Remove all unused and unlabeled container images。',
@@ -504,6 +507,8 @@ const message = {
lastHour: 'Last Hour',
last10Min: 'Last 10 Minutes',
cleanLog: 'Clean log',
cleanLogHelper:
'Clearing logs requires restarting the container, and this operation cannot be rolled back. Do you want to continue?',
newName: 'New name',
source: 'Resource rate',
cpuShare: 'CPU Share',
@@ -533,7 +538,7 @@ const message = {
exposePort: 'Expose port',
exposeAll: 'Expose all',
cmd: 'Command',
cmdHelper: 'Example: echo "hello"',
cmdHelper: "Separate multiple commands with ' ' as delimiter, such as 'nginx' '-g' 'daemon off;'",
autoRemove: 'Auto remove',
cpuQuota: 'NacosCPU',
memoryLimit: 'Memory',
@@ -1460,12 +1465,12 @@ const message = {
certificatePath: 'Certificate file',
ipWhiteListHelper: 'The role of IP whitelist: all rules are invalid for IP whitelist',
redirect: 'redirect',
sourceDomain: 'source domain name/path',
sourceDomain: 'Source domain',
targetURL: 'Target URL address',
keepPath: 'Keep URI parameters',
keepPath: 'URI params',
path: 'path',
redirectType: 'redirection type',
redirectWay: 'way',
redirectWay: 'Way',
keep: 'keep',
notKeep: 'Do not keep',
redirectRoot: 'Redirect to the homepage',
@@ -1663,15 +1668,16 @@ const message = {
},
tool: {
supervisor: {
loadStatusErr: 'Failed to retrieve process status, please check the status of the supervisor service.',
notSupport: 'Supervisor is not detected, please refer to the official document for installation',
list: 'Daemon process',
config: 'Supervisor configuration',
primaryConfig: 'Main configuration file location',
notSupportCrl: 'The supervisorctl is not detected, please refer to the official document for installation',
user: 'start user',
command: 'start command',
dir: 'run directory',
numprocs: 'Number of processes',
user: 'User',
command: 'Command',
dir: 'Directory',
numprocs: 'Numprocs',
initWarn:
'The initialization operation needs to modify the [include] files parameter of the configuration file, the directory where the modified service configuration file is located: 1panel installation directory/1panel/tools/supervisord/supervisor.d/',
operatorHelper: 'Operation {1} will be performed on {0}, continue? ',
@@ -1684,6 +1690,14 @@ const message = {
restartHelper:
'Initialization will restart the service, causing all the original daemon processes to close',
msg: 'Message',
RUNNING: 'Running',
STOPPED: 'Stopped',
STOPPING: 'Stopping',
STARTING: 'Starting',
FATAL: 'Failed to start',
BACKOFF: 'Start exception',
statusCode: 'Status code',
manage: 'Management',
},
},
};
+15 -2
View File
@@ -469,7 +469,10 @@ const message = {
rename: '重命名',
remove: '刪除',
containerPrune: '清理容器',
containerPruneHelper: '清理容器 將刪除所有處於停止狀態的容器,該操作無法回滾,是否繼續?',
containerPruneHelper1: '清理容器 將刪除所有處於停止狀態的容器。',
containerPruneHelper2:
'若容器來自於應用商店,在執行清理操作後,您需要前往 [應用商店] 的 [已安裝] 列表,點擊 [重建] 按鈕進行重新安裝。',
containerPruneHelper3: '該操作無法回滾,是否繼續?',
imagePrune: '清理鏡像',
imagePruneSome: '未標簽鏡像',
imagePruneSomeHelper: '清理標簽為 none 且未被任何容器使用的鏡像。',
@@ -493,6 +496,7 @@ const message = {
lastHour: '最近 1 小時',
last10Min: '最近 10 分鐘',
cleanLog: '清空日誌',
cleanLogHelper: '清空日誌需要重啟容器,該操作無法回滾,是否繼續?',
newName: '新名稱',
source: '資源使用率',
cpuShare: 'CPU 權重',
@@ -519,7 +523,7 @@ const message = {
exposePort: '暴露端口',
exposeAll: '暴露所有',
cmd: '啟動命令',
cmdHelper: '例:echo "hello"',
cmdHelper: "多個命令間請用 ' ' 分隔開,如 'nginx' '-g' 'daemon off;'",
autoRemove: '容器退出後自動刪除容器',
cpuQuota: 'CPU 限製',
memoryLimit: '內存限製',
@@ -1577,6 +1581,7 @@ const message = {
},
tool: {
supervisor: {
loadStatusErr: '獲取進程狀態失敗,請檢查 supervisor 服務狀態',
notSupport: '未檢測到 Supervisor,請參考官方文檔進行安裝',
list: '守護進程',
config: 'Supervisor 配置',
@@ -1596,6 +1601,14 @@ const message = {
serviceNameHelper: 'systemctl 管理的 Supervisor 服務名稱,一般為 supervisor 或 supervisord',
restartHelper: '初始化會重啟服務,導致原有的守護進程全部關閉',
msg: '信息',
RUNNING: '運行中',
STOPPED: '已停止',
STOPPING: '停止中',
STARTING: '啟動中',
FATAL: '啟動失敗',
BACKOFF: '啟動異常',
statusCode: '狀態碼',
manage: '管理',
},
},
};
+15 -2
View File
@@ -469,7 +469,10 @@ const message = {
rename: '重命名',
remove: '删除',
containerPrune: '清理容器',
containerPruneHelper: '清理容器 将删除所有处于停止状态的容器,该操作无法回滚,是否继续?',
containerPruneHelper1: '清理容器 将删除所有处于停止状态的容器。',
containerPruneHelper2:
'若容器来自于应用商店,在执行清理操作后,您需要前往 [应用商店] 的 [已安装] 列表,点击 [重建] 按钮进行重新安装。',
containerPruneHelper3: '该操作无法回滚,是否继续?',
imagePrune: '清理镜像',
imagePruneSome: '未标签镜像',
imagePruneSomeHelper: '清理标签为 none 且未被任何容器使用的镜像。',
@@ -493,6 +496,7 @@ const message = {
lastHour: '最近 1 小时',
last10Min: '最近 10 分钟',
cleanLog: '清空日志',
cleanLogHelper: '清空日志需要重启容器,该操作无法回滚,是否继续?',
newName: '新名称',
source: '资源使用率',
cpuShare: 'CPU 权重',
@@ -519,7 +523,7 @@ const message = {
exposePort: '暴露端口',
exposeAll: '暴露所有',
cmd: '启动命令',
cmdHelper: '例:echo "hello"',
cmdHelper: "多个命令间请用 ' ' 分隔开,如 'nginx' '-g' 'daemon off;'",
autoRemove: '容器退出后自动删除容器',
cpuQuota: 'CPU 限制',
memoryLimit: '内存限制',
@@ -1579,6 +1583,7 @@ const message = {
},
tool: {
supervisor: {
loadStatusErr: '获取进程状态失败,请检查 supervisor 服务状态',
notSupport: '未检测到 Supervisor,请参考官方文档进行安装',
list: '守护进程',
config: 'Supervisor 配置',
@@ -1598,6 +1603,14 @@ const message = {
serviceNameHelper: 'systemctl 管理的 Supervisor 服务名称,一般为 supervisor、supervisord',
restartHelper: '初始化会重启服务,导致原有的守护进程全部关闭',
msg: '信息',
RUNNING: '运行中',
STOPPED: '已停止',
STOPPING: '停止中',
STARTING: '启动中',
FATAL: '启动失败',
BACKOFF: '启动异常',
statusCode: '状态码',
manage: '管理',
},
},
};
@@ -22,7 +22,7 @@
}
}
&.is-active {
background-color: var(--el-menu-item-bg-color-active);;
background-color: var(--el-menu-item-bg-color-active);
border: 2px solid $primary-color;
&::before {
@@ -81,3 +81,7 @@
padding: 4px 8px;
}
}
.el-sub-menu__title {
padding-right: 0;
}
+1 -1
View File
@@ -148,7 +148,6 @@ onMounted(() => {
top: 0;
bottom: 0;
left: 0;
z-index: 1001;
overflow: hidden;
}
@@ -178,6 +177,7 @@ onMounted(() => {
transition: transform 0.28s;
width: var(--panel-menu-width) !important;
background: #ffffff;
z-index: 9999;
}
.app-footer {
display: block;
+10
View File
@@ -27,6 +27,16 @@ const databaseRouter = {
requiresAuth: false,
},
},
{
path: 'mysql/setting',
name: 'MySQL-Setting',
component: () => import('@/views/database/mysql/setting/index.vue'),
hidden: true,
meta: {
activeMenu: '/databases',
requiresAuth: false,
},
},
{
path: 'mysql/remote',
name: 'MySQL-Remote',
+1 -1
View File
@@ -181,7 +181,7 @@ html {
.mask-prompt {
position: absolute;
z-index: 9999;
z-index: 9998;
top: 220px;
left: 45%;
transform: translate(-50%, -50%);
+2 -3
View File
@@ -119,7 +119,6 @@
v-model:page-size="paginationConfig.pageSize"
v-bind="paginationConfig"
@change="search(req)"
:page-sizes="[30, 60, 90]"
:layout="mobile ? 'total, prev, pager, next' : 'total, sizes, prev, pager, next, jumper'"
/>
</div>
@@ -259,14 +258,14 @@ onMounted(() => {
}
.app-desc {
margin-top: 5px;
margin-top: 8px;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
text-overflow: ellipsis;
height: 45px;
height: 43px;
.desc {
font-size: 14px;
@@ -157,6 +157,7 @@
</LayoutContent>
<CodemirrorDialog ref="mydetail" />
<PruneDialog @search="search" ref="dialogPruneRef" />
<ReNameDialog @search="search" ref="dialogReNameRef" />
<ContainerLogDialog ref="dialogContainerLogRef" />
@@ -172,6 +173,7 @@
<script lang="ts" setup>
import Tooltip from '@/components/tooltip/index.vue';
import TableSetting from '@/components/table-setting/index.vue';
import PruneDialog from '@/views/container/container/prune/index.vue';
import ReNameDialog from '@/views/container/container/rename/index.vue';
import OperateDialog from '@/views/container/container/operate/index.vue';
import UpgraeDialog from '@/views/container/container/upgrade/index.vue';
@@ -185,7 +187,6 @@ import { reactive, onMounted, ref, computed } from 'vue';
import {
containerListStats,
containerOperator,
containerPrune,
inspect,
loadContainerInfo,
loadDockerStatus,
@@ -196,7 +197,6 @@ import { ElMessageBox } from 'element-plus';
import i18n from '@/lang';
import router from '@/routers';
import { MsgSuccess, MsgWarning } from '@/utils/message';
import { computeSize } from '@/utils/util';
import { GlobalStore } from '@/store';
const globalStore = GlobalStore();
@@ -264,6 +264,7 @@ const mydetail = ref();
const dialogContainerLogRef = ref();
const dialogReNameRef = ref();
const dialogPruneRef = ref();
const search = async (column?: any) => {
let filterItem = props.filters ? props.filters : '';
@@ -360,31 +361,7 @@ const onInspect = async (id: string) => {
};
const onClean = () => {
ElMessageBox.confirm(i18n.global.t('container.containerPruneHelper'), i18n.global.t('container.containerPrune'), {
confirmButtonText: i18n.global.t('commons.button.confirm'),
cancelButtonText: i18n.global.t('commons.button.cancel'),
type: 'info',
}).then(async () => {
loading.value = true;
let params = {
pruneType: 'container',
withTagAll: false,
};
await containerPrune(params)
.then((res) => {
loading.value = false;
MsgSuccess(
i18n.global.t('container.cleanSuccessWithSpace', [
res.data.deletedNumber,
computeSize(res.data.spaceReclaimed),
]),
);
search();
})
.catch(() => {
loading.value = false;
});
});
dialogPruneRef.value!.acceptParams();
};
const checkStatus = (operation: string, row: Container.ContainerInfo | null) => {
@@ -161,7 +161,7 @@ const onDownload = async () => {
};
const onClean = async () => {
ElMessageBox.confirm(i18n.global.t('commons.msg.clean'), i18n.global.t('container.cleanLog'), {
ElMessageBox.confirm(i18n.global.t('container.cleanLogHelper'), i18n.global.t('container.cleanLog'), {
confirmButtonText: i18n.global.t('commons.button.confirm'),
cancelButtonText: i18n.global.t('commons.button.cancel'),
type: 'info',
@@ -110,7 +110,8 @@
</el-select>
</el-form-item>
<el-form-item :label="$t('container.cmd')" prop="cmdStr">
<el-input :placeholder="$t('container.cmdHelper')" v-model="dialogData.rowData!.cmdStr" />
<el-input v-model="dialogData.rowData!.cmdStr" />
<span class="input-help">{{ $t('container.cmdHelper') }}</span>
</el-form-item>
<el-form-item prop="autoRemove">
<el-checkbox v-model="dialogData.rowData!.autoRemove">
@@ -0,0 +1,71 @@
<template>
<el-dialog v-model="dialogVisiable" :title="$t('container.containerPrune')" :destroy-on-close="true" width="30%">
<div>
<ul class="help-ul">
<li lineClass style="color: red">{{ $t('container.containerPruneHelper1') }}</li>
<li class="lineClass">{{ $t('container.containerPruneHelper2') }}</li>
<li class="lineClass">{{ $t('container.containerPruneHelper3') }}</li>
</ul>
</div>
<template #footer>
<span class="dialog-footer">
<el-button :disabled="loading" @click="dialogVisiable = false">
{{ $t('commons.button.cancel') }}
</el-button>
<el-button :disabled="loading" type="primary" @click="onClean()">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { containerPrune } from '@/api/modules/container';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { ref } from 'vue';
import { computeSize } from '@/utils/util';
const loading = ref(false);
const dialogVisiable = ref<boolean>(false);
const emit = defineEmits<{ (e: 'search'): void }>();
const onClean = async () => {
loading.value = true;
let params = {
pruneType: 'container',
withTagAll: false,
};
await containerPrune(params)
.then((res) => {
loading.value = false;
MsgSuccess(
i18n.global.t('container.cleanSuccessWithSpace', [
res.data.deletedNumber,
computeSize(res.data.spaceReclaimed),
]),
);
dialogVisiable.value = false;
emit('search');
})
.catch(() => {
loading.value = false;
});
};
const acceptParams = (): void => {
dialogVisiable.value = true;
};
defineExpose({
acceptParams,
});
</script>
<style lang="scss" scoped>
.lineClass {
line-height: 30px;
}
</style>
@@ -43,7 +43,7 @@
<el-button v-if="!terminalOpen" @click="initTerm(formRef)">
{{ $t('commons.button.conn') }}
</el-button>
<el-button v-else @click="handleClose()">{{ $t('commons.button.disconn') }}</el-button>
<el-button v-else @click="onClose()">{{ $t('commons.button.disconn') }}</el-button>
<Terminal style="height: calc(100vh - 302px)" ref="terminalRef"></Terminal>
</el-form>
</el-drawer>
@@ -99,10 +99,14 @@ const initTerm = (formEl: FormInstance | undefined) => {
});
};
function handleClose() {
const onClose = () => {
terminalRef.value?.onClose();
terminalVisiable.value = false;
terminalOpen.value = false;
};
function handleClose() {
onClose();
terminalVisiable.value = false;
}
defineExpose({
@@ -51,7 +51,9 @@
</el-table-column>
<el-table-column width="90">
<template #default="{ row }">
<el-tag effect="dark" round v-if="row.isSystem">system</el-tag>
<el-tag effect="dark" round v-if="row.isSystem || row.name === '1panel-network'">
system
</el-tag>
</template>
</el-table-column>
<el-table-column
@@ -78,11 +80,12 @@
</el-table-column>
<el-table-column
prop="createdAt"
show-overflow-tooltip
min-width="90"
:label="$t('commons.table.date')"
:formatter="dateFormat"
/>
<fu-table-operations :buttons="buttons" :label="$t('commons.table.operate')" fix />
<fu-table-operations width="100" :buttons="buttons" :label="$t('commons.table.operate')" fix />
</ComplexTable>
</template>
</LayoutContent>
@@ -222,7 +225,7 @@ const onInspect = async (id: string) => {
};
function isSystem(val: string) {
return val === 'bridge' || val === '1panel-network' || val === 'none' || val === 'host';
return val === 'bridge' || val === 'none' || val === 'host';
}
const buttons = [
@@ -16,7 +16,15 @@
</span>
</el-form-item>
<el-form-item :label="$t('database.remoteConn')">
<el-tag>{{ form.systemIP + ':' + form.port }}</el-tag>
<el-tooltip v-if="loadConnInfo(true).length > 48" :content="loadConnInfo(true)" placement="top">
<el-tag>{{ loadConnInfo(true).substring(0, 48) }}...</el-tag>
</el-tooltip>
<el-tag v-else>{{ loadConnInfo(true) }}</el-tag>
<el-button
@click="onCopy(form.systemIP + ':' + form.port)"
icon="DocumentCopy"
link
></el-button>
<span class="input-help">{{ $t('database.remoteConnHelper2') }}</span>
</el-form-item>
@@ -42,13 +50,27 @@
<el-row type="flex" justify="center" v-if="form.from !== 'local'">
<el-col :span="22">
<el-form-item :label="$t('database.remoteConn')">
<el-tag>{{ form.remoteIP + ':' + form.port }}</el-tag>
<el-tooltip
v-if="loadConnInfo(false).length > 48"
:content="loadConnInfo(false)"
placement="top"
>
<el-tag>{{ loadConnInfo(false).substring(0, 48) }}...</el-tag>
</el-tooltip>
<el-tag v-else>{{ loadConnInfo(false) }}</el-tag>
<el-button
@click="onCopy(form.remoteIP + ':' + form.port)"
icon="DocumentCopy"
link
></el-button>
</el-form-item>
<el-form-item :label="$t('commons.login.username')">
<el-tag>{{ form.username }}</el-tag>
<el-button @click="onCopy(form.username)" icon="DocumentCopy" link></el-button>
</el-form-item>
<el-form-item :label="$t('commons.login.password')">
<el-tag>{{ form.password }}</el-tag>
<el-button @click="onCopy(form.password)" icon="DocumentCopy" link></el-button>
</el-form-item>
</el-col>
</el-row>
@@ -121,6 +143,12 @@ const acceptParams = (param: DialogProps): void => {
dialogVisiable.value = true;
};
function loadConnInfo(isLocal: boolean) {
let ip = isLocal ? form.systemIP : form.remoteIP;
let info = ip + ':' + form.port;
return info;
}
const random = async () => {
form.password = getRandomStr(16);
};
+5 -18
View File
@@ -11,7 +11,7 @@
></AppStatus>
</template>
<template v-if="!isOnSetting" #search>
<template #search>
<el-select v-model="paginationConfig.from" @change="search()">
<template #prefix>{{ $t('commons.table.type') }}</template>
<el-option-group>
@@ -28,7 +28,7 @@
</el-select>
</template>
<template #toolbar v-if="!isOnSetting">
<template #toolbar>
<el-row>
<el-col :xs="24" :sm="20" :md="20" :lg="20" :xl="20">
<el-button
@@ -77,7 +77,7 @@
</el-col>
</el-row>
</template>
<template #main v-if="(mysqlIsExist && !isOnSetting) || !isLocal()">
<template #main v-if="mysqlIsExist || !isLocal()">
<ComplexTable
:pagination-config="paginationConfig"
@sort-change="search"
@@ -162,14 +162,10 @@
</LayoutContent>
</div>
<el-card
v-if="mysqlStatus != 'Running' && !isOnSetting && mysqlIsExist && !loading && maskShow && isLocal"
class="mask-prompt"
>
<el-card v-if="mysqlStatus != 'Running' && mysqlIsExist && !loading && maskShow && isLocal" class="mask-prompt">
<span>{{ $t('commons.service.serviceNotStarted', ['MySQL']) }}</span>
</el-card>
<Setting ref="settingRef" style="margin-top: 20px" />
<el-dialog
v-model="phpVisiable"
:title="$t('app.checkTitle')"
@@ -208,7 +204,6 @@ import DeleteDialog from '@/views/database/mysql/delete/index.vue';
import PasswordDialog from '@/views/database/mysql/password/index.vue';
import RootPasswordDialog from '@/views/database/mysql/conn/index.vue';
import AppResources from '@/views/database/mysql/check/index.vue';
import Setting from '@/views/database/mysql/setting/index.vue';
import AppStatus from '@/components/app-status/index.vue';
import Backups from '@/components/backup/index.vue';
import UploadDialog from '@/components/upload/index.vue';
@@ -238,7 +233,6 @@ const maskShow = ref(true);
const dbOptions = ref<Array<Database.RemoteDBOption>>([]);
const mysqlName = ref();
const isOnSetting = ref<boolean>();
const checkRef = ref();
const deleteRef = ref();
@@ -292,15 +286,8 @@ function isLocal() {
const passwordRef = ref();
const settingRef = ref();
const onSetting = async () => {
isOnSetting.value = true;
let params = {
status: mysqlStatus.value,
mysqlName: mysqlName.value,
mysqlVersion: mysqlVersion.value,
};
settingRef.value!.acceptParams(params);
router.push({ name: 'MySQL-Setting' });
};
const search = async (column?: any) => {
@@ -28,8 +28,8 @@
</template>
<template #main>
<ComplexTable :pagination-config="paginationConfig" @sort-change="search" @search="search" :data="data">
<el-table-column :label="$t('commons.table.name')" prop="name" sortable />
<el-table-column :label="$t('database.address')" prop="address" />
<el-table-column show-overflow-tooltip :label="$t('commons.table.name')" prop="name" sortable />
<el-table-column show-overflow-tooltip :label="$t('database.address')" prop="address" />
<el-table-column :label="$t('commons.login.username')" prop="username" />
<el-table-column :label="$t('commons.login.password')" prop="password">
<template #default="{ row }">
@@ -74,7 +74,7 @@
show-overflow-tooltip
/>
<fu-table-operations
width="370px"
width="170px"
:buttons="buttons"
:ellipsis="10"
:label="$t('commons.table.operate')"
@@ -138,7 +138,7 @@ const onOpenDialog = async (
version: '5.6',
address: '',
port: 3306,
username: '',
username: 'root',
password: '',
description: '',
},
@@ -8,7 +8,7 @@
:back="handleClose"
/>
</template>
<el-form ref="formRef" label-position="top" :model="dialogData.rowData" :rules="rules">
<el-form ref="formRef" v-loading="loading" label-position="top" :model="dialogData.rowData" :rules="rules">
<el-row type="flex" justify="center">
<el-col :span="22">
<el-form-item :label="$t('commons.table.name')" prop="name">
@@ -20,7 +20,7 @@
<el-tag v-else>{{ dialogData.rowData!.name }}</el-tag>
</el-form-item>
<el-form-item :label="$t('database.version')" prop="version">
<el-select v-model="dialogData.rowData!.version">
<el-select @change="isOK = false" v-model="dialogData.rowData!.version">
<el-option value="5.6" label="5.6" />
<el-option value="5.7" label="5.7" />
<el-option value="8.0" label="8.0" />
@@ -28,17 +28,23 @@
<span class="input-help">{{ $t('database.versionHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('database.address')" prop="address">
<el-input clearable v-model.trim="dialogData.rowData!.address" />
<el-input @change="isOK = false" clearable v-model.trim="dialogData.rowData!.address" />
</el-form-item>
<el-form-item :label="$t('commons.table.port')" prop="port">
<el-input clearable v-model.number="dialogData.rowData!.port" />
<el-input @change="isOK = false" clearable v-model.number="dialogData.rowData!.port" />
</el-form-item>
<el-form-item :label="$t('commons.login.username')" prop="username">
<el-input clearable v-model.trim="dialogData.rowData!.username" />
<el-input @change="isOK = false" clearable v-model.trim="dialogData.rowData!.username" />
<span class="input-help">{{ $t('database.userHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('commons.login.password')" prop="password">
<el-input type="password" clearable show-password v-model.trim="dialogData.rowData!.password" />
<el-input
@change="isOK = false"
type="password"
clearable
show-password
v-model.trim="dialogData.rowData!.password"
/>
</el-form-item>
<el-form-item :label="$t('commons.table.description')" prop="description">
<el-input clearable v-model.trim="dialogData.rowData!.description" />
@@ -49,7 +55,10 @@
<template #footer>
<span class="dialog-footer">
<el-button @click="drawerVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
<el-button type="primary" @click="onSubmit(formRef)">
<el-button @click="onSubmit(formRef, 'check')">
{{ $t('terminal.testConn') }}
</el-button>
<el-button type="primary" :disabled="!isOK" @click="onSubmit(formRef, dialogData.title)">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
@@ -63,9 +72,9 @@ import i18n from '@/lang';
import { ElForm } from 'element-plus';
import { Database } from '@/api/interface/database';
import DrawerHeader from '@/components/drawer-header/index.vue';
import { MsgSuccess } from '@/utils/message';
import { MsgError, MsgSuccess } from '@/utils/message';
import { Rules } from '@/global/form-rules';
import { addRemoteDB, editRemoteDB } from '@/api/modules/database';
import { addRemoteDB, checkRemoteDB, editRemoteDB } from '@/api/modules/database';
interface DialogProps {
title: string;
@@ -77,6 +86,9 @@ const drawerVisiable = ref(false);
const dialogData = ref<DialogProps>({
title: '',
});
const isOK = ref(false);
const loading = ref();
const acceptParams = (params: DialogProps): void => {
dialogData.value = params;
title.value = i18n.global.t('database.' + dialogData.value.title + 'RemoteDB');
@@ -91,7 +103,7 @@ const handleClose = () => {
const rules = reactive({
name: [Rules.requiredInput],
version: [Rules.requiredSelect],
address: [Rules.ip],
address: [Rules.host],
port: [Rules.port],
username: [Rules.requiredInput],
password: [Rules.requiredInput],
@@ -100,40 +112,65 @@ const rules = reactive({
type FormInstance = InstanceType<typeof ElForm>;
const formRef = ref<FormInstance>();
const onSubmit = async (formEl: FormInstance | undefined) => {
const onSubmit = async (formEl: FormInstance | undefined, operation: string) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
if (dialogData.value.title === 'create') {
let param = {
name: dialogData.value.rowData.name,
type: 'mysql',
version: dialogData.value.rowData.version,
from: 'remote',
address: dialogData.value.rowData.address,
port: dialogData.value.rowData.port,
username: dialogData.value.rowData.username,
password: dialogData.value.rowData.password,
description: dialogData.value.rowData.description,
};
await addRemoteDB(param);
}
if (dialogData.value.title === 'edit') {
let param = {
id: dialogData.value.rowData.id,
version: dialogData.value.rowData.version,
address: dialogData.value.rowData.address,
port: dialogData.value.rowData.port,
username: dialogData.value.rowData.username,
password: dialogData.value.rowData.password,
description: dialogData.value.rowData.description,
};
await editRemoteDB(param);
let param = {
id: dialogData.value.rowData.id,
name: dialogData.value.rowData.name,
type: 'mysql',
version: dialogData.value.rowData.version,
from: 'remote',
address: dialogData.value.rowData.address,
port: dialogData.value.rowData.port,
username: dialogData.value.rowData.username,
password: dialogData.value.rowData.password,
description: dialogData.value.rowData.description,
};
loading.value = true;
if (operation === 'check') {
await checkRemoteDB(param)
.then((res) => {
loading.value = false;
if (res.data) {
isOK.value = true;
MsgSuccess(i18n.global.t('terminal.connTestOk'));
} else {
MsgError(i18n.global.t('terminal.connTestFailed'));
}
})
.catch(() => {
loading.value = false;
MsgError(i18n.global.t('terminal.connTestFailed'));
});
}
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
emit('search');
drawerVisiable.value = false;
if (operation === 'create') {
await addRemoteDB(param)
.then(() => {
loading.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
emit('search');
drawerVisiable.value = false;
})
.catch(() => {
loading.value = false;
});
}
if (operation === 'edit') {
await editRemoteDB(param)
.then(() => {
loading.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
emit('search');
drawerVisiable.value = false;
})
.catch(() => {
loading.value = false;
});
}
});
};
@@ -1,7 +1,11 @@
<template>
<div v-show="onSetting" v-loading="loading">
<LayoutContent :title="'MySQL ' + $t('commons.button.set')" :reload="true">
<template #buttons>
<div v-loading="loading">
<LayoutContent>
<template #title>
<back-button name="MySQL" :header="'MySQL ' + $t('commons.button.set')" />
</template>
<template #toolbar>
<el-button type="primary" :plain="activeName !== 'conf'" @click="jumpToConf">
{{ $t('database.confChange') }}
</el-button>
@@ -115,12 +119,12 @@ import Status from '@/views/database/mysql/setting/status/index.vue';
import Variables from '@/views/database/mysql/setting/variables/index.vue';
import SlowLog from '@/views/database/mysql/setting/slow-log/index.vue';
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import { reactive, ref } from 'vue';
import { onMounted, reactive, ref } from 'vue';
import { Codemirror } from 'vue-codemirror';
import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from '@codemirror/theme-one-dark';
import { loadDatabaseFile, loadMysqlBaseInfo, loadMysqlVariables, updateMysqlConfByFile } from '@/api/modules/database';
import { ChangePort, GetAppDefaultConfig } from '@/api/modules/app';
import { ChangePort, CheckAppInstalled, GetAppDefaultConfig } from '@/api/modules/app';
import { Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
@@ -146,34 +150,12 @@ const statusRef = ref();
const variablesRef = ref();
const slowLogRef = ref();
const onSetting = ref<boolean>(false);
const mysqlName = ref();
const mysqlStatus = ref();
const mysqlVersion = ref();
const variables = ref();
interface DialogProps {
mysqlName: string;
mysqlVersion: string;
status: string;
}
const dialogContainerLogRef = ref();
const acceptParams = (props: DialogProps): void => {
onSetting.value = true;
mysqlStatus.value = props.status;
mysqlVersion.value = props.mysqlVersion;
loadBaseInfo();
if (mysqlStatus.value === 'Running') {
loadVariables();
loadSlowLogs();
statusRef.value!.acceptParams({ mysqlName: props.mysqlName });
}
};
const onClose = (): void => {
onSetting.value = false;
};
const jumpToConf = async () => {
activeName.value = 'conf';
loadMysqlConf();
@@ -303,8 +285,21 @@ const loadMysqlConf = async () => {
mysqlConf.value = res.data;
};
defineExpose({
acceptParams,
onClose,
const onLoadInfo = async () => {
await CheckAppInstalled('mysql').then((res) => {
mysqlName.value = res.data.name;
mysqlStatus.value = res.data.status;
mysqlVersion.value = res.data.version;
loadBaseInfo();
if (mysqlStatus.value === 'Running') {
loadVariables();
loadSlowLogs();
statusRef.value!.acceptParams({ mysqlName: mysqlName.value });
}
});
};
onMounted(() => {
onLoadInfo();
});
</script>
+7 -6
View File
@@ -374,9 +374,10 @@ const onLoadCurrentInfo = async () => {
const res = await loadCurrentInfo(searchInfo.ioOption, searchInfo.netOption);
currentInfo.value.timeSinceUptime = res.data.timeSinceUptime;
let timeInterval = Number(res.data.uptime - currentInfo.value.uptime) || 3;
currentChartInfo.netBytesSent =
res.data.netBytesSent - currentInfo.value.netBytesSent > 0
? Number(((res.data.netBytesSent - currentInfo.value.netBytesSent) / 1024 / 3).toFixed(2))
? Number(((res.data.netBytesSent - currentInfo.value.netBytesSent) / 1024 / timeInterval).toFixed(2))
: 0;
netBytesSents.value.push(currentChartInfo.netBytesSent);
if (netBytesSents.value.length > 20) {
@@ -385,7 +386,7 @@ const onLoadCurrentInfo = async () => {
currentChartInfo.netBytesRecv =
res.data.netBytesRecv - currentInfo.value.netBytesRecv > 0
? Number(((res.data.netBytesRecv - currentInfo.value.netBytesRecv) / 1024 / 3).toFixed(2))
? Number(((res.data.netBytesRecv - currentInfo.value.netBytesRecv) / 1024 / timeInterval).toFixed(2))
: 0;
netBytesRecvs.value.push(currentChartInfo.netBytesRecv);
if (netBytesRecvs.value.length > 20) {
@@ -394,7 +395,7 @@ const onLoadCurrentInfo = async () => {
currentChartInfo.ioReadBytes =
res.data.ioReadBytes - currentInfo.value.ioReadBytes > 0
? Number(((res.data.ioReadBytes - currentInfo.value.ioReadBytes) / 1024 / 1024 / 3).toFixed(2))
? Number(((res.data.ioReadBytes - currentInfo.value.ioReadBytes) / 1024 / 1024 / timeInterval).toFixed(2))
: 0;
ioReadBytes.value.push(currentChartInfo.ioReadBytes);
if (ioReadBytes.value.length > 20) {
@@ -403,17 +404,17 @@ const onLoadCurrentInfo = async () => {
currentChartInfo.ioWriteBytes =
res.data.ioWriteBytes - currentInfo.value.ioWriteBytes > 0
? Number(((res.data.ioWriteBytes - currentInfo.value.ioWriteBytes) / 1024 / 1024 / 3).toFixed(2))
? Number(((res.data.ioWriteBytes - currentInfo.value.ioWriteBytes) / 1024 / 1024 / timeInterval).toFixed(2))
: 0;
ioWriteBytes.value.push(currentChartInfo.ioWriteBytes);
if (ioWriteBytes.value.length > 20) {
ioWriteBytes.value.splice(0, 1);
}
currentChartInfo.ioCount = Math.round(Number((res.data.ioCount - currentInfo.value.ioCount) / 3));
currentChartInfo.ioCount = Math.round(Number((res.data.ioCount - currentInfo.value.ioCount) / timeInterval));
let ioReadTime = res.data.ioReadTime - currentInfo.value.ioReadTime;
let ioWriteTime = res.data.ioWriteTime - currentInfo.value.ioWriteTime;
let ioChoose = ioReadTime > ioWriteTime ? ioReadTime : ioWriteTime;
currentChartInfo.ioTime = Math.round(Number(ioChoose / 3));
currentChartInfo.ioTime = Math.round(Number(ioChoose / timeInterval));
timeIODatas.value.push(dateFormatForSecond(res.data.shotTime));
if (timeIODatas.value.length > 20) {
@@ -247,7 +247,7 @@ const onDelete = async (row: Host.RuleIP | null) => {
}
}
loading.value = true;
await batchOperateRule({ type: 'port', rules: rules })
await batchOperateRule({ type: 'address', rules: rules })
.then(() => {
loading.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
@@ -68,7 +68,7 @@
@search="search"
:data="data"
>
<el-table-column type="selection" :selectable="selectable" fix />
<el-table-column type="selection" fix />
<el-table-column :label="$t('commons.table.protocol')" :min-width="90" prop="protocol" />
<el-table-column :label="$t('commons.table.port')" :min-width="120" prop="port" />
<el-table-column :label="$t('commons.table.status')" :min-width="120">
@@ -87,7 +87,6 @@
<template #default="{ row }">
<el-button
v-if="row.strategy === 'accept'"
:disabled="row.appName === '1panel'"
@click="onChangeStatus(row, 'drop')"
link
type="success"
@@ -303,28 +302,18 @@ const onDelete = async (row: Host.RuleInfo | null) => {
});
};
function selectable(row) {
return row.appName !== '1panel';
}
const buttons = [
{
label: i18n.global.t('commons.button.edit'),
click: (row: Host.RulePort) => {
onOpenDialog('edit', row);
},
disabled: (row: any) => {
return row.appName === '1panel';
},
},
{
label: i18n.global.t('commons.button.delete'),
click: (row: Host.RuleInfo) => {
onDelete(row);
},
disabled: (row: any) => {
return row.appName === '1panel';
},
},
];
@@ -73,6 +73,8 @@ const handleReady = (payload) => {
};
let timer: NodeJS.Timer | null = null;
const em = defineEmits(['search']);
const getContent = () => {
loading.value = true;
OperateSupervisorProcessFile(req)
@@ -114,8 +116,9 @@ const submit = () => {
loading.value = true;
OperateSupervisorProcessFile(updateReq)
.then(() => {
em('search');
open.value = false;
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
getContent();
})
.finally(() => {
loading.value = false;
+104 -41
View File
@@ -20,35 +20,84 @@
</template>
<template #main v-if="showTable">
<ComplexTable :data="data" :class="{ mask: !supervisorStatus.isRunning }">
<el-table-column :label="$t('commons.table.name')" fix prop="name" width="150px"></el-table-column>
<el-table-column
:label="$t('commons.table.name')"
fix
prop="name"
min-width="80px"
show-overflow-tooltip
></el-table-column>
<el-table-column
:label="$t('tool.supervisor.command')"
prop="command"
min-width="100px"
fix
show-overflow-tooltip
></el-table-column>
<el-table-column
:label="$t('tool.supervisor.dir')"
prop="dir"
min-width="100px"
fix
show-overflow-tooltip
></el-table-column>
<el-table-column :label="$t('tool.supervisor.user')" prop="user" width="100px"></el-table-column>
<el-table-column
:label="$t('tool.supervisor.user')"
prop="user"
show-overflow-tooltip
min-width="50px"
></el-table-column>
<el-table-column
:label="$t('tool.supervisor.numprocs')"
prop="numprocs"
width="100px"
min-width="60px"
></el-table-column>
<el-table-column :label="$t('commons.table.status')" width="100px">
<el-table-column :label="$t('tool.supervisor.manage')" min-width="80px">
<template #default="{ row }">
<div v-if="row.status">
<div v-if="row.status && row.status.length > 0 && row.hasLoad">
<el-button
v-if="checkStatus(row.status) === 'RUNNING'"
link
type="success"
:icon="VideoPlay"
@click="operate('stop', row.name)"
>
{{ $t('commons.status.running') }}
</el-button>
<el-button
v-else-if="checkStatus(row.status) === 'WARNING'"
link
type="warning"
:icon="RefreshRight"
@click="operate('restart', row.name)"
>
{{ $t('commons.status.unhealthy') }}
</el-button>
<el-button
v-else
link
type="danger"
:icon="VideoPause"
@click="operate('start', row.name)"
>
{{ $t('commons.status.stopped') }}
</el-button>
</div>
<div v-if="!row.hasLoad">
<el-button link loading></el-button>
</div>
</template>
</el-table-column>
<el-table-column :label="$t('commons.table.status')" min-width="60px">
<template #default="{ row }">
<div v-if="row.hasLoad">
<el-popover placement="bottom" :width="600" trigger="hover">
<template #reference>
<el-button type="primary" link v-if="row.status.length > 1">
{{ $t('website.check') }}
</el-button>
<el-button type="primary" link v-else>
<span>{{ row.status[0].status }}</span>
<span>{{ $t('tool.supervisor.' + row.status[0].status) }}</span>
</el-button>
</template>
<el-table :data="row.status">
@@ -60,7 +109,7 @@
/>
<el-table-column
property="status"
:label="$t('commons.table.status')"
:label="$t('tool.supervisor.statusCode')"
width="100px"
/>
<el-table-column property="PID" label="PID" width="100px" />
@@ -78,6 +127,9 @@
</el-table>
</el-popover>
</div>
<div v-if="!row.hasLoad">
<el-button link loading></el-button>
</div>
</template>
</el-table-column>
<fu-table-operations
@@ -85,7 +137,7 @@
:buttons="buttons"
:label="$t('commons.table.operate')"
:fixed="mobile ? false : 'right'"
width="350px"
width="280px"
fix
/>
</ComplexTable>
@@ -93,7 +145,7 @@
<ConfigSuperVisor v-if="setSuperVisor" />
</LayoutContent>
<Create ref="createRef" @close="search"></Create>
<File ref="fileRef"></File>
<File ref="fileRef" @search="search"></File>
</div>
</template>
@@ -105,11 +157,12 @@ import ConfigSuperVisor from './config/index.vue';
import { computed, onMounted } from 'vue';
import Create from './create/index.vue';
import File from './file/index.vue';
import { GetSupervisorProcess, OperateSupervisorProcess } from '@/api/modules/host-tool';
import { GetSupervisorProcess, LoadProcessStatus, OperateSupervisorProcess } from '@/api/modules/host-tool';
import { GlobalStore } from '@/store';
import i18n from '@/lang';
import { HostTool } from '@/api/interface/host-tool';
import { MsgSuccess } from '@/utils/message';
import { VideoPlay, VideoPause, RefreshRight } from '@element-plus/icons-vue';
const globalStore = GlobalStore();
const loading = ref(false);
@@ -131,6 +184,7 @@ const setting = () => {
const getStatus = (status: any) => {
supervisorStatus.value = status;
search();
};
const showStopped = computed((): boolean => {
@@ -158,7 +212,11 @@ const openCreate = () => {
};
const search = async () => {
if (!supervisorStatus.value.isExist) {
return;
}
loading.value = true;
loadStatus();
try {
const res = await GetSupervisorProcess();
data.value = res.data;
@@ -166,10 +224,46 @@ const search = async () => {
loading.value = false;
};
const loadStatus = async () => {
await LoadProcessStatus()
.then((res) => {
let stats = res.data || [];
for (const process of data.value) {
process.status = [];
for (const item of stats) {
if (process.name === item.name.split(':')[0]) {
process.status.push(item);
}
}
process.hasLoad = true;
}
})
.catch(() => {
for (const process of data.value) {
process.status = [{ name: '-', status: 'FATAL', msg: i18n.global.t('tool.supervisor.loadStatusErr') }];
process.hasLoad = true;
}
});
};
const mobile = computed(() => {
return globalStore.isMobile();
});
const checkStatus = (status: HostTool.ProcessStatus[]): string => {
if (!status || status.length === 0) return 'STOPPED';
const statusCounts = status.reduce((acc, curr) => {
acc[curr.status] = (acc[curr.status] || 0) + 1;
return acc;
}, {} as Record<string, number>);
if (statusCounts['STARTING']) return 'STARTING';
if (statusCounts['RUNNING'] === status.length) return 'RUNNING';
if (statusCounts['RUNNING'] > 0) return 'WARNING';
return 'STOPPED';
};
const operate = async (operation: string, name: string) => {
try {
ElMessageBox.confirm(
@@ -224,42 +318,11 @@ const buttons = [
getFile(row.name, 'out.log');
},
},
{
label: i18n.global.t('app.start'),
click: function (row: HostTool.SupersivorProcess) {
operate('start', row.name);
},
disabled: (row: any) => {
if (row.status == undefined) {
return true;
} else {
return row.status && row.status[0].status == 'RUNNING';
}
},
},
{
label: i18n.global.t('app.stop'),
click: function (row: HostTool.SupersivorProcess) {
operate('stop', row.name);
},
disabled: (row: any) => {
if (row.status == undefined) {
return true;
}
return row.status && row.status[0].status != 'RUNNING';
},
},
{
label: i18n.global.t('commons.button.restart'),
click: function (row: HostTool.SupersivorProcess) {
operate('restart', row.name);
},
disabled: (row: any): boolean => {
if (row.status == undefined) {
return true;
}
return row.status && row.status[0].status != 'RUNNING';
},
},
{
label: i18n.global.t('commons.button.delete'),
@@ -148,7 +148,7 @@
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue';
import { ref, reactive, onMounted, computed } from 'vue';
import { useRouter } from 'vue-router';
import type { ElForm } from 'element-plus';
import { loginApi, getCaptcha, mfaLoginApi, checkIsDemo, getLanguage } from '@/api/modules/auth';
@@ -182,9 +182,10 @@ const loginForm = reactive({
agreeLicense: false,
language: 'zh',
});
const loginRules = reactive({
name: [{ required: true, message: i18n.global.t('commons.rule.username'), trigger: 'blur' }],
password: [{ required: true, message: i18n.global.t('commons.rule.password'), trigger: 'blur' }],
name: computed(() => [{ required: true, message: i18n.global.t('commons.rule.username'), trigger: 'blur' }]),
password: computed(() => [{ required: true, message: i18n.global.t('commons.rule.password'), trigger: 'blur' }]),
});
const mfaButtonFocused = ref();
@@ -4,10 +4,17 @@
<template #header>
<DrawerHeader :header="$t('setting.systemIP')" :back="handleClose" />
</template>
<el-form ref="formRef" label-position="top" :model="form" @submit.prevent v-loading="loading">
<el-form
ref="formRef"
label-position="top"
:model="form"
:rules="rules"
@submit.prevent
v-loading="loading"
>
<el-row type="flex" justify="center">
<el-col :span="22">
<el-form-item :label="$t('setting.systemIP')" prop="systemIP" :rules="Rules.ipV4V6OrDomain">
<el-form-item :label="$t('setting.systemIP')" prop="systemIP">
<el-input clearable v-model="form.systemIP" />
<span class="input-help">{{ $t('commons.rule.hostHelper') }}</span>
</el-form-item>
@@ -31,8 +38,8 @@ import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { updateSetting } from '@/api/modules/setting';
import { FormInstance } from 'element-plus';
import { Rules } from '@/global/form-rules';
import DrawerHeader from '@/components/drawer-header/index.vue';
import { checkDomain, checkIpV4V6 } from '@/utils/util';
const emit = defineEmits<{ (e: 'search'): void }>();
@@ -47,6 +54,18 @@ const form = reactive({
});
const formRef = ref<FormInstance>();
const rules = reactive({
systemIP: [{ validator: checkSystemIP, trigger: 'blur' }],
});
function checkSystemIP(rule: any, value: any, callback: any) {
if (form.systemIP !== '') {
if (checkIpV4V6(form.systemIP) && checkDomain(form.systemIP)) {
return callback(new Error(i18n.global.t('commons.rule.host')));
}
}
callback();
}
const acceptParams = (params: DialogProps): void => {
form.systemIP = params.systemIP;
@@ -234,16 +234,13 @@ const submit = async (formEl: FormInstance | undefined) => {
};
const getProtocolAndHost = (url: string): { protocol: string; host: string } | null => {
const regex = /^(https?:\/\/)([^\/]+)/;
const match = url.match(regex);
if (match) {
return {
protocol: match[1],
host: match[2],
};
if (url.startsWith('https://')) {
return { protocol: 'https://', host: url.replaceAll('https://', '') };
}
console.log('err');
return null;
if (url.startsWith('http://')) {
return { protocol: 'http://', host: url.replaceAll('http://', '') };
}
return { protocol: '', host: url };
};
defineExpose({
@@ -5,28 +5,28 @@
{{ $t('commons.button.create') + $t('website.redirect') }}
</el-button>
</template>
<el-table-column :label="$t('commons.table.name')" prop="name"></el-table-column>
<el-table-column :label="$t('website.sourceDomain')" prop="domain" min-width="150px">
<el-table-column :label="$t('commons.table.name')" prop="name" min-width="60px" show-overflow-tooltip />
<el-table-column :label="$t('website.sourceDomain')" prop="domain" min-width="80px" show-overflow-tooltip>
<template #default="{ row }">
<span v-if="row.type === 'domain'">{{ row.domains.join(',') }}</span>
<span v-else>{{ row.path }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('commons.table.type')" prop="type" width="80px">
<el-table-column :label="$t('commons.table.type')" prop="type" min-width="60px">
<template #default="{ row }">
<span v-if="row.type != 404">{{ $t('website.' + row.type) }}</span>
<span v-else>{{ 404 }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('website.redirectWay')" prop="redirect" width="80px"></el-table-column>
<el-table-column :label="$t('website.targetURL')" prop="target"></el-table-column>
<el-table-column :label="$t('website.keepPath')" prop="keepPath">
<el-table-column :label="$t('website.redirectWay')" prop="redirect" min-width="50px"></el-table-column>
<el-table-column :label="$t('website.targetURL')" prop="target" min-width="100px" show-overflow-tooltip />
<el-table-column :label="$t('website.keepPath')" prop="keepPath" min-width="80px" show-overflow-tooltip>
<template #default="{ row }">
<span v-if="row.type != '404'">{{ row.keepPath ? $t('website.keep') : $t('website.notKeep') }}</span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column :label="$t('commons.table.status')" prop="enable">
<el-table-column :label="$t('commons.table.status')" prop="enable" min-width="50px">
<template #default="{ row }">
<el-button v-if="row.enable" link type="success" :icon="VideoPlay" @click="opProxy(row)">
{{ $t('commons.status.running') }}
@@ -38,7 +38,7 @@
</el-table-column>
<fu-table-operations
:ellipsis="10"
width="220px"
width="180px"
:buttons="buttons"
:label="$t('commons.table.operate')"
:fixed="mobile ? false : 'right'"
+1 -31
View File
@@ -8,7 +8,6 @@ require (
github.com/compose-spec/compose-go v1.13.2
github.com/creack/pty v1.1.18
github.com/dgraph-io/badger/v4 v4.1.0
github.com/docker/cli v23.0.1+incompatible
github.com/docker/compose/v2 v2.17.2
github.com/docker/docker v23.0.3+incompatible
github.com/docker/go-connections v0.4.0
@@ -62,7 +61,6 @@ require (
)
require (
github.com/AlecAivazis/survey/v2 v2.3.6 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/Microsoft/go-winio v0.6.0 // indirect
@@ -70,22 +68,10 @@ require (
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1755 // indirect
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/aws/aws-sdk-go-v2 v1.16.3 // indirect
github.com/aws/aws-sdk-go-v2/config v1.15.5 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.12.0 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.11 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.11.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.16.4 // indirect
github.com/aws/smithy-go v1.11.2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bodgit/plumbing v1.2.0 // indirect
github.com/bodgit/sevenzip v1.3.0 // indirect
github.com/bodgit/windows v1.0.0 // indirect
github.com/buger/goterm v1.0.4 // indirect
github.com/bytedance/sonic v1.9.1 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
@@ -102,6 +88,7 @@ require (
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/distribution/distribution/v3 v3.0.0-20230223072852-e5d5810851d1 // indirect
github.com/docker/buildx v0.10.4 // indirect
github.com/docker/cli v23.0.1+incompatible // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/docker/docker-credential-helpers v0.7.0 // indirect
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
@@ -110,7 +97,6 @@ require (
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/felixge/httpsnoop v1.0.2 // indirect
github.com/fsnotify/fsevents v0.1.1 // indirect
github.com/fvbommel/sortorder v1.0.2 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
@@ -131,7 +117,6 @@ require (
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/golang/glog v1.0.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/flatbuffers v1.12.1 // indirect
@@ -139,7 +124,6 @@ require (
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
@@ -155,10 +139,8 @@ require (
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jonboulle/clockwork v0.3.1-0.20230117163003-a89700cec744 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/klauspost/pgzip v1.2.5 // indirect
github.com/kr/fs v0.1.0 // indirect
@@ -166,12 +148,9 @@ require (
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mattn/go-shellwords v1.0.12 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/miekg/dns v1.1.50 // indirect
github.com/miekg/pkcs11 v1.1.1 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
@@ -180,11 +159,8 @@ require (
github.com/moby/buildkit v0.11.5 // indirect
github.com/moby/locker v1.0.1 // indirect
github.com/moby/patternmatcher v0.5.0 // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/moby/sys/mountinfo v0.6.2 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
github.com/moby/sys/signal v0.7.0 // indirect
github.com/moby/sys/symlink v0.2.0 // indirect
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
@@ -204,9 +180,7 @@ require (
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rs/xid v1.4.0 // indirect
github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002 // indirect
github.com/shoenig/go-m1cpu v0.1.5 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
@@ -214,7 +188,6 @@ require (
github.com/stretchr/testify v1.8.4 // indirect
github.com/therootcompany/xz v1.0.1 // indirect
github.com/theupdateframework/notary v0.7.0 // indirect
github.com/tilt-dev/fsnotify v1.4.8-0.20220602155310-fff9c274a375 // indirect
github.com/tklauser/go-sysconf v0.3.11 // indirect
github.com/tklauser/numcpus v0.6.0 // indirect
github.com/tonistiigi/fsutil v0.0.0-20230105215944-fb433841cbfa // indirect
@@ -233,10 +206,7 @@ require (
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.29.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0 // indirect
go.opentelemetry.io/otel v1.15.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.4.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.4.1 // indirect
go.opentelemetry.io/otel/internal/metric v0.27.0 // indirect
go.opentelemetry.io/otel/metric v0.27.0 // indirect
go.opentelemetry.io/otel/sdk v1.4.1 // indirect
-74
View File
@@ -39,8 +39,6 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/AlecAivazis/survey/v2 v2.3.6 h1:NvTuVHISgTHEHeBFqt6BHOe4Ny/NwGZr7w+F8S9ziyw=
github.com/AlecAivazis/survey/v2 v2.3.6/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
@@ -59,8 +57,6 @@ github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2y
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
github.com/Microsoft/hcsshim v0.9.7 h1:mKNHW/Xvv1aFH87Jb6ERDzXTJTLPlmzfZ28VBFD/bfg=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
@@ -84,28 +80,6 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/aws/aws-sdk-go v1.44.99 h1:ITZ9q/fmH+Ksaz2TbyMU2d19vOOWs/hAlt8NbXAieHw=
github.com/aws/aws-sdk-go v1.44.99/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go-v2 v1.16.3 h1:0W1TSJ7O6OzwuEvIXAtJGvOeQ0SGAhcpxPN2/NK5EhM=
github.com/aws/aws-sdk-go-v2 v1.16.3/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU=
github.com/aws/aws-sdk-go-v2/config v1.15.5 h1:P+xwhr6kabhxDTXTVH9YoHkqjLJ0wVVpIUHtFNr2hjU=
github.com/aws/aws-sdk-go-v2/config v1.15.5/go.mod h1:ZijHHh0xd/A+ZY53az0qzC5tT46kt4JVCePf2NX9Lk4=
github.com/aws/aws-sdk-go-v2/credentials v1.12.0 h1:4R/NqlcRFSkR0wxOhgHi+agGpbEr5qMCjn7VqUIJY+E=
github.com/aws/aws-sdk-go-v2/credentials v1.12.0/go.mod h1:9YWk7VW+eyKsoIL6/CljkTrNVWBSK9pkqOPUuijid4A=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4 h1:FP8gquGeGHHdfY6G5llaMQDF+HAf20VKc8opRwmjf04=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4/go.mod h1:u/s5/Z+ohUQOPXl00m2yJVyioWDECsbpXTQlaqSlufc=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.10 h1:uFWgo6mGJI1n17nbcvSc6fxVuR3xLNqvXt12JCnEcT8=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.10/go.mod h1:F+EZtuIwjlv35kRJPyBGcsA4f7bnSoz15zOQ2lJq1Z4=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.4 h1:cnsvEKSoHN4oAN7spMMr0zhEW2MHnhAVpmqQg8E6UcM=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.4/go.mod h1:8glyUqVIM4AmeenIsPo0oVh3+NUwnsQml2OFupfQW+0=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.11 h1:6cZRymlLEIlDTEB0+5+An6Zj1CKt6rSE69tOmFeu1nk=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.11/go.mod h1:0MR+sS1b/yxsfAPvAESrw8NfwUoxMinDyw6EYR9BS2U=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.4 h1:b16QW0XWl0jWjLABFc1A+uh145Oqv+xDcObNk0iQgUk=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.4/go.mod h1:uKkN7qmSIsNJVyMtxNQoCEYMvFEXbOg9fwCJPdfp2u8=
github.com/aws/aws-sdk-go-v2/service/sso v1.11.4 h1:Uw5wBybFQ1UeA9ts0Y07gbv0ncZnIAyw858tDW0NP2o=
github.com/aws/aws-sdk-go-v2/service/sso v1.11.4/go.mod h1:cPDwJwsP4Kff9mldCXAmddjJL6JGQqtA3Mzer2zyr88=
github.com/aws/aws-sdk-go-v2/service/sts v1.16.4 h1:+xtV90n3abQmgzk1pS++FdxZTrPEDgQng6e4/56WR2A=
github.com/aws/aws-sdk-go-v2/service/sts v1.16.4/go.mod h1:lfSYenAXtavyX2A1LsViglqlG9eEFYxNryTZS5rn3QE=
github.com/aws/smithy-go v1.11.2 h1:eG/N+CcUMAvsdffgMvjMKwfyDzIkjM6pfxMJ8Mzc6mE=
github.com/aws/smithy-go v1.11.2/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM=
github.com/beorn7/perks v0.0.0-20150223135152-b965b613227f/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -120,8 +94,6 @@ github.com/bodgit/sevenzip v1.3.0 h1:1ljgELgtHqvgIp8W8kgeEGHIWP4ch3xGI8uOBZgLVKY
github.com/bodgit/sevenzip v1.3.0/go.mod h1:omwNcgZTEooWM8gA/IJ2Nk/+ZQ94+GsytRzOJJ8FBlM=
github.com/bodgit/windows v1.0.0 h1:rLQ/XjsleZvx4fR1tB/UxQrK+SJ2OFHzfPjLWWOhDIA=
github.com/bodgit/windows v1.0.0/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM=
github.com/buger/goterm v1.0.4 h1:Z9YvGmOih81P0FbVtEYTFF6YsSgxSUKEhf/f9bTMXbY=
github.com/buger/goterm v1.0.4/go.mod h1:HiFWV3xnkolgrBV3mY8m0X0Pumt4zg4QhbdOzQtB8tE=
github.com/bugsnag/bugsnag-go v1.0.5-0.20150529004307-13fd6b8acda0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
github.com/bugsnag/bugsnag-go v1.5.0 h1:tP8hiPv1pGGW3LA6LKy5lW6WG+y9J2xWUdPd3WC452k=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
@@ -184,7 +156,6 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
@@ -236,7 +207,6 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484 h1:pEtiCjIXx3RvGjlUJuCNxNOw0MNblyR9Wi+vJGBFh+8=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -254,8 +224,6 @@ github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoD
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/fsnotify/fsevents v0.1.1 h1:/125uxJvvoSDDBPen6yUZbil8J9ydKZnnl3TWWmvnkw=
github.com/fsnotify/fsevents v0.1.1/go.mod h1:+d+hS27T6k5J8CRaPLKFgwKYcpS7GwW3Ule9+SC2ZRc=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
@@ -376,7 +344,6 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -450,7 +417,6 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -487,8 +453,6 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@@ -524,8 +488,6 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/jonboulle/clockwork v0.3.1-0.20230117163003-a89700cec744 h1:fJ+REXDOpsMqA2spt3wAq3HGJJvWnNitGK2KVZTos+8=
github.com/jonboulle/clockwork v0.3.1-0.20230117163003-a89700cec744/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
@@ -544,8 +506,6 @@ github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVE
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
@@ -588,17 +548,11 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/mattn/go-sqlite3 v1.6.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
@@ -606,8 +560,6 @@ github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwp
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mholt/archiver/v4 v4.0.0-alpha.8 h1:tRGQuDVPh66WCOelqe6LIGh0gwmfwxUrSSDunscGsRM=
github.com/mholt/archiver/v4 v4.0.0-alpha.8/go.mod h1:5f7FUYGXdJWUjESffJaYR4R60VhnHxb2X3T1teMyv5A=
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
@@ -632,17 +584,13 @@ github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo=
github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI=
github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg=
github.com/moby/sys/symlink v0.2.0 h1:tk1rOM+Ljp0nFmfOIBtlV3rTDlWOwFRhjEeAhZB0nZc=
github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6BMgR/gFs=
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA=
github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -759,8 +707,6 @@ github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
@@ -775,8 +721,6 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
github.com/secure-systems-lab/go-securesystemslib v0.4.0 h1:b23VGrQhTA8cN2CbBw7/FulN9fTtqYUdS5+Oxzt+DUE=
github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002 h1:ka9QPuQg2u4LGipiZGsgkg3rJCo4iIUCy75FddM0GRQ=
github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002/go.mod h1:/yeG0My1xr/u+HZrFQ1tOQQQQrOawfyMUH13ai5brBc=
github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI=
github.com/shirou/gopsutil/v3 v3.23.4 h1:hZwmDxZs7Ewt75DV81r4pFMqbq+di2cbt9FsQBqLD2o=
github.com/shirou/gopsutil/v3 v3.23.4/go.mod h1:ZcGxyfzAMRevhUR2+cfhXDH6gQdFYE/t8j1nsU4mPI8=
@@ -854,8 +798,6 @@ github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+x
github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY=
github.com/theupdateframework/notary v0.7.0 h1:QyagRZ7wlSpjT5N2qQAh/pN+DVqgekv4DzbAiAiEL3c=
github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnHqbFDGRSlXPO0AhYWw=
github.com/tilt-dev/fsnotify v1.4.8-0.20220602155310-fff9c274a375 h1:QB54BJwA6x8QU9nHY3xJSZR2kX9bgpZekRKGkLTmEXA=
github.com/tilt-dev/fsnotify v1.4.8-0.20220602155310-fff9c274a375/go.mod h1:xRroudyp5iVtxKqZCrA6n2TLFRBf8bmnjr1UD4x+z7g=
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
@@ -924,14 +866,9 @@ go.opentelemetry.io/otel v1.4.0/go.mod h1:jeAqMFKy2uLIxCtKxoFj0FAL5zAPKQagc3+GtB
go.opentelemetry.io/otel v1.4.1/go.mod h1:StM6F/0fSwpd8dKWDCdRr7uRvEPYdW0hBSlbdTiUde4=
go.opentelemetry.io/otel v1.15.1 h1:3Iwq3lfRByPaws0f6bU3naAqOR1n5IeDWd9390kWHa8=
go.opentelemetry.io/otel v1.15.1/go.mod h1:mHHGEHVDLal6YrKMmk9LqC4a3sF5g+fHfrttQIB1NTc=
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.4.1 h1:imIM3vRDMyZK1ypQlQlO+brE22I9lRhJsBDXpDWjlz8=
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.4.1/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.1 h1:WPpPsAAs8I2rA47v5u0558meKmmwm1Dj99ZbqCV8sZ8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.1/go.mod h1:o5RW5o2pKpJLD5dNTCmjF1DorYwMeFJmb/rKr5sLaa8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.1 h1:AxqDiGk8CorEXStMDZF5Hz9vo9Z7ZZ+I5m8JRl/ko40=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.1/go.mod h1:c6E4V3/U+miqjs/8l950wggHGL1qzlp0Ypj9xoGrPqo=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.4.1 h1:8qOago/OqoFclMUUj/184tZyRdDZFpcejSjbk5Jrl6Y=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.4.1/go.mod h1:VwYo0Hak6Efuy0TXsZs8o1hnV3dHDPNtDbycG0hI8+M=
go.opentelemetry.io/otel/internal/metric v0.27.0 h1:9dAVGAfFiiEq5NVB9FUJ5et+btbDQAUIJehJ+ikyryk=
go.opentelemetry.io/otel/internal/metric v0.27.0/go.mod h1:n1CVxRqKqYZtqyTh9U/onvKapPGv7y/rpyOTI+LFNzw=
go.opentelemetry.io/otel/metric v0.27.0 h1:HhJPsGhJoKRSegPQILFbODU56NS/L1UE4fS1sC5kIwQ=
@@ -946,8 +883,6 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe
go.opentelemetry.io/proto/otlp v0.12.0 h1:CMJ/3Wp7iOWES+CYLfnBv+DVmPbB+kmy9PJ92XvlR6c=
go.opentelemetry.io/proto/otlp v0.12.0/go.mod h1:TsIjwGWIx5VFYv9KGVlOpxoBl5Dy+63SUguV7GGvlSQ=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU=
@@ -1046,7 +981,6 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1092,7 +1026,6 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1106,13 +1039,9 @@ golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1124,7 +1053,6 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
@@ -1195,8 +1123,6 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=