Compare commits

..
8 Commits
339 changed files with 12414 additions and 14497 deletions
-36
View File
@@ -1,36 +0,0 @@
on:
pull_request:
branches:
- dev
push:
branches:
- dev
name: Build Test
jobs:
build-linux-binary:
runs-on: ubuntu-latest
steps:
- name: Install cross-compilers
run: sudo apt-get update && sudo apt-get -y install gcc-x86-64-linux-gnu gcc-aarch64-linux-gnu gcc-arm-linux-gnueabi gcc-powerpc64le-linux-gnu gcc-s390x-linux-gnu
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '18.14'
- name: Build Web
id: build_frontend
run: |
cd frontend && npm install && npm run build:dev
env:
NODE_OPTIONS: --max-old-space-size=8192
- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: '1.20.x'
- name: Build Server
uses: goreleaser/goreleaser-action@v4
with:
args: release --snapshot --clean
-52
View File
@@ -1,52 +0,0 @@
on:
push:
# Sequence of patterns matched against refs/tags
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
name: Create Release And Upload assets
jobs:
create-release:
runs-on: ubuntu-latest
steps:
- name: Install cross-compilers
run: sudo apt-get update && sudo apt-get -y install gcc-x86-64-linux-gnu gcc-aarch64-linux-gnu gcc-arm-linux-gnueabi gcc-powerpc64le-linux-gnu gcc-s390x-linux-gnu
- name: Checkout code
uses: actions/checkout@v2
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '18.14'
- name: Build Web
run: |
cd frontend && npm install && npm run build:dev
env:
NODE_OPTIONS: --max-old-space-size=8192
- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: '1.20.x'
- name: Build Release
uses: goreleaser/goreleaser-action@v4
with:
args: release --skip-publish --clean
- name: Upload Assets
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
draft: true
files: |
dist/*.tar.gz
dist/checksums.txt
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Setup OSSUTIL
uses: yizhoumo/setup-ossutil@v1
with:
endpoint: ${{ secrets.OSS_ENDPOINT }}
access-key-id: ${{ secrets.OSS_ACCESS_KEY_ID }}
access-key-secret: ${{ secrets.OSS_ACCESS_KEY_SECRET }}
ossutil-version: '1.7.14'
- name: Upload Assets to OSS
run: ossutil cp -r dist/ oss://resource-fit2cloud-com/1panel/package/stable/${{ github.ref_name }}/release/ --include "*.tar.gz" --include "checksums.txt" --only-current-dir
-9
View File
@@ -23,12 +23,3 @@ cmd/server/web/assets
cmd/server/web/monacoeditorwork
cmd/server/web/index.html
frontend/auto-imports.d.ts
frontend/components.d.ts
.history/
dist/
1pctl
1panel.service
install.sh
cmd/server/web/.DS_Store
cmd/server/.DS_Store
-68
View File
@@ -1,68 +0,0 @@
# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com
before:
hooks:
# - export NODE_OPTIONS="--max-old-space-size=8192"
# - make build_web
- chmod +x ./script.sh
- ./script.sh
- sed -i 's@ORIGINAL_VERSION=.*@ORIGINAL_VERSION=v{{ .Version }}@g' 1pctl
- go mod tidy
builds:
- main: ./cmd/server/main.go
binary: 1panel
flags:
- -trimpath
ldflags:
- -w -s
- --extldflags "-static -fpic"
tags:
- osusergo
env:
- CGO_ENABLED=1
- >-
{{- if eq .Arch "amd64"}}CC=x86_64-linux-gnu-gcc{{- end }}
{{- if eq .Arch "arm64"}}CC=aarch64-linux-gnu-gcc{{- end }}
{{- if eq .Arch "arm"}}CC=arm-linux-gnueabi-gcc{{- end }}
{{- if eq .Arch "loong64"}}CC=loongarch64-linux-gnu-gcc{{- end }}
{{- if eq .Arch "ppc64le"}}CC=powerpc64le-linux-gnu-gcc{{- end }}
{{- if eq .Arch "s390x"}}CC=s390x-linux-gnu-gcc{{- end }}
goos:
- linux
goarm:
- 7
goarch:
- amd64
- arm64
- arm
- ppc64le
- s390x
archives:
- format: tar.gz
name_template: "1panel-v{{ .Version }}-{{ .Os }}-{{ .Arch }}{{- if .Arm }}v{{ .Arm }}{{ end }}"
wrap_in_directory: true
files:
- 1pctl
- 1panel.service
- install.sh
- README.md
- LICENSE
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ incpatch .Version }}-next"
release:
draft: true
mode: append
extra_files:
- glob: dist/*.tar.gz
- glob: dist/checksums.txt
name_template: "Release {{.Tag}}"
# The lines beneath this are called `modelines`. See `:help modeline`
# Feel free to remove those if you don't want/use them.
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
-3
View File
@@ -1,3 +0,0 @@
{
"ansible.python.interpreterPath": "/opt/homebrew/bin/python3"
}
-34
View File
@@ -1,34 +0,0 @@
FROM node:18.14 as build_web
ARG TARGETARCH
ARG NPM_REGISTRY="https://registry.npmmirror.com"
ENV NODE_OPTIONS="--max-old-space-size=4096"
WORKDIR /data
RUN set -ex \
&& npm config set registry ${NPM_REGISTRY}
ADD . /data
RUN set -ex \
&& cd /data/frontend \
&& npm install
RUN set -ex \
&& cd /data/frontend \
&& npm run build:dev
FROM golang:1.20
ARG TARGETARCH
ARG GOPROXY="https://goproxy.cn,direct"
COPY --from=build_web /data /data
WORKDIR /data
RUN set -ex \
&& go env -w GOPROXY=${GOPROXY} \
&& go install github.com/goreleaser/goreleaser@latest \
&& goreleaser build --single-target --snapshot --clean
CMD ["/bin/bash"]
+1 -10
View File
@@ -10,16 +10,9 @@ WEB_PATH=$(BASE_PAH)/frontend
SERVER_PATH=$(BASE_PAH)/backend
MAIN= $(BASE_PAH)/cmd/server/main.go
APP_NAME=1panel
ASSERT_PATH= $(BASE_PAH)/cmd/server/web/assets
clean_assets:
rm -rf $(ASSERT_PATH)
upx_bin:
upx $(BUILD_PATH)/$(APP_NAME)
build_frontend:
cd $(WEB_PATH) && npm install && npm run build:pro
cd $(WEB_PATH) && npm install && npm run build:dev
build_backend_on_linux:
cd $(SERVER_PATH) \
@@ -34,5 +27,3 @@ build_backend_on_archlinux:
&& CGO_ENABLED=1 GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOBUILD) -trimpath -ldflags '-s -w --extldflags "-fpic"' -tags osusergo -o $(BUILD_PATH)/$(APP_NAME) $(MAIN)
build_all: build_frontend build_backend_on_linux
build_on_local: clean_assets build_frontend build_backend_on_darwin upx_bin
+1 -11
View File
@@ -5,7 +5,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/i18n"
"github.com/gin-gonic/gin"
)
@@ -40,15 +39,6 @@ func (b *BaseApi) SearchApp(c *gin.Context) {
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"应用商店同步","formatEN":"App store synchronization"}
func (b *BaseApi) SyncApp(c *gin.Context) {
go appService.SyncAppListFromLocal()
res, err := appService.GetAppUpdate()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
if !res.CanUpdate {
helper.SuccessWithMsg(c, i18n.GetMsgByKey("AppStoreIsUpToDate"))
return
}
go func() {
global.LOG.Infof("sync app list start ...")
if err := appService.SyncAppListFromRemote(); err != nil {
@@ -138,7 +128,7 @@ func (b *BaseApi) GetAppDetailByID(c *gin.Context) {
// @Success 200 {object} model.AppInstall
// @Security ApiKeyAuth
// @Router /apps/install [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[{"input_column":"name","input_value":"name","isList":false,"db":"app_installs","output_column":"app_id","output_value":"appId"},{"info":"appId","isList":false,"db":"apps","output_column":"key","output_value":"appKey"}],"formatZH":"安装应用 [appKey]-[name]","formatEN":"Install app [appKey]-[name]"}
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"name","input_value":"name","isList":false,"db":"app_installs","output_colume":"app_id","output_value":"appId"},{"info":"appId","isList":false,"db":"apps","output_colume":"key","output_value":"appKey"}],"formatZH":"安装应用 [appKey]-[name]","formatEN":"Install app [appKey]-[name]"}
func (b *BaseApi) InstallApp(c *gin.Context) {
var req request.AppInstallCreate
if err := c.ShouldBindJSON(&req); err != nil {
+1 -1
View File
@@ -159,7 +159,7 @@ func (b *BaseApi) SyncInstalled(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /apps/installed/op [post]
// @x-panel-log {"bodyKeys":["installId","operate"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"installId","isList":false,"db":"app_installs","output_column":"app_id","output_value":"appId"},{"input_column":"id","input_value":"installId","isList":false,"db":"app_installs","output_column":"name","output_value":"appName"},{"input_column":"id","input_value":"appId","isList":false,"db":"apps","output_column":"key","output_value":"appKey"}],"formatZH":"[operate] 应用 [appKey][appName]","formatEN":"[operate] App [appKey][appName]"}
// @x-panel-log {"bodyKeys":["installId","operate"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"installId","isList":false,"db":"app_installs","output_colume":"app_id","output_value":"appId"},{"input_colume":"id","input_value":"installId","isList":false,"db":"app_installs","output_colume":"name","output_value":"appName"},{"input_colume":"id","input_value":"appId","isList":false,"db":"apps","output_colume":"key","output_value":"appKey"}],"formatZH":"[appKey] 应用 [appName] [operate]","formatEN":"[appKey] App [appName] [operate]"}
func (b *BaseApi) OperateInstalled(c *gin.Context) {
var req request.AppInstalledOperate
if err := c.ShouldBindJSON(&req); err != nil {
+1 -6
View File
@@ -103,12 +103,7 @@ func (b *BaseApi) Captcha(c *gin.Context) {
// @Router /auth/issafety [get]
func (b *BaseApi) CheckIsSafety(c *gin.Context) {
code := c.DefaultQuery("code", "")
status, err := authService.CheckIsSafety(code)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, status)
helper.SuccessWithData(c, authService.CheckIsSafety(code))
}
// @Tags Auth
+2 -2
View File
@@ -106,7 +106,7 @@ func (b *BaseApi) ListBuckets(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/backup/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":true,"db":"backup_accounts","output_column":"type","output_value":"types"}],"formatZH":"删除备份账号 [types]","formatEN":"delete backup account [types]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":true,"db":"backup_accounts","output_colume":"type","output_value":"types"}],"formatZH":"删除备份账号 [types]","formatEN":"delete backup account [types]"}
func (b *BaseApi) DeleteBackup(c *gin.Context) {
var req dto.OperateByID
if err := c.ShouldBindJSON(&req); err != nil {
@@ -188,7 +188,7 @@ func (b *BaseApi) DownloadRecord(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/backup/record/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"backup_records","output_column":"file_name","output_value":"files"}],"formatZH":"删除备份记录 [files]","formatEN":"delete backup records [files]"}
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"ids","isList":true,"db":"backup_records","output_colume":"file_name","output_value":"files"}],"formatZH":"删除备份记录 [files]","formatEN":"delete backup records [files]"}
func (b *BaseApi) DeleteBackupRecord(c *gin.Context) {
var req dto.BatchDeleteReq
if err := c.ShouldBindJSON(&req); err != nil {
+1 -1
View File
@@ -85,7 +85,7 @@ func (b *BaseApi) ListCommand(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /hosts/command/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"commands","output_column":"name","output_value":"names"}],"formatZH":"删除快捷命令 [names]","formatEN":"delete quick command [names]"}
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"ids","isList":true,"db":"commands","output_colume":"name","output_value":"names"}],"formatZH":"删除快捷命令 [names]","formatEN":"delete quick command [names]"}
func (b *BaseApi) DeleteCommand(c *gin.Context) {
var req dto.BatchDeleteReq
if err := c.ShouldBindJSON(&req); err != nil {
+2 -2
View File
@@ -87,7 +87,7 @@ func (b *BaseApi) ListComposeTemplate(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/template/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"compose_templates","output_column":"name","output_value":"names"}],"formatZH":"删除 compose 模版 [names]","formatEN":"delete compose template [names]"}
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"ids","isList":true,"db":"compose_templates","output_colume":"name","output_value":"names"}],"formatZH":"删除 compose 模版 [names]","formatEN":"delete compose template [names]"}
func (b *BaseApi) DeleteComposeTemplate(c *gin.Context) {
var req dto.BatchDeleteReq
if err := c.ShouldBindJSON(&req); err != nil {
@@ -114,7 +114,7 @@ func (b *BaseApi) DeleteComposeTemplate(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/template/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"compose_templates","output_column":"name","output_value":"name"}],"formatZH":"更新 compose 模版 [name]","formatEN":"update compose template information [name]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"compose_templates","output_colume":"name","output_value":"name"}],"formatZH":"更新 compose 模版 [name]","formatEN":"update compose template information [name]"}
func (b *BaseApi) UpdateComposeTemplate(c *gin.Context) {
var req dto.ComposeTemplateUpdate
if err := c.ShouldBindJSON(&req); err != nil {
+4 -57
View File
@@ -179,59 +179,6 @@ func (b *BaseApi) ContainerCreate(c *gin.Context) {
helper.SuccessWithData(c, nil)
}
// @Tags Container
// @Summary Clean container
// @Description 容器清理
// @Accept json
// @Param request body dto.ContainerPrune true "request"
// @Success 200 {object} dto.ContainerPruneReport
// @Security ApiKeyAuth
// @Router /containers/prune [post]
// @x-panel-log {"bodyKeys":["pruneType"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"清理容器 [pruneType]","formatEN":"clean container [pruneType]"}
func (b *BaseApi) ContainerPrune(c *gin.Context) {
var req dto.ContainerPrune
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
}
report, err := containerService.Prune(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, report)
}
// @Tags Container
// @Summary Clean container log
// @Description 清理容器日志
// @Accept json
// @Param request body dto.OperationWithName true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/clean/log [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"清理容器 [name] 日志","formatEN":"clean container [name] logs"}
func (b *BaseApi) CleanContainerLog(c *gin.Context) {
var req dto.OperationWithName
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
}
if err := containerService.ContainerLogClean(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Container
// @Summary Operate Container
// @Description 容器操作
@@ -395,13 +342,13 @@ func (b *BaseApi) DeleteNetwork(c *gin.Context) {
// @Summary Create network
// @Description 创建容器网络
// @Accept json
// @Param request body dto.NetworkCreate true "request"
// @Param request body dto.NetworkCreat true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/network [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建容器网络 name","formatEN":"create container network [name]"}
func (b *BaseApi) CreateNetwork(c *gin.Context) {
var req dto.NetworkCreate
var req dto.NetworkCreat
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
@@ -498,13 +445,13 @@ func (b *BaseApi) DeleteVolume(c *gin.Context) {
// @Summary Create volume
// @Description 创建容器存储卷
// @Accept json
// @Param request body dto.VolumeCreate true "request"
// @Param request body dto.VolumeCreat true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/volume [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建容器存储卷 [name]","formatEN":"create container volume [name]"}
func (b *BaseApi) CreateVolume(c *gin.Context) {
var req dto.VolumeCreate
var req dto.VolumeCreat
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
+6 -6
View File
@@ -102,7 +102,7 @@ func (b *BaseApi) SearchJobRecords(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /cronjobs/records/clean [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"cronjobs","output_column":"name","output_value":"name"}],"formatZH":"清空计划任务记录 [name]","formatEN":"clean cronjob [name] records"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"cronjobs","output_colume":"name","output_value":"name"}],"formatZH":"清空计划任务记录 [name]","formatEN":"clean cronjob [name] records"}
func (b *BaseApi) CleanRecord(c *gin.Context) {
var req dto.CronjobClean
if err := c.ShouldBindJSON(&req); err != nil {
@@ -126,7 +126,7 @@ func (b *BaseApi) CleanRecord(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /cronjobs/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"cronjobs","output_column":"name","output_value":"names"}],"formatZH":"删除计划任务 [names]","formatEN":"delete cronjob [names]"}
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"ids","isList":true,"db":"cronjobs","output_colume":"name","output_value":"names"}],"formatZH":"删除计划任务 [names]","formatEN":"delete cronjob [names]"}
func (b *BaseApi) DeleteCronjob(c *gin.Context) {
var req dto.CronjobBatchDelete
if err := c.ShouldBindJSON(&req); err != nil {
@@ -153,7 +153,7 @@ func (b *BaseApi) DeleteCronjob(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /cronjobs/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"cronjobs","output_column":"name","output_value":"name"}],"formatZH":"更新计划任务 [name]","formatEN":"update cronjob [name]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"cronjobs","output_colume":"name","output_value":"name"}],"formatZH":"更新计划任务 [name]","formatEN":"update cronjob [name]"}
func (b *BaseApi) UpdateCronjob(c *gin.Context) {
var req dto.CronjobUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -180,7 +180,7 @@ func (b *BaseApi) UpdateCronjob(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /cronjobs/status [post]
// @x-panel-log {"bodyKeys":["id","status"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"cronjobs","output_column":"name","output_value":"name"}],"formatZH":"修改计划任务 [name] 状态为 [status]","formatEN":"change the status of cronjob [name] to [status]."}
// @x-panel-log {"bodyKeys":["id","status"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"cronjobs","output_colume":"name","output_value":"name"}],"formatZH":"修改计划任务 [name] 状态为 [status]","formatEN":"change the status of cronjob [name] to [status]."}
func (b *BaseApi) UpdateCronjobStatus(c *gin.Context) {
var req dto.CronjobUpdateStatus
if err := c.ShouldBindJSON(&req); err != nil {
@@ -207,7 +207,7 @@ func (b *BaseApi) UpdateCronjobStatus(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /cronjobs/download [post]
// @x-panel-log {"bodyKeys":["recordID"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"recordID","isList":false,"db":"job_records","output_column":"file","output_value":"file"}],"formatZH":"下载计划任务记录 [file]","formatEN":"download the cronjob record [file]"}
// @x-panel-log {"bodyKeys":["recordID"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"recordID","isList":false,"db":"job_records","output_colume":"file","output_value":"file"}],"formatZH":"下载计划任务记录 [file]","formatEN":"download the cronjob record [file]"}
func (b *BaseApi) TargetDownload(c *gin.Context) {
var req dto.CronjobDownload
if err := c.ShouldBindJSON(&req); err != nil {
@@ -235,7 +235,7 @@ func (b *BaseApi) TargetDownload(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /cronjobs/handle [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"cronjobs","output_column":"name","output_value":"name"}],"formatZH":"手动执行计划任务 [name]","formatEN":"manually execute the cronjob [name]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"cronjobs","output_colume":"name","output_value":"name"}],"formatZH":"手动执行计划任务 [name]","formatEN":"manually execute the cronjob [name]"}
func (b *BaseApi) HandleOnce(c *gin.Context) {
var req dto.OperateByID
if err := c.ShouldBindJSON(&req); err != nil {
+4 -4
View File
@@ -54,7 +54,7 @@ func (b *BaseApi) CreateMysql(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/description/update [post]
// @x-panel-log {"bodyKeys":["id","description"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"database_mysqls","output_column":"name","output_value":"name"}],"formatZH":"mysql 数据库 [name] 描述信息修改 [description]","formatEN":"The description of the mysql database [name] is modified => [description]"}
// @x-panel-log {"bodyKeys":["id","description"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"database_mysqls","output_colume":"name","output_value":"name"}],"formatZH":"mysql 数据库 [name] 描述信息修改 [description]","formatEN":"The description of the mysql database [name] is modified => [description]"}
func (b *BaseApi) UpdateMysqlDescription(c *gin.Context) {
var req dto.UpdateDescription
if err := c.ShouldBindJSON(&req); err != nil {
@@ -80,7 +80,7 @@ func (b *BaseApi) UpdateMysqlDescription(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/change/password [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"database_mysqls","output_column":"name","output_value":"name"}],"formatZH":"更新数据库 [name] 密码","formatEN":"Update database [name] password"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"database_mysqls","output_colume":"name","output_value":"name"}],"formatZH":"更新数据库 [name] 密码","formatEN":"Update database [name] password"}
func (b *BaseApi) ChangeMysqlPassword(c *gin.Context) {
var req dto.ChangeDBInfo
if err := c.ShouldBindJSON(&req); err != nil {
@@ -115,7 +115,7 @@ func (b *BaseApi) ChangeMysqlPassword(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/change/access [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"database_mysqls","output_column":"name","output_value":"name"}],"formatZH":"更新数据库 [name] 访问权限","formatEN":"Update database [name] access"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"database_mysqls","output_colume":"name","output_value":"name"}],"formatZH":"更新数据库 [name] 访问权限","formatEN":"Update database [name] access"}
func (b *BaseApi) ChangeMysqlAccess(c *gin.Context) {
var req dto.ChangeDBInfo
if err := c.ShouldBindJSON(&req); err != nil {
@@ -264,7 +264,7 @@ func (b *BaseApi) DeleteCheckMysql(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /databases/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"database_mysqls","output_column":"name","output_value":"name"}],"formatZH":"删除 mysql 数据库 [name]","formatEN":"delete mysql database [name]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"database_mysqls","output_colume":"name","output_value":"name"}],"formatZH":"删除 mysql 数据库 [name]","formatEN":"delete mysql database [name]"}
func (b *BaseApi) DeleteMysql(c *gin.Context) {
var req dto.MysqlDBDelete
if err := c.ShouldBindJSON(&req); err != nil {
+3 -27
View File
@@ -58,13 +58,13 @@ func (b *BaseApi) LoadDaemonJson(c *gin.Context) {
// @Summary Update docker daemon.json
// @Description 修改 docker 配置信息
// @Accept json
// @Param request body dto.SettingUpdate true "request"
// @Param request body dto.DaemonJsonConf true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/daemonjson/update [post]
// @x-panel-log {"bodyKeys":["key", "value"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新 docker daemon.json 配置 [key]=>[value]","formatEN":"Updated the docker daemon.json configuration [key]=>[value]"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新 docker daemon.json 配置","formatEN":"Updated the docker daemon.json configuration"}
func (b *BaseApi) UpdateDaemonJson(c *gin.Context) {
var req dto.SettingUpdate
var req dto.DaemonJsonConf
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
@@ -78,30 +78,6 @@ func (b *BaseApi) UpdateDaemonJson(c *gin.Context) {
helper.SuccessWithData(c, nil)
}
// @Tags Container Docker
// @Summary Update docker daemon.json log option
// @Description 修改 docker 日志配置
// @Accept json
// @Param request body dto.LogOption true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/daemonjson/update [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新 docker daemon.json 日志配置","formatEN":"Updated the docker daemon.json log option"}
func (b *BaseApi) UpdateLogOption(c *gin.Context) {
var req dto.LogOption
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := dockerService.UpdateLogOption(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Container Docker
// @Summary Update docker daemon.json by upload file
// @Description 上传替换 docker 配置文件
+3 -4
View File
@@ -26,10 +26,9 @@ var (
cronjobService = service.NewICronjobService()
hostService = service.NewIHostService()
groupService = service.NewIGroupService()
fileService = service.NewIFileService()
sshService = service.NewISSHService()
hostService = service.NewIHostService()
groupService = service.NewIGroupService()
fileService = service.NewIFileService()
firewallService = service.NewIFirewallService()
settingService = service.NewISettingService()
+13 -96
View File
@@ -5,7 +5,6 @@ import (
"fmt"
"io"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
@@ -455,93 +454,17 @@ func (b *BaseApi) MoveFile(c *gin.Context) {
// @Router /files/download [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"下载文件 [name]","formatEN":"Download file [name]"}
func (b *BaseApi) Download(c *gin.Context) {
filePath := c.Query("path")
file, err := os.Open(filePath)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
}
info, _ := file.Stat()
c.Header("Content-Length", strconv.FormatInt(info.Size(), 10))
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(info.Name()))
http.ServeContent(c.Writer, c.Request, info.Name(), info.ModTime(), file)
}
// @Tags File
// @Summary Chunk Download file
// @Description 分片下载下载文件
// @Accept json
// @Param request body request.FileDownload true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /files/chunkdownload [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"下载文件 [name]","formatEN":"Download file [name]"}
func (b *BaseApi) DownloadChunkFiles(c *gin.Context) {
var req request.FileChunkDownload
var req request.FileDownload
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
fileOp := files.NewFileOp()
if !fileOp.Stat(req.Path) {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrPathNotFound, nil)
return
}
filePath := req.Path
fstFile, err := fileOp.OpenFile(filePath)
filePath, err := fileService.FileDownload(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
info, err := fstFile.Stat()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
if info.IsDir() {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrFileDownloadDir, err)
return
}
c.Writer.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", req.Name))
c.Writer.Header().Set("Content-Type", "application/octet-stream")
c.Writer.Header().Set("Content-Length", strconv.FormatInt(info.Size(), 10))
c.Writer.Header().Set("Accept-Ranges", "bytes")
if c.Request.Header.Get("Range") != "" {
rangeHeader := c.Request.Header.Get("Range")
rangeArr := strings.Split(rangeHeader, "=")[1]
rangeParts := strings.Split(rangeArr, "-")
startPos, _ := strconv.ParseInt(rangeParts[0], 10, 64)
var endPos int64
if rangeParts[1] == "" {
endPos = info.Size() - 1
} else {
endPos, _ = strconv.ParseInt(rangeParts[1], 10, 64)
}
c.Writer.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", startPos, endPos, info.Size()))
c.Writer.WriteHeader(http.StatusPartialContent)
buffer := make([]byte, 1024*1024)
file, err := os.Open(filePath)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
defer file.Close()
file.Seek(startPos, 0)
reader := io.LimitReader(file, endPos-startPos+1)
_, err = io.CopyBuffer(c.Writer, reader, buffer)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
} else {
c.File(filePath)
}
c.File(filePath)
}
// @Tags File
@@ -652,7 +575,6 @@ func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int)
// @Security ApiKeyAuth
// @Router /files/chunkupload [post]
func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
var err error
fileForm, err := c.FormFile("chunk")
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
@@ -663,16 +585,19 @@ func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
chunkIndex, err := strconv.Atoi(c.PostForm("chunkIndex"))
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
chunkCount, err := strconv.Atoi(c.PostForm("chunkCount"))
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
fileOp := files.NewFileOp()
tmpDir := path.Join(global.CONF.System.TmpDir, "upload")
if !fileOp.Stat(tmpDir) {
@@ -681,45 +606,37 @@ func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
return
}
}
filename := c.PostForm("filename")
fileDir := filepath.Join(tmpDir, filename)
_ = os.MkdirAll(fileDir, 0755)
filePath := filepath.Join(fileDir, filename)
defer func() {
if err != nil {
_ = os.Remove(fileDir)
}
}()
var (
emptyFile *os.File
chunkData []byte
)
emptyFile, err = os.Create(filePath)
emptyFile, err := os.Create(filePath)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
defer emptyFile.Close()
chunkData, err = io.ReadAll(uploadFile)
chunkData, err := io.ReadAll(uploadFile)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, buserr.WithMap(constant.ErrFileUpload, map[string]interface{}{"name": filename, "detail": err.Error()}, err))
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrFileUpload, err)
return
}
chunkPath := filepath.Join(fileDir, fmt.Sprintf("%s.%d", filename, chunkIndex))
err = os.WriteFile(chunkPath, chunkData, 0644)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, buserr.WithMap(constant.ErrFileUpload, map[string]interface{}{"name": filename, "detail": err.Error()}, err))
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrFileUpload, err)
return
}
if chunkIndex+1 == chunkCount {
err = mergeChunks(filename, fileDir, c.PostForm("path"), chunkCount)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, buserr.WithMap(constant.ErrFileUpload, map[string]interface{}{"name": filename, "detail": err.Error()}, err))
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrFileUpload, err)
return
}
helper.SuccessWithData(c, true)
+1 -1
View File
@@ -149,7 +149,7 @@ func (b *BaseApi) BatchOperateRule(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := firewallService.BatchOperateRule(req); err != nil {
if err := firewallService.BacthOperateRule(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
+2 -2
View File
@@ -42,7 +42,7 @@ func (b *BaseApi) CreateGroup(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /groups/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"groups","output_column":"name","output_value":"name"},{"input_column":"id","input_value":"id","isList":false,"db":"groups","output_column":"type","output_value":"type"}],"formatZH":"删除组 [type][name]","formatEN":"delete group [type][name]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"groups","output_colume":"name","output_value":"name"},{"input_colume":"id","input_value":"id","isList":false,"db":"groups","output_colume":"type","output_value":"type"}],"formatZH":"删除组 [type][name]","formatEN":"delete group [type][name]"}
func (b *BaseApi) DeleteGroup(c *gin.Context) {
var req dto.OperateByID
if err := c.ShouldBindJSON(&req); err != nil {
@@ -92,7 +92,7 @@ func (b *BaseApi) UpdateGroup(c *gin.Context) {
// @Description 查询系统组
// @Accept json
// @Param request body dto.GroupSearch true "request"
// @Success 200 {array} dto.GroupInfo
// @Success 200 {anrry} dto.GroupInfo
// @Security ApiKeyAuth
// @Router /groups/search [post]
func (b *BaseApi) ListGroup(c *gin.Context) {
+2 -2
View File
@@ -183,7 +183,7 @@ func (b *BaseApi) GetHostInfo(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /hosts/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"hosts","output_column":"addr","output_value":"addrs"}],"formatZH":"删除主机 [addrs]","formatEN":"delete host [addrs]"}
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"ids","isList":true,"db":"hosts","output_colume":"addr","output_value":"addrs"}],"formatZH":"删除主机 [addrs]","formatEN":"delete host [addrs]"}
func (b *BaseApi) DeleteHost(c *gin.Context) {
var req dto.BatchDeleteReq
if err := c.ShouldBindJSON(&req); err != nil {
@@ -269,7 +269,7 @@ func (b *BaseApi) UpdateHost(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /hosts/update/group [post]
// @x-panel-log {"bodyKeys":["id","group"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"hosts","output_column":"addr","output_value":"addr"}],"formatZH":"切换主机[addr]分组 => [group]","formatEN":"change host [addr] group => [group]"}
// @x-panel-log {"bodyKeys":["id","group"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"hosts","output_colume":"addr","output_value":"addr"}],"formatZH":"切换主机[addr]分组 => [group]","formatEN":"change host [addr] group => [group]"}
func (b *BaseApi) UpdateHostGroup(c *gin.Context) {
var req dto.ChangeHostGroup
if err := c.ShouldBindJSON(&req); err != nil {
+3 -3
View File
@@ -93,7 +93,7 @@ func (b *BaseApi) ImageBuild(c *gin.Context) {
// @Success 200 {string} log
// @Security ApiKeyAuth
// @Router /containers/image/pull [post]
// @x-panel-log {"bodyKeys":["repoID","imageName"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"repoID","isList":false,"db":"image_repos","output_column":"name","output_value":"reponame"}],"formatZH":"镜像拉取 [reponame][imageName]","formatEN":"image pull [reponame][imageName]"}
// @x-panel-log {"bodyKeys":["repoID","imageName"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"repoID","isList":false,"db":"image_repos","output_colume":"name","output_value":"reponame"}],"formatZH":"镜像拉取 [reponame][imageName]","formatEN":"image pull [reponame][imageName]"}
func (b *BaseApi) ImagePull(c *gin.Context) {
var req dto.ImagePull
if err := c.ShouldBindJSON(&req); err != nil {
@@ -122,7 +122,7 @@ func (b *BaseApi) ImagePull(c *gin.Context) {
// @Success 200 {string} log
// @Security ApiKeyAuth
// @Router /containers/image/push [post]
// @x-panel-log {"bodyKeys":["repoID","tagName","name"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"repoID","isList":false,"db":"image_repos","output_column":"name","output_value":"reponame"}],"formatZH":"[tagName] 推送到 [reponame][name]","formatEN":"push [tagName] to [reponame][name]"}
// @x-panel-log {"bodyKeys":["repoID","tagName","name"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"repoID","isList":false,"db":"image_repos","output_colume":"name","output_value":"reponame"}],"formatZH":"[tagName] 推送到 [reponame][name]","formatEN":"push [tagName] to [reponame][name]"}
func (b *BaseApi) ImagePush(c *gin.Context) {
var req dto.ImagePush
if err := c.ShouldBindJSON(&req); err != nil {
@@ -207,7 +207,7 @@ func (b *BaseApi) ImageSave(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/image/tag [post]
// @x-panel-log {"bodyKeys":["repoID","targetName"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"repoID","isList":false,"db":"image_repos","output_column":"name","output_value":"reponame"}],"formatZH":"tag 镜像 [reponame][targetName]","formatEN":"tag image [reponame][targetName]"}
// @x-panel-log {"bodyKeys":["repoID","targetName"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"repoID","isList":false,"db":"image_repos","output_colume":"name","output_value":"reponame"}],"formatZH":"tag 镜像 [reponame][targetName]","formatEN":"tag image [reponame][targetName]"}
func (b *BaseApi) ImageTag(c *gin.Context) {
var req dto.ImageTag
if err := c.ShouldBindJSON(&req); err != nil {
+2 -2
View File
@@ -119,7 +119,7 @@ func (b *BaseApi) CreateRepo(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/repo/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"image_repos","output_column":"name","output_value":"names"}],"formatZH":"删除镜像仓库 [names]","formatEN":"delete image repo [names]"}
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"ids","isList":true,"db":"image_repos","output_colume":"name","output_value":"names"}],"formatZH":"删除镜像仓库 [names]","formatEN":"delete image repo [names]"}
func (b *BaseApi) DeleteRepo(c *gin.Context) {
var req dto.ImageRepoDelete
if err := c.ShouldBindJSON(&req); err != nil {
@@ -147,7 +147,7 @@ func (b *BaseApi) DeleteRepo(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/repo/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"image_repos","output_column":"name","output_value":"name"}],"formatZH":"更新镜像仓库 [name]","formatEN":"update image repo information [name]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"image_repos","output_colume":"name","output_value":"name"}],"formatZH":"更新镜像仓库 [name]","formatEN":"update image repo information [name]"}
func (b *BaseApi) UpdateRepo(c *gin.Context) {
var req dto.ImageRepoUpdate
if err := c.ShouldBindJSON(&req); err != nil {
+1 -1
View File
@@ -53,7 +53,7 @@ func (b *BaseApi) GetNginxConfigByScope(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /openResty/update [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新 nginx 配置 [domain]","formatEN":"Update nginx conf [domain]"}
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"websiteId","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"更新 nginx 配置 [domain]","formatEN":"Update nginx conf [domain]"}
func (b *BaseApi) UpdateNginxConfigByScope(c *gin.Context) {
var req request.NginxConfigUpdate
if err := c.ShouldBindJSON(&req); err != nil {
+11 -23
View File
@@ -2,12 +2,14 @@ package v1
import (
"errors"
"time"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/mfa"
"github.com/1Panel-dev/1Panel/backend/utils/ntp"
"github.com/gin-gonic/gin"
)
@@ -186,41 +188,27 @@ func (b *BaseApi) HandlePasswordExpired(c *gin.Context) {
helper.SuccessWithData(c, nil)
}
// @Tags System Setting
// @Summary Load time zone options
// @Description 加载系统可用时区
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/time/option [get]
func (b *BaseApi) LoadTimeZone(c *gin.Context) {
zones, err := settingService.LoadTimeZone()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, zones)
}
// @Tags System Setting
// @Summary Sync system time
// @Description 系统时间同步
// @Accept json
// @Param request body dto.SyncTime true "request"
// @Success 200 {string} ntime
// @Security ApiKeyAuth
// @Router /settings/time/sync [post]
// @x-panel-log {"bodyKeys":["ntpSite"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"系统时间同步[ntpSite]","formatEN":"sync system time [ntpSite]"}
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"系统时间同步","formatEN":"sync system time"}
func (b *BaseApi) SyncTime(c *gin.Context) {
var req dto.SyncTime
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
ntime, err := ntp.GetRemoteTime()
if err != nil {
helper.SuccessWithData(c, time.Now().Format("2006-01-02 15:04:05 MST -0700"))
return
}
if err := settingService.SyncTime(req); err != nil {
ts := ntime.Format("2006-01-02 15:04:05")
if err := ntp.UpdateSystemDate(ts); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
helper.SuccessWithData(c, ntime.Format("2006-01-02 15:04:05 MST -0700"))
}
// @Tags System Setting
+4 -4
View File
@@ -68,7 +68,7 @@ func (b *BaseApi) ImportSnapshot(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/snapshot/description/update [post]
// @x-panel-log {"bodyKeys":["id","description"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"snapshots","output_column":"name","output_value":"name"}],"formatZH":"快照 [name] 描述信息修改 [description]","formatEN":"The description of the snapshot [name] is modified => [description]"}
// @x-panel-log {"bodyKeys":["id","description"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"snapshots","output_colume":"name","output_value":"name"}],"formatZH":"快照 [name] 描述信息修改 [description]","formatEN":"The description of the snapshot [name] is modified => [description]"}
func (b *BaseApi) UpdateSnapDescription(c *gin.Context) {
var req dto.UpdateDescription
if err := c.ShouldBindJSON(&req); err != nil {
@@ -119,7 +119,7 @@ func (b *BaseApi) SearchSnapshot(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/snapshot/recover [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"snapshots","output_column":"name","output_value":"name"}],"formatZH":"从系统快照 [name] 恢复","formatEN":"Recover from system backup [name]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"snapshots","output_colume":"name","output_value":"name"}],"formatZH":"从系统快照 [name] 恢复","formatEN":"Recover from system backup [name]"}
func (b *BaseApi) RecoverSnapshot(c *gin.Context) {
var req dto.SnapshotRecover
if err := c.ShouldBindJSON(&req); err != nil {
@@ -146,7 +146,7 @@ func (b *BaseApi) RecoverSnapshot(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/snapshot/rollback [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"snapshots","output_column":"name","output_value":"name"}],"formatZH":"从系统快照 [name] 回滚","formatEN":"Rollback from system backup [name]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"snapshots","output_colume":"name","output_value":"name"}],"formatZH":"从系统快照 [name] 回滚","formatEN":"Rollback from system backup [name]"}
func (b *BaseApi) RollbackSnapshot(c *gin.Context) {
var req dto.SnapshotRecover
if err := c.ShouldBindJSON(&req); err != nil {
@@ -173,7 +173,7 @@ func (b *BaseApi) RollbackSnapshot(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/snapshot/del [post]
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"ids","isList":true,"db":"snapshots","output_column":"name","output_value":"name"}],"formatZH":"删除系统快照 [name]","formatEN":"Delete system backup [name]"}
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"ids","isList":true,"db":"snapshots","output_colume":"name","output_value":"name"}],"formatZH":"删除系统快照 [name]","formatEN":"Delete system backup [name]"}
func (b *BaseApi) DeleteSnapshot(c *gin.Context) {
var req dto.BatchDeleteReq
if err := c.ShouldBindJSON(&req); err != nil {
-185
View File
@@ -1,185 +0,0 @@
package v1
import (
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/gin-gonic/gin"
)
// @Tags SSH
// @Summary Load host ssh setting info
// @Description 加载 SSH 配置信息
// @Success 200 {object} dto.SSHInfo
// @Security ApiKeyAuth
// @Router /host/ssh/search [post]
func (b *BaseApi) GetSSHInfo(c *gin.Context) {
info, err := sshService.GetSSHInfo()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, info)
}
// @Tags SSH
// @Summary Operate ssh
// @Description 修改 SSH 服务状态
// @Accept json
// @Param request body dto.Operate true "request"
// @Security ApiKeyAuth
// @Router /host/ssh/operate [post]
// @x-panel-log {"bodyKeys":["operation"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"[operation] SSH ","formatEN":"[operation] SSH"}
func (b *BaseApi) OperateSSH(c *gin.Context) {
var req dto.Operate
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
}
if err := sshService.OperateSSH(req.Operation); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags SSH
// @Summary Update host ssh setting
// @Description 更新 SSH 配置
// @Accept json
// @Param request body dto.SettingUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /host/ssh/update [post]
// @x-panel-log {"bodyKeys":["key","value"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改 SSH 配置 [key] => [value]","formatEN":"update SSH setting [key] => [value]"}
func (b *BaseApi) UpdateSSH(c *gin.Context) {
var req dto.SettingUpdate
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
}
if err := sshService.Update(req.Key, req.Value); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags SSH
// @Summary Update host ssh setting by file
// @Description 上传文件更新 SSH 配置
// @Accept json
// @Param request body dto.SSHConf true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /host/conffile/update [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改 SSH 配置文件","formatEN":"update SSH conf"}
func (b *BaseApi) UpdateSSHByfile(c *gin.Context) {
var req dto.SSHConf
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
}
if err := sshService.UpdateByFile(req.File); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags SSH
// @Summary Generate host ssh secret
// @Description 生成 ssh 密钥
// @Accept json
// @Param request body dto.GenerateSSH true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /host/ssh/generate [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"生成 SSH 密钥 ","formatEN":"generate SSH secret"}
func (b *BaseApi) GenerateSSH(c *gin.Context) {
var req dto.GenerateSSH
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
}
if err := sshService.GenerateSSH(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags SSH
// @Summary Load host ssh secret
// @Description 获取 ssh 密钥
// @Accept json
// @Param request body dto.GenerateLoad true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /host/ssh/secret [post]
func (b *BaseApi) LoadSSHSecret(c *gin.Context) {
var req dto.GenerateLoad
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
}
data, err := sshService.LoadSSHSecret(req.EncryptionMode)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}
// @Tags SSH
// @Summary Load host ssh logs
// @Description 获取 ssh 登录日志
// @Accept json
// @Param request body dto.SearchSSHLog true "request"
// @Success 200 {object} dto.SSHLog
// @Security ApiKeyAuth
// @Router /host/ssh/logs [post]
func (b *BaseApi) LoadSSHLogs(c *gin.Context) {
var req dto.SearchSSHLog
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
}
data, err := sshService.LoadLog(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}
+9 -38
View File
@@ -5,8 +5,8 @@ import (
"encoding/json"
"fmt"
"net/http"
"os/exec"
"strconv"
"strings"
"time"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
@@ -112,12 +112,11 @@ func (b *BaseApi) RedisWsSsh(c *gin.Context) {
if len(redisConf.Requirepass) != 0 {
commands = fmt.Sprintf("redis-cli -a %s --no-auth-warning", redisConf.Requirepass)
}
pidMap := loadMapFromDockerTop(redisConf.ContainerName)
slave, err := terminal.NewCommand(fmt.Sprintf("docker exec -it %s %s", redisConf.ContainerName, commands))
if wshandleError(wsConn, err) {
return
}
defer killBash(redisConf.ContainerName, commands, pidMap)
defer killBash(redisConf.ContainerName, commands)
defer slave.Close()
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave)
@@ -176,12 +175,11 @@ func (b *BaseApi) ContainerWsSsh(c *gin.Context) {
if len(user) != 0 {
commands = fmt.Sprintf("docker exec -it -u %s %s %s", user, containerID, command)
}
pidMap := loadMapFromDockerTop(containerID)
slave, err := terminal.NewCommand(commands)
if wshandleError(wsConn, err) {
return
}
defer killBash(containerID, command, pidMap)
defer killBash(containerID, command)
defer slave.Close()
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave)
@@ -221,40 +219,13 @@ func wshandleError(ws *websocket.Conn, err error) bool {
return false
}
func loadMapFromDockerTop(containerID string) map[string]string {
pidMap := make(map[string]string)
sudo := cmd.SudoHandleCmd()
stdout, err := cmd.Execf("%s docker top %s -eo pid,command ", sudo, containerID)
if err != nil {
return pidMap
}
lines := strings.Split(stdout, "\n")
for _, line := range lines {
parts := strings.Fields(line)
if len(parts) != 2 {
continue
}
pidMap[parts[0]] = parts[1]
}
return pidMap
}
func killBash(containerID, comm string, pidMap map[string]string) {
sudo := cmd.SudoHandleCmd()
newPidMap := loadMapFromDockerTop(containerID)
for pid, command := range newPidMap {
isOld := false
for pid2 := range pidMap {
if pid == pid2 {
isOld = true
break
}
}
if !isOld && command == comm {
_, _ = cmd.Execf("%s kill -9 %s", sudo, pid)
}
func killBash(containerID, comm string) {
sudo := ""
if cmd.HasNoPasswordSudo() {
sudo = "sudo"
}
command := exec.Command("sh", "-c", fmt.Sprintf("%s kill -9 $(docker top %s -eo pid,command | grep '%s' | awk '{print $1}')", sudo, containerID, comm))
_, _ = command.CombinedOutput()
}
var upGrader = websocket.Upgrader{
+16 -59
View File
@@ -95,7 +95,7 @@ func (b *BaseApi) CreateWebsite(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/operate [post]
// @x-panel-log {"bodyKeys":["id", "operate"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"[operate] 网站 [domain]","formatEN":"[operate] website [domain]"}
// @x-panel-log {"bodyKeys":["id", "operate"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"[operate] 网站 [domain]","formatEN":"[operate] website [domain]"}
func (b *BaseApi) OpWebsite(c *gin.Context) {
var req request.WebsiteOp
if err := c.ShouldBindJSON(&req); err != nil {
@@ -118,7 +118,7 @@ func (b *BaseApi) OpWebsite(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"删除网站 [domain]","formatEN":"Delete website [domain]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"删除网站 [domain]","formatEN":"Delete website [domain]"}
func (b *BaseApi) DeleteWebsite(c *gin.Context) {
var req request.WebsiteDelete
if err := c.ShouldBindJSON(&req); err != nil {
@@ -232,7 +232,7 @@ func (b *BaseApi) GetWebDomains(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/domains/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_domains","output_column":"domain","output_value":"domain"}],"formatZH":"删除域名 [domain]","formatEN":"Delete domain [domain]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"website_domains","output_colume":"domain","output_value":"domain"}],"formatZH":"删除域名 [domain]","formatEN":"Delete domain [domain]"}
func (b *BaseApi) DeleteWebDomain(c *gin.Context) {
var req request.WebsiteDomainDelete
if err := c.ShouldBindJSON(&req); err != nil {
@@ -300,7 +300,7 @@ func (b *BaseApi) GetNginxConfig(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/config/update [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"nginx 配置修改 [domain]","formatEN":"Nginx conf update [domain]"}
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"websiteId","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"nginx 配置修改 [domain]","formatEN":"Nginx conf update [domain]"}
func (b *BaseApi) UpdateNginxConfig(c *gin.Context) {
var req request.NginxConfigUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -344,7 +344,7 @@ func (b *BaseApi) GetHTTPSConfig(c *gin.Context) {
// @Success 200 {object} response.WebsiteHTTPS
// @Security ApiKeyAuth
// @Router /websites/:id/https [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] https 配置","formatEN":"Update website https [domain] conf"}
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"websiteId","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] https 配置","formatEN":"Update website https [domain] conf"}
func (b *BaseApi) UpdateHTTPSConfig(c *gin.Context) {
var req request.WebsiteHTTPSOp
if err := c.ShouldBindJSON(&req); err != nil {
@@ -414,7 +414,7 @@ func (b *BaseApi) GetWebsiteWafConfig(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/waf/update [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"WAF 配置修改 [domain]","formatEN":"WAF conf update [domain]"}
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"websiteId","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"WAF 配置修改 [domain]","formatEN":"WAF conf update [domain]"}
func (b *BaseApi) UpdateWebsiteWafConfig(c *gin.Context) {
var req request.WebsiteWafUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -436,7 +436,7 @@ func (b *BaseApi) UpdateWebsiteWafConfig(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/nginx/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"[domain] Nginx 配置修改","formatEN":"[domain] Nginx conf update"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"[domain] Nginx 配置修改","formatEN":"[domain] Nginx conf update"}
func (b *BaseApi) UpdateWebsiteNginxConfig(c *gin.Context) {
var req request.WebsiteNginxUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -458,7 +458,7 @@ func (b *BaseApi) UpdateWebsiteNginxConfig(c *gin.Context) {
// @Success 200 {object} response.WebsiteLog
// @Security ApiKeyAuth
// @Router /websites/log [post]
// @x-panel-log {"bodyKeys":["id", "operate"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"[domain][operate] 日志","formatEN":"[domain][operate] logs"}
// @x-panel-log {"bodyKeys":["id", "operate"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"[domain][operate] 日志","formatEN":"[domain][operate] logs"}
func (b *BaseApi) OpWebsiteLog(c *gin.Context) {
var req request.WebsiteLogReq
if err := c.ShouldBindJSON(&req); err != nil {
@@ -481,7 +481,7 @@ func (b *BaseApi) OpWebsiteLog(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/default/server [post]
// @x-panel-log {"bodyKeys":["id", "operate"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"修改默认 server => [domain]","formatEN":"Change default server => [domain]"}
// @x-panel-log {"bodyKeys":["id", "operate"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"修改默认 server => [domain]","formatEN":"Change default server => [domain]"}
func (b *BaseApi) ChangeDefaultServer(c *gin.Context) {
var req request.WebsiteDefaultUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -525,7 +525,7 @@ func (b *BaseApi) GetWebsitePHPConfig(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/php/config [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"[domain] PHP 配置修改","formatEN":"[domain] PHP conf update"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"[domain] PHP 配置修改","formatEN":"[domain] PHP conf update"}
func (b *BaseApi) UpdateWebsitePHPConfig(c *gin.Context) {
var req request.WebsitePHPConfigUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -547,7 +547,7 @@ func (b *BaseApi) UpdateWebsitePHPConfig(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/php/update [post]
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"php 配置修改 [domain]","formatEN":"Nginx conf update [domain]"}
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"websiteId","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"php 配置修改 [domain]","formatEN":"Nginx conf update [domain]"}
func (b *BaseApi) UpdatePHPFile(c *gin.Context) {
var req request.WebsitePHPFileUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -591,7 +591,7 @@ func (b *BaseApi) GetRewriteConfig(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/rewrite/update [post]
// @x-panel-log {"bodyKeys":["websiteID"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteID","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"伪静态配置修改 [domain]","formatEN":"Nginx conf rewrite update [domain]"}
// @x-panel-log {"bodyKeys":["websiteID"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"websiteID","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"伪静态配置修改 [domain]","formatEN":"Nginx conf rewrite update [domain]"}
func (b *BaseApi) UpdateRewriteConfig(c *gin.Context) {
var req request.NginxRewriteUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -613,7 +613,7 @@ func (b *BaseApi) UpdateRewriteConfig(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/dir/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] 目录","formatEN":"Update domain [domain] dir"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] 目录","formatEN":"Update domain [domain] dir"}
func (b *BaseApi) UpdateSiteDir(c *gin.Context) {
var req request.WebsiteUpdateDir
if err := c.ShouldBindJSON(&req); err != nil {
@@ -635,7 +635,7 @@ func (b *BaseApi) UpdateSiteDir(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/dir/permission [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] 目录权限","formatEN":"Update domain [domain] dir permission"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"更新网站 [domain] 目录权限","formatEN":"Update domain [domain] dir permission"}
func (b *BaseApi) UpdateSiteDirPermission(c *gin.Context) {
var req request.WebsiteUpdateDirPermission
if err := c.ShouldBindJSON(&req); err != nil {
@@ -679,7 +679,7 @@ func (b *BaseApi) GetProxyConfig(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/proxies/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"修改网站 [domain] 反向代理配置 ","formatEN":"Update domain [domain] proxy config"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"修改网站 [domain] 反向代理配置 ","formatEN":"Update domain [domain] proxy config"}
func (b *BaseApi) UpdateProxyConfig(c *gin.Context) {
var req request.WebsiteProxyConfig
if err := c.ShouldBindJSON(&req); err != nil {
@@ -702,7 +702,7 @@ func (b *BaseApi) UpdateProxyConfig(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/proxy/file [post]
// @x-panel-log {"bodyKeys":["websiteID"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteID","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新反向代理文件 [domain]","formatEN":"Nginx conf proxy file update [domain]"}
// @x-panel-log {"bodyKeys":["websiteID"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"websiteID","isList":false,"db":"websites","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"更新反向代理文件 [domain]","formatEN":"Nginx conf proxy file update [domain]"}
func (b *BaseApi) UpdateProxyConfigFile(c *gin.Context) {
var req request.NginxProxyUpdate
if err := c.ShouldBindJSON(&req); err != nil {
@@ -758,46 +758,3 @@ func (b *BaseApi) UpdateAuthConfig(c *gin.Context) {
}
helper.SuccessWithOutData(c)
}
// @Tags Website
// @Summary Get AntiLeech conf
// @Description 获取防盗链配置
// @Accept json
// @Param request body request.NginxCommonReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/leech [post]
func (b *BaseApi) GetAntiLeech(c *gin.Context) {
var req request.NginxCommonReq
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
res, err := websiteService.GetAntiLeech(req.WebsiteID)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, res)
}
// @Tags Website
// @Summary Update AntiLeech
// @Description 更新防盗链配置
// @Accept json
// @Param request body request.NginxAntiLeechUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/leech/update [post]
func (b *BaseApi) UpdateAntiLeech(c *gin.Context) {
var req request.NginxAntiLeechUpdate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := websiteService.UpdateAntiLeech(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}
+1 -1
View File
@@ -64,7 +64,7 @@ func (b *BaseApi) CreateWebsiteAcmeAccount(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/acme/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_acme_accounts","output_column":"email","output_value":"email"}],"formatZH":"删除网站 acme [email]","formatEN":"Delete website acme [email]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"website_acme_accounts","output_colume":"email","output_value":"email"}],"formatZH":"删除网站 acme [email]","formatEN":"Delete website acme [email]"}
func (b *BaseApi) DeleteWebsiteAcmeAccount(c *gin.Context) {
var req request.WebsiteResourceReq
if err := c.ShouldBindJSON(&req); err != nil {
+1 -1
View File
@@ -85,7 +85,7 @@ func (b *BaseApi) UpdateWebsiteDnsAccount(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/dns/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_dns_accounts","output_column":"name","output_value":"name"}],"formatZH":"删除网站 dns [name]","formatEN":"Delete website dns [name]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"website_dns_accounts","output_colume":"name","output_value":"name"}],"formatZH":"删除网站 dns [name]","formatEN":"Delete website dns [name]"}
func (b *BaseApi) DeleteWebsiteDnsAccount(c *gin.Context) {
var req request.WebsiteResourceReq
if err := c.ShouldBindJSON(&req); err != nil {
+3 -3
View File
@@ -75,7 +75,7 @@ func (b *BaseApi) CreateWebsiteSSL(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/ssl/renew [post]
// @x-panel-log {"bodyKeys":["SSLId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"SSLId","isList":false,"db":"website_ssls","output_column":"primary_domain","output_value":"domain"}],"formatZH":"重置 ssl [domain]","formatEN":"Renew ssl [domain]"}
// @x-panel-log {"bodyKeys":["SSLId"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"SSLId","isList":false,"db":"website_ssls","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"重置 ssl [domain]","formatEN":"Renew ssl [domain]"}
func (b *BaseApi) RenewWebsiteSSL(c *gin.Context) {
var req request.WebsiteSSLRenew
if err := c.ShouldBindJSON(&req); err != nil {
@@ -119,7 +119,7 @@ func (b *BaseApi) GetDNSResolve(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/ssl/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_ssls","output_column":"primary_domain","output_value":"domain"}],"formatZH":"删除 ssl [domain]","formatEN":"Delete ssl [domain]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"website_ssls","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"删除 ssl [domain]","formatEN":"Delete ssl [domain]"}
func (b *BaseApi) DeleteWebsiteSSL(c *gin.Context) {
var req request.WebsiteResourceReq
if err := c.ShouldBindJSON(&req); err != nil {
@@ -185,7 +185,7 @@ func (b *BaseApi) GetWebsiteSSLById(c *gin.Context) {
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/ssl/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_ssls","output_column":"primary_domain","output_value":"domain"}],"formatZH":"更新证书设置 [domain]","formatEN":"Update ssl config [domain]"}
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"website_ssls","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"更新证书设置 [domain]","formatEN":"Update ssl config [domain]"}
func (b *BaseApi) UpdateWebsiteSSL(c *gin.Context) {
var req request.WebsiteSSLUpdate
if err := c.ShouldBindJSON(&req); err != nil {
+10 -42
View File
@@ -1,7 +1,7 @@
package dto
import (
"github.com/1Panel-dev/1Panel/backend/app/model"
"encoding/json"
)
type AppDatabase struct {
@@ -32,47 +32,19 @@ type AppVersion struct {
}
type AppList struct {
Valid bool `json:"valid"`
Violations []string `json:"violations"`
LastModified int `json:"lastModified"`
Apps []AppDefine `json:"apps"`
Extra ExtraProperties `json:"additionalProperties"`
Version string `json:"version"`
Tags []Tag `json:"tags"`
Items []AppDefine `json:"items"`
}
type AppDefine struct {
Icon string `json:"icon"`
Name string `json:"name"`
ReadMe string `json:"readMe"`
LastModified int `json:"lastModified"`
AppProperty AppProperty `json:"additionalProperties"`
Versions []AppConfigVersion `json:"versions"`
}
type LocalAppAppDefine struct {
AppProperty model.App `json:"additionalProperties" yaml:"additionalProperties"`
}
type LocalAppParam struct {
AppParams LocalAppInstallDefine `json:"additionalProperties" yaml:"additionalProperties"`
}
type LocalAppInstallDefine struct {
FormFields interface{} `json:"formFields" yaml:"formFields"`
}
type ExtraProperties struct {
Tags []Tag `json:"tags"`
}
type AppProperty struct {
Key string `json:"key"`
Name string `json:"name"`
Type string `json:"type"`
Tags []string `json:"tags"`
Versions []string `json:"versions"`
ShortDescZh string `json:"shortDescZh"`
ShortDescEn string `json:"shortDescEn"`
Key string `json:"key"`
Type string `json:"type"`
Required []string `json:"Required"`
CrossVersionUpdate bool `json:"crossVersionUpdate"`
Limit int `json:"limit"`
@@ -82,12 +54,9 @@ type AppProperty struct {
Document string `json:"document"`
}
type AppConfigVersion struct {
Name string `json:"name"`
LastModified int `json:"lastModified"`
DownloadUrl string `json:"downloadUrl"`
DownloadCallBackUrl string `json:"downloadCallBackUrl"`
AppForm interface{} `json:"additionalProperties"`
func (define AppDefine) GetRequired() string {
by, _ := json.Marshal(define.Required)
return string(by)
}
type Tag struct {
@@ -110,7 +79,6 @@ type AppFormFields struct {
Edit bool `json:"edit"`
Rule string `json:"rule"`
Multiple bool `json:"multiple"`
Child interface{} `json:"child"`
Values []AppFormValue `json:"values"`
}
-4
View File
@@ -23,10 +23,6 @@ type OperateByID struct {
ID uint `json:"id" validate:"required"`
}
type Operate struct {
Operation string `json:"operation" validate:"required"`
}
type BatchDeleteReq struct {
Ids []uint `json:"ids" validate:"required"`
}
+2 -12
View File
@@ -80,16 +80,6 @@ type ContainerOperation struct {
NewName string `json:"newName"`
}
type ContainerPrune struct {
PruneType string `json:"pruneType" validate:"required,oneof=container image volume network"`
WithTagAll bool `josn:"withTagAll"`
}
type ContainerPruneReport struct {
DeletedNumber int `json:"deletedNumber"`
SpaceReclaimed int `json:"spaceReclaimed"`
}
type Network struct {
ID string `json:"id"`
Name string `json:"name"`
@@ -101,7 +91,7 @@ type Network struct {
CreatedAt time.Time `json:"createdAt"`
Attachable bool `json:"attachable"`
}
type NetworkCreate struct {
type NetworkCreat struct {
Name string `json:"name"`
Driver string `json:"driver"`
Options []string `json:"options"`
@@ -118,7 +108,7 @@ type Volume struct {
Mountpoint string `json:"mountpoint"`
CreatedAt time.Time `json:"createdAt"`
}
type VolumeCreate struct {
type VolumeCreat struct {
Name string `json:"name"`
Driver string `json:"driver"`
Options []string `json:"options"`
+3 -6
View File
@@ -6,11 +6,10 @@ type CronjobCreate struct {
Name string `json:"name" validate:"required"`
Type string `json:"type" validate:"required"`
SpecType string `json:"specType" validate:"required"`
Week int `json:"week" validate:"number,max=6,min=0"`
Week int `json:"week" validate:"number,max=7,min=1"`
Day int `json:"day" validate:"number"`
Hour int `json:"hour" validate:"number"`
Minute int `json:"minute" validate:"number"`
Second int `json:"second" validate:"number"`
Script string `json:"script"`
Website string `json:"website"`
@@ -27,11 +26,10 @@ type CronjobUpdate struct {
ID uint `json:"id" validate:"required"`
Name string `json:"name" validate:"required"`
SpecType string `json:"specType" validate:"required"`
Week int `json:"week" validate:"number,max=6,min=0"`
Week int `json:"week" validate:"number,max=7,min=1"`
Day int `json:"day" validate:"number"`
Hour int `json:"hour" validate:"number"`
Minute int `json:"minute" validate:"number"`
Second int `json:"second" validate:"number"`
Script string `json:"script"`
Website string `json:"website"`
@@ -73,7 +71,6 @@ type CronjobInfo struct {
Day int `json:"day"`
Hour int `json:"hour"`
Minute int `json:"minute"`
Second int `json:"second"`
Script string `json:"script"`
Website string `json:"website"`
@@ -86,7 +83,7 @@ type CronjobInfo struct {
TargetDirID int `json:"targetDirID"`
RetainCopies int `json:"retainCopies"`
LastRecordTime string `json:"lastRecordTime"`
LastRecrodTime string `json:"lastRecrodTime"`
Status string `json:"status"`
}
+3 -9
View File
@@ -13,16 +13,10 @@ type DaemonJsonConf struct {
LiveRestore bool `json:"liveRestore"`
IPTables bool `json:"iptables"`
CgroupDriver string `json:"cgroupDriver"`
LogMaxSize string `json:"logMaxSize"`
LogMaxFile string `json:"logMaxFile"`
}
type LogOption struct {
LogMaxSize string `json:"logMaxSize"`
LogMaxFile string `json:"logMaxFile"`
}
type DockerOperation struct {
Operation string `json:"operation" validate:"required,oneof=start restart stop"`
StopSocket bool `json:"stopSocket"`
StopService bool `json:"stopService"`
Operation string `json:"operation" validate:"required,oneof=start restart stop"`
}
-13
View File
@@ -18,18 +18,6 @@ type AppInstallCreate struct {
Params map[string]interface{} `json:"params"`
Name string `json:"name" validate:"required"`
Services map[string]string `json:"services"`
AppContainerConfig
}
type AppContainerConfig struct {
Advanced bool `json:"advanced"`
CpuQuota float64 `json:"cpuQuota"`
MemoryLimit float64 `json:"memoryLimit"`
MemoryUnit string `json:"memoryUnit"`
ContainerName string `json:"containerName"`
AllowPort bool `json:"allowPort"`
EditCompose bool `json:"editCompose"`
DockerCompose string `json:"dockerCompose"`
}
type AppInstalledSearch struct {
@@ -63,7 +51,6 @@ type AppInstalledOperate struct {
type AppInstalledUpdate struct {
InstallId uint `json:"installId" validate:"required"`
Params map[string]interface{} `json:"params" validate:"required"`
AppContainerConfig
}
type PortUpdate struct {
-5
View File
@@ -82,11 +82,6 @@ type FileDownload struct {
Compress bool `json:"compress" validate:"required"`
}
type FileChunkDownload struct {
Path string `json:"path" validate:"required"`
Name string `json:"name" validate:"required"`
}
type DirSizeReq struct {
Path string `json:"path" validate:"required"`
}
-18
View File
@@ -48,21 +48,3 @@ type NginxAuthUpdate struct {
type NginxAuthReq struct {
WebsiteID uint `json:"websiteID" validate:"required"`
}
type NginxCommonReq struct {
WebsiteID uint `json:"websiteID" validate:"required"`
}
type NginxAntiLeechUpdate struct {
WebsiteID uint `json:"websiteID" validate:"required"`
Extends string `json:"extends" validate:"required"`
Return string `json:"return" validate:"required"`
Enable bool `json:"enable" validate:"required"`
ServerNames []string `json:"serverNames"`
Cache bool `json:"cache"`
CacheTime int `json:"cacheTime"`
CacheUint string `json:"cacheUint"`
NoneRef bool `json:"noneRef"`
LogEnable bool `json:"logEnable"`
Blocked bool `json:"blocked"`
}
+2 -9
View File
@@ -18,7 +18,6 @@ type WebsiteCreate struct {
OtherDomains string `json:"otherDomains"`
Proxy string `json:"proxy"`
WebsiteGroupID uint `json:"webSiteGroupID" validate:"required"`
IPV6 bool `json:"IPV6"`
AppType string `json:"appType" validate:"oneof=new installed"`
AppInstall NewAppInstall `json:"appInstall"`
@@ -38,8 +37,6 @@ type NewAppInstall struct {
Name string `json:"name"`
AppDetailId uint `json:"appDetailID"`
Params map[string]interface{} `json:"params"`
AppContainerConfig
}
type WebsiteInstallCheckReq struct {
@@ -52,7 +49,6 @@ type WebsiteUpdate struct {
Remark string `json:"remark"`
WebsiteGroupID uint `json:"webSiteGroupID" validate:"required"`
ExpireDate string `json:"expireDate"`
IPV6 bool `json:"IPV6"`
}
type WebsiteDelete struct {
@@ -140,11 +136,8 @@ type WebsiteDefaultUpdate struct {
}
type WebsitePHPConfigUpdate struct {
ID uint `json:"id" validate:"required"`
Params map[string]string `json:"params"`
Scope string `json:"scope" validate:"required"`
DisableFunctions []string `json:"disableFunctions"`
UploadMaxSize string `json:"uploadMaxSize"`
ID uint `json:"id" validate:"required"`
Params map[string]string `json:"params" validate:"required"`
}
type WebsitePHPFileUpdate struct {
+5 -12
View File
@@ -1,7 +1,6 @@
package response
import (
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"time"
"github.com/1Panel-dev/1Panel/backend/app/model"
@@ -13,15 +12,15 @@ type AppRes struct {
}
type AppUpdateRes struct {
CanUpdate bool `json:"canUpdate"`
AppStoreLastModified int `json:"appStoreLastModified"`
Version string `json:"version"`
CanUpdate bool `json:"canUpdate"`
DownloadPath string `json:"downloadPath"`
}
type AppDTO struct {
model.App
Installed bool `json:"installed"`
Versions []string `json:"versions"`
Tags []model.Tag `json:"tags"`
Versions []string `json:"versions"`
Tags []model.Tag `json:"tags"`
}
type TagDTO struct {
@@ -55,7 +54,6 @@ type AppInstalledDTO struct {
AppName string `json:"appName"`
Icon string `json:"icon"`
CanUpdate bool `json:"canUpdate"`
Path string `json:"path"`
}
type DatabaseConn struct {
@@ -83,8 +81,3 @@ type AppParam struct {
Required bool `json:"required"`
Multiple bool `json:"multiple"`
}
type AppConfig struct {
Params []AppParam `json:"params"`
request.AppContainerConfig
}
-13
View File
@@ -21,16 +21,3 @@ type NginxAuthRes struct {
Enable bool `json:"enable"`
Items []dto.NginxAuth `json:"items"`
}
type NginxAntiLeechRes struct {
Enable bool `json:"enable"`
Extends string `json:"extends"`
Return string `json:"return"`
ServerNames []string `json:"serverNames"`
Cache bool `json:"cache"`
CacheTime int `json:"cacheTime"`
CacheUint string `json:"cacheUint"`
NoneRef bool `json:"noneRef"`
LogEnable bool `json:"logEnable"`
Blocked bool `json:"blocked"`
}
+1 -3
View File
@@ -45,9 +45,7 @@ type WebsiteLog struct {
}
type PHPConfig struct {
Params map[string]string `json:"params"`
DisableFunctions []string `json:"disableFunctions"`
UploadMaxSize string `json:"uploadMaxSize"`
Params map[string]string `json:"params"`
}
type NginxRewriteRes struct {
+1 -11
View File
@@ -9,8 +9,6 @@ type SettingInfo struct {
SessionTimeout string `json:"sessionTimeout"`
LocalTime string `json:"localTime"`
TimeZone string `json:"timeZone"`
NtpSite string `json:"ntpSite"`
Port string `json:"port"`
PanelName string `json:"panelName"`
@@ -20,8 +18,6 @@ type SettingInfo struct {
ServerPort string `json:"serverPort"`
SSL string `json:"ssl"`
SSLType string `json:"sslType"`
BindDomain string `json:"bindDomain"`
AllowIPs string `json:"allowIPs"`
SecurityEntrance string `json:"securityEntrance"`
ExpirationDays string `json:"expirationDays"`
ExpirationTime string `json:"expirationTime"`
@@ -30,7 +26,6 @@ type SettingInfo struct {
MFASecret string `json:"mfaSecret"`
MonitorStatus string `json:"monitorStatus"`
MonitorInterval string `json:"monitorInterval"`
MonitorStoreDays string `json:"monitorStoreDays"`
MessageType string `json:"messageType"`
@@ -38,8 +33,7 @@ type SettingInfo struct {
WeChatVars string `json:"weChatVars"`
DingVars string `json:"dingVars"`
AppStoreVersion string `json:"appStoreVersion"`
AppStoreLastModified string `json:"appStoreLastModified"`
AppStoreVersion string `json:"appStoreVersion"`
}
type SettingUpdate struct {
@@ -112,10 +106,6 @@ type UpgradeInfo struct {
ReleaseNote string `json:"releaseNote"`
}
type SyncTime struct {
NtpSite string `json:"ntpSite"`
}
type Upgrade struct {
Version string `json:"version"`
}
-49
View File
@@ -1,49 +0,0 @@
package dto
import "time"
type SSHInfo struct {
Status string `json:"status"`
Message string `json:"message"`
Port string `json:"port"`
ListenAddress string `json:"listenAddress"`
PasswordAuthentication string `json:"passwordAuthentication"`
PubkeyAuthentication string `json:"pubkeyAuthentication"`
PermitRootLogin string `json:"permitRootLogin"`
UseDNS string `json:"useDNS"`
}
type GenerateSSH struct {
EncryptionMode string `json:"encryptionMode" validate:"required,oneof=rsa ed25519 ecdsa dsa"`
Password string `json:"password"`
}
type GenerateLoad struct {
EncryptionMode string `json:"encryptionMode" validate:"required,oneof=rsa ed25519 ecdsa dsa"`
}
type SSHConf struct {
File string `json:"file"`
}
type SearchSSHLog struct {
PageInfo
Info string `json:"info"`
Status string `json:"Status" validate:"required,oneof=Success Failed All"`
}
type SSHLog struct {
Logs []SSHHistory `json:"logs"`
TotalCount int `json:"totalCount"`
SuccessfulCount int `json:"successfulCount"`
FailedCount int `json:"failedCount"`
}
type SSHHistory struct {
Date time.Time `json:"date"`
DateStr string `json:"dateStr"`
Area string `json:"area"`
User string `json:"user"`
AuthMode string `json:"authMode"`
Address string `json:"address"`
Port string `json:"port"`
Status string `json:"status"`
Message string `json:"message"`
}
+18 -21
View File
@@ -2,25 +2,22 @@ package model
type App struct {
BaseModel
Name string `json:"name" gorm:"type:varchar(64);not null"`
Key string `json:"key" gorm:"type:varchar(64);not null;"`
ShortDescZh string `json:"shortDescZh" yaml:"shortDescZh" gorm:"type:longtext;"`
ShortDescEn string `json:"shortDescEn" yaml:"shortDescEn" gorm:"type:longtext;"`
Icon string `json:"icon" gorm:"type:longtext;"`
Type string `json:"type" gorm:"type:varchar(64);not null"`
Status string `json:"status" gorm:"type:varchar(64);not null"`
Required string `json:"required" gorm:"type:varchar(64);"`
CrossVersionUpdate bool `json:"crossVersionUpdate"`
Limit int `json:"limit" gorm:"type:Integer;not null"`
Website string `json:"website" gorm:"type:varchar(64);not null"`
Github string `json:"github" gorm:"type:varchar(64);not null"`
Document string `json:"document" gorm:"type:varchar(64);not null"`
Recommend int `json:"recommend" gorm:"type:Integer;not null"`
Resource string `json:"resource" gorm:"type:varchar;not null;default:remote"`
ReadMe string `json:"readMe" gorm:"type:varchar;"`
LastModified int `json:"lastModified" gorm:"type:Integer;"`
Details []AppDetail `json:"-" gorm:"-:migration"`
TagsKey []string `json:"tags" yaml:"tags" gorm:"-"`
AppTags []AppTag `json:"-" gorm:"-:migration"`
Name string `json:"name" gorm:"type:varchar(64);not null"`
Key string `json:"key" gorm:"type:varchar(64);not null;uniqueIndex"`
ShortDescZh string `json:"shortDescZh" gorm:"type:longtext;"`
ShortDescEn string `json:"shortDescEn" gorm:"type:longtext;"`
Icon string `json:"icon" gorm:"type:longtext;"`
Type string `json:"type" gorm:"type:varchar(64);not null"`
Status string `json:"status" gorm:"type:varchar(64);not null"`
Required string `json:"required" gorm:"type:varchar(64);not null"`
CrossVersionUpdate bool `json:"crossVersionUpdate"`
Limit int `json:"limit" gorm:"type:Integer;not null"`
Website string `json:"website" gorm:"type:varchar(64);not null"`
Github string `json:"github" gorm:"type:varchar(64);not null"`
Document string `json:"document" gorm:"type:varchar(64);not null"`
Recommend int `json:"recommend" gorm:"type:Integer;not null"`
Resource string `json:"resource" gorm:"type:varchar;not null;default:remote"`
Details []AppDetail `json:"-" gorm:"-:migration"`
TagsKey []string `json:"-" gorm:"-"`
AppTags []AppTag `json:"-" gorm:"-:migration"`
}
+7 -10
View File
@@ -2,14 +2,11 @@ package model
type AppDetail struct {
BaseModel
AppId uint `json:"appId" gorm:"type:integer;not null"`
Version string `json:"version" gorm:"type:varchar(64);not null"`
Params string `json:"-" gorm:"type:longtext;"`
DockerCompose string `json:"dockerCompose" gorm:"type:longtext;"`
Status string `json:"status" gorm:"type:varchar(64);not null"`
LastVersion string `json:"lastVersion" gorm:"type:varchar(64);"`
LastModified int `json:"lastModified" gorm:"type:integer;"`
DownloadUrl string `json:"downloadUrl" gorm:"type:varchar;"`
DownloadCallBackUrl string `json:"downloadCallBackUrl" gorm:"type:longtext;"`
Update bool `json:"update"`
AppId uint `json:"appId" gorm:"type:integer;not null"`
Version string `json:"version" gorm:"type:varchar(64);not null"`
Params string `json:"-" gorm:"type:longtext;"`
DockerCompose string `json:"-" gorm:"type:longtext;not null"`
Readme string `json:"readme" gorm:"type:longtext;"`
Status string `json:"status" gorm:"type:varchar(64);not null"`
LastVersion string `json:"lastVersion" gorm:"type:varchar(64);"`
}
-1
View File
@@ -13,7 +13,6 @@ type Cronjob struct {
Day uint64 `gorm:"type:decimal" json:"day"`
Hour uint64 `gorm:"type:decimal" json:"hour"`
Minute uint64 `gorm:"type:decimal" json:"minute"`
Second uint64 `gorm:"type:decimal" json:"second"`
Script string `gorm:"longtext" json:"script"`
Website string `gorm:"type:varchar(64)" json:"website"`
-1
View File
@@ -19,7 +19,6 @@ type Website struct {
ErrorLog bool `json:"errorLog"`
AccessLog bool `json:"accessLog"`
DefaultServer bool `json:"defaultServer"`
IPV6 bool `json:"IPV6"`
Rewrite string `gorm:"type:varchar" json:"rewrite"`
WebsiteGroupID uint `gorm:"type:integer" json:"webSiteGroupId"`
-5
View File
@@ -24,7 +24,6 @@ type IAppRepo interface {
GetByKey(ctx context.Context, key string) (model.App, error)
Create(ctx context.Context, app *model.App) error
Save(ctx context.Context, app *model.App) error
BatchDelete(ctx context.Context, apps []model.App) error
}
func NewIAppRepo() IAppRepo {
@@ -107,7 +106,3 @@ func (a AppRepo) Create(ctx context.Context, app *model.App) error {
func (a AppRepo) Save(ctx context.Context, app *model.App) error {
return getTx(ctx).Omit(clause.Associations).Save(app).Error
}
func (a AppRepo) BatchDelete(ctx context.Context, apps []model.App) error {
return getTx(ctx).Omit(clause.Associations).Delete(&apps).Error
}
-6
View File
@@ -4,7 +4,6 @@ import (
"context"
"github.com/1Panel-dev/1Panel/backend/app/model"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
type AppDetailRepo struct {
@@ -19,7 +18,6 @@ type IAppDetailRepo interface {
DeleteByAppIds(ctx context.Context, appIds []uint) error
GetBy(opts ...DBOption) ([]model.AppDetail, error)
BatchUpdateBy(maps map[string]interface{}, opts ...DBOption) error
BatchDelete(ctx context.Context, appDetails []model.AppDetail) error
}
func NewIAppDetailRepo() IAppDetailRepo {
@@ -68,7 +66,3 @@ func (a AppDetailRepo) BatchUpdateBy(maps map[string]interface{}, opts ...DBOpti
}
return db.Updates(&maps).Error
}
func (a AppDetailRepo) BatchDelete(ctx context.Context, appDetails []model.AppDetail) error {
return getTx(ctx).Omit(clause.Associations).Delete(&appDetails).Error
}
-14
View File
@@ -19,10 +19,8 @@ type IAppInstallRepo interface {
WithAppIdsIn(appIds []uint) DBOption
WithStatus(status string) DBOption
WithServiceName(serviceName string) DBOption
WithContainerName(containerName string) DBOption
WithPort(port int) DBOption
WithIdNotInWebsite() DBOption
WithIDNotIs(id uint) DBOption
ListBy(opts ...DBOption) ([]model.AppInstall, error)
GetFirst(opts ...DBOption) (model.AppInstall, error)
Create(ctx context.Context, install *model.AppInstall) error
@@ -57,12 +55,6 @@ func (a *AppInstallRepo) WithAppId(appId uint) DBOption {
}
}
func (a *AppInstallRepo) WithIDNotIs(id uint) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("id != ?", id)
}
}
func (a *AppInstallRepo) WithAppIdsIn(appIds []uint) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("app_id in (?)", appIds)
@@ -81,12 +73,6 @@ func (a *AppInstallRepo) WithServiceName(serviceName string) DBOption {
}
}
func (a *AppInstallRepo) WithContainerName(containerName string) DBOption {
return func(db *gorm.DB) *gorm.DB {
return db.Where("container_name = ?", containerName)
}
}
func (a *AppInstallRepo) WithPort(port int) DBOption {
return func(db *gorm.DB) *gorm.DB {
return db.Where("https_port = ? or http_port = ?", port, port)
-9
View File
@@ -19,7 +19,6 @@ type IAppInstallResourceRpo interface {
GetFirst(opts ...DBOption) (model.AppInstallResource, error)
Create(ctx context.Context, resource *model.AppInstallResource) error
DeleteBy(ctx context.Context, opts ...DBOption) error
BatchUpdateBy(maps map[string]interface{}, opts ...DBOption) error
}
func NewIAppInstallResourceRpo() IAppInstallResourceRpo {
@@ -72,11 +71,3 @@ func (a AppInstallResourceRpo) Create(ctx context.Context, resource *model.AppIn
func (a AppInstallResourceRpo) DeleteBy(ctx context.Context, opts ...DBOption) error {
return getTx(ctx, opts...).Delete(&model.AppInstallResource{}).Error
}
func (a *AppInstallResourceRpo) BatchUpdateBy(maps map[string]interface{}, opts ...DBOption) error {
db := getDb(opts...).Model(&model.AppInstallResource{})
if len(opts) == 0 {
db = db.Where("1=1")
}
return db.Updates(&maps).Error
}
-7
View File
@@ -14,7 +14,6 @@ type IRuntimeRepo interface {
WithImage(image string) DBOption
WithNotId(id uint) DBOption
WithStatus(status string) DBOption
WithDetailId(id uint) DBOption
Page(page, size int, opts ...DBOption) (int64, []model.Runtime, error)
Create(ctx context.Context, runtime *model.Runtime) error
Save(runtime *model.Runtime) error
@@ -44,12 +43,6 @@ func (r *RuntimeRepo) WithImage(image string) DBOption {
}
}
func (r *RuntimeRepo) WithDetailId(id uint) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("app_detail_id = ?", id)
}
}
func (r *RuntimeRepo) WithNotId(id uint) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("id != ?", id)
-28
View File
@@ -1,8 +1,6 @@
package repo
import (
"time"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/global"
"gorm.io/gorm"
@@ -16,13 +14,6 @@ type ISettingRepo interface {
Create(key, value string) error
Update(key, value string) error
WithByKey(key string) DBOption
CreateMonitorBase(model model.MonitorBase) error
BatchCreateMonitorIO(ioList []model.MonitorIO) error
BatchCreateMonitorNet(ioList []model.MonitorNetwork) error
DelMonitorBase(timeForDelete time.Time) error
DelMonitorIO(timeForDelete time.Time) error
DelMonitorNet(timeForDelete time.Time) error
}
func NewISettingRepo() ISettingRepo {
@@ -66,22 +57,3 @@ func (c *SettingRepo) WithByKey(key string) DBOption {
func (u *SettingRepo) Update(key, value string) error {
return global.DB.Model(&model.Setting{}).Where("key = ?", key).Updates(map[string]interface{}{"value": value}).Error
}
func (u *SettingRepo) CreateMonitorBase(model model.MonitorBase) error {
return global.DB.Create(&model).Error
}
func (u *SettingRepo) BatchCreateMonitorIO(ioList []model.MonitorIO) error {
return global.DB.CreateInBatches(ioList, len(ioList)).Error
}
func (u *SettingRepo) BatchCreateMonitorNet(ioList []model.MonitorNetwork) error {
return global.DB.CreateInBatches(ioList, len(ioList)).Error
}
func (u *SettingRepo) DelMonitorBase(timeForDelete time.Time) error {
return global.DB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorBase{}).Error
}
func (u *SettingRepo) DelMonitorIO(timeForDelete time.Time) error {
return global.DB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorIO{}).Error
}
func (u *SettingRepo) DelMonitorNet(timeForDelete time.Time) error {
return global.DB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorNetwork{}).Error
}
+252 -421
View File
@@ -5,25 +5,25 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"path"
"strings"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/utils/docker"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/app/repo"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/i18n"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/docker"
"github.com/1Panel-dev/1Panel/backend/utils/files"
http2 "github.com/1Panel-dev/1Panel/backend/utils/http"
"gopkg.in/yaml.v3"
"io"
"net/http"
"os"
"path"
"strconv"
)
type AppService struct {
@@ -100,8 +100,6 @@ func (a AppService) PageApp(req request.AppSearch) (interface{}, error) {
continue
}
appDTO.Tags = tags
installs, _ := appInstallRepo.ListBy(appInstallRepo.WithAppId(a.ID))
appDTO.Installed = len(installs) > 0
}
res.Items = appDTOs
res.Total = total
@@ -162,13 +160,7 @@ func (a AppService) GetAppDetail(appId uint, version, appType string) (response.
return appDetailDTO, err
}
fileOp := files.NewFileOp()
versionPath := path.Join(constant.AppResourceDir, app.Resource, app.Key, detail.Version)
if !fileOp.Stat(versionPath) {
if err = downloadApp(app, detail, nil); err != nil {
return appDetailDTO, err
}
}
buildPath := path.Join(versionPath, "build")
buildPath := path.Join(constant.AppResourceDir, app.Key, "versions", detail.Version, "build")
paramsPath := path.Join(buildPath, "config.json")
if !fileOp.Stat(paramsPath) {
return appDetailDTO, buserr.New(constant.ErrFileNotExist)
@@ -261,7 +253,7 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
}
app, err = appRepo.GetFirst(commonRepo.WithByID(appDetail.AppId))
if err != nil {
return
return nil, err
}
if err = checkRequiredAndLimit(app); err != nil {
return
@@ -278,55 +270,35 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
App: app,
}
composeMap := make(map[string]interface{})
if req.EditCompose {
if err = yaml.Unmarshal([]byte(req.DockerCompose), &composeMap); err != nil {
return
}
} else {
if err = yaml.Unmarshal([]byte(appDetail.DockerCompose), &composeMap); err != nil {
return
}
if err = yaml.Unmarshal([]byte(appDetail.DockerCompose), &composeMap); err != nil {
return
}
value, ok := composeMap["services"]
if !ok {
err = buserr.New(constant.ErrFileParse)
err = buserr.New("")
return
}
servicesMap := value.(map[string]interface{})
containerName := constant.ContainerPrefix + app.Key + "-" + common.RandStr(4)
if req.Advanced && req.ContainerName != "" {
containerName = req.ContainerName
appInstalls, _ := appInstallRepo.ListBy(appInstallRepo.WithContainerName(containerName))
if len(appInstalls) > 0 {
err = buserr.New(constant.ErrContainerName)
return
}
containerExist := false
containerExist, err = checkContainerNameIsExist(req.ContainerName, appInstall.GetPath())
if err != nil {
return
}
if containerExist {
err = buserr.New(constant.ErrContainerName)
return
}
}
req.Params[constant.ContainerName] = containerName
appInstall.ContainerName = containerName
changeKeys := make(map[string]string, len(servicesMap))
index := 0
for k := range servicesMap {
appInstall.ServiceName = k
serviceName := k + "-" + common.RandStr(4)
changeKeys[k] = serviceName
containerName := constant.ContainerPrefix + k + "-" + common.RandStr(4)
if index > 0 {
continue
}
req.Params["CONTAINER_NAME"] = containerName
appInstall.ServiceName = serviceName
appInstall.ContainerName = containerName
index++
}
if err = addDockerComposeCommonParam(composeMap, appInstall.ServiceName, req.AppContainerConfig, req.Params); err != nil {
return
for k, v := range changeKeys {
servicesMap[v] = servicesMap[k]
delete(servicesMap, k)
}
var (
composeByte []byte
paramByte []byte
@@ -346,258 +318,34 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
}
}
}()
if err = copyAppData(app.Key, appDetail.Version, req.Name, req.Params, app.Resource == constant.AppResourceLocal); err != nil {
return
}
fileOp := files.NewFileOp()
if err = fileOp.WriteFile(appInstall.GetComposePath(), strings.NewReader(string(composeByte)), 0775); err != nil {
return
}
paramByte, err = json.Marshal(req.Params)
if err != nil {
return
}
appInstall.Env = string(paramByte)
if err = appInstallRepo.Create(ctx, appInstall); err != nil {
return
}
if err = createLink(ctx, app, appInstall, req.Params); err != nil {
return
}
go func() {
if err = copyData(app, appDetail, appInstall, req); err != nil {
if appInstall.Status == constant.Installing {
appInstall.Status = constant.Error
appInstall.Message = err.Error()
}
_ = appInstallRepo.Save(context.Background(), appInstall)
return
}
if err = upAppPre(app, appInstall); err != nil {
return
}
upApp(appInstall)
}()
if err = upAppPre(app, appInstall); err != nil {
return
}
go upApp(appInstall)
go updateToolApp(appInstall)
return
}
func (a AppService) SyncAppListFromLocal() {
fileOp := files.NewFileOp()
localAppDir := constant.LocalAppResourceDir
if !fileOp.Stat(localAppDir) {
return
}
var (
err error
dirEntries []os.DirEntry
localApps []model.App
)
defer func() {
if err != nil {
global.LOG.Errorf("sync app failed %v", err)
}
}()
global.LOG.Infof("start sync local apps...")
dirEntries, err = os.ReadDir(localAppDir)
if err != nil {
return
}
for _, dirEntry := range dirEntries {
if dirEntry.IsDir() {
appDir := path.Join(localAppDir, dirEntry.Name())
appDirEntries, err := os.ReadDir(appDir)
if err != nil {
global.LOG.Errorf(i18n.GetMsgWithMap("ErrAppDirNull", map[string]interface{}{"name": dirEntry.Name(), "err": err.Error()}))
continue
}
app, err := handleLocalApp(appDir)
if err != nil {
global.LOG.Errorf(i18n.GetMsgWithMap("LocalAppErr", map[string]interface{}{"name": dirEntry.Name(), "err": err.Error()}))
continue
}
var appDetails []model.AppDetail
for _, appDirEntry := range appDirEntries {
if appDirEntry.IsDir() {
appDetail := model.AppDetail{
Version: appDirEntry.Name(),
Status: constant.AppNormal,
}
versionDir := path.Join(appDir, appDirEntry.Name())
if err = handleLocalAppDetail(versionDir, &appDetail); err != nil {
global.LOG.Errorf(i18n.GetMsgWithMap("LocalAppVersionErr", map[string]interface{}{"name": app.Name, "version": appDetail.Version, "err": err.Error()}))
continue
}
appDetails = append(appDetails, appDetail)
}
}
if len(appDetails) > 0 {
app.Details = appDetails
localApps = append(localApps, *app)
} else {
global.LOG.Errorf(i18n.GetMsgWithMap("LocalAppVersionNull", map[string]interface{}{"name": app.Name}))
}
}
}
var (
newApps []model.App
deleteApps []model.App
updateApps []model.App
oldAppIds []uint
deleteAppIds []uint
deleteAppDetails []model.AppDetail
newAppDetails []model.AppDetail
updateDetails []model.AppDetail
appTags []*model.AppTag
)
oldApps, _ := appRepo.GetBy(appRepo.WithResource(constant.AppResourceLocal))
apps := make(map[string]model.App, len(oldApps))
for _, old := range oldApps {
old.Status = constant.AppTakeDown
apps[old.Key] = old
}
for _, app := range localApps {
if oldApp, ok := apps[app.Key]; ok {
app.ID = oldApp.ID
appDetails := make(map[string]model.AppDetail, len(oldApp.Details))
for _, old := range oldApp.Details {
old.Status = constant.AppTakeDown
appDetails[old.Version] = old
}
for i, newDetail := range app.Details {
version := newDetail.Version
newDetail.Status = constant.AppNormal
newDetail.AppId = app.ID
oldDetail, exist := appDetails[version]
if exist {
newDetail.ID = oldDetail.ID
}
app.Details[i] = newDetail
}
}
app.TagsKey = append(app.TagsKey, constant.AppResourceLocal)
apps[app.Key] = app
}
for _, app := range apps {
if app.ID == 0 {
newApps = append(newApps, app)
} else {
oldAppIds = append(oldAppIds, app.ID)
if app.Status == constant.AppTakeDown {
installs, _ := appInstallRepo.ListBy(appInstallRepo.WithAppId(app.ID))
if len(installs) > 0 {
updateApps = append(updateApps, app)
continue
}
deleteAppIds = append(deleteAppIds, app.ID)
deleteApps = append(deleteApps, app)
deleteAppDetails = append(deleteAppDetails, app.Details...)
} else {
updateApps = append(updateApps, app)
}
}
}
tags, _ := tagRepo.All()
tagMap := make(map[string]uint, len(tags))
for _, tag := range tags {
tagMap[tag.Key] = tag.ID
}
tx, ctx := getTxAndContext()
defer tx.Rollback()
if len(newApps) > 0 {
if err = appRepo.BatchCreate(ctx, newApps); err != nil {
return
}
}
for _, update := range updateApps {
if err = appRepo.Save(ctx, &update); err != nil {
return
}
}
if len(deleteApps) > 0 {
if err = appRepo.BatchDelete(ctx, deleteApps); err != nil {
return
}
if err = appDetailRepo.DeleteByAppIds(ctx, deleteAppIds); err != nil {
return
}
}
if err = appTagRepo.DeleteByAppIds(ctx, oldAppIds); err != nil {
return
}
for _, newApp := range newApps {
if newApp.ID > 0 {
for _, detail := range newApp.Details {
detail.AppId = newApp.ID
newAppDetails = append(newAppDetails, detail)
}
}
}
for _, update := range updateApps {
for _, detail := range update.Details {
if detail.ID == 0 {
detail.AppId = update.ID
newAppDetails = append(newAppDetails, detail)
} else {
if detail.Status == constant.AppNormal {
updateDetails = append(updateDetails, detail)
} else {
deleteAppDetails = append(deleteAppDetails, detail)
}
}
}
}
allApps := append(newApps, updateApps...)
for _, app := range allApps {
for _, t := range app.TagsKey {
tagId, ok := tagMap[t]
if ok {
appTags = append(appTags, &model.AppTag{
AppId: app.ID,
TagId: tagId,
})
}
}
}
if len(newAppDetails) > 0 {
if err = appDetailRepo.BatchCreate(ctx, newAppDetails); err != nil {
return
}
}
for _, updateAppDetail := range updateDetails {
if err = appDetailRepo.Update(ctx, updateAppDetail); err != nil {
return
}
}
if len(deleteAppDetails) > 0 {
if err = appDetailRepo.BatchDelete(ctx, deleteAppDetails); err != nil {
return
}
}
if len(oldAppIds) > 0 {
if err = appTagRepo.DeleteByAppIds(ctx, oldAppIds); err != nil {
return
}
}
if len(appTags) > 0 {
if err = appTagRepo.BatchCreate(ctx, appTags); err != nil {
return
}
}
tx.Commit()
global.LOG.Infof("sync local apps success")
}
func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
res := &response.AppUpdateRes{
CanUpdate: false,
@@ -606,8 +354,8 @@ func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
if err != nil {
return nil, err
}
versionUrl := fmt.Sprintf("%s/%s/1panel.json.version.txt", global.CONF.System.AppRepo, global.CONF.System.Mode)
versionRes, err := http2.GetHttpRes(versionUrl)
versionUrl := fmt.Sprintf("%s/%s/%s/appstore/apps.json", global.CONF.System.RepoUrl, global.CONF.System.Mode, setting.SystemVersion)
versionRes, err := http.Get(versionUrl)
if err != nil {
return nil, err
}
@@ -616,49 +364,182 @@ func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
if err != nil {
return nil, err
}
lastModifiedStr := string(body)
lastModified, err := strconv.Atoi(lastModifiedStr)
if err != nil {
list := &dto.AppList{}
if err = json.Unmarshal(body, list); err != nil {
return nil, err
}
appStoreLastModified, _ := strconv.Atoi(setting.AppStoreLastModified)
if setting.AppStoreLastModified == "" || lastModified != appStoreLastModified {
res.Version = list.Version
if setting.AppStoreVersion == "" || common.CompareVersion(list.Version, setting.AppStoreVersion) {
res.CanUpdate = true
res.DownloadPath = fmt.Sprintf("%s/%s/%s/appstore/apps-%s.tar.gz", global.CONF.System.RepoUrl, global.CONF.System.Mode, setting.SystemVersion, list.Version)
return res, err
}
return res, nil
}
func getAppFromRepo(downloadPath string) error {
downloadUrl := downloadPath
global.LOG.Infof("download file from %s", downloadUrl)
func (a AppService) SyncAppListFromLocal() {
fileOp := files.NewFileOp()
packagePath := path.Join(constant.ResourceDir, path.Base(downloadUrl))
if err := fileOp.DownloadFile(downloadUrl, packagePath); err != nil {
return err
appDir := constant.LocalAppResourceDir
listFile := path.Join(appDir, "list.json")
if !fileOp.Stat(listFile) {
return
}
if err := fileOp.Decompress(packagePath, constant.ResourceDir, files.Zip); err != nil {
return err
global.LOG.Infof("start sync local apps...")
content, err := fileOp.GetContent(listFile)
if err != nil {
global.LOG.Errorf("get list.json content failed %s", err.Error())
return
}
defer func() {
_ = fileOp.DeleteFile(packagePath)
}()
return nil
}
list := &dto.AppList{}
if err := json.Unmarshal(content, list); err != nil {
global.LOG.Errorf("unmarshal list.json failed %s", err.Error())
return
}
oldApps, _ := appRepo.GetBy(appRepo.WithResource(constant.AppResourceLocal))
appsMap := getApps(oldApps, list.Items, true)
for _, l := range list.Items {
localKey := "local" + l.Key
app := appsMap[localKey]
icon, err := os.ReadFile(path.Join(appDir, l.Key, "metadata", "logo.png"))
if err != nil {
global.LOG.Errorf("get [%s] icon error: %s", l.Name, err.Error())
continue
}
iconStr := base64.StdEncoding.EncodeToString(icon)
app.Icon = iconStr
app.TagsKey = append(l.Tags, "Local")
app.Recommend = 9999
versions := l.Versions
detailsMap := getAppDetails(app.Details, versions)
for _, v := range versions {
detail := detailsMap[v]
detailPath := path.Join(appDir, l.Key, "versions", v)
if _, err := os.Stat(detailPath); err != nil {
global.LOG.Errorf("get [%s] folder error: %s", detailPath, err.Error())
continue
}
readmeStr, err := os.ReadFile(path.Join(detailPath, "README.md"))
if err != nil {
global.LOG.Errorf("get [%s] README error: %s", detailPath, err.Error())
}
detail.Readme = string(readmeStr)
dockerComposeStr, err := os.ReadFile(path.Join(detailPath, "docker-compose.yml"))
if err != nil {
global.LOG.Errorf("get [%s] docker-compose.yml error: %s", detailPath, err.Error())
continue
}
detail.DockerCompose = string(dockerComposeStr)
paramStr, err := os.ReadFile(path.Join(detailPath, "config.json"))
if err != nil {
global.LOG.Errorf("get [%s] form.json error: %s", detailPath, err.Error())
}
detail.Params = string(paramStr)
detailsMap[v] = detail
}
var newDetails []model.AppDetail
for _, v := range detailsMap {
newDetails = append(newDetails, v)
}
app.Details = newDetails
appsMap[localKey] = app
}
var (
addAppArray []model.App
updateArray []model.App
appIds []uint
)
for _, v := range appsMap {
if v.ID == 0 {
addAppArray = append(addAppArray, v)
} else {
updateArray = append(updateArray, v)
appIds = append(appIds, v.ID)
}
}
tx, ctx := getTxAndContext()
if len(addAppArray) > 0 {
if err := appRepo.BatchCreate(ctx, addAppArray); err != nil {
tx.Rollback()
return
}
}
for _, update := range updateArray {
if err := appRepo.Save(ctx, &update); err != nil {
tx.Rollback()
return
}
}
if err := appTagRepo.DeleteByAppIds(ctx, appIds); err != nil {
tx.Rollback()
return
}
apps := append(addAppArray, updateArray...)
var (
addDetails []model.AppDetail
updateDetails []model.AppDetail
appTags []*model.AppTag
)
tags, _ := tagRepo.All()
tagMap := make(map[string]uint, len(tags))
for _, app := range tags {
tagMap[app.Key] = app.ID
}
for _, a := range apps {
for _, t := range a.TagsKey {
tagId, ok := tagMap[t]
if ok {
appTags = append(appTags, &model.AppTag{
AppId: a.ID,
TagId: tagId,
})
}
}
for _, d := range a.Details {
d.AppId = a.ID
if d.ID == 0 {
addDetails = append(addDetails, d)
} else {
updateDetails = append(updateDetails, d)
}
}
}
if len(addDetails) > 0 {
if err := appDetailRepo.BatchCreate(ctx, addDetails); err != nil {
tx.Rollback()
return
}
}
for _, u := range updateDetails {
if err := appDetailRepo.Update(ctx, u); err != nil {
tx.Rollback()
return
}
}
if len(appTags) > 0 {
if err := appTagRepo.BatchCreate(ctx, appTags); err != nil {
tx.Rollback()
return
}
}
tx.Commit()
global.LOG.Infof("sync local apps success")
}
func (a AppService) SyncAppListFromRemote() error {
updateRes, err := a.GetAppUpdate()
if err != nil {
return err
}
if !updateRes.CanUpdate {
global.LOG.Infof("The latest version is [%s] The app store is already up to date", updateRes.Version)
return nil
}
if err = getAppFromRepo(fmt.Sprintf("%s/%s/1panel.json.zip", global.CONF.System.AppRepo, global.CONF.System.Mode)); err != nil {
if err := getAppFromRepo(updateRes.DownloadPath, updateRes.Version); err != nil {
global.LOG.Errorf("get app from oss error: %s", err.Error())
return err
}
listFile := path.Join(constant.ResourceDir, "1panel.json")
appDir := constant.AppResourceDir
listFile := path.Join(appDir, "list.json")
content, err := os.ReadFile(listFile)
if err != nil {
return err
@@ -667,13 +548,11 @@ func (a AppService) SyncAppListFromRemote() error {
if err := json.Unmarshal(content, list); err != nil {
return err
}
var (
tags []*model.Tag
appTags []*model.AppTag
oldAppIds []uint
tags []*model.Tag
appTags []*model.AppTag
)
for _, t := range list.Extra.Tags {
for _, t := range list.Tags {
tags = append(tags, &model.Tag{
Key: t.Key,
Name: t.Name,
@@ -683,193 +562,145 @@ func (a AppService) SyncAppListFromRemote() error {
if err != nil {
return err
}
for _, old := range oldApps {
oldAppIds = append(oldAppIds, old.ID)
}
baseRemoteUrl := fmt.Sprintf("%s/%s/1panel", global.CONF.System.AppRepo, global.CONF.System.Mode)
appsMap := getApps(oldApps, list.Apps)
for _, l := range list.Apps {
app := appsMap[l.AppProperty.Key]
iconRes, err := http.Get(l.Icon)
appsMap := getApps(oldApps, list.Items, false)
for _, l := range list.Items {
app := appsMap[l.Key]
icon, err := os.ReadFile(path.Join(appDir, l.Key, "metadata", "logo.png"))
if err != nil {
return err
global.LOG.Errorf("get [%s] icon error: %s", l.Name, err.Error())
continue
}
body, err := io.ReadAll(iconRes.Body)
if err != nil {
return err
}
iconStr := base64.StdEncoding.EncodeToString(body)
iconStr := base64.StdEncoding.EncodeToString(icon)
app.Icon = iconStr
app.TagsKey = l.AppProperty.Tags
if l.AppProperty.Recommend > 0 {
app.Recommend = l.AppProperty.Recommend
app.TagsKey = l.Tags
if l.Recommend > 0 {
app.Recommend = l.Recommend
} else {
app.Recommend = 9999
}
app.ReadMe = l.ReadMe
app.LastModified = l.LastModified
versions := l.Versions
detailsMap := getAppDetails(app.Details, versions)
for _, v := range versions {
version := v.Name
detail := detailsMap[version]
dockerComposeUrl := fmt.Sprintf("%s/%s/%s/%s", baseRemoteUrl, app.Key, version, "docker-compose.yml")
composeRes, err := http.Get(dockerComposeUrl)
detail := detailsMap[v]
detailPath := path.Join(appDir, l.Key, "versions", v)
if _, err := os.Stat(detailPath); err != nil {
global.LOG.Errorf("get [%s] folder error: %s", detailPath, err.Error())
continue
}
readmeStr, err := os.ReadFile(path.Join(detailPath, "README.md"))
if err != nil {
return err
global.LOG.Errorf("get [%s] README error: %s", detailPath, err.Error())
}
bodyContent, err := io.ReadAll(composeRes.Body)
detail.Readme = string(readmeStr)
dockerComposeStr, err := os.ReadFile(path.Join(detailPath, "docker-compose.yml"))
if err != nil {
return err
global.LOG.Errorf("get [%s] docker-compose.yml error: %s", detailPath, err.Error())
continue
}
detail.DockerCompose = string(bodyContent)
paramByte, _ := json.Marshal(v.AppForm)
detail.Params = string(paramByte)
detail.DownloadUrl = v.DownloadUrl
detail.DownloadCallBackUrl = v.DownloadCallBackUrl
if v.LastModified > detail.LastModified {
detail.Update = true
detail.LastModified = v.LastModified
detail.DockerCompose = string(dockerComposeStr)
paramStr, err := os.ReadFile(path.Join(detailPath, "config.json"))
if err != nil {
global.LOG.Errorf("get [%s] form.json error: %s", detailPath, err.Error())
}
detailsMap[version] = detail
detail.Params = string(paramStr)
detailsMap[v] = detail
}
var newDetails []model.AppDetail
for _, detail := range detailsMap {
newDetails = append(newDetails, detail)
for _, v := range detailsMap {
newDetails = append(newDetails, v)
}
app.Details = newDetails
appsMap[l.AppProperty.Key] = app
appsMap[l.Key] = app
}
var (
addAppArray []model.App
updateAppArray []model.App
deleteAppArray []model.App
deleteIds []uint
tagMap = make(map[string]uint, len(tags))
addAppArray []model.App
updateArray []model.App
tagMap = make(map[string]uint, len(tags))
)
for _, v := range appsMap {
if v.ID == 0 {
addAppArray = append(addAppArray, v)
} else {
if v.Status == constant.AppTakeDown {
installs, _ := appInstallRepo.ListBy(appInstallRepo.WithAppId(v.ID))
if len(installs) > 0 {
updateAppArray = append(updateAppArray, v)
continue
}
deleteAppArray = append(deleteAppArray, v)
deleteIds = append(deleteIds, v.ID)
} else {
updateAppArray = append(updateAppArray, v)
}
updateArray = append(updateArray, v)
}
}
tx, ctx := getTxAndContext()
defer tx.Rollback()
if len(addAppArray) > 0 {
if err := appRepo.BatchCreate(ctx, addAppArray); err != nil {
return err
}
}
if len(deleteAppArray) > 0 {
if err := appRepo.BatchDelete(ctx, deleteAppArray); err != nil {
return err
}
if err := appDetailRepo.DeleteByAppIds(ctx, deleteIds); err != nil {
tx.Rollback()
return err
}
}
if err := tagRepo.DeleteAll(ctx); err != nil {
tx.Rollback()
return err
}
if len(tags) > 0 {
if err := tagRepo.BatchCreate(ctx, tags); err != nil {
tx.Rollback()
return err
}
for _, t := range tags {
tagMap[t.Key] = t.ID
}
}
for _, update := range updateAppArray {
for _, update := range updateArray {
if err := appRepo.Save(ctx, &update); err != nil {
tx.Rollback()
return err
}
}
apps := append(addAppArray, updateAppArray...)
apps := append(addAppArray, updateArray...)
var (
addDetails []model.AppDetail
updateDetails []model.AppDetail
deleteDetails []model.AppDetail
)
for _, app := range apps {
for _, t := range app.TagsKey {
for _, a := range apps {
for _, t := range a.TagsKey {
tagId, ok := tagMap[t]
if ok {
appTags = append(appTags, &model.AppTag{
AppId: app.ID,
AppId: a.ID,
TagId: tagId,
})
}
}
for _, d := range app.Details {
d.AppId = app.ID
for _, d := range a.Details {
d.AppId = a.ID
if d.ID == 0 {
addDetails = append(addDetails, d)
} else {
if d.Status == constant.AppTakeDown {
runtime, _ := runtimeRepo.GetFirst(runtimeRepo.WithDetailId(d.ID))
if runtime != nil {
updateDetails = append(updateDetails, d)
continue
}
installs, _ := appInstallRepo.ListBy(appInstallRepo.WithDetailIdsIn([]uint{d.ID}))
if len(installs) > 0 {
updateDetails = append(updateDetails, d)
continue
}
deleteDetails = append(deleteDetails, d)
} else {
updateDetails = append(updateDetails, d)
}
updateDetails = append(updateDetails, d)
}
}
}
if len(addDetails) > 0 {
if err := appDetailRepo.BatchCreate(ctx, addDetails); err != nil {
return err
}
}
if len(deleteDetails) > 0 {
if err := appDetailRepo.BatchDelete(ctx, deleteDetails); err != nil {
tx.Rollback()
return err
}
}
for _, u := range updateDetails {
if err := appDetailRepo.Update(ctx, u); err != nil {
tx.Rollback()
return err
}
}
if len(oldAppIds) > 0 {
if err := appTagRepo.DeleteByAppIds(ctx, oldAppIds); err != nil {
return err
}
if err := appTagRepo.DeleteAll(ctx); err != nil {
tx.Rollback()
return err
}
if len(appTags) > 0 {
if err := appTagRepo.BatchCreate(ctx, appTags); err != nil {
tx.Rollback()
return err
}
}
tx.Commit()
if err := NewISettingService().Update("AppStoreLastModified", strconv.Itoa(list.LastModified)); err != nil {
return err
}
return nil
}
+45 -105
View File
@@ -11,9 +11,6 @@ import (
"strconv"
"strings"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"gopkg.in/yaml.v3"
"github.com/1Panel-dev/1Panel/backend/utils/env"
"github.com/1Panel-dev/1Panel/backend/utils/nginx"
"github.com/joho/godotenv"
@@ -48,7 +45,7 @@ type IAppInstallService interface {
SyncAll(systemInit bool) error
GetServices(key string) ([]response.AppService, error)
GetUpdateVersions(installId uint) ([]dto.AppVersion, error)
GetParams(id uint) (*response.AppConfig, error)
GetParams(id uint) ([]response.AppParam, error)
ChangeAppPort(req request.PortUpdate) error
GetDefaultConfigByKey(key string) (string, error)
DeleteCheck(installId uint) ([]dto.AppResource, error)
@@ -186,9 +183,6 @@ func (a *AppInstallService) Operate(req request.AppInstalledOperate) error {
if err != nil {
return err
}
if !req.ForceDelete && !files.NewFileOp().Stat(install.GetPath()) {
return buserr.New(constant.ErrInstallDirNotFound)
}
dockerComposePath := install.GetComposePath()
switch req.Operate {
case constant.Rebuild:
@@ -231,68 +225,35 @@ func (a *AppInstallService) Update(req request.AppInstalledUpdate) error {
return err
}
changePort := false
var (
oldPorts []int
newPorts []int
)
port, ok := req.Params["PANEL_APP_PORT_HTTP"]
if ok {
portN := int(math.Ceil(port.(float64)))
if portN != installed.HttpPort {
oldPorts = append(oldPorts, installed.HttpPort)
changePort = true
httpPort, err := checkPort("PANEL_APP_PORT_HTTP", req.Params)
if err != nil {
return err
}
installed.HttpPort = httpPort
newPorts = append(newPorts, httpPort)
}
}
ports, ok := req.Params["PANEL_APP_PORT_HTTPS"]
if ok {
portN := int(math.Ceil(ports.(float64)))
if portN != installed.HttpsPort {
oldPorts = append(oldPorts, installed.HttpsPort)
httpsPort, err := checkPort("PANEL_APP_PORT_HTTPS", req.Params)
if err != nil {
return err
}
installed.HttpsPort = httpsPort
}
}
backupDockerCompose := installed.DockerCompose
if req.Advanced {
composeMap := make(map[string]interface{})
if req.EditCompose {
if err = yaml.Unmarshal([]byte(req.DockerCompose), &composeMap); err != nil {
return err
}
} else {
if err = yaml.Unmarshal([]byte(installed.DockerCompose), &composeMap); err != nil {
return err
}
}
if err = addDockerComposeCommonParam(composeMap, installed.ServiceName, req.AppContainerConfig, req.Params); err != nil {
return err
}
composeByte, err := yaml.Marshal(composeMap)
if err != nil {
return err
}
installed.DockerCompose = string(composeByte)
if req.ContainerName == "" {
req.Params[constant.ContainerName] = installed.ContainerName
} else {
req.Params[constant.ContainerName] = req.ContainerName
if installed.ContainerName != req.ContainerName {
exist, _ := appInstallRepo.GetFirst(appInstallRepo.WithContainerName(req.ContainerName), appInstallRepo.WithIDNotIs(installed.ID))
if exist.ID > 0 {
return buserr.New(constant.ErrContainerName)
}
containerExist, err := checkContainerNameIsExist(req.ContainerName, installed.GetPath())
if err != nil {
return err
}
if containerExist {
return buserr.New(constant.ErrContainerName)
}
installed.ContainerName = req.ContainerName
}
newPorts = append(newPorts, httpsPort)
}
}
@@ -301,7 +262,6 @@ func (a *AppInstallService) Update(req request.AppInstalledUpdate) error {
if err != nil {
return err
}
backupEnvMaps := oldEnvMaps
handleMap(req.Params, oldEnvMaps)
paramByte, err := json.Marshal(oldEnvMaps)
if err != nil {
@@ -311,42 +271,36 @@ func (a *AppInstallService) Update(req request.AppInstalledUpdate) error {
if err := env.Write(oldEnvMaps, envPath); err != nil {
return err
}
fileOp := files.NewFileOp()
_ = fileOp.WriteFile(installed.GetComposePath(), strings.NewReader(installed.DockerCompose), 0755)
if err := rebuildApp(installed); err != nil {
_ = env.Write(backupEnvMaps, envPath)
_ = fileOp.WriteFile(installed.GetComposePath(), strings.NewReader(backupDockerCompose), 0755)
return err
}
installed.Status = constant.Running
_ = appInstallRepo.Save(context.Background(), &installed)
if err := rebuildApp(installed); err != nil {
return err
}
website, _ := websiteRepo.GetFirst(websiteRepo.WithAppInstallId(installed.ID))
if changePort && website.ID != 0 && website.Status == constant.Running {
go func() {
nginxInstall, err := getNginxFull(&website)
if err != nil {
global.LOG.Errorf(buserr.WithErr(constant.ErrUpdateBuWebsite, err).Error())
return
}
config := nginxInstall.SiteConfig.Config
servers := config.FindServers()
if len(servers) == 0 {
global.LOG.Errorf(buserr.WithErr(constant.ErrUpdateBuWebsite, errors.New("nginx config is not valid")).Error())
return
}
server := servers[0]
proxy := fmt.Sprintf("http://127.0.0.1:%d", installed.HttpPort)
server.UpdateRootProxy([]string{proxy})
nginxInstall, err := getNginxFull(&website)
if err != nil {
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
}
config := nginxInstall.SiteConfig.Config
servers := config.FindServers()
if len(servers) == 0 {
return buserr.WithErr(constant.ErrUpdateBuWebsite, errors.New("nginx config is not valid"))
}
server := servers[0]
proxy := fmt.Sprintf("http://127.0.0.1:%d", installed.HttpPort)
server.UpdateRootProxy([]string{proxy})
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
global.LOG.Errorf(buserr.WithErr(constant.ErrUpdateBuWebsite, err).Error())
return
}
if err := nginxCheckAndReload(nginxInstall.SiteConfig.OldContent, config.FilePath, nginxInstall.Install.ContainerName); err != nil {
global.LOG.Errorf(buserr.WithErr(constant.ErrUpdateBuWebsite, err).Error())
return
}
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
}
if err := nginxCheckAndReload(nginxInstall.SiteConfig.OldContent, config.FilePath, nginxInstall.Install.ContainerName); err != nil {
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
}
}
if changePort {
go func() {
_ = OperateFirewallPort(oldPorts, newPorts)
}()
}
return nil
@@ -358,10 +312,10 @@ func (a *AppInstallService) SyncAll(systemInit bool) error {
return err
}
for _, i := range allList {
if i.Status == constant.Installing || i.Status == constant.Upgrading {
if i.Status == constant.Installing {
if systemInit {
i.Status = constant.Error
i.Message = "1Panel restart causes the task to terminate"
i.Message = "System restart causes application exception"
_ = appInstallRepo.Save(context.Background(), &i)
}
continue
@@ -412,9 +366,6 @@ func (a *AppInstallService) GetUpdateVersions(installId uint) ([]dto.AppVersion,
return versions, err
}
for _, detail := range details {
if common.IsCrossVersion(install.Version, detail.Version) && !app.CrossVersionUpdate {
continue
}
if common.CompareVersion(detail.Version, install.Version) {
versions = append(versions, dto.AppVersion{
Version: detail.Version,
@@ -450,6 +401,10 @@ func (a *AppInstallService) ChangeAppPort(req request.PortUpdate) error {
}
}
if err := OperateFirewallPort([]int{int(appInstall.Port)}, []int{int(req.Port)}); err != nil {
global.LOG.Errorf("allow firewall failed, err: %v", err)
}
return nil
}
@@ -497,16 +452,7 @@ func (a *AppInstallService) GetDefaultConfigByKey(key string) (string, error) {
if err != nil {
return "", err
}
fileOp := files.NewFileOp()
filePath := path.Join(constant.AppResourceDir, "remote", appInstall.App.Key, appInstall.Version, "conf")
if !fileOp.Stat(filePath) {
filePath = path.Join(constant.AppResourceDir, appInstall.App.Key, "versions", appInstall.Version, "conf")
}
if !fileOp.Stat(filePath) {
return "", buserr.New(constant.ErrPathNotFound)
}
filePath := path.Join(constant.AppResourceDir, appInstall.App.Key, "versions", appInstall.Version, "conf")
if key == constant.AppMysql {
filePath = path.Join(filePath, "my.cnf")
}
@@ -523,12 +469,11 @@ func (a *AppInstallService) GetDefaultConfigByKey(key string) (string, error) {
return string(contentByte), nil
}
func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) {
func (a *AppInstallService) GetParams(id uint) ([]response.AppParam, error) {
var (
params []response.AppParam
res []response.AppParam
appForm dto.AppForm
envs = make(map[string]interface{})
res response.AppConfig
)
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(id))
if err != nil {
@@ -570,15 +515,10 @@ func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) {
}
appParam.Values = form.Values
}
params = append(params, appParam)
res = append(res, appParam)
}
}
config := getAppCommonConfig(envs)
config.DockerCompose = install.DockerCompose
res.Params = params
res.AppContainerConfig = config
return &res, nil
return res, nil
}
func syncById(installId uint) error {
+117 -407
View File
@@ -2,22 +2,16 @@ package service
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/i18n"
"github.com/compose-spec/compose-go/types"
"github.com/subosito/gotenv"
"gopkg.in/yaml.v3"
"math"
"net/http"
"os"
"os/exec"
"path"
"reflect"
"regexp"
"strconv"
"strings"
@@ -35,7 +29,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/utils/compose"
composeV2 "github.com/1Panel-dev/1Panel/backend/utils/docker"
"github.com/1Panel-dev/1Panel/backend/utils/files"
dockerTypes "github.com/docker/docker/api/types"
"github.com/pkg/errors"
)
@@ -50,6 +43,7 @@ func checkPort(key string, params map[string]interface{}) (int, error) {
port, ok := params[key]
if ok {
portN := int(math.Ceil(port.(float64)))
oldInstalled, _ := appInstallRepo.ListBy(appInstallRepo.WithPort(portN))
if len(oldInstalled) > 0 {
var apps []string
@@ -231,121 +225,40 @@ func upgradeInstall(installId uint, detailId uint) error {
return err
}
install.Status = constant.Upgrading
detailDir := path.Join(constant.ResourceDir, "apps", install.App.Key, "versions", detail.Version)
if install.App.Resource == constant.AppResourceLocal {
detailDir = path.Join(constant.ResourceDir, "localApps", strings.TrimPrefix(install.App.Key, "local"), "versions", detail.Version)
}
go func() {
var upErr error
defer func() {
if upErr != nil {
install.Status = constant.UpgradeErr
install.Message = upErr.Error()
_ = appInstallRepo.Save(context.Background(), &install)
}
}()
cmd := exec.Command("/bin/bash", "-c", fmt.Sprintf("cp -rf %s/* %s", detailDir, install.GetPath()))
stdout, err := cmd.CombinedOutput()
if err != nil {
if stdout != nil {
return errors.New(string(stdout))
}
return err
}
detailDir := path.Join(constant.ResourceDir, "apps", install.App.Resource, install.App.Key, detail.Version)
if install.App.Resource == constant.AppResourceRemote {
if upErr = downloadApp(install.App, detail, &install); upErr != nil {
return
}
go func() {
_, _ = http.Get(detail.DownloadCallBackUrl)
}()
}
if install.App.Resource == constant.AppResourceLocal {
detailDir = path.Join(constant.ResourceDir, "apps", "local", strings.TrimPrefix(install.App.Key, "local"), detail.Version)
if out, err := compose.Down(install.GetComposePath()); err != nil {
if out != "" {
return errors.New(out)
}
return err
}
install.DockerCompose = detail.DockerCompose
install.Version = detail.Version
install.AppDetailId = detailId
cmd := exec.Command("/bin/bash", "-c", fmt.Sprintf("cp -rf %s/* %s", detailDir, install.GetPath()))
stdout, err := cmd.CombinedOutput()
if err != nil {
if stdout != nil {
upErr = errors.New(string(stdout))
return
}
upErr = err
return
fileOp := files.NewFileOp()
if err := fileOp.WriteFile(install.GetComposePath(), strings.NewReader(install.DockerCompose), 0775); err != nil {
return err
}
if out, err := compose.Up(install.GetComposePath()); err != nil {
if out != "" {
return errors.New(out)
}
composeMap := make(map[string]interface{})
if upErr = yaml.Unmarshal([]byte(detail.DockerCompose), &composeMap); upErr != nil {
return
}
value, ok := composeMap["services"]
if !ok {
upErr = buserr.New(constant.ErrFileParse)
return
}
servicesMap := value.(map[string]interface{})
index := 0
oldServiceName := ""
for k := range servicesMap {
oldServiceName = k
index++
if index > 0 {
break
}
}
servicesMap[install.ServiceName] = servicesMap[oldServiceName]
if install.ServiceName != oldServiceName {
delete(servicesMap, oldServiceName)
}
envs := make(map[string]interface{})
if upErr = json.Unmarshal([]byte(install.Env), &envs); upErr != nil {
return
}
config := getAppCommonConfig(envs)
if config.ContainerName == "" {
config.ContainerName = install.ContainerName
envs[constant.ContainerName] = install.ContainerName
}
config.Advanced = true
if upErr = addDockerComposeCommonParam(composeMap, install.ServiceName, config, envs); upErr != nil {
return
}
paramByte, upErr := json.Marshal(envs)
if upErr != nil {
return
}
install.Env = string(paramByte)
composeByte, upErr := yaml.Marshal(composeMap)
if upErr != nil {
return
}
install.DockerCompose = string(composeByte)
install.Version = detail.Version
install.AppDetailId = detailId
if out, err := compose.Down(install.GetComposePath()); err != nil {
if out != "" {
upErr = errors.New(out)
return
}
return
}
fileOp := files.NewFileOp()
envParams := make(map[string]string, len(envs))
handleMap(envs, envParams)
if err = env.Write(envParams, install.GetEnvPath()); err != nil {
return
}
if upErr = fileOp.WriteFile(install.GetComposePath(), strings.NewReader(install.DockerCompose), 0775); upErr != nil {
return
}
if out, err := compose.Up(install.GetComposePath()); err != nil {
if out != "" {
upErr = errors.New(out)
return
}
upErr = err
return
}
install.Status = constant.Running
_ = appInstallRepo.Save(context.Background(), &install)
}()
return err
}
return appInstallRepo.Save(context.Background(), &install)
}
@@ -402,6 +315,34 @@ func checkRequiredAndLimit(app model.App) error {
if err := checkLimit(app); err != nil {
return err
}
if app.Required != "" {
var requiredArray []string
if err := json.Unmarshal([]byte(app.Required), &requiredArray); err != nil {
return err
}
for _, key := range requiredArray {
if key == "" {
continue
}
requireApp, err := appRepo.GetFirst(appRepo.WithKey(key))
if err != nil {
return err
}
details, err := appDetailRepo.GetBy(appDetailRepo.WithAppId(requireApp.ID))
if err != nil {
return err
}
var detailIds []uint
for _, d := range details {
detailIds = append(detailIds, d.ID)
}
_, err = appInstallRepo.GetFirst(appInstallRepo.WithDetailIdsIn(detailIds))
if err != nil {
return buserr.WithDetail(constant.ErrAppRequired, requireApp.Name, nil)
}
}
}
return nil
}
@@ -418,74 +359,24 @@ func handleMap(params map[string]interface{}, envParams map[string]string) {
}
}
func downloadApp(app model.App, appDetail model.AppDetail, appInstall *model.AppInstall) (err error) {
appResourceDir := path.Join(constant.AppResourceDir, app.Resource)
appDownloadDir := path.Join(appResourceDir, app.Key)
appVersionDir := path.Join(appDownloadDir, appDetail.Version)
func copyAppData(key, version, installName string, params map[string]interface{}, isLocal bool) (err error) {
fileOp := files.NewFileOp()
if !appDetail.Update && fileOp.Stat(appVersionDir) {
return
}
if !fileOp.Stat(appDownloadDir) {
_ = fileOp.CreateDir(appDownloadDir, 0755)
}
if !fileOp.Stat(appVersionDir) {
_ = fileOp.CreateDir(appVersionDir, 0755)
}
global.LOG.Infof("download app[%s] from %s", app.Name, appDetail.DownloadUrl)
filePath := path.Join(appVersionDir, appDetail.Version+".tar.gz")
defer func() {
if err != nil {
if appInstall != nil {
appInstall.Status = constant.DownloadErr
appInstall.Message = err.Error()
}
}
}()
if err = fileOp.DownloadFile(appDetail.DownloadUrl, filePath); err != nil {
global.LOG.Errorf("download app[%s] error %v", app.Name, err)
return
}
if err = fileOp.Decompress(filePath, appVersionDir, files.TarGz); err != nil {
global.LOG.Errorf("decompress app[%s] error %v", app.Name, err)
return
}
_ = fileOp.DeleteFile(filePath)
appDetail.Update = false
_ = appDetailRepo.Update(context.Background(), appDetail)
return
}
func copyData(app model.App, appDetail model.AppDetail, appInstall *model.AppInstall, req request.AppInstallCreate) (err error) {
fileOp := files.NewFileOp()
appResourceDir := path.Join(constant.AppResourceDir, app.Resource)
if app.Resource == constant.AppResourceRemote {
err = downloadApp(app, appDetail, appInstall)
if err != nil {
return
}
go func() {
_, _ = http.Get(appDetail.DownloadCallBackUrl)
}()
}
appKey := app.Key
installAppDir := path.Join(constant.AppInstallDir, app.Key)
if app.Resource == constant.AppResourceLocal {
appResourceDir := constant.AppResourceDir
installAppDir := path.Join(constant.AppInstallDir, key)
appKey := key
if isLocal {
appResourceDir = constant.LocalAppResourceDir
appKey = strings.TrimPrefix(app.Key, "local")
appKey = strings.TrimPrefix(key, "local")
installAppDir = path.Join(constant.LocalAppInstallDir, appKey)
}
resourceDir := path.Join(appResourceDir, appKey, appDetail.Version)
resourceDir := path.Join(appResourceDir, appKey, "versions", version)
if !fileOp.Stat(installAppDir) {
if err = fileOp.CreateDir(installAppDir, 0755); err != nil {
return
}
}
appDir := path.Join(installAppDir, req.Name)
appDir := path.Join(installAppDir, installName)
if fileOp.Stat(appDir) {
if err = fileOp.DeleteDir(appDir); err != nil {
return
@@ -494,20 +385,17 @@ func copyData(app model.App, appDetail model.AppDetail, appInstall *model.AppIns
if err = fileOp.Copy(resourceDir, installAppDir); err != nil {
return
}
versionDir := path.Join(installAppDir, appDetail.Version)
versionDir := path.Join(installAppDir, version)
if err = fileOp.Rename(versionDir, appDir); err != nil {
return
}
envPath := path.Join(appDir, ".env")
envParams := make(map[string]string, len(req.Params))
handleMap(req.Params, envParams)
envParams := make(map[string]string, len(params))
handleMap(params, envParams)
if err = env.Write(envParams, envPath); err != nil {
return
}
if err := fileOp.WriteFile(appInstall.GetComposePath(), strings.NewReader(appInstall.DockerCompose), 0755); err != nil {
return err
}
return
}
@@ -543,31 +431,6 @@ func getServiceFromInstall(appInstall *model.AppInstall) (service *composeV2.Com
return
}
func checkContainerNameIsExist(containerName, appDir string) (bool, error) {
client, err := composeV2.NewDockerClient()
if err != nil {
return false, err
}
var options dockerTypes.ContainerListOptions
list, err := client.ContainerList(context.Background(), options)
if err != nil {
return false, err
}
for _, container := range list {
if containerName == container.Names[0][1:] {
if workDir, ok := container.Labels[composeWorkdirLabel]; ok {
if workDir != appDir {
return true, nil
}
} else {
return true, nil
}
}
}
return false, nil
}
func upApp(appInstall *model.AppInstall) {
upProject := func(appInstall *model.AppInstall) (err error) {
if err == nil {
@@ -610,21 +473,21 @@ func rebuildApp(appInstall model.AppInstall) error {
return syncById(appInstall.ID)
}
func getAppDetails(details []model.AppDetail, versions []dto.AppConfigVersion) map[string]model.AppDetail {
func getAppDetails(details []model.AppDetail, versions []string) map[string]model.AppDetail {
appDetails := make(map[string]model.AppDetail, len(details))
for _, old := range details {
old.Status = constant.AppTakeDown
appDetails[old.Version] = old
}
for _, v := range versions {
version := v.Name
detail, ok := appDetails[version]
detail, ok := appDetails[v]
if ok {
detail.Status = constant.AppNormal
appDetails[version] = detail
appDetails[v] = detail
} else {
appDetails[version] = model.AppDetail{
Version: version,
appDetails[v] = model.AppDetail{
Version: v,
Status: constant.AppNormal,
}
}
@@ -632,110 +495,43 @@ func getAppDetails(details []model.AppDetail, versions []dto.AppConfigVersion) m
return appDetails
}
func getApps(oldApps []model.App, items []dto.AppDefine) map[string]model.App {
func getApps(oldApps []model.App, items []dto.AppDefine, isLocal bool) map[string]model.App {
apps := make(map[string]model.App, len(oldApps))
for _, old := range oldApps {
old.Status = constant.AppTakeDown
apps[old.Key] = old
}
for _, item := range items {
config := item.AppProperty
key := config.Key
key := item.Key
if isLocal {
key = "local" + key
}
app, ok := apps[key]
if !ok {
app = model.App{}
}
app.Resource = constant.AppResourceRemote
if isLocal {
app.Resource = constant.AppResourceLocal
} else {
app.Resource = constant.AppResourceRemote
}
app.Name = item.Name
app.Limit = config.Limit
app.Limit = item.Limit
app.Key = key
app.ShortDescZh = config.ShortDescZh
app.ShortDescEn = config.ShortDescEn
app.Website = config.Website
app.Document = config.Document
app.Github = config.Github
app.Type = config.Type
app.CrossVersionUpdate = config.CrossVersionUpdate
app.ShortDescZh = item.ShortDescZh
app.ShortDescEn = item.ShortDescEn
app.Website = item.Website
app.Document = item.Document
app.Github = item.Github
app.Type = item.Type
app.CrossVersionUpdate = item.CrossVersionUpdate
app.Required = item.GetRequired()
app.Status = constant.AppNormal
app.LastModified = item.LastModified
app.ReadMe = item.ReadMe
apps[key] = app
}
return apps
}
func handleLocalAppDetail(versionDir string, appDetail *model.AppDetail) error {
fileOp := files.NewFileOp()
dockerComposePath := path.Join(versionDir, "docker-compose.yml")
if !fileOp.Stat(dockerComposePath) {
return errors.New(i18n.GetMsgWithMap("ErrFileNotFound", map[string]interface{}{"name": "docker-compose.yml"}))
}
dockerComposeByte, _ := fileOp.GetContent(dockerComposePath)
if dockerComposeByte == nil {
return errors.New(i18n.GetMsgWithMap("ErrFileParseApp", map[string]interface{}{"name": "docker-compose.yml"}))
}
appDetail.DockerCompose = string(dockerComposeByte)
paramPath := path.Join(versionDir, "data.yml")
if !fileOp.Stat(paramPath) {
return errors.New(i18n.GetMsgWithMap("ErrFileNotFound", map[string]interface{}{"name": "data.yml"}))
}
paramByte, _ := fileOp.GetContent(paramPath)
if paramByte == nil {
return errors.New(i18n.GetMsgWithMap("ErrFileParseApp", map[string]interface{}{"name": "data.yml"}))
}
appParamConfig := dto.LocalAppParam{}
if err := yaml.Unmarshal(paramByte, &appParamConfig); err != nil {
return errors.New(i18n.GetMsgWithMap("ErrFileParseApp", map[string]interface{}{"name": "data.yml"}))
}
dataJson, err := json.Marshal(appParamConfig.AppParams)
if err != nil {
return errors.New(i18n.GetMsgWithMap("ErrFileParseApp", map[string]interface{}{"name": "data.yml", "err": err.Error()}))
}
appDetail.Params = string(dataJson)
return nil
}
func handleLocalApp(appDir string) (app *model.App, err error) {
fileOp := files.NewFileOp()
configYamlPath := path.Join(appDir, "data.yml")
if !fileOp.Stat(configYamlPath) {
err = errors.New(i18n.GetMsgWithMap("ErrFileNotFound", map[string]interface{}{"name": "data.yml"}))
return
}
iconPath := path.Join(appDir, "logo.png")
if !fileOp.Stat(iconPath) {
err = errors.New(i18n.GetMsgWithMap("ErrFileNotFound", map[string]interface{}{"name": "logo.png"}))
return
}
configYamlByte, err := fileOp.GetContent(configYamlPath)
if err != nil {
err = errors.New(i18n.GetMsgWithMap("ErrFileParseApp", map[string]interface{}{"name": "data.yml", "err": err.Error()}))
return
}
localAppDefine := dto.LocalAppAppDefine{}
if err = yaml.Unmarshal(configYamlByte, &localAppDefine); err != nil {
err = errors.New(i18n.GetMsgWithMap("ErrFileParseApp", map[string]interface{}{"name": "data.yml", "err": err.Error()}))
return
}
app = &localAppDefine.AppProperty
app.Resource = constant.AppResourceLocal
app.Status = constant.AppNormal
app.Recommend = 9999
app.TagsKey = append(app.TagsKey, "Local")
app.Key = "local" + app.Key
readMePath := path.Join(appDir, "README.md")
readMeByte, err := fileOp.GetContent(readMePath)
if err == nil {
app.ReadMe = string(readMeByte)
}
iconByte, _ := fileOp.GetContent(iconPath)
if iconByte != nil {
iconStr := base64.StdEncoding.EncodeToString(iconByte)
app.Icon = iconStr
}
return
}
func handleErr(install model.AppInstall, err error, out string) error {
reErr := err
install.Message = err.Error()
@@ -748,6 +544,29 @@ func handleErr(install model.AppInstall, err error, out string) error {
return reErr
}
func getAppFromRepo(downloadPath, version string) error {
downloadUrl := downloadPath
appDir := constant.AppResourceDir
global.LOG.Infof("download file from %s", downloadUrl)
fileOp := files.NewFileOp()
if _, err := fileOp.CopyAndBackup(appDir); err != nil {
return err
}
packagePath := path.Join(constant.ResourceDir, path.Base(downloadUrl))
if err := fileOp.DownloadFile(downloadUrl, packagePath); err != nil {
return err
}
if err := fileOp.Decompress(packagePath, constant.ResourceDir, files.TarGz); err != nil {
return err
}
_ = NewISettingService().Update("AppStoreVersion", version)
defer func() {
_ = fileOp.DeleteFile(packagePath)
}()
return nil
}
func handleInstalled(appInstallList []model.AppInstall, updated bool) ([]response.AppInstalledDTO, error) {
var res []response.AppInstalledDTO
for _, installed := range appInstallList {
@@ -756,7 +575,6 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool) ([]respons
}
installDTO := response.AppInstalledDTO{
AppInstall: installed,
Path: installed.GetPath(),
}
app, err := appRepo.GetFirst(commonRepo.WithByID(installed.AppId))
if err != nil {
@@ -768,9 +586,6 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool) ([]respons
}
var versions []string
for _, detail := range details {
if common.IsCrossVersion(installed.Version, detail.Version) && !app.CrossVersionUpdate {
continue
}
versions = append(versions, detail.Version)
}
versions = common.GetSortedVersions(versions)
@@ -852,108 +667,3 @@ func updateToolApp(installed *model.AppInstall) {
return
}
}
func addDockerComposeCommonParam(composeMap map[string]interface{}, serviceName string, req request.AppContainerConfig, params map[string]interface{}) error {
services, serviceValid := composeMap["services"].(map[string]interface{})
if !serviceValid {
return buserr.New(constant.ErrFileParse)
}
service, serviceExist := services[serviceName]
if !serviceExist {
return buserr.New(constant.ErrFileParse)
}
serviceValue := service.(map[string]interface{})
deploy := map[string]interface{}{
"resources": map[string]interface{}{
"limits": map[string]interface{}{
"cpus": "${CPUS}",
"memory": "${MEMORY_LIMIT}",
},
},
}
serviceValue["deploy"] = deploy
ports, ok := serviceValue["ports"].([]interface{})
if ok {
for i, port := range ports {
portStr, portOK := port.(string)
if !portOK {
continue
}
portArray := strings.Split(portStr, ":")
if len(portArray) == 2 {
portArray = append([]string{"${HOST_IP}"}, portArray...)
}
ports[i] = strings.Join(portArray, ":")
}
serviceValue["ports"] = ports
}
params[constant.CPUS] = "0"
params[constant.MemoryLimit] = "0"
if req.Advanced {
if req.CpuQuota > 0 {
params[constant.CPUS] = req.CpuQuota
}
if req.MemoryLimit > 0 {
params[constant.MemoryLimit] = strconv.FormatFloat(req.MemoryLimit, 'f', -1, 32) + req.MemoryUnit
}
}
_, portExist := serviceValue["ports"].([]interface{})
if portExist {
allowHost := "127.0.0.1"
if req.Advanced && req.AllowPort {
allowHost = "0.0.0.0"
}
params[constant.HostIP] = allowHost
}
services[serviceName] = serviceValue
return nil
}
func getAppCommonConfig(envs map[string]interface{}) request.AppContainerConfig {
config := request.AppContainerConfig{}
if hostIp, ok := envs[constant.HostIP]; ok {
config.AllowPort = hostIp.(string) == "0.0.0.0"
} else {
config.AllowPort = true
}
if cpuCore, ok := envs[constant.CPUS]; ok {
numStr, ok := cpuCore.(string)
if ok {
num, err := strconv.ParseFloat(numStr, 64)
if err == nil {
config.CpuQuota = num
}
} else {
num64, flOk := cpuCore.(float64)
if flOk {
config.CpuQuota = num64
}
}
} else {
config.CpuQuota = 0
}
if memLimit, ok := envs[constant.MemoryLimit]; ok {
re := regexp.MustCompile(`(\d+)([A-Za-z]+)`)
matches := re.FindStringSubmatch(memLimit.(string))
if len(matches) == 3 {
num, err := strconv.ParseFloat(matches[1], 64)
if err == nil {
unit := matches[2]
config.MemoryLimit = num
config.MemoryUnit = unit
}
}
} else {
config.MemoryLimit = 0
config.MemoryUnit = "M"
}
if containerName, ok := envs[constant.ContainerName]; ok {
config.ContainerName = containerName.(string)
}
return config
}
+10 -13
View File
@@ -17,7 +17,7 @@ import (
type AuthService struct{}
type IAuthService interface {
CheckIsSafety(code string) (string, error)
CheckIsSafety(code string) bool
VerifyCode(code string) (bool, error)
Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo, error)
LogOut(c *gin.Context) error
@@ -33,11 +33,11 @@ func (u *AuthService) Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo,
if err != nil {
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
}
passwordSetting, err := settingRepo.Get(settingRepo.WithByKey("Password"))
passwrodSetting, err := settingRepo.Get(settingRepo.WithByKey("Password"))
if err != nil {
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
}
pass, err := encrypt.StringDecrypt(passwordSetting.Value)
pass, err := encrypt.StringDecrypt(passwrodSetting.Value)
if err != nil {
return nil, constant.ErrAuth
}
@@ -60,11 +60,11 @@ func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin) (*dto.UserLogi
if err != nil {
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
}
passwordSetting, err := settingRepo.Get(settingRepo.WithByKey("Password"))
passwrodSetting, err := settingRepo.Get(settingRepo.WithByKey("Password"))
if err != nil {
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
}
pass, err := encrypt.StringDecrypt(passwordSetting.Value)
pass, err := encrypt.StringDecrypt(passwrodSetting.Value)
if err != nil {
return nil, err
}
@@ -109,7 +109,7 @@ func (u *AuthService) generateSession(c *gin.Context, name, authMethod string) (
sessionUser, err := global.SESSION.Get(sID)
if err != nil {
sID = uuid.New().String()
c.SetCookie(constant.SessionName, sID, 0, "", "", false, false)
c.SetCookie(constant.SessionName, sID, 604800, "", "", false, false)
err := global.SESSION.Set(sID, sessionUser, lifeTime)
if err != nil {
return nil, err
@@ -143,16 +143,13 @@ func (u *AuthService) VerifyCode(code string) (bool, error) {
return setting.Value == code, nil
}
func (u *AuthService) CheckIsSafety(code string) (string, error) {
func (u *AuthService) CheckIsSafety(code string) bool {
status, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
if err != nil {
return "", err
return false
}
if len(status.Value) == 0 {
return "disable", nil
return true
}
if status.Value == code {
return "pass", nil
}
return "unpass", nil
return status.Value == code
}
+5 -60
View File
@@ -99,7 +99,7 @@ func handleAppBackup(install *model.AppInstall, backupDir, fileName string) erro
return err
}
appPath := install.GetPath()
appPath := fmt.Sprintf("%s/%s", install.GetPath(), install.Name)
if err := handleTar(appPath, tmpDir, "app.tar.gz", ""); err != nil {
return err
}
@@ -148,7 +148,7 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
if err := json.Unmarshal(appjson, &oldInstall); err != nil {
return fmt.Errorf("unmarshal app.json failed, err: %v", err)
}
if oldInstall.App.Key != install.App.Key || oldInstall.Name != install.Name {
if oldInstall.App.Key != install.App.Key || oldInstall.Name != install.Name || oldInstall.Version != install.Version || oldInstall.ID != install.ID {
return errors.New("the current backup file does not match the application")
}
@@ -172,7 +172,6 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
}()
}
newEnvFile := ""
resource, _ := appInstallResourceRepo.GetFirst(appInstallResourceRepo.WithAppInstallId(install.ID))
if resource.ID != 0 && install.App.Key != "mysql" {
mysqlInfo, err := appInstallRepo.LoadBaseInfo(resource.Key, "")
@@ -183,22 +182,7 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
if err != nil {
return err
}
newDB, envMap, err := reCreateDB(db.ID, oldInstall.Env)
if err != nil {
return err
}
oldHost := fmt.Sprintf("\"PANEL_DB_HOST\":\"%v\"", envMap["PANEL_DB_HOST"].(string))
newHost := fmt.Sprintf("\"PANEL_DB_HOST\":\"%v\"", mysqlInfo.ServiceName)
oldInstall.Env = strings.ReplaceAll(oldInstall.Env, oldHost, newHost)
envMap["PANEL_DB_HOST"] = mysqlInfo.ServiceName
newEnvFile, err = coverEnvJsonToStr(oldInstall.Env)
if err != nil {
return err
}
_ = appInstallResourceRepo.BatchUpdateBy(map[string]interface{}{"resource_id": newDB.ID}, commonRepo.WithByID(resource.ID))
if err := handleMysqlRecover(mysqlInfo, tmpPath, newDB.Name, fmt.Sprintf("%s.sql.gz", install.Name), true); err != nil {
if err := handleMysqlRecover(mysqlInfo, tmpPath, db.Name, fmt.Sprintf("%s.sql.gz", install.Name), true); err != nil {
global.LOG.Errorf("handle recover from sql.gz failed, err: %v", err)
return err
}
@@ -209,50 +193,11 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
return err
}
if len(newEnvFile) != 0 {
envPath := fmt.Sprintf("%s/%s/%s/.env", constant.AppInstallDir, install.App.Key, install.Name)
file, err := os.OpenFile(envPath, os.O_WRONLY|os.O_TRUNC, 0640)
if err != nil {
return err
}
defer file.Close()
_, _ = file.WriteString(newEnvFile)
}
oldInstall.ID = install.ID
oldInstall.Status = constant.StatusRunning
oldInstall.AppId = install.AppId
oldInstall.AppDetailId = install.AppDetailId
if err := appInstallRepo.Save(context.Background(), &oldInstall); err != nil {
oldInstall.Status = constant.Running
if err := appInstallRepo.Save(context.Background(), install); err != nil {
global.LOG.Errorf("save db app install failed, err: %v", err)
return err
}
isOk = true
return nil
}
func reCreateDB(dbID uint, oldEnv string) (*model.DatabaseMysql, map[string]interface{}, error) {
mysqlService := NewIMysqlService()
ctx := context.Background()
_ = mysqlService.Delete(ctx, dto.MysqlDBDelete{ID: dbID, DeleteBackup: true, ForceDelete: true})
envMap := make(map[string]interface{})
if err := json.Unmarshal([]byte(oldEnv), &envMap); err != nil {
return nil, envMap, err
}
oldName, _ := envMap["PANEL_DB_NAME"].(string)
oldUser, _ := envMap["PANEL_DB_USER"].(string)
oldPassword, _ := envMap["PANEL_DB_USER_PASSWORD"].(string)
createDB, err := mysqlService.Create(context.Background(), dto.MysqlDBCreate{
Name: oldName,
Format: "utf8mb4",
Username: oldUser,
Password: oldPassword,
Permission: "%",
})
if err != nil {
return nil, envMap, err
}
return createDB, envMap, nil
}
+6 -6
View File
@@ -37,7 +37,7 @@ func (u *BackupService) RedisBackup() error {
timeNow := time.Now().Format("20060102150405")
fileName := fmt.Sprintf("%s.rdb", timeNow)
if appendonly == "yes" {
if strings.HasPrefix(redisInfo.Version, "6.") {
if redisInfo.Version == "6.0.16" {
fileName = fmt.Sprintf("%s.aof", timeNow)
} else {
fileName = fmt.Sprintf("%s.tar.gz", timeNow)
@@ -120,10 +120,10 @@ func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback
}
if appendonly == "yes" {
if strings.HasPrefix(redisInfo.Version, "6.") && !strings.HasSuffix(recoverFile, ".aof") {
if redisInfo.Version == "6.0.16" && !strings.HasSuffix(recoverFile, ".aof") {
return buserr.New(constant.ErrTypeOfRedis)
}
if strings.HasPrefix(redisInfo.Version, "7.") && !strings.HasSuffix(recoverFile, ".tar.gz") {
if redisInfo.Version == "7.0.5" && !strings.HasSuffix(recoverFile, ".tar.gz") {
return buserr.New(constant.ErrTypeOfRedis)
}
} else {
@@ -137,7 +137,7 @@ func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback
if !isRollback {
suffix := "rdb"
if appendonly == "yes" {
if strings.HasPrefix(redisInfo.Version, "6.") {
if redisInfo.Version == "6.0.16" {
suffix = "aof"
} else {
suffix = "tar.gz"
@@ -165,14 +165,14 @@ func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback
if _, err := compose.Down(composeDir + "/docker-compose.yml"); err != nil {
return err
}
if appendonly == "yes" && strings.HasPrefix(redisInfo.Version, "7.") {
if appendonly == "yes" && redisInfo.Version == "7.0.5" {
redisDataDir := fmt.Sprintf("%s/%s/%s/data", constant.AppInstallDir, "redis", redisInfo.Name)
if err := handleUnTar(recoverFile, redisDataDir); err != nil {
return err
}
} else {
itemName := "dump.rdb"
if appendonly == "yes" && strings.HasPrefix(redisInfo.Version, "6.") {
if appendonly == "yes" && redisInfo.Version == "6.0.16" {
itemName = "appendonly.aof"
}
input, err := os.ReadFile(recoverFile)
+5 -74
View File
@@ -6,7 +6,6 @@ import (
"errors"
"fmt"
"io"
"os"
"os/exec"
"sort"
"strconv"
@@ -40,18 +39,16 @@ type IContainerService interface {
CreateCompose(req dto.ComposeCreate) (string, error)
ComposeOperation(req dto.ComposeOperation) error
ContainerCreate(req dto.ContainerCreate) error
ContainerLogClean(req dto.OperationWithName) error
ContainerOperation(req dto.ContainerOperation) error
ContainerLogs(param dto.ContainerLog) (string, error)
ContainerStats(id string) (*dto.ContainterStats, error)
Inspect(req dto.InspectReq) (string, error)
DeleteNetwork(req dto.BatchDelete) error
CreateNetwork(req dto.NetworkCreate) error
CreateNetwork(req dto.NetworkCreat) error
DeleteVolume(req dto.BatchDelete) error
CreateVolume(req dto.VolumeCreate) error
CreateVolume(req dto.VolumeCreat) error
TestCompose(req dto.ComposeCreate) (bool, error)
ComposeUpdate(req dto.ComposeUpdate) error
Prune(req dto.ContainerPrune) (dto.ContainerPruneReport, error)
}
func NewIContainerService() IContainerService {
@@ -78,11 +75,11 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
return 0, nil, err
}
if len(req.Name) != 0 {
length, count := len(list), 0
for count < length {
lenth, count := len(list), 0
for count < lenth {
if !strings.Contains(list[count].Names[0][1:], req.Name) {
list = append(list[:count], list[(count+1):]...)
length--
lenth--
} else {
count++
}
@@ -168,51 +165,6 @@ func (u *ContainerService) Inspect(req dto.InspectReq) (string, error) {
return string(bytes), nil
}
func (u *ContainerService) Prune(req dto.ContainerPrune) (dto.ContainerPruneReport, error) {
report := dto.ContainerPruneReport{}
client, err := docker.NewDockerClient()
if err != nil {
return report, err
}
pruneFilters := filters.NewArgs()
if req.WithTagAll {
pruneFilters.Add("dangling", "false")
if req.PruneType != "image" {
pruneFilters.Add("until", "24h")
}
}
switch req.PruneType {
case "container":
rep, err := client.ContainersPrune(context.Background(), pruneFilters)
if err != nil {
return report, err
}
report.DeletedNumber = len(rep.ContainersDeleted)
report.SpaceReclaimed = int(rep.SpaceReclaimed)
case "image":
rep, err := client.ImagesPrune(context.Background(), pruneFilters)
if err != nil {
return report, err
}
report.DeletedNumber = len(rep.ImagesDeleted)
report.SpaceReclaimed = int(rep.SpaceReclaimed)
case "network":
rep, err := client.NetworksPrune(context.Background(), pruneFilters)
if err != nil {
return report, err
}
report.DeletedNumber = len(rep.NetworksDeleted)
case "volume":
rep, err := client.VolumesPrune(context.Background(), pruneFilters)
if err != nil {
return report, err
}
report.DeletedNumber = len(rep.VolumesDeleted)
report.SpaceReclaimed = int(rep.SpaceReclaimed)
}
return report, nil
}
func (u *ContainerService) ContainerCreate(req dto.ContainerCreate) error {
portMap, err := checkPortStats(req.ExposedPorts)
if err != nil {
@@ -311,27 +263,6 @@ func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error
return err
}
func (u *ContainerService) ContainerLogClean(req dto.OperationWithName) error {
client, err := docker.NewDockerClient()
if err != nil {
return err
}
container, err := client.ContainerInspect(context.Background(), req.Name)
if err != nil {
return err
}
file, err := os.OpenFile(container.LogPath, os.O_RDWR|os.O_CREATE, 0666)
if err != nil {
return err
}
defer file.Close()
if err = file.Truncate(0); err != nil {
return err
}
_, _ = file.Seek(0, 0)
return nil
}
func (u *ContainerService) ContainerLogs(req dto.ContainerLog) (string, error) {
cmd := exec.Command("docker", "logs", req.ContainerID)
if req.Mode != "all" {
+3 -3
View File
@@ -101,11 +101,11 @@ func (u *ContainerService) PageCompose(req dto.SearchWithPage) (int64, interface
records = append(records, value)
}
if len(req.Info) != 0 {
length, count := len(records), 0
for count < length {
lenth, count := len(records), 0
for count < lenth {
if !strings.Contains(records[count].Name, req.Info) {
records = append(records[:count], records[(count+1):]...)
length--
lenth--
} else {
count++
}
+4 -4
View File
@@ -24,11 +24,11 @@ func (u *ContainerService) PageNetwork(req dto.SearchWithPage) (int64, interface
return 0, nil, err
}
if len(req.Info) != 0 {
length, count := len(list), 0
for count < length {
lenth, count := len(list), 0
for count < lenth {
if !strings.Contains(list[count].Name, req.Info) {
list = append(list[:count], list[(count+1):]...)
length--
lenth--
} else {
count++
}
@@ -90,7 +90,7 @@ func (u *ContainerService) DeleteNetwork(req dto.BatchDelete) error {
}
return nil
}
func (u *ContainerService) CreateNetwork(req dto.NetworkCreate) error {
func (u *ContainerService) CreateNetwork(req dto.NetworkCreat) error {
client, err := docker.NewDockerClient()
if err != nil {
return err
+4 -4
View File
@@ -24,11 +24,11 @@ func (u *ContainerService) PageVolume(req dto.SearchWithPage) (int64, interface{
return 0, nil, err
}
if len(req.Info) != 0 {
length, count := len(list.Volumes), 0
for count < length {
lenth, count := len(list.Volumes), 0
for count < lenth {
if !strings.Contains(list.Volumes[count].Name, req.Info) {
list.Volumes = append(list.Volumes[:count], list.Volumes[(count+1):]...)
length--
lenth--
} else {
count++
}
@@ -103,7 +103,7 @@ func (u *ContainerService) DeleteVolume(req dto.BatchDelete) error {
}
return nil
}
func (u *ContainerService) CreateVolume(req dto.VolumeCreate) error {
func (u *ContainerService) CreateVolume(req dto.VolumeCreat) error {
client, err := docker.NewDockerClient()
if err != nil {
return err
+9 -15
View File
@@ -53,9 +53,9 @@ func (u *CronjobService) SearchWithPage(search dto.SearchWithPage) (int64, inter
}
record, _ := cronjobRepo.RecordFirst(cronjob.ID)
if record.ID != 0 {
item.LastRecordTime = record.StartTime.Format("2006-01-02 15:04:05")
item.LastRecrodTime = record.StartTime.Format("2006-01-02 15:04:05")
} else {
item.LastRecordTime = "-"
item.LastRecrodTime = "-"
}
dtoCronjobs = append(dtoCronjobs, item)
}
@@ -85,7 +85,7 @@ func (u *CronjobService) CleanRecord(req dto.CronjobClean) error {
if err != nil {
return err
}
if req.CleanData && (cronjob.Type == "database" || cronjob.Type == "website" || cronjob.Type == "directory") {
if req.CleanData && cronjob.Type != "shell" && cronjob.Type != "curl" {
cronjob.RetainCopies = 0
backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID)))
if err != nil {
@@ -190,6 +190,7 @@ func (u *CronjobService) StartJob(cronjob *model.Cronjob) (int, error) {
if err != nil {
return 0, err
}
global.LOG.Debug(global.Cron.Entries())
return entryID, nil
}
@@ -221,20 +222,16 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
if err != nil {
return constant.ErrRecordNotFound
}
upMap := make(map[string]interface{})
cronjob.EntryID = cronModel.EntryID
cronjob.Type = cronModel.Type
cronjob.Spec = loadSpec(cronjob)
if cronModel.Status == constant.StatusEnable {
newEntryID, err := u.StartJob(&cronjob)
if err != nil {
return err
}
upMap["entry_id"] = newEntryID
} else {
global.Cron.Remove(cron.EntryID(cronjob.EntryID))
newEntryID, err := u.StartJob(&cronjob)
if err != nil {
return err
}
upMap := make(map[string]interface{})
upMap["entry_id"] = newEntryID
upMap["name"] = req.Name
upMap["spec"] = cronjob.Spec
upMap["script"] = req.Script
@@ -243,7 +240,6 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
upMap["day"] = req.Day
upMap["hour"] = req.Hour
upMap["minute"] = req.Minute
upMap["second"] = req.Second
upMap["website"] = req.Website
upMap["exclusion_rules"] = req.ExclusionRules
upMap["db_name"] = req.DBName
@@ -326,8 +322,6 @@ func loadSpec(cronjob model.Cronjob) string {
return fmt.Sprintf("%v * * * *", cronjob.Minute)
case "perNMinute":
return fmt.Sprintf("@every %vm", cronjob.Minute)
case "perNSecond":
return fmt.Sprintf("@every %vs", cronjob.Second)
default:
return ""
}
+28 -128
View File
@@ -6,7 +6,6 @@ import (
"os"
"path"
"strings"
"sync"
"time"
"github.com/1Panel-dev/1Panel/backend/app/model"
@@ -15,8 +14,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cloud_storage"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"github.com/1Panel-dev/1Panel/backend/utils/ntp"
"github.com/pkg/errors"
)
@@ -32,31 +29,31 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
if len(cronjob.Script) == 0 {
return
}
message, err = u.handleShell(cronjob.Type, cronjob.Name, cronjob.Script)
u.HandleRmExpired("LOCAL", "", cronjob, nil)
case "curl":
if len(cronjob.URL) == 0 {
return
stdout, errExec := cmd.ExecCronjobWithTimeOut(cronjob.Script, 5*time.Minute)
if errExec != nil {
err = errExec
}
message, err = u.handleShell(cronjob.Type, cronjob.Name, fmt.Sprintf("curl '%s'", cronjob.URL))
u.HandleRmExpired("LOCAL", "", cronjob, nil)
case "ntp":
err = u.handleNtpSync()
message = []byte(stdout)
u.HandleRmExpired("LOCAL", "", cronjob, nil)
case "website":
record.File, err = u.handleBackup(cronjob, record.StartTime)
record.File, err = u.HandleBackup(cronjob, record.StartTime)
case "database":
record.File, err = u.handleBackup(cronjob, record.StartTime)
record.File, err = u.HandleBackup(cronjob, record.StartTime)
case "directory":
if len(cronjob.SourceDir) == 0 {
return
}
record.File, err = u.handleBackup(cronjob, record.StartTime)
case "cutWebsiteLog":
record.File, err = u.handleCutWebsiteLog(cronjob, record.StartTime)
if err != nil {
global.LOG.Errorf("cut website log file failed, err: %v", err)
record.File, err = u.HandleBackup(cronjob, record.StartTime)
case "curl":
if len(cronjob.URL) == 0 {
return
}
stdout, errCurl := cmd.ExecWithTimeOut("curl "+cronjob.URL, 5*time.Minute)
if err != nil {
err = errCurl
}
message = []byte(stdout)
u.HandleRmExpired("LOCAL", "", cronjob, nil)
}
if err != nil {
cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), string(message))
@@ -72,36 +69,7 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
}()
}
func (u *CronjobService) handleShell(cronType, cornName, script string) ([]byte, error) {
handleDir := fmt.Sprintf("%s/task/%s/%s", constant.DataDir, cronType, cornName)
if _, err := os.Stat(handleDir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(handleDir, os.ModePerm); err != nil {
return nil, err
}
}
stdout, err := cmd.ExecCronjobWithTimeOut(script, handleDir, 24*time.Hour)
if err != nil {
return nil, err
}
return []byte(stdout), nil
}
func (u *CronjobService) handleNtpSync() error {
ntpServer, err := settingRepo.Get(settingRepo.WithByKey("NtpSite"))
if err != nil {
return err
}
ntime, err := ntp.GetRemoteTime(ntpServer.Value)
if err != nil {
return err
}
if err := ntp.UpdateSystemTime(ntime.Format("2006-01-02 15:04:05")); err != nil {
return err
}
return nil
}
func (u *CronjobService) handleBackup(cronjob *model.Cronjob, startTime time.Time) (string, error) {
func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Time) (string, error) {
backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID)))
if err != nil {
return "", err
@@ -159,17 +127,15 @@ func (u *CronjobService) HandleRmExpired(backType, localDir string, cronjob *mod
records, _ := cronjobRepo.ListRecord(cronjobRepo.WithByJobID(int(cronjob.ID)), commonRepo.WithOrderBy("created_at desc"))
if len(records) > int(cronjob.RetainCopies) {
for i := int(cronjob.RetainCopies); i < len(records); i++ {
if len(records[i].File) != 0 {
files := strings.Split(records[i].File, ",")
for _, file := range files {
if backType != "LOCAL" {
_, _ = backClient.Delete(strings.ReplaceAll(file, localDir+"/", ""))
_ = os.Remove(file)
} else {
_ = os.Remove(file)
}
_ = backupRepo.DeleteRecord(context.TODO(), backupRepo.WithByFileName(path.Base(file)))
files := strings.Split(records[i].File, ",")
for _, file := range files {
if backType != "LOCAL" {
_, _ = backClient.Delete(strings.ReplaceAll(file, localDir+"/", ""))
_ = os.Remove(file)
} else {
_ = os.Remove(file)
}
_ = backupRepo.DeleteRecord(context.TODO(), backupRepo.WithByFileName(path.Base(file)))
}
_ = cronjobRepo.DeleteRecord(commonRepo.WithByID(uint(records[i].ID)))
@@ -185,18 +151,18 @@ func handleTar(sourceDir, targetDir, name, exclusionRules string) error {
}
}
excludes := strings.Split(exclusionRules, ",")
excludes := strings.Split(exclusionRules, ";")
excludeRules := ""
for _, exclude := range excludes {
if len(exclude) == 0 {
continue
}
excludeRules += " --exclude " + exclude
excludeRules += (" --exclude " + exclude)
}
path := ""
if strings.Contains(sourceDir, "/") {
itemDir := strings.ReplaceAll(sourceDir[strings.LastIndex(sourceDir, "/"):], "/", "")
aheadDir := sourceDir[:strings.LastIndex(sourceDir, "/")]
aheadDir := strings.ReplaceAll(sourceDir, itemDir, "")
path += fmt.Sprintf("-C %s %s", aheadDir, itemDir)
} else {
path = sourceDir
@@ -296,72 +262,6 @@ func (u *CronjobService) handleDatabase(cronjob model.Cronjob, app *repo.RootInf
return paths, nil
}
func (u *CronjobService) handleCutWebsiteLog(cronjob *model.Cronjob, startTime time.Time) (string, error) {
var (
websites []string
err error
filePaths []string
)
if cronjob.Website == "all" {
websites, _ = NewIWebsiteService().GetWebsiteOptions()
if len(websites) == 0 {
return "", nil
}
} else {
websites = append(websites, cronjob.Website)
}
nginx, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return "", nil
}
baseDir := path.Join(nginx.GetPath(), "www", "sites")
fileOp := files.NewFileOp()
var wg sync.WaitGroup
wg.Add(len(websites))
for _, websiteName := range websites {
name := websiteName
go func() {
website, _ := websiteRepo.GetFirst(websiteRepo.WithDomain(name))
if website.ID == 0 {
wg.Done()
return
}
websiteLogDir := path.Join(baseDir, website.PrimaryDomain, "log")
srcAccessLogPath := path.Join(websiteLogDir, "access.log")
srcErrorLogPath := path.Join(websiteLogDir, "error.log")
dstLogDir := path.Join(global.CONF.System.Backup, "log", "website", website.PrimaryDomain)
if !fileOp.Stat(dstLogDir) {
_ = os.MkdirAll(dstLogDir, 0755)
}
dstName := fmt.Sprintf("%s_log_%s.gz", website.PrimaryDomain, startTime.Format("20060102150405"))
filePaths = append(filePaths, path.Join(dstLogDir, dstName))
if err = fileOp.Compress([]string{srcAccessLogPath, srcErrorLogPath}, dstLogDir, dstName, files.Gz); err != nil {
global.LOG.Errorf("There was an error in compressing the website[%s] access.log", website.PrimaryDomain)
} else {
_ = fileOp.WriteFile(srcAccessLogPath, strings.NewReader(""), 0755)
_ = fileOp.WriteFile(srcErrorLogPath, strings.NewReader(""), 0755)
}
global.LOG.Infof("The website[%s] log file was successfully rotated in the directory [%s]", website.PrimaryDomain, dstLogDir)
var record model.BackupRecord
record.Type = "cutWebsiteLog"
record.Name = cronjob.Website
record.Source = "LOCAL"
record.BackupType = "LOCAL"
record.FileDir = dstLogDir
record.FileName = dstName
if err = backupRepo.CreateRecord(&record); err != nil {
global.LOG.Errorf("save backup record failed, err: %v", err)
}
wg.Done()
}()
}
wg.Wait()
u.HandleRmExpired("LOCAL", "", cronjob, nil)
return strings.Join(filePaths, ","), nil
}
func (u *CronjobService) handleWebsite(cronjob model.Cronjob, backup model.BackupAccount, startTime time.Time) ([]string, error) {
var paths []string
localDir, err := loadLocalDir()
+20 -22
View File
@@ -14,6 +14,7 @@ import (
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/app/repo"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
@@ -32,7 +33,7 @@ type IMysqlService interface {
Create(ctx context.Context, req dto.MysqlDBCreate) (*model.DatabaseMysql, error)
ChangeAccess(info dto.ChangeDBInfo) error
ChangePassword(info dto.ChangeDBInfo) error
UpdateVariables(updates []dto.MysqlVariablesUpdate) error
UpdateVariables(updatas []dto.MysqlVariablesUpdate) error
UpdateConfByFile(info dto.MysqlConfUpdateByFile) error
UpdateDescription(req dto.UpdateDescription) error
DeleteCheck(id uint) ([]string, error)
@@ -99,7 +100,7 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode
}
return nil, err
}
if err := u.createUser(app.ContainerName, app.Password, app.Version, req); err != nil {
if err := u.createUser(app, req); err != nil {
return nil, err
}
@@ -194,7 +195,7 @@ func (u *MysqlService) ChangePassword(info dto.ChangeDBInfo) error {
}
passwordChangeCMD := fmt.Sprintf("set password for '%s'@'%s' = password('%s')", mysql.Username, mysql.Permission, info.Value)
if !strings.HasPrefix(app.Version, "5.7") {
if app.Version != "5.7.39" {
passwordChangeCMD = fmt.Sprintf("ALTER USER '%s'@'%s' IDENTIFIED WITH mysql_native_password BY '%s';", mysql.Username, mysql.Permission, info.Value)
}
if info.ID != 0 {
@@ -229,7 +230,7 @@ func (u *MysqlService) ChangePassword(info dto.ChangeDBInfo) error {
for _, host := range hosts {
if host == "%" || host == "localhost" {
passwordRootChangeCMD := fmt.Sprintf("set password for 'root'@'%s' = password('%s')", host, info.Value)
if !strings.HasPrefix(app.Version, "5.7") {
if app.Version != "5.7.39" {
passwordRootChangeCMD = fmt.Sprintf("alter user 'root'@'%s' identified with mysql_native_password BY '%s';", host, info.Value)
}
if err := excuteSql(app.ContainerName, app.Password, passwordRootChangeCMD); err != nil {
@@ -290,7 +291,7 @@ func (u *MysqlService) ChangeAccess(info dto.ChangeDBInfo) error {
}
}
if err := u.createUser(app.ContainerName, app.Password, app.Version, dto.MysqlDBCreate{
if err := u.createUser(app, dto.MysqlDBCreate{
Username: mysql.Username,
Name: mysql.Name,
Permission: info.Value,
@@ -330,7 +331,7 @@ func (u *MysqlService) UpdateConfByFile(info dto.MysqlConfUpdateByFile) error {
return nil
}
func (u *MysqlService) UpdateVariables(updates []dto.MysqlVariablesUpdate) error {
func (u *MysqlService) UpdateVariables(updatas []dto.MysqlVariablesUpdate) error {
app, err := appInstallRepo.LoadBaseInfo("mysql", "")
if err != nil {
return err
@@ -345,8 +346,8 @@ func (u *MysqlService) UpdateVariables(updates []dto.MysqlVariablesUpdate) error
files = strings.Split(string(lineBytes), "\n")
group := "[mysqld]"
for _, info := range updates {
if !strings.HasPrefix(app.Version, "5.7") {
for _, info := range updatas {
if app.Version != "5.7.39" {
if info.Param == "query_cache_size" {
continue
}
@@ -469,7 +470,7 @@ func (u *MysqlService) LoadStatus() (*dto.MysqlStatus, error) {
return &info, nil
}
func (u *MysqlService) createUser(container, password, version string, req dto.MysqlDBCreate) error {
func (u *MysqlService) createUser(app *repo.RootInfo, req dto.MysqlDBCreate) error {
var userlist []string
if strings.Contains(req.Permission, ",") {
ips := strings.Split(req.Permission, ",")
@@ -483,35 +484,32 @@ func (u *MysqlService) createUser(container, password, version string, req dto.M
}
for _, user := range userlist {
if err := excSQL(container, password, fmt.Sprintf("create user %s identified by '%s';", user, req.Password)); err != nil {
if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("create user %s identified by '%s';", user, req.Password)); err != nil {
handleCreateError(req.Name, userlist, app)
if strings.Contains(err.Error(), "ERROR 1396") {
handleCreateError(container, password, req.Name, userlist, false)
return buserr.New(constant.ErrUserIsExist)
}
handleCreateError(container, password, req.Name, userlist, true)
return err
}
grantStr := fmt.Sprintf("grant all privileges on `%s`.* to %s", req.Name, user)
if req.Name == "*" {
grantStr = fmt.Sprintf("grant all privileges on *.* to %s", user)
}
if strings.HasPrefix(version, "5.7") {
if app.Version == "5.7.39" {
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, req.Password)
}
if err := excSQL(container, password, grantStr); err != nil {
handleCreateError(container, password, req.Name, userlist, true)
if err := excSQL(app.ContainerName, app.Password, grantStr); err != nil {
handleCreateError(req.Name, userlist, app)
return err
}
}
return nil
}
func handleCreateError(contaienr, password, dbName string, userlist []string, dropUser bool) {
_ = excSQL(contaienr, password, fmt.Sprintf("drop database `%s`", dbName))
if dropUser {
for _, user := range userlist {
if err := excSQL(contaienr, password, fmt.Sprintf("drop user if exists %s", user)); err != nil {
global.LOG.Errorf("drop user failed, err: %v", err)
}
func handleCreateError(dbName string, userlist []string, app *repo.RootInfo) {
_ = excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop database `%s`", dbName))
for _, user := range userlist {
if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop user if exists %s", user)); err != nil {
global.LOG.Errorf("drop user failed, err: %v", err)
}
}
}
+67 -172
View File
@@ -4,7 +4,6 @@ import (
"bufio"
"context"
"encoding/json"
"fmt"
"os"
"path"
"strings"
@@ -19,8 +18,7 @@ import (
type DockerService struct{}
type IDockerService interface {
UpdateConf(req dto.SettingUpdate) error
UpdateLogOption(req dto.LogOption) error
UpdateConf(req dto.DaemonJsonConf) error
UpdateConfByFile(info dto.DaemonJsonUpdateByFile) error
LoadDockerStatus() string
LoadDockerConf() *dto.DaemonJsonConf
@@ -32,54 +30,46 @@ func NewIDockerService() IDockerService {
}
type daemonJsonItem struct {
Status string `json:"status"`
Mirrors []string `json:"registry-mirrors"`
Registries []string `json:"insecure-registries"`
LiveRestore bool `json:"live-restore"`
IPTables bool `json:"iptables"`
ExecOpts []string `json:"exec-opts"`
LogOption logOption `json:"log-opts"`
}
type logOption struct {
LogMaxSize string `json:"max-size"`
LogMaxFile string `json:"max-file"`
Status string `json:"status"`
Mirrors []string `json:"registry-mirrors"`
Registries []string `json:"insecure-registries"`
LiveRestore bool `json:"live-restore"`
IPTables bool `json:"iptables"`
ExecOpts []string `json:"exec-opts"`
}
func (u *DockerService) LoadDockerStatus() string {
client, err := docker.NewDockerClient()
if err != nil {
return constant.Stopped
}
if _, err := client.Ping(context.Background()); err != nil {
return constant.Stopped
status := constant.StatusRunning
stdout, err := cmd.Exec("systemctl is-active docker")
if string(stdout) != "active\n" || err != nil {
status = constant.Stopped
}
return constant.StatusRunning
return status
}
func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf {
ctx := context.Background()
var data dto.DaemonJsonConf
data.IPTables = true
data.Status = constant.StatusRunning
data.Version = "-"
client, err := docker.NewDockerClient()
if err != nil {
stdout, err := cmd.Exec("systemctl is-active docker")
if string(stdout) != "active\n" || err != nil {
data.Status = constant.Stopped
} else {
if _, err := client.Ping(ctx); err != nil {
data.Status = constant.Stopped
}
itemVersion, err := client.ServerVersion(ctx)
if err == nil {
data.Version = itemVersion.Version
}
}
data.IsSwarm = false
stdout2, _ := cmd.Exec("docker info | grep Swarm")
if string(stdout2) == " Swarm: active\n" {
data.IsSwarm = true
}
data.Version = "-"
client, err := docker.NewDockerClient()
if err == nil {
ctx := context.Background()
itemVersion, err := client.ServerVersion(ctx)
if err == nil {
data.Version = itemVersion.Version
}
}
if _, err := os.Stat(constant.DaemonJsonPath); err != nil {
return &data
}
@@ -88,19 +78,18 @@ func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf {
return &data
}
var conf daemonJsonItem
daemonMap := make(map[string]interface{})
if err := json.Unmarshal(file, &daemonMap); err != nil {
deamonMap := make(map[string]interface{})
if err := json.Unmarshal(file, &deamonMap); err != nil {
return &data
}
arr, err := json.Marshal(daemonMap)
arr, err := json.Marshal(deamonMap)
if err != nil {
return &data
}
if err := json.Unmarshal(arr, &conf); err != nil {
fmt.Println(err)
return &data
}
if _, ok := daemonMap["iptables"]; !ok {
if _, ok := deamonMap["iptables"]; !ok {
conf.IPTables = true
}
data.CgroupDriver = "cgroupfs"
@@ -110,8 +99,6 @@ func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf {
break
}
}
data.LogMaxSize = conf.LogOption.LogMaxSize
data.LogMaxFile = conf.LogOption.LogMaxFile
data.Mirrors = conf.Mirrors
data.Registries = conf.Registries
data.IPTables = conf.IPTables
@@ -119,7 +106,7 @@ func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf {
return &data
}
func (u *DockerService) UpdateConf(req dto.SettingUpdate) error {
func (u *DockerService) UpdateConf(req dto.DaemonJsonConf) error {
if _, err := os.Stat(constant.DaemonJsonPath); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(path.Dir(constant.DaemonJsonPath), os.ModePerm); err != nil {
return err
@@ -131,96 +118,50 @@ func (u *DockerService) UpdateConf(req dto.SettingUpdate) error {
if err != nil {
return err
}
daemonMap := make(map[string]interface{})
_ = json.Unmarshal(file, &daemonMap)
deamonMap := make(map[string]interface{})
_ = json.Unmarshal(file, &deamonMap)
switch req.Key {
case "Registries":
if len(req.Value) == 0 {
delete(daemonMap, "insecure-registries")
} else {
daemonMap["insecure-registries"] = strings.Split(req.Value, ",")
}
case "Mirrors":
if len(req.Value) == 0 {
delete(daemonMap, "registry-mirrors")
} else {
daemonMap["registry-mirrors"] = strings.Split(req.Value, ",")
}
case "LogOption":
if req.Value == "disable" {
delete(daemonMap, "log-opts")
}
case "LiveRestore":
if req.Value == "disable" {
delete(daemonMap, "live-restore")
} else {
daemonMap["live-restore"] = true
}
case "IPtables":
if req.Value == "enable" {
delete(daemonMap, "iptables")
} else {
daemonMap["iptables"] = false
}
case "Dirver":
if opts, ok := daemonMap["exec-opts"]; ok {
if optsValue, isArray := opts.([]interface{}); isArray {
for i := 0; i < len(optsValue); i++ {
if opt, isStr := optsValue[i].(string); isStr {
if strings.HasPrefix(opt, "native.cgroupdriver=") {
optsValue[i] = "native.cgroupdriver=" + req.Value
break
}
if len(req.Registries) == 0 {
delete(deamonMap, "insecure-registries")
} else {
deamonMap["insecure-registries"] = req.Registries
}
if len(req.Mirrors) == 0 {
delete(deamonMap, "registry-mirrors")
} else {
deamonMap["registry-mirrors"] = req.Mirrors
}
if !req.LiveRestore {
delete(deamonMap, "live-restore")
} else {
deamonMap["live-restore"] = req.LiveRestore
}
if req.IPTables {
delete(deamonMap, "iptables")
} else {
deamonMap["iptables"] = false
}
if opts, ok := deamonMap["exec-opts"]; ok {
if optsValue, isArray := opts.([]interface{}); isArray {
for i := 0; i < len(optsValue); i++ {
if opt, isStr := optsValue[i].(string); isStr {
if strings.HasPrefix(opt, "native.cgroupdriver=") {
optsValue[i] = "native.cgroupdriver=" + req.CgroupDriver
break
}
}
}
} else {
if req.Value == "systemd" {
daemonMap["exec-opts"] = []string{"native.cgroupdriver=systemd"}
}
}
} else {
if req.CgroupDriver == "systemd" {
deamonMap["exec-opts"] = []string{"native.cgroupdriver=systemd"}
}
}
if len(daemonMap) == 0 {
if len(deamonMap) == 0 {
_ = os.Remove(constant.DaemonJsonPath)
return nil
}
newJson, err := json.MarshalIndent(daemonMap, "", "\t")
if err != nil {
return err
}
if err := os.WriteFile(constant.DaemonJsonPath, newJson, 0640); err != nil {
return err
}
stdout, err := cmd.Exec("systemctl restart docker")
if err != nil {
return errors.New(string(stdout))
}
return nil
}
func (u *DockerService) UpdateLogOption(req dto.LogOption) error {
if _, err := os.Stat(constant.DaemonJsonPath); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(path.Dir(constant.DaemonJsonPath), os.ModePerm); err != nil {
return err
}
_, _ = os.Create(constant.DaemonJsonPath)
}
file, err := os.ReadFile(constant.DaemonJsonPath)
if err != nil {
return err
}
daemonMap := make(map[string]interface{})
_ = json.Unmarshal(file, &daemonMap)
changeLogOption(daemonMap, req.LogMaxFile, req.LogMaxSize)
if len(daemonMap) == 0 {
_ = os.Remove(constant.DaemonJsonPath)
return nil
}
newJson, err := json.MarshalIndent(daemonMap, "", "\t")
newJson, err := json.MarshalIndent(deamonMap, "", "\t")
if err != nil {
return err
}
@@ -265,7 +206,10 @@ func (u *DockerService) UpdateConfByFile(req dto.DaemonJsonUpdateByFile) error {
func (u *DockerService) OperateDocker(req dto.DockerOperation) error {
service := "docker"
if req.Operation == "stop" {
service = "docker.socket"
service = "docker.service"
if req.StopSocket {
service = "docker.socket"
}
}
stdout, err := cmd.Execf("systemctl %s %s ", req.Operation, service)
if err != nil {
@@ -273,52 +217,3 @@ func (u *DockerService) OperateDocker(req dto.DockerOperation) error {
}
return nil
}
func changeLogOption(daemonMap map[string]interface{}, logMaxFile, logMaxSize string) {
if opts, ok := daemonMap["log-opts"]; ok {
if len(logMaxFile) != 0 || len(logMaxSize) != 0 {
daemonMap["log-driver"] = "json-file"
}
optsMap, isMap := opts.(map[string]interface{})
if isMap {
if len(logMaxFile) != 0 {
optsMap["max-file"] = logMaxFile
} else {
delete(optsMap, "max-file")
}
if len(logMaxSize) != 0 {
optsMap["max-size"] = logMaxSize
} else {
delete(optsMap, "max-size")
}
if len(optsMap) == 0 {
delete(daemonMap, "log-opts")
}
} else {
optsMap := make(map[string]interface{})
if len(logMaxFile) != 0 {
optsMap["max-file"] = logMaxFile
}
if len(logMaxSize) != 0 {
optsMap["max-size"] = logMaxSize
}
if len(optsMap) != 0 {
daemonMap["log-opts"] = optsMap
}
}
} else {
if len(logMaxFile) != 0 || len(logMaxSize) != 0 {
daemonMap["log-driver"] = "json-file"
}
optsMap := make(map[string]interface{})
if len(logMaxFile) != 0 {
optsMap["max-file"] = logMaxFile
}
if len(logMaxSize) != 0 {
optsMap["max-size"] = logMaxSize
}
if len(optsMap) != 0 {
daemonMap["log-opts"] = optsMap
}
}
}
+15 -11
View File
@@ -27,7 +27,7 @@ type IFirewallService interface {
OperateAddressRule(req dto.AddrRuleOperate, reload bool) error
UpdatePortRule(req dto.PortRuleUpdate) error
UpdateAddrRule(req dto.AddrRuleUpdate) error
BatchOperateRule(req dto.BatchRuleOperate) error
BacthOperateRule(req dto.BatchRuleOperate) error
}
func NewIFirewallService() IFirewallService {
@@ -276,7 +276,7 @@ func (u *FirewallService) UpdateAddrRule(req dto.AddrRuleUpdate) error {
return client.Reload()
}
func (u *FirewallService) BatchOperateRule(req dto.BatchRuleOperate) error {
func (u *FirewallService) BacthOperateRule(req dto.BatchRuleOperate) error {
client, err := firewall.NewFirewallClient()
if err != nil {
return err
@@ -368,16 +368,18 @@ func (u *FirewallService) pingStatus() string {
if _, err := os.Stat("/etc/sysctl.conf"); err != nil {
return constant.StatusNone
}
sudo := cmd.SudoHandleCmd()
command := fmt.Sprintf("%s cat /etc/sysctl.conf | grep net/ipv4/icmp_echo_ignore_all= ", sudo)
stdout, _ := cmd.Exec(command)
commond := "cat /etc/sysctl.conf | grep net/ipv4/icmp_echo_ignore_all= "
if cmd.HasNoPasswordSudo() {
commond = "sudo cat /etc/sysctl.conf | grep net/ipv4/icmp_echo_ignore_all= "
}
stdout, _ := cmd.Exec(commond)
if stdout == "net/ipv4/icmp_echo_ignore_all=1\n" {
return constant.StatusEnable
}
return constant.StatusDisable
}
func (u *FirewallService) updatePingStatus(enable string) error {
func (u *FirewallService) updatePingStatus(enabel string) error {
lineBytes, err := os.ReadFile(confPath)
if err != nil {
return err
@@ -387,14 +389,14 @@ func (u *FirewallService) updatePingStatus(enable string) error {
hasLine := false
for _, line := range files {
if strings.Contains(line, "net/ipv4/icmp_echo_ignore_all") || strings.HasPrefix(line, "net/ipv4/icmp_echo_ignore_all") {
newFiles = append(newFiles, "net/ipv4/icmp_echo_ignore_all="+enable)
newFiles = append(newFiles, "net/ipv4/icmp_echo_ignore_all="+enabel)
hasLine = true
} else {
newFiles = append(newFiles, line)
}
}
if !hasLine {
newFiles = append(newFiles, "net/ipv4/icmp_echo_ignore_all="+enable)
newFiles = append(newFiles, "net/ipv4/icmp_echo_ignore_all="+enabel)
}
file, err := os.OpenFile(confPath, os.O_WRONLY|os.O_TRUNC, 0666)
if err != nil {
@@ -406,9 +408,11 @@ func (u *FirewallService) updatePingStatus(enable string) error {
return err
}
sudo := cmd.SudoHandleCmd()
command := fmt.Sprintf("%s sysctl -p", sudo)
stdout, err := cmd.Exec(command)
commond := "sysctl -p"
if cmd.HasNoPasswordSudo() {
commond = "sudo sysctl -p"
}
stdout, err := cmd.Exec(commond)
if err != nil {
return fmt.Errorf("update ping status failed, err: %v", stdout)
}
+18 -24
View File
@@ -50,11 +50,9 @@ func (u *ImageRepoService) Login(req dto.OperateByID) error {
if err != nil {
return err
}
if repo.Auth {
if err := u.CheckConn(repo.DownloadUrl, repo.Username, repo.Password); err != nil {
_ = imageRepoRepo.Update(repo.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
return err
}
if err := u.CheckConn(repo.DownloadUrl, repo.Username, repo.Password); err != nil {
_ = imageRepoRepo.Update(repo.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error})
return err
}
_ = imageRepoRepo.Update(repo.ID, map[string]interface{}{"status": constant.StatusSuccess})
return nil
@@ -87,12 +85,12 @@ func (u *ImageRepoService) Create(req dto.ImageRepoCreate) error {
return errors.New(string(stdout))
}
ticker := time.NewTicker(3 * time.Second)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
ctx, cancle := context.WithTimeout(context.Background(), time.Second*20)
if err := func() error {
for range ticker.C {
select {
case <-ctx.Done():
cancel()
cancle()
return errors.New("the docker service cannot be restarted")
default:
stdout, err := cmd.Exec("systemctl is-active docker")
@@ -113,11 +111,9 @@ func (u *ImageRepoService) Create(req dto.ImageRepoCreate) error {
}
imageRepo.Status = constant.StatusSuccess
if req.Auth {
if err := u.CheckConn(req.DownloadUrl, req.Username, req.Password); err != nil {
imageRepo.Status = constant.StatusFailed
imageRepo.Message = err.Error()
}
if err := u.CheckConn(req.DownloadUrl, req.Username, req.Password); err != nil {
imageRepo.Status = constant.StatusFailed
imageRepo.Message = err.Error()
}
if err := imageRepoRepo.Create(&imageRepo); err != nil {
return err
@@ -146,7 +142,7 @@ func (u *ImageRepoService) Update(req dto.ImageRepoUpdate) error {
if err != nil {
return err
}
if repo.DownloadUrl != req.DownloadUrl || (!repo.Auth && req.Auth) {
if repo.DownloadUrl != req.DownloadUrl {
_ = u.handleRegistries(req.DownloadUrl, repo.DownloadUrl, "update")
if repo.Auth {
_, _ = cmd.Execf("docker logout %s", repo.DownloadUrl)
@@ -166,11 +162,9 @@ func (u *ImageRepoService) Update(req dto.ImageRepoUpdate) error {
upMap["status"] = constant.StatusSuccess
upMap["message"] = ""
if req.Auth {
if err := u.CheckConn(req.DownloadUrl, req.Username, req.Password); err != nil {
upMap["status"] = constant.StatusFailed
upMap["message"] = err.Error()
}
if err := u.CheckConn(req.DownloadUrl, req.Username, req.Password); err != nil {
upMap["status"] = constant.StatusFailed
upMap["message"] = err.Error()
}
return imageRepoRepo.Update(req.ID, upMap)
}
@@ -194,16 +188,16 @@ func (u *ImageRepoService) handleRegistries(newHost, delHost, handle string) err
_, _ = os.Create(constant.DaemonJsonPath)
}
daemonMap := make(map[string]interface{})
deamonMap := make(map[string]interface{})
file, err := os.ReadFile(constant.DaemonJsonPath)
if err != nil {
return err
}
if err := json.Unmarshal(file, &daemonMap); err != nil {
if err := json.Unmarshal(file, &deamonMap); err != nil {
return err
}
iRegistries := daemonMap["insecure-registries"]
iRegistries := deamonMap["insecure-registries"]
registries, _ := iRegistries.([]interface{})
switch handle {
case "create":
@@ -223,11 +217,11 @@ func (u *ImageRepoService) handleRegistries(newHost, delHost, handle string) err
}
}
if len(registries) == 0 {
delete(daemonMap, "insecure-registries")
delete(deamonMap, "insecure-registries")
} else {
daemonMap["insecure-registries"] = registries
deamonMap["insecure-registries"] = registries
}
newJson, err := json.MarshalIndent(daemonMap, "", "\t")
newJson, err := json.MarshalIndent(deamonMap, "", "\t")
if err != nil {
return err
}
+1 -7
View File
@@ -64,13 +64,7 @@ func (r *RuntimeService) Create(create request.RuntimeCreate) (err error) {
return err
}
fileOp := files.NewFileOp()
appVersionDir := path.Join(constant.AppResourceDir, app.Resource, app.Key, appDetail.Version)
if !fileOp.Stat(appVersionDir) {
if err := downloadApp(app, appDetail, nil); err != nil {
return err
}
}
buildDir := path.Join(appVersionDir, "build")
buildDir := path.Join(constant.AppResourceDir, app.Key, "versions", appDetail.Version, "build")
if !fileOp.Stat(buildDir) {
return buserr.New(constant.ErrDirNotFound)
}
+6 -77
View File
@@ -19,24 +19,20 @@ import (
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"github.com/1Panel-dev/1Panel/backend/utils/ntp"
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
"github.com/gin-gonic/gin"
"github.com/robfig/cron/v3"
)
type SettingService struct{}
type ISettingService interface {
GetSettingInfo() (*dto.SettingInfo, error)
LoadTimeZone() ([]string, error)
Update(key, value string) error
UpdatePassword(c *gin.Context, old, new string) error
UpdatePort(port uint) error
UpdateSSL(c *gin.Context, req dto.SSLUpdate) error
LoadFromCert() (*dto.SSLInfo, error)
HandlePasswordExpired(c *gin.Context, old, new string) error
SyncTime(req dto.SyncTime) error
}
func NewISettingService() ISettingService {
@@ -64,86 +60,19 @@ func (u *SettingService) GetSettingInfo() (*dto.SettingInfo, error) {
return &info, err
}
func (u *SettingService) LoadTimeZone() ([]string, error) {
std, err := cmd.Exec("timedatectl list-timezones")
if err != nil {
return []string{}, nil
}
return strings.Split(std, "\n"), err
}
func (u *SettingService) Update(key, value string) error {
switch key {
case "MonitorStatus":
if value == "enable" && global.MonitorCronID == 0 {
interval, err := settingRepo.Get(settingRepo.WithByKey("MonitorInterval"))
if err != nil {
return err
}
if err := StartMonitor(false, interval.Value); err != nil {
return err
}
}
if value == "disable" && global.MonitorCronID != 0 {
global.Cron.Remove(cron.EntryID(global.MonitorCronID))
global.MonitorCronID = 0
}
case "MonitorInterval":
status, err := settingRepo.Get(settingRepo.WithByKey("MonitorStatus"))
if err != nil {
return err
}
if status.Value == "enable" && global.MonitorCronID != 0 {
if err := StartMonitor(true, value); err != nil {
return err
}
}
case "TimeZone":
if err := ntp.UpdateSystemTimeZone(value); err != nil {
return err
}
}
if err := settingRepo.Update(key, value); err != nil {
return err
}
switch key {
case "ExpirationDays":
if key == "ExpirationDays" {
timeout, _ := strconv.Atoi(value)
if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format("2006-01-02 15:04:05")); err != nil {
return err
}
case "TimeZone":
go func() {
_, err := cmd.Exec("systemctl restart 1panel.service")
if err != nil {
global.LOG.Errorf("restart system for new time zone failed, err: %v", err)
}
}()
case "BindDomain":
if len(value) != 0 {
_ = global.SESSION.Clean()
}
case "UserName", "Password":
}
if err := settingRepo.Update(key, value); err != nil {
return err
}
if key == "UserName" {
_ = global.SESSION.Clean()
}
return nil
}
func (u *SettingService) SyncTime(req dto.SyncTime) error {
if err := settingRepo.Update("NtpSite", req.NtpSite); err != nil {
return err
}
ntime, err := ntp.GetRemoteTime(req.NtpSite)
if err != nil {
return err
}
ts := ntime.Format("2006-01-02 15:04:05")
if err := ntp.UpdateSystemTime(ts); err != nil {
return err
}
return nil
}
+10 -10
View File
@@ -93,7 +93,7 @@ func (u *SnapshotService) UpdateDescription(req dto.UpdateDescription) error {
type SnapshotJson struct {
OldBaseDir string `json:"oldBaseDir"`
OldDockerDataDir string `json:"oldDockerDataDir"`
OldBackupDataDir string `json:"oldBackupDataDir"`
OldBackupDataDir string `json:"oldDackupDataDir"`
OldPanelDataDir string `json:"oldPanelDataDir"`
BaseDir string `json:"baseDir"`
@@ -113,7 +113,7 @@ func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
if err != nil {
return err
}
backupAccount, err := NewIBackupService().NewClient(&backup)
backupAccont, err := NewIBackupService().NewClient(&backup)
if err != nil {
return err
}
@@ -202,7 +202,7 @@ func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
global.LOG.Infof("start to upload snapshot to %s, please wait", backup.Type)
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusUploading})
localPath := fmt.Sprintf("%s/system/1panel_%s_%s.tar.gz", localDir, versionItem.Value, timeNow)
if ok, err := backupAccount.Upload(localPath, fmt.Sprintf("system_snapshot/1panel_%s_%s.tar.gz", versionItem.Value, timeNow)); err != nil || !ok {
if ok, err := backupAccont.Upload(localPath, fmt.Sprintf("system_snapshot/1panel_%s_%s.tar.gz", versionItem.Value, timeNow)); err != nil || !ok {
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
global.LOG.Errorf("upload snapshot to %s failed, err: %v", backup.Type, err)
return
@@ -796,15 +796,15 @@ func (u *SnapshotService) updateLiveRestore(enabled bool) error {
if err != nil {
return err
}
daemonMap := make(map[string]interface{})
_ = json.Unmarshal(file, &daemonMap)
deamonMap := make(map[string]interface{})
_ = json.Unmarshal(file, &deamonMap)
if !enabled {
delete(daemonMap, "live-restore")
delete(deamonMap, "live-restore")
} else {
daemonMap["live-restore"] = enabled
deamonMap["live-restore"] = enabled
}
newJson, err := json.MarshalIndent(daemonMap, "", "\t")
newJson, err := json.MarshalIndent(deamonMap, "", "\t")
if err != nil {
return err
}
@@ -818,8 +818,8 @@ func (u *SnapshotService) updateLiveRestore(enabled bool) error {
}
ticker := time.NewTicker(3 * time.Second)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
ctx, cancle := context.WithTimeout(context.Background(), time.Second*30)
defer cancle()
for range ticker.C {
select {
case <-ctx.Done():
-425
View File
@@ -1,425 +0,0 @@
package service
import (
"fmt"
"os"
"os/user"
"path"
"path/filepath"
"sort"
"strings"
"time"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"github.com/1Panel-dev/1Panel/backend/utils/qqwry"
)
const sshPath = "/etc/ssh/sshd_config"
type SSHService struct{}
type ISSHService interface {
GetSSHInfo() (*dto.SSHInfo, error)
OperateSSH(operation string) error
UpdateByFile(value string) error
Update(key, value string) error
GenerateSSH(req dto.GenerateSSH) error
LoadSSHSecret(mode string) (string, error)
LoadLog(req dto.SearchSSHLog) (*dto.SSHLog, error)
}
func NewISSHService() ISSHService {
return &SSHService{}
}
func (u *SSHService) GetSSHInfo() (*dto.SSHInfo, error) {
data := dto.SSHInfo{
Status: constant.StatusEnable,
Message: "",
Port: "22",
ListenAddress: "0.0.0.0",
PasswordAuthentication: "yes",
PubkeyAuthentication: "yes",
PermitRootLogin: "yes",
UseDNS: "yes",
}
sudo := cmd.SudoHandleCmd()
stdout, err := cmd.Execf("%s systemctl status sshd", sudo)
if err != nil {
data.Message = stdout
data.Status = constant.StatusDisable
}
stdLines := strings.Split(stdout, "\n")
for _, stdline := range stdLines {
if strings.Contains(stdline, "active (running)") {
data.Status = constant.StatusEnable
break
}
}
sshConf, err := os.ReadFile(sshPath)
if err != nil {
data.Message = err.Error()
data.Status = constant.StatusDisable
}
lines := strings.Split(string(sshConf), "\n")
for _, line := range lines {
if strings.HasPrefix(line, "Port ") {
data.Port = strings.ReplaceAll(line, "Port ", "")
}
if strings.HasPrefix(line, "ListenAddress ") {
data.ListenAddress = strings.ReplaceAll(line, "ListenAddress ", "")
}
if strings.HasPrefix(line, "PasswordAuthentication ") {
data.PasswordAuthentication = strings.ReplaceAll(line, "PasswordAuthentication ", "")
}
if strings.HasPrefix(line, "PubkeyAuthentication ") {
data.PubkeyAuthentication = strings.ReplaceAll(line, "PubkeyAuthentication ", "")
}
if strings.HasPrefix(line, "PermitRootLogin ") {
data.PermitRootLogin = strings.ReplaceAll(line, "PermitRootLogin ", "")
}
if strings.HasPrefix(line, "UseDNS ") {
data.UseDNS = strings.ReplaceAll(line, "UseDNS ", "")
}
}
return &data, nil
}
func (u *SSHService) OperateSSH(operation string) error {
if operation == "start" || operation == "stop" || operation == "restart" {
sudo := cmd.SudoHandleCmd()
stdout, err := cmd.Execf("%s systemctl %s sshd", sudo, operation)
if err != nil {
return fmt.Errorf("%s sshd failed, stdout: %s, err: %v", operation, stdout, err)
}
return nil
}
return fmt.Errorf("not support such operation: %s", operation)
}
func (u *SSHService) Update(key, value string) error {
sshConf, err := os.ReadFile(sshPath)
if err != nil {
return err
}
lines := strings.Split(string(sshConf), "\n")
newFiles := updateSSHConf(lines, key, value)
if err := settingRepo.Update(key, value); err != nil {
return err
}
file, err := os.OpenFile(sshPath, os.O_WRONLY|os.O_TRUNC, 0666)
if err != nil {
return err
}
defer file.Close()
if _, err = file.WriteString(strings.Join(newFiles, "\n")); err != nil {
return err
}
sudo := cmd.SudoHandleCmd()
if key == "Port" {
stdout, _ := cmd.Execf("%s getenforce", sudo)
if stdout == "Enforcing\n" {
_, _ = cmd.Execf("%s semanage port -a -t ssh_port_t -p tcp %s", sudo, value)
}
}
_, _ = cmd.Execf("%s systemctl restart sshd", sudo)
return nil
}
func (u *SSHService) UpdateByFile(value string) error {
file, err := os.OpenFile(sshPath, os.O_WRONLY|os.O_TRUNC, 0666)
if err != nil {
return err
}
defer file.Close()
if _, err = file.WriteString(value); err != nil {
return err
}
sudo := cmd.SudoHandleCmd()
_, _ = cmd.Execf("%s systemctl restart sshd", sudo)
return nil
}
func (u *SSHService) GenerateSSH(req dto.GenerateSSH) error {
currentUser, err := user.Current()
if err != nil {
return fmt.Errorf("load current user failed, err: %v", err)
}
secretFile := fmt.Sprintf("%s/.ssh/id_item_%s", currentUser.HomeDir, req.EncryptionMode)
secretPubFile := fmt.Sprintf("%s/.ssh/id_item_%s.pub", currentUser.HomeDir, req.EncryptionMode)
authFile := currentUser.HomeDir + "/.ssh/authorized_keys"
command := fmt.Sprintf("ssh-keygen -t %s -f %s/.ssh/id_item_%s | echo y", req.EncryptionMode, currentUser.HomeDir, req.EncryptionMode)
if len(req.Password) != 0 {
command = fmt.Sprintf("ssh-keygen -t %s -P %s -f %s/.ssh/id_item_%s | echo y", req.EncryptionMode, req.Password, currentUser.HomeDir, req.EncryptionMode)
}
stdout, err := cmd.Exec(command)
if err != nil {
return fmt.Errorf("generate failed, err: %v, message: %s", err, stdout)
}
defer func() {
_ = os.Remove(secretFile)
}()
defer func() {
_ = os.Remove(secretPubFile)
}()
if _, err := os.Stat(authFile); err != nil {
_, _ = os.Create(authFile)
}
stdout1, err := cmd.Execf("cat %s >> %s/.ssh/authorized_keys", secretPubFile, currentUser.HomeDir)
if err != nil {
return fmt.Errorf("generate failed, err: %v, message: %s", err, stdout1)
}
fileOp := files.NewFileOp()
if err := fileOp.Rename(secretFile, fmt.Sprintf("%s/.ssh/id_%s", currentUser.HomeDir, req.EncryptionMode)); err != nil {
return err
}
if err := fileOp.Rename(secretPubFile, fmt.Sprintf("%s/.ssh/id_%s.pub", currentUser.HomeDir, req.EncryptionMode)); err != nil {
return err
}
return nil
}
func (u *SSHService) LoadSSHSecret(mode string) (string, error) {
currentUser, err := user.Current()
if err != nil {
return "", fmt.Errorf("load current user failed, err: %v", err)
}
homeDir := currentUser.HomeDir
if _, err := os.Stat(fmt.Sprintf("%s/.ssh/id_%s", homeDir, mode)); err != nil {
return "", nil
}
file, err := os.ReadFile(fmt.Sprintf("%s/.ssh/id_%s", homeDir, mode))
return string(file), err
}
func (u *SSHService) LoadLog(req dto.SearchSSHLog) (*dto.SSHLog, error) {
var fileList []string
var data dto.SSHLog
baseDir := "/var/log"
if err := filepath.Walk(baseDir, func(pathItem string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() && strings.HasPrefix(info.Name(), "secure") || strings.HasPrefix(info.Name(), "auth") {
if strings.HasSuffix(info.Name(), ".gz") {
if err := handleGunzip(pathItem); err == nil {
fileList = append(fileList, strings.ReplaceAll(pathItem, ".gz", ""))
}
} else {
fileList = append(fileList, pathItem)
}
}
return nil
}); err != nil {
return nil, err
}
fileList = sortFileList(fileList)
command := ""
if len(req.Info) != 0 {
command = fmt.Sprintf(" | grep '%s'", req.Info)
}
for i := 0; i < len(fileList); i++ {
if strings.HasPrefix(path.Base(fileList[i]), "secure") {
commandItem := fmt.Sprintf("cat %s | grep -a 'Failed password for' | grep -v 'invalid' %s", fileList[i], command)
dataItem := loadFailedSecureDatas(commandItem)
data.FailedCount += len(dataItem)
data.TotalCount += len(dataItem)
if req.Status != constant.StatusSuccess {
data.Logs = append(data.Logs, dataItem...)
}
}
if strings.HasPrefix(path.Base(fileList[i]), "auth.log") {
commandItem := fmt.Sprintf("cat %s | grep -a 'Connection closed by authenticating user' | grep -a 'preauth' %s", fileList[i], command)
dataItem := loadFailedAuthDatas(commandItem)
data.FailedCount += len(dataItem)
data.TotalCount += len(dataItem)
if req.Status != constant.StatusSuccess {
data.Logs = append(data.Logs, dataItem...)
}
}
commandItem := fmt.Sprintf("cat %s | grep -a Accepted %s", fileList[i], command)
dataItem := loadSuccessDatas(commandItem)
data.TotalCount += len(dataItem)
if req.Status != constant.StatusFailed {
data.Logs = append(data.Logs, dataItem...)
}
}
data.SuccessfulCount = data.TotalCount - data.FailedCount
if len(data.Logs) < 1 {
return nil, nil
}
var itemDatas []dto.SSHHistory
total, start, end := len(data.Logs), (req.Page-1)*req.PageSize, req.Page*req.PageSize
if start > total {
itemDatas = make([]dto.SSHHistory, 0)
} else {
if end >= total {
end = total
}
itemDatas = data.Logs[start:end]
}
data.Logs = itemDatas
timeNow := time.Now()
nyc, _ := time.LoadLocation(common.LoadTimeZone())
qqWry, err := qqwry.NewQQwry()
if err != nil {
global.LOG.Errorf("load qqwry datas failed: %s", err)
}
var itemLogs []dto.SSHHistory
for i := len(data.Logs) - 1; i >= 0; i-- {
data.Logs[i].Area = qqWry.Find(data.Logs[i].Address).Area
data.Logs[i].Date, _ = time.ParseInLocation("2006 Jan 2 15:04:05", fmt.Sprintf("%d %s", timeNow.Year(), data.Logs[i].DateStr), nyc)
itemLogs = append(itemLogs, data.Logs[i])
}
data.Logs = itemLogs
return &data, nil
}
func sortFileList(fileNames []string) []string {
if len(fileNames) < 2 {
return fileNames
}
var itemFile []string
if strings.Contains(fileNames[0], "secure") {
sort.Slice(fileNames, func(i, j int) bool {
return fileNames[i] < fileNames[j]
})
itemFile = append(itemFile, fileNames[1:]...)
itemFile = append(itemFile, fileNames[0])
return itemFile
}
sort.Slice(fileNames, func(i, j int) bool {
return fileNames[i] > fileNames[j]
})
return fileNames
}
func updateSSHConf(oldFiles []string, param string, value interface{}) []string {
hasKey := false
var newFiles []string
for _, line := range oldFiles {
if strings.HasPrefix(line, param+" ") {
newFiles = append(newFiles, fmt.Sprintf("%s %v", param, value))
hasKey = true
continue
}
newFiles = append(newFiles, line)
}
if !hasKey {
newFiles = []string{}
for _, line := range oldFiles {
if strings.HasPrefix(line, fmt.Sprintf("#%s ", param)) && !hasKey {
newFiles = append(newFiles, fmt.Sprintf("%s %v", param, value))
hasKey = true
continue
}
newFiles = append(newFiles, line)
}
}
if !hasKey {
newFiles = []string{}
newFiles = append(newFiles, oldFiles...)
newFiles = append(newFiles, fmt.Sprintf("%s %v", param, value))
}
return newFiles
}
func loadSuccessDatas(command string) []dto.SSHHistory {
var datas []dto.SSHHistory
stdout2, err := cmd.Exec(command)
if err == nil {
lines := strings.Split(string(stdout2), "\n")
for _, line := range lines {
parts := strings.Fields(line)
if len(parts) < 14 {
continue
}
historyItem := dto.SSHHistory{
DateStr: fmt.Sprintf("%s %s %s", parts[0], parts[1], parts[2]),
AuthMode: parts[6],
User: parts[8],
Address: parts[10],
Port: parts[12],
Status: constant.StatusSuccess,
}
datas = append(datas, historyItem)
}
}
return datas
}
func loadFailedAuthDatas(command string) []dto.SSHHistory {
var datas []dto.SSHHistory
stdout2, err := cmd.Exec(command)
if err == nil {
lines := strings.Split(string(stdout2), "\n")
for _, line := range lines {
parts := strings.Fields(line)
if len(parts) < 14 {
continue
}
historyItem := dto.SSHHistory{
DateStr: fmt.Sprintf("%s %s %s", parts[0], parts[1], parts[2]),
AuthMode: parts[8],
User: parts[10],
Address: parts[11],
Port: parts[13],
Status: constant.StatusFailed,
}
if strings.Contains(line, ": ") {
historyItem.Message = strings.Split(line, ": ")[1]
}
datas = append(datas, historyItem)
}
}
return datas
}
func loadFailedSecureDatas(command string) []dto.SSHHistory {
var datas []dto.SSHHistory
stdout2, err := cmd.Exec(command)
if err == nil {
lines := strings.Split(string(stdout2), "\n")
for _, line := range lines {
parts := strings.Fields(line)
if len(parts) < 14 {
continue
}
historyItem := dto.SSHHistory{
DateStr: fmt.Sprintf("%s %s %s", parts[0], parts[1], parts[2]),
AuthMode: parts[6],
User: parts[8],
Address: parts[10],
Port: parts[12],
Status: constant.StatusFailed,
}
if strings.Contains(line, ": ") {
historyItem.Message = strings.Split(line, ": ")[1]
}
datas = append(datas, historyItem)
}
}
return datas
}
func handleGunzip(path string) error {
if _, err := cmd.Execf("gunzip %s", path); err != nil {
return err
}
return nil
}
+8 -31
View File
@@ -2,6 +2,7 @@ package service
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
@@ -11,8 +12,6 @@ import (
"time"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common"
@@ -68,7 +67,7 @@ func (u *UpgradeService) SearchUpgrade() (*dto.UpgradeInfo, error) {
notes, err := u.loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, global.CONF.System.Mode, itemVersion, itemVersion))
if err != nil {
return nil, fmt.Errorf("load releases-notes of version %s failed, err: %v", latestVersion, err)
return nil, fmt.Errorf("load relase-notes of version %s failed, err: %v", latestVersion, err)
}
upgrade.ReleaseNote = notes
return &upgrade, nil
@@ -77,7 +76,7 @@ func (u *UpgradeService) SearchUpgrade() (*dto.UpgradeInfo, error) {
func (u *UpgradeService) LoadNotes(req dto.Upgrade) (string, error) {
notes, err := u.loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, global.CONF.System.Mode, req.Version, req.Version))
if err != nil {
return "", fmt.Errorf("load releases-notes of version %s failed, err: %v", req.Version, err)
return "", fmt.Errorf("load relase-notes of version %s failed, err: %v", req.Version, err)
}
return notes, nil
}
@@ -94,13 +93,9 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
if err := os.MkdirAll(originalDir, os.ModePerm); err != nil {
return err
}
itemArch, err := loadArch()
if err != nil {
return err
}
downloadPath := fmt.Sprintf("%s/%s/%s/release", global.CONF.System.RepoUrl, global.CONF.System.Mode, req.Version)
fileName := fmt.Sprintf("1panel-%s-%s-%s.tar.gz", req.Version, "linux", itemArch)
fileName := fmt.Sprintf("1panel-%s-%s-%s.tar.gz", req.Version, "linux", runtime.GOARCH)
_ = settingRepo.Update("SystemStatus", "Upgrading")
go func() {
if err := fileOp.DownloadFile(downloadPath+"/"+fileName, rootDir+"/"+fileName); err != nil {
@@ -205,12 +200,12 @@ func (u *UpgradeService) loadVersion(isLatest bool, currentVersion string) (stri
}
latestVersionRes, err := http.Get(path)
if err != nil {
return "", buserr.New(constant.ErrOSSConn)
return "", err
}
defer latestVersionRes.Body.Close()
version, err := io.ReadAll(latestVersionRes.Body)
if err != nil {
return "", buserr.New(constant.ErrOSSConn)
return "", err
}
if isLatest {
return string(version), nil
@@ -218,7 +213,7 @@ func (u *UpgradeService) loadVersion(isLatest bool, currentVersion string) (stri
versionMap := make(map[string]string)
if err := json.Unmarshal(version, &versionMap); err != nil {
return "", buserr.New(constant.ErrOSSConn)
return "", fmt.Errorf("load version map failed, err: %v", err)
}
if len(currentVersion) < 4 {
@@ -227,7 +222,7 @@ func (u *UpgradeService) loadVersion(isLatest bool, currentVersion string) (stri
if version, ok := versionMap[currentVersion[0:4]]; ok {
return version, nil
}
return "", buserr.New(constant.ErrOSSConn)
return "", errors.New("load version failed in latest.current")
}
func (u *UpgradeService) loadReleaseNotes(path string) (string, error) {
@@ -242,21 +237,3 @@ func (u *UpgradeService) loadReleaseNotes(path string) (string, error) {
}
return string(release), nil
}
func loadArch() (string, error) {
switch runtime.GOARCH {
case "amd64", "ppc64le", "s390x", "arm64":
return runtime.GOARCH, nil
case "arm":
std, err := cmd.Exec("uname -m")
if err != nil {
return "", fmt.Errorf("std: %s, err: %s", std, err.Error())
}
if std == "armv7l\n" {
return "armv7", nil
}
return "", fmt.Errorf("unsupport such arch: arm-%s", std)
default:
return "", fmt.Errorf("unsupport such arch: %s", runtime.GOARCH)
}
}
+28 -254
View File
@@ -16,7 +16,6 @@ import (
"github.com/1Panel-dev/1Panel/backend/utils/nginx/parser"
"github.com/1Panel-dev/1Panel/cmd/server/nginx_conf"
"golang.org/x/crypto/bcrypt"
"gopkg.in/ini.v1"
"gorm.io/gorm"
"os"
"path"
@@ -76,8 +75,6 @@ type IWebsiteService interface {
UpdateProxyFile(req request.NginxProxyUpdate) (err error)
GetAuthBasics(req request.NginxAuthReq) (res response.NginxAuthRes, err error)
UpdateAuthBasic(req request.NginxAuthUpdate) (err error)
GetAntiLeech(id uint) (*response.NginxAntiLeechRes, error)
UpdateAntiLeech(req request.NginxAntiLeechUpdate) (err error)
}
func NewIWebsiteService() IWebsiteService {
@@ -176,7 +173,6 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
SiteDir: "/",
AccessLog: true,
ErrorLog: true,
IPV6: create.IPV6,
}
var (
@@ -210,7 +206,6 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
req.Name = create.AppInstall.Name
req.AppDetailId = create.AppInstall.AppDetailId
req.Params = create.AppInstall.Params
req.AppContainerConfig = create.AppInstall.AppContainerConfig
tx, installCtx := getTxAndContext()
install, err = NewIAppService().Install(installCtx, req)
if err != nil {
@@ -248,7 +243,6 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
req.AppDetailId = create.AppInstall.AppDetailId
req.Params = create.AppInstall.Params
req.Params["IMAGE_NAME"] = runtime.Image
req.AppContainerConfig = create.AppInstall.AppContainerConfig
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return err
@@ -341,8 +335,6 @@ func (w WebsiteService) UpdateWebsite(req request.WebsiteUpdate) error {
website.PrimaryDomain = req.PrimaryDomain
website.WebsiteGroupID = req.WebsiteGroupID
website.Remark = req.Remark
website.IPV6 = req.IPV6
if req.ExpireDate != "" {
expireDate, err := time.Parse(constant.DateLayout, req.ExpireDate)
if err != nil {
@@ -681,16 +673,21 @@ func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteH
websiteSSL.ExpireDate = cert.NotAfter
websiteSSL.StartDate = cert.NotBefore
websiteSSL.Type = cert.Issuer.CommonName
if len(cert.Issuer.Organization) > 0 {
websiteSSL.Organization = cert.Issuer.Organization[0]
} else {
websiteSSL.Organization = cert.Issuer.CommonName
websiteSSL.Organization = cert.Issuer.Organization[0]
websiteSSL.PrimaryDomain = cert.Subject.CommonName
if len(cert.Subject.Names) > 0 {
var domains []string
for _, name := range cert.Subject.Names {
if v, ok := name.Value.(string); ok {
if v != cert.Subject.CommonName {
domains = append(domains, v)
}
}
}
if len(domains) > 0 {
websiteSSL.Domains = strings.Join(domains, "")
}
}
if len(cert.DNSNames) > 0 {
websiteSSL.PrimaryDomain = cert.DNSNames[0]
websiteSSL.Domains = strings.Join(cert.DNSNames, ",")
}
websiteSSL.Provider = constant.Manual
websiteSSL.PrivateKey = req.PrivateKey
websiteSSL.Pem = req.Certificate
@@ -862,7 +859,7 @@ func (w WebsiteService) OpWebsiteLog(req request.WebsiteLogReq) (*response.Websi
if err != nil {
return nil, err
}
if fileInfo.Size() > 20<<20 {
if fileInfo.Size() > 10<<20 {
return nil, buserr.New(constant.ErrFileToLarge)
}
fileInfo.Size()
@@ -908,11 +905,6 @@ func (w WebsiteService) OpWebsiteLog(req request.WebsiteLogReq) (*response.Websi
if err := websiteRepo.Save(context.Background(), &website); err != nil {
return nil, err
}
case constant.DeleteLog:
logPath := path.Join(nginx.Install.GetPath(), "www", "sites", website.Alias, "log", req.LogType)
if err := files.NewFileOp().WriteFile(logPath, strings.NewReader(""), 0755); err != nil {
return nil, err
}
}
return res, nil
}
@@ -1010,27 +1002,7 @@ func (w WebsiteService) GetPHPConfig(id uint) (*response.PHPConfig, error) {
params[matches[1]] = matches[2]
}
}
cfg, err := ini.Load(phpConfigPath)
if err != nil {
return nil, err
}
phpConfig, err := cfg.GetSection("PHP")
if err != nil {
return nil, err
}
disableFunctionStr := phpConfig.Key("disable_functions").Value()
res := &response.PHPConfig{Params: params}
if disableFunctionStr != "" {
disableFunctions := strings.Split(disableFunctionStr, ",")
if len(disableFunctions) > 0 {
res.DisableFunctions = disableFunctions
}
}
uploadMaxSize := phpConfig.Key("upload_max_filesize").Value()
if uploadMaxSize != "" {
res.UploadMaxSize = uploadMaxSize
}
return res, nil
return &response.PHPConfig{Params: params}, nil
}
func (w WebsiteService) UpdatePHPConfig(req request.WebsitePHPConfigUpdate) (err error) {
@@ -1054,55 +1026,23 @@ func (w WebsiteService) UpdatePHPConfig(req request.WebsitePHPConfigUpdate) (err
defer configFile.Close()
contentBytes, err := fileOp.GetContent(phpConfigPath)
if err != nil {
return err
}
if req.Scope == "params" {
content := string(contentBytes)
lines := strings.Split(content, "\n")
for i, line := range lines {
if strings.HasPrefix(line, ";") {
continue
}
for key, value := range req.Params {
pattern := "^" + regexp.QuoteMeta(key) + "\\s*=\\s*.*$"
if matched, _ := regexp.MatchString(pattern, line); matched {
lines[i] = key + " = " + value
}
content := string(contentBytes)
lines := strings.Split(content, "\n")
for i, line := range lines {
if strings.HasPrefix(line, ";") {
continue
}
for key, value := range req.Params {
pattern := "^" + regexp.QuoteMeta(key) + "\\s*=\\s*.*$"
if matched, _ := regexp.MatchString(pattern, line); matched {
lines[i] = key + " = " + value
}
}
updatedContent := strings.Join(lines, "\n")
if err := fileOp.WriteFile(phpConfigPath, strings.NewReader(updatedContent), 0755); err != nil {
return err
}
}
cfg, err := ini.Load(phpConfigPath)
if err != nil {
updatedContent := strings.Join(lines, "\n")
if err := fileOp.WriteFile(phpConfigPath, strings.NewReader(updatedContent), 0755); err != nil {
return err
}
phpConfig, err := cfg.GetSection("PHP")
if err != nil {
return err
}
if req.Scope == "disable_functions" {
disable := phpConfig.Key("disable_functions")
disable.SetValue(strings.Join(req.DisableFunctions, ","))
if err = cfg.SaveTo(phpConfigPath); err != nil {
return err
}
}
if req.Scope == "upload_max_filesize" {
postMaxSize := phpConfig.Key("post_max_size")
postMaxSize.SetValue(req.UploadMaxSize)
uploadMaxFileSize := phpConfig.Key("upload_max_filesize")
uploadMaxFileSize.SetValue(req.UploadMaxSize)
if err = cfg.SaveTo(phpConfigPath); err != nil {
return err
}
}
appInstallReq := request.AppInstalledOperate{
InstallId: appInstall.ID,
Operate: constant.Restart,
@@ -1111,7 +1051,6 @@ func (w WebsiteService) UpdatePHPConfig(req request.WebsitePHPConfigUpdate) (err
_ = fileOp.WriteFile(phpConfigPath, strings.NewReader(string(contentBytes)), 0755)
return err
}
return nil
}
@@ -1645,168 +1584,3 @@ func (w WebsiteService) GetAuthBasics(req request.NginxAuthReq) (res response.Ng
}
return
}
func (w WebsiteService) UpdateAntiLeech(req request.NginxAntiLeechUpdate) (err error) {
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
if err != nil {
return
}
nginxFull, err := getNginxFull(&website)
if err != nil {
return
}
fileOp := files.NewFileOp()
backpContent, err := fileOp.GetContent(nginxFull.SiteConfig.Config.FilePath)
if err != nil {
return
}
block := nginxFull.SiteConfig.Config.FindServers()[0]
locations := block.FindDirectives("location")
for _, location := range locations {
loParams := location.GetParameters()
if len(loParams) > 1 || loParams[0] == "~" {
extendStr := loParams[1]
if strings.HasPrefix(extendStr, `.*\.(`) && strings.HasSuffix(extendStr, `)$`) {
block.RemoveDirective("location", loParams)
}
}
}
if req.Enable {
exts := strings.Split(req.Extends, ",")
newDirective := components.Directive{
Name: "location",
Parameters: []string{"~", fmt.Sprintf(`.*\.(%s)$`, strings.Join(exts, "|"))},
}
newBlock := &components.Block{}
newBlock.Directives = make([]components.IDirective, 0)
if req.Cache {
newBlock.Directives = append(newBlock.Directives, &components.Directive{
Name: "expires",
Parameters: []string{strconv.Itoa(req.CacheTime) + req.CacheUint},
})
}
newBlock.Directives = append(newBlock.Directives, &components.Directive{
Name: "log_not_found",
Parameters: []string{"off"},
})
validDir := &components.Directive{
Name: "valid_referers",
Parameters: []string{},
}
if req.NoneRef {
validDir.Parameters = append(validDir.Parameters, "none")
}
if len(req.ServerNames) > 0 {
validDir.Parameters = append(validDir.Parameters, strings.Join(req.ServerNames, " "))
}
newBlock.Directives = append(newBlock.Directives, validDir)
ifDir := &components.Directive{
Name: "if",
Parameters: []string{"($invalid_referer)"},
}
ifDir.Block = &components.Block{
Directives: []components.IDirective{
&components.Directive{
Name: "return",
Parameters: []string{req.Return},
},
&components.Directive{
Name: "access_log",
Parameters: []string{"off"},
},
},
}
newBlock.Directives = append(newBlock.Directives, ifDir)
newDirective.Block = newBlock
block.Directives = append(block.Directives, &newDirective)
}
if err = nginx.WriteConfig(nginxFull.SiteConfig.Config, nginx.IndentedStyle); err != nil {
return
}
if err = updateNginxConfig(constant.NginxScopeServer, nil, &website); err != nil {
_ = fileOp.WriteFile(nginxFull.SiteConfig.Config.FilePath, bytes.NewReader(backpContent), 0755)
return
}
return
}
func (w WebsiteService) GetAntiLeech(id uint) (*response.NginxAntiLeechRes, error) {
website, err := websiteRepo.GetFirst(commonRepo.WithByID(id))
if err != nil {
return nil, err
}
nginxFull, err := getNginxFull(&website)
if err != nil {
return nil, err
}
res := &response.NginxAntiLeechRes{
LogEnable: true,
ServerNames: []string{},
}
block := nginxFull.SiteConfig.Config.FindServers()[0]
locations := block.FindDirectives("location")
for _, location := range locations {
loParams := location.GetParameters()
if len(loParams) > 1 || loParams[0] == "~" {
extendStr := loParams[1]
if strings.HasPrefix(extendStr, `.*\.(`) && strings.HasSuffix(extendStr, `)$`) {
str1 := strings.TrimPrefix(extendStr, `.*\.(`)
str2 := strings.TrimSuffix(str1, ")$")
res.Extends = strings.Join(strings.Split(str2, "|"), ",")
}
}
lDirectives := location.GetBlock().GetDirectives()
for _, lDir := range lDirectives {
if lDir.GetName() == "valid_referers" {
res.Enable = true
params := lDir.GetParameters()
for _, param := range params {
if param == "none" {
res.NoneRef = true
continue
}
if param == "blocked" {
res.Blocked = true
continue
}
if param == "server_names" {
continue
}
res.ServerNames = append(res.ServerNames, param)
}
}
if lDir.GetName() == "if" && lDir.GetParameters()[0] == "($invalid_referer)" {
directives := lDir.GetBlock().GetDirectives()
for _, dir := range directives {
if dir.GetName() == "return" {
res.Return = strings.Join(dir.GetParameters(), " ")
}
if dir.GetName() == "access_log" {
if strings.Join(dir.GetParameters(), "") == "off" {
res.LogEnable = false
}
}
}
}
if lDir.GetName() == "expires" {
res.Cache = true
re := regexp.MustCompile(`^(\d+)(\w+)$`)
matches := re.FindStringSubmatch(lDir.GetParameters()[0])
if matches == nil {
continue
}
cacheTime, err := strconv.Atoi(matches[1])
if err != nil {
continue
}
unit := matches[2]
res.CacheUint = unit
res.CacheTime = cacheTime
}
}
}
return res, nil
}
-16
View File
@@ -190,9 +190,6 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
for _, domain := range domains {
serverNames = append(serverNames, domain.Domain)
server.UpdateListen(strconv.Itoa(domain.Port), false)
if website.IPV6 {
server.UpdateListen("[::]:"+strconv.Itoa(domain.Port), false)
}
}
server.UpdateServerName(serverNames)
@@ -294,9 +291,6 @@ func addListenAndServerName(website model.Website, ports []int, domains []string
server := config.FindServers()[0]
for _, port := range ports {
server.AddListen(strconv.Itoa(port), false)
if website.IPV6 {
server.UpdateListen("[::]:"+strconv.Itoa(port), false)
}
}
for _, domain := range domains {
server.AddServerName(domain)
@@ -317,7 +311,6 @@ func deleteListenAndServerName(website model.Website, binds []string, domains []
server := config.FindServers()[0]
for _, bind := range binds {
server.DeleteListen(bind)
server.DeleteListen("[::]:" + bind)
}
for _, domain := range domains {
server.DeleteServerName(domain)
@@ -379,9 +372,6 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
config := nginxFull.SiteConfig.Config
server := config.FindServers()[0]
server.UpdateListen("443", website.DefaultServer, "ssl")
if website.IPV6 {
server.UpdateListen("[::]:443", website.DefaultServer, "ssl")
}
switch req.HttpConfig {
case constant.HTTPSOnly:
@@ -390,16 +380,10 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
server.RemoveDirective("if", []string{"($scheme"})
case constant.HTTPToHTTPS:
server.UpdateListen("80", website.DefaultServer)
if website.IPV6 {
server.UpdateListen("[::]:80", website.DefaultServer)
}
server.AddHTTP2HTTPS()
case constant.HTTPAlso:
server.UpdateListen("80", website.DefaultServer)
server.RemoveDirective("if", []string{"($scheme"})
if website.IPV6 {
server.UpdateListen("[::]:80", website.DefaultServer)
}
}
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
-1
View File
@@ -19,6 +19,5 @@ type System struct {
Password string `mapstructure:"password"`
Entrance string `mapstructure:"entrance"`
IsDemo bool `mapstructure:"is_demo"`
AppRepo string `mapstructure:"app_repo"`
ChangeUserInfo bool `mapstructure:"change_user_info"`
}
+6 -15
View File
@@ -1,16 +1,12 @@
package constant
const (
Running = "Running"
UnHealthy = "UnHealthy"
Error = "Error"
Stopped = "Stopped"
Installing = "Installing"
Syncing = "Syncing"
DownloadErr = "DownloadErr"
DirNotFound = "DirNotFound"
Upgrading = "Upgrading"
UpgradeErr = "UpgradeErr"
Running = "Running"
UnHealthy = "UnHealthy"
Error = "Error"
Stopped = "Stopped"
Installing = "Installing"
Syncing = "Syncing"
ContainerPrefix = "1Panel-"
@@ -23,11 +19,6 @@ const (
AppResourceLocal = "local"
AppResourceRemote = "remote"
CPUS = "CPUS"
MemoryLimit = "MEMORY_LIMIT"
HostIP = "HOST_IP"
ContainerName = "CONTAINER_NAME"
)
type AppOperate string
+7 -8
View File
@@ -7,12 +7,11 @@ import (
)
var (
DataDir = global.CONF.System.DataDir
ResourceDir = path.Join(DataDir, "resource")
AppResourceDir = path.Join(ResourceDir, "apps")
AppInstallDir = path.Join(DataDir, "apps")
LocalAppResourceDir = path.Join(AppResourceDir, "local")
LocalAppInstallDir = path.Join(AppInstallDir, "local")
RemoteAppResourceDir = path.Join(AppResourceDir, "remote")
RuntimeDir = path.Join(DataDir, "runtime")
DataDir = global.CONF.System.DataDir
ResourceDir = path.Join(DataDir, "resource")
AppResourceDir = path.Join(ResourceDir, "apps")
AppInstallDir = path.Join(DataDir, "apps")
LocalAppResourceDir = path.Join(ResourceDir, "localApps")
LocalAppInstallDir = path.Join(DataDir, "localApps")
RuntimeDir = path.Join(DataDir, "runtime")
)
+10 -8
View File
@@ -14,8 +14,6 @@ const (
CodePasswordExpired = 405
CodeAuth = 406
CodeGlobalLoading = 407
CodeErrIP = 408
CodeErrDomain = 409
CodeErrInternalServer = 500
CodeErrHeader = 406
)
@@ -32,39 +30,45 @@ var (
ErrInvalidParams = errors.New("ErrInvalidParams")
ErrTokenParse = errors.New("ErrTokenParse")
ErrPageGenerate = errors.New("generate page info failed")
ErrRepoNotValid = "ErrRepoNotValid"
)
// api
var (
ErrTypeInternalServer = "ErrInternalServer"
ErrTypeInvalidParams = "ErrInvalidParams"
ErrTypeToken = "ErrToken"
ErrTypeTokenTimeOut = "ErrTokenTimeOut"
ErrTypeNotLogin = "ErrNotLogin"
ErrTypePasswordExpired = "ErrPasswordExpired"
ErrTypeNotSafety = "ErrNotSafety"
ErrNameIsExist = "ErrNameIsExist"
ErrDemoEnvironment = "ErrDemoEnvironment"
ErrInitUser = "ErrInitUser"
)
// app
var (
ErrPortInUsed = "ErrPortInUsed"
ErrAppLimit = "ErrAppLimit"
ErrFileToLarge = "ErrFileToLarge"
ErrAppRequired = "ErrAppRequired"
ErrFileCanNotRead = "ErrFileCanNotRead"
ErrFileToLarge = "ErrFileToLarge"
ErrNotInstall = "ErrNotInstall"
ErrPortInOtherApp = "ErrPortInOtherApp"
ErrDbUserNotValid = "ErrDbUserNotValid"
ErrUpdateBuWebsite = "ErrUpdateBuWebsite"
Err1PanelNetworkFailed = "Err1PanelNetworkFailed"
ErrCmdTimeout = "ErrCmdTimeout"
ErrFileParse = "ErrFileParse"
ErrInstallDirNotFound = "ErrInstallDirNotFound"
ErrContainerName = "ErrContainerName"
)
// website
var (
ErrDomainIsExist = "ErrDomainIsExist"
ErrAliasIsExist = "ErrAliasIsExist"
ErrAppDelete = "ErrAppDelete"
ErrGroupIsUsed = "ErrGroupIsUsed"
ErrUsernameIsExist = "ErrUsernameIsExist"
ErrUsernameIsNotExist = "ErrUsernameIsNotExist"
@@ -85,7 +89,6 @@ var (
ErrLinkPathNotFound = "ErrLinkPathNotFound"
ErrFileIsExit = "ErrFileIsExit"
ErrFileUpload = "ErrFileUpload"
ErrFileDownloadDir = "ErrFileDownloadDir"
)
// mysql
@@ -118,5 +121,4 @@ var (
var (
ErrBackupInUsed = "ErrBackupInUsed"
ErrOSSConn = "ErrOSSConn"
)
-1
View File
@@ -38,7 +38,6 @@ const (
GetLog = "get"
DisableLog = "disable"
EnableLog = "enable"
DeleteLog = "delete"
AccessLog = "access.log"
ErrorLog = "error.log"
+8 -23
View File
@@ -15,34 +15,19 @@ import (
func Run() {
nyc, _ := time.LoadLocation(common.LoadTimeZone())
global.Cron = cron.New(cron.WithLocation(nyc), cron.WithChain(cron.Recover(cron.DefaultLogger)), cron.WithChain(cron.DelayIfStillRunning(cron.DefaultLogger)))
var (
interval model.Setting
status model.Setting
)
if err := global.DB.Where("key = ?", "MonitorStatus").Find(&status).Error; err != nil {
global.LOG.Errorf("load monitor status from db failed, err: %v", err)
Cron := cron.New(cron.WithLocation(nyc), cron.WithChain(cron.Recover(cron.DefaultLogger)), cron.WithChain(cron.DelayIfStillRunning(cron.DefaultLogger)))
if _, err := Cron.AddJob("@every 5m", job.NewMonitorJob()); err != nil {
global.LOG.Errorf("can not add monitor corn job: %s", err.Error())
}
if status.Value == "enable" {
if err := global.DB.Where("key = ?", "MonitorInterval").Find(&interval).Error; err != nil {
global.LOG.Errorf("load monitor interval from db failed, err: %v", err)
}
if err := service.StartMonitor(false, interval.Value); err != nil {
global.LOG.Errorf("can not add monitor corn job: %s", err.Error())
}
}
if _, err := global.Cron.AddJob("@daily", job.NewWebsiteJob()); err != nil {
if _, err := Cron.AddJob("@daily", job.NewWebsiteJob()); err != nil {
global.LOG.Errorf("can not add website corn job: %s", err.Error())
}
if _, err := global.Cron.AddJob("@daily", job.NewSSLJob()); err != nil {
if _, err := Cron.AddJob("@daily", job.NewSSLJob()); err != nil {
global.LOG.Errorf("can not add ssl corn job: %s", err.Error())
}
if _, err := global.Cron.AddJob("@daily", job.NewAppStoreJob()); err != nil {
global.LOG.Errorf("can not add appstore corn job: %s", err.Error())
}
global.Cron.Start()
Cron.Start()
global.Cron = Cron
var cronJobs []model.Cronjob
if err := global.DB.Where("status = ?", constant.StatusEnable).Find(&cronJobs).Error; err != nil {
-20
View File
@@ -1,20 +0,0 @@
package job
import (
"github.com/1Panel-dev/1Panel/backend/app/service"
"github.com/1Panel-dev/1Panel/backend/global"
)
type app struct{}
func NewAppStoreJob() *app {
return &app{}
}
func (a *app) Run() {
global.LOG.Info("AppStore scheduled task in progress ...")
if err := service.NewIAppService().SyncAppListFromRemote(); err != nil {
global.LOG.Errorf("AppStore sync failed %s", err.Error())
}
global.LOG.Info("AppStore scheduled task has completed")
}
@@ -1,13 +1,12 @@
package service
package job
import (
"fmt"
"strconv"
"time"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/app/repo"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/robfig/cron/v3"
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/disk"
"github.com/shirou/gopsutil/v3/load"
@@ -15,17 +14,14 @@ import (
"github.com/shirou/gopsutil/v3/net"
)
type MonitorService struct{}
type monitor struct{}
type IMonitorService interface {
Run()
func NewMonitorJob() *monitor {
return &monitor{}
}
func NewIMonitorService() IMonitorService {
return &MonitorService{}
}
func (m *MonitorService) Run() {
func (m *monitor) Run() {
settingRepo := repo.NewISettingRepo()
monitorStatus, _ := settingRepo.Get(settingRepo.WithByKey("MonitorStatus"))
if monitorStatus.Value == "disable" {
return
@@ -46,7 +42,7 @@ func (m *MonitorService) Run() {
memoryInfo, _ := mem.VirtualMemory()
itemModel.Memory = memoryInfo.UsedPercent
if err := settingRepo.CreateMonitorBase(itemModel); err != nil {
if err := global.DB.Create(&itemModel).Error; err != nil {
global.LOG.Errorf("Insert basic monitoring data failed, err: %v", err)
}
@@ -59,9 +55,9 @@ func (m *MonitorService) Run() {
}
storeDays, _ := strconv.Atoi(MonitorStoreDays.Value)
timeForDelete := time.Now().AddDate(0, 0, -storeDays)
_ = settingRepo.DelMonitorBase(timeForDelete)
_ = settingRepo.DelMonitorIO(timeForDelete)
_ = settingRepo.DelMonitorNet(timeForDelete)
_ = global.DB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorBase{}).Error
_ = global.DB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorIO{}).Error
_ = global.DB.Where("created_at < ?", timeForDelete).Delete(&model.MonitorNetwork{}).Error
}
func loadDiskIO() {
@@ -95,7 +91,7 @@ func loadDiskIO() {
}
}
}
if err := settingRepo.BatchCreateMonitorIO(ioList); err != nil {
if err := global.DB.CreateInBatches(ioList, len(ioList)).Error; err != nil {
global.LOG.Errorf("Insert io monitoring data failed, err: %v", err)
}
}
@@ -137,19 +133,7 @@ func loadNetIO() {
}
}
if err := settingRepo.BatchCreateMonitorNet(netList); err != nil {
if err := global.DB.CreateInBatches(netList, len(netList)).Error; err != nil {
global.LOG.Errorf("Insert network monitoring data failed, err: %v", err)
}
}
func StartMonitor(removeBefore bool, interval string) error {
if removeBefore {
global.Cron.Remove(cron.EntryID(global.MonitorCronID))
}
monitorID, err := global.Cron.AddJob(fmt.Sprintf("@every %sm", interval), NewIMonitorService())
if err != nil {
return err
}
global.MonitorCronID = int(monitorID)
return nil
}
+1 -2
View File
@@ -20,6 +20,5 @@ var (
CACHE *badger_db.Cache
Viper *viper.Viper
Cron *cron.Cron
MonitorCronID int
Cron *cron.Cron
)
-7
View File
@@ -46,13 +46,6 @@ func GetErrMsg(key string, maps map[string]interface{}) string {
return content
}
func GetMsgByKey(key string) string {
content := ginI18n.MustGetMessage(&i18n.LocalizeConfig{
MessageID: key,
})
return content
}
//go:embed lang/*
var fs embed.FS
+6 -21
View File
@@ -17,6 +17,7 @@ ErrRepoNotValid: "Remote repository verification failed!"
ErrNameIsExist: "Name is already exist"
ErrDemoEnvironment: "Demo server, prohibit this operation!"
ErrCmdTimeout: "Command execution timed out!"
ErrInitUser: "The user initialization has been completed by the system. Please do not repeat the operation!"
#app
ErrPortInUsed: "{{ .detail }} port already in use"
@@ -28,22 +29,6 @@ ErrDbUserNotValid: "Stock database, username and password do not match!"
ErrDockerComposeNotValid: "docker-compose file format error!"
ErrUpdateBuWebsite: 'The application was updated successfully, but the modification of the website configuration file failed, please check the configuration!'
Err1PanelNetworkFailed: 'Default container network creation failed! {{ .detail }}'
ErrFileParse: 'Application docker-compose file parsing failed!'
ErrInstallDirNotFound: 'installation directory does not exist'
AppStoreIsUpToDate: 'The app store is already up to date!'
LocalAppVersionNull: 'The {{.name}} app is not synced to version! Could not add to application list'
LocalAppVersionErr: '{{.name}} failed to sync version {{.version}}! {{.err}}'
ErrFileNotFound: '{{.name}} file does not exist'
ErrFileParseApp: 'Failed to parse {{.name}} file {{.err}}'
ErrAppDirNull: 'version folder does not exist'
LocalAppErr: "App {{.name}} sync failed! {{.err}}"
ErrContainerName: "ContainerName is already exist"
ErrAppSystemRestart: "1Panel restart causes the task to terminate"
ErrCreateHttpClient: "Failed to create HTTP request {{.err}}"
ErrHttpReqTimeOut: "Request timed out {{.err}}"
ErrHttpReqFailed: "Request failed {{.err}}"
ErrHttpReqNotFound: "The file does not exist"
ErrNoSuchHost: "Network connection failed"
#file
ErrFileCanNotRead: "File can not read"
@@ -52,14 +37,15 @@ ErrPathNotFound: "Path is not found"
ErrMovePathFailed: "The target path cannot contain the original path!"
ErrLinkPathNotFound: "Target path does not exist!"
ErrFileIsExit: "File already exists!"
ErrFileUpload: "Failed to upload file {{.name}} {{.detail}}"
ErrFileDownloadDir: "Download folder not supported"
ErrFileUpload: "Failed to upload file"
#website
ErrDomainIsExist: "Domain is already exist"
ErrAliasIsExist: "Alias is already exist"
ErrAppDelete: 'Other Website use this App'
ErrGroupIsUsed: 'The group is in use and cannot be deleted'
ErrUsernameIsExist: 'Username is already exist'
ErrUsernameIsNotExist: 'Username is not exist'
#ssl
ErrSSLCannotDelete: "The certificate is being used by the website and cannot be removed"
@@ -78,6 +64,7 @@ ErrTypeOfRedis: "The recovery file type does not match the current persistence m
#container
ErrInUsed: "{{ .detail }} is in use and cannot be deleted"
ErrObjectInUsed: "This object is in use and cannot be deleted"
ErrPortRules: "Invalid port specification"
#runtime
ErrDirNotFound: "The build folder does not exist! Please check file integrity!"
@@ -87,6 +74,4 @@ ErrImageExist: "Image is already exist!"
ErrDelWithWebsite: "The operating environment has been associated with a website and cannot be deleted"
#setting
ErrBackupInUsed: "The backup account is already being used in a cronjob and cannot be deleted."
ErrOSSConn: "Unable to successfully request the latest version. Please check if the server can connect to the external network environment."
ErrBackupInUsed: "The backup account is already being used in a cronjob and cannot be deleted."
+5 -20
View File
@@ -17,6 +17,7 @@ ErrRepoNotValid: "远程仓库校验失败!"
ErrNameIsExist: "名称已存在"
ErrDemoEnvironment: "演示服务器,禁止此操作!"
ErrCmdTimeout: "命令执行超时!"
ErrInitUser: "系统已完成用户初始化,请勿重复操作!"
#app
ErrPortInUsed: "{{ .detail }} 端口已被占用!"
@@ -28,22 +29,6 @@ ErrDbUserNotValid: "存量数据库,用户名密码不匹配!"
ErrDockerComposeNotValid: "docker-compose 文件格式错误"
ErrUpdateBuWebsite: '应用更新成功,但是网站配置文件修改失败,请检查配置!'
Err1PanelNetworkFailed: '默认容器网络创建失败!{{ .detail }}'
ErrFileParse: '应用 docker-compose 文件解析失败!'
ErrInstallDirNotFound: '安装目录不存在'
AppStoreIsUpToDate: '应用商店已经是最新版本'
LocalAppVersionNull: '{{.name}} 应用未同步到版本!无法添加到应用列表'
LocalAppVersionErr: '{{.name}} 同步版本 {{.version}} 失败!{{.err}}'
ErrFileNotFound: '{{.name}} 文件不存在'
ErrFileParseApp: '{{.name}} 文件解析失败 {{.err}}'
ErrAppDirNull: '版本文件夹不存在'
LocalAppErr: "应用 {{.name}} 同步失败!{{.err}}"
ErrContainerName: "容器名称已存在"
ErrAppSystemRestart: "1Panel 重启导致任务终止"
ErrCreateHttpClient: "创建HTTP请求失败 {{.err}}"
ErrHttpReqTimeOut: "请求超时 {{.err}}"
ErrHttpReqFailed: "请求失败 {{.err}}"
ErrHttpReqNotFound: "文件不存在"
ErrNoSuchHost: "网络连接失败"
#file
ErrFileCanNotRead: "此文件不支持预览"
@@ -52,14 +37,15 @@ ErrPathNotFound: "目录不存在"
ErrMovePathFailed: "目标路径不能包含原路径!"
ErrLinkPathNotFound: "目标路径不存在!"
ErrFileIsExit: "文件已存在!"
ErrFileUpload: "{{ .name }} 上传文件失败 {{ .detail}}"
ErrFileDownloadDir: "不支持下载文件夹"
ErrFileUpload: "上传文件失败"
#website
ErrDomainIsExist: "域名已存在"
ErrAliasIsExist: "代号已存在"
ErrAppDelete: '其他网站使用此应用,无法删除'
ErrGroupIsUsed: '分组正在使用中,无法删除'
ErrUsernameIsExist: '用户名已存在'
ErrUsernameIsNotExist: '用户不存在'
#ssl
ErrSSLCannotDelete: "证书正在被网站使用,无法删除"
@@ -78,6 +64,7 @@ ErrTypeOfRedis: "恢复文件类型与当前持久化方式不符,请修改后
#container
ErrInUsed: "{{ .detail }} 正被使用,无法删除"
ErrObjectInUsed: "该对象正被使用,无法删除"
ErrPortRules: "无效的端口规格"
#runtime
ErrDirNotFound: "build 文件夹不存在!请检查文件完整性!"
@@ -88,5 +75,3 @@ ErrDelWithWebsite: "运行环境已经关联网站,无法删除"
#setting
ErrBackupInUsed: "该备份账号已在计划任务中使用,无法删除"
ErrOSSConn: "无法成功请求最新版本,请检查服务器是否能够连接到外部网络环境。"
+3 -6
View File
@@ -15,13 +15,10 @@ func Init() {
constant.AppResourceDir = path.Join(constant.ResourceDir, "apps")
constant.AppInstallDir = path.Join(constant.DataDir, "apps")
constant.RuntimeDir = path.Join(constant.DataDir, "runtime")
constant.LocalAppResourceDir = path.Join(constant.ResourceDir, "localApps")
constant.LocalAppInstallDir = path.Join(constant.DataDir, "localApps")
constant.LocalAppResourceDir = path.Join(constant.AppResourceDir, "local")
constant.LocalAppInstallDir = path.Join(constant.AppInstallDir, "local")
constant.RemoteAppResourceDir = path.Join(constant.AppResourceDir, "remote")
dirs := []string{constant.DataDir, constant.ResourceDir, constant.AppResourceDir, constant.AppInstallDir,
global.CONF.System.Backup, constant.RuntimeDir, constant.LocalAppResourceDir, constant.RemoteAppResourceDir}
dirs := []string{constant.DataDir, constant.ResourceDir, constant.AppResourceDir, constant.AppInstallDir, global.CONF.System.Backup, constant.RuntimeDir, constant.LocalAppResourceDir}
fileOp := files.NewFileOp()
for _, dir := range dirs {
+2 -2
View File
@@ -16,13 +16,13 @@ func syncApp() {
global.LOG.Errorf("sync app error: %s", err.Error())
return
}
if setting.AppStoreLastModified != "0" {
if setting.AppStoreVersion != "" {
global.LOG.Info("no need to sync")
return
}
global.LOG.Info("sync app start...")
if err := service.NewIAppService().SyncAppListFromRemote(); err != nil {
global.LOG.Errorf("sync app error")
global.LOG.Errorf("sync app error: %s", err.Error())
return
}
global.LOG.Info("sync app successful")
+8 -8
View File
@@ -14,29 +14,29 @@ func Init() {
options := badger.Options{
Dir: c,
ValueDir: c,
ValueLogFileSize: 64 << 20,
ValueLogMaxEntries: 10 << 20,
ValueLogFileSize: 102400000,
ValueLogMaxEntries: 100000,
VLogPercentile: 0.1,
MemTableSize: 32 << 20,
MemTableSize: 64 << 20,
BaseTableSize: 2 << 20,
BaseLevelSize: 10 << 20,
TableSizeMultiplier: 2,
LevelSizeMultiplier: 10,
MaxLevels: 7,
NumGoroutines: 4,
NumGoroutines: 8,
MetricsEnabled: true,
NumCompactors: 2,
NumCompactors: 4,
NumLevelZeroTables: 5,
NumLevelZeroTablesStall: 15,
NumMemtables: 1,
NumMemtables: 5,
BloomFalsePositive: 0.01,
BlockSize: 2 * 1024,
BlockSize: 4 * 1024,
SyncWrites: false,
NumVersionsToKeep: 1,
CompactL0OnClose: false,
VerifyValueChecksum: false,
BlockCacheSize: 32 << 20,
BlockCacheSize: 256 << 20,
IndexCacheSize: 0,
ZSTDCompressionLevel: 1,
EncryptionKey: []byte{},
+5 -2
View File
@@ -45,7 +45,10 @@ func Init() {
global.LOG.Fatalf("init entrance before start failed, err: %v", err)
}
sudo := cmd.SudoHandleCmd()
_, _ = cmd.Execf("%s sed -i '/CHANGE_USER_INFO=true/d' /usr/local/bin/1pctl", sudo)
if cmd.HasNoPasswordSudo() {
_, _ = cmd.Exec("sudo sed -i '/CHANGE_USER_INFO=true/d' /usr/local/bin/1pctl")
} else {
_, _ = cmd.Exec("sed -i '/CHANGE_USER_INFO=true/d' /usr/local/bin/1pctl")
}
}
}
-5
View File
@@ -26,11 +26,6 @@ func Init() {
migrations.UpdateTableHost,
migrations.UpdateTableWebsite,
migrations.AddEntranceAndSSL,
migrations.UpdateTableSetting,
migrations.UpdateTableAppDetail,
migrations.AddBindAndAllowIPs,
migrations.UpdateCronjobWithSecond,
migrations.UpdateWebsite,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)
-78
View File
@@ -2,7 +2,6 @@ package migrations
import (
"fmt"
"strings"
"time"
"github.com/1Panel-dev/1Panel/backend/app/model"
@@ -313,80 +312,3 @@ var AddEntranceAndSSL = &gormigrate.Migration{
return tx.AutoMigrate(&model.Website{})
},
}
var UpdateTableSetting = &gormigrate.Migration{
ID: "20200516-update-table-setting",
Migrate: func(tx *gorm.DB) error {
if err := tx.Create(&model.Setting{Key: "AppStoreLastModified", Value: "0"}).Error; err != nil {
return err
}
return nil
},
}
var UpdateTableAppDetail = &gormigrate.Migration{
ID: "20200517-update-table-app-detail",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.App{}); err != nil {
return err
}
if err := tx.AutoMigrate(&model.AppDetail{}); err != nil {
return err
}
return nil
},
}
var AddBindAndAllowIPs = &gormigrate.Migration{
ID: "20230517-add-bind-and-allow",
Migrate: func(tx *gorm.DB) error {
if err := tx.Create(&model.Setting{Key: "BindDomain", Value: ""}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "AllowIPs", Value: ""}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "TimeZone", Value: common.LoadTimeZoneByCmd()}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "NtpSite", Value: "pool.ntp.org"}).Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "MonitorInterval", Value: "1"}).Error; err != nil {
return err
}
return nil
},
}
var UpdateCronjobWithSecond = &gormigrate.Migration{
ID: "20200524-update-table-cronjob",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.Cronjob{}); err != nil {
return err
}
var jobs []model.Cronjob
if err := tx.Where("exclusion_rules != ?", "").Find(&jobs).Error; err != nil {
return err
}
for _, job := range jobs {
if strings.Contains(job.ExclusionRules, ";") {
newRules := strings.ReplaceAll(job.ExclusionRules, ";", ",")
if err := tx.Model(&model.Cronjob{}).Where("id = ?", job.ID).Update("exclusion_rules", newRules).Error; err != nil {
return err
}
}
}
return nil
},
}
var UpdateWebsite = &gormigrate.Migration{
ID: "20200530-update-table-website",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.Website{}); err != nil {
return err
}
return nil
},
}
+13 -15
View File
@@ -1,10 +1,11 @@
package router
import (
"github.com/gin-contrib/gzip"
"html/template"
"net/http"
"github.com/gin-contrib/gzip"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/i18n"
"github.com/1Panel-dev/1Panel/backend/middleware"
@@ -17,16 +18,23 @@ import (
ginSwagger "github.com/swaggo/gin-swagger"
)
func setWebStatic(rootRouter *gin.RouterGroup) {
rootRouter.StaticFS("/public", http.FS(web.Favicon))
func setWebStatic(rootRouter *gin.Engine) {
rootRouter.StaticFS("/fav", http.FS(web.Favicon))
rootRouter.GET("/assets/*filepath", func(c *gin.Context) {
staticServer := http.FileServer(http.FS(web.Assets))
staticServer.ServeHTTP(c.Writer, c.Request)
})
rootRouter.GET("/", func(c *gin.Context) {
staticServer := http.FileServer(http.FS(web.IndexHtml))
staticServer.ServeHTTP(c.Writer, c.Request)
})
rootRouter.NoRoute(func(c *gin.Context) {
c.Writer.WriteHeader(http.StatusOK)
_, _ = c.Writer.Write(web.IndexByte)
c.Writer.Header().Add("Accept", "text/html")
c.Writer.Flush()
})
}
func Routers() *gin.Engine {
@@ -37,14 +45,8 @@ func Routers() *gin.Engine {
if global.CONF.System.IsDemo {
Router.Use(middleware.DemoHandle())
}
Router.NoRoute(func(c *gin.Context) {
c.Writer.WriteHeader(http.StatusOK)
_, _ = c.Writer.Write(web.IndexByte)
c.Writer.Header().Add("Accept", "text/html")
c.Writer.Flush()
})
Router.Use(gzip.Gzip(gzip.DefaultCompression))
setWebStatic(Router)
Router.Use(i18n.GinI18nLocalize())
Router.SetFuncMap(template.FuncMap{
"Localize": ginI18n.GetMessage,
@@ -59,12 +61,8 @@ func Routers() *gin.Engine {
PublicGroup.GET("/health", func(c *gin.Context) {
c.JSON(200, "ok")
})
PublicGroup.Use(gzip.Gzip(gzip.DefaultCompression))
setWebStatic(PublicGroup)
}
PrivateGroup := Router.Group("/api/v1")
PrivateGroup.Use(middleware.WhiteAllow())
PrivateGroup.Use(middleware.BindDomain())
PrivateGroup.Use(middleware.GlobalLoading())
{
systemRouter.InitBaseRouter(PrivateGroup)
+2 -2
View File
@@ -1,16 +1,16 @@
package log
import (
"golang.org/x/sys/unix"
"os"
"runtime"
"syscall"
)
var stdErrFileHandler *os.File
func dupWrite(file *os.File) error {
stdErrFileHandler = file
if err := unix.Dup2(int(file.Fd()), int(os.Stderr.Fd())); err != nil {
if err := syscall.Dup2(int(file.Fd()), int(os.Stderr.Fd())); err != nil {
return err
}
runtime.SetFinalizer(stdErrFileHandler, func(fd *os.File) {

Some files were not shown because too many files have changed in this diff Show More