Compare commits

..
12 Commits
19 changed files with 118 additions and 52 deletions
+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
+18 -18
View File
@@ -378,25 +378,25 @@ func (h *HostToolService) OperateSupervisorProcess(req request.SupervisorProcess
}
func (h *HostToolService) LoadProcessStatus() ([]response.ProcessStatus, error) {
var datas []response.ProcessStatus
statuLines, err := cmd.Exec("supervisorctl status")
if err != nil {
return datas, fmt.Errorf("exec `supervisorctl status` failed, err: %v", statuLines)
var res []response.ProcessStatus
statusLines, _ := cmd.Exec("supervisorctl status")
if len(statusLines) == 0 {
return res, nil
}
lines := strings.Split(string(statuLines), "\n")
lines := strings.Split(statusLines, "\n")
for _, line := range lines {
fields := strings.Fields(line)
if len(fields) > 1 {
datas = append(datas, response.ProcessStatus{Name: fields[0]})
res = append(res, response.ProcessStatus{Name: fields[0]})
}
}
var wg sync.WaitGroup
wg.Add(len(datas))
for i := 0; i < len(datas); i++ {
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", datas[index].Name), 2*time.Second)
status, err := cmd.ExecWithTimeOut(fmt.Sprintf("supervisorctl status %s", res[index].Name), 2*time.Second)
if err != nil {
time.Sleep(2 * time.Second)
continue
@@ -406,25 +406,25 @@ func (h *HostToolService) LoadProcessStatus() ([]response.ProcessStatus, error)
time.Sleep(2 * time.Second)
continue
}
datas[index].Name = fields[0]
datas[index].Status = fields[1]
res[index].Name = fields[0]
res[index].Status = fields[1]
if fields[1] != "RUNNING" {
datas[index].Msg = strings.Join(fields[2:], " ")
res[index].Msg = strings.Join(fields[2:], " ")
break
}
datas[index].PID = strings.TrimSuffix(fields[3], ",")
datas[index].Uptime = fields[5]
res[index].PID = strings.TrimSuffix(fields[3], ",")
res[index].Uptime = fields[5]
break
}
if len(datas[index].Status) == 0 {
datas[index].Status = "FATAL"
datas[index].Msg = "Timeout for getting process status"
if len(res[index].Status) == 0 {
res[index].Status = "FATAL"
res[index].Msg = "Timeout for getting process status"
}
wg.Done()
}(i)
}
wg.Wait()
return datas, nil
return res, nil
}
func (h *HostToolService) GetSupervisorProcessConfig() ([]response.SupervisorProcessConfig, error) {
+1
View File
@@ -46,6 +46,7 @@ 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"
+1
View File
@@ -46,6 +46,7 @@ ErrContainerNotFound: '{{ .name }} 容器不存在'
ErrContainerMsg: '{{ .name }} 容器異常,具體請在容器頁面查看日誌'
ErrAppBackup: '{{ .name }} 應用備份失敗 err {{.err}}'
ErrImagePull: '{{ .name }} 鏡像拉取失敗 err {{.err}}'
ErrVersionTooLow: '當前 1Panel 版本過低,無法更新應用商店,請升級版本之後操作'
#file
ErrFileCanNotRead: "此文件不支持預覽"
+1
View File
@@ -46,6 +46,7 @@ ErrContainerNotFound: '{{ .name }} 容器不存在'
ErrContainerMsg: '{{ .name }} 容器异常,具体请在容器页面查看日志'
ErrAppBackup: '{{ .name }} 应用备份失败 err {{.err}}'
ErrImagePull: '镜像拉取失败 {{.err}}'
ErrVersionTooLow: '当前 1Panel 版本过低,无法更新应用商店,请升级版本之后操作'
#file
ErrFileCanNotRead: "此文件不支持预览"
+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 {
-4
View File
@@ -8,7 +8,6 @@ import (
"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"
)
@@ -28,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
}
+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
@@ -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;
}
@@ -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 = [
+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';
},
},
];
@@ -184,6 +184,7 @@ const setting = () => {
const getStatus = (status: any) => {
supervisorStatus.value = status;
search();
};
const showStopped = computed((): boolean => {
@@ -211,6 +212,9 @@ const openCreate = () => {
};
const search = async () => {
if (!supervisorStatus.value.isExist) {
return;
}
loading.value = true;
loadStatus();
try {
@@ -231,9 +235,7 @@ const loadStatus = async () => {
process.status.push(item);
}
}
if (process.status.length !== 0) {
process.hasLoad = true;
}
process.hasLoad = true;
}
})
.catch(() => {