mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-12 16:00:33 +00:00
Compare commits
268
Commits
release-1.0
...
v1.2.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5bff6473e | ||
|
|
a1c0408aae | ||
|
|
ab523b6879 | ||
|
|
740b4c52d2 | ||
|
|
dbb94942df | ||
|
|
1e4ea2f8c3 | ||
|
|
8083837333 | ||
|
|
dd89933613 | ||
|
|
5101dace59 | ||
|
|
81c56a740c | ||
|
|
27cc3bcccd | ||
|
|
8ddaa26a57 | ||
|
|
3a848428c3 | ||
|
|
4c18f3aa1d | ||
|
|
be6278c0b7 | ||
|
|
d5e08d5db2 | ||
|
|
2d321b4a79 | ||
|
|
fcd764d521 | ||
|
|
7d4a8782d8 | ||
|
|
eea28e8481 | ||
|
|
71d679d426 | ||
|
|
2b23523bec | ||
|
|
149c26728c | ||
|
|
8c5c2440fe | ||
|
|
f22caed20c | ||
|
|
ed3e7e7c26 | ||
|
|
54bc33a1a2 | ||
|
|
900e141297 | ||
|
|
ca1eca476c | ||
|
|
c4d2593a42 | ||
|
|
932811c167 | ||
|
|
95ad101a08 | ||
|
|
a0c329019f | ||
|
|
8a92913230 | ||
|
|
5a8deddc63 | ||
|
|
2a1e60da44 | ||
|
|
6ca3deeac1 | ||
|
|
1b2edbb79a | ||
|
|
49c9929a53 | ||
|
|
8ce73a38dd | ||
|
|
28ebf7a0cc | ||
|
|
4f168656fc | ||
|
|
7f1f758e60 | ||
|
|
f8ab71953d | ||
|
|
eb50ee1c03 | ||
|
|
a184cb9bc4 | ||
|
|
0b50a10fb8 | ||
|
|
9bafdc1b0b | ||
|
|
63af54353b | ||
|
|
b67739af13 | ||
|
|
40633619ca | ||
|
|
e672d1d896 | ||
|
|
c69d162f5a | ||
|
|
2fd97b1753 | ||
|
|
5f893929da | ||
|
|
1c06b7b608 | ||
|
|
3ac64d65b6 | ||
|
|
f4f83283d3 | ||
|
|
aed4a55655 | ||
|
|
5f55a56a9e | ||
|
|
e95e79b572 | ||
|
|
15c0d0074b | ||
|
|
f4716cb62f | ||
|
|
1f2dfce7d1 | ||
|
|
c679631440 | ||
|
|
c62fd4841a | ||
|
|
a073113817 | ||
|
|
09d462b829 | ||
|
|
379b171f0a | ||
|
|
c424e22924 | ||
|
|
18e171446e | ||
|
|
c0a1555c73 | ||
|
|
3b0c844f33 | ||
|
|
566a4f3568 | ||
|
|
2c8b19bff2 | ||
|
|
292dca6419 | ||
|
|
ebe0f98209 | ||
|
|
eba1e5495f | ||
|
|
0ebd04f012 | ||
|
|
c5e8a3fa04 | ||
|
|
42b76fd82d | ||
|
|
bbf610569d | ||
|
|
eeb5fa81a1 | ||
|
|
f65ca6678f | ||
|
|
680f48dcba | ||
|
|
8947e00302 | ||
|
|
b42cf32326 | ||
|
|
5b68332b9a | ||
|
|
d7f53862e9 | ||
|
|
7887bf96de | ||
|
|
db2aa35b2f | ||
|
|
936b0e59ab | ||
|
|
6e3923d0da | ||
|
|
4377575206 | ||
|
|
0c09b12680 | ||
|
|
8a32d8032f | ||
|
|
9f12a91f4a | ||
|
|
dd0ca4bcaf | ||
|
|
14cc97eb44 | ||
|
|
2d31c5b005 | ||
|
|
05e7506f61 | ||
|
|
37806f1113 | ||
|
|
79622f324b | ||
|
|
34e84081e3 | ||
|
|
edf07be281 | ||
|
|
1208514f37 | ||
|
|
bfd857ec4b | ||
|
|
9435290bb6 | ||
|
|
acf64dcf25 | ||
|
|
2dd88364f8 | ||
|
|
d900b52a50 | ||
|
|
bd8d96be4d | ||
|
|
17dd07fe32 | ||
|
|
a06e5f28b3 | ||
|
|
d5f400670c | ||
|
|
5222388ba1 | ||
|
|
549ccbe6a0 | ||
|
|
7fd6afb17f | ||
|
|
2ff4da5e46 | ||
|
|
0f6e98be20 | ||
|
|
4399ffa9a4 | ||
|
|
44a1d9d16c | ||
|
|
565fd1c605 | ||
|
|
09ac40846f | ||
|
|
a0b820649e | ||
|
|
6cee4bfe7c | ||
|
|
ad0c859b54 | ||
|
|
d660b7d315 | ||
|
|
2dbc7f28fd | ||
|
|
e224bc4b24 | ||
|
|
9c52977825 | ||
|
|
cb151dc985 | ||
|
|
24b9f8f705 | ||
|
|
5592063e69 | ||
|
|
7b19aab305 | ||
|
|
5c50695bdc | ||
|
|
1086597e3a | ||
|
|
2944ea508e | ||
|
|
5e887bd00c | ||
|
|
76b3cf4d2b | ||
|
|
4a9895218e | ||
|
|
222593ea69 | ||
|
|
05b7fd1f63 | ||
|
|
256c04f3b8 | ||
|
|
02577ef746 | ||
|
|
059c3a0b80 | ||
|
|
5ce1b1591a | ||
|
|
6595ad6228 | ||
|
|
e7608673d7 | ||
|
|
4c8fc1defa | ||
|
|
975663f0ff | ||
|
|
9603389586 | ||
|
|
cd79cac0af | ||
|
|
d151e98fab | ||
|
|
6115ffe0fc | ||
|
|
b646c5385d | ||
|
|
04a1cff37e | ||
|
|
a5be9ca226 | ||
|
|
0356bdbf54 | ||
|
|
4c276ff383 | ||
|
|
f8432ba521 | ||
|
|
7f75ea06c2 | ||
|
|
11d3e98155 | ||
|
|
01185306f2 | ||
|
|
6ff9c4335f | ||
|
|
b2e38c320d | ||
|
|
c63897ded4 | ||
|
|
d6dcb59ab7 | ||
|
|
bd1ced0af7 | ||
|
|
1bbf501783 | ||
|
|
b16308b7ea | ||
|
|
42531dae5a | ||
|
|
aeb9135cde | ||
|
|
f092927ab8 | ||
|
|
3ac467fc53 | ||
|
|
b9e1de8446 | ||
|
|
245bbf651b | ||
|
|
a8b83cf4ed | ||
|
|
38725097a6 | ||
|
|
e935fa128f | ||
|
|
ef16934952 | ||
|
|
550872a564 | ||
|
|
e746a959af | ||
|
|
ab0f4380b2 | ||
|
|
7c236ccc3a | ||
|
|
52030dbea0 | ||
|
|
4e20ec1c9b | ||
|
|
0ddbdfeac9 | ||
|
|
a5fd55e90e | ||
|
|
844a6c11b4 | ||
|
|
a4cab09b62 | ||
|
|
12d010351a | ||
|
|
d00e5b0421 | ||
|
|
4c2fb7095d | ||
|
|
cca1406f0f | ||
|
|
1bba2664b6 | ||
|
|
cc51eaef3f | ||
|
|
2bd289defa | ||
|
|
47d090d481 | ||
|
|
4a4c2b24dd | ||
|
|
8603d4347b | ||
|
|
188a3e0ac5 | ||
|
|
a22efc90f6 | ||
|
|
d0d76c023f | ||
|
|
241a4e62ac | ||
|
|
295f2a5cf2 | ||
|
|
e3cf522565 | ||
|
|
0f1107314f | ||
|
|
18c5c99705 | ||
|
|
18b4c98daa | ||
|
|
24246da71c | ||
|
|
49ab26200d | ||
|
|
5c524f0d23 | ||
|
|
15d7d74c1b | ||
|
|
29979b23c2 | ||
|
|
3de223144d | ||
|
|
18029d8369 | ||
|
|
fb62ac17e5 | ||
|
|
dbe70ecc28 | ||
|
|
74b6af64e9 | ||
|
|
fa83199d7b | ||
|
|
750a2a445e | ||
|
|
6fb1e690aa | ||
|
|
77c0eb99f0 | ||
|
|
db64cf02bd | ||
|
|
57a6417812 | ||
|
|
12beef49b5 | ||
|
|
155363afa6 | ||
|
|
3b3fad7278 | ||
|
|
b6c4c4539f | ||
|
|
807302f6cd | ||
|
|
8902111c23 | ||
|
|
e45ef455ef | ||
|
|
0eb25d8413 | ||
|
|
a0e4c266a1 | ||
|
|
e452dfdb1f | ||
|
|
e3b542665d | ||
|
|
a481a8b322 | ||
|
|
1b5387dc5a | ||
|
|
281cf48aaa | ||
|
|
ce2b92ee01 | ||
|
|
daba12ee42 | ||
|
|
363a67b0f2 | ||
|
|
1a1a14719d | ||
|
|
5706de5ca7 | ||
|
|
947293f34e | ||
|
|
04a76fd94d | ||
|
|
c629fa9575 | ||
|
|
d4c1caa26a | ||
|
|
22d9bdacf6 | ||
|
|
64a954df53 | ||
|
|
1949be2490 | ||
|
|
8be00dad7f | ||
|
|
bf9a37623a | ||
|
|
3de0ae1b0f | ||
|
|
57a2c2616b | ||
|
|
c63967158b | ||
|
|
8902fdc78a | ||
|
|
1c5d01b11c | ||
|
|
c1c324af23 | ||
|
|
db74d010d7 | ||
|
|
c9d36d84f7 | ||
|
|
d5f446d7cf | ||
|
|
a2fcdabb7b | ||
|
|
a434bbbc12 | ||
|
|
2585801f8a | ||
|
|
c501d9fefe | ||
|
|
1d99559d4c |
@@ -11,15 +11,19 @@ SERVER_PATH=$(BASE_PAH)/backend
|
|||||||
MAIN= $(BASE_PAH)/cmd/server/main.go
|
MAIN= $(BASE_PAH)/cmd/server/main.go
|
||||||
APP_NAME=1panel
|
APP_NAME=1panel
|
||||||
|
|
||||||
build_web:
|
build_frontend:
|
||||||
cd $(WEB_PATH) && npm install && npm run build:dev
|
cd $(WEB_PATH) && npm install && npm run build:dev
|
||||||
|
|
||||||
build_bin:
|
build_backend_on_linux:
|
||||||
cd $(SERVER_PATH) \
|
cd $(SERVER_PATH) \
|
||||||
&& CGO_ENABLED=1 GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOBUILD) -trimpath -ldflags '-s -w --extldflags "-static -fpic"' -tags 'osusergo,netgo' -o $(BUILD_PATH)/$(APP_NAME) $(MAIN)
|
&& CGO_ENABLED=1 GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOBUILD) -trimpath -ldflags '-s -w --extldflags "-static -fpic"' -tags 'osusergo,netgo' -o $(BUILD_PATH)/$(APP_NAME) $(MAIN)
|
||||||
|
|
||||||
build_linux_on_mac:
|
build_backend_on_darwin:
|
||||||
cd $(SERVER_PATH) \
|
cd $(SERVER_PATH) \
|
||||||
&& CGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC=x86_64-linux-musl-gcc CXX=x86_64-linux-musl-g++ $(GOBUILD) -trimpath -ldflags '-s -w --extldflags "-static -fpic"' -o $(BUILD_PATH)/$(APP_NAME) $(MAIN)
|
&& CGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC=x86_64-linux-musl-gcc CXX=x86_64-linux-musl-g++ $(GOBUILD) -trimpath -ldflags '-s -w --extldflags "-static -fpic"' -o $(BUILD_PATH)/$(APP_NAME) $(MAIN)
|
||||||
|
|
||||||
build_all: build_web build_bin
|
build_backend_on_archlinux:
|
||||||
|
cd $(SERVER_PATH) \
|
||||||
|
&& 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
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
1Panel 是一个现代化、开源的 Linux 服务器运维管理面板。1Panel 的功能和优势包括:
|
1Panel 是一个现代化、开源的 Linux 服务器运维管理面板。1Panel 的功能和优势包括:
|
||||||
|
|
||||||
- **快速建站**:深度集成 Wordpress 和 [Halo](https://github.com/halo-dev/halo/),域名绑定、SSL 证书配置等一键搞定;
|
- **快速建站**:深度集成 Wordpress 和 [Halo](https://github.com/halo-dev/halo/),域名绑定、SSL 证书配置等一键搞定;
|
||||||
- **高效管理**:通过 Web 端轻松管理 Linux 服务器,包括应用管理、主机监控、文件管理、数据库管理、容器管理等;
|
- **高效管理**:通过 Web 端轻松管理 Linux 服务器,包括主机监控、文件管理、数据库管理、容器管理等;
|
||||||
- **安全可靠**:最小漏洞暴露面,提供防火墙和安全审计等功能;
|
- **安全可靠**:基于容器来管理和部署应用,最小漏洞暴露面,提供防火墙和日志审计等功能;
|
||||||
- **一键备份**:支持一键备份和恢复,备份数据云端存储,永不丢失。
|
- **一键备份**:支持一键备份和恢复,备份数据到各类云端存储,永不丢失。
|
||||||
|
|
||||||
## UI 展示
|
## UI 展示
|
||||||
|
|
||||||
@@ -41,12 +41,9 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
|
|||||||
|
|
||||||
- [在线文档](https://1panel.cn/docs/)
|
- [在线文档](https://1panel.cn/docs/)
|
||||||
- [教学视频](https://space.bilibili.com/510493147/channel/collectiondetail?sid=1199760)
|
- [教学视频](https://space.bilibili.com/510493147/channel/collectiondetail?sid=1199760)
|
||||||
|
- [社区论坛](https://bbs.fit2cloud.com/c/1p/7)
|
||||||
|
|
||||||
## 社区
|
**加入微信交流群**
|
||||||
|
|
||||||
如果您在使用过程中有任何疑问或对建议,欢迎提交 GitHub Issue 或加入到我们微信交流群进行交流沟通。
|
|
||||||
|
|
||||||
**微信交流群**
|
|
||||||
|
|
||||||
<img src="https://1panel.cn/img/wechat-group.jpg" width="156" height="156"/>
|
<img src="https://1panel.cn/img/wechat-group.jpg" width="156" height="156"/>
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
如果您发现安全问题,请直接联系我们:
|
如果您发现安全问题,请直接联系我们:
|
||||||
|
|
||||||
- wanghe@fit2cloud.com
|
- wanghe@fit2cloud.com
|
||||||
|
- zhengkun@fit2cloud.com
|
||||||
- support@fit2cloud.com
|
- support@fit2cloud.com
|
||||||
- 400-052-0755
|
- 400-052-0755
|
||||||
|
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
All security bugs should be reported to the contact as below:
|
All security bugs should be reported to the contact as below:
|
||||||
|
|
||||||
- wanghe@fit2cloud.com
|
- wanghe@fit2cloud.com
|
||||||
|
- zhengkun@fit2cloud.com
|
||||||
- support@fit2cloud.com
|
- support@fit2cloud.com
|
||||||
- 400-052-0755
|
- 400-052-0755
|
||||||
|
|
||||||
|
|||||||
+37
-11
@@ -38,13 +38,15 @@ func (b *BaseApi) SearchApp(c *gin.Context) {
|
|||||||
// @Router /apps/sync [post]
|
// @Router /apps/sync [post]
|
||||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"应用商店同步","formatEN":"App store synchronization"}
|
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"应用商店同步","formatEN":"App store synchronization"}
|
||||||
func (b *BaseApi) SyncApp(c *gin.Context) {
|
func (b *BaseApi) SyncApp(c *gin.Context) {
|
||||||
global.LOG.Infof("sync app list start ...")
|
go appService.SyncAppListFromLocal()
|
||||||
if err := appService.SyncAppList(); err != nil {
|
go func() {
|
||||||
global.LOG.Errorf("sync app list error [%s]", err.Error())
|
global.LOG.Infof("sync app list start ...")
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
if err := appService.SyncAppListFromRemote(); err != nil {
|
||||||
return
|
global.LOG.Errorf("sync app list error [%s]", err.Error())
|
||||||
}
|
} else {
|
||||||
global.LOG.Infof("sync app list success!")
|
global.LOG.Infof("sync app list success!")
|
||||||
|
}
|
||||||
|
}()
|
||||||
helper.SuccessWithData(c, "")
|
helper.SuccessWithData(c, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,14 +73,15 @@ func (b *BaseApi) GetApp(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// @Tags App
|
// @Tags App
|
||||||
// @Summary Search app detail by id
|
// @Summary Search app detail by appid
|
||||||
// @Description 通过 id 获取应用详情
|
// @Description 通过 appid 获取应用详情
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param appId path integer true "app id"
|
// @Param appId path integer true "app id"
|
||||||
// @Param version path string true "app 版本"
|
// @Param version path string true "app 版本"
|
||||||
|
// @Param version path string true "app 类型"
|
||||||
// @Success 200 {object} response.AppDetailDTO
|
// @Success 200 {object} response.AppDetailDTO
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /apps/detail/:appId/:version [get]
|
// @Router /apps/detail/:appId/:version/:type [get]
|
||||||
func (b *BaseApi) GetAppDetail(c *gin.Context) {
|
func (b *BaseApi) GetAppDetail(c *gin.Context) {
|
||||||
appId, err := helper.GetIntParamByKey(c, "appId")
|
appId, err := helper.GetIntParamByKey(c, "appId")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -86,7 +89,30 @@ func (b *BaseApi) GetAppDetail(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
version := c.Param("version")
|
version := c.Param("version")
|
||||||
appDetailDTO, err := appService.GetAppDetail(appId, version)
|
appType := c.Param("type")
|
||||||
|
appDetailDTO, err := appService.GetAppDetail(appId, version, appType)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, appDetailDTO)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags App
|
||||||
|
// @Summary Get app detail by id
|
||||||
|
// @Description 通过 id 获取应用详情
|
||||||
|
// @Accept json
|
||||||
|
// @Param appId path integer true "id"
|
||||||
|
// @Success 200 {object} response.AppDetailDTO
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /apps/details/:id [get]
|
||||||
|
func (b *BaseApi) GetAppDetailByID(c *gin.Context) {
|
||||||
|
appDetailID, err := helper.GetIntParamByKey(c, "id")
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
appDetailDTO, err := appService.GetAppDetailByID(appDetailID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -93,24 +93,24 @@ func (b *BaseApi) LoadPort(c *gin.Context) {
|
|||||||
|
|
||||||
// @Tags App
|
// @Tags App
|
||||||
// @Summary Search app password by key
|
// @Summary Search app password by key
|
||||||
// @Description 获取应用密码
|
// @Description 获取应用连接信息
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param key path string true "request"
|
// @Param key path string true "request"
|
||||||
// @Success 200 {string} password
|
// @Success 200 {string} response.DatabaseConn
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /apps/installed/loadpassword/:key [get]
|
// @Router /apps/installed/conninfo/:key [get]
|
||||||
func (b *BaseApi) LoadPassword(c *gin.Context) {
|
func (b *BaseApi) LoadConnInfo(c *gin.Context) {
|
||||||
key, ok := c.Params.Get("key")
|
key, ok := c.Params.Get("key")
|
||||||
if !ok {
|
if !ok {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error key in path"))
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error key in path"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
password, err := appInstallService.LoadPassword(key)
|
conn, err := appInstallService.LoadConnInfo(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
helper.SuccessWithData(c, password)
|
helper.SuccessWithData(c, conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags App
|
// @Tags App
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
@@ -28,7 +26,7 @@ func (b *BaseApi) Login(c *gin.Context) {
|
|||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if req.AuthMethod != "jwt" {
|
if req.AuthMethod != "jwt" && !req.IgnoreCaptcha {
|
||||||
if err := captcha.VerifyCode(req.CaptchaID, req.Captcha); err != nil {
|
if err := captcha.VerifyCode(req.CaptchaID, req.Captcha); err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
@@ -102,71 +100,10 @@ func (b *BaseApi) Captcha(c *gin.Context) {
|
|||||||
// @Summary Load safety status
|
// @Summary Load safety status
|
||||||
// @Description 获取系统安全登录状态
|
// @Description 获取系统安全登录状态
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Failure 402
|
// @Router /auth/issafety [get]
|
||||||
// @Router /auth/status [get]
|
func (b *BaseApi) CheckIsSafety(c *gin.Context) {
|
||||||
func (b *BaseApi) GetSafetyStatus(c *gin.Context) {
|
code := c.DefaultQuery("code", "")
|
||||||
if err := authService.SafetyStatus(c); err != nil {
|
helper.SuccessWithData(c, authService.CheckIsSafety(code))
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrUnSafety, constant.ErrTypeNotSafety, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
helper.SuccessWithData(c, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BaseApi) SafeEntrance(c *gin.Context) {
|
|
||||||
code, exist := c.Params.Get("code")
|
|
||||||
if !exist {
|
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrUnSafety, constant.ErrTypeNotSafety, errors.New("missing code"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ok, err := authService.VerifyCode(code)
|
|
||||||
if err != nil {
|
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrUnSafety, constant.ErrTypeNotSafety, errors.New("missing code"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrUnSafety, constant.ErrTypeNotSafety, errors.New("missing code"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := authService.SafeEntrance(c, code); err != nil {
|
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrUnSafety, constant.ErrTypeNotSafety, errors.New("missing code"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
helper.SuccessWithData(c, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Tags Auth
|
|
||||||
// @Summary Check is First login
|
|
||||||
// @Description 判断是否为首次登录
|
|
||||||
// @Success 200
|
|
||||||
// @Router /auth/status [get]
|
|
||||||
func (b *BaseApi) CheckIsFirstLogin(c *gin.Context) {
|
|
||||||
helper.SuccessWithData(c, authService.CheckIsFirst())
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Tags Auth
|
|
||||||
// @Summary Init user
|
|
||||||
// @Description 初始化用户
|
|
||||||
// @Accept json
|
|
||||||
// @Param request body dto.InitUser true "request"
|
|
||||||
// @Success 200
|
|
||||||
// @Router /auth/init [post]
|
|
||||||
func (b *BaseApi) InitUserInfo(c *gin.Context) {
|
|
||||||
var req dto.InitUser
|
|
||||||
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 := authService.InitUser(c, req); err != nil {
|
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
helper.SuccessWithData(c, nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags Auth
|
// @Tags Auth
|
||||||
|
|||||||
@@ -104,9 +104,9 @@ func (b *BaseApi) ListBuckets(c *gin.Context) {
|
|||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /settings/backup/del [post]
|
// @Router /settings/backup/del [post]
|
||||||
// @x-panel-log {"bodyKeys":["ids"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"ids","isList":true,"db":"backup_accounts","output_colume":"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) {
|
func (b *BaseApi) DeleteBackup(c *gin.Context) {
|
||||||
var req dto.BatchDeleteReq
|
var req dto.OperateByID
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
return
|
||||||
@@ -116,7 +116,7 @@ func (b *BaseApi) DeleteBackup(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := backupService.BatchDelete(req.Ids); err != nil {
|
if err := backupService.Delete(req.ID); err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -77,8 +78,9 @@ func (b *BaseApi) SearchJobRecords(c *gin.Context) {
|
|||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
req.StartTime = req.StartTime.Add(8 * time.Hour)
|
loc, _ := time.LoadLocation(common.LoadTimeZone())
|
||||||
req.EndTime = req.EndTime.Add(8 * time.Hour)
|
req.StartTime = req.StartTime.In(loc)
|
||||||
|
req.EndTime = req.EndTime.In(loc)
|
||||||
|
|
||||||
total, list, err := cronjobService.SearchRecords(req)
|
total, list, err := cronjobService.SearchRecords(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -92,17 +94,41 @@ func (b *BaseApi) SearchJobRecords(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Tags Cronjob
|
||||||
|
// @Summary Clean job records
|
||||||
|
// @Description 清空计划任务记录
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.CronjobClean true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /cronjobs/records/clean [post]
|
||||||
|
// @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 {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cronjobService.CleanRecord(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
// @Tags Cronjob
|
// @Tags Cronjob
|
||||||
// @Summary Delete cronjob
|
// @Summary Delete cronjob
|
||||||
// @Description 删除计划任务
|
// @Description 删除计划任务
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.BatchDeleteReq true "request"
|
// @Param request body dto.CronjobBatchDelete true "request"
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /cronjobs/del [post]
|
// @Router /cronjobs/del [post]
|
||||||
// @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]"}
|
// @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) {
|
func (b *BaseApi) DeleteCronjob(c *gin.Context) {
|
||||||
var req dto.BatchDeleteReq
|
var req dto.CronjobBatchDelete
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
return
|
||||||
@@ -112,7 +138,7 @@ func (b *BaseApi) DeleteCronjob(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cronjobService.Delete(req.Ids); err != nil {
|
if err := cronjobService.Delete(req); err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||||
@@ -35,7 +34,7 @@ func (b *BaseApi) LoadDaemonJsonFile(c *gin.Context) {
|
|||||||
helper.SuccessWithData(c, "daemon.json is not find in path")
|
helper.SuccessWithData(c, "daemon.json is not find in path")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
content, err := ioutil.ReadFile(constant.DaemonJsonPath)
|
content, err := os.ReadFile(constant.DaemonJsonPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
|
|||||||
+28
-25
@@ -9,40 +9,43 @@ type ApiGroup struct {
|
|||||||
var ApiGroupApp = new(ApiGroup)
|
var ApiGroupApp = new(ApiGroup)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
authService = service.ServiceGroupApp.AuthService
|
authService = service.NewIAuthService()
|
||||||
dashboardService = service.ServiceGroupApp.DashboardService
|
dashboardService = service.NewIDashboardService()
|
||||||
|
|
||||||
appService = service.NewIAppService()
|
appService = service.NewIAppService()
|
||||||
appInstallService = service.ServiceGroupApp.AppInstallService
|
appInstallService = service.NewIAppInstalledService()
|
||||||
|
|
||||||
containerService = service.ServiceGroupApp.ContainerService
|
containerService = service.NewIContainerService()
|
||||||
composeTemplateService = service.ServiceGroupApp.ComposeTemplateService
|
composeTemplateService = service.NewIComposeTemplateService()
|
||||||
imageRepoService = service.ServiceGroupApp.ImageRepoService
|
imageRepoService = service.NewIImageRepoService()
|
||||||
imageService = service.ServiceGroupApp.ImageService
|
imageService = service.NewIImageService()
|
||||||
dockerService = service.ServiceGroupApp.DockerService
|
dockerService = service.NewIDockerService()
|
||||||
|
|
||||||
mysqlService = service.ServiceGroupApp.MysqlService
|
mysqlService = service.NewIMysqlService()
|
||||||
redisService = service.ServiceGroupApp.RedisService
|
redisService = service.NewIRedisService()
|
||||||
|
|
||||||
cronjobService = service.ServiceGroupApp.CronjobService
|
cronjobService = service.NewICronjobService()
|
||||||
|
|
||||||
hostService = service.ServiceGroupApp.HostService
|
hostService = service.NewIHostService()
|
||||||
groupService = service.ServiceGroupApp.GroupService
|
groupService = service.NewIGroupService()
|
||||||
fileService = service.ServiceGroupApp.FileService
|
fileService = service.NewIFileService()
|
||||||
|
firewallService = service.NewIFirewallService()
|
||||||
|
|
||||||
settingService = service.ServiceGroupApp.SettingService
|
settingService = service.NewISettingService()
|
||||||
backupService = service.ServiceGroupApp.BackupService
|
backupService = service.NewIBackupService()
|
||||||
|
|
||||||
commandService = service.ServiceGroupApp.CommandService
|
commandService = service.NewICommandService()
|
||||||
|
|
||||||
websiteService = service.ServiceGroupApp.WebsiteService
|
websiteService = service.NewIWebsiteService()
|
||||||
websiteDnsAccountService = service.ServiceGroupApp.WebsiteDnsAccountService
|
websiteDnsAccountService = service.NewIWebsiteDnsAccountService()
|
||||||
websiteSSLService = service.ServiceGroupApp.WebsiteSSLService
|
websiteSSLService = service.NewIWebsiteSSLService()
|
||||||
websiteAcmeAccountService = service.ServiceGroupApp.WebsiteAcmeAccountService
|
websiteAcmeAccountService = service.NewIWebsiteAcmeAccountService()
|
||||||
|
|
||||||
nginxService = service.ServiceGroupApp.NginxService
|
nginxService = service.NewINginxService()
|
||||||
|
|
||||||
logService = service.ServiceGroupApp.LogService
|
logService = service.NewILogService()
|
||||||
snapshotService = service.ServiceGroupApp.SnapshotService
|
snapshotService = service.NewISnapshotService()
|
||||||
upgradeService = service.ServiceGroupApp.UpgradeService
|
upgradeService = service.NewIUpgradeService()
|
||||||
|
|
||||||
|
runtimeService = service.NewRuntimeService()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package v1
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
@@ -186,7 +186,29 @@ func (b *BaseApi) ChangeFileMode(c *gin.Context) {
|
|||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
helper.SuccessWithData(c, nil)
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags File
|
||||||
|
// @Summary Change file owner
|
||||||
|
// @Description 修改文件用户/组
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.FileRoleUpdate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /files/owner [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["path","user","group"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改用户/组 [paths] => [user]/[group]","formatEN":"Change owner [paths] => [user]/[group]"}
|
||||||
|
func (b *BaseApi) ChangeFileOwner(c *gin.Context) {
|
||||||
|
var req request.FileRoleUpdate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := fileService.ChangeOwner(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags File
|
// @Tags File
|
||||||
@@ -498,7 +520,6 @@ func (b *BaseApi) Size(c *gin.Context) {
|
|||||||
// @Success 200 {string} content
|
// @Success 200 {string} content
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /files/loadfile [post]
|
// @Router /files/loadfile [post]
|
||||||
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"读取文件 [path]","formatEN":"Read file [path]"}
|
|
||||||
func (b *BaseApi) LoadFromFile(c *gin.Context) {
|
func (b *BaseApi) LoadFromFile(c *gin.Context) {
|
||||||
var req dto.FilePath
|
var req dto.FilePath
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
@@ -510,7 +531,7 @@ func (b *BaseApi) LoadFromFile(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
content, err := ioutil.ReadFile(req.Path)
|
content, err := os.ReadFile(req.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
@@ -533,7 +554,7 @@ func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int)
|
|||||||
|
|
||||||
for i := 0; i < chunkCount; i++ {
|
for i := 0; i < chunkCount; i++ {
|
||||||
chunkPath := filepath.Join(fileDir, fmt.Sprintf("%s.%d", fileName, i))
|
chunkPath := filepath.Join(fileDir, fmt.Sprintf("%s.%d", fileName, i))
|
||||||
chunkData, err := ioutil.ReadFile(chunkPath)
|
chunkData, err := os.ReadFile(chunkPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -599,14 +620,14 @@ func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
defer emptyFile.Close()
|
defer emptyFile.Close()
|
||||||
|
|
||||||
chunkData, err := ioutil.ReadAll(uploadFile)
|
chunkData, err := io.ReadAll(uploadFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrFileUpload, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrFileUpload, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
chunkPath := filepath.Join(fileDir, fmt.Sprintf("%s.%d", filename, chunkIndex))
|
chunkPath := filepath.Join(fileDir, fmt.Sprintf("%s.%d", filename, chunkIndex))
|
||||||
err = ioutil.WriteFile(chunkPath, chunkData, 0644)
|
err = os.WriteFile(chunkPath, chunkData, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrFileUpload, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrFileUpload, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -0,0 +1,207 @@
|
|||||||
|
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 Firewall
|
||||||
|
// @Summary Load firewall base info
|
||||||
|
// @Description 获取防火墙基础信息
|
||||||
|
// @Success 200 {object} dto.FirewallBaseInfo
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /hosts/firewall/base [get]
|
||||||
|
func (b *BaseApi) LoadFirewallBaseInfo(c *gin.Context) {
|
||||||
|
data, err := firewallService.LoadBaseInfo()
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Firewall
|
||||||
|
// @Summary Page firewall rules
|
||||||
|
// @Description 获取防火墙规则列表分页
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.SearchWithPage true "request"
|
||||||
|
// @Success 200 {object} dto.PageResult
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /hosts/firewall/search [post]
|
||||||
|
func (b *BaseApi) SearchFirewallRule(c *gin.Context) {
|
||||||
|
var req dto.RuleSearch
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
total, list, err := firewallService.SearchWithPage(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, dto.PageResult{
|
||||||
|
Items: list,
|
||||||
|
Total: total,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Firewall
|
||||||
|
// @Summary Page firewall status
|
||||||
|
// @Description 修改防火墙状态
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.FirewallOperation true "request"
|
||||||
|
// @Success 200 {object} dto.PageResult
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /hosts/firewall/operate [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["operation"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"[operation] 防火墙","formatEN":"[operation] firewall"}
|
||||||
|
func (b *BaseApi) OperateFirewall(c *gin.Context) {
|
||||||
|
var req dto.FirewallOperation
|
||||||
|
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 := firewallService.OperateFirewall(req.Operation); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Firewall
|
||||||
|
// @Summary Create group
|
||||||
|
// @Description 创建防火墙端口规则
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.PortRuleOperate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /hosts/firewall/port [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["port","strategy"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"添加端口规则 [strategy] [port]","formatEN":"create port rules [strategy][port]"}
|
||||||
|
func (b *BaseApi) OperatePortRule(c *gin.Context) {
|
||||||
|
var req dto.PortRuleOperate
|
||||||
|
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 := firewallService.OperatePortRule(req, true); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Firewall
|
||||||
|
// @Summary Create group
|
||||||
|
// @Description 创建防火墙 IP 规则
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.AddrRuleOperate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /hosts/firewall/ip [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["strategy","address"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"添加 ip 规则 [strategy] [address]","formatEN":"create address rules [strategy][address]"}
|
||||||
|
func (b *BaseApi) OperateIPRule(c *gin.Context) {
|
||||||
|
var req dto.AddrRuleOperate
|
||||||
|
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 := firewallService.OperateAddressRule(req, true); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Firewall
|
||||||
|
// @Summary Create group
|
||||||
|
// @Description 批量删除防火墙规则
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.BatchRuleOperate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /hosts/firewall/ip [post]
|
||||||
|
func (b *BaseApi) BatchOperateRule(c *gin.Context) {
|
||||||
|
var req dto.BatchRuleOperate
|
||||||
|
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 := firewallService.BacthOperateRule(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Firewall
|
||||||
|
// @Summary Create group
|
||||||
|
// @Description 更新端口防火墙规则
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.PortRuleUpdate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /hosts/firewall/update/port [post]
|
||||||
|
func (b *BaseApi) UpdatePortRule(c *gin.Context) {
|
||||||
|
var req dto.PortRuleUpdate
|
||||||
|
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 := firewallService.UpdatePortRule(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Firewall
|
||||||
|
// @Summary Create group
|
||||||
|
// @Description 更新 ip 防火墙规则
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.AddrRuleUpdate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /hosts/firewall/update/ip [post]
|
||||||
|
func (b *BaseApi) UpdateAddrRule(c *gin.Context) {
|
||||||
|
var req dto.AddrRuleUpdate
|
||||||
|
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 := firewallService.UpdateAddrRule(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
// @Param request body dto.GroupCreate true "request"
|
// @Param request body dto.GroupCreate true "request"
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /hosts/group [post]
|
// @Router /groups [post]
|
||||||
// @x-panel-log {"bodyKeys":["name","type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建组 [name][type]","formatEN":"create group [name][type]"}
|
// @x-panel-log {"bodyKeys":["name","type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建组 [name][type]","formatEN":"create group [name][type]"}
|
||||||
func (b *BaseApi) CreateGroup(c *gin.Context) {
|
func (b *BaseApi) CreateGroup(c *gin.Context) {
|
||||||
var req dto.GroupCreate
|
var req dto.GroupCreate
|
||||||
@@ -41,7 +41,7 @@ func (b *BaseApi) CreateGroup(c *gin.Context) {
|
|||||||
// @Param request body dto.OperateByID true "request"
|
// @Param request body dto.OperateByID true "request"
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /hosts/group/del [post]
|
// @Router /groups/del [post]
|
||||||
// @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]"}
|
// @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) {
|
func (b *BaseApi) DeleteGroup(c *gin.Context) {
|
||||||
var req dto.OperateByID
|
var req dto.OperateByID
|
||||||
@@ -68,7 +68,7 @@ func (b *BaseApi) DeleteGroup(c *gin.Context) {
|
|||||||
// @Param request body dto.GroupUpdate true "request"
|
// @Param request body dto.GroupUpdate true "request"
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /hosts/group/update [post]
|
// @Router /groups/update [post]
|
||||||
// @x-panel-log {"bodyKeys":["name","type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新组 [name][type]","formatEN":"update group [name][type]"}
|
// @x-panel-log {"bodyKeys":["name","type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新组 [name][type]","formatEN":"update group [name][type]"}
|
||||||
func (b *BaseApi) UpdateGroup(c *gin.Context) {
|
func (b *BaseApi) UpdateGroup(c *gin.Context) {
|
||||||
var req dto.GroupUpdate
|
var req dto.GroupUpdate
|
||||||
@@ -94,7 +94,7 @@ func (b *BaseApi) UpdateGroup(c *gin.Context) {
|
|||||||
// @Param request body dto.GroupSearch true "request"
|
// @Param request body dto.GroupSearch true "request"
|
||||||
// @Success 200 {anrry} dto.GroupInfo
|
// @Success 200 {anrry} dto.GroupInfo
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /hosts/group/search [post]
|
// @Router /groups/search [post]
|
||||||
func (b *BaseApi) ListGroup(c *gin.Context) {
|
func (b *BaseApi) ListGroup(c *gin.Context) {
|
||||||
var req dto.GroupSearch
|
var req dto.GroupSearch
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
|||||||
@@ -83,6 +83,15 @@ func SuccessWithData(ctx *gin.Context, data interface{}) {
|
|||||||
ctx.Abort()
|
ctx.Abort()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SuccessWithOutData(ctx *gin.Context) {
|
||||||
|
res := dto.Response{
|
||||||
|
Code: constant.CodeSuccess,
|
||||||
|
Message: "success",
|
||||||
|
}
|
||||||
|
ctx.JSON(http.StatusOK, res)
|
||||||
|
ctx.Abort()
|
||||||
|
}
|
||||||
|
|
||||||
func SuccessWithMsg(ctx *gin.Context, msg string) {
|
func SuccessWithMsg(ctx *gin.Context, msg string) {
|
||||||
res := dto.Response{
|
res := dto.Response{
|
||||||
Code: constant.CodeSuccess,
|
Code: constant.CodeSuccess,
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/copier"
|
"github.com/1Panel-dev/1Panel/backend/utils/copier"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/ssh"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -74,33 +73,9 @@ func (b *BaseApi) TestByInfo(c *gin.Context) {
|
|||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if req.AuthMode == "password" && len(req.Password) != 0 {
|
|
||||||
password, err := base64.StdEncoding.DecodeString(req.Password)
|
|
||||||
if err != nil {
|
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
req.Password = string(password)
|
|
||||||
}
|
|
||||||
if req.AuthMode == "key" && len(req.PrivateKey) != 0 {
|
|
||||||
privateKey, err := base64.StdEncoding.DecodeString(req.PrivateKey)
|
|
||||||
if err != nil {
|
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
req.PrivateKey = string(privateKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
var connInfo ssh.ConnInfo
|
connStatus := hostService.TestByInfo(req)
|
||||||
_ = copier.Copy(&connInfo, &req)
|
helper.SuccessWithData(c, connStatus)
|
||||||
connInfo.PrivateKey = []byte(req.PrivateKey)
|
|
||||||
client, err := connInfo.NewClient()
|
|
||||||
if err != nil {
|
|
||||||
helper.SuccessWithData(c, false)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer client.Close()
|
|
||||||
helper.SuccessWithData(c, true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags Host
|
// @Tags Host
|
||||||
@@ -270,11 +245,13 @@ func (b *BaseApi) UpdateHost(c *gin.Context) {
|
|||||||
upMap["port"] = req.Port
|
upMap["port"] = req.Port
|
||||||
upMap["user"] = req.User
|
upMap["user"] = req.User
|
||||||
upMap["auth_mode"] = req.AuthMode
|
upMap["auth_mode"] = req.AuthMode
|
||||||
|
upMap["remember_password"] = req.RememberPassword
|
||||||
if len(req.Password) != 0 {
|
if len(req.Password) != 0 {
|
||||||
upMap["password"] = req.Password
|
upMap["password"] = req.Password
|
||||||
}
|
}
|
||||||
if len(req.PrivateKey) != 0 {
|
if len(req.PrivateKey) != 0 {
|
||||||
upMap["private_key"] = req.PrivateKey
|
upMap["private_key"] = req.PrivateKey
|
||||||
|
upMap["pass_phrase"] = req.PassPhrase
|
||||||
}
|
}
|
||||||
upMap["description"] = req.Description
|
upMap["description"] = req.Description
|
||||||
if err := hostService.Update(req.ID, upMap); err != nil {
|
if err := hostService.Update(req.ID, upMap); err != nil {
|
||||||
@@ -291,7 +268,7 @@ func (b *BaseApi) UpdateHost(c *gin.Context) {
|
|||||||
// @Param request body dto.ChangeHostGroup true "request"
|
// @Param request body dto.ChangeHostGroup true "request"
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /hosts/update [post]
|
// @Router /hosts/update/group [post]
|
||||||
// @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]"}
|
// @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) {
|
func (b *BaseApi) UpdateHostGroup(c *gin.Context) {
|
||||||
var req dto.ChangeHostGroup
|
var req dto.ChangeHostGroup
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/shirou/gopsutil/v3/disk"
|
"github.com/shirou/gopsutil/v3/disk"
|
||||||
"github.com/shirou/gopsutil/v3/net"
|
"github.com/shirou/gopsutil/v3/net"
|
||||||
@@ -24,8 +25,9 @@ func (b *BaseApi) LoadMonitor(c *gin.Context) {
|
|||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
req.StartTime = req.StartTime.Add(8 * time.Hour)
|
loc, _ := time.LoadLocation(common.LoadTimeZone())
|
||||||
req.EndTime = req.EndTime.Add(8 * time.Hour)
|
req.StartTime = req.StartTime.In(loc)
|
||||||
|
req.EndTime = req.EndTime.In(loc)
|
||||||
|
|
||||||
var backdatas []dto.MonitorData
|
var backdatas []dto.MonitorData
|
||||||
if req.Param == "all" || req.Param == "cpu" || req.Param == "memory" || req.Param == "load" {
|
if req.Param == "all" || req.Param == "cpu" || req.Param == "memory" || req.Param == "load" {
|
||||||
|
|||||||
@@ -0,0 +1,123 @@
|
|||||||
|
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/app/dto/request"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// @Tags Runtime
|
||||||
|
// @Summary List runtimes
|
||||||
|
// @Description 获取运行环境列表
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.RuntimeSearch true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /runtimes/search [post]
|
||||||
|
func (b *BaseApi) SearchRuntimes(c *gin.Context) {
|
||||||
|
var req request.RuntimeSearch
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
total, items, err := runtimeService.Page(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, dto.PageResult{
|
||||||
|
Total: total,
|
||||||
|
Items: items,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Runtime
|
||||||
|
// @Summary Create runtime
|
||||||
|
// @Description 创建运行环境
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.RuntimeCreate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /runtimes [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建运行环境 [name]","formatEN":"Create runtime [name]"}
|
||||||
|
func (b *BaseApi) CreateRuntime(c *gin.Context) {
|
||||||
|
var req request.RuntimeCreate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := runtimeService.Create(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Website
|
||||||
|
// @Summary Delete runtime
|
||||||
|
// @Description 删除运行环境
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.RuntimeDelete true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /runtimes/del [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"删除网站 [name]","formatEN":"Delete website [name]"}
|
||||||
|
func (b *BaseApi) DeleteRuntime(c *gin.Context) {
|
||||||
|
var req request.RuntimeDelete
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := runtimeService.Delete(req.ID)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Runtime
|
||||||
|
// @Summary Update runtime
|
||||||
|
// @Description 更新运行环境
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.RuntimeUpdate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /runtimes/update [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新运行环境 [name]","formatEN":"Update runtime [name]"}
|
||||||
|
func (b *BaseApi) UpdateRuntime(c *gin.Context) {
|
||||||
|
var req request.RuntimeUpdate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := runtimeService.Update(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Runtime
|
||||||
|
// @Summary Get runtime
|
||||||
|
// @Description 获取运行环境
|
||||||
|
// @Accept json
|
||||||
|
// @Param id path string true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /runtimes/:id [get]
|
||||||
|
func (b *BaseApi) GetRuntime(c *gin.Context) {
|
||||||
|
id, err := helper.GetIntParamByKey(c, "id")
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := runtimeService.Get(id)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, res)
|
||||||
|
}
|
||||||
@@ -92,6 +92,48 @@ func (b *BaseApi) UpdatePassword(c *gin.Context) {
|
|||||||
helper.SuccessWithData(c, nil)
|
helper.SuccessWithData(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Tags System Setting
|
||||||
|
// @Summary Update system ssl
|
||||||
|
// @Description 修改系统 ssl 登录
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.SSLUpdate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /settings/ssl/update [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["ssl"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改系统 ssl => [ssl]","formatEN":"update system ssl => [ssl]"}
|
||||||
|
func (b *BaseApi) UpdateSSL(c *gin.Context) {
|
||||||
|
var req dto.SSLUpdate
|
||||||
|
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 := settingService.UpdateSSL(c, req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags System Setting
|
||||||
|
// @Summary Load system cert info
|
||||||
|
// @Description 获取证书信息
|
||||||
|
// @Success 200 {object} dto.SettingInfo
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /settings/ssl/info [get]
|
||||||
|
func (b *BaseApi) LoadFromCert(c *gin.Context) {
|
||||||
|
info, err := settingService.LoadFromCert()
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, info)
|
||||||
|
}
|
||||||
|
|
||||||
// @Tags System Setting
|
// @Tags System Setting
|
||||||
// @Summary Update system port
|
// @Summary Update system port
|
||||||
// @Description 更新系统端口
|
// @Description 更新系统端口
|
||||||
@@ -154,7 +196,7 @@ func (b *BaseApi) HandlePasswordExpired(c *gin.Context) {
|
|||||||
// @Router /settings/time/sync [post]
|
// @Router /settings/time/sync [post]
|
||||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"系统时间同步","formatEN":"sync system time"}
|
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"系统时间同步","formatEN":"sync system time"}
|
||||||
func (b *BaseApi) SyncTime(c *gin.Context) {
|
func (b *BaseApi) SyncTime(c *gin.Context) {
|
||||||
ntime, err := ntp.Getremotetime()
|
ntime, err := ntp.GetRemoteTime()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.SuccessWithData(c, time.Now().Format("2006-01-02 15:04:05 MST -0700"))
|
helper.SuccessWithData(c, time.Now().Format("2006-01-02 15:04:05 MST -0700"))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os/exec"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -42,6 +45,9 @@ func (b *BaseApi) WsSsh(c *gin.Context) {
|
|||||||
var connInfo ssh.ConnInfo
|
var connInfo ssh.ConnInfo
|
||||||
_ = copier.Copy(&connInfo, &host)
|
_ = copier.Copy(&connInfo, &host)
|
||||||
connInfo.PrivateKey = []byte(host.PrivateKey)
|
connInfo.PrivateKey = []byte(host.PrivateKey)
|
||||||
|
if len(host.PassPhrase) != 0 {
|
||||||
|
connInfo.PassPhrase = []byte(host.PassPhrase)
|
||||||
|
}
|
||||||
|
|
||||||
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -102,14 +108,15 @@ func (b *BaseApi) RedisWsSsh(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer wsConn.Close()
|
defer wsConn.Close()
|
||||||
commands := fmt.Sprintf("docker exec -it %s redis-cli", redisConf.ContainerName)
|
commands := "redis-cli"
|
||||||
if len(redisConf.Requirepass) != 0 {
|
if len(redisConf.Requirepass) != 0 {
|
||||||
commands = fmt.Sprintf("docker exec -it %s redis-cli -a %s --no-auth-warning", redisConf.ContainerName, redisConf.Requirepass)
|
commands = fmt.Sprintf("redis-cli -a %s --no-auth-warning", redisConf.Requirepass)
|
||||||
}
|
}
|
||||||
slave, err := terminal.NewCommand(commands)
|
slave, err := terminal.NewCommand(fmt.Sprintf("docker exec -it %s %s", redisConf.ContainerName, commands))
|
||||||
if wshandleError(wsConn, err) {
|
if wshandleError(wsConn, err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
defer killBash(redisConf.ContainerName, commands)
|
||||||
defer slave.Close()
|
defer slave.Close()
|
||||||
|
|
||||||
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave)
|
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave)
|
||||||
@@ -172,6 +179,7 @@ func (b *BaseApi) ContainerWsSsh(c *gin.Context) {
|
|||||||
if wshandleError(wsConn, err) {
|
if wshandleError(wsConn, err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
defer killBash(containerID, command)
|
||||||
defer slave.Close()
|
defer slave.Close()
|
||||||
|
|
||||||
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave)
|
tty, err := terminal.NewLocalWsSession(cols, rows, wsConn, slave)
|
||||||
@@ -196,13 +204,30 @@ func wshandleError(ws *websocket.Conn, err error) bool {
|
|||||||
global.LOG.Errorf("handler ws faled:, err: %v", err)
|
global.LOG.Errorf("handler ws faled:, err: %v", err)
|
||||||
dt := time.Now().Add(time.Second)
|
dt := time.Now().Add(time.Second)
|
||||||
if ctlerr := ws.WriteControl(websocket.CloseMessage, []byte(err.Error()), dt); ctlerr != nil {
|
if ctlerr := ws.WriteControl(websocket.CloseMessage, []byte(err.Error()), dt); ctlerr != nil {
|
||||||
_ = ws.WriteMessage(websocket.TextMessage, []byte(err.Error()))
|
wsData, err := json.Marshal(terminal.WsMsg{
|
||||||
|
Type: terminal.WsMsgCmd,
|
||||||
|
Data: base64.StdEncoding.EncodeToString([]byte(err.Error())),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
_ = ws.WriteMessage(websocket.TextMessage, []byte("{\"type\":\"cmd\",\"data\":\"failed to encoding to json\"}"))
|
||||||
|
} else {
|
||||||
|
_ = ws.WriteMessage(websocket.TextMessage, wsData)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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{
|
var upGrader = websocket.Upgrader{
|
||||||
ReadBufferSize: 1024,
|
ReadBufferSize: 1024,
|
||||||
WriteBufferSize: 1024 * 1024 * 10,
|
WriteBufferSize: 1024 * 1024 * 10,
|
||||||
|
|||||||
+272
-10
@@ -78,14 +78,12 @@ func (b *BaseApi) CreateWebsite(c *gin.Context) {
|
|||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tx, ctx := helper.GetTxAndContext()
|
|
||||||
err := websiteService.CreateWebsite(ctx, req)
|
err := websiteService.CreateWebsite(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tx.Commit()
|
|
||||||
helper.SuccessWithData(c, nil)
|
helper.SuccessWithData(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,14 +125,12 @@ func (b *BaseApi) DeleteWebsite(c *gin.Context) {
|
|||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tx, ctx := helper.GetTxAndContext()
|
|
||||||
err := websiteService.DeleteWebsite(ctx, req)
|
err := websiteService.DeleteWebsite(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tx.Commit()
|
|
||||||
helper.SuccessWithData(c, nil)
|
helper.SuccessWithData(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,14 +185,16 @@ func (b *BaseApi) GetWebsite(c *gin.Context) {
|
|||||||
// @Param id path integer true "request"
|
// @Param id path integer true "request"
|
||||||
// @Success 200 {object} response.FileInfo
|
// @Success 200 {object} response.FileInfo
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /websites/:id/nginx [get]
|
// @Router /websites/:id/config/:type [get]
|
||||||
func (b *BaseApi) GetWebsiteNginx(c *gin.Context) {
|
func (b *BaseApi) GetWebsiteNginx(c *gin.Context) {
|
||||||
id, err := helper.GetParamID(c)
|
id, err := helper.GetParamID(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fileInfo, err := websiteService.GetWebsiteNginxConfig(id)
|
configType := c.Param("type")
|
||||||
|
|
||||||
|
fileInfo, err := websiteService.GetWebsiteNginxConfig(id, configType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
@@ -496,3 +494,267 @@ func (b *BaseApi) ChangeDefaultServer(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
helper.SuccessWithData(c, nil)
|
helper.SuccessWithData(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Tags Website
|
||||||
|
// @Summary Load websit php conf
|
||||||
|
// @Description 获取网站 php 配置
|
||||||
|
// @Accept json
|
||||||
|
// @Param id path integer true "request"
|
||||||
|
// @Success 200 {object} response.PHPConfig
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/php/config/:id [get]
|
||||||
|
func (b *BaseApi) GetWebsitePHPConfig(c *gin.Context) {
|
||||||
|
id, err := helper.GetParamID(c)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data, err := websiteService.GetPHPConfig(id)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Website PHP
|
||||||
|
// @Summary Update website php conf
|
||||||
|
// @Description 更新 网站 PHP 配置
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.WebsitePHPConfigUpdate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/php/config [post]
|
||||||
|
// @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 {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := websiteService.UpdatePHPConfig(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Website PHP
|
||||||
|
// @Summary Update php conf
|
||||||
|
// @Description 更新 php 配置
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.WebsitePHPFileUpdate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/php/update [post]
|
||||||
|
// @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 {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := websiteService.UpdatePHPConfigFile(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Website
|
||||||
|
// @Summary Get rewrite conf
|
||||||
|
// @Description 获取伪静态配置
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.NginxRewriteReq true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/rewrite [post]
|
||||||
|
func (b *BaseApi) GetRewriteConfig(c *gin.Context) {
|
||||||
|
var req request.NginxRewriteReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := websiteService.GetRewriteConfig(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Website
|
||||||
|
// @Summary Update rewrite conf
|
||||||
|
// @Description 更新伪静态配置
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.NginxRewriteUpdate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/rewrite/update [post]
|
||||||
|
// @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 {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := websiteService.UpdateRewriteConfig(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Website
|
||||||
|
// @Summary Update Site Dir
|
||||||
|
// @Description 更新网站目录
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.WebsiteUpdateDir true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/dir/update [post]
|
||||||
|
// @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 {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := websiteService.UpdateSiteDir(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Website
|
||||||
|
// @Summary Update Site Dir permission
|
||||||
|
// @Description 更新网站目录权限
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.WebsiteUpdateDirPermission true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/dir/permission [post]
|
||||||
|
// @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 {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := websiteService.UpdateSitePermission(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Website
|
||||||
|
// @Summary Get proxy conf
|
||||||
|
// @Description 获取反向代理配置
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.WebsiteProxyReq true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/proxies [post]
|
||||||
|
func (b *BaseApi) GetProxyConfig(c *gin.Context) {
|
||||||
|
var req request.WebsiteProxyReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := websiteService.GetProxies(req.ID)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Website
|
||||||
|
// @Summary Update proxy conf
|
||||||
|
// @Description 修改反向代理配置
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.WebsiteProxyConfig true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/proxies/update [post]
|
||||||
|
// @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 {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := websiteService.OperateProxy(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Website
|
||||||
|
// @Summary Update proxy file
|
||||||
|
// @Description 更新反向代理文件
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.NginxProxyUpdate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/proxy/file [post]
|
||||||
|
// @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 {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := websiteService.UpdateProxyFile(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Website
|
||||||
|
// @Summary Get AuthBasic conf
|
||||||
|
// @Description 获取密码访问配置
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.NginxAuthReq true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/auths [post]
|
||||||
|
func (b *BaseApi) GetAuthConfig(c *gin.Context) {
|
||||||
|
var req request.NginxAuthReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := websiteService.GetAuthBasics(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Website
|
||||||
|
// @Summary Get AuthBasic conf
|
||||||
|
// @Description 更新密码访问配置
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.NginxAuthUpdate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/auths/update [post]
|
||||||
|
func (b *BaseApi) UpdateAuthConfig(c *gin.Context) {
|
||||||
|
var req request.NginxAuthUpdate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := websiteService.UpdateAuthBasic(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ type AppFormFields struct {
|
|||||||
Disabled bool `json:"disabled"`
|
Disabled bool `json:"disabled"`
|
||||||
Edit bool `json:"edit"`
|
Edit bool `json:"edit"`
|
||||||
Rule string `json:"rule"`
|
Rule string `json:"rule"`
|
||||||
|
Multiple bool `json:"multiple"`
|
||||||
Values []AppFormValue `json:"values"`
|
Values []AppFormValue `json:"values"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-10
@@ -17,11 +17,12 @@ type MfaCredential struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Login struct {
|
type Login struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
Captcha string `json:"captcha"`
|
IgnoreCaptcha bool `json:"ignoreCaptcha"`
|
||||||
CaptchaID string `json:"captchaID"`
|
Captcha string `json:"captcha"`
|
||||||
AuthMethod string `json:"authMethod"`
|
CaptchaID string `json:"captchaID"`
|
||||||
|
AuthMethod string `json:"authMethod"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MFALogin struct {
|
type MFALogin struct {
|
||||||
@@ -30,8 +31,3 @@ type MFALogin struct {
|
|||||||
Code string `json:"code"`
|
Code string `json:"code"`
|
||||||
AuthMethod string `json:"authMethod"`
|
AuthMethod string `json:"authMethod"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type InitUser struct {
|
|
||||||
Name string `json:"name" validate:"required"`
|
|
||||||
Password string `json:"password" validate:"required"`
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ type BackupRecords struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DownloadRecord struct {
|
type DownloadRecord struct {
|
||||||
Source string `json:"source" validate:"required,oneof=OSS S3 SFTP MINIO LOCAL"`
|
Source string `json:"source" validate:"required,oneof=OSS S3 SFTP MINIO LOCAL COS KODO"`
|
||||||
FileDir string `json:"fileDir" validate:"required"`
|
FileDir string `json:"fileDir" validate:"required"`
|
||||||
FileName string `json:"fileName" validate:"required"`
|
FileName string `json:"fileName" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ type PageInfo struct {
|
|||||||
|
|
||||||
type UpdateDescription struct {
|
type UpdateDescription struct {
|
||||||
ID uint `json:"id" validate:"required"`
|
ID uint `json:"id" validate:"required"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description" validate:"max=256"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OperationWithName struct {
|
type OperationWithName struct {
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ type ContainerInfo struct {
|
|||||||
State string `json:"state"`
|
State string `json:"state"`
|
||||||
RunTime string `json:"runTime"`
|
RunTime string `json:"runTime"`
|
||||||
|
|
||||||
|
CPUPercent float64 `json:"cpuPercent"`
|
||||||
|
MemoryPercent float64 `json:"memoryPercent"`
|
||||||
|
Ports []string `json:"ports"`
|
||||||
|
|
||||||
IsFromApp bool `json:"isFromApp"`
|
IsFromApp bool `json:"isFromApp"`
|
||||||
IsFromCompose bool `json:"isFromCompose"`
|
IsFromCompose bool `json:"isFromCompose"`
|
||||||
}
|
}
|
||||||
@@ -59,8 +63,10 @@ type VolumeHelper struct {
|
|||||||
Mode string `json:"mode"`
|
Mode string `json:"mode"`
|
||||||
}
|
}
|
||||||
type PortHelper struct {
|
type PortHelper struct {
|
||||||
ContainerPort int `json:"containerPort"`
|
HostIP string `json:"hostIP"`
|
||||||
HostPort int `json:"hostPort"`
|
HostPort string `json:"hostPort"`
|
||||||
|
ContainerPort string `json:"containerPort"`
|
||||||
|
Protocol string `json:"protocol"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContainerLog struct {
|
type ContainerLog struct {
|
||||||
@@ -140,6 +146,7 @@ type ComposeOperation struct {
|
|||||||
Name string `json:"name" validate:"required"`
|
Name string `json:"name" validate:"required"`
|
||||||
Path string `json:"path" validate:"required"`
|
Path string `json:"path" validate:"required"`
|
||||||
Operation string `json:"operation" validate:"required,oneof=start stop down"`
|
Operation string `json:"operation" validate:"required,oneof=start stop down"`
|
||||||
|
WithFile bool `json:"withFile"`
|
||||||
}
|
}
|
||||||
type ComposeUpdate struct {
|
type ComposeUpdate struct {
|
||||||
Name string `json:"name" validate:"required"`
|
Name string `json:"name" validate:"required"`
|
||||||
|
|||||||
@@ -52,6 +52,16 @@ type CronjobDownload struct {
|
|||||||
BackupAccountID uint `json:"backupAccountID" validate:"required"`
|
BackupAccountID uint `json:"backupAccountID" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CronjobClean struct {
|
||||||
|
CleanData bool `json:"cleanData"`
|
||||||
|
CronjobID uint `json:"cronjobID" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CronjobBatchDelete struct {
|
||||||
|
CleanData bool `json:"cleanData"`
|
||||||
|
IDs []uint `json:"ids"`
|
||||||
|
}
|
||||||
|
|
||||||
type CronjobInfo struct {
|
type CronjobInfo struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
|||||||
@@ -5,11 +5,13 @@ type DaemonJsonUpdateByFile struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DaemonJsonConf struct {
|
type DaemonJsonConf struct {
|
||||||
|
IsSwarm bool `json:"isSwarm"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
Mirrors []string `json:"registryMirrors"`
|
Mirrors []string `json:"registryMirrors"`
|
||||||
Registries []string `json:"insecureRegistries"`
|
Registries []string `json:"insecureRegistries"`
|
||||||
LiveRestore bool `json:"liveRestore"`
|
LiveRestore bool `json:"liveRestore"`
|
||||||
|
IPTables bool `json:"iptables"`
|
||||||
CgroupDriver string `json:"cgroupDriver"`
|
CgroupDriver string `json:"cgroupDriver"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
type FirewallBaseInfo struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
PingStatus string `json:"pingStatus"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuleSearch struct {
|
||||||
|
PageInfo
|
||||||
|
Info string `json:"info"`
|
||||||
|
Type string `json:"type" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FirewallOperation struct {
|
||||||
|
Operation string `json:"operation" validate:"required,oneof=start stop disablePing enablePing"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PortRuleOperate struct {
|
||||||
|
Operation string `json:"operation" validate:"required,oneof=add remove"`
|
||||||
|
Address string `json:"address"`
|
||||||
|
Port string `json:"port" validate:"required"`
|
||||||
|
Protocol string `json:"protocol" validate:"required,oneof=tcp udp tcp/udp"`
|
||||||
|
Strategy string `json:"strategy" validate:"required,oneof=accept drop"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AddrRuleOperate struct {
|
||||||
|
Operation string `json:"operation" validate:"required,oneof=add remove"`
|
||||||
|
Address string `json:"address" validate:"required"`
|
||||||
|
Strategy string `json:"strategy" validate:"required,oneof=accept drop"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PortRuleUpdate struct {
|
||||||
|
OldRule PortRuleOperate `json:"oldRule"`
|
||||||
|
NewRule PortRuleOperate `json:"newRule"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AddrRuleUpdate struct {
|
||||||
|
OldRule AddrRuleOperate `json:"oldRule"`
|
||||||
|
NewRule AddrRuleOperate `json:"newRule"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BatchRuleOperate struct {
|
||||||
|
Type string `json:"type" validate:"required"`
|
||||||
|
Rules []PortRuleOperate `json:"rules"`
|
||||||
|
}
|
||||||
+26
-19
@@ -5,15 +5,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type HostOperate struct {
|
type HostOperate struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
GroupID uint `json:"groupID"`
|
GroupID uint `json:"groupID"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Addr string `json:"addr" validate:"required"`
|
Addr string `json:"addr" validate:"required"`
|
||||||
Port uint `json:"port" validate:"required,number,max=65535,min=1"`
|
Port uint `json:"port" validate:"required,number,max=65535,min=1"`
|
||||||
User string `json:"user" validate:"required"`
|
User string `json:"user" validate:"required"`
|
||||||
AuthMode string `json:"authMode" validate:"oneof=password key"`
|
AuthMode string `json:"authMode" validate:"oneof=password key"`
|
||||||
PrivateKey string `json:"privateKey"`
|
Password string `json:"password"`
|
||||||
Password string `json:"password"`
|
PrivateKey string `json:"privateKey"`
|
||||||
|
PassPhrase string `json:"passPhrase"`
|
||||||
|
RememberPassword bool `json:"rememberPassword"`
|
||||||
|
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
}
|
}
|
||||||
@@ -23,8 +25,9 @@ type HostConnTest struct {
|
|||||||
Port uint `json:"port" validate:"required,number,max=65535,min=1"`
|
Port uint `json:"port" validate:"required,number,max=65535,min=1"`
|
||||||
User string `json:"user" validate:"required"`
|
User string `json:"user" validate:"required"`
|
||||||
AuthMode string `json:"authMode" validate:"oneof=password key"`
|
AuthMode string `json:"authMode" validate:"oneof=password key"`
|
||||||
PrivateKey string `json:"privateKey"`
|
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
|
PrivateKey string `json:"privateKey"`
|
||||||
|
PassPhrase string `json:"passPhrase"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SearchHostWithPage struct {
|
type SearchHostWithPage struct {
|
||||||
@@ -43,15 +46,19 @@ type ChangeHostGroup struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HostInfo struct {
|
type HostInfo struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
GroupID uint `json:"groupID"`
|
GroupID uint `json:"groupID"`
|
||||||
GroupBelong string `json:"groupBelong"`
|
GroupBelong string `json:"groupBelong"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Addr string `json:"addr"`
|
Addr string `json:"addr"`
|
||||||
Port uint `json:"port"`
|
Port uint `json:"port"`
|
||||||
User string `json:"user"`
|
User string `json:"user"`
|
||||||
AuthMode string `json:"authMode"`
|
AuthMode string `json:"authMode"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
PrivateKey string `json:"privateKey"`
|
||||||
|
PassPhrase string `json:"passPhrase"`
|
||||||
|
RememberPassword bool `json:"rememberPassword"`
|
||||||
|
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,13 +28,20 @@ type NginxParam struct {
|
|||||||
Params []string
|
Params []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NginxAuth struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
}
|
||||||
|
|
||||||
type NginxKey string
|
type NginxKey string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Index NginxKey = "index"
|
Index NginxKey = "index"
|
||||||
LimitConn NginxKey = "limit-conn"
|
LimitConn NginxKey = "limit-conn"
|
||||||
SSL NginxKey = "ssl"
|
SSL NginxKey = "ssl"
|
||||||
HttpPer NginxKey = "http-per"
|
CACHE NginxKey = "cache"
|
||||||
|
HttpPer NginxKey = "http-per"
|
||||||
|
ProxyCache NginxKey = "proxy-cache"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ScopeKeyMap = map[NginxKey][]string{
|
var ScopeKeyMap = map[NginxKey][]string{
|
||||||
@@ -46,5 +53,7 @@ var ScopeKeyMap = map[NginxKey][]string{
|
|||||||
|
|
||||||
var StaticFileKeyMap = map[NginxKey]struct {
|
var StaticFileKeyMap = map[NginxKey]struct {
|
||||||
}{
|
}{
|
||||||
SSL: {},
|
SSL: {},
|
||||||
|
CACHE: {},
|
||||||
|
ProxyCache: {},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ type FileCreate struct {
|
|||||||
IsLink bool `json:"isLink"`
|
IsLink bool `json:"isLink"`
|
||||||
IsSymlink bool `json:"isSymlink"`
|
IsSymlink bool `json:"isSymlink"`
|
||||||
LinkPath string `json:"linkPath"`
|
LinkPath string `json:"linkPath"`
|
||||||
|
Sub bool `json:"sub"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FileDelete struct {
|
type FileDelete struct {
|
||||||
@@ -88,3 +89,10 @@ type DirSizeReq struct {
|
|||||||
type FileProcessReq struct {
|
type FileProcessReq struct {
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FileRoleUpdate struct {
|
||||||
|
Path string `json:"path" validate:"required"`
|
||||||
|
User string `json:"user" validate:"required"`
|
||||||
|
Group string `json:"group" validate:"required"`
|
||||||
|
Sub bool `json:"sub" validate:"required"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,3 +19,32 @@ type NginxConfigUpdate struct {
|
|||||||
WebsiteID uint `json:"websiteId" validate:"required"`
|
WebsiteID uint `json:"websiteId" validate:"required"`
|
||||||
Params interface{} `json:"params"`
|
Params interface{} `json:"params"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NginxRewriteReq struct {
|
||||||
|
WebsiteID uint `json:"websiteId" validate:"required"`
|
||||||
|
Name string `json:"name" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type NginxRewriteUpdate struct {
|
||||||
|
WebsiteID uint `json:"websiteId" validate:"required"`
|
||||||
|
Name string `json:"name" validate:"required"`
|
||||||
|
Content string `json:"content" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type NginxProxyUpdate struct {
|
||||||
|
WebsiteID uint `json:"websiteID" validate:"required"`
|
||||||
|
Content string `json:"content" validate:"required"`
|
||||||
|
Name string `json:"name" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type NginxAuthUpdate struct {
|
||||||
|
WebsiteID uint `json:"websiteID" validate:"required"`
|
||||||
|
Operate string `json:"operate" validate:"required"`
|
||||||
|
Username string `json:"username" validate:"required"`
|
||||||
|
Password string `json:"password" validate:"required"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type NginxAuthReq struct {
|
||||||
|
WebsiteID uint `json:"websiteID" validate:"required"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import "github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
|
|
||||||
|
type RuntimeSearch struct {
|
||||||
|
dto.PageInfo
|
||||||
|
Type string `json:"type"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuntimeCreate struct {
|
||||||
|
AppDetailID uint `json:"appDetailId"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Params map[string]interface{} `json:"params"`
|
||||||
|
Resource string `json:"resource"`
|
||||||
|
Image string `json:"image"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuntimeDelete struct {
|
||||||
|
ID uint `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuntimeUpdate struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
ID uint `json:"id"`
|
||||||
|
Params map[string]interface{} `json:"params"`
|
||||||
|
Image string `json:"image"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
}
|
||||||
@@ -23,6 +23,14 @@ type WebsiteCreate struct {
|
|||||||
AppInstall NewAppInstall `json:"appInstall"`
|
AppInstall NewAppInstall `json:"appInstall"`
|
||||||
AppID uint `json:"appID"`
|
AppID uint `json:"appID"`
|
||||||
AppInstallID uint `json:"appInstallID"`
|
AppInstallID uint `json:"appInstallID"`
|
||||||
|
|
||||||
|
RuntimeID uint `json:"runtimeID"`
|
||||||
|
RuntimeConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuntimeConfig struct {
|
||||||
|
ProxyType string `json:"proxyType"`
|
||||||
|
Port int `json:"port"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type NewAppInstall struct {
|
type NewAppInstall struct {
|
||||||
@@ -126,3 +134,46 @@ type WebsiteLogReq struct {
|
|||||||
type WebsiteDefaultUpdate struct {
|
type WebsiteDefaultUpdate struct {
|
||||||
ID uint `json:"id" validate:"required"`
|
ID uint `json:"id" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WebsitePHPConfigUpdate struct {
|
||||||
|
ID uint `json:"id" validate:"required"`
|
||||||
|
Params map[string]string `json:"params" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsitePHPFileUpdate struct {
|
||||||
|
ID uint `json:"id" validate:"required"`
|
||||||
|
Type string `json:"type" validate:"required"`
|
||||||
|
Content string `json:"content" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsiteUpdateDir struct {
|
||||||
|
ID uint `json:"id" validate:"required"`
|
||||||
|
SiteDir string `json:"siteDir" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsiteUpdateDirPermission struct {
|
||||||
|
ID uint `json:"id" validate:"required"`
|
||||||
|
User string `json:"user" validate:"required"`
|
||||||
|
Group string `json:"group" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsiteProxyConfig struct {
|
||||||
|
ID uint `json:"id" validate:"required"`
|
||||||
|
Operate string `json:"operate" validate:"required"`
|
||||||
|
Enable bool `json:"enable" validate:"required"`
|
||||||
|
Cache bool `json:"cache" validate:"required"`
|
||||||
|
CacheTime int `json:"cacheTime" validate:"required"`
|
||||||
|
CacheUnit string `json:"cacheUnit" validate:"required"`
|
||||||
|
Name string `json:"name" validate:"required"`
|
||||||
|
Modifier string `json:"modifier" validate:"required"`
|
||||||
|
Match string `json:"match" validate:"required"`
|
||||||
|
ProxyPass string `json:"proxyPass" validate:"required"`
|
||||||
|
ProxyHost string `json:"proxyHost" validate:"required"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
FilePath string `json:"filePath"`
|
||||||
|
Replaces map[string]string `json:"replaces"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsiteProxyReq struct {
|
||||||
|
ID uint `json:"id" validate:"required"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
package response
|
package response
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AppRes struct {
|
type AppRes struct {
|
||||||
@@ -43,6 +44,7 @@ type AppDetailDTO struct {
|
|||||||
model.AppDetail
|
model.AppDetail
|
||||||
Enable bool `json:"enable"`
|
Enable bool `json:"enable"`
|
||||||
Params interface{} `json:"params"`
|
Params interface{} `json:"params"`
|
||||||
|
Image string `json:"image"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppInstalledDTO struct {
|
type AppInstalledDTO struct {
|
||||||
@@ -54,6 +56,12 @@ type AppInstalledDTO struct {
|
|||||||
CanUpdate bool `json:"canUpdate"`
|
CanUpdate bool `json:"canUpdate"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DatabaseConn struct {
|
||||||
|
Password string `json:"password"`
|
||||||
|
ServiceName string `json:"serviceName"`
|
||||||
|
Port int64 `json:"port"`
|
||||||
|
}
|
||||||
|
|
||||||
type AppService struct {
|
type AppService struct {
|
||||||
Label string `json:"label"`
|
Label string `json:"label"`
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
@@ -70,4 +78,6 @@ type AppParam struct {
|
|||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Values interface{} `json:"values"`
|
Values interface{} `json:"values"`
|
||||||
ShowValue string `json:"showValue"`
|
ShowValue string `json:"showValue"`
|
||||||
|
Required bool `json:"required"`
|
||||||
|
Multiple bool `json:"multiple"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package response
|
package response
|
||||||
|
|
||||||
|
import "github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
|
|
||||||
type NginxStatus struct {
|
type NginxStatus struct {
|
||||||
Active string `json:"active"`
|
Active string `json:"active"`
|
||||||
Accepts string `json:"accepts"`
|
Accepts string `json:"accepts"`
|
||||||
@@ -14,3 +16,8 @@ type NginxParam struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Params []string `json:"params"`
|
Params []string `json:"params"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NginxAuthRes struct {
|
||||||
|
Enable bool `json:"enable"`
|
||||||
|
Items []dto.NginxAuth `json:"items"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
import "github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
|
||||||
|
type RuntimeRes struct {
|
||||||
|
model.Runtime
|
||||||
|
AppParams []AppParam `json:"appParams"`
|
||||||
|
AppID uint `json:"appId"`
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ type WebsiteDTO struct {
|
|||||||
AccessLogPath string `json:"accessLogPath"`
|
AccessLogPath string `json:"accessLogPath"`
|
||||||
SitePath string `json:"sitePath"`
|
SitePath string `json:"sitePath"`
|
||||||
AppName string `json:"appName"`
|
AppName string `json:"appName"`
|
||||||
|
RuntimeName string `json:"runtimeName"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebsitePreInstallCheck struct {
|
type WebsitePreInstallCheck struct {
|
||||||
@@ -42,3 +43,11 @@ type WebsiteLog struct {
|
|||||||
Enable bool `json:"enable"`
|
Enable bool `json:"enable"`
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PHPConfig struct {
|
||||||
|
Params map[string]string `json:"params"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type NginxRewriteRes struct {
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ type SettingInfo struct {
|
|||||||
Language string `json:"language"`
|
Language string `json:"language"`
|
||||||
|
|
||||||
ServerPort string `json:"serverPort"`
|
ServerPort string `json:"serverPort"`
|
||||||
|
SSL string `json:"ssl"`
|
||||||
|
SSLType string `json:"sslType"`
|
||||||
SecurityEntrance string `json:"securityEntrance"`
|
SecurityEntrance string `json:"securityEntrance"`
|
||||||
ExpirationDays string `json:"expirationDays"`
|
ExpirationDays string `json:"expirationDays"`
|
||||||
ExpirationTime string `json:"expirationTime"`
|
ExpirationTime string `json:"expirationTime"`
|
||||||
@@ -39,6 +41,23 @@ type SettingUpdate struct {
|
|||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SSLUpdate struct {
|
||||||
|
SSLType string `json:"sslType"`
|
||||||
|
Domain string `json:"domain"`
|
||||||
|
SSL string `json:"ssl" validate:"required,oneof=enable disable"`
|
||||||
|
Cert string `json:"cert"`
|
||||||
|
Key string `json:"key"`
|
||||||
|
SSLID uint `json:"sslID"`
|
||||||
|
}
|
||||||
|
type SSLInfo struct {
|
||||||
|
Domain string `json:"domain"`
|
||||||
|
Timeout string `json:"timeout"`
|
||||||
|
RootPath string `json:"rootPath"`
|
||||||
|
Cert string `json:"cert"`
|
||||||
|
Key string `json:"key"`
|
||||||
|
SSLID uint `json:"sslID"`
|
||||||
|
}
|
||||||
|
|
||||||
type PasswordUpdate struct {
|
type PasswordUpdate struct {
|
||||||
OldPassword string `json:"oldPassword" validate:"required"`
|
OldPassword string `json:"oldPassword" validate:"required"`
|
||||||
NewPassword string `json:"newPassword" validate:"required"`
|
NewPassword string `json:"newPassword" validate:"required"`
|
||||||
@@ -49,8 +68,8 @@ type PortUpdate struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SnapshotCreate struct {
|
type SnapshotCreate struct {
|
||||||
From string `json:"from" validate:"required,oneof=OSS S3 SFTP MINIO"`
|
From string `json:"from" validate:"required,oneof=OSS S3 SFTP MINIO COS KODO"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description" validate:"max=256"`
|
||||||
}
|
}
|
||||||
type SnapshotRecover struct {
|
type SnapshotRecover struct {
|
||||||
IsNew bool `json:"isNew"`
|
IsNew bool `json:"isNew"`
|
||||||
@@ -60,12 +79,12 @@ type SnapshotRecover struct {
|
|||||||
type SnapshotImport struct {
|
type SnapshotImport struct {
|
||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
Names []string `json:"names"`
|
Names []string `json:"names"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description" validate:"max=256"`
|
||||||
}
|
}
|
||||||
type SnapshotInfo struct {
|
type SnapshotInfo struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description" validate:"max=256"`
|
||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ type App struct {
|
|||||||
Github string `json:"github" 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"`
|
Document string `json:"document" gorm:"type:varchar(64);not null"`
|
||||||
Recommend int `json:"recommend" gorm:"type:Integer;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"`
|
Details []AppDetail `json:"-" gorm:"-:migration"`
|
||||||
TagsKey []string `json:"-" gorm:"-"`
|
TagsKey []string `json:"-" gorm:"-"`
|
||||||
AppTags []AppTag `json:"-" gorm:"-:migration"`
|
AppTags []AppTag `json:"-" gorm:"-:migration"`
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package model
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"path"
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
)
|
)
|
||||||
@@ -26,9 +27,21 @@ type AppInstall struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *AppInstall) GetPath() string {
|
func (i *AppInstall) GetPath() string {
|
||||||
return path.Join(constant.AppInstallDir, i.App.Key, i.Name)
|
return path.Join(i.getAppPath(), i.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *AppInstall) GetComposePath() string {
|
func (i *AppInstall) GetComposePath() string {
|
||||||
return path.Join(constant.AppInstallDir, i.App.Key, i.Name, "docker-compose.yml")
|
return path.Join(i.getAppPath(), i.Name, "docker-compose.yml")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *AppInstall) GetEnvPath() string {
|
||||||
|
return path.Join(i.getAppPath(), i.Name, ".env")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *AppInstall) getAppPath() string {
|
||||||
|
if i.App.Resource == constant.AppResourceLocal {
|
||||||
|
return path.Join(constant.LocalAppInstallDir, strings.TrimPrefix(i.App.Key, constant.AppResourceLocal))
|
||||||
|
} else {
|
||||||
|
return path.Join(constant.AppInstallDir, i.App.Key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,17 @@ package model
|
|||||||
|
|
||||||
type Host struct {
|
type Host struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
GroupID uint `gorm:"type:decimal;not null" json:"group_id"`
|
|
||||||
Name string `gorm:"type:varchar(64);not null" json:"name"`
|
GroupID uint `gorm:"type:decimal;not null" json:"group_id"`
|
||||||
Addr string `gorm:"type:varchar(16);not null" json:"addr"`
|
Name string `gorm:"type:varchar(64);not null" json:"name"`
|
||||||
Port int `gorm:"type:decimal;not null" json:"port"`
|
Addr string `gorm:"type:varchar(16);not null" json:"addr"`
|
||||||
User string `gorm:"type:varchar(64);not null" json:"user"`
|
Port int `gorm:"type:decimal;not null" json:"port"`
|
||||||
AuthMode string `gorm:"type:varchar(16);not null" json:"authMode"`
|
User string `gorm:"type:varchar(64);not null" json:"user"`
|
||||||
Password string `gorm:"type:varchar(64)" json:"password"`
|
AuthMode string `gorm:"type:varchar(16);not null" json:"authMode"`
|
||||||
PrivateKey string `gorm:"type:varchar(256)" json:"privateKey"`
|
Password string `gorm:"type:varchar(64)" json:"password"`
|
||||||
|
PrivateKey string `gorm:"type:varchar(256)" json:"privateKey"`
|
||||||
|
PassPhrase string `gorm:"type:varchar(256)" json:"passPhrase"`
|
||||||
|
RememberPassword bool `json:"rememberPassword"`
|
||||||
|
|
||||||
Description string `gorm:"type:varchar(256)" json:"description"`
|
Description string `gorm:"type:varchar(256)" json:"description"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type Runtime struct {
|
||||||
|
BaseModel
|
||||||
|
Name string `gorm:"type:varchar;not null" json:"name"`
|
||||||
|
AppDetailID uint `gorm:"type:integer" json:"appDetailId"`
|
||||||
|
Image string `gorm:"type:varchar" json:"image"`
|
||||||
|
WorkDir string `gorm:"type:varchar" json:"workDir"`
|
||||||
|
DockerCompose string `gorm:"type:varchar" json:"dockerCompose"`
|
||||||
|
Env string `gorm:"type:varchar" json:"env"`
|
||||||
|
Params string `gorm:"type:varchar" json:"params"`
|
||||||
|
Version string `gorm:"type:varchar;not null" json:"version"`
|
||||||
|
Type string `gorm:"type:varchar;not null" json:"type"`
|
||||||
|
Status string `gorm:"type:varchar;not null" json:"status"`
|
||||||
|
Resource string `gorm:"type:varchar;not null" json:"resource"`
|
||||||
|
Message string `gorm:"type:longtext;" json:"message"`
|
||||||
|
}
|
||||||
@@ -4,23 +4,33 @@ import "time"
|
|||||||
|
|
||||||
type Website struct {
|
type Website struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Protocol string `gorm:"type:varchar(64);not null" json:"protocol"`
|
Protocol string `gorm:"type:varchar;not null" json:"protocol"`
|
||||||
PrimaryDomain string `gorm:"type:varchar(128);not null" json:"primaryDomain"`
|
PrimaryDomain string `gorm:"type:varchar;not null" json:"primaryDomain"`
|
||||||
Type string `gorm:"type:varchar(64);not null" json:"type"`
|
Type string `gorm:"type:varchar;not null" json:"type"`
|
||||||
Alias string `gorm:"type:varchar(128);not null" json:"alias"`
|
Alias string `gorm:"type:varchar;not null" json:"alias"`
|
||||||
Remark string `gorm:"type:longtext;" json:"remark"`
|
Remark string `gorm:"type:longtext;" json:"remark"`
|
||||||
Status string `gorm:"type:varchar(64);not null" json:"status"`
|
Status string `gorm:"type:varchar;not null" json:"status"`
|
||||||
HttpConfig string `gorm:"type:varchar(64);not null" json:"httpConfig"`
|
HttpConfig string `gorm:"type:varchar;not null" json:"httpConfig"`
|
||||||
ExpireDate time.Time `json:"expireDate"`
|
ExpireDate time.Time `json:"expireDate"`
|
||||||
AppInstallID uint `gorm:"type:integer" json:"appInstallId"`
|
|
||||||
WebsiteGroupID uint `gorm:"type:integer" json:"webSiteGroupId"`
|
Proxy string `gorm:"type:varchar;" json:"proxy"`
|
||||||
WebsiteSSLID uint `gorm:"type:integer" json:"webSiteSSLId"`
|
ProxyType string `gorm:"type:varchar;" json:"proxyType"`
|
||||||
Proxy string `gorm:"type:varchar(128);not null" json:"proxy"`
|
SiteDir string `gorm:"type:varchar;" json:"siteDir"`
|
||||||
ErrorLog bool `json:"errorLog"`
|
ErrorLog bool `json:"errorLog"`
|
||||||
AccessLog bool `json:"accessLog"`
|
AccessLog bool `json:"accessLog"`
|
||||||
DefaultServer bool `json:"defaultServer"`
|
DefaultServer bool `json:"defaultServer"`
|
||||||
Domains []WebsiteDomain `json:"domains" gorm:"-:migration"`
|
Rewrite string `gorm:"type:varchar" json:"rewrite"`
|
||||||
WebsiteSSL WebsiteSSL `json:"webSiteSSL" gorm:"-:migration"`
|
|
||||||
|
WebsiteGroupID uint `gorm:"type:integer" json:"webSiteGroupId"`
|
||||||
|
WebsiteSSLID uint `gorm:"type:integer" json:"webSiteSSLId"`
|
||||||
|
RuntimeID uint `gorm:"type:integer" json:"runtimeID"`
|
||||||
|
AppInstallID uint `gorm:"type:integer" json:"appInstallId"`
|
||||||
|
|
||||||
|
User string `gorm:"type:varchar;" json:"user"`
|
||||||
|
Group string `gorm:"type:varchar;" json:"group"`
|
||||||
|
|
||||||
|
Domains []WebsiteDomain `json:"domains" gorm:"-:migration"`
|
||||||
|
WebsiteSSL WebsiteSSL `json:"webSiteSSL" gorm:"-:migration"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w Website) TableName() string {
|
func (w Website) TableName() string {
|
||||||
|
|||||||
+26
-1
@@ -11,6 +11,25 @@ import (
|
|||||||
type AppRepo struct {
|
type AppRepo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IAppRepo interface {
|
||||||
|
WithKey(key string) DBOption
|
||||||
|
WithType(typeStr string) DBOption
|
||||||
|
OrderByRecommend() DBOption
|
||||||
|
GetRecommend() DBOption
|
||||||
|
WithResource(resource string) DBOption
|
||||||
|
Page(page, size int, opts ...DBOption) (int64, []model.App, error)
|
||||||
|
GetFirst(opts ...DBOption) (model.App, error)
|
||||||
|
GetBy(opts ...DBOption) ([]model.App, error)
|
||||||
|
BatchCreate(ctx context.Context, apps []model.App) error
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIAppRepo() IAppRepo {
|
||||||
|
return &AppRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppRepo) WithKey(key string) DBOption {
|
func (a AppRepo) WithKey(key string) DBOption {
|
||||||
return func(db *gorm.DB) *gorm.DB {
|
return func(db *gorm.DB) *gorm.DB {
|
||||||
return db.Where("key = ?", key)
|
return db.Where("key = ?", key)
|
||||||
@@ -35,12 +54,18 @@ func (a AppRepo) GetRecommend() DBOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a AppRepo) WithResource(resource string) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("resource = ?", resource)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppRepo) Page(page, size int, opts ...DBOption) (int64, []model.App, error) {
|
func (a AppRepo) Page(page, size int, opts ...DBOption) (int64, []model.App, error) {
|
||||||
var apps []model.App
|
var apps []model.App
|
||||||
db := getDb(opts...).Model(&model.App{})
|
db := getDb(opts...).Model(&model.App{})
|
||||||
count := int64(0)
|
count := int64(0)
|
||||||
db = db.Count(&count)
|
db = db.Count(&count)
|
||||||
err := db.Limit(size).Offset(size * (page - 1)).Preload("AppTags").Find(&apps).Error
|
err := db.Debug().Limit(size).Offset(size * (page - 1)).Preload("AppTags").Find(&apps).Error
|
||||||
return count, apps, err
|
return count, apps, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,21 @@ import (
|
|||||||
type AppDetailRepo struct {
|
type AppDetailRepo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IAppDetailRepo interface {
|
||||||
|
WithVersion(version string) DBOption
|
||||||
|
WithAppId(id uint) DBOption
|
||||||
|
GetFirst(opts ...DBOption) (model.AppDetail, error)
|
||||||
|
Update(ctx context.Context, detail model.AppDetail) error
|
||||||
|
BatchCreate(ctx context.Context, details []model.AppDetail) error
|
||||||
|
DeleteByAppIds(ctx context.Context, appIds []uint) error
|
||||||
|
GetBy(opts ...DBOption) ([]model.AppDetail, error)
|
||||||
|
BatchUpdateBy(maps map[string]interface{}, opts ...DBOption) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIAppDetailRepo() IAppDetailRepo {
|
||||||
|
return &AppDetailRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppDetailRepo) WithVersion(version string) DBOption {
|
func (a AppDetailRepo) WithVersion(version string) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
return g.Where("version = ?", version)
|
return g.Where("version = ?", version)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package repo
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
@@ -11,6 +12,31 @@ import (
|
|||||||
|
|
||||||
type AppInstallRepo struct{}
|
type AppInstallRepo struct{}
|
||||||
|
|
||||||
|
type IAppInstallRepo interface {
|
||||||
|
WithDetailIdsIn(detailIds []uint) DBOption
|
||||||
|
WithDetailIdNotIn(detailIds []uint) DBOption
|
||||||
|
WithAppId(appId uint) DBOption
|
||||||
|
WithAppIdsIn(appIds []uint) DBOption
|
||||||
|
WithStatus(status string) DBOption
|
||||||
|
WithServiceName(serviceName string) DBOption
|
||||||
|
WithPort(port int) DBOption
|
||||||
|
WithIdNotInWebsite() DBOption
|
||||||
|
ListBy(opts ...DBOption) ([]model.AppInstall, error)
|
||||||
|
GetFirst(opts ...DBOption) (model.AppInstall, error)
|
||||||
|
Create(ctx context.Context, install *model.AppInstall) error
|
||||||
|
Save(ctx context.Context, install *model.AppInstall) error
|
||||||
|
DeleteBy(opts ...DBOption) error
|
||||||
|
Delete(ctx context.Context, install model.AppInstall) error
|
||||||
|
Page(page, size int, opts ...DBOption) (int64, []model.AppInstall, error)
|
||||||
|
BatchUpdateBy(maps map[string]interface{}, opts ...DBOption) error
|
||||||
|
LoadBaseInfo(key string, name string) (*RootInfo, error)
|
||||||
|
GetFirstByCtx(ctx context.Context, opts ...DBOption) (model.AppInstall, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIAppInstallRepo() IAppInstallRepo {
|
||||||
|
return &AppInstallRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
func (a *AppInstallRepo) WithDetailIdsIn(detailIds []uint) DBOption {
|
func (a *AppInstallRepo) WithDetailIdsIn(detailIds []uint) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
return g.Where("app_detail_id in (?)", detailIds)
|
return g.Where("app_detail_id in (?)", detailIds)
|
||||||
@@ -73,13 +99,20 @@ func (a *AppInstallRepo) GetFirst(opts ...DBOption) (model.AppInstall, error) {
|
|||||||
return install, err
|
return install, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AppInstallRepo) Create(ctx context.Context, install *model.AppInstall) error {
|
func (a *AppInstallRepo) GetFirstByCtx(ctx context.Context, opts ...DBOption) (model.AppInstall, error) {
|
||||||
db := getTx(ctx).Model(&model.AppInstall{})
|
var install model.AppInstall
|
||||||
return db.Create(&install).Error
|
db := getTx(ctx, opts...).Model(&model.AppInstall{})
|
||||||
|
err := db.Preload("App").First(&install).Error
|
||||||
|
return install, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AppInstallRepo) Save(install *model.AppInstall) error {
|
func (a *AppInstallRepo) Create(ctx context.Context, install *model.AppInstall) error {
|
||||||
return getDb().Save(&install).Error
|
db := getTx(ctx).Model(&model.AppInstall{})
|
||||||
|
return db.Omit(clause.Associations).Create(&install).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AppInstallRepo) Save(ctx context.Context, install *model.AppInstall) error {
|
||||||
|
return getTx(ctx).Omit(clause.Associations).Save(&install).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AppInstallRepo) DeleteBy(opts ...DBOption) error {
|
func (a *AppInstallRepo) DeleteBy(opts ...DBOption) error {
|
||||||
@@ -112,9 +145,11 @@ type RootInfo struct {
|
|||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Port int64 `json:"port"`
|
Port int64 `json:"port"`
|
||||||
|
HttpsPort int64 `json:"httpsPort"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
UserPassword string `json:"userPassword"`
|
UserPassword string `json:"userPassword"`
|
||||||
ContainerName string `json:"containerName"`
|
ContainerName string `json:"containerName"`
|
||||||
|
ServiceName string `json:"serviceName"`
|
||||||
Param string `json:"param"`
|
Param string `json:"param"`
|
||||||
Env string `json:"env"`
|
Env string `json:"env"`
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
@@ -152,7 +187,9 @@ func (a *AppInstallRepo) LoadBaseInfo(key string, name string) (*RootInfo, error
|
|||||||
info.UserPassword = userPassword
|
info.UserPassword = userPassword
|
||||||
}
|
}
|
||||||
info.Port = int64(appInstall.HttpPort)
|
info.Port = int64(appInstall.HttpPort)
|
||||||
|
info.HttpsPort = int64(appInstall.HttpsPort)
|
||||||
info.ID = appInstall.ID
|
info.ID = appInstall.ID
|
||||||
|
info.ServiceName = appInstall.ServiceName
|
||||||
info.ContainerName = appInstall.ContainerName
|
info.ContainerName = appInstall.ContainerName
|
||||||
info.Name = appInstall.Name
|
info.Name = appInstall.Name
|
||||||
info.Env = appInstall.Env
|
info.Env = appInstall.Env
|
||||||
|
|||||||
@@ -11,6 +11,20 @@ import (
|
|||||||
type AppInstallResourceRpo struct {
|
type AppInstallResourceRpo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IAppInstallResourceRpo interface {
|
||||||
|
WithAppInstallId(appInstallId uint) DBOption
|
||||||
|
WithLinkId(linkId uint) DBOption
|
||||||
|
WithResourceId(resourceId uint) DBOption
|
||||||
|
GetBy(opts ...DBOption) ([]model.AppInstallResource, error)
|
||||||
|
GetFirst(opts ...DBOption) (model.AppInstallResource, error)
|
||||||
|
Create(ctx context.Context, resource *model.AppInstallResource) error
|
||||||
|
DeleteBy(ctx context.Context, opts ...DBOption) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIAppInstallResourceRpo() IAppInstallResourceRpo {
|
||||||
|
return &AppInstallResourceRpo{}
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppInstallResourceRpo) WithAppInstallId(appInstallId uint) DBOption {
|
func (a AppInstallResourceRpo) WithAppInstallId(appInstallId uint) DBOption {
|
||||||
return func(db *gorm.DB) *gorm.DB {
|
return func(db *gorm.DB) *gorm.DB {
|
||||||
return db.Where("app_install_id = ?", appInstallId)
|
return db.Where("app_install_id = ?", appInstallId)
|
||||||
|
|||||||
@@ -8,6 +8,18 @@ import (
|
|||||||
type AppTagRepo struct {
|
type AppTagRepo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IAppTagRepo interface {
|
||||||
|
BatchCreate(ctx context.Context, tags []*model.AppTag) error
|
||||||
|
DeleteByAppIds(ctx context.Context, appIds []uint) error
|
||||||
|
DeleteAll(ctx context.Context) error
|
||||||
|
GetByAppId(appId uint) ([]model.AppTag, error)
|
||||||
|
GetByTagIds(tagIds []uint) ([]model.AppTag, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIAppTagRepo() IAppTagRepo {
|
||||||
|
return &AppTagRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppTagRepo) BatchCreate(ctx context.Context, tags []*model.AppTag) error {
|
func (a AppTagRepo) BatchCreate(ctx context.Context, tags []*model.AppTag) error {
|
||||||
return getTx(ctx).Create(&tags).Error
|
return getTx(ctx).Create(&tags).Error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ type IBackupRepo interface {
|
|||||||
Delete(opts ...DBOption) error
|
Delete(opts ...DBOption) error
|
||||||
DeleteRecord(ctx context.Context, opts ...DBOption) error
|
DeleteRecord(ctx context.Context, opts ...DBOption) error
|
||||||
WithByDetailName(detailName string) DBOption
|
WithByDetailName(detailName string) DBOption
|
||||||
|
WithByFileName(fileName string) DBOption
|
||||||
|
WithByType(backupType string) DBOption
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIBackupRepo() IBackupRepo {
|
func NewIBackupRepo() IBackupRepo {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type ICommandRepo interface {
|
|||||||
Create(command *model.Command) error
|
Create(command *model.Command) error
|
||||||
Update(id uint, vars map[string]interface{}) error
|
Update(id uint, vars map[string]interface{}) error
|
||||||
Delete(opts ...DBOption) error
|
Delete(opts ...DBOption) error
|
||||||
|
Get(opts ...DBOption) (model.Command, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewICommandRepo() ICommandRepo {
|
func NewICommandRepo() ICommandRepo {
|
||||||
|
|||||||
@@ -21,10 +21,15 @@ type ICommonRepo interface {
|
|||||||
WithIdsIn(ids []uint) DBOption
|
WithIdsIn(ids []uint) DBOption
|
||||||
WithByDate(startTime, endTime time.Time) DBOption
|
WithByDate(startTime, endTime time.Time) DBOption
|
||||||
WithByStartDate(startTime time.Time) DBOption
|
WithByStartDate(startTime time.Time) DBOption
|
||||||
|
WithByStatus(status string) DBOption
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommonRepo struct{}
|
type CommonRepo struct{}
|
||||||
|
|
||||||
|
func NewCommonRepo() ICommonRepo {
|
||||||
|
return &CommonRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *CommonRepo) WithByID(id uint) DBOption {
|
func (c *CommonRepo) WithByID(id uint) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
return g.Where("id = ?", id)
|
return g.Where("id = ?", id)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ type IComposeTemplateRepo interface {
|
|||||||
|
|
||||||
CreateRecord(compose *model.Compose) error
|
CreateRecord(compose *model.Compose) error
|
||||||
DeleteRecord(opts ...DBOption) error
|
DeleteRecord(opts ...DBOption) error
|
||||||
|
ListRecord() ([]model.Compose, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIComposeTemplateRepo() IComposeTemplateRepo {
|
func NewIComposeTemplateRepo() IComposeTemplateRepo {
|
||||||
|
|||||||
@@ -20,12 +20,15 @@ type ICronjobRepo interface {
|
|||||||
Page(limit, offset int, opts ...DBOption) (int64, []model.Cronjob, error)
|
Page(limit, offset int, opts ...DBOption) (int64, []model.Cronjob, error)
|
||||||
Create(cronjob *model.Cronjob) error
|
Create(cronjob *model.Cronjob) error
|
||||||
WithByJobID(id int) DBOption
|
WithByJobID(id int) DBOption
|
||||||
|
WithByBackupID(id uint) DBOption
|
||||||
|
WithByRecordDropID(id int) DBOption
|
||||||
Save(id uint, cronjob model.Cronjob) error
|
Save(id uint, cronjob model.Cronjob) error
|
||||||
Update(id uint, vars map[string]interface{}) error
|
Update(id uint, vars map[string]interface{}) error
|
||||||
Delete(opts ...DBOption) error
|
Delete(opts ...DBOption) error
|
||||||
DeleteRecord(opts ...DBOption) error
|
DeleteRecord(opts ...DBOption) error
|
||||||
StartRecords(cronjobID uint, fromLocal bool, targetPath string) model.JobRecords
|
StartRecords(cronjobID uint, fromLocal bool, targetPath string) model.JobRecords
|
||||||
EndRecords(record model.JobRecords, status, message, records string)
|
EndRecords(record model.JobRecords, status, message, records string)
|
||||||
|
PageRecords(page, size int, opts ...DBOption) (int64, []model.JobRecords, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewICronjobRepo() ICronjobRepo {
|
func NewICronjobRepo() ICronjobRepo {
|
||||||
@@ -112,6 +115,18 @@ func (c *CronjobRepo) WithByJobID(id int) DBOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *CronjobRepo) WithByBackupID(id uint) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("target_dir_id = ?", id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CronjobRepo) WithByRecordDropID(id int) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("id < ?", id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (u *CronjobRepo) StartRecords(cronjobID uint, fromLocal bool, targetPath string) model.JobRecords {
|
func (u *CronjobRepo) StartRecords(cronjobID uint, fromLocal bool, targetPath string) model.JobRecords {
|
||||||
var record model.JobRecords
|
var record model.JobRecords
|
||||||
record.StartTime = time.Now()
|
record.StartTime = time.Now()
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
package repo
|
|
||||||
|
|
||||||
type RepoGroup struct {
|
|
||||||
CommonRepo
|
|
||||||
AppRepo
|
|
||||||
AppTagRepo
|
|
||||||
TagRepo
|
|
||||||
AppDetailRepo
|
|
||||||
AppInstallRepo
|
|
||||||
AppInstallResourceRpo
|
|
||||||
ImageRepoRepo
|
|
||||||
ComposeTemplateRepo
|
|
||||||
MysqlRepo
|
|
||||||
CronjobRepo
|
|
||||||
HostRepo
|
|
||||||
CommandRepo
|
|
||||||
GroupRepo
|
|
||||||
SettingRepo
|
|
||||||
BackupRepo
|
|
||||||
WebsiteRepo
|
|
||||||
WebsiteDomainRepo
|
|
||||||
WebsiteDnsAccountRepo
|
|
||||||
WebsiteSSLRepo
|
|
||||||
WebsiteAcmeAccountRepo
|
|
||||||
LogRepo
|
|
||||||
SnapshotRepo
|
|
||||||
}
|
|
||||||
|
|
||||||
var RepoGroupApp = new(RepoGroup)
|
|
||||||
+11
-11
@@ -25,7 +25,7 @@ func NewIHostRepo() IHostRepo {
|
|||||||
return &HostRepo{}
|
return &HostRepo{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *HostRepo) Get(opts ...DBOption) (model.Host, error) {
|
func (h *HostRepo) Get(opts ...DBOption) (model.Host, error) {
|
||||||
var host model.Host
|
var host model.Host
|
||||||
db := global.DB
|
db := global.DB
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
@@ -35,7 +35,7 @@ func (u *HostRepo) Get(opts ...DBOption) (model.Host, error) {
|
|||||||
return host, err
|
return host, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *HostRepo) GetList(opts ...DBOption) ([]model.Host, error) {
|
func (h *HostRepo) GetList(opts ...DBOption) ([]model.Host, error) {
|
||||||
var hosts []model.Host
|
var hosts []model.Host
|
||||||
db := global.DB.Model(&model.Host{})
|
db := global.DB.Model(&model.Host{})
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
@@ -45,7 +45,7 @@ func (u *HostRepo) GetList(opts ...DBOption) ([]model.Host, error) {
|
|||||||
return hosts, err
|
return hosts, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *HostRepo) Page(page, size int, opts ...DBOption) (int64, []model.Host, error) {
|
func (h *HostRepo) Page(page, size int, opts ...DBOption) (int64, []model.Host, error) {
|
||||||
var users []model.Host
|
var users []model.Host
|
||||||
db := global.DB.Model(&model.Host{})
|
db := global.DB.Model(&model.Host{})
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
@@ -57,7 +57,7 @@ func (u *HostRepo) Page(page, size int, opts ...DBOption) (int64, []model.Host,
|
|||||||
return count, users, err
|
return count, users, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *HostRepo) WithByInfo(info string) DBOption {
|
func (h *HostRepo) WithByInfo(info string) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
if len(info) == 0 {
|
if len(info) == 0 {
|
||||||
return g
|
return g
|
||||||
@@ -67,22 +67,22 @@ func (c *HostRepo) WithByInfo(info string) DBOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *HostRepo) WithByPort(port uint) DBOption {
|
func (h *HostRepo) WithByPort(port uint) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
return g.Where("port = ?", port)
|
return g.Where("port = ?", port)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (u *HostRepo) WithByUser(user string) DBOption {
|
func (h *HostRepo) WithByUser(user string) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
return g.Where("user = ?", user)
|
return g.Where("user = ?", user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (u *HostRepo) WithByAddr(addr string) DBOption {
|
func (h *HostRepo) WithByAddr(addr string) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
return g.Where("addr = ?", addr)
|
return g.Where("addr = ?", addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (u *HostRepo) WithByGroup(group string) DBOption {
|
func (h *HostRepo) WithByGroup(group string) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
if len(group) == 0 {
|
if len(group) == 0 {
|
||||||
return g
|
return g
|
||||||
@@ -91,15 +91,15 @@ func (u *HostRepo) WithByGroup(group string) DBOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *HostRepo) Create(host *model.Host) error {
|
func (h *HostRepo) Create(host *model.Host) error {
|
||||||
return global.DB.Create(host).Error
|
return global.DB.Create(host).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *HostRepo) Update(id uint, vars map[string]interface{}) error {
|
func (h *HostRepo) Update(id uint, vars map[string]interface{}) error {
|
||||||
return global.DB.Model(&model.Host{}).Where("id = ?", id).Updates(vars).Error
|
return global.DB.Model(&model.Host{}).Where("id = ?", id).Updates(vars).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *HostRepo) Delete(opts ...DBOption) error {
|
func (h *HostRepo) Delete(opts ...DBOption) error {
|
||||||
db := global.DB
|
db := global.DB
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
db = opt(db)
|
db = opt(db)
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RuntimeRepo struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type IRuntimeRepo interface {
|
||||||
|
WithName(name string) DBOption
|
||||||
|
WithImage(image string) DBOption
|
||||||
|
WithNotId(id uint) DBOption
|
||||||
|
WithStatus(status string) DBOption
|
||||||
|
Page(page, size int, opts ...DBOption) (int64, []model.Runtime, error)
|
||||||
|
Create(ctx context.Context, runtime *model.Runtime) error
|
||||||
|
Save(runtime *model.Runtime) error
|
||||||
|
DeleteBy(opts ...DBOption) error
|
||||||
|
GetFirst(opts ...DBOption) (*model.Runtime, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIRunTimeRepo() IRuntimeRepo {
|
||||||
|
return &RuntimeRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeRepo) WithName(name string) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("name = ?", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeRepo) WithStatus(status string) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("status = ?", status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeRepo) WithImage(image string) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("image = ?", image)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeRepo) WithNotId(id uint) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("id != ?", id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeRepo) Page(page, size int, opts ...DBOption) (int64, []model.Runtime, error) {
|
||||||
|
var runtimes []model.Runtime
|
||||||
|
db := getDb(opts...).Model(&model.Runtime{})
|
||||||
|
count := int64(0)
|
||||||
|
db = db.Count(&count)
|
||||||
|
err := db.Limit(size).Offset(size * (page - 1)).Find(&runtimes).Error
|
||||||
|
return count, runtimes, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeRepo) Create(ctx context.Context, runtime *model.Runtime) error {
|
||||||
|
db := getTx(ctx).Model(&model.Runtime{})
|
||||||
|
return db.Create(&runtime).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeRepo) Save(runtime *model.Runtime) error {
|
||||||
|
return getDb().Save(&runtime).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeRepo) DeleteBy(opts ...DBOption) error {
|
||||||
|
return getDb(opts...).Delete(&model.Runtime{}).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeRepo) GetFirst(opts ...DBOption) (*model.Runtime, error) {
|
||||||
|
var runtime model.Runtime
|
||||||
|
if err := getDb(opts...).First(&runtime).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &runtime, nil
|
||||||
|
}
|
||||||
@@ -8,6 +8,19 @@ import (
|
|||||||
type TagRepo struct {
|
type TagRepo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ITagRepo interface {
|
||||||
|
BatchCreate(ctx context.Context, tags []*model.Tag) error
|
||||||
|
DeleteAll(ctx context.Context) error
|
||||||
|
All() ([]model.Tag, error)
|
||||||
|
GetByIds(ids []uint) ([]model.Tag, error)
|
||||||
|
GetByKeys(keys []string) ([]model.Tag, error)
|
||||||
|
GetByAppId(appId uint) ([]model.Tag, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewITagRepo() ITagRepo {
|
||||||
|
return &TagRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
func (t TagRepo) BatchCreate(ctx context.Context, tags []*model.Tag) error {
|
func (t TagRepo) BatchCreate(ctx context.Context, tags []*model.Tag) error {
|
||||||
return getTx(ctx).Create(&tags).Error
|
return getTx(ctx).Create(&tags).Error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ type IWebsiteRepo interface {
|
|||||||
WithGroupID(groupId uint) DBOption
|
WithGroupID(groupId uint) DBOption
|
||||||
WithDefaultServer() DBOption
|
WithDefaultServer() DBOption
|
||||||
WithDomainLike(domain string) DBOption
|
WithDomainLike(domain string) DBOption
|
||||||
|
WithRuntimeID(runtimeID uint) DBOption
|
||||||
Page(page, size int, opts ...DBOption) (int64, []model.Website, error)
|
Page(page, size int, opts ...DBOption) (int64, []model.Website, error)
|
||||||
List(opts ...DBOption) ([]model.Website, error)
|
List(opts ...DBOption) ([]model.Website, error)
|
||||||
GetFirst(opts ...DBOption) (model.Website, error)
|
GetFirst(opts ...DBOption) (model.Website, error)
|
||||||
@@ -40,6 +41,12 @@ func (w *WebsiteRepo) WithAppInstallId(appInstallId uint) DBOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *WebsiteRepo) WithRuntimeID(runtimeID uint) DBOption {
|
||||||
|
return func(db *gorm.DB) *gorm.DB {
|
||||||
|
return db.Where("runtime_id = ?", runtimeID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (w *WebsiteRepo) WithDomain(domain string) DBOption {
|
func (w *WebsiteRepo) WithDomain(domain string) DBOption {
|
||||||
return func(db *gorm.DB) *gorm.DB {
|
return func(db *gorm.DB) *gorm.DB {
|
||||||
return db.Where("primary_domain = ?", domain)
|
return db.Where("primary_domain = ?", domain)
|
||||||
|
|||||||
@@ -7,6 +7,19 @@ import (
|
|||||||
type WebsiteDnsAccountRepo struct {
|
type WebsiteDnsAccountRepo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IWebsiteDnsAccountRepo interface {
|
||||||
|
Page(page, size int, opts ...DBOption) (int64, []model.WebsiteDnsAccount, error)
|
||||||
|
GetFirst(opts ...DBOption) (*model.WebsiteDnsAccount, error)
|
||||||
|
List(opts ...DBOption) ([]model.WebsiteDnsAccount, error)
|
||||||
|
Create(account model.WebsiteDnsAccount) error
|
||||||
|
Save(account model.WebsiteDnsAccount) error
|
||||||
|
DeleteBy(opts ...DBOption) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIWebsiteDnsAccountRepo() IWebsiteDnsAccountRepo {
|
||||||
|
return &WebsiteDnsAccountRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
func (w WebsiteDnsAccountRepo) Page(page, size int, opts ...DBOption) (int64, []model.WebsiteDnsAccount, error) {
|
func (w WebsiteDnsAccountRepo) Page(page, size int, opts ...DBOption) (int64, []model.WebsiteDnsAccount, error) {
|
||||||
var accounts []model.WebsiteDnsAccount
|
var accounts []model.WebsiteDnsAccount
|
||||||
db := getDb(opts...).Model(&model.WebsiteDnsAccount{})
|
db := getDb(opts...).Model(&model.WebsiteDnsAccount{})
|
||||||
|
|||||||
@@ -10,6 +10,23 @@ import (
|
|||||||
type WebsiteDomainRepo struct {
|
type WebsiteDomainRepo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IWebsiteDomainRepo interface {
|
||||||
|
WithWebsiteId(websiteId uint) DBOption
|
||||||
|
WithPort(port int) DBOption
|
||||||
|
WithDomain(domain string) DBOption
|
||||||
|
Page(page, size int, opts ...DBOption) (int64, []model.WebsiteDomain, error)
|
||||||
|
GetFirst(opts ...DBOption) (model.WebsiteDomain, error)
|
||||||
|
GetBy(opts ...DBOption) ([]model.WebsiteDomain, error)
|
||||||
|
BatchCreate(ctx context.Context, domains []model.WebsiteDomain) error
|
||||||
|
Create(ctx context.Context, app *model.WebsiteDomain) error
|
||||||
|
Save(ctx context.Context, app *model.WebsiteDomain) error
|
||||||
|
DeleteBy(ctx context.Context, opts ...DBOption) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIWebsiteDomainRepo() IWebsiteDomainRepo {
|
||||||
|
return &WebsiteDomainRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
func (w WebsiteDomainRepo) WithWebsiteId(websiteId uint) DBOption {
|
func (w WebsiteDomainRepo) WithWebsiteId(websiteId uint) DBOption {
|
||||||
return func(db *gorm.DB) *gorm.DB {
|
return func(db *gorm.DB) *gorm.DB {
|
||||||
return db.Where("website_id = ?", websiteId)
|
return db.Where("website_id = ?", websiteId)
|
||||||
|
|||||||
+289
-60
@@ -5,14 +5,15 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
"io"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"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"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
"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/dto/response"
|
||||||
@@ -32,10 +33,12 @@ type IAppService interface {
|
|||||||
PageApp(req request.AppSearch) (interface{}, error)
|
PageApp(req request.AppSearch) (interface{}, error)
|
||||||
GetAppTags() ([]response.TagDTO, error)
|
GetAppTags() ([]response.TagDTO, error)
|
||||||
GetApp(key string) (*response.AppDTO, error)
|
GetApp(key string) (*response.AppDTO, error)
|
||||||
GetAppDetail(appId uint, version string) (response.AppDetailDTO, error)
|
GetAppDetail(appId uint, version, appType string) (response.AppDetailDTO, error)
|
||||||
Install(ctx context.Context, req request.AppInstallCreate) (*model.AppInstall, error)
|
Install(ctx context.Context, req request.AppInstallCreate) (*model.AppInstall, error)
|
||||||
SyncAppList() error
|
SyncAppListFromRemote() error
|
||||||
GetAppUpdate() (*response.AppUpdateRes, error)
|
GetAppUpdate() (*response.AppUpdateRes, error)
|
||||||
|
GetAppDetailByID(id uint) (*response.AppDetailDTO, error)
|
||||||
|
SyncAppListFromLocal()
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIAppService() IAppService {
|
func NewIAppService() IAppService {
|
||||||
@@ -138,7 +141,7 @@ func (a AppService) GetApp(key string) (*response.AppDTO, error) {
|
|||||||
return &appDTO, nil
|
return &appDTO, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AppService) GetAppDetail(appId uint, version string) (response.AppDetailDTO, error) {
|
func (a AppService) GetAppDetail(appId uint, version, appType string) (response.AppDetailDTO, error) {
|
||||||
var (
|
var (
|
||||||
appDetailDTO response.AppDetailDTO
|
appDetailDTO response.AppDetailDTO
|
||||||
opts []repo.DBOption
|
opts []repo.DBOption
|
||||||
@@ -148,14 +151,55 @@ func (a AppService) GetAppDetail(appId uint, version string) (response.AppDetail
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return appDetailDTO, err
|
return appDetailDTO, err
|
||||||
}
|
}
|
||||||
paramMap := make(map[string]interface{})
|
|
||||||
if err := json.Unmarshal([]byte(detail.Params), ¶mMap); err != nil {
|
|
||||||
return appDetailDTO, err
|
|
||||||
}
|
|
||||||
appDetailDTO.AppDetail = detail
|
appDetailDTO.AppDetail = detail
|
||||||
appDetailDTO.Params = paramMap
|
|
||||||
appDetailDTO.Enable = true
|
appDetailDTO.Enable = true
|
||||||
|
|
||||||
|
if appType == "runtime" {
|
||||||
|
app, err := appRepo.GetFirst(commonRepo.WithByID(appId))
|
||||||
|
if err != nil {
|
||||||
|
return appDetailDTO, err
|
||||||
|
}
|
||||||
|
fileOp := files.NewFileOp()
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
param, err := fileOp.GetContent(paramsPath)
|
||||||
|
if err != nil {
|
||||||
|
return appDetailDTO, err
|
||||||
|
}
|
||||||
|
paramMap := make(map[string]interface{})
|
||||||
|
if err := json.Unmarshal(param, ¶mMap); err != nil {
|
||||||
|
return appDetailDTO, err
|
||||||
|
}
|
||||||
|
appDetailDTO.Params = paramMap
|
||||||
|
composePath := path.Join(buildPath, "docker-compose.yml")
|
||||||
|
if !fileOp.Stat(composePath) {
|
||||||
|
return appDetailDTO, buserr.New(constant.ErrFileNotExist)
|
||||||
|
}
|
||||||
|
compose, err := fileOp.GetContent(composePath)
|
||||||
|
if err != nil {
|
||||||
|
return appDetailDTO, err
|
||||||
|
}
|
||||||
|
composeMap := make(map[string]interface{})
|
||||||
|
if err := yaml.Unmarshal(compose, &composeMap); err != nil {
|
||||||
|
return appDetailDTO, err
|
||||||
|
}
|
||||||
|
if service, ok := composeMap["services"]; ok {
|
||||||
|
servicesMap := service.(map[string]interface{})
|
||||||
|
for k := range servicesMap {
|
||||||
|
appDetailDTO.Image = k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
paramMap := make(map[string]interface{})
|
||||||
|
if err := json.Unmarshal([]byte(detail.Params), ¶mMap); err != nil {
|
||||||
|
return appDetailDTO, err
|
||||||
|
}
|
||||||
|
appDetailDTO.Params = paramMap
|
||||||
|
}
|
||||||
|
|
||||||
app, err := appRepo.GetFirst(commonRepo.WithByID(detail.AppId))
|
app, err := appRepo.GetFirst(commonRepo.WithByID(detail.AppId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return appDetailDTO, err
|
return appDetailDTO, err
|
||||||
@@ -165,57 +209,75 @@ func (a AppService) GetAppDetail(appId uint, version string) (response.AppDetail
|
|||||||
}
|
}
|
||||||
return appDetailDTO, nil
|
return appDetailDTO, nil
|
||||||
}
|
}
|
||||||
|
func (a AppService) GetAppDetailByID(id uint) (*response.AppDetailDTO, error) {
|
||||||
|
res := &response.AppDetailDTO{}
|
||||||
|
appDetail, err := appDetailRepo.GetFirst(commonRepo.WithByID(id))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res.AppDetail = appDetail
|
||||||
|
paramMap := make(map[string]interface{})
|
||||||
|
if err := json.Unmarshal([]byte(appDetail.Params), ¶mMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res.Params = paramMap
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (*model.AppInstall, error) {
|
func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (appInstall *model.AppInstall, err error) {
|
||||||
if err := docker.CreateDefaultDockerNetwork(); err != nil {
|
if err = docker.CreateDefaultDockerNetwork(); err != nil {
|
||||||
return nil, buserr.WithDetail(constant.Err1PanelNetworkFailed, err.Error(), nil)
|
err = buserr.WithDetail(constant.Err1PanelNetworkFailed, err.Error(), nil)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if list, _ := appInstallRepo.ListBy(commonRepo.WithByName(req.Name)); len(list) > 0 {
|
if list, _ := appInstallRepo.ListBy(commonRepo.WithByName(req.Name)); len(list) > 0 {
|
||||||
return nil, buserr.New(constant.ErrNameIsExist)
|
err = buserr.New(constant.ErrNameIsExist)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
httpPort, err := checkPort("PANEL_APP_PORT_HTTP", req.Params)
|
var (
|
||||||
|
httpPort int
|
||||||
|
httpsPort int
|
||||||
|
appDetail model.AppDetail
|
||||||
|
app model.App
|
||||||
|
)
|
||||||
|
httpPort, err = checkPort("PANEL_APP_PORT_HTTP", req.Params)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
httpsPort, err = checkPort("PANEL_APP_PORT_HTTPS", req.Params)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
appDetail, err = appDetailRepo.GetFirst(commonRepo.WithByID(req.AppDetailId))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
app, err = appRepo.GetFirst(commonRepo.WithByID(appDetail.AppId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
httpsPort, err := checkPort("PANEL_APP_PORT_HTTPS", req.Params)
|
if err = checkRequiredAndLimit(app); err != nil {
|
||||||
if err != nil {
|
return
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
appDetail, err := appDetailRepo.GetFirst(commonRepo.WithByID(req.AppDetailId))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
app, err := appRepo.GetFirst(commonRepo.WithByID(appDetail.AppId))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := checkRequiredAndLimit(app); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
paramByte, err := json.Marshal(req.Params)
|
appInstall = &model.AppInstall{
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
appInstall := model.AppInstall{
|
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
AppId: appDetail.AppId,
|
AppId: appDetail.AppId,
|
||||||
AppDetailId: appDetail.ID,
|
AppDetailId: appDetail.ID,
|
||||||
Version: appDetail.Version,
|
Version: appDetail.Version,
|
||||||
Status: constant.Installing,
|
Status: constant.Installing,
|
||||||
Env: string(paramByte),
|
|
||||||
HttpPort: httpPort,
|
HttpPort: httpPort,
|
||||||
HttpsPort: httpsPort,
|
HttpsPort: httpsPort,
|
||||||
App: app,
|
App: app,
|
||||||
}
|
}
|
||||||
composeMap := make(map[string]interface{})
|
composeMap := make(map[string]interface{})
|
||||||
if err := yaml.Unmarshal([]byte(appDetail.DockerCompose), &composeMap); err != nil {
|
if err = yaml.Unmarshal([]byte(appDetail.DockerCompose), &composeMap); err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
value, ok := composeMap["services"]
|
value, ok := composeMap["services"]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, buserr.New("")
|
err = buserr.New("")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
servicesMap := value.(map[string]interface{})
|
servicesMap := value.(map[string]interface{})
|
||||||
changeKeys := make(map[string]string, len(servicesMap))
|
changeKeys := make(map[string]string, len(servicesMap))
|
||||||
@@ -236,33 +298,52 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
|
|||||||
servicesMap[v] = servicesMap[k]
|
servicesMap[v] = servicesMap[k]
|
||||||
delete(servicesMap, k)
|
delete(servicesMap, k)
|
||||||
}
|
}
|
||||||
composeByte, err := yaml.Marshal(composeMap)
|
|
||||||
|
var (
|
||||||
|
composeByte []byte
|
||||||
|
paramByte []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
composeByte, err = yaml.Marshal(composeMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
appInstall.DockerCompose = string(composeByte)
|
appInstall.DockerCompose = string(composeByte)
|
||||||
|
|
||||||
if err := copyAppData(app.Key, appDetail.Version, req.Name, req.Params); err != nil {
|
defer func() {
|
||||||
return nil, err
|
if err != nil {
|
||||||
}
|
hErr := handleAppInstallErr(ctx, appInstall)
|
||||||
|
if hErr != nil {
|
||||||
|
global.LOG.Errorf("delete app dir error %s", hErr.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err = copyAppData(app.Key, appDetail.Version, req.Name, req.Params, app.Resource == constant.AppResourceLocal); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
fileOp := files.NewFileOp()
|
fileOp := files.NewFileOp()
|
||||||
if err := fileOp.WriteFile(appInstall.GetComposePath(), strings.NewReader(string(composeByte)), 0775); err != nil {
|
if err = fileOp.WriteFile(appInstall.GetComposePath(), strings.NewReader(string(composeByte)), 0775); err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
|
paramByte, err = json.Marshal(req.Params)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
appInstall.Env = string(paramByte)
|
||||||
|
|
||||||
if err := appInstallRepo.Create(ctx, &appInstall); err != nil {
|
if err = appInstallRepo.Create(ctx, appInstall); err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
if err := createLink(ctx, app, &appInstall, req.Params); err != nil {
|
if err = createLink(ctx, app, appInstall, req.Params); err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
if err := upAppPre(app, appInstall); err != nil {
|
if err = upAppPre(app, appInstall); err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
go upApp(appInstall.GetComposePath(), appInstall)
|
go upApp(appInstall)
|
||||||
go updateToolApp(appInstall)
|
go updateToolApp(appInstall)
|
||||||
return &appInstall, nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
|
func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
|
||||||
@@ -275,12 +356,11 @@ func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
|
|||||||
}
|
}
|
||||||
versionUrl := fmt.Sprintf("%s/%s/%s/appstore/apps.json", global.CONF.System.RepoUrl, global.CONF.System.Mode, setting.SystemVersion)
|
versionUrl := fmt.Sprintf("%s/%s/%s/appstore/apps.json", global.CONF.System.RepoUrl, global.CONF.System.Mode, setting.SystemVersion)
|
||||||
versionRes, err := http.Get(versionUrl)
|
versionRes, err := http.Get(versionUrl)
|
||||||
global.LOG.Infof("get current version from [%s]", versionUrl)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer versionRes.Body.Close()
|
defer versionRes.Body.Close()
|
||||||
body, err := ioutil.ReadAll(versionRes.Body)
|
body, err := io.ReadAll(versionRes.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -297,7 +377,155 @@ func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AppService) SyncAppList() error {
|
func (a AppService) SyncAppListFromLocal() {
|
||||||
|
fileOp := files.NewFileOp()
|
||||||
|
appDir := constant.LocalAppResourceDir
|
||||||
|
listFile := path.Join(appDir, "list.json")
|
||||||
|
if !fileOp.Stat(listFile) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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()
|
updateRes, err := a.GetAppUpdate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -330,11 +558,11 @@ func (a AppService) SyncAppList() error {
|
|||||||
Name: t.Name,
|
Name: t.Name,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
oldApps, err := appRepo.GetBy()
|
oldApps, err := appRepo.GetBy(appRepo.WithResource(constant.AppResourceRemote))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
appsMap := getApps(oldApps, list.Items)
|
appsMap := getApps(oldApps, list.Items, false)
|
||||||
for _, l := range list.Items {
|
for _, l := range list.Items {
|
||||||
app := appsMap[l.Key]
|
app := appsMap[l.Key]
|
||||||
icon, err := os.ReadFile(path.Join(appDir, l.Key, "metadata", "logo.png"))
|
icon, err := os.ReadFile(path.Join(appDir, l.Key, "metadata", "logo.png"))
|
||||||
@@ -390,8 +618,9 @@ func (a AppService) SyncAppList() error {
|
|||||||
var (
|
var (
|
||||||
addAppArray []model.App
|
addAppArray []model.App
|
||||||
updateArray []model.App
|
updateArray []model.App
|
||||||
|
tagMap = make(map[string]uint, len(tags))
|
||||||
)
|
)
|
||||||
tagMap := make(map[string]uint, len(tags))
|
|
||||||
for _, v := range appsMap {
|
for _, v := range appsMap {
|
||||||
if v.ID == 0 {
|
if v.ID == 0 {
|
||||||
addAppArray = append(addAppArray, v)
|
addAppArray = append(addAppArray, v)
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
@@ -38,7 +38,7 @@ type IAppInstallService interface {
|
|||||||
Page(req request.AppInstalledSearch) (int64, []response.AppInstalledDTO, error)
|
Page(req request.AppInstalledSearch) (int64, []response.AppInstalledDTO, error)
|
||||||
CheckExist(key string) (*response.AppInstalledCheck, error)
|
CheckExist(key string) (*response.AppInstalledCheck, error)
|
||||||
LoadPort(key string) (int64, error)
|
LoadPort(key string) (int64, error)
|
||||||
LoadPassword(key string) (string, error)
|
LoadConnInfo(key string) (response.DatabaseConn, error)
|
||||||
SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error)
|
SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error)
|
||||||
Operate(req request.AppInstalledOperate) error
|
Operate(req request.AppInstalledOperate) error
|
||||||
Update(req request.AppInstalledUpdate) error
|
Update(req request.AppInstalledUpdate) error
|
||||||
@@ -133,12 +133,16 @@ func (a *AppInstallService) LoadPort(key string) (int64, error) {
|
|||||||
return app.Port, nil
|
return app.Port, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AppInstallService) LoadPassword(key string) (string, error) {
|
func (a *AppInstallService) LoadConnInfo(key string) (response.DatabaseConn, error) {
|
||||||
|
var data response.DatabaseConn
|
||||||
app, err := appInstallRepo.LoadBaseInfo(key, "")
|
app, err := appInstallRepo.LoadBaseInfo(key, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil
|
return data, nil
|
||||||
}
|
}
|
||||||
return app.Password, nil
|
data.Password = app.Password
|
||||||
|
data.ServiceName = app.ServiceName
|
||||||
|
data.Port = app.Port
|
||||||
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AppInstallService) SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error) {
|
func (a *AppInstallService) SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error) {
|
||||||
@@ -175,7 +179,7 @@ func (a *AppInstallService) SearchForWebsite(req request.AppInstalledSearch) ([]
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *AppInstallService) Operate(req request.AppInstalledOperate) error {
|
func (a *AppInstallService) Operate(req request.AppInstalledOperate) error {
|
||||||
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(req.InstallId))
|
install, err := appInstallRepo.GetFirstByCtx(context.Background(), commonRepo.WithByID(req.InstallId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -202,17 +206,14 @@ func (a *AppInstallService) Operate(req request.AppInstalledOperate) error {
|
|||||||
}
|
}
|
||||||
return syncById(install.ID)
|
return syncById(install.ID)
|
||||||
case constant.Delete:
|
case constant.Delete:
|
||||||
tx, ctx := getTxAndContext()
|
if err := deleteAppInstall(install, req.DeleteBackup, req.ForceDelete, req.DeleteDB); err != nil && !req.ForceDelete {
|
||||||
if err := deleteAppInstall(ctx, install, req.DeleteBackup, req.ForceDelete, req.DeleteDB); err != nil && !req.ForceDelete {
|
|
||||||
tx.Rollback()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tx.Commit()
|
|
||||||
return nil
|
return nil
|
||||||
case constant.Sync:
|
case constant.Sync:
|
||||||
return syncById(install.ID)
|
return syncById(install.ID)
|
||||||
case constant.Upgrade:
|
case constant.Upgrade:
|
||||||
return updateInstall(install.ID, req.DetailId)
|
return upgradeInstall(install.ID, req.DetailId)
|
||||||
default:
|
default:
|
||||||
return errors.New("operate not support")
|
return errors.New("operate not support")
|
||||||
}
|
}
|
||||||
@@ -224,27 +225,35 @@ func (a *AppInstallService) Update(req request.AppInstalledUpdate) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
changePort := false
|
changePort := false
|
||||||
|
var (
|
||||||
|
oldPorts []int
|
||||||
|
newPorts []int
|
||||||
|
)
|
||||||
port, ok := req.Params["PANEL_APP_PORT_HTTP"]
|
port, ok := req.Params["PANEL_APP_PORT_HTTP"]
|
||||||
if ok {
|
if ok {
|
||||||
portN := int(math.Ceil(port.(float64)))
|
portN := int(math.Ceil(port.(float64)))
|
||||||
if portN != installed.HttpPort {
|
if portN != installed.HttpPort {
|
||||||
|
oldPorts = append(oldPorts, installed.HttpPort)
|
||||||
changePort = true
|
changePort = true
|
||||||
httpPort, err := checkPort("PANEL_APP_PORT_HTTP", req.Params)
|
httpPort, err := checkPort("PANEL_APP_PORT_HTTP", req.Params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
installed.HttpPort = httpPort
|
installed.HttpPort = httpPort
|
||||||
|
newPorts = append(newPorts, httpPort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ports, ok := req.Params["PANEL_APP_PORT_HTTPS"]
|
ports, ok := req.Params["PANEL_APP_PORT_HTTPS"]
|
||||||
if ok {
|
if ok {
|
||||||
portN := int(math.Ceil(ports.(float64)))
|
portN := int(math.Ceil(ports.(float64)))
|
||||||
if portN != installed.HttpsPort {
|
if portN != installed.HttpsPort {
|
||||||
|
oldPorts = append(oldPorts, installed.HttpsPort)
|
||||||
httpsPort, err := checkPort("PANEL_APP_PORT_HTTPS", req.Params)
|
httpsPort, err := checkPort("PANEL_APP_PORT_HTTPS", req.Params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
installed.HttpsPort = httpsPort
|
installed.HttpsPort = httpsPort
|
||||||
|
newPorts = append(newPorts, httpsPort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,7 +271,7 @@ func (a *AppInstallService) Update(req request.AppInstalledUpdate) error {
|
|||||||
if err := env.Write(oldEnvMaps, envPath); err != nil {
|
if err := env.Write(oldEnvMaps, envPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_ = appInstallRepo.Save(&installed)
|
_ = appInstallRepo.Save(context.Background(), &installed)
|
||||||
|
|
||||||
if err := rebuildApp(installed); err != nil {
|
if err := rebuildApp(installed); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -289,6 +298,11 @@ func (a *AppInstallService) Update(req request.AppInstalledUpdate) error {
|
|||||||
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
|
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if changePort {
|
||||||
|
go func() {
|
||||||
|
_ = OperateFirewallPort(oldPorts, newPorts)
|
||||||
|
}()
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,7 +316,7 @@ func (a *AppInstallService) SyncAll(systemInit bool) error {
|
|||||||
if systemInit {
|
if systemInit {
|
||||||
i.Status = constant.Error
|
i.Status = constant.Error
|
||||||
i.Message = "System restart causes application exception"
|
i.Message = "System restart causes application exception"
|
||||||
_ = appInstallRepo.Save(&i)
|
_ = appInstallRepo.Save(context.Background(), &i)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -387,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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,14 +418,12 @@ func (a *AppInstallService) DeleteCheck(installId uint) ([]dto.AppResource, erro
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if app.Type == "website" {
|
websites, _ := websiteRepo.GetBy(websiteRepo.WithAppInstallId(appInstall.ID))
|
||||||
websites, _ := websiteRepo.GetBy(websiteRepo.WithAppInstallId(appInstall.ID))
|
for _, website := range websites {
|
||||||
for _, website := range websites {
|
res = append(res, dto.AppResource{
|
||||||
res = append(res, dto.AppResource{
|
Type: "website",
|
||||||
Type: "website",
|
Name: website.PrimaryDomain,
|
||||||
Name: website.PrimaryDomain,
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if app.Key == constant.AppOpenresty {
|
if app.Key == constant.AppOpenresty {
|
||||||
websites, _ := websiteRepo.GetBy()
|
websites, _ := websiteRepo.GetBy()
|
||||||
@@ -567,15 +583,15 @@ func syncById(installId uint) error {
|
|||||||
if containerCount == 0 {
|
if containerCount == 0 {
|
||||||
appInstall.Status = constant.Error
|
appInstall.Status = constant.Error
|
||||||
appInstall.Message = "container is not found"
|
appInstall.Message = "container is not found"
|
||||||
return appInstallRepo.Save(&appInstall)
|
return appInstallRepo.Save(context.Background(), &appInstall)
|
||||||
}
|
}
|
||||||
if errCount == 0 && existedCount == 0 {
|
if errCount == 0 && existedCount == 0 {
|
||||||
appInstall.Status = constant.Running
|
appInstall.Status = constant.Running
|
||||||
return appInstallRepo.Save(&appInstall)
|
return appInstallRepo.Save(context.Background(), &appInstall)
|
||||||
}
|
}
|
||||||
if existedCount == normalCount {
|
if existedCount == normalCount {
|
||||||
appInstall.Status = constant.Stopped
|
appInstall.Status = constant.Stopped
|
||||||
return appInstallRepo.Save(&appInstall)
|
return appInstallRepo.Save(context.Background(), &appInstall)
|
||||||
}
|
}
|
||||||
if errCount == normalCount {
|
if errCount == normalCount {
|
||||||
appInstall.Status = constant.Error
|
appInstall.Status = constant.Error
|
||||||
@@ -600,7 +616,7 @@ func syncById(installId uint) error {
|
|||||||
errMsg.Write([]byte("\n"))
|
errMsg.Write([]byte("\n"))
|
||||||
}
|
}
|
||||||
appInstall.Message = errMsg.String()
|
appInstall.Message = errMsg.String()
|
||||||
return appInstallRepo.Save(&appInstall)
|
return appInstallRepo.Save(context.Background(), &appInstall)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateInstallInfoInDB(appKey, appName, param string, isRestart bool, value interface{}) error {
|
func updateInstallInfoInDB(appKey, appName, param string, isRestart bool, value interface{}) error {
|
||||||
@@ -612,7 +628,7 @@ func updateInstallInfoInDB(appKey, appName, param string, isRestart bool, value
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
envPath := fmt.Sprintf("%s/%s/%s/.env", constant.AppInstallDir, appKey, appInstall.Name)
|
envPath := fmt.Sprintf("%s/%s/%s/.env", constant.AppInstallDir, appKey, appInstall.Name)
|
||||||
lineBytes, err := ioutil.ReadFile(envPath)
|
lineBytes, err := os.ReadFile(envPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,12 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||||
|
"github.com/compose-spec/compose-go/types"
|
||||||
|
"github.com/subosito/gotenv"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -23,6 +27,7 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/compose"
|
"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"
|
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@@ -125,7 +130,23 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteAppInstall(ctx context.Context, install model.AppInstall, deleteBackup bool, forceDelete bool, deleteDB bool) error {
|
func handleAppInstallErr(ctx context.Context, install *model.AppInstall) error {
|
||||||
|
op := files.NewFileOp()
|
||||||
|
appDir := install.GetPath()
|
||||||
|
dir, _ := os.Stat(appDir)
|
||||||
|
if dir != nil {
|
||||||
|
_, _ = compose.Down(install.GetComposePath())
|
||||||
|
if err := op.DeleteDir(appDir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := deleteLink(ctx, install, true, true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteAppInstall(install model.AppInstall, deleteBackup bool, forceDelete bool, deleteDB bool) error {
|
||||||
op := files.NewFileOp()
|
op := files.NewFileOp()
|
||||||
appDir := install.GetPath()
|
appDir := install.GetPath()
|
||||||
dir, _ := os.Stat(appDir)
|
dir, _ := os.Stat(appDir)
|
||||||
@@ -134,36 +155,34 @@ func deleteAppInstall(ctx context.Context, install model.AppInstall, deleteBacku
|
|||||||
if err != nil && !forceDelete {
|
if err != nil && !forceDelete {
|
||||||
return handleErr(install, err, out)
|
return handleErr(install, err, out)
|
||||||
}
|
}
|
||||||
if err := op.DeleteDir(appDir); err != nil && !forceDelete {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
tx, ctx := helper.GetTxAndContext()
|
||||||
|
defer tx.Rollback()
|
||||||
if err := appInstallRepo.Delete(ctx, install); err != nil {
|
if err := appInstallRepo.Delete(ctx, install); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := deleteLink(ctx, &install, deleteDB, forceDelete); err != nil && !forceDelete {
|
if err := deleteLink(ctx, &install, deleteDB, forceDelete); err != nil && !forceDelete {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType("app"), commonRepo.WithByName(install.App.Key), backupRepo.WithByDetailName(install.Name))
|
||||||
|
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType(install.App.Key))
|
||||||
|
if install.App.Key == constant.AppMysql {
|
||||||
|
_ = mysqlRepo.DeleteAll(ctx)
|
||||||
|
}
|
||||||
uploadDir := fmt.Sprintf("%s/1panel/uploads/app/%s/%s", global.CONF.System.BaseDir, install.App.Key, install.Name)
|
uploadDir := fmt.Sprintf("%s/1panel/uploads/app/%s/%s", global.CONF.System.BaseDir, install.App.Key, install.Name)
|
||||||
if _, err := os.Stat(uploadDir); err == nil {
|
if _, err := os.Stat(uploadDir); err == nil {
|
||||||
_ = os.RemoveAll(uploadDir)
|
_ = os.RemoveAll(uploadDir)
|
||||||
}
|
}
|
||||||
if deleteBackup {
|
if deleteBackup {
|
||||||
localDir, err := loadLocalDir()
|
localDir, _ := loadLocalDir()
|
||||||
if err != nil && !forceDelete {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
backupDir := fmt.Sprintf("%s/app/%s/%s", localDir, install.App.Key, install.Name)
|
backupDir := fmt.Sprintf("%s/app/%s/%s", localDir, install.App.Key, install.Name)
|
||||||
if _, err := os.Stat(backupDir); err == nil {
|
if _, err := os.Stat(backupDir); err == nil {
|
||||||
_ = os.RemoveAll(backupDir)
|
_ = os.RemoveAll(backupDir)
|
||||||
}
|
}
|
||||||
global.LOG.Infof("delete app %s-%s backups successful", install.App.Key, install.Name)
|
global.LOG.Infof("delete app %s-%s backups successful", install.App.Key, install.Name)
|
||||||
}
|
}
|
||||||
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType("app"), commonRepo.WithByName(install.App.Key), backupRepo.WithByDetailName(install.Name))
|
_ = op.DeleteDir(appDir)
|
||||||
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType(install.App.Key))
|
tx.Commit()
|
||||||
if install.App.Key == constant.AppMysql {
|
|
||||||
_ = mysqlRepo.DeleteAll(ctx)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,7 +209,7 @@ func deleteLink(ctx context.Context, install *model.AppInstall, deleteDB bool, f
|
|||||||
return appInstallResourceRepo.DeleteBy(ctx, appInstallResourceRepo.WithAppInstallId(install.ID))
|
return appInstallResourceRepo.DeleteBy(ctx, appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateInstall(installId uint, detailId uint) error {
|
func upgradeInstall(installId uint, detailId uint) error {
|
||||||
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
|
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -205,7 +224,25 @@ func updateInstall(installId uint, detailId uint) error {
|
|||||||
if err := NewIBackupService().AppBackup(dto.CommonBackup{Name: install.App.Key, DetailName: install.Name}); err != nil {
|
if err := NewIBackupService().AppBackup(dto.CommonBackup{Name: install.App.Key, DetailName: install.Name}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err = compose.Down(install.GetComposePath()); err != nil {
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
if out, err := compose.Down(install.GetComposePath()); err != nil {
|
||||||
|
if out != "" {
|
||||||
|
return errors.New(out)
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
install.DockerCompose = detail.DockerCompose
|
install.DockerCompose = detail.DockerCompose
|
||||||
@@ -216,32 +253,51 @@ func updateInstall(installId uint, detailId uint) error {
|
|||||||
if err := fileOp.WriteFile(install.GetComposePath(), strings.NewReader(install.DockerCompose), 0775); err != nil {
|
if err := fileOp.WriteFile(install.GetComposePath(), strings.NewReader(install.DockerCompose), 0775); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err = compose.Up(install.GetComposePath()); err != nil {
|
if out, err := compose.Up(install.GetComposePath()); err != nil {
|
||||||
|
if out != "" {
|
||||||
|
return errors.New(out)
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return appInstallRepo.Save(&install)
|
return appInstallRepo.Save(context.Background(), &install)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getContainerNames(install model.AppInstall) ([]string, error) {
|
func getContainerNames(install model.AppInstall) ([]string, error) {
|
||||||
composeMap := install.DockerCompose
|
envStr, err := coverEnvJsonToStr(install.Env)
|
||||||
envMap := make(map[string]interface{})
|
|
||||||
_ = json.Unmarshal([]byte(install.Env), &envMap)
|
|
||||||
newEnvMap := make(map[string]string, len(envMap))
|
|
||||||
handleMap(envMap, newEnvMap)
|
|
||||||
project, err := compose.GetComposeProject([]byte(composeMap), newEnvMap)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
containerNames := []string{install.ContainerName}
|
project, err := composeV2.GetComposeProject(install.Name, install.GetPath(), []byte(install.DockerCompose), []byte(envStr), true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
containerMap := make(map[string]struct{})
|
||||||
|
containerMap[install.ContainerName] = struct{}{}
|
||||||
for _, service := range project.AllServices() {
|
for _, service := range project.AllServices() {
|
||||||
if service.ContainerName == "${CONTAINER_NAME}" || service.ContainerName == "" {
|
if service.ContainerName == "${CONTAINER_NAME}" || service.ContainerName == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
containerNames = append(containerNames, service.ContainerName)
|
containerMap[service.ContainerName] = struct{}{}
|
||||||
|
}
|
||||||
|
var containerNames []string
|
||||||
|
for k := range containerMap {
|
||||||
|
containerNames = append(containerNames, k)
|
||||||
}
|
}
|
||||||
return containerNames, nil
|
return containerNames, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func coverEnvJsonToStr(envJson string) (string, error) {
|
||||||
|
envMap := make(map[string]interface{})
|
||||||
|
_ = json.Unmarshal([]byte(envJson), &envMap)
|
||||||
|
newEnvMap := make(map[string]string, len(envMap))
|
||||||
|
handleMap(envMap, newEnvMap)
|
||||||
|
envStr, err := gotenv.Marshal(newEnvMap)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return envStr, nil
|
||||||
|
}
|
||||||
|
|
||||||
func checkLimit(app model.App) error {
|
func checkLimit(app model.App) error {
|
||||||
if app.Limit > 0 {
|
if app.Limit > 0 {
|
||||||
installs, err := appInstallRepo.ListBy(appInstallRepo.WithAppId(app.ID))
|
installs, err := appInstallRepo.ListBy(appInstallRepo.WithAppId(app.ID))
|
||||||
@@ -256,11 +312,9 @@ func checkLimit(app model.App) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkRequiredAndLimit(app model.App) error {
|
func checkRequiredAndLimit(app model.App) error {
|
||||||
|
|
||||||
if err := checkLimit(app); err != nil {
|
if err := checkLimit(app); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if app.Required != "" {
|
if app.Required != "" {
|
||||||
var requiredArray []string
|
var requiredArray []string
|
||||||
if err := json.Unmarshal([]byte(app.Required), &requiredArray); err != nil {
|
if err := json.Unmarshal([]byte(app.Required), &requiredArray); err != nil {
|
||||||
@@ -289,7 +343,6 @@ func checkRequiredAndLimit(app model.App) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,10 +359,17 @@ func handleMap(params map[string]interface{}, envParams map[string]string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyAppData(key, version, installName string, params map[string]interface{}) (err error) {
|
func copyAppData(key, version, installName string, params map[string]interface{}, isLocal bool) (err error) {
|
||||||
fileOp := files.NewFileOp()
|
fileOp := files.NewFileOp()
|
||||||
resourceDir := path.Join(constant.AppResourceDir, key, "versions", version)
|
appResourceDir := constant.AppResourceDir
|
||||||
installAppDir := path.Join(constant.AppInstallDir, key)
|
installAppDir := path.Join(constant.AppInstallDir, key)
|
||||||
|
appKey := key
|
||||||
|
if isLocal {
|
||||||
|
appResourceDir = constant.LocalAppResourceDir
|
||||||
|
appKey = strings.TrimPrefix(key, "local")
|
||||||
|
installAppDir = path.Join(constant.LocalAppInstallDir, appKey)
|
||||||
|
}
|
||||||
|
resourceDir := path.Join(appResourceDir, appKey, "versions", version)
|
||||||
|
|
||||||
if !fileOp.Stat(installAppDir) {
|
if !fileOp.Stat(installAppDir) {
|
||||||
if err = fileOp.CreateDir(installAppDir, 0755); err != nil {
|
if err = fileOp.CreateDir(installAppDir, 0755); err != nil {
|
||||||
@@ -340,7 +400,7 @@ func copyAppData(key, version, installName string, params map[string]interface{}
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 处理文件夹权限等问题
|
// 处理文件夹权限等问题
|
||||||
func upAppPre(app model.App, appInstall model.AppInstall) error {
|
func upAppPre(app model.App, appInstall *model.AppInstall) error {
|
||||||
if app.Key == "nexus" {
|
if app.Key == "nexus" {
|
||||||
dataPath := path.Join(appInstall.GetPath(), "data")
|
dataPath := path.Join(appInstall.GetPath(), "data")
|
||||||
if err := files.NewFileOp().Chown(dataPath, 200, 0); err != nil {
|
if err := files.NewFileOp().Chown(dataPath, 200, 0); err != nil {
|
||||||
@@ -350,19 +410,53 @@ func upAppPre(app model.App, appInstall model.AppInstall) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func upApp(composeFilePath string, appInstall model.AppInstall) {
|
func getServiceFromInstall(appInstall *model.AppInstall) (service *composeV2.ComposeService, err error) {
|
||||||
out, err := compose.Up(composeFilePath)
|
var (
|
||||||
|
project *types.Project
|
||||||
|
envStr string
|
||||||
|
)
|
||||||
|
envStr, err = coverEnvJsonToStr(appInstall.Env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if out != "" {
|
return
|
||||||
appInstall.Message = out
|
}
|
||||||
|
project, err = composeV2.GetComposeProject(appInstall.Name, appInstall.GetPath(), []byte(appInstall.DockerCompose), []byte(envStr), true)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
service, err = composeV2.NewComposeService()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
service.SetProject(project)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func upApp(appInstall *model.AppInstall) {
|
||||||
|
upProject := func(appInstall *model.AppInstall) (err error) {
|
||||||
|
if err == nil {
|
||||||
|
var composeService *composeV2.ComposeService
|
||||||
|
composeService, err = getServiceFromInstall(appInstall)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = composeService.ComposeUp()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return
|
||||||
} else {
|
} else {
|
||||||
appInstall.Message = err.Error()
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if err := upProject(appInstall); err != nil {
|
||||||
appInstall.Status = constant.Error
|
appInstall.Status = constant.Error
|
||||||
_ = appInstallRepo.Save(&appInstall)
|
appInstall.Message = err.Error()
|
||||||
} else {
|
} else {
|
||||||
appInstall.Status = constant.Running
|
appInstall.Status = constant.Running
|
||||||
_ = appInstallRepo.Save(&appInstall)
|
}
|
||||||
|
exist, _ := appInstallRepo.GetFirst(commonRepo.WithByID(appInstall.ID))
|
||||||
|
if exist.ID > 0 {
|
||||||
|
_ = appInstallRepo.Save(context.Background(), appInstall)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,20 +495,29 @@ func getAppDetails(details []model.AppDetail, versions []string) map[string]mode
|
|||||||
return appDetails
|
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))
|
apps := make(map[string]model.App, len(oldApps))
|
||||||
for _, old := range oldApps {
|
for _, old := range oldApps {
|
||||||
old.Status = constant.AppTakeDown
|
old.Status = constant.AppTakeDown
|
||||||
apps[old.Key] = old
|
apps[old.Key] = old
|
||||||
}
|
}
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
app, ok := apps[item.Key]
|
key := item.Key
|
||||||
|
if isLocal {
|
||||||
|
key = "local" + key
|
||||||
|
}
|
||||||
|
app, ok := apps[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
app = model.App{}
|
app = model.App{}
|
||||||
}
|
}
|
||||||
|
if isLocal {
|
||||||
|
app.Resource = constant.AppResourceLocal
|
||||||
|
} else {
|
||||||
|
app.Resource = constant.AppResourceRemote
|
||||||
|
}
|
||||||
app.Name = item.Name
|
app.Name = item.Name
|
||||||
app.Limit = item.Limit
|
app.Limit = item.Limit
|
||||||
app.Key = item.Key
|
app.Key = key
|
||||||
app.ShortDescZh = item.ShortDescZh
|
app.ShortDescZh = item.ShortDescZh
|
||||||
app.ShortDescEn = item.ShortDescEn
|
app.ShortDescEn = item.ShortDescEn
|
||||||
app.Website = item.Website
|
app.Website = item.Website
|
||||||
@@ -424,7 +527,7 @@ func getApps(oldApps []model.App, items []dto.AppDefine) map[string]model.App {
|
|||||||
app.CrossVersionUpdate = item.CrossVersionUpdate
|
app.CrossVersionUpdate = item.CrossVersionUpdate
|
||||||
app.Required = item.GetRequired()
|
app.Required = item.GetRequired()
|
||||||
app.Status = constant.AppNormal
|
app.Status = constant.AppNormal
|
||||||
apps[item.Key] = app
|
apps[key] = app
|
||||||
}
|
}
|
||||||
return apps
|
return apps
|
||||||
}
|
}
|
||||||
@@ -437,7 +540,7 @@ func handleErr(install model.AppInstall, err error, out string) error {
|
|||||||
reErr = errors.New(out)
|
reErr = errors.New(out)
|
||||||
install.Status = constant.Error
|
install.Status = constant.Error
|
||||||
}
|
}
|
||||||
_ = appInstallRepo.Save(&install)
|
_ = appInstallRepo.Save(context.Background(), &install)
|
||||||
return reErr
|
return reErr
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,6 +570,9 @@ func getAppFromRepo(downloadPath, version string) error {
|
|||||||
func handleInstalled(appInstallList []model.AppInstall, updated bool) ([]response.AppInstalledDTO, error) {
|
func handleInstalled(appInstallList []model.AppInstall, updated bool) ([]response.AppInstalledDTO, error) {
|
||||||
var res []response.AppInstalledDTO
|
var res []response.AppInstalledDTO
|
||||||
for _, installed := range appInstallList {
|
for _, installed := range appInstallList {
|
||||||
|
if updated && installed.App.Type == "php" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
installDTO := response.AppInstalledDTO{
|
installDTO := response.AppInstalledDTO{
|
||||||
AppInstall: installed,
|
AppInstall: installed,
|
||||||
}
|
}
|
||||||
@@ -512,7 +618,7 @@ func getAppInstallByKey(key string) (model.AppInstall, error) {
|
|||||||
return appInstall, nil
|
return appInstall, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateToolApp(installed model.AppInstall) {
|
func updateToolApp(installed *model.AppInstall) {
|
||||||
tooKey, ok := dto.AppToolMap[installed.App.Key]
|
tooKey, ok := dto.AppToolMap[installed.App.Key]
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
@@ -548,7 +654,7 @@ func updateToolApp(installed model.AppInstall) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
toolInstall.Env = string(contentByte)
|
toolInstall.Env = string(contentByte)
|
||||||
if err := appInstallRepo.Save(&toolInstall); err != nil {
|
if err := appInstallRepo.Save(context.Background(), &toolInstall); err != nil {
|
||||||
global.LOG.Errorf("update tool app [%s] error : %s", toolInstall.Name, err.Error())
|
global.LOG.Errorf("update tool app [%s] error : %s", toolInstall.Name, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
@@ -19,35 +17,17 @@ import (
|
|||||||
type AuthService struct{}
|
type AuthService struct{}
|
||||||
|
|
||||||
type IAuthService interface {
|
type IAuthService interface {
|
||||||
SafetyStatus(c *gin.Context) error
|
CheckIsSafety(code string) bool
|
||||||
CheckIsFirst() bool
|
|
||||||
InitUser(c *gin.Context, req dto.InitUser) error
|
|
||||||
VerifyCode(code string) (bool, error)
|
VerifyCode(code string) (bool, error)
|
||||||
SafeEntrance(c *gin.Context, code string) error
|
|
||||||
Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo, error)
|
Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo, error)
|
||||||
LogOut(c *gin.Context) error
|
LogOut(c *gin.Context) error
|
||||||
|
MFALogin(c *gin.Context, info dto.MFALogin) (*dto.UserLoginInfo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIAuthService() IAuthService {
|
func NewIAuthService() IAuthService {
|
||||||
return &AuthService{}
|
return &AuthService{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *AuthService) SafeEntrance(c *gin.Context, code string) error {
|
|
||||||
codeWithMD5 := encrypt.Md5(code)
|
|
||||||
cookieValue, _ := encrypt.StringEncrypt(codeWithMD5)
|
|
||||||
c.SetCookie(codeWithMD5, cookieValue, 604800, "", "", false, false)
|
|
||||||
|
|
||||||
expiredSetting, err := settingRepo.Get(settingRepo.WithByKey("ExpirationDays"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
timeout, _ := strconv.Atoi(expiredSetting.Value)
|
|
||||||
if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format("2006-01-02 15:04:05")); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *AuthService) Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo, error) {
|
func (u *AuthService) Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo, error) {
|
||||||
nameSetting, err := settingRepo.Get(settingRepo.WithByKey("UserName"))
|
nameSetting, err := settingRepo.Get(settingRepo.WithByKey("UserName"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -163,57 +143,13 @@ func (u *AuthService) VerifyCode(code string) (bool, error) {
|
|||||||
return setting.Value == code, nil
|
return setting.Value == code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *AuthService) SafetyStatus(c *gin.Context) error {
|
func (u *AuthService) CheckIsSafety(code string) bool {
|
||||||
setting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
|
status, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false
|
||||||
}
|
}
|
||||||
codeWithEcrypt, err := c.Cookie(encrypt.Md5(setting.Value))
|
if len(status.Value) == 0 {
|
||||||
if err != nil {
|
return true
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
code, err := encrypt.StringDecrypt(codeWithEcrypt)
|
return status.Value == code
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if code != encrypt.Md5(setting.Value) {
|
|
||||||
return errors.New("code not match")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *AuthService) CheckIsFirst() bool {
|
|
||||||
user, _ := settingRepo.Get(settingRepo.WithByKey("UserName"))
|
|
||||||
pass, _ := settingRepo.Get(settingRepo.WithByKey("Password"))
|
|
||||||
return len(user.Value) == 0 || len(pass.Value) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *AuthService) InitUser(c *gin.Context, req dto.InitUser) error {
|
|
||||||
user, _ := settingRepo.Get(settingRepo.WithByKey("UserName"))
|
|
||||||
pass, _ := settingRepo.Get(settingRepo.WithByKey("Password"))
|
|
||||||
if len(user.Value) == 0 || len(pass.Value) == 0 {
|
|
||||||
newPass, err := encrypt.StringEncrypt(req.Password)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := settingRepo.Update("UserName", req.Name); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := settingRepo.Update("Password", newPass); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
expiredSetting, err := settingRepo.Get(settingRepo.WithByKey("ExpirationDays"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
timeout, _ := strconv.Atoi(expiredSetting.Value)
|
|
||||||
if timeout != 0 {
|
|
||||||
if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format("2006-01-02 15:04:05")); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Errorf("can't init user because user %s is in system", user.Value)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,10 +9,11 @@ import (
|
|||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/cloud_storage"
|
"github.com/1Panel-dev/1Panel/backend/utils/cloud_storage"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
fileUtils "github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
"github.com/jinzhu/copier"
|
"github.com/jinzhu/copier"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@@ -26,7 +27,7 @@ type IBackupService interface {
|
|||||||
Create(backupDto dto.BackupOperate) error
|
Create(backupDto dto.BackupOperate) error
|
||||||
GetBuckets(backupDto dto.ForBuckets) ([]interface{}, error)
|
GetBuckets(backupDto dto.ForBuckets) ([]interface{}, error)
|
||||||
Update(ireq dto.BackupOperate) error
|
Update(ireq dto.BackupOperate) error
|
||||||
BatchDelete(ids []uint) error
|
Delete(id uint) error
|
||||||
BatchDeleteRecord(ids []uint) error
|
BatchDeleteRecord(ids []uint) error
|
||||||
NewClient(backup *model.BackupAccount) (cloud_storage.CloudStorageClient, error)
|
NewClient(backup *model.BackupAccount) (cloud_storage.CloudStorageClient, error)
|
||||||
|
|
||||||
@@ -53,36 +54,13 @@ func NewIBackupService() IBackupService {
|
|||||||
func (u *BackupService) List() ([]dto.BackupInfo, error) {
|
func (u *BackupService) List() ([]dto.BackupInfo, error) {
|
||||||
ops, err := backupRepo.List(commonRepo.WithOrderBy("created_at desc"))
|
ops, err := backupRepo.List(commonRepo.WithOrderBy("created_at desc"))
|
||||||
var dtobas []dto.BackupInfo
|
var dtobas []dto.BackupInfo
|
||||||
ossExist, s3Exist, sftpExist, minioExist := false, false, false, false
|
dtobas = append(dtobas, u.loadByType("LOCAL", ops))
|
||||||
for _, group := range ops {
|
dtobas = append(dtobas, u.loadByType("OSS", ops))
|
||||||
switch group.Type {
|
dtobas = append(dtobas, u.loadByType("S3", ops))
|
||||||
case "OSS":
|
dtobas = append(dtobas, u.loadByType("SFTP", ops))
|
||||||
ossExist = true
|
dtobas = append(dtobas, u.loadByType("MINIO", ops))
|
||||||
case "S3":
|
dtobas = append(dtobas, u.loadByType("COS", ops))
|
||||||
s3Exist = true
|
dtobas = append(dtobas, u.loadByType("KODO", ops))
|
||||||
case "SFTP":
|
|
||||||
sftpExist = true
|
|
||||||
case "MINIO":
|
|
||||||
minioExist = true
|
|
||||||
}
|
|
||||||
var item dto.BackupInfo
|
|
||||||
if err := copier.Copy(&item, &group); err != nil {
|
|
||||||
return nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
|
||||||
}
|
|
||||||
dtobas = append(dtobas, item)
|
|
||||||
}
|
|
||||||
if !ossExist {
|
|
||||||
dtobas = append(dtobas, dto.BackupInfo{Type: "OSS"})
|
|
||||||
}
|
|
||||||
if !s3Exist {
|
|
||||||
dtobas = append(dtobas, dto.BackupInfo{Type: "S3"})
|
|
||||||
}
|
|
||||||
if !sftpExist {
|
|
||||||
dtobas = append(dtobas, dto.BackupInfo{Type: "SFTP"})
|
|
||||||
}
|
|
||||||
if !minioExist {
|
|
||||||
dtobas = append(dtobas, dto.BackupInfo{Type: "MINIO"})
|
|
||||||
}
|
|
||||||
return dtobas, err
|
return dtobas, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +101,7 @@ func (u *BackupService) DownloadRecord(info dto.DownloadRecord) (string, error)
|
|||||||
case constant.Sftp:
|
case constant.Sftp:
|
||||||
varMap["username"] = backup.AccessKey
|
varMap["username"] = backup.AccessKey
|
||||||
varMap["password"] = backup.Credential
|
varMap["password"] = backup.Credential
|
||||||
case constant.OSS, constant.S3, constant.MinIo:
|
case constant.OSS, constant.S3, constant.MinIo, constant.Cos, constant.Kodo:
|
||||||
varMap["accessKey"] = backup.AccessKey
|
varMap["accessKey"] = backup.AccessKey
|
||||||
varMap["secretKey"] = backup.Credential
|
varMap["secretKey"] = backup.Credential
|
||||||
}
|
}
|
||||||
@@ -171,7 +149,7 @@ func (u *BackupService) GetBuckets(backupDto dto.ForBuckets) ([]interface{}, err
|
|||||||
case constant.Sftp:
|
case constant.Sftp:
|
||||||
varMap["username"] = backupDto.AccessKey
|
varMap["username"] = backupDto.AccessKey
|
||||||
varMap["password"] = backupDto.Credential
|
varMap["password"] = backupDto.Credential
|
||||||
case constant.OSS, constant.S3, constant.MinIo:
|
case constant.OSS, constant.S3, constant.MinIo, constant.Cos, constant.Kodo:
|
||||||
varMap["accessKey"] = backupDto.AccessKey
|
varMap["accessKey"] = backupDto.AccessKey
|
||||||
varMap["secretKey"] = backupDto.Credential
|
varMap["secretKey"] = backupDto.Credential
|
||||||
}
|
}
|
||||||
@@ -182,8 +160,12 @@ func (u *BackupService) GetBuckets(backupDto dto.ForBuckets) ([]interface{}, err
|
|||||||
return client.ListBuckets()
|
return client.ListBuckets()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *BackupService) BatchDelete(ids []uint) error {
|
func (u *BackupService) Delete(id uint) error {
|
||||||
return backupRepo.Delete(commonRepo.WithIdsIn(ids))
|
cronjobs, _ := cronjobRepo.List(cronjobRepo.WithByBackupID(id))
|
||||||
|
if len(cronjobs) != 0 {
|
||||||
|
return buserr.New(constant.ErrBackupInUsed)
|
||||||
|
}
|
||||||
|
return backupRepo.Delete(commonRepo.WithByID(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *BackupService) BatchDeleteRecord(ids []uint) error {
|
func (u *BackupService) BatchDeleteRecord(ids []uint) error {
|
||||||
@@ -241,7 +223,7 @@ func (u *BackupService) Update(req dto.BackupOperate) error {
|
|||||||
if strings.HasSuffix(dirStr, "/") {
|
if strings.HasSuffix(dirStr, "/") {
|
||||||
dirStr = dirStr[:strings.LastIndex(dirStr, "/")]
|
dirStr = dirStr[:strings.LastIndex(dirStr, "/")]
|
||||||
}
|
}
|
||||||
if err := updateBackupDir(dirStr, oldDir); err != nil {
|
if err := copyDir(oldDir, dirStr); err != nil {
|
||||||
_ = backupRepo.Update(req.ID, (map[string]interface{}{"vars": oldVars}))
|
_ = backupRepo.Update(req.ID, (map[string]interface{}{"vars": oldVars}))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -277,7 +259,7 @@ func (u *BackupService) NewClient(backup *model.BackupAccount) (cloud_storage.Cl
|
|||||||
case constant.Sftp:
|
case constant.Sftp:
|
||||||
varMap["username"] = backup.AccessKey
|
varMap["username"] = backup.AccessKey
|
||||||
varMap["password"] = backup.Credential
|
varMap["password"] = backup.Credential
|
||||||
case constant.OSS, constant.S3, constant.MinIo:
|
case constant.OSS, constant.S3, constant.MinIo, constant.Cos, constant.Kodo:
|
||||||
varMap["accessKey"] = backup.AccessKey
|
varMap["accessKey"] = backup.AccessKey
|
||||||
varMap["secretKey"] = backup.Credential
|
varMap["secretKey"] = backup.Credential
|
||||||
}
|
}
|
||||||
@@ -290,6 +272,19 @@ func (u *BackupService) NewClient(backup *model.BackupAccount) (cloud_storage.Cl
|
|||||||
return backClient, nil
|
return backClient, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *BackupService) loadByType(accountType string, accounts []model.BackupAccount) dto.BackupInfo {
|
||||||
|
for _, account := range accounts {
|
||||||
|
if account.Type == accountType {
|
||||||
|
var item dto.BackupInfo
|
||||||
|
if err := copier.Copy(&item, &account); err != nil {
|
||||||
|
global.LOG.Errorf("copy backup account to dto backup info failed, err: %v", err)
|
||||||
|
}
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dto.BackupInfo{Type: accountType}
|
||||||
|
}
|
||||||
|
|
||||||
func loadLocalDir() (string, error) {
|
func loadLocalDir() (string, error) {
|
||||||
backup, err := backupRepo.Get(commonRepo.WithByType("LOCAL"))
|
backup, err := backupRepo.Get(commonRepo.WithByType("LOCAL"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -314,18 +309,33 @@ func loadLocalDir() (string, error) {
|
|||||||
return "", fmt.Errorf("error type dir: %T", varMap["dir"])
|
return "", fmt.Errorf("error type dir: %T", varMap["dir"])
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateBackupDir(dir, oldDir string) error {
|
func copyDir(src, dst string) error {
|
||||||
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
srcInfo, err := os.Stat(src)
|
||||||
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
|
if err = os.MkdirAll(dst, srcInfo.Mode()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
files, err := os.ReadDir(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fileOP := fileUtils.NewFileOp()
|
||||||
|
for _, file := range files {
|
||||||
|
srcPath := fmt.Sprintf("%s/%s", src, file.Name())
|
||||||
|
dstPath := fmt.Sprintf("%s/%s", dst, file.Name())
|
||||||
|
if file.IsDir() {
|
||||||
|
if err = copyDir(srcPath, dstPath); err != nil {
|
||||||
|
global.LOG.Errorf("copy dir %s to %s failed, err: %v", srcPath, dstPath, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := fileOP.CopyFile(srcPath, dst); err != nil {
|
||||||
|
global.LOG.Errorf("copy file %s to %s failed, err: %v", srcPath, dstPath, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if strings.HasSuffix(oldDir, "/") {
|
|
||||||
oldDir = oldDir[:strings.LastIndex(oldDir, "/")]
|
|
||||||
}
|
|
||||||
stdout, err := cmd.Execf("cp -r %s/* %s", oldDir, dir)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(string(stdout))
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
@@ -32,6 +33,7 @@ func (u *BackupService) AppBackup(req dto.CommonBackup) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
timeNow := time.Now().Format("20060102150405")
|
timeNow := time.Now().Format("20060102150405")
|
||||||
|
|
||||||
backupDir := fmt.Sprintf("%s/app/%s/%s", localDir, req.Name, req.DetailName)
|
backupDir := fmt.Sprintf("%s/app/%s/%s", localDir, req.Name, req.DetailName)
|
||||||
|
|
||||||
fileName := fmt.Sprintf("%s_%s.tar.gz", req.DetailName, timeNow)
|
fileName := fmt.Sprintf("%s_%s.tar.gz", req.DetailName, timeNow)
|
||||||
@@ -97,7 +99,7 @@ func handleAppBackup(install *model.AppInstall, backupDir, fileName string) erro
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
appPath := fmt.Sprintf("%s/%s/%s", constant.AppInstallDir, install.App.Key, install.Name)
|
appPath := fmt.Sprintf("%s/%s", install.GetPath(), install.Name)
|
||||||
if err := handleTar(appPath, tmpDir, "app.tar.gz", ""); err != nil {
|
if err := handleTar(appPath, tmpDir, "app.tar.gz", ""); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -192,7 +194,7 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
|
|||||||
}
|
}
|
||||||
|
|
||||||
oldInstall.Status = constant.Running
|
oldInstall.Status = constant.Running
|
||||||
if err := appInstallRepo.Save(install); err != nil {
|
if err := appInstallRepo.Save(context.Background(), install); err != nil {
|
||||||
global.LOG.Errorf("save db app install failed, err: %v", err)
|
global.LOG.Errorf("save db app install failed, err: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -176,11 +175,11 @@ func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback
|
|||||||
if appendonly == "yes" && redisInfo.Version == "6.0.16" {
|
if appendonly == "yes" && redisInfo.Version == "6.0.16" {
|
||||||
itemName = "appendonly.aof"
|
itemName = "appendonly.aof"
|
||||||
}
|
}
|
||||||
input, err := ioutil.ReadFile(recoverFile)
|
input, err := os.ReadFile(recoverFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = ioutil.WriteFile(composeDir+"/data/"+itemName, input, 0640); err != nil {
|
if err = os.WriteFile(composeDir+"/data/"+itemName, input, 0640); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
@@ -47,6 +47,8 @@ type IContainerService interface {
|
|||||||
CreateNetwork(req dto.NetworkCreat) error
|
CreateNetwork(req dto.NetworkCreat) error
|
||||||
DeleteVolume(req dto.BatchDelete) error
|
DeleteVolume(req dto.BatchDelete) error
|
||||||
CreateVolume(req dto.VolumeCreat) error
|
CreateVolume(req dto.VolumeCreat) error
|
||||||
|
TestCompose(req dto.ComposeCreate) (bool, error)
|
||||||
|
ComposeUpdate(req dto.ComposeUpdate) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIContainerService() IContainerService {
|
func NewIContainerService() IContainerService {
|
||||||
@@ -96,27 +98,45 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
|
|||||||
records = list[start:end]
|
records = list[start:end]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(len(records))
|
||||||
for _, container := range records {
|
for _, container := range records {
|
||||||
IsFromCompose := false
|
go func(item types.Container) {
|
||||||
if _, ok := container.Labels[composeProjectLabel]; ok {
|
IsFromCompose := false
|
||||||
IsFromCompose = true
|
if _, ok := item.Labels[composeProjectLabel]; ok {
|
||||||
}
|
IsFromCompose = true
|
||||||
IsFromApp := false
|
}
|
||||||
if created, ok := container.Labels[composeCreatedBy]; ok && created == "Apps" {
|
IsFromApp := false
|
||||||
IsFromApp = true
|
if created, ok := item.Labels[composeCreatedBy]; ok && created == "Apps" {
|
||||||
}
|
IsFromApp = true
|
||||||
backDatas = append(backDatas, dto.ContainerInfo{
|
}
|
||||||
ContainerID: container.ID,
|
|
||||||
CreateTime: time.Unix(container.Created, 0).Format("2006-01-02 15:04:05"),
|
var ports []string
|
||||||
Name: container.Names[0][1:],
|
for _, port := range item.Ports {
|
||||||
ImageId: strings.Split(container.ImageID, ":")[1],
|
if port.IP == "::" || port.PublicPort == 0 {
|
||||||
ImageName: container.Image,
|
continue
|
||||||
State: container.State,
|
}
|
||||||
RunTime: container.Status,
|
ports = append(ports, fmt.Sprintf("%v:%v/%s", port.PublicPort, port.PrivatePort, port.Type))
|
||||||
IsFromApp: IsFromApp,
|
}
|
||||||
IsFromCompose: IsFromCompose,
|
cpu, mem := loadCpuAndMem(client, item.ID)
|
||||||
})
|
backDatas = append(backDatas, dto.ContainerInfo{
|
||||||
|
ContainerID: item.ID,
|
||||||
|
CreateTime: time.Unix(item.Created, 0).Format("2006-01-02 15:04:05"),
|
||||||
|
Name: item.Names[0][1:],
|
||||||
|
ImageId: strings.Split(item.ImageID, ":")[1],
|
||||||
|
ImageName: item.Image,
|
||||||
|
State: item.State,
|
||||||
|
RunTime: item.Status,
|
||||||
|
CPUPercent: cpu,
|
||||||
|
MemoryPercent: mem,
|
||||||
|
Ports: ports,
|
||||||
|
IsFromApp: IsFromApp,
|
||||||
|
IsFromCompose: IsFromCompose,
|
||||||
|
})
|
||||||
|
wg.Done()
|
||||||
|
}(container)
|
||||||
}
|
}
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
return int64(total), backDatas, nil
|
return int64(total), backDatas, nil
|
||||||
}
|
}
|
||||||
@@ -146,24 +166,27 @@ func (u *ContainerService) Inspect(req dto.InspectReq) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *ContainerService) ContainerCreate(req dto.ContainerCreate) error {
|
func (u *ContainerService) ContainerCreate(req dto.ContainerCreate) error {
|
||||||
if len(req.ExposedPorts) != 0 {
|
portMap, err := checkPortStats(req.ExposedPorts)
|
||||||
for _, port := range req.ExposedPorts {
|
if err != nil {
|
||||||
if common.ScanPort(port.HostPort) {
|
return err
|
||||||
return buserr.WithDetail(constant.ErrPortInUsed, port.HostPort, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
client, err := docker.NewDockerClient()
|
client, err := docker.NewDockerClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exposeds := make(nat.PortSet)
|
||||||
|
for port := range portMap {
|
||||||
|
exposeds[port] = struct{}{}
|
||||||
|
}
|
||||||
config := &container.Config{
|
config := &container.Config{
|
||||||
Image: req.Image,
|
Image: req.Image,
|
||||||
Cmd: req.Cmd,
|
Cmd: req.Cmd,
|
||||||
Env: req.Env,
|
Env: req.Env,
|
||||||
Labels: stringsToMap(req.Labels),
|
Labels: stringsToMap(req.Labels),
|
||||||
Tty: true,
|
Tty: true,
|
||||||
OpenStdin: true,
|
OpenStdin: true,
|
||||||
|
ExposedPorts: exposeds,
|
||||||
}
|
}
|
||||||
hostConf := &container.HostConfig{
|
hostConf := &container.HostConfig{
|
||||||
AutoRemove: req.AutoRemove,
|
AutoRemove: req.AutoRemove,
|
||||||
@@ -180,11 +203,7 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerCreate) error {
|
|||||||
hostConf.Memory = req.Memory
|
hostConf.Memory = req.Memory
|
||||||
}
|
}
|
||||||
if len(req.ExposedPorts) != 0 {
|
if len(req.ExposedPorts) != 0 {
|
||||||
hostConf.PortBindings = make(nat.PortMap)
|
hostConf.PortBindings = portMap
|
||||||
for _, port := range req.ExposedPorts {
|
|
||||||
bindItem := nat.PortBinding{HostPort: strconv.Itoa(port.HostPort)}
|
|
||||||
hostConf.PortBindings[nat.Port(fmt.Sprintf("%d/tcp", port.ContainerPort))] = []nat.PortBinding{bindItem}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if len(req.Volumes) != 0 {
|
if len(req.Volumes) != 0 {
|
||||||
config.Volumes = make(map[string]struct{})
|
config.Volumes = make(map[string]struct{})
|
||||||
@@ -197,8 +216,10 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerCreate) error {
|
|||||||
global.LOG.Infof("new container info %s has been made, now start to create", req.Name)
|
global.LOG.Infof("new container info %s has been made, now start to create", req.Name)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
if err := pullImages(ctx, client, req.Image); err != nil {
|
if !checkImageExist(client, req.Image) {
|
||||||
return err
|
if err := pullImages(ctx, client, req.Image); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
container, err := client.ContainerCreate(ctx, config, hostConf, &network.NetworkingConfig{}, &v1.Platform{}, req.Name)
|
container, err := client.ContainerCreate(ctx, config, hostConf, &network.NetworkingConfig{}, &v1.Platform{}, req.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -225,9 +246,9 @@ func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error
|
|||||||
case constant.ContainerOpStart:
|
case constant.ContainerOpStart:
|
||||||
err = client.ContainerStart(ctx, req.Name, types.ContainerStartOptions{})
|
err = client.ContainerStart(ctx, req.Name, types.ContainerStartOptions{})
|
||||||
case constant.ContainerOpStop:
|
case constant.ContainerOpStop:
|
||||||
err = client.ContainerStop(ctx, req.Name, nil)
|
err = client.ContainerStop(ctx, req.Name, container.StopOptions{})
|
||||||
case constant.ContainerOpRestart:
|
case constant.ContainerOpRestart:
|
||||||
err = client.ContainerRestart(ctx, req.Name, nil)
|
err = client.ContainerRestart(ctx, req.Name, container.StopOptions{})
|
||||||
case constant.ContainerOpKill:
|
case constant.ContainerOpKill:
|
||||||
err = client.ContainerKill(ctx, req.Name, "SIGKILL")
|
err = client.ContainerKill(ctx, req.Name, "SIGKILL")
|
||||||
case constant.ContainerOpPause:
|
case constant.ContainerOpPause:
|
||||||
@@ -265,18 +286,18 @@ func (u *ContainerService) ContainerStats(id string) (*dto.ContainterStats, erro
|
|||||||
}
|
}
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(res.Body)
|
body, err := io.ReadAll(res.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
res.Body.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
res.Body.Close()
|
||||||
var stats *types.StatsJSON
|
var stats *types.StatsJSON
|
||||||
if err := json.Unmarshal(body, &stats); err != nil {
|
if err := json.Unmarshal(body, &stats); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var data dto.ContainterStats
|
var data dto.ContainterStats
|
||||||
previousCPU := stats.PreCPUStats.CPUUsage.TotalUsage
|
data.CPUPercent = calculateCPUPercentUnix(stats)
|
||||||
previousSystem := stats.PreCPUStats.SystemUsage
|
|
||||||
data.CPUPercent = calculateCPUPercentUnix(previousCPU, previousSystem, stats)
|
|
||||||
data.IORead, data.IOWrite = calculateBlockIO(stats.BlkioStats)
|
data.IORead, data.IOWrite = calculateBlockIO(stats.BlkioStats)
|
||||||
data.Memory = float64(stats.MemoryStats.Usage) / 1024 / 1024
|
data.Memory = float64(stats.MemoryStats.Usage) / 1024 / 1024
|
||||||
if cache, ok := stats.MemoryStats.Stats["cache"]; ok {
|
if cache, ok := stats.MemoryStats.Stats["cache"]; ok {
|
||||||
@@ -291,25 +312,36 @@ func (u *ContainerService) ContainerStats(id string) (*dto.ContainterStats, erro
|
|||||||
func stringsToMap(list []string) map[string]string {
|
func stringsToMap(list []string) map[string]string {
|
||||||
var lableMap = make(map[string]string)
|
var lableMap = make(map[string]string)
|
||||||
for _, label := range list {
|
for _, label := range list {
|
||||||
sps := strings.Split(label, "=")
|
if strings.Contains(label, "=") {
|
||||||
if len(sps) > 1 {
|
sps := strings.SplitN(label, "=", 2)
|
||||||
lableMap[sps[0]] = sps[1]
|
lableMap[sps[0]] = sps[1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return lableMap
|
return lableMap
|
||||||
}
|
}
|
||||||
func calculateCPUPercentUnix(previousCPU, previousSystem uint64, v *types.StatsJSON) float64 {
|
|
||||||
var (
|
func calculateCPUPercentUnix(stats *types.StatsJSON) float64 {
|
||||||
cpuPercent = 0.0
|
cpuPercent := 0.0
|
||||||
cpuDelta = float64(v.CPUStats.CPUUsage.TotalUsage) - float64(previousCPU)
|
cpuDelta := float64(stats.CPUStats.CPUUsage.TotalUsage) - float64(stats.PreCPUStats.CPUUsage.TotalUsage)
|
||||||
systemDelta = float64(v.CPUStats.SystemUsage) - float64(previousSystem)
|
systemDelta := float64(stats.CPUStats.SystemUsage) - float64(stats.PreCPUStats.SystemUsage)
|
||||||
)
|
|
||||||
|
|
||||||
if systemDelta > 0.0 && cpuDelta > 0.0 {
|
if systemDelta > 0.0 && cpuDelta > 0.0 {
|
||||||
cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CPUStats.CPUUsage.PercpuUsage)) * 100.0
|
cpuPercent = (cpuDelta / systemDelta) * 100.0
|
||||||
|
if len(stats.CPUStats.CPUUsage.PercpuUsage) != 0 {
|
||||||
|
cpuPercent = cpuPercent * float64(len(stats.CPUStats.CPUUsage.PercpuUsage))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return cpuPercent
|
return cpuPercent
|
||||||
}
|
}
|
||||||
|
func calculateMemPercentUnix(memStats types.MemoryStats) float64 {
|
||||||
|
memPercent := 0.0
|
||||||
|
memUsage := float64(memStats.Usage - memStats.Stats["cache"])
|
||||||
|
memLimit := float64(memStats.Limit)
|
||||||
|
if memUsage > 0.0 && memLimit > 0.0 {
|
||||||
|
memPercent = (memUsage / memLimit) * 100.0
|
||||||
|
}
|
||||||
|
return memPercent
|
||||||
|
}
|
||||||
func calculateBlockIO(blkio types.BlkioStats) (blkRead float64, blkWrite float64) {
|
func calculateBlockIO(blkio types.BlkioStats) (blkRead float64, blkWrite float64) {
|
||||||
for _, bioEntry := range blkio.IoServiceBytesRecursive {
|
for _, bioEntry := range blkio.IoServiceBytesRecursive {
|
||||||
switch strings.ToLower(bioEntry.Op) {
|
switch strings.ToLower(bioEntry.Op) {
|
||||||
@@ -331,15 +363,100 @@ func calculateNetwork(network map[string]types.NetworkStats) (float64, float64)
|
|||||||
return rx, tx
|
return rx, tx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkImageExist(client *client.Client, image string) bool {
|
||||||
|
images, err := client.ImageList(context.Background(), types.ImageListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, img := range images {
|
||||||
|
for _, tag := range img.RepoTags {
|
||||||
|
if tag == image || tag == image+":latest" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func pullImages(ctx context.Context, client *client.Client, image string) error {
|
func pullImages(ctx context.Context, client *client.Client, image string) error {
|
||||||
out, err := client.ImagePull(ctx, image, types.ImagePullOptions{})
|
out, err := client.ImagePull(ctx, image, types.ImagePullOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer out.Close()
|
defer out.Close()
|
||||||
_, err = io.Copy(ioutil.Discard, out)
|
_, err = io.Copy(io.Discard, out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadCpuAndMem(client *client.Client, container string) (float64, float64) {
|
||||||
|
res, err := client.ContainerStats(context.Background(), container, false)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
res.Body.Close()
|
||||||
|
return 0, 0
|
||||||
|
}
|
||||||
|
res.Body.Close()
|
||||||
|
var stats *types.StatsJSON
|
||||||
|
if err := json.Unmarshal(body, &stats); err != nil {
|
||||||
|
return 0, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
CPUPercent := calculateCPUPercentUnix(stats)
|
||||||
|
MemPercent := calculateMemPercentUnix(stats.MemoryStats)
|
||||||
|
return CPUPercent, MemPercent
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkPortStats(ports []dto.PortHelper) (nat.PortMap, error) {
|
||||||
|
portMap := make(nat.PortMap)
|
||||||
|
if len(ports) == 0 {
|
||||||
|
return portMap, nil
|
||||||
|
}
|
||||||
|
for _, port := range ports {
|
||||||
|
if strings.Contains(port.ContainerPort, "-") {
|
||||||
|
if !strings.Contains(port.HostPort, "-") {
|
||||||
|
return portMap, buserr.New(constant.ErrPortRules)
|
||||||
|
}
|
||||||
|
hostStart, _ := strconv.Atoi(strings.Split(port.HostPort, "-")[0])
|
||||||
|
hostEnd, _ := strconv.Atoi(strings.Split(port.HostPort, "-")[1])
|
||||||
|
containerStart, _ := strconv.Atoi(strings.Split(port.ContainerPort, "-")[0])
|
||||||
|
containerEnd, _ := strconv.Atoi(strings.Split(port.ContainerPort, "-")[1])
|
||||||
|
if (hostEnd-hostStart) <= 0 || (containerEnd-containerStart) <= 0 {
|
||||||
|
return portMap, buserr.New(constant.ErrPortRules)
|
||||||
|
}
|
||||||
|
if (containerEnd - containerStart) != (hostEnd - hostStart) {
|
||||||
|
return portMap, buserr.New(constant.ErrPortRules)
|
||||||
|
}
|
||||||
|
for i := 0; i <= hostEnd-hostStart; i++ {
|
||||||
|
bindItem := nat.PortBinding{HostPort: strconv.Itoa(hostStart + i), HostIP: port.HostIP}
|
||||||
|
portMap[nat.Port(fmt.Sprintf("%d/%s", containerStart+i, port.Protocol))] = []nat.PortBinding{bindItem}
|
||||||
|
}
|
||||||
|
for i := hostStart; i <= hostEnd; i++ {
|
||||||
|
if common.ScanPort(i) {
|
||||||
|
return portMap, buserr.WithDetail(constant.ErrPortInUsed, i, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
portItem := 0
|
||||||
|
if strings.Contains(port.HostPort, "-") {
|
||||||
|
portItem, _ = strconv.Atoi(strings.Split(port.HostPort, "-")[0])
|
||||||
|
} else {
|
||||||
|
portItem, _ = strconv.Atoi(port.HostPort)
|
||||||
|
}
|
||||||
|
if common.ScanPort(portItem) {
|
||||||
|
return portMap, buserr.WithDetail(constant.ErrPortInUsed, portItem, nil)
|
||||||
|
}
|
||||||
|
bindItem := nat.PortBinding{HostPort: strconv.Itoa(portItem), HostIP: port.HostIP}
|
||||||
|
portMap[nat.Port(fmt.Sprintf("%s/%s", port.ContainerPort, port.Protocol))] = []nat.PortBinding{bindItem}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return portMap, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
@@ -154,9 +155,10 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) (string, error)
|
|||||||
go func() {
|
go func() {
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
cmd := exec.Command("docker-compose", "-f", req.Path, "up", "-d")
|
cmd := exec.Command("docker-compose", "-f", req.Path, "up", "-d")
|
||||||
stdout, err := cmd.CombinedOutput()
|
multiWriter := io.MultiWriter(os.Stdout, file)
|
||||||
_, _ = file.Write(stdout)
|
cmd.Stdout = multiWriter
|
||||||
if err != nil {
|
cmd.Stderr = multiWriter
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
global.LOG.Errorf("docker-compose up %s failed, err: %v", req.Name, err)
|
global.LOG.Errorf("docker-compose up %s failed, err: %v", req.Name, err)
|
||||||
_, _ = compose.Down(req.Path)
|
_, _ = compose.Down(req.Path)
|
||||||
_, _ = file.WriteString("docker-compose up failed!")
|
_, _ = file.WriteString("docker-compose up failed!")
|
||||||
@@ -180,7 +182,9 @@ func (u *ContainerService) ComposeOperation(req dto.ComposeOperation) error {
|
|||||||
global.LOG.Infof("docker-compose %s %s successful", req.Operation, req.Name)
|
global.LOG.Infof("docker-compose %s %s successful", req.Operation, req.Name)
|
||||||
if req.Operation == "down" {
|
if req.Operation == "down" {
|
||||||
_ = composeRepo.DeleteRecord(commonRepo.WithByName(req.Name))
|
_ = composeRepo.DeleteRecord(commonRepo.WithByName(req.Name))
|
||||||
_ = os.RemoveAll(strings.ReplaceAll(req.Path, "/docker-compose.yml", ""))
|
if req.WithFile {
|
||||||
|
_ = os.RemoveAll(path.Dir(req.Path))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -211,15 +215,7 @@ func (u *ContainerService) ComposeUpdate(req dto.ComposeUpdate) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *ContainerService) loadPath(req *dto.ComposeCreate) error {
|
func (u *ContainerService) loadPath(req *dto.ComposeCreate) error {
|
||||||
if req.From == "template" {
|
if req.From == "template" || req.From == "edit" {
|
||||||
template, err := composeRepo.Get(commonRepo.WithByID(req.Template))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
req.From = "edit"
|
|
||||||
req.File = template.Content
|
|
||||||
}
|
|
||||||
if req.From == "edit" {
|
|
||||||
dir := fmt.Sprintf("%s/docker/compose/%s", constant.DataDir, req.Name)
|
dir := fmt.Sprintf("%s/docker/compose/%s", constant.DataDir, req.Name)
|
||||||
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
||||||
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
|
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||||
"github.com/docker/docker/api/types"
|
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/volume"
|
"github.com/docker/docker/api/types/volume"
|
||||||
)
|
)
|
||||||
@@ -37,14 +36,14 @@ func (u *ContainerService) PageVolume(req dto.SearchWithPage) (int64, interface{
|
|||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
data []dto.Volume
|
data []dto.Volume
|
||||||
records []*types.Volume
|
records []*volume.Volume
|
||||||
)
|
)
|
||||||
sort.Slice(list.Volumes, func(i, j int) bool {
|
sort.Slice(list.Volumes, func(i, j int) bool {
|
||||||
return list.Volumes[i].CreatedAt > list.Volumes[j].CreatedAt
|
return list.Volumes[i].CreatedAt > list.Volumes[j].CreatedAt
|
||||||
})
|
})
|
||||||
total, start, end := len(list.Volumes), (req.Page-1)*req.PageSize, req.Page*req.PageSize
|
total, start, end := len(list.Volumes), (req.Page-1)*req.PageSize, req.Page*req.PageSize
|
||||||
if start > total {
|
if start > total {
|
||||||
records = make([]*types.Volume, 0)
|
records = make([]*volume.Volume, 0)
|
||||||
} else {
|
} else {
|
||||||
if end >= total {
|
if end >= total {
|
||||||
end = total
|
end = total
|
||||||
@@ -119,7 +118,7 @@ func (u *ContainerService) CreateVolume(req dto.VolumeCreat) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
options := volume.VolumeCreateBody{
|
options := volume.CreateOptions{
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
Driver: req.Driver,
|
Driver: req.Driver,
|
||||||
DriverOpts: stringsToMap(req.Options),
|
DriverOpts: stringsToMap(req.Options),
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
@@ -24,7 +25,10 @@ type ICronjobService interface {
|
|||||||
HandleOnce(id uint) error
|
HandleOnce(id uint) error
|
||||||
Update(id uint, req dto.CronjobUpdate) error
|
Update(id uint, req dto.CronjobUpdate) error
|
||||||
UpdateStatus(id uint, status string) error
|
UpdateStatus(id uint, status string) error
|
||||||
Delete(ids []uint) error
|
Delete(req dto.CronjobBatchDelete) error
|
||||||
|
Download(down dto.CronjobDownload) (string, error)
|
||||||
|
StartJob(cronjob *model.Cronjob) (int, error)
|
||||||
|
CleanRecord(req dto.CronjobClean) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewICronjobService() ICronjobService {
|
func NewICronjobService() ICronjobService {
|
||||||
@@ -76,6 +80,44 @@ func (u *CronjobService) SearchRecords(search dto.SearchRecord) (int64, interfac
|
|||||||
return total, dtoCronjobs, err
|
return total, dtoCronjobs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *CronjobService) CleanRecord(req dto.CronjobClean) error {
|
||||||
|
cronjob, err := cronjobRepo.Get(commonRepo.WithByID(req.CronjobID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if req.CleanData && cronjob.Type != "shell" && cronjob.Type != "curl" {
|
||||||
|
cronjob.RetainCopies = 0
|
||||||
|
backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if backup.Type != "LOCAL" {
|
||||||
|
localDir, err := loadLocalDir()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
client, err := NewIBackupService().NewClient(&backup)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
u.HandleRmExpired(backup.Type, localDir, &cronjob, client)
|
||||||
|
} else {
|
||||||
|
u.HandleRmExpired(backup.Type, "", &cronjob, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delRecords, err := cronjobRepo.ListRecord(cronjobRepo.WithByJobID(int(req.CronjobID)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, del := range delRecords {
|
||||||
|
_ = os.RemoveAll(del.Records)
|
||||||
|
}
|
||||||
|
if err := cronjobRepo.DeleteRecord(cronjobRepo.WithByJobID(int(req.CronjobID))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (u *CronjobService) Download(down dto.CronjobDownload) (string, error) {
|
func (u *CronjobService) Download(down dto.CronjobDownload) (string, error) {
|
||||||
record, _ := cronjobRepo.GetRecord(commonRepo.WithByID(down.RecordID))
|
record, _ := cronjobRepo.GetRecord(commonRepo.WithByID(down.RecordID))
|
||||||
if record.ID == 0 {
|
if record.ID == 0 {
|
||||||
@@ -89,24 +131,19 @@ func (u *CronjobService) Download(down dto.CronjobDownload) (string, error) {
|
|||||||
if cronjob.ID == 0 {
|
if cronjob.ID == 0 {
|
||||||
return "", constant.ErrRecordNotFound
|
return "", constant.ErrRecordNotFound
|
||||||
}
|
}
|
||||||
if backup.Type == "LOCAL" {
|
if backup.Type == "LOCAL" || record.FromLocal {
|
||||||
if _, err := os.Stat(record.File); err != nil && os.IsNotExist(err) {
|
if _, err := os.Stat(record.File); err != nil && os.IsNotExist(err) {
|
||||||
return "", constant.ErrRecordNotFound
|
return "", constant.ErrRecordNotFound
|
||||||
}
|
}
|
||||||
return record.File, nil
|
return record.File, nil
|
||||||
}
|
}
|
||||||
if record.FromLocal {
|
|
||||||
local, _ := loadLocalDir()
|
|
||||||
if _, err := os.Stat(local + "/" + record.File); err == nil {
|
|
||||||
return local + "/" + record.File, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
client, err := NewIBackupService().NewClient(&backup)
|
client, err := NewIBackupService().NewClient(&backup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
tempPath := fmt.Sprintf("%s/download/%s", constant.DataDir, record.File)
|
tempPath := fmt.Sprintf("%s/download/%s", constant.DataDir, record.File)
|
||||||
isOK, _ := client.Download(record.File, tempPath)
|
_ = os.MkdirAll(path.Dir(tempPath), os.ModePerm)
|
||||||
|
isOK, err := client.Download(record.File, tempPath)
|
||||||
if !isOK || err != nil {
|
if !isOK || err != nil {
|
||||||
return "", constant.ErrRecordNotFound
|
return "", constant.ErrRecordNotFound
|
||||||
}
|
}
|
||||||
@@ -157,21 +194,23 @@ func (u *CronjobService) StartJob(cronjob *model.Cronjob) (int, error) {
|
|||||||
return entryID, nil
|
return entryID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *CronjobService) Delete(ids []uint) error {
|
func (u *CronjobService) Delete(req dto.CronjobBatchDelete) error {
|
||||||
if len(ids) == 1 {
|
for _, id := range req.IDs {
|
||||||
if err := u.HandleDelete(ids[0]); err != nil {
|
cronjob, _ := cronjobRepo.Get(commonRepo.WithByID(id))
|
||||||
|
if cronjob.ID == 0 {
|
||||||
|
return errors.New("find cronjob in db failed")
|
||||||
|
}
|
||||||
|
global.Cron.Remove(cron.EntryID(cronjob.EntryID))
|
||||||
|
global.LOG.Infof("stop cronjob entryID: %d", cronjob.EntryID)
|
||||||
|
if err := u.CleanRecord(dto.CronjobClean{CronjobID: id, CleanData: req.CleanData}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := cronjobRepo.Delete(commonRepo.WithByID(id)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return cronjobRepo.Delete(commonRepo.WithByID(ids[0]))
|
|
||||||
}
|
}
|
||||||
cronjobs, err := cronjobRepo.List(commonRepo.WithIdsIn(ids))
|
|
||||||
if err != nil {
|
return nil
|
||||||
return err
|
|
||||||
}
|
|
||||||
for i := range cronjobs {
|
|
||||||
_ = u.HandleDelete(ids[i])
|
|
||||||
}
|
|
||||||
return cronjobRepo.Delete(commonRepo.WithIdsIn(ids))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
|
func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
|
||||||
|
|||||||
@@ -3,18 +3,18 @@ package service
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/cloud_storage"
|
"github.com/1Panel-dev/1Panel/backend/utils/cloud_storage"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/robfig/cron/v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
||||||
@@ -29,11 +29,12 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
|||||||
if len(cronjob.Script) == 0 {
|
if len(cronjob.Script) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
stdout, errExec := cmd.Exec(cronjob.Script)
|
stdout, errExec := cmd.ExecCronjobWithTimeOut(cronjob.Script, 5*time.Minute)
|
||||||
if errExec != nil {
|
if errExec != nil {
|
||||||
err = errExec
|
err = errExec
|
||||||
}
|
}
|
||||||
message = []byte(stdout)
|
message = []byte(stdout)
|
||||||
|
u.HandleRmExpired("LOCAL", "", cronjob, nil)
|
||||||
case "website":
|
case "website":
|
||||||
record.File, err = u.HandleBackup(cronjob, record.StartTime)
|
record.File, err = u.HandleBackup(cronjob, record.StartTime)
|
||||||
case "database":
|
case "database":
|
||||||
@@ -47,11 +48,12 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
|||||||
if len(cronjob.URL) == 0 {
|
if len(cronjob.URL) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
stdout, errCurl := cmd.Exec("curl " + cronjob.URL)
|
stdout, errCurl := cmd.ExecWithTimeOut("curl "+cronjob.URL, 5*time.Minute)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errCurl
|
err = errCurl
|
||||||
}
|
}
|
||||||
message = []byte(stdout)
|
message = []byte(stdout)
|
||||||
|
u.HandleRmExpired("LOCAL", "", cronjob, nil)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), string(message))
|
cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), string(message))
|
||||||
@@ -68,11 +70,6 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Time) (string, error) {
|
func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Time) (string, error) {
|
||||||
var (
|
|
||||||
backupDir string
|
|
||||||
fileName string
|
|
||||||
record model.BackupRecord
|
|
||||||
)
|
|
||||||
backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID)))
|
backup, err := backupRepo.Get(commonRepo.WithByID(uint(cronjob.TargetDirID)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -89,144 +86,60 @@ func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Tim
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
fileName = fmt.Sprintf("db_%s_%s.sql.gz", cronjob.DBName, startTime.Format("20060102150405"))
|
paths, err := u.handleDatabase(*cronjob, app, backup, startTime)
|
||||||
backupDir = fmt.Sprintf("%s/database/mysql/%s/%s", localDir, app.Name, cronjob.DBName)
|
return strings.Join(paths, ","), err
|
||||||
if err = handleMysqlBackup(app, backupDir, cronjob.DBName, fileName); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
record.Type = "mysql"
|
|
||||||
record.Name = app.Name
|
|
||||||
record.DetailName = cronjob.DBName
|
|
||||||
case "website":
|
case "website":
|
||||||
fileName = fmt.Sprintf("website_%s_%s.tar.gz", cronjob.Website, startTime.Format("20060102150405"))
|
paths, err := u.handleWebsite(*cronjob, backup, startTime)
|
||||||
backupDir = fmt.Sprintf("%s/website/%s", localDir, cronjob.Website)
|
return strings.Join(paths, ","), err
|
||||||
website, err := websiteRepo.GetFirst(websiteRepo.WithDomain(cronjob.Website))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if err := handleWebsiteBackup(&website, backupDir, fileName); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
record.Type = "website"
|
|
||||||
record.Name = website.PrimaryDomain
|
|
||||||
default:
|
default:
|
||||||
fileName = fmt.Sprintf("directory%s_%s.tar.gz", strings.ReplaceAll(cronjob.SourceDir, "/", "_"), startTime.Format("20060102150405"))
|
fileName := fmt.Sprintf("directory%s_%s.tar.gz", strings.ReplaceAll(cronjob.SourceDir, "/", "_"), startTime.Format("20060102150405"))
|
||||||
backupDir = fmt.Sprintf("%s/%s/%s", localDir, cronjob.Type, cronjob.Name)
|
backupDir := fmt.Sprintf("%s/%s/%s", localDir, cronjob.Type, cronjob.Name)
|
||||||
|
itemFileDir := fmt.Sprintf("%s/%s", cronjob.Type, cronjob.Name)
|
||||||
global.LOG.Infof("handle tar %s to %s", backupDir, fileName)
|
global.LOG.Infof("handle tar %s to %s", backupDir, fileName)
|
||||||
if err := handleTar(cronjob.SourceDir, backupDir, fileName, cronjob.ExclusionRules); err != nil {
|
if err := handleTar(cronjob.SourceDir, backupDir, fileName, cronjob.ExclusionRules); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
}
|
var client cloud_storage.CloudStorageClient
|
||||||
|
if backup.Type != "LOCAL" {
|
||||||
itemFileDir := strings.ReplaceAll(backupDir, localDir+"/", "")
|
if !cronjob.KeepLocal {
|
||||||
if len(record.Name) != 0 {
|
defer func() {
|
||||||
record.FileName = fileName
|
_ = os.RemoveAll(fmt.Sprintf("%s/%s", backupDir, fileName))
|
||||||
record.FileDir = backupDir
|
}()
|
||||||
record.Source = "LOCAL"
|
}
|
||||||
record.BackupType = backup.Type
|
client, err = NewIBackupService().NewClient(&backup)
|
||||||
if !cronjob.KeepLocal && backup.Type != "LOCAL" {
|
if err != nil {
|
||||||
record.Source = backup.Type
|
return "", err
|
||||||
record.FileDir = itemFileDir
|
}
|
||||||
}
|
if _, err = client.Upload(backupDir+"/"+fileName, itemFileDir+"/"+fileName); err != nil {
|
||||||
if err := backupRepo.CreateRecord(&record); err != nil {
|
return "", err
|
||||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fullPath := fmt.Sprintf("%s/%s", backupDir, fileName)
|
|
||||||
if backup.Type != "LOCAL" {
|
|
||||||
fullPath = fmt.Sprintf("%s/%s", itemFileDir, fileName)
|
|
||||||
}
|
|
||||||
if backup.Type == "LOCAL" {
|
|
||||||
u.HandleRmExpired(backup.Type, backupDir, cronjob, nil)
|
|
||||||
return fullPath, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if !cronjob.KeepLocal {
|
|
||||||
defer func() {
|
|
||||||
_ = os.RemoveAll(fmt.Sprintf("%s/%s", backupDir, fileName))
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
client, err := NewIBackupService().NewClient(&backup)
|
|
||||||
if err != nil {
|
|
||||||
return fullPath, err
|
|
||||||
}
|
|
||||||
if _, err = client.Upload(backupDir+"/"+fileName, itemFileDir+"/"+fileName); err != nil {
|
|
||||||
return fullPath, err
|
|
||||||
}
|
|
||||||
u.HandleRmExpired(backup.Type, itemFileDir, cronjob, client)
|
|
||||||
if cronjob.KeepLocal {
|
|
||||||
u.HandleRmExpired("LOCAL", backupDir, cronjob, client)
|
|
||||||
}
|
|
||||||
return fullPath, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *CronjobService) HandleDelete(id uint) error {
|
|
||||||
cronjob, _ := cronjobRepo.Get(commonRepo.WithByID(id))
|
|
||||||
if cronjob.ID == 0 {
|
|
||||||
return errors.New("find cronjob in db failed")
|
|
||||||
}
|
|
||||||
commonDir := fmt.Sprintf("%s/%s/", cronjob.Type, cronjob.Name)
|
|
||||||
global.Cron.Remove(cron.EntryID(cronjob.EntryID))
|
|
||||||
global.LOG.Infof("stop cronjob entryID: %d", cronjob.EntryID)
|
|
||||||
_ = cronjobRepo.DeleteRecord(cronjobRepo.WithByJobID(int(id)))
|
|
||||||
|
|
||||||
dir := fmt.Sprintf("%s/task/%s/%s", constant.DataDir, cronjob.Type, cronjob.Name)
|
|
||||||
if _, err := os.Stat(dir); err == nil {
|
|
||||||
if err := os.RemoveAll(dir); err != nil {
|
|
||||||
global.LOG.Errorf("rm file %s/task/%s failed, err: %v", constant.DataDir, commonDir, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *CronjobService) HandleRmExpired(backType, backupDir string, cronjob *model.Cronjob, backClient cloud_storage.CloudStorageClient) {
|
|
||||||
global.LOG.Infof("start to handle remove expired, retain copies: %d", cronjob.RetainCopies)
|
|
||||||
if backType != "LOCAL" {
|
|
||||||
currentObjs, err := backClient.ListObjects(backupDir + "/")
|
|
||||||
if err != nil {
|
|
||||||
global.LOG.Errorf("list bucket object %s failed, err: %v", backupDir, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := 0; i < len(currentObjs)-int(cronjob.RetainCopies); i++ {
|
|
||||||
_, _ = backClient.Delete(currentObjs[i].(string))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
files, err := ioutil.ReadDir(backupDir)
|
|
||||||
if err != nil {
|
|
||||||
global.LOG.Errorf("read dir %s failed, err: %v", backupDir, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(files) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
prefix := ""
|
|
||||||
switch cronjob.Type {
|
|
||||||
case "database":
|
|
||||||
prefix = "db_"
|
|
||||||
case "website":
|
|
||||||
prefix = "website_"
|
|
||||||
case "directory":
|
|
||||||
prefix = "directory_"
|
|
||||||
}
|
|
||||||
|
|
||||||
dbCopies := uint64(0)
|
|
||||||
for i := len(files) - 1; i >= 0; i-- {
|
|
||||||
if strings.HasPrefix(files[i].Name(), prefix) {
|
|
||||||
dbCopies++
|
|
||||||
if dbCopies > cronjob.RetainCopies {
|
|
||||||
_ = os.Remove(backupDir + "/" + files[i].Name())
|
|
||||||
_ = backupRepo.DeleteRecord(context.Background(), backupRepo.WithByFileName(files[i].Name()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
u.HandleRmExpired(backup.Type, localDir, cronjob, client)
|
||||||
|
if backup.Type == "LOCAL" || cronjob.KeepLocal {
|
||||||
|
return fmt.Sprintf("%s/%s/%s/%s", localDir, cronjob.Type, cronjob.Name, fileName), nil
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s/%s/%s", cronjob.Type, cronjob.Name, fileName), nil
|
||||||
}
|
}
|
||||||
records, _ := cronjobRepo.ListRecord(cronjobRepo.WithByJobID(int(cronjob.ID)))
|
}
|
||||||
|
|
||||||
|
func (u *CronjobService) HandleRmExpired(backType, localDir string, cronjob *model.Cronjob, backClient cloud_storage.CloudStorageClient) {
|
||||||
|
global.LOG.Infof("start to handle remove expired, retain copies: %d", cronjob.RetainCopies)
|
||||||
|
records, _ := cronjobRepo.ListRecord(cronjobRepo.WithByJobID(int(cronjob.ID)), commonRepo.WithOrderBy("created_at desc"))
|
||||||
if len(records) > int(cronjob.RetainCopies) {
|
if len(records) > int(cronjob.RetainCopies) {
|
||||||
for i := int(cronjob.RetainCopies); i < len(records); i++ {
|
for i := int(cronjob.RetainCopies); i < len(records); i++ {
|
||||||
_ = cronjobRepo.DeleteRecord(cronjobRepo.WithByJobID(int(records[i].ID)))
|
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)))
|
||||||
|
_ = os.Remove(records[i].Records)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,7 +170,7 @@ func handleTar(sourceDir, targetDir, name, exclusionRules string) error {
|
|||||||
|
|
||||||
commands := fmt.Sprintf("tar zcvf %s %s %s", targetDir+"/"+name, excludeRules, path)
|
commands := fmt.Sprintf("tar zcvf %s %s %s", targetDir+"/"+name, excludeRules, path)
|
||||||
global.LOG.Debug(commands)
|
global.LOG.Debug(commands)
|
||||||
stdout, err := cmd.Exec(commands)
|
stdout, err := cmd.ExecWithTimeOut(commands, 5*time.Minute)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("do handle tar failed, stdout: %s, err: %v", stdout, err)
|
global.LOG.Errorf("do handle tar failed, stdout: %s, err: %v", stdout, err)
|
||||||
return errors.New(stdout)
|
return errors.New(stdout)
|
||||||
@@ -274,10 +187,144 @@ func handleUnTar(sourceFile, targetDir string) error {
|
|||||||
|
|
||||||
commands := fmt.Sprintf("tar zxvfC %s %s", sourceFile, targetDir)
|
commands := fmt.Sprintf("tar zxvfC %s %s", sourceFile, targetDir)
|
||||||
global.LOG.Debug(commands)
|
global.LOG.Debug(commands)
|
||||||
stdout, err := cmd.Exec(commands)
|
stdout, err := cmd.ExecWithTimeOut(commands, 5*time.Minute)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("do handle untar failed, stdout: %s, err: %v", stdout, err)
|
global.LOG.Errorf("do handle untar failed, stdout: %s, err: %v", stdout, err)
|
||||||
return errors.New(stdout)
|
return errors.New(stdout)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *CronjobService) handleDatabase(cronjob model.Cronjob, app *repo.RootInfo, backup model.BackupAccount, startTime time.Time) ([]string, error) {
|
||||||
|
var paths []string
|
||||||
|
localDir, err := loadLocalDir()
|
||||||
|
if err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var dblist []string
|
||||||
|
if cronjob.DBName == "all" {
|
||||||
|
mysqlService := NewIMysqlService()
|
||||||
|
dblist, err = mysqlService.ListDBName()
|
||||||
|
if err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dblist = append(dblist, cronjob.DBName)
|
||||||
|
}
|
||||||
|
|
||||||
|
var client cloud_storage.CloudStorageClient
|
||||||
|
if backup.Type != "LOCAL" {
|
||||||
|
client, err = NewIBackupService().NewClient(&backup)
|
||||||
|
if err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, dbName := range dblist {
|
||||||
|
var record model.BackupRecord
|
||||||
|
|
||||||
|
record.Type = "mysql"
|
||||||
|
record.Name = app.Name
|
||||||
|
record.Source = "LOCAL"
|
||||||
|
record.BackupType = backup.Type
|
||||||
|
|
||||||
|
backupDir := fmt.Sprintf("%s/database/mysql/%s/%s", localDir, app.Name, dbName)
|
||||||
|
record.FileName = fmt.Sprintf("db_%s_%s.sql.gz", dbName, startTime.Format("20060102150405"))
|
||||||
|
if err = handleMysqlBackup(app, backupDir, dbName, record.FileName); err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
record.DetailName = dbName
|
||||||
|
record.FileDir = backupDir
|
||||||
|
itemFileDir := strings.ReplaceAll(backupDir, localDir+"/", "")
|
||||||
|
if !cronjob.KeepLocal && backup.Type != "LOCAL" {
|
||||||
|
record.Source = backup.Type
|
||||||
|
record.FileDir = itemFileDir
|
||||||
|
}
|
||||||
|
paths = append(paths, fmt.Sprintf("%s/%s", record.FileDir, record.FileName))
|
||||||
|
|
||||||
|
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||||
|
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
if backup.Type != "LOCAL" {
|
||||||
|
if !cronjob.KeepLocal {
|
||||||
|
defer func() {
|
||||||
|
_ = os.RemoveAll(fmt.Sprintf("%s/%s", backupDir, record.FileName))
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
if _, err = client.Upload(backupDir+"/"+record.FileName, itemFileDir+"/"+record.FileName); err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
u.HandleRmExpired(backup.Type, localDir, &cronjob, client)
|
||||||
|
return paths, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *CronjobService) handleWebsite(cronjob model.Cronjob, backup model.BackupAccount, startTime time.Time) ([]string, error) {
|
||||||
|
var paths []string
|
||||||
|
localDir, err := loadLocalDir()
|
||||||
|
if err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var weblist []string
|
||||||
|
if cronjob.Website == "all" {
|
||||||
|
weblist, err = NewIWebsiteService().GetWebsiteOptions()
|
||||||
|
if err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
weblist = append(weblist, cronjob.Website)
|
||||||
|
}
|
||||||
|
|
||||||
|
var client cloud_storage.CloudStorageClient
|
||||||
|
if backup.Type != "LOCAL" {
|
||||||
|
client, err = NewIBackupService().NewClient(&backup)
|
||||||
|
if err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, websiteItem := range weblist {
|
||||||
|
var record model.BackupRecord
|
||||||
|
record.Type = "website"
|
||||||
|
record.Name = cronjob.Website
|
||||||
|
record.Source = "LOCAL"
|
||||||
|
record.BackupType = backup.Type
|
||||||
|
website, err := websiteRepo.GetFirst(websiteRepo.WithDomain(websiteItem))
|
||||||
|
if err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
backupDir := fmt.Sprintf("%s/website/%s", localDir, website.PrimaryDomain)
|
||||||
|
record.FileDir = backupDir
|
||||||
|
itemFileDir := strings.ReplaceAll(backupDir, localDir+"/", "")
|
||||||
|
if !cronjob.KeepLocal && backup.Type != "LOCAL" {
|
||||||
|
record.Source = backup.Type
|
||||||
|
record.FileDir = strings.ReplaceAll(backupDir, localDir+"/", "")
|
||||||
|
}
|
||||||
|
record.FileName = fmt.Sprintf("website_%s_%s.tar.gz", website.PrimaryDomain, startTime.Format("20060102150405"))
|
||||||
|
paths = append(paths, fmt.Sprintf("%s/%s", record.FileDir, record.FileName))
|
||||||
|
if err := handleWebsiteBackup(&website, backupDir, record.FileName); err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
record.Name = website.PrimaryDomain
|
||||||
|
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||||
|
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
if backup.Type != "LOCAL" {
|
||||||
|
if !cronjob.KeepLocal {
|
||||||
|
defer func() {
|
||||||
|
_ = os.RemoveAll(fmt.Sprintf("%s/%s", backupDir, record.FileName))
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
if _, err = client.Upload(backupDir+"/"+record.FileName, itemFileDir+"/"+record.FileName); err != nil {
|
||||||
|
return paths, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
u.HandleRmExpired(backup.Type, localDir, &cronjob, client)
|
||||||
|
return paths, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -186,7 +186,10 @@ func loadDiskInfo() []dto.DiskInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(mounts); i++ {
|
for i := 0; i < len(mounts); i++ {
|
||||||
state, _ := disk.Usage(mounts[i].Mount)
|
state, err := disk.Usage(mounts[i].Mount)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
var itemData dto.DiskInfo
|
var itemData dto.DiskInfo
|
||||||
itemData.Path = mounts[i].Mount
|
itemData.Path = mounts[i].Mount
|
||||||
itemData.Type = mounts[i].Type
|
itemData.Type = mounts[i].Type
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"regexp"
|
"regexp"
|
||||||
@@ -94,25 +93,28 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode
|
|||||||
}
|
}
|
||||||
|
|
||||||
createSql := fmt.Sprintf("create database `%s` default character set %s collate %s", req.Name, req.Format, formatMap[req.Format])
|
createSql := fmt.Sprintf("create database `%s` default character set %s collate %s", req.Name, req.Format, formatMap[req.Format])
|
||||||
if err := excuteSql(app.ContainerName, app.Password, createSql); err != nil {
|
if err := excSQL(app.ContainerName, app.Password, createSql); err != nil {
|
||||||
if strings.Contains(err.Error(), "ERROR 1007") {
|
if strings.Contains(err.Error(), "ERROR 1007") {
|
||||||
return nil, buserr.New(constant.ErrDatabaseIsExist)
|
return nil, buserr.New(constant.ErrDatabaseIsExist)
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tmpPermission := req.Permission
|
tmpPermission := req.Permission
|
||||||
if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("create user '%s'@'%s' identified by '%s';", req.Username, tmpPermission, req.Password)); err != nil {
|
if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("create user '%s'@'%s' identified by '%s';", req.Username, tmpPermission, req.Password)); err != nil {
|
||||||
_ = excuteSql(app.ContainerName, app.Password, fmt.Sprintf("drop database `%s`", req.Name))
|
_ = excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop database `%s`", req.Name))
|
||||||
if strings.Contains(err.Error(), "ERROR 1396") {
|
if strings.Contains(err.Error(), "ERROR 1396") {
|
||||||
return nil, buserr.New(constant.ErrUserIsExist)
|
return nil, buserr.New(constant.ErrUserIsExist)
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
grantStr := fmt.Sprintf("grant all privileges on `%s`.* to '%s'@'%s'", req.Name, req.Username, tmpPermission)
|
grantStr := fmt.Sprintf("grant all privileges on `%s`.* to '%s'@'%s'", req.Name, req.Username, tmpPermission)
|
||||||
|
if req.Name == "*" {
|
||||||
|
grantStr = fmt.Sprintf("grant all privileges on *.* to '%s'@'%s'", mysql.Username, tmpPermission)
|
||||||
|
}
|
||||||
if app.Version == "5.7.39" {
|
if app.Version == "5.7.39" {
|
||||||
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, req.Password)
|
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, req.Password)
|
||||||
}
|
}
|
||||||
if err := excuteSql(app.ContainerName, app.Password, grantStr); err != nil {
|
if err := excSQL(app.ContainerName, app.Password, grantStr); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,10 +163,10 @@ func (u *MysqlService) Delete(ctx context.Context, req dto.MysqlDBDelete) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("drop user if exists '%s'@'%s'", db.Username, db.Permission)); err != nil && !req.ForceDelete {
|
if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop user if exists '%s'@'%s'", db.Username, db.Permission)); err != nil && !req.ForceDelete {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("drop database if exists `%s`", db.Name)); err != nil && !req.ForceDelete {
|
if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop database if exists `%s`", db.Name)); err != nil && !req.ForceDelete {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
global.LOG.Info("execute delete database sql successful, now start to drop uploads and records")
|
global.LOG.Info("execute delete database sql successful, now start to drop uploads and records")
|
||||||
@@ -293,6 +295,9 @@ func (u *MysqlService) ChangeAccess(info dto.ChangeDBInfo) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
grantStr := fmt.Sprintf("grant all privileges on `%s`.* to '%s'@'%s'", mysql.Name, mysql.Username, info.Value)
|
grantStr := fmt.Sprintf("grant all privileges on `%s`.* to '%s'@'%s'", mysql.Name, mysql.Username, info.Value)
|
||||||
|
if mysql.Name == "*" {
|
||||||
|
grantStr = fmt.Sprintf("grant all privileges on *.* to '%s'@'%s'", mysql.Username, info.Value)
|
||||||
|
}
|
||||||
if app.Version == "5.7.39" {
|
if app.Version == "5.7.39" {
|
||||||
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, mysql.Password)
|
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, mysql.Password)
|
||||||
}
|
}
|
||||||
@@ -339,7 +344,7 @@ func (u *MysqlService) UpdateVariables(updatas []dto.MysqlVariablesUpdate) error
|
|||||||
var files []string
|
var files []string
|
||||||
|
|
||||||
path := fmt.Sprintf("%s/mysql/%s/conf/my.cnf", constant.AppInstallDir, app.Name)
|
path := fmt.Sprintf("%s/mysql/%s/conf/my.cnf", constant.AppInstallDir, app.Name)
|
||||||
lineBytes, err := ioutil.ReadFile(path)
|
lineBytes, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -509,6 +514,21 @@ func excuteSql(containerName, password, command string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func excSQL(containerName, password, command string) error {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
cmd := exec.CommandContext(ctx, "docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
|
||||||
|
stdout, err := cmd.CombinedOutput()
|
||||||
|
if ctx.Err() == context.DeadlineExceeded {
|
||||||
|
return buserr.WithDetail(constant.ErrExecTimeOut, containerName, nil)
|
||||||
|
}
|
||||||
|
stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
|
||||||
|
if err != nil || strings.HasPrefix(string(stdStr), "ERROR ") {
|
||||||
|
return errors.New(stdStr)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func updateMyCnf(oldFiles []string, group string, param string, value interface{}) []string {
|
func updateMyCnf(oldFiles []string, group string, param string, value interface{}) []string {
|
||||||
isOn := false
|
isOn := false
|
||||||
hasGroup := false
|
hasGroup := false
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -215,7 +214,7 @@ type redisConfig struct {
|
|||||||
|
|
||||||
func confSet(redisName string, changeConf []redisConfig) error {
|
func confSet(redisName string, changeConf []redisConfig) error {
|
||||||
path := fmt.Sprintf("%s/redis/%s/conf/redis.conf", constant.AppInstallDir, redisName)
|
path := fmt.Sprintf("%s/redis/%s/conf/redis.conf", constant.AppInstallDir, redisName)
|
||||||
lineBytes, err := ioutil.ReadFile(path)
|
lineBytes, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -35,6 +34,7 @@ type daemonJsonItem struct {
|
|||||||
Mirrors []string `json:"registry-mirrors"`
|
Mirrors []string `json:"registry-mirrors"`
|
||||||
Registries []string `json:"insecure-registries"`
|
Registries []string `json:"insecure-registries"`
|
||||||
LiveRestore bool `json:"live-restore"`
|
LiveRestore bool `json:"live-restore"`
|
||||||
|
IPTables bool `json:"iptables"`
|
||||||
ExecOpts []string `json:"exec-opts"`
|
ExecOpts []string `json:"exec-opts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,55 +49,60 @@ func (u *DockerService) LoadDockerStatus() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf {
|
func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf {
|
||||||
status := constant.StatusRunning
|
var data dto.DaemonJsonConf
|
||||||
|
data.IPTables = true
|
||||||
|
data.Status = constant.StatusRunning
|
||||||
stdout, err := cmd.Exec("systemctl is-active docker")
|
stdout, err := cmd.Exec("systemctl is-active docker")
|
||||||
if string(stdout) != "active\n" || err != nil {
|
if string(stdout) != "active\n" || err != nil {
|
||||||
status = constant.Stopped
|
data.Status = constant.Stopped
|
||||||
}
|
}
|
||||||
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()
|
client, err := docker.NewDockerClient()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
itemVersion, err := client.ServerVersion(ctx)
|
itemVersion, err := client.ServerVersion(ctx)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
version = itemVersion.Version
|
data.Version = itemVersion.Version
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, err := os.Stat(constant.DaemonJsonPath); err != nil {
|
if _, err := os.Stat(constant.DaemonJsonPath); err != nil {
|
||||||
return &dto.DaemonJsonConf{Status: status, Version: version}
|
return &data
|
||||||
}
|
}
|
||||||
file, err := ioutil.ReadFile(constant.DaemonJsonPath)
|
file, err := os.ReadFile(constant.DaemonJsonPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &dto.DaemonJsonConf{Status: status, Version: version}
|
return &data
|
||||||
}
|
}
|
||||||
var conf daemonJsonItem
|
var conf daemonJsonItem
|
||||||
deamonMap := make(map[string]interface{})
|
deamonMap := make(map[string]interface{})
|
||||||
if err := json.Unmarshal(file, &deamonMap); err != nil {
|
if err := json.Unmarshal(file, &deamonMap); err != nil {
|
||||||
return &dto.DaemonJsonConf{Status: status, Version: version}
|
return &data
|
||||||
}
|
}
|
||||||
arr, err := json.Marshal(deamonMap)
|
arr, err := json.Marshal(deamonMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &dto.DaemonJsonConf{Status: status, Version: version}
|
return &data
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(arr, &conf); err != nil {
|
if err := json.Unmarshal(arr, &conf); err != nil {
|
||||||
return &dto.DaemonJsonConf{Status: status, Version: version}
|
return &data
|
||||||
}
|
}
|
||||||
driver := "cgroupfs"
|
if _, ok := deamonMap["iptables"]; !ok {
|
||||||
|
conf.IPTables = true
|
||||||
|
}
|
||||||
|
data.CgroupDriver = "cgroupfs"
|
||||||
for _, opt := range conf.ExecOpts {
|
for _, opt := range conf.ExecOpts {
|
||||||
if strings.HasPrefix(opt, "native.cgroupdriver=") {
|
if strings.HasPrefix(opt, "native.cgroupdriver=") {
|
||||||
driver = strings.ReplaceAll(opt, "native.cgroupdriver=", "")
|
data.CgroupDriver = strings.ReplaceAll(opt, "native.cgroupdriver=", "")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data := dto.DaemonJsonConf{
|
data.Mirrors = conf.Mirrors
|
||||||
Status: status,
|
data.Registries = conf.Registries
|
||||||
Version: version,
|
data.IPTables = conf.IPTables
|
||||||
Mirrors: conf.Mirrors,
|
data.LiveRestore = conf.LiveRestore
|
||||||
Registries: conf.Registries,
|
|
||||||
LiveRestore: conf.LiveRestore,
|
|
||||||
CgroupDriver: driver,
|
|
||||||
}
|
|
||||||
|
|
||||||
return &data
|
return &data
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +114,7 @@ func (u *DockerService) UpdateConf(req dto.DaemonJsonConf) error {
|
|||||||
_, _ = os.Create(constant.DaemonJsonPath)
|
_, _ = os.Create(constant.DaemonJsonPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := ioutil.ReadFile(constant.DaemonJsonPath)
|
file, err := os.ReadFile(constant.DaemonJsonPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -131,6 +136,11 @@ func (u *DockerService) UpdateConf(req dto.DaemonJsonConf) error {
|
|||||||
} else {
|
} else {
|
||||||
deamonMap["live-restore"] = req.LiveRestore
|
deamonMap["live-restore"] = req.LiveRestore
|
||||||
}
|
}
|
||||||
|
if req.IPTables {
|
||||||
|
delete(deamonMap, "iptables")
|
||||||
|
} else {
|
||||||
|
deamonMap["iptables"] = false
|
||||||
|
}
|
||||||
if opts, ok := deamonMap["exec-opts"]; ok {
|
if opts, ok := deamonMap["exec-opts"]; ok {
|
||||||
if optsValue, isArray := opts.([]interface{}); isArray {
|
if optsValue, isArray := opts.([]interface{}); isArray {
|
||||||
for i := 0; i < len(optsValue); i++ {
|
for i := 0; i < len(optsValue); i++ {
|
||||||
@@ -147,11 +157,15 @@ func (u *DockerService) UpdateConf(req dto.DaemonJsonConf) error {
|
|||||||
deamonMap["exec-opts"] = []string{"native.cgroupdriver=systemd"}
|
deamonMap["exec-opts"] = []string{"native.cgroupdriver=systemd"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(deamonMap) == 0 {
|
||||||
|
_ = os.Remove(constant.DaemonJsonPath)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
newJson, err := json.MarshalIndent(deamonMap, "", "\t")
|
newJson, err := json.MarshalIndent(deamonMap, "", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ioutil.WriteFile(constant.DaemonJsonPath, newJson, 0640); err != nil {
|
if err := os.WriteFile(constant.DaemonJsonPath, newJson, 0640); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,6 +177,16 @@ func (u *DockerService) UpdateConf(req dto.DaemonJsonConf) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *DockerService) UpdateConfByFile(req dto.DaemonJsonUpdateByFile) error {
|
func (u *DockerService) UpdateConfByFile(req dto.DaemonJsonUpdateByFile) error {
|
||||||
|
if len(req.File) == 0 {
|
||||||
|
_ = os.Remove(constant.DaemonJsonPath)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
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.OpenFile(constant.DaemonJsonPath, os.O_WRONLY|os.O_TRUNC, 0640)
|
file, err := os.OpenFile(constant.DaemonJsonPath, os.O_WRONLY|os.O_TRUNC, 0640)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -2,76 +2,38 @@ package service
|
|||||||
|
|
||||||
import "github.com/1Panel-dev/1Panel/backend/app/repo"
|
import "github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||||
|
|
||||||
type ServiceGroup struct {
|
|
||||||
AuthService
|
|
||||||
DashboardService
|
|
||||||
|
|
||||||
AppService
|
|
||||||
AppInstallService
|
|
||||||
|
|
||||||
ContainerService
|
|
||||||
ImageService
|
|
||||||
ImageRepoService
|
|
||||||
ComposeTemplateService
|
|
||||||
DockerService
|
|
||||||
|
|
||||||
MysqlService
|
|
||||||
RedisService
|
|
||||||
|
|
||||||
CronjobService
|
|
||||||
|
|
||||||
HostService
|
|
||||||
GroupService
|
|
||||||
CommandService
|
|
||||||
FileService
|
|
||||||
|
|
||||||
SettingService
|
|
||||||
BackupService
|
|
||||||
|
|
||||||
WebsiteService
|
|
||||||
WebsiteDnsAccountService
|
|
||||||
WebsiteSSLService
|
|
||||||
WebsiteAcmeAccountService
|
|
||||||
|
|
||||||
NginxService
|
|
||||||
|
|
||||||
LogService
|
|
||||||
SnapshotService
|
|
||||||
UpgradeService
|
|
||||||
}
|
|
||||||
|
|
||||||
var ServiceGroupApp = new(ServiceGroup)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
commonRepo = repo.RepoGroupApp.CommonRepo
|
commonRepo = repo.NewCommonRepo()
|
||||||
|
|
||||||
appRepo = repo.RepoGroupApp.AppRepo
|
appRepo = repo.NewIAppRepo()
|
||||||
appTagRepo = repo.RepoGroupApp.AppTagRepo
|
appTagRepo = repo.NewIAppTagRepo()
|
||||||
appDetailRepo = repo.RepoGroupApp.AppDetailRepo
|
appDetailRepo = repo.NewIAppDetailRepo()
|
||||||
tagRepo = repo.RepoGroupApp.TagRepo
|
tagRepo = repo.NewITagRepo()
|
||||||
appInstallRepo = repo.RepoGroupApp.AppInstallRepo
|
appInstallRepo = repo.NewIAppInstallRepo()
|
||||||
appInstallResourceRepo = repo.RepoGroupApp.AppInstallResourceRpo
|
appInstallResourceRepo = repo.NewIAppInstallResourceRpo()
|
||||||
|
|
||||||
mysqlRepo = repo.RepoGroupApp.MysqlRepo
|
mysqlRepo = repo.NewIMysqlRepo()
|
||||||
|
|
||||||
imageRepoRepo = repo.RepoGroupApp.ImageRepoRepo
|
imageRepoRepo = repo.NewIImageRepoRepo()
|
||||||
composeRepo = repo.RepoGroupApp.ComposeTemplateRepo
|
composeRepo = repo.NewIComposeTemplateRepo()
|
||||||
|
|
||||||
cronjobRepo = repo.RepoGroupApp.CronjobRepo
|
cronjobRepo = repo.NewICronjobRepo()
|
||||||
|
|
||||||
hostRepo = repo.RepoGroupApp.HostRepo
|
hostRepo = repo.NewIHostRepo()
|
||||||
groupRepo = repo.RepoGroupApp.GroupRepo
|
groupRepo = repo.NewIGroupRepo()
|
||||||
commandRepo = repo.RepoGroupApp.CommandRepo
|
commandRepo = repo.NewICommandRepo()
|
||||||
|
|
||||||
settingRepo = repo.RepoGroupApp.SettingRepo
|
settingRepo = repo.NewISettingRepo()
|
||||||
backupRepo = repo.RepoGroupApp.BackupRepo
|
backupRepo = repo.NewIBackupRepo()
|
||||||
|
|
||||||
websiteRepo = repo.NewIWebsiteRepo()
|
websiteRepo = repo.NewIWebsiteRepo()
|
||||||
websiteDomainRepo = repo.RepoGroupApp.WebsiteDomainRepo
|
websiteDomainRepo = repo.NewIWebsiteDomainRepo()
|
||||||
websiteDnsRepo = repo.RepoGroupApp.WebsiteDnsAccountRepo
|
websiteDnsRepo = repo.NewIWebsiteDnsAccountRepo()
|
||||||
websiteSSLRepo = repo.NewISSLRepo()
|
websiteSSLRepo = repo.NewISSLRepo()
|
||||||
websiteAcmeRepo = repo.NewIAcmeAccountRepo()
|
websiteAcmeRepo = repo.NewIAcmeAccountRepo()
|
||||||
|
|
||||||
logRepo = repo.RepoGroupApp.LogRepo
|
logRepo = repo.NewILogRepo()
|
||||||
snapshotRepo = repo.NewISnapshotRepo()
|
snapshotRepo = repo.NewISnapshotRepo()
|
||||||
|
|
||||||
|
runtimeRepo = repo.NewIRunTimeRepo()
|
||||||
)
|
)
|
||||||
|
|||||||
+50
-17
@@ -22,7 +22,31 @@ import (
|
|||||||
type FileService struct {
|
type FileService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) GetFileList(op request.FileOption) (response.FileInfo, error) {
|
type IFileService interface {
|
||||||
|
GetFileList(op request.FileOption) (response.FileInfo, error)
|
||||||
|
SearchUploadWithPage(req request.SearchUploadWithPage) (int64, interface{}, error)
|
||||||
|
GetFileTree(op request.FileOption) ([]response.FileTree, error)
|
||||||
|
Create(op request.FileCreate) error
|
||||||
|
Delete(op request.FileDelete) error
|
||||||
|
BatchDelete(op request.FileBatchDelete) error
|
||||||
|
ChangeMode(op request.FileCreate) error
|
||||||
|
Compress(c request.FileCompress) error
|
||||||
|
DeCompress(c request.FileDeCompress) error
|
||||||
|
GetContent(op request.FileOption) (response.FileInfo, error)
|
||||||
|
SaveContent(edit request.FileEdit) error
|
||||||
|
FileDownload(d request.FileDownload) (string, error)
|
||||||
|
DirSize(req request.DirSizeReq) (response.DirSizeRes, error)
|
||||||
|
ChangeName(req request.FileRename) error
|
||||||
|
Wget(w request.FileWget) (string, error)
|
||||||
|
MvFile(m request.FileMove) error
|
||||||
|
ChangeOwner(req request.FileRoleUpdate) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIFileService() IFileService {
|
||||||
|
return &FileService{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileService) GetFileList(op request.FileOption) (response.FileInfo, error) {
|
||||||
var fileInfo response.FileInfo
|
var fileInfo response.FileInfo
|
||||||
if _, err := os.Stat(op.Path); err != nil && os.IsNotExist(err) {
|
if _, err := os.Stat(op.Path); err != nil && os.IsNotExist(err) {
|
||||||
return fileInfo, nil
|
return fileInfo, nil
|
||||||
@@ -35,7 +59,7 @@ func (f FileService) GetFileList(op request.FileOption) (response.FileInfo, erro
|
|||||||
return fileInfo, nil
|
return fileInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) SearchUploadWithPage(req request.SearchUploadWithPage) (int64, interface{}, error) {
|
func (f *FileService) SearchUploadWithPage(req request.SearchUploadWithPage) (int64, interface{}, error) {
|
||||||
var (
|
var (
|
||||||
files []response.UploadInfo
|
files []response.UploadInfo
|
||||||
backData []response.UploadInfo
|
backData []response.UploadInfo
|
||||||
@@ -65,7 +89,7 @@ func (f FileService) SearchUploadWithPage(req request.SearchUploadWithPage) (int
|
|||||||
return int64(total), backData, nil
|
return int64(total), backData, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) GetFileTree(op request.FileOption) ([]response.FileTree, error) {
|
func (f *FileService) GetFileTree(op request.FileOption) ([]response.FileTree, error) {
|
||||||
var treeArray []response.FileTree
|
var treeArray []response.FileTree
|
||||||
info, err := files.NewFileInfo(op.FileOption)
|
info, err := files.NewFileInfo(op.FileOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -88,7 +112,7 @@ func (f FileService) GetFileTree(op request.FileOption) ([]response.FileTree, er
|
|||||||
return append(treeArray, node), nil
|
return append(treeArray, node), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) Create(op request.FileCreate) error {
|
func (f *FileService) Create(op request.FileCreate) error {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
if fo.Stat(op.Path) {
|
if fo.Stat(op.Path) {
|
||||||
return buserr.New(constant.ErrFileIsExit)
|
return buserr.New(constant.ErrFileIsExit)
|
||||||
@@ -107,7 +131,7 @@ func (f FileService) Create(op request.FileCreate) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) Delete(op request.FileDelete) error {
|
func (f *FileService) Delete(op request.FileDelete) error {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
if op.IsDir {
|
if op.IsDir {
|
||||||
return fo.DeleteDir(op.Path)
|
return fo.DeleteDir(op.Path)
|
||||||
@@ -116,7 +140,7 @@ func (f FileService) Delete(op request.FileDelete) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) BatchDelete(op request.FileBatchDelete) error {
|
func (f *FileService) BatchDelete(op request.FileBatchDelete) error {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
if op.IsDir {
|
if op.IsDir {
|
||||||
for _, file := range op.Paths {
|
for _, file := range op.Paths {
|
||||||
@@ -134,12 +158,21 @@ func (f FileService) BatchDelete(op request.FileBatchDelete) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) ChangeMode(op request.FileCreate) error {
|
func (f *FileService) ChangeMode(op request.FileCreate) error {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
return fo.Chmod(op.Path, fs.FileMode(op.Mode))
|
if op.Sub {
|
||||||
|
return fo.ChmodR(op.Path, op.Mode)
|
||||||
|
} else {
|
||||||
|
return fo.Chmod(op.Path, fs.FileMode(op.Mode))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) Compress(c request.FileCompress) error {
|
func (f *FileService) ChangeOwner(req request.FileRoleUpdate) error {
|
||||||
|
fo := files.NewFileOp()
|
||||||
|
return fo.ChownR(req.Path, req.User, req.Group, req.Sub)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileService) Compress(c request.FileCompress) error {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
if !c.Replace && fo.Stat(filepath.Join(c.Dst, c.Name)) {
|
if !c.Replace && fo.Stat(filepath.Join(c.Dst, c.Name)) {
|
||||||
return buserr.New(constant.ErrFileIsExit)
|
return buserr.New(constant.ErrFileIsExit)
|
||||||
@@ -147,12 +180,12 @@ func (f FileService) Compress(c request.FileCompress) error {
|
|||||||
return fo.Compress(c.Files, c.Dst, c.Name, files.CompressType(c.Type))
|
return fo.Compress(c.Files, c.Dst, c.Name, files.CompressType(c.Type))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) DeCompress(c request.FileDeCompress) error {
|
func (f *FileService) DeCompress(c request.FileDeCompress) error {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
return fo.Decompress(c.Path, c.Dst, files.CompressType(c.Type))
|
return fo.Decompress(c.Path, c.Dst, files.CompressType(c.Type))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) GetContent(op request.FileOption) (response.FileInfo, error) {
|
func (f *FileService) GetContent(op request.FileOption) (response.FileInfo, error) {
|
||||||
info, err := files.NewFileInfo(op.FileOption)
|
info, err := files.NewFileInfo(op.FileOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response.FileInfo{}, err
|
return response.FileInfo{}, err
|
||||||
@@ -160,7 +193,7 @@ func (f FileService) GetContent(op request.FileOption) (response.FileInfo, error
|
|||||||
return response.FileInfo{FileInfo: *info}, nil
|
return response.FileInfo{FileInfo: *info}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) SaveContent(edit request.FileEdit) error {
|
func (f *FileService) SaveContent(edit request.FileEdit) error {
|
||||||
info, err := files.NewFileInfo(files.FileOption{
|
info, err := files.NewFileInfo(files.FileOption{
|
||||||
Path: edit.Path,
|
Path: edit.Path,
|
||||||
Expand: false,
|
Expand: false,
|
||||||
@@ -173,18 +206,18 @@ func (f FileService) SaveContent(edit request.FileEdit) error {
|
|||||||
return fo.WriteFile(edit.Path, strings.NewReader(edit.Content), info.FileMode)
|
return fo.WriteFile(edit.Path, strings.NewReader(edit.Content), info.FileMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) ChangeName(req request.FileRename) error {
|
func (f *FileService) ChangeName(req request.FileRename) error {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
return fo.Rename(req.OldName, req.NewName)
|
return fo.Rename(req.OldName, req.NewName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) Wget(w request.FileWget) (string, error) {
|
func (f *FileService) Wget(w request.FileWget) (string, error) {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
key := "file-wget-" + common.GetUuid()
|
key := "file-wget-" + common.GetUuid()
|
||||||
return key, fo.DownloadFileWithProcess(w.Url, filepath.Join(w.Path, w.Name), key)
|
return key, fo.DownloadFileWithProcess(w.Url, filepath.Join(w.Path, w.Name), key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) MvFile(m request.FileMove) error {
|
func (f *FileService) MvFile(m request.FileMove) error {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
if !fo.Stat(m.NewPath) {
|
if !fo.Stat(m.NewPath) {
|
||||||
return buserr.New(constant.ErrPathNotFound)
|
return buserr.New(constant.ErrPathNotFound)
|
||||||
@@ -217,7 +250,7 @@ func (f FileService) MvFile(m request.FileMove) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) FileDownload(d request.FileDownload) (string, error) {
|
func (f *FileService) FileDownload(d request.FileDownload) (string, error) {
|
||||||
filePath := d.Paths[0]
|
filePath := d.Paths[0]
|
||||||
if d.Compress {
|
if d.Compress {
|
||||||
tempPath := filepath.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().UnixNano()))
|
tempPath := filepath.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().UnixNano()))
|
||||||
@@ -233,7 +266,7 @@ func (f FileService) FileDownload(d request.FileDownload) (string, error) {
|
|||||||
return filePath, nil
|
return filePath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f FileService) DirSize(req request.DirSizeReq) (response.DirSizeRes, error) {
|
func (f *FileService) DirSize(req request.DirSizeReq) (response.DirSizeRes, error) {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
size, err := fo.GetDirSize(req.Path)
|
size, err := fo.GetDirSize(req.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -0,0 +1,448 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/firewall"
|
||||||
|
fireClient "github.com/1Panel-dev/1Panel/backend/utils/firewall/client"
|
||||||
|
"github.com/jinzhu/copier"
|
||||||
|
)
|
||||||
|
|
||||||
|
const confPath = "/etc/sysctl.conf"
|
||||||
|
|
||||||
|
type FirewallService struct{}
|
||||||
|
|
||||||
|
type IFirewallService interface {
|
||||||
|
LoadBaseInfo() (dto.FirewallBaseInfo, error)
|
||||||
|
SearchWithPage(search dto.RuleSearch) (int64, interface{}, error)
|
||||||
|
OperateFirewall(operation string) error
|
||||||
|
OperatePortRule(req dto.PortRuleOperate, reload bool) error
|
||||||
|
OperateAddressRule(req dto.AddrRuleOperate, reload bool) error
|
||||||
|
UpdatePortRule(req dto.PortRuleUpdate) error
|
||||||
|
UpdateAddrRule(req dto.AddrRuleUpdate) error
|
||||||
|
BacthOperateRule(req dto.BatchRuleOperate) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIFirewallService() IFirewallService {
|
||||||
|
return &FirewallService{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) LoadBaseInfo() (dto.FirewallBaseInfo, error) {
|
||||||
|
var baseInfo dto.FirewallBaseInfo
|
||||||
|
baseInfo.PingStatus = u.pingStatus()
|
||||||
|
baseInfo.Status = "not running"
|
||||||
|
baseInfo.Version = "-"
|
||||||
|
baseInfo.Name = "-"
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == "no such type" {
|
||||||
|
return baseInfo, nil
|
||||||
|
}
|
||||||
|
return baseInfo, err
|
||||||
|
}
|
||||||
|
baseInfo.Name = client.Name()
|
||||||
|
baseInfo.Status, err = client.Status()
|
||||||
|
if err != nil {
|
||||||
|
return baseInfo, err
|
||||||
|
}
|
||||||
|
if baseInfo.Status == "not running" {
|
||||||
|
return baseInfo, err
|
||||||
|
}
|
||||||
|
baseInfo.Version, err = client.Version()
|
||||||
|
if err != nil {
|
||||||
|
return baseInfo, err
|
||||||
|
}
|
||||||
|
return baseInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) SearchWithPage(req dto.RuleSearch) (int64, interface{}, error) {
|
||||||
|
var (
|
||||||
|
datas []fireClient.FireInfo
|
||||||
|
backDatas []fireClient.FireInfo
|
||||||
|
)
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
if req.Type == "port" {
|
||||||
|
ports, err := client.ListPort()
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
if len(req.Info) != 0 {
|
||||||
|
for _, port := range ports {
|
||||||
|
if strings.Contains(port.Port, req.Info) {
|
||||||
|
datas = append(datas, port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
datas = ports
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addrs, err := client.ListAddress()
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
if len(req.Info) != 0 {
|
||||||
|
for _, addr := range addrs {
|
||||||
|
if strings.Contains(addr.Address, req.Info) {
|
||||||
|
datas = append(datas, addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
datas = addrs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
total, start, end := len(datas), (req.Page-1)*req.PageSize, req.Page*req.PageSize
|
||||||
|
if start > total {
|
||||||
|
backDatas = make([]fireClient.FireInfo, 0)
|
||||||
|
} else {
|
||||||
|
if end >= total {
|
||||||
|
end = total
|
||||||
|
}
|
||||||
|
backDatas = datas[start:end]
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Type == "port" {
|
||||||
|
apps := u.loadPortByApp()
|
||||||
|
for i := 0; i < len(backDatas); i++ {
|
||||||
|
port, _ := strconv.Atoi(backDatas[i].Port)
|
||||||
|
backDatas[i].IsUsed = common.ScanPort(port)
|
||||||
|
if backDatas[i].Protocol == "udp" {
|
||||||
|
backDatas[i].IsUsed = common.ScanUDPPort(port)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, app := range apps {
|
||||||
|
if app.HttpPort == backDatas[i].Port || app.HttpsPort == backDatas[i].Port {
|
||||||
|
backDatas[i].APPName = app.AppName
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return int64(total), backDatas, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) OperateFirewall(operation string) error {
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch operation {
|
||||||
|
case "start":
|
||||||
|
if err := client.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := u.addPortsBeforeStart(client); err != nil {
|
||||||
|
_ = client.Stop()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, _ = cmd.Exec("systemctl restart docker")
|
||||||
|
return nil
|
||||||
|
case "stop":
|
||||||
|
if err := client.Stop(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, _ = cmd.Exec("systemctl restart docker")
|
||||||
|
return nil
|
||||||
|
case "disablePing":
|
||||||
|
return u.updatePingStatus("0")
|
||||||
|
case "enablePing":
|
||||||
|
return u.updatePingStatus("1")
|
||||||
|
}
|
||||||
|
return fmt.Errorf("not support such operation: %s", operation)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool) error {
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if client.Name() == "ufw" {
|
||||||
|
req.Port = strings.ReplaceAll(req.Port, "-", ":")
|
||||||
|
if req.Operation == "remove" && req.Protocol == "tcp/udp" {
|
||||||
|
req.Protocol = ""
|
||||||
|
return u.operatePort(client, req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.Protocol == "tcp/udp" {
|
||||||
|
if client.Name() == "firewalld" && strings.Contains(req.Port, ",") {
|
||||||
|
ports := strings.Split(req.Port, ",")
|
||||||
|
for _, port := range ports {
|
||||||
|
if len(port) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
req.Port = port
|
||||||
|
req.Protocol = "tcp"
|
||||||
|
if err := u.operatePort(client, req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Protocol = "udp"
|
||||||
|
if err := u.operatePort(client, req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
req.Protocol = "tcp"
|
||||||
|
if err := u.operatePort(client, req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Protocol = "udp"
|
||||||
|
if err := u.operatePort(client, req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if strings.Contains(req.Port, ",") {
|
||||||
|
ports := strings.Split(req.Port, ",")
|
||||||
|
for _, port := range ports {
|
||||||
|
req.Port = port
|
||||||
|
if err := u.operatePort(client, req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := u.operatePort(client, req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if reload {
|
||||||
|
return client.Reload()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) OperateAddressRule(req dto.AddrRuleOperate, reload bool) error {
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var fireInfo fireClient.FireInfo
|
||||||
|
if err := copier.Copy(&fireInfo, &req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
addressList := strings.Split(req.Address, ",")
|
||||||
|
for _, addr := range addressList {
|
||||||
|
if len(addr) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fireInfo.Address = addr
|
||||||
|
if err := client.RichRules(fireInfo, req.Operation); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if reload {
|
||||||
|
return client.Reload()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) UpdatePortRule(req dto.PortRuleUpdate) error {
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := u.OperatePortRule(req.OldRule, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := u.OperatePortRule(req.NewRule, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return client.Reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) UpdateAddrRule(req dto.AddrRuleUpdate) error {
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := u.OperateAddressRule(req.OldRule, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := u.OperateAddressRule(req.NewRule, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return client.Reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) BacthOperateRule(req dto.BatchRuleOperate) error {
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if req.Type == "port" {
|
||||||
|
for _, rule := range req.Rules {
|
||||||
|
if err := u.OperatePortRule(rule, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return client.Reload()
|
||||||
|
}
|
||||||
|
for _, rule := range req.Rules {
|
||||||
|
itemRule := dto.AddrRuleOperate{Operation: rule.Operation, Address: rule.Address, Strategy: rule.Strategy}
|
||||||
|
if err := u.OperateAddressRule(itemRule, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return client.Reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
func OperateFirewallPort(oldPorts, newPorts []int) error {
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, port := range newPorts {
|
||||||
|
|
||||||
|
if err := client.Port(fireClient.FireInfo{Port: strconv.Itoa(port), Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, port := range oldPorts {
|
||||||
|
if err := client.Port(fireClient.FireInfo{Port: strconv.Itoa(port), Protocol: "tcp", Strategy: "accept"}, "remove"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return client.Reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) operatePort(client firewall.FirewallClient, req dto.PortRuleOperate) error {
|
||||||
|
var fireInfo fireClient.FireInfo
|
||||||
|
if err := copier.Copy(&fireInfo, &req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if client.Name() == "ufw" {
|
||||||
|
if len(fireInfo.Address) != 0 && fireInfo.Address != "Anywhere" {
|
||||||
|
return client.RichRules(fireInfo, req.Operation)
|
||||||
|
}
|
||||||
|
return client.Port(fireInfo, req.Operation)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(fireInfo.Address) != 0 || fireInfo.Strategy == "drop" {
|
||||||
|
return client.RichRules(fireInfo, req.Operation)
|
||||||
|
}
|
||||||
|
return client.Port(fireInfo, req.Operation)
|
||||||
|
}
|
||||||
|
|
||||||
|
type portOfApp struct {
|
||||||
|
AppName string
|
||||||
|
HttpPort string
|
||||||
|
HttpsPort string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) loadPortByApp() []portOfApp {
|
||||||
|
var datas []portOfApp
|
||||||
|
apps, err := appInstallRepo.ListBy()
|
||||||
|
if err != nil {
|
||||||
|
return datas
|
||||||
|
}
|
||||||
|
for i := 0; i < len(apps); i++ {
|
||||||
|
datas = append(datas, portOfApp{
|
||||||
|
AppName: apps[i].App.Key,
|
||||||
|
HttpPort: strconv.Itoa(apps[i].HttpPort),
|
||||||
|
HttpsPort: strconv.Itoa(apps[i].HttpsPort),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
systemPort, err := settingRepo.Get(settingRepo.WithByKey("ServerPort"))
|
||||||
|
if err != nil {
|
||||||
|
return datas
|
||||||
|
}
|
||||||
|
datas = append(datas, portOfApp{AppName: "1panel", HttpPort: systemPort.Value})
|
||||||
|
|
||||||
|
return datas
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) pingStatus() string {
|
||||||
|
if _, err := os.Stat("/etc/sysctl.conf"); err != nil {
|
||||||
|
return constant.StatusNone
|
||||||
|
}
|
||||||
|
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(enabel string) error {
|
||||||
|
lineBytes, err := os.ReadFile(confPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
files := strings.Split(string(lineBytes), "\n")
|
||||||
|
var newFiles []string
|
||||||
|
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="+enabel)
|
||||||
|
hasLine = true
|
||||||
|
} else {
|
||||||
|
newFiles = append(newFiles, line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !hasLine {
|
||||||
|
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 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
_, err = file.WriteString(strings.Join(newFiles, "\n"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) addPortsBeforeStart(client firewall.FirewallClient) error {
|
||||||
|
serverPort, err := settingRepo.Get(settingRepo.WithByKey("ServerPort"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := client.Port(fireClient.FireInfo{Port: serverPort.Value, Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := client.Port(fireClient.FireInfo{Port: "22", Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := client.Port(fireClient.FireInfo{Port: "80", Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := client.Port(fireClient.FireInfo{Port: "443", Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
apps := u.loadPortByApp()
|
||||||
|
for _, app := range apps {
|
||||||
|
if err := client.Port(fireClient.FireInfo{Port: app.HttpPort, Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.Reload()
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
@@ -15,6 +16,7 @@ type HostService struct{}
|
|||||||
|
|
||||||
type IHostService interface {
|
type IHostService interface {
|
||||||
TestLocalConn(id uint) bool
|
TestLocalConn(id uint) bool
|
||||||
|
TestByInfo(req dto.HostConnTest) bool
|
||||||
GetHostInfo(id uint) (*model.Host, error)
|
GetHostInfo(id uint) (*model.Host, error)
|
||||||
SearchForTree(search dto.SearchForTree) ([]dto.HostTree, error)
|
SearchForTree(search dto.SearchForTree) ([]dto.HostTree, error)
|
||||||
SearchWithPage(search dto.SearchHostWithPage) (int64, interface{}, error)
|
SearchWithPage(search dto.SearchHostWithPage) (int64, interface{}, error)
|
||||||
@@ -27,6 +29,46 @@ func NewIHostService() IHostService {
|
|||||||
return &HostService{}
|
return &HostService{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *HostService) TestByInfo(req dto.HostConnTest) bool {
|
||||||
|
if req.AuthMode == "password" && len(req.Password) != 0 {
|
||||||
|
password, err := base64.StdEncoding.DecodeString(req.Password)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
req.Password = string(password)
|
||||||
|
}
|
||||||
|
if req.AuthMode == "key" && len(req.PrivateKey) != 0 {
|
||||||
|
privateKey, err := base64.StdEncoding.DecodeString(req.PrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
req.PrivateKey = string(privateKey)
|
||||||
|
}
|
||||||
|
if len(req.Password) == 0 && len(req.PrivateKey) == 0 {
|
||||||
|
host, err := hostRepo.Get(hostRepo.WithByAddr(req.Addr))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
req.Password = host.Password
|
||||||
|
req.AuthMode = host.AuthMode
|
||||||
|
req.PrivateKey = host.PrivateKey
|
||||||
|
req.PassPhrase = host.PassPhrase
|
||||||
|
}
|
||||||
|
|
||||||
|
var connInfo ssh.ConnInfo
|
||||||
|
_ = copier.Copy(&connInfo, &req)
|
||||||
|
connInfo.PrivateKey = []byte(req.PrivateKey)
|
||||||
|
if len(req.PassPhrase) != 0 {
|
||||||
|
connInfo.PassPhrase = []byte(req.PassPhrase)
|
||||||
|
}
|
||||||
|
client, err := connInfo.NewClient()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (u *HostService) TestLocalConn(id uint) bool {
|
func (u *HostService) TestLocalConn(id uint) bool {
|
||||||
var (
|
var (
|
||||||
host model.Host
|
host model.Host
|
||||||
@@ -47,6 +89,10 @@ func (u *HostService) TestLocalConn(id uint) bool {
|
|||||||
if err := copier.Copy(&connInfo, &host); err != nil {
|
if err := copier.Copy(&connInfo, &host); err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
connInfo.PrivateKey = []byte(host.PrivateKey)
|
||||||
|
if len(host.PassPhrase) != 0 {
|
||||||
|
connInfo.PassPhrase = []byte(host.PassPhrase)
|
||||||
|
}
|
||||||
client, err := connInfo.NewClient()
|
client, err := connInfo.NewClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
@@ -77,6 +123,11 @@ func (u *HostService) SearchWithPage(search dto.SearchHostWithPage) (int64, inte
|
|||||||
}
|
}
|
||||||
group, _ := groupRepo.Get(commonRepo.WithByID(host.GroupID))
|
group, _ := groupRepo.Get(commonRepo.WithByID(host.GroupID))
|
||||||
item.GroupBelong = group.Name
|
item.GroupBelong = group.Name
|
||||||
|
if !item.RememberPassword {
|
||||||
|
item.Password = ""
|
||||||
|
item.PrivateKey = ""
|
||||||
|
item.PassPhrase = ""
|
||||||
|
}
|
||||||
dtoHosts = append(dtoHosts, item)
|
dtoHosts = append(dtoHosts, item)
|
||||||
}
|
}
|
||||||
return total, dtoHosts, err
|
return total, dtoHosts, err
|
||||||
@@ -144,6 +195,8 @@ func (u *HostService) Create(req dto.HostOperate) (*dto.HostInfo, error) {
|
|||||||
upMap["auth_mode"] = req.AuthMode
|
upMap["auth_mode"] = req.AuthMode
|
||||||
upMap["password"] = req.Password
|
upMap["password"] = req.Password
|
||||||
upMap["private_key"] = req.PrivateKey
|
upMap["private_key"] = req.PrivateKey
|
||||||
|
upMap["pass_phrase"] = req.PassPhrase
|
||||||
|
upMap["remember_password"] = req.RememberPassword
|
||||||
upMap["description"] = req.Description
|
upMap["description"] = req.Description
|
||||||
if err := hostRepo.Update(sameHostID, upMap); err != nil {
|
if err := hostRepo.Update(sameHostID, upMap); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -34,6 +33,7 @@ type IImageService interface {
|
|||||||
ImageSave(req dto.ImageSave) error
|
ImageSave(req dto.ImageSave) error
|
||||||
ImagePush(req dto.ImagePush) (string, error)
|
ImagePush(req dto.ImagePush) (string, error)
|
||||||
ImageRemove(req dto.BatchDelete) error
|
ImageRemove(req dto.BatchDelete) error
|
||||||
|
ImageTag(req dto.ImageTag) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIImageService() IImageService {
|
func NewIImageService() IImageService {
|
||||||
@@ -173,7 +173,7 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
body, err := ioutil.ReadAll(res.Body)
|
body, err := io.ReadAll(res.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("build image %s failed, err: %v", req.Name, err)
|
global.LOG.Errorf("build image %s failed, err: %v", req.Name, err)
|
||||||
_, _ = file.WriteString(fmt.Sprintf("build image %s failed, err: %v", req.Name, err))
|
_, _ = file.WriteString(fmt.Sprintf("build image %s failed, err: %v", req.Name, err))
|
||||||
@@ -274,7 +274,7 @@ func (u *ImageService) ImageLoad(req dto.ImageLoad) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
content, err := ioutil.ReadAll(res.Body)
|
content, err := io.ReadAll(res.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package service
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -190,7 +189,7 @@ func (u *ImageRepoService) handleRegistries(newHost, delHost, handle string) err
|
|||||||
}
|
}
|
||||||
|
|
||||||
deamonMap := make(map[string]interface{})
|
deamonMap := make(map[string]interface{})
|
||||||
file, err := ioutil.ReadFile(constant.DaemonJsonPath)
|
file, err := os.ReadFile(constant.DaemonJsonPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -226,7 +225,7 @@ func (u *ImageRepoService) handleRegistries(newHost, delHost, handle string) err
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ioutil.WriteFile(constant.DaemonJsonPath, newJson, 0640); err != nil {
|
if err := os.WriteFile(constant.DaemonJsonPath, newJson, 0640); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
"io"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
@@ -18,6 +19,18 @@ import (
|
|||||||
type NginxService struct {
|
type NginxService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type INginxService interface {
|
||||||
|
GetNginxConfig() (response.FileInfo, error)
|
||||||
|
GetConfigByScope(req request.NginxScopeReq) ([]response.NginxParam, error)
|
||||||
|
UpdateConfigByScope(req request.NginxConfigUpdate) error
|
||||||
|
GetStatus() (response.NginxStatus, error)
|
||||||
|
UpdateConfigFile(req request.NginxConfigFileUpdate) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewINginxService() INginxService {
|
||||||
|
return &NginxService{}
|
||||||
|
}
|
||||||
|
|
||||||
func (n NginxService) GetNginxConfig() (response.FileInfo, error) {
|
func (n NginxService) GetNginxConfig() (response.FileInfo, error) {
|
||||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -55,7 +68,7 @@ func (n NginxService) GetStatus() (response.NginxStatus, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return response.NginxStatus{}, err
|
return response.NginxStatus{}, err
|
||||||
}
|
}
|
||||||
content, err := ioutil.ReadAll(res.Body)
|
content, err := io.ReadAll(res.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response.NginxStatus{}, err
|
return response.NginxStatus{}, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getNginxFull(website *model.Website) (dto.NginxFull, error) {
|
func getNginxFull(website *model.Website) (dto.NginxFull, error) {
|
||||||
@@ -160,6 +161,10 @@ func getNginxParamsFromStaticFile(scope dto.NginxKey, newParams []dto.NginxParam
|
|||||||
switch scope {
|
switch scope {
|
||||||
case dto.SSL:
|
case dto.SSL:
|
||||||
newConfig = parser.NewStringParser(string(nginx_conf.SSL)).Parse()
|
newConfig = parser.NewStringParser(string(nginx_conf.SSL)).Parse()
|
||||||
|
case dto.CACHE:
|
||||||
|
newConfig = parser.NewStringParser(string(nginx_conf.Cache)).Parse()
|
||||||
|
case dto.ProxyCache:
|
||||||
|
newConfig = parser.NewStringParser(string(nginx_conf.ProxyCache)).Parse()
|
||||||
}
|
}
|
||||||
for _, dir := range newConfig.GetDirectives() {
|
for _, dir := range newConfig.GetDirectives() {
|
||||||
addParam := dto.NginxParam{
|
addParam := dto.NginxParam{
|
||||||
@@ -191,7 +196,7 @@ func opNginx(containerName, operate string) error {
|
|||||||
if operate == constant.NginxCheck {
|
if operate == constant.NginxCheck {
|
||||||
nginxCmd = fmt.Sprintf("docker exec -i %s %s", containerName, "nginx -t")
|
nginxCmd = fmt.Sprintf("docker exec -i %s %s", containerName, "nginx -t")
|
||||||
}
|
}
|
||||||
if out, err := cmd.Exec(nginxCmd); err != nil {
|
if out, err := cmd.ExecWithTimeOut(nginxCmd, 2*time.Second); err != nil {
|
||||||
return errors.New(out)
|
return errors.New(out)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -0,0 +1,276 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"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/utils/docker"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
|
"github.com/subosito/gotenv"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RuntimeService struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type IRuntimeService interface {
|
||||||
|
Page(req request.RuntimeSearch) (int64, []response.RuntimeRes, error)
|
||||||
|
Create(create request.RuntimeCreate) error
|
||||||
|
Delete(id uint) error
|
||||||
|
Update(req request.RuntimeUpdate) error
|
||||||
|
Get(id uint) (res *response.RuntimeRes, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRuntimeService() IRuntimeService {
|
||||||
|
return &RuntimeService{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeService) Create(create request.RuntimeCreate) (err error) {
|
||||||
|
exist, _ := runtimeRepo.GetFirst(runtimeRepo.WithName(create.Name))
|
||||||
|
if exist != nil {
|
||||||
|
return buserr.New(constant.ErrNameIsExist)
|
||||||
|
}
|
||||||
|
if create.Resource == constant.ResourceLocal {
|
||||||
|
runtime := &model.Runtime{
|
||||||
|
Name: create.Name,
|
||||||
|
Resource: create.Resource,
|
||||||
|
Type: create.Type,
|
||||||
|
Version: create.Version,
|
||||||
|
Status: constant.RuntimeNormal,
|
||||||
|
}
|
||||||
|
return runtimeRepo.Create(context.Background(), runtime)
|
||||||
|
}
|
||||||
|
exist, _ = runtimeRepo.GetFirst(runtimeRepo.WithImage(create.Image))
|
||||||
|
if exist != nil {
|
||||||
|
return buserr.New(constant.ErrImageExist)
|
||||||
|
}
|
||||||
|
appDetail, err := appDetailRepo.GetFirst(commonRepo.WithByID(create.AppDetailID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
app, err := appRepo.GetFirst(commonRepo.WithByID(appDetail.AppId))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fileOp := files.NewFileOp()
|
||||||
|
buildDir := path.Join(constant.AppResourceDir, app.Key, "versions", appDetail.Version, "build")
|
||||||
|
if !fileOp.Stat(buildDir) {
|
||||||
|
return buserr.New(constant.ErrDirNotFound)
|
||||||
|
}
|
||||||
|
runtimeDir := path.Join(constant.RuntimeDir, create.Type)
|
||||||
|
tempDir := filepath.Join(runtimeDir, fmt.Sprintf("%d", time.Now().UnixNano()))
|
||||||
|
if err = fileOp.CopyDir(buildDir, tempDir); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
oldDir := path.Join(tempDir, "build")
|
||||||
|
newNameDir := path.Join(runtimeDir, create.Name)
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
_ = fileOp.DeleteDir(newNameDir)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if oldDir != newNameDir {
|
||||||
|
if err = fileOp.Rename(oldDir, newNameDir); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = fileOp.DeleteDir(tempDir); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
composeContent, envContent, forms, err := handleParams(create.Image, create.Type, newNameDir, create.Params)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
composeService, err := getComposeService(create.Name, newNameDir, composeContent, envContent, false)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
runtime := &model.Runtime{
|
||||||
|
Name: create.Name,
|
||||||
|
DockerCompose: string(composeContent),
|
||||||
|
Env: string(envContent),
|
||||||
|
AppDetailID: create.AppDetailID,
|
||||||
|
Type: create.Type,
|
||||||
|
Image: create.Image,
|
||||||
|
Resource: create.Resource,
|
||||||
|
Status: constant.RuntimeBuildIng,
|
||||||
|
Version: create.Version,
|
||||||
|
Params: string(forms),
|
||||||
|
}
|
||||||
|
if err = runtimeRepo.Create(context.Background(), runtime); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
go buildRuntime(runtime, composeService, "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeService) Page(req request.RuntimeSearch) (int64, []response.RuntimeRes, error) {
|
||||||
|
var (
|
||||||
|
opts []repo.DBOption
|
||||||
|
res []response.RuntimeRes
|
||||||
|
)
|
||||||
|
if req.Name != "" {
|
||||||
|
opts = append(opts, commonRepo.WithLikeName(req.Name))
|
||||||
|
}
|
||||||
|
if req.Status != "" {
|
||||||
|
opts = append(opts, runtimeRepo.WithStatus(req.Status))
|
||||||
|
}
|
||||||
|
total, runtimes, err := runtimeRepo.Page(req.Page, req.PageSize, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
for _, runtime := range runtimes {
|
||||||
|
res = append(res, response.RuntimeRes{
|
||||||
|
Runtime: runtime,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return total, res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeService) Delete(id uint) error {
|
||||||
|
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(id))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
website, _ := websiteRepo.GetFirst(websiteRepo.WithRuntimeID(id))
|
||||||
|
if website.ID > 0 {
|
||||||
|
return buserr.New(constant.ErrDelWithWebsite)
|
||||||
|
}
|
||||||
|
if runtime.Resource == constant.ResourceAppstore {
|
||||||
|
client, err := docker.NewClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
imageID, err := client.GetImageIDByName(runtime.Image)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if imageID != "" {
|
||||||
|
if err := client.DeleteImage(imageID); err != nil {
|
||||||
|
global.LOG.Errorf("delete image id [%s] error %v", imageID, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runtimeDir := path.Join(constant.RuntimeDir, runtime.Type, runtime.Name)
|
||||||
|
if err := files.NewFileOp().DeleteDir(runtimeDir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return runtimeRepo.DeleteBy(commonRepo.WithByID(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeService) Get(id uint) (*response.RuntimeRes, error) {
|
||||||
|
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(id))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res := &response.RuntimeRes{}
|
||||||
|
res.Runtime = *runtime
|
||||||
|
if runtime.Resource == constant.ResourceLocal {
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
appDetail, err := appDetailRepo.GetFirst(commonRepo.WithByID(runtime.AppDetailID))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res.AppID = appDetail.AppId
|
||||||
|
var (
|
||||||
|
appForm dto.AppForm
|
||||||
|
appParams []response.AppParam
|
||||||
|
)
|
||||||
|
if err := json.Unmarshal([]byte(runtime.Params), &appForm); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
envs, err := gotenv.Unmarshal(runtime.Env)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, form := range appForm.FormFields {
|
||||||
|
if v, ok := envs[form.EnvKey]; ok {
|
||||||
|
appParam := response.AppParam{
|
||||||
|
Edit: false,
|
||||||
|
Key: form.EnvKey,
|
||||||
|
Rule: form.Rule,
|
||||||
|
Type: form.Type,
|
||||||
|
Required: form.Required,
|
||||||
|
}
|
||||||
|
if form.Edit {
|
||||||
|
appParam.Edit = true
|
||||||
|
}
|
||||||
|
appParam.LabelZh = form.LabelZh
|
||||||
|
appParam.LabelEn = form.LabelEn
|
||||||
|
appParam.Multiple = form.Multiple
|
||||||
|
appParam.Value = v
|
||||||
|
if form.Type == "select" {
|
||||||
|
if form.Multiple {
|
||||||
|
if v == "" {
|
||||||
|
appParam.Value = []string{}
|
||||||
|
} else {
|
||||||
|
appParam.Value = strings.Split(v, ",")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, fv := range form.Values {
|
||||||
|
if fv.Value == v {
|
||||||
|
appParam.ShowValue = fv.Label
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
appParam.Values = form.Values
|
||||||
|
}
|
||||||
|
appParams = append(appParams, appParam)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.AppParams = appParams
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
|
||||||
|
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(req.ID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
oldImage := runtime.Image
|
||||||
|
if runtime.Resource == constant.ResourceLocal {
|
||||||
|
runtime.Version = req.Version
|
||||||
|
return runtimeRepo.Save(runtime)
|
||||||
|
}
|
||||||
|
exist, _ := runtimeRepo.GetFirst(runtimeRepo.WithImage(req.Name), runtimeRepo.WithNotId(req.ID))
|
||||||
|
if exist != nil {
|
||||||
|
return buserr.New(constant.ErrImageExist)
|
||||||
|
}
|
||||||
|
runtimeDir := path.Join(constant.RuntimeDir, runtime.Type, runtime.Name)
|
||||||
|
composeContent, envContent, _, err := handleParams(req.Image, runtime.Type, runtimeDir, req.Params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
composeService, err := getComposeService(runtime.Name, runtimeDir, composeContent, envContent, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
runtime.Image = req.Image
|
||||||
|
runtime.Env = string(envContent)
|
||||||
|
runtime.DockerCompose = string(composeContent)
|
||||||
|
runtime.Status = constant.RuntimeBuildIng
|
||||||
|
_ = runtimeRepo.Save(runtime)
|
||||||
|
client, err := docker.NewClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
imageID, err := client.GetImageIDByName(oldImage)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go buildRuntime(runtime, composeService, imageID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
"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/docker"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
|
"github.com/docker/cli/cli/command"
|
||||||
|
"github.com/subosito/gotenv"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func buildRuntime(runtime *model.Runtime, service *docker.ComposeService, oldImageID string) {
|
||||||
|
err := service.ComposeBuild()
|
||||||
|
if err != nil {
|
||||||
|
runtime.Status = constant.RuntimeError
|
||||||
|
runtime.Message = buserr.New(constant.ErrImageBuildErr).Error() + ":" + err.Error()
|
||||||
|
} else {
|
||||||
|
runtime.Status = constant.RuntimeNormal
|
||||||
|
if oldImageID != "" {
|
||||||
|
client, err := docker.NewClient()
|
||||||
|
if err == nil {
|
||||||
|
newImageID, err := client.GetImageIDByName(runtime.Image)
|
||||||
|
if err == nil && newImageID != oldImageID {
|
||||||
|
global.LOG.Infof("delete imageID [%s] ", oldImageID)
|
||||||
|
if err := client.DeleteImage(oldImageID); err != nil {
|
||||||
|
global.LOG.Errorf("delete imageID [%s] error %v", oldImageID, err)
|
||||||
|
} else {
|
||||||
|
global.LOG.Infof("delete old image success")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
global.LOG.Errorf("delete imageID [%s] error %v", oldImageID, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = runtimeRepo.Save(runtime)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleParams(image, runtimeType, runtimeDir string, params map[string]interface{}) (composeContent []byte, envContent []byte, forms []byte, err error) {
|
||||||
|
fileOp := files.NewFileOp()
|
||||||
|
composeContent, err = fileOp.GetContent(path.Join(runtimeDir, "docker-compose.yml"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
env, err := gotenv.Read(path.Join(runtimeDir, ".env"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
forms, err = fileOp.GetContent(path.Join(runtimeDir, "config.json"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
params["IMAGE_NAME"] = image
|
||||||
|
if runtimeType == constant.RuntimePHP {
|
||||||
|
if extends, ok := params["PHP_EXTENSIONS"]; ok {
|
||||||
|
if extendsArray, ok := extends.([]interface{}); ok {
|
||||||
|
strArray := make([]string, len(extendsArray))
|
||||||
|
for i, v := range extendsArray {
|
||||||
|
strArray[i] = fmt.Sprintf("%v", v)
|
||||||
|
}
|
||||||
|
params["PHP_EXTENSIONS"] = strings.Join(strArray, ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newMap := make(map[string]string)
|
||||||
|
handleMap(params, newMap)
|
||||||
|
for k, v := range newMap {
|
||||||
|
env[k] = v
|
||||||
|
}
|
||||||
|
envStr, err := gotenv.Marshal(env)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = gotenv.Write(env, path.Join(runtimeDir, ".env")); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
envContent = []byte(envStr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getComposeService(name, runtimeDir string, composeFile, env []byte, skipNormalization bool) (*docker.ComposeService, error) {
|
||||||
|
project, err := docker.GetComposeProject(name, runtimeDir, composeFile, env, skipNormalization)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
logPath := path.Join(runtimeDir, "build.log")
|
||||||
|
fileOp := files.NewFileOp()
|
||||||
|
if fileOp.Stat(logPath) {
|
||||||
|
_ = fileOp.DeleteFile(logPath)
|
||||||
|
}
|
||||||
|
file, err := os.Create(logPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
composeService, err := docker.NewComposeService(command.WithOutputStream(file))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
composeService.SetProject(project)
|
||||||
|
return composeService, nil
|
||||||
|
}
|
||||||
@@ -1,8 +1,14 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
@@ -12,6 +18,8 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
|
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -22,6 +30,8 @@ type ISettingService interface {
|
|||||||
Update(key, value string) error
|
Update(key, value string) error
|
||||||
UpdatePassword(c *gin.Context, old, new string) error
|
UpdatePassword(c *gin.Context, old, new string) error
|
||||||
UpdatePort(port uint) 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
|
HandlePasswordExpired(c *gin.Context, old, new string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +80,14 @@ func (u *SettingService) UpdatePort(port uint) error {
|
|||||||
if common.ScanPort(int(port)) {
|
if common.ScanPort(int(port)) {
|
||||||
return buserr.WithDetail(constant.ErrPortInUsed, port, nil)
|
return buserr.WithDetail(constant.ErrPortInUsed, port, nil)
|
||||||
}
|
}
|
||||||
|
serverPort, err := settingRepo.Get(settingRepo.WithByKey("ServerPort"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
portValue, _ := strconv.Atoi(serverPort.Value)
|
||||||
|
if err := OperateFirewallPort([]int{portValue}, []int{int(port)}); err != nil {
|
||||||
|
global.LOG.Errorf("set system firewall ports failed, err: %v", err)
|
||||||
|
}
|
||||||
if err := settingRepo.Update("ServerPort", strconv.Itoa(int(port))); err != nil {
|
if err := settingRepo.Update("ServerPort", strconv.Itoa(int(port))); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -83,6 +100,135 @@ func (u *SettingService) UpdatePort(port uint) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *SettingService) UpdateSSL(c *gin.Context, req dto.SSLUpdate) error {
|
||||||
|
secretDir := global.CONF.System.BaseDir + "/1panel/secret/"
|
||||||
|
if req.SSL == "disable" {
|
||||||
|
if err := settingRepo.Update("SSL", "disable"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := settingRepo.Update("SSLType", "self"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_ = os.Remove(secretDir + "server.crt")
|
||||||
|
_ = os.Remove(secretDir + "server.key")
|
||||||
|
go func() {
|
||||||
|
_, err := cmd.Exec("systemctl restart 1panel.service")
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("restart system failed, err: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := os.Stat(secretDir); err != nil && os.IsNotExist(err) {
|
||||||
|
if err = os.MkdirAll(secretDir, os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := settingRepo.Update("SSLType", req.SSLType); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if req.SSLType == "self" {
|
||||||
|
if len(req.Domain) == 0 {
|
||||||
|
return fmt.Errorf("load domain failed")
|
||||||
|
}
|
||||||
|
if err := ssl.GenerateSSL(req.Domain); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.SSLType == "select" {
|
||||||
|
sslInfo, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(req.SSLID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Cert = sslInfo.Pem
|
||||||
|
req.Key = sslInfo.PrivateKey
|
||||||
|
req.SSLType = "import"
|
||||||
|
if err := settingRepo.Update("SSLID", strconv.Itoa(int(req.SSLID))); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.SSLType == "import" {
|
||||||
|
cert, err := os.OpenFile(secretDir+"server.crt.tmp", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer cert.Close()
|
||||||
|
if _, err := cert.WriteString(req.Cert); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
key, err := os.OpenFile(secretDir+"server.key.tmp", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := key.WriteString(req.Key); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer key.Close()
|
||||||
|
}
|
||||||
|
if err := checkCertValid(req.Domain); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fileOp := files.NewFileOp()
|
||||||
|
if err := fileOp.Rename(secretDir+"server.crt.tmp", secretDir+"server.crt"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := fileOp.Rename(secretDir+"server.key.tmp", secretDir+"server.key"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := settingRepo.Update("SSL", req.SSL); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
_, err := cmd.Exec("systemctl restart 1panel.service")
|
||||||
|
if err != nil {
|
||||||
|
global.LOG.Errorf("restart system failed, err: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *SettingService) LoadFromCert() (*dto.SSLInfo, error) {
|
||||||
|
ssl, err := settingRepo.Get(settingRepo.WithByKey("SSL"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if ssl.Value == "disable" {
|
||||||
|
return &dto.SSLInfo{}, nil
|
||||||
|
}
|
||||||
|
sslType, err := settingRepo.Get(settingRepo.WithByKey("SSLType"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
data, err := loadInfoFromCert()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
switch sslType.Value {
|
||||||
|
case "import":
|
||||||
|
if _, err := os.Stat(global.CONF.System.BaseDir + "/1panel/secret/server.crt"); err != nil {
|
||||||
|
return nil, fmt.Errorf("load server.crt file failed, err: %v", err)
|
||||||
|
}
|
||||||
|
certFile, _ := os.ReadFile(global.CONF.System.BaseDir + "/1panel/secret/server.crt")
|
||||||
|
data.Cert = string(certFile)
|
||||||
|
|
||||||
|
if _, err := os.Stat(global.CONF.System.BaseDir + "/1panel/secret/server.key"); err != nil {
|
||||||
|
return nil, fmt.Errorf("load server.key file failed, err: %v", err)
|
||||||
|
}
|
||||||
|
keyFile, _ := os.ReadFile(global.CONF.System.BaseDir + "/1panel/secret/server.key")
|
||||||
|
data.Key = string(keyFile)
|
||||||
|
case "select":
|
||||||
|
sslID, err := settingRepo.Get(settingRepo.WithByKey("SSLID"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
id, _ := strconv.Atoi(sslID.Value)
|
||||||
|
data.SSLID = uint(id)
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (u *SettingService) HandlePasswordExpired(c *gin.Context, old, new string) error {
|
func (u *SettingService) HandlePasswordExpired(c *gin.Context, old, new string) error {
|
||||||
setting, err := settingRepo.Get(settingRepo.WithByKey("Password"))
|
setting, err := settingRepo.Get(settingRepo.WithByKey("Password"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -121,3 +267,60 @@ func (u *SettingService) UpdatePassword(c *gin.Context, old, new string) error {
|
|||||||
_ = global.SESSION.Clean()
|
_ = global.SESSION.Clean()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadInfoFromCert() (*dto.SSLInfo, error) {
|
||||||
|
var info dto.SSLInfo
|
||||||
|
certFile := global.CONF.System.BaseDir + "/1panel/secret/server.crt"
|
||||||
|
if _, err := os.Stat(certFile); err != nil {
|
||||||
|
return &info, err
|
||||||
|
}
|
||||||
|
certData, err := os.ReadFile(certFile)
|
||||||
|
if err != nil {
|
||||||
|
return &info, err
|
||||||
|
}
|
||||||
|
certBlock, _ := pem.Decode(certData)
|
||||||
|
if certBlock == nil {
|
||||||
|
return &info, err
|
||||||
|
}
|
||||||
|
certObj, err := x509.ParseCertificate(certBlock.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return &info, err
|
||||||
|
}
|
||||||
|
var domains []string
|
||||||
|
if len(certObj.IPAddresses) != 0 {
|
||||||
|
for _, ip := range certObj.IPAddresses {
|
||||||
|
domains = append(domains, ip.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(certObj.DNSNames) != 0 {
|
||||||
|
domains = append(domains, certObj.DNSNames...)
|
||||||
|
}
|
||||||
|
return &dto.SSLInfo{
|
||||||
|
Domain: strings.Join(domains, ","),
|
||||||
|
Timeout: certObj.NotAfter.Format("2006-01-02 15:04:05"),
|
||||||
|
RootPath: global.CONF.System.BaseDir + "/1panel/secret/server.crt",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkCertValid(domain string) error {
|
||||||
|
certificate, err := os.ReadFile(global.CONF.System.BaseDir + "/1panel/secret/server.crt.tmp")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
key, err := os.ReadFile(global.CONF.System.BaseDir + "/1panel/secret/server.key.tmp")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err = tls.X509KeyPair(certificate, key); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
certBlock, _ := pem.Decode(certificate)
|
||||||
|
if certBlock == nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := x509.ParseCertificate(certBlock.Bytes); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -484,7 +483,7 @@ func (u *SnapshotService) SnapshotRollback(req dto.SnapshotRecover) error {
|
|||||||
|
|
||||||
func (u *SnapshotService) saveJson(snapJson SnapshotJson, path string) error {
|
func (u *SnapshotService) saveJson(snapJson SnapshotJson, path string) error {
|
||||||
remarkInfo, _ := json.MarshalIndent(snapJson, "", "\t")
|
remarkInfo, _ := json.MarshalIndent(snapJson, "", "\t")
|
||||||
if err := ioutil.WriteFile(fmt.Sprintf("%s/snapshot.json", path), remarkInfo, 0640); err != nil {
|
if err := os.WriteFile(fmt.Sprintf("%s/snapshot.json", path), remarkInfo, 0640); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -793,7 +792,7 @@ func (u *SnapshotService) updateLiveRestore(enabled bool) error {
|
|||||||
if _, err := os.Stat(constant.DaemonJsonPath); err != nil {
|
if _, err := os.Stat(constant.DaemonJsonPath); err != nil {
|
||||||
return fmt.Errorf("load docker daemon.json conf failed, err: %v", err)
|
return fmt.Errorf("load docker daemon.json conf failed, err: %v", err)
|
||||||
}
|
}
|
||||||
file, err := ioutil.ReadFile(constant.DaemonJsonPath)
|
file, err := os.ReadFile(constant.DaemonJsonPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -809,7 +808,7 @@ func (u *SnapshotService) updateLiveRestore(enabled bool) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ioutil.WriteFile(constant.DaemonJsonPath, newJson, 0640); err != nil {
|
if err := os.WriteFile(constant.DaemonJsonPath, newJson, 0640); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -855,7 +854,7 @@ func (u *SnapshotService) handleTar(sourceDir, targetDir, name, exclusionRules s
|
|||||||
|
|
||||||
commands := fmt.Sprintf("tar --warning=no-file-changed -zcf %s %s -C %s .", targetDir+"/"+name, exStr, sourceDir)
|
commands := fmt.Sprintf("tar --warning=no-file-changed -zcf %s %s -C %s .", targetDir+"/"+name, exStr, sourceDir)
|
||||||
global.LOG.Debug(commands)
|
global.LOG.Debug(commands)
|
||||||
stdout, err := cmd.Exec(commands)
|
stdout, err := cmd.ExecWithTimeOut(commands, 30*time.Minute)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("do handle tar failed, stdout: %s, err: %v", stdout, err)
|
global.LOG.Errorf("do handle tar failed, stdout: %s, err: %v", stdout, err)
|
||||||
return errors.New(stdout)
|
return errors.New(stdout)
|
||||||
@@ -872,7 +871,7 @@ func (u *SnapshotService) handleUnTar(sourceDir, targetDir string) error {
|
|||||||
|
|
||||||
commands := fmt.Sprintf("tar -zxf %s -C %s .", sourceDir, targetDir)
|
commands := fmt.Sprintf("tar -zxf %s -C %s .", sourceDir, targetDir)
|
||||||
global.LOG.Debug(commands)
|
global.LOG.Debug(commands)
|
||||||
stdout, err := cmd.Exec(commands)
|
stdout, err := cmd.ExecWithTimeOut(commands, 30*time.Minute)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.LOG.Errorf("do handle untar failed, stdout: %s, err: %v", stdout, err)
|
global.LOG.Errorf("do handle untar failed, stdout: %s, err: %v", stdout, err)
|
||||||
return errors.New(stdout)
|
return errors.New(stdout)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
@@ -148,7 +148,7 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
|
|||||||
go writeLogs(req.Version)
|
go writeLogs(req.Version)
|
||||||
_ = settingRepo.Update("SystemVersion", req.Version)
|
_ = settingRepo.Update("SystemVersion", req.Version)
|
||||||
_ = settingRepo.Update("SystemStatus", "Free")
|
_ = settingRepo.Update("SystemStatus", "Free")
|
||||||
_, _ = cmd.Exec("systemctl daemon-reload && systemctl restart 1panel.service")
|
_, _ = cmd.ExecWithTimeOut("systemctl daemon-reload && systemctl restart 1panel.service", 1*time.Minute)
|
||||||
}()
|
}()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -203,7 +203,7 @@ func (u *UpgradeService) loadVersion(isLatest bool, currentVersion string) (stri
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
defer latestVersionRes.Body.Close()
|
defer latestVersionRes.Body.Close()
|
||||||
version, err := ioutil.ReadAll(latestVersionRes.Body)
|
version, err := io.ReadAll(latestVersionRes.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -231,7 +231,7 @@ func (u *UpgradeService) loadReleaseNotes(path string) (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
defer releaseNotes.Body.Close()
|
defer releaseNotes.Body.Close()
|
||||||
release, err := ioutil.ReadAll(releaseNotes.Body)
|
release, err := io.ReadAll(releaseNotes.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|||||||
+847
-73
File diff suppressed because it is too large
Load Diff
@@ -13,6 +13,16 @@ import (
|
|||||||
type WebsiteAcmeAccountService struct {
|
type WebsiteAcmeAccountService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IWebsiteAcmeAccountService interface {
|
||||||
|
Page(search dto.PageInfo) (int64, []response.WebsiteAcmeAccountDTO, error)
|
||||||
|
Create(create request.WebsiteAcmeAccountCreate) (response.WebsiteAcmeAccountDTO, error)
|
||||||
|
Delete(id uint) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIWebsiteAcmeAccountService() IWebsiteAcmeAccountService {
|
||||||
|
return &WebsiteAcmeAccountService{}
|
||||||
|
}
|
||||||
|
|
||||||
func (w WebsiteAcmeAccountService) Page(search dto.PageInfo) (int64, []response.WebsiteAcmeAccountDTO, error) {
|
func (w WebsiteAcmeAccountService) Page(search dto.PageInfo) (int64, []response.WebsiteAcmeAccountDTO, error) {
|
||||||
total, accounts, err := websiteAcmeRepo.Page(search.Page, search.PageSize, commonRepo.WithOrderBy("created_at desc"))
|
total, accounts, err := websiteAcmeRepo.Page(search.Page, search.PageSize, commonRepo.WithOrderBy("created_at desc"))
|
||||||
var accountDTOs []response.WebsiteAcmeAccountDTO
|
var accountDTOs []response.WebsiteAcmeAccountDTO
|
||||||
|
|||||||
@@ -13,6 +13,17 @@ import (
|
|||||||
type WebsiteDnsAccountService struct {
|
type WebsiteDnsAccountService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IWebsiteDnsAccountService interface {
|
||||||
|
Page(search dto.PageInfo) (int64, []response.WebsiteDnsAccountDTO, error)
|
||||||
|
Create(create request.WebsiteDnsAccountCreate) (request.WebsiteDnsAccountCreate, error)
|
||||||
|
Update(update request.WebsiteDnsAccountUpdate) (request.WebsiteDnsAccountUpdate, error)
|
||||||
|
Delete(id uint) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIWebsiteDnsAccountService() IWebsiteDnsAccountService {
|
||||||
|
return &WebsiteDnsAccountService{}
|
||||||
|
}
|
||||||
|
|
||||||
func (w WebsiteDnsAccountService) Page(search dto.PageInfo) (int64, []response.WebsiteDnsAccountDTO, error) {
|
func (w WebsiteDnsAccountService) Page(search dto.PageInfo) (int64, []response.WebsiteDnsAccountDTO, error) {
|
||||||
total, accounts, err := websiteDnsRepo.Page(search.Page, search.PageSize, commonRepo.WithOrderBy("created_at desc"))
|
total, accounts, err := websiteDnsRepo.Page(search.Page, search.PageSize, commonRepo.WithOrderBy("created_at desc"))
|
||||||
var accountDTOs []response.WebsiteDnsAccountDTO
|
var accountDTOs []response.WebsiteDnsAccountDTO
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs
|
|||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var websiteSSL model.WebsiteSSL
|
||||||
|
|
||||||
switch create.Provider {
|
switch create.Provider {
|
||||||
case constant.DNSAccount:
|
case constant.DNSAccount:
|
||||||
dnsAccount, err := websiteDnsRepo.GetFirst(commonRepo.WithByID(create.DnsAccountID))
|
dnsAccount, err := websiteDnsRepo.GetFirst(commonRepo.WithByID(create.DnsAccountID))
|
||||||
@@ -92,6 +94,7 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs
|
|||||||
if err := client.UseDns(ssl.DnsType(dnsAccount.Type), dnsAccount.Authorization); err != nil {
|
if err := client.UseDns(ssl.DnsType(dnsAccount.Type), dnsAccount.Authorization); err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
websiteSSL.AutoRenew = create.AutoRenew
|
||||||
case constant.Http:
|
case constant.Http:
|
||||||
appInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
appInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -100,6 +103,7 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs
|
|||||||
if err := client.UseHTTP(path.Join(constant.AppInstallDir, constant.AppOpenresty, appInstall.Name, "root")); err != nil {
|
if err := client.UseHTTP(path.Join(constant.AppInstallDir, constant.AppOpenresty, appInstall.Name, "root")); err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
websiteSSL.AutoRenew = create.AutoRenew
|
||||||
case constant.DnsManual:
|
case constant.DnsManual:
|
||||||
if err := client.UseManualDns(); err != nil {
|
if err := client.UseManualDns(); err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
@@ -115,7 +119,7 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
var websiteSSL model.WebsiteSSL
|
|
||||||
websiteSSL.DnsAccountID = create.DnsAccountID
|
websiteSSL.DnsAccountID = create.DnsAccountID
|
||||||
websiteSSL.AcmeAccountID = acmeAccount.ID
|
websiteSSL.AcmeAccountID = acmeAccount.ID
|
||||||
websiteSSL.Provider = create.Provider
|
websiteSSL.Provider = create.Provider
|
||||||
@@ -133,7 +137,6 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs
|
|||||||
websiteSSL.StartDate = cert.NotBefore
|
websiteSSL.StartDate = cert.NotBefore
|
||||||
websiteSSL.Type = cert.Issuer.CommonName
|
websiteSSL.Type = cert.Issuer.CommonName
|
||||||
websiteSSL.Organization = cert.Issuer.Organization[0]
|
websiteSSL.Organization = cert.Issuer.Organization[0]
|
||||||
websiteSSL.AutoRenew = create.AutoRenew
|
|
||||||
|
|
||||||
if err := websiteSSLRepo.Create(context.TODO(), &websiteSSL); err != nil {
|
if err := websiteSSLRepo.Create(context.TODO(), &websiteSSL); err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/nginx/components"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -20,10 +23,8 @@ import (
|
|||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getDomain(domainStr string, websiteID uint) (model.WebsiteDomain, error) {
|
func getDomain(domainStr string) (model.WebsiteDomain, error) {
|
||||||
domain := model.WebsiteDomain{
|
domain := model.WebsiteDomain{}
|
||||||
WebsiteID: websiteID,
|
|
||||||
}
|
|
||||||
domainArray := strings.Split(domainStr, ":")
|
domainArray := strings.Split(domainStr, ":")
|
||||||
if len(domainArray) == 1 {
|
if len(domainArray) == 1 {
|
||||||
domain.Domain = domainArray[0]
|
domain.Domain = domainArray[0]
|
||||||
@@ -43,15 +44,26 @@ func getDomain(domainStr string, websiteID uint) (model.WebsiteDomain, error) {
|
|||||||
return model.WebsiteDomain{}, nil
|
return model.WebsiteDomain{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createStaticHtml(website *model.Website) error {
|
func createIndexFile(website *model.Website, runtime *model.Runtime) error {
|
||||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
indexFolder := path.Join(constant.AppInstallDir, constant.AppOpenresty, nginxInstall.Name, "www", "sites", website.Alias, "index")
|
indexFolder := path.Join(constant.AppInstallDir, constant.AppOpenresty, nginxInstall.Name, "www", "sites", website.Alias, "index")
|
||||||
indexPath := path.Join(indexFolder, "index.html")
|
indexPath := ""
|
||||||
indexContent := string(nginx_conf.Index)
|
indexContent := ""
|
||||||
|
switch website.Type {
|
||||||
|
case constant.Static:
|
||||||
|
indexPath = path.Join(indexFolder, "index.html")
|
||||||
|
indexContent = string(nginx_conf.Index)
|
||||||
|
case constant.Runtime:
|
||||||
|
if runtime.Type == constant.RuntimePHP {
|
||||||
|
indexPath = path.Join(indexFolder, "index.php")
|
||||||
|
indexContent = string(nginx_conf.IndexPHP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fileOp := files.NewFileOp()
|
fileOp := files.NewFileOp()
|
||||||
if !fileOp.Stat(indexFolder) {
|
if !fileOp.Stat(indexFolder) {
|
||||||
if err := fileOp.CreateDir(indexFolder, 0755); err != nil {
|
if err := fileOp.CreateDir(indexFolder, 0755); err != nil {
|
||||||
@@ -63,13 +75,52 @@ func createStaticHtml(website *model.Website) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if website.Type == constant.Runtime && runtime.Resource == constant.ResourceAppstore {
|
||||||
|
if err := chownRootDir(indexFolder); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
if err := fileOp.WriteFile(indexPath, strings.NewReader(indexContent), 0755); err != nil {
|
if err := fileOp.WriteFile(indexPath, strings.NewReader(indexContent), 0755); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createWebsiteFolder(nginxInstall model.AppInstall, website *model.Website) error {
|
func createProxyFile(website *model.Website, runtime *model.Runtime) error {
|
||||||
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
proxyFolder := path.Join(constant.AppInstallDir, constant.AppOpenresty, nginxInstall.Name, "www", "sites", website.Alias, "proxy")
|
||||||
|
filePath := path.Join(proxyFolder, "root.conf")
|
||||||
|
fileOp := files.NewFileOp()
|
||||||
|
if !fileOp.Stat(proxyFolder) {
|
||||||
|
if err := fileOp.CreateDir(proxyFolder, 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !fileOp.Stat(filePath) {
|
||||||
|
if err := fileOp.CreateFile(filePath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config := parser.NewStringParser(string(nginx_conf.Proxy)).Parse()
|
||||||
|
config.FilePath = filePath
|
||||||
|
directives := config.Directives
|
||||||
|
location, ok := directives[0].(*components.Location)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("error")
|
||||||
|
}
|
||||||
|
location.ChangePath("^~", "/")
|
||||||
|
location.UpdateDirective("proxy_pass", []string{website.Proxy})
|
||||||
|
location.UpdateDirective("proxy_set_header", []string{"Host", "$host"})
|
||||||
|
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||||
|
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createWebsiteFolder(nginxInstall model.AppInstall, website *model.Website, runtime *model.Runtime) error {
|
||||||
nginxFolder := path.Join(constant.AppInstallDir, constant.AppOpenresty, nginxInstall.Name)
|
nginxFolder := path.Join(constant.AppInstallDir, constant.AppOpenresty, nginxInstall.Name)
|
||||||
siteFolder := path.Join(nginxFolder, "www", "sites", website.Alias)
|
siteFolder := path.Join(nginxFolder, "www", "sites", website.Alias)
|
||||||
fileOp := files.NewFileOp()
|
fileOp := files.NewFileOp()
|
||||||
@@ -86,14 +137,30 @@ func createWebsiteFolder(nginxInstall model.AppInstall, website *model.Website)
|
|||||||
if err := fileOp.CreateFile(path.Join(siteFolder, "log", "error.log")); err != nil {
|
if err := fileOp.CreateFile(path.Join(siteFolder, "log", "error.log")); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := fileOp.CreateDir(path.Join(siteFolder, "index"), 0755); err != nil {
|
if err := fileOp.CreateDir(path.Join(siteFolder, "index"), 0775); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := fileOp.CreateDir(path.Join(siteFolder, "ssl"), 0755); err != nil {
|
if err := fileOp.CreateDir(path.Join(siteFolder, "ssl"), 0755); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if website.Type == constant.Static {
|
if website.Type == constant.Runtime {
|
||||||
if err := createStaticHtml(website); err != nil {
|
if runtime.Type == constant.RuntimePHP && runtime.Resource == constant.ResourceLocal {
|
||||||
|
phpPoolDir := path.Join(siteFolder, "php-pool")
|
||||||
|
if err := fileOp.CreateDir(phpPoolDir, 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := fileOp.CreateFile(path.Join(phpPoolDir, "php-fpm.sock")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if website.Type == constant.Static || website.Type == constant.Runtime {
|
||||||
|
if err := createIndexFile(website, runtime); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if website.Type == constant.Proxy {
|
||||||
|
if err := createProxyFile(website, runtime); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,12 +168,12 @@ func createWebsiteFolder(nginxInstall model.AppInstall, website *model.Website)
|
|||||||
return fileOp.CopyDir(path.Join(nginxFolder, "www", "common", "waf", "rules"), path.Join(siteFolder, "waf"))
|
return fileOp.CopyDir(path.Join(nginxFolder, "www", "common", "waf", "rules"), path.Join(siteFolder, "waf"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, appInstall *model.AppInstall) error {
|
func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, appInstall *model.AppInstall, runtime *model.Runtime) error {
|
||||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := createWebsiteFolder(nginxInstall, website); err != nil {
|
if err := createWebsiteFolder(nginxInstall, website, runtime); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,22 +201,38 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
|
|||||||
server.UpdateDirective("set", []string{"$RulePath", path.Join(siteFolder, "waf", "rules")})
|
server.UpdateDirective("set", []string{"$RulePath", path.Join(siteFolder, "waf", "rules")})
|
||||||
server.UpdateDirective("set", []string{"$logdir", path.Join(siteFolder, "log")})
|
server.UpdateDirective("set", []string{"$logdir", path.Join(siteFolder, "log")})
|
||||||
|
|
||||||
|
rootIndex := path.Join("/www/sites", website.Alias, "index")
|
||||||
switch website.Type {
|
switch website.Type {
|
||||||
case constant.Deployment:
|
case constant.Deployment:
|
||||||
proxy := fmt.Sprintf("http://127.0.0.1:%d", appInstall.HttpPort)
|
proxy := fmt.Sprintf("http://127.0.0.1:%d", appInstall.HttpPort)
|
||||||
server.UpdateRootProxy([]string{proxy})
|
server.UpdateRootProxy([]string{proxy})
|
||||||
case constant.Static:
|
case constant.Static:
|
||||||
server.UpdateRoot(path.Join("/www/sites", website.Alias, "index"))
|
server.UpdateRoot(rootIndex)
|
||||||
server.UpdateRootLocation()
|
|
||||||
case constant.Proxy:
|
case constant.Proxy:
|
||||||
server.UpdateRootProxy([]string{website.Proxy})
|
nginxInclude := fmt.Sprintf("/www/sites/%s/proxy/*.conf", website.Alias)
|
||||||
|
server.UpdateDirective("include", []string{nginxInclude})
|
||||||
|
case constant.Runtime:
|
||||||
|
if runtime.Resource == constant.ResourceLocal {
|
||||||
|
switch runtime.Type {
|
||||||
|
case constant.RuntimePHP:
|
||||||
|
server.UpdateRoot(rootIndex)
|
||||||
|
localPath := path.Join(nginxInstall.GetPath(), rootIndex, "index.php")
|
||||||
|
server.UpdatePHPProxy([]string{website.Proxy}, localPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if runtime.Resource == constant.ResourceAppstore {
|
||||||
|
switch runtime.Type {
|
||||||
|
case constant.RuntimePHP:
|
||||||
|
server.UpdateRoot(rootIndex)
|
||||||
|
server.UpdatePHPProxy([]string{website.Proxy}, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config.FilePath = configPath
|
config.FilePath = configPath
|
||||||
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := opNginx(nginxInstall.ContainerName, constant.NginxCheck); err != nil {
|
if err := opNginx(nginxInstall.ContainerName, constant.NginxCheck); err != nil {
|
||||||
_ = deleteWebsiteFolder(nginxInstall, website)
|
_ = deleteWebsiteFolder(nginxInstall, website)
|
||||||
return err
|
return err
|
||||||
@@ -218,7 +301,7 @@ func addListenAndServerName(website model.Website, ports []int, domains []string
|
|||||||
return nginxCheckAndReload(nginxConfig.OldContent, nginxConfig.FilePath, nginxFull.Install.ContainerName)
|
return nginxCheckAndReload(nginxConfig.OldContent, nginxConfig.FilePath, nginxFull.Install.ContainerName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteListenAndServerName(website model.Website, ports []int, domains []string) error {
|
func deleteListenAndServerName(website model.Website, binds []string, domains []string) error {
|
||||||
nginxFull, err := getNginxFull(&website)
|
nginxFull, err := getNginxFull(&website)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -226,8 +309,8 @@ func deleteListenAndServerName(website model.Website, ports []int, domains []str
|
|||||||
nginxConfig := nginxFull.SiteConfig
|
nginxConfig := nginxFull.SiteConfig
|
||||||
config := nginxFull.SiteConfig.Config
|
config := nginxFull.SiteConfig.Config
|
||||||
server := config.FindServers()[0]
|
server := config.FindServers()[0]
|
||||||
for _, port := range ports {
|
for _, bind := range binds {
|
||||||
server.DeleteListen(strconv.Itoa(port))
|
server.DeleteListen(bind)
|
||||||
}
|
}
|
||||||
for _, domain := range domains {
|
for _, domain := range domains {
|
||||||
server.DeleteServerName(domain)
|
server.DeleteServerName(domain)
|
||||||
@@ -289,16 +372,20 @@ func applySSL(website model.Website, websiteSSL model.WebsiteSSL, req request.We
|
|||||||
config := nginxFull.SiteConfig.Config
|
config := nginxFull.SiteConfig.Config
|
||||||
server := config.FindServers()[0]
|
server := config.FindServers()[0]
|
||||||
server.UpdateListen("443", false, "ssl")
|
server.UpdateListen("443", false, "ssl")
|
||||||
|
server.UpdateListen("[::]:443", false, "ssl")
|
||||||
|
|
||||||
switch req.HttpConfig {
|
switch req.HttpConfig {
|
||||||
case constant.HTTPSOnly:
|
case constant.HTTPSOnly:
|
||||||
server.RemoveListenByBind("80")
|
server.RemoveListenByBind("80")
|
||||||
|
server.RemoveListenByBind("[::]:80")
|
||||||
server.RemoveDirective("if", []string{"($scheme"})
|
server.RemoveDirective("if", []string{"($scheme"})
|
||||||
case constant.HTTPToHTTPS:
|
case constant.HTTPToHTTPS:
|
||||||
server.UpdateListen("80", website.DefaultServer)
|
server.UpdateListen("80", website.DefaultServer)
|
||||||
|
server.UpdateListen("[::]:80", false)
|
||||||
server.AddHTTP2HTTPS()
|
server.AddHTTP2HTTPS()
|
||||||
case constant.HTTPAlso:
|
case constant.HTTPAlso:
|
||||||
server.UpdateListen("80", website.DefaultServer)
|
server.UpdateListen("80", website.DefaultServer)
|
||||||
|
server.UpdateListen("[::]:80", false)
|
||||||
server.RemoveDirective("if", []string{"($scheme"})
|
server.RemoveDirective("if", []string{"($scheme"})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,13 +497,32 @@ func opWebsite(website *model.Website, operate string) error {
|
|||||||
}
|
}
|
||||||
server := servers[0]
|
server := servers[0]
|
||||||
if operate == constant.StopWeb {
|
if operate == constant.StopWeb {
|
||||||
if website.Type != constant.Static {
|
proxyInclude := fmt.Sprintf("/www/sites/%s/proxy/*.conf", website.Alias)
|
||||||
|
server.RemoveDirective("include", []string{proxyInclude})
|
||||||
|
rewriteInclude := fmt.Sprintf("/www/sites/%s/rewrite/%s.conf", website.Alias, website.Alias)
|
||||||
|
server.RemoveDirective("include", []string{rewriteInclude})
|
||||||
|
|
||||||
|
switch website.Type {
|
||||||
|
case constant.Deployment:
|
||||||
server.RemoveDirective("location", []string{"/"})
|
server.RemoveDirective("location", []string{"/"})
|
||||||
|
case constant.Runtime:
|
||||||
|
server.RemoveDirective("location", []string{"~", "[^/]\\.php(/|$)"})
|
||||||
}
|
}
|
||||||
server.UpdateRoot("/usr/share/nginx/html/stop")
|
server.UpdateRoot("/usr/share/nginx/html/stop")
|
||||||
website.Status = constant.WebStopped
|
website.Status = constant.WebStopped
|
||||||
}
|
}
|
||||||
if operate == constant.StartWeb {
|
if operate == constant.StartWeb {
|
||||||
|
proxyInclude := fmt.Sprintf("/www/sites/%s/proxy/*.conf", website.Alias)
|
||||||
|
absoluteIncludeDir := path.Join(nginxInstall.Install.GetPath(), fmt.Sprintf("/www/sites/%s/proxy", website.Alias))
|
||||||
|
if files.NewFileOp().Stat(absoluteIncludeDir) {
|
||||||
|
server.UpdateDirective("include", []string{proxyInclude})
|
||||||
|
}
|
||||||
|
server.UpdateDirective("include", []string{proxyInclude})
|
||||||
|
rewriteInclude := fmt.Sprintf("/www/sites/%s/rewrite/%s.conf", website.Alias, website.Alias)
|
||||||
|
absoluteRewritePath := path.Join(nginxInstall.Install.GetPath(), rewriteInclude)
|
||||||
|
if files.NewFileOp().Stat(absoluteRewritePath) {
|
||||||
|
server.UpdateDirective("include", []string{rewriteInclude})
|
||||||
|
}
|
||||||
switch website.Type {
|
switch website.Type {
|
||||||
case constant.Deployment:
|
case constant.Deployment:
|
||||||
server.RemoveDirective("root", nil)
|
server.RemoveDirective("root", nil)
|
||||||
@@ -431,7 +537,14 @@ func opWebsite(website *model.Website, operate string) error {
|
|||||||
server.UpdateRootLocation()
|
server.UpdateRootLocation()
|
||||||
case constant.Proxy:
|
case constant.Proxy:
|
||||||
server.RemoveDirective("root", nil)
|
server.RemoveDirective("root", nil)
|
||||||
server.UpdateRootProxy([]string{website.Proxy})
|
case constant.Runtime:
|
||||||
|
rootIndex := path.Join("/www/sites", website.Alias, "index")
|
||||||
|
server.UpdateRoot(rootIndex)
|
||||||
|
localPath := ""
|
||||||
|
if website.ProxyType == constant.RuntimeProxyUnix {
|
||||||
|
localPath = path.Join(nginxInstall.Install.GetPath(), rootIndex, "index.php")
|
||||||
|
}
|
||||||
|
server.UpdatePHPProxy([]string{website.Proxy}, localPath)
|
||||||
}
|
}
|
||||||
website.Status = constant.WebRunning
|
website.Status = constant.WebRunning
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
@@ -446,3 +559,22 @@ func opWebsite(website *model.Website, operate string) error {
|
|||||||
}
|
}
|
||||||
return nginxCheckAndReload(nginxInstall.SiteConfig.OldContent, config.FilePath, nginxInstall.Install.ContainerName)
|
return nginxCheckAndReload(nginxInstall.SiteConfig.OldContent, config.FilePath, nginxInstall.Install.ContainerName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkIsLinkApp(website model.Website) bool {
|
||||||
|
if website.Type == constant.Deployment {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if website.Type == constant.Runtime {
|
||||||
|
runtime, _ := runtimeRepo.GetFirst(commonRepo.WithByID(website.RuntimeID))
|
||||||
|
return runtime.Resource == constant.ResourceAppstore
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func chownRootDir(path string) error {
|
||||||
|
_, err := cmd.ExecWithTimeOut(fmt.Sprintf("chown -R 1000:1000 %s", path), 1*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package configs
|
|||||||
|
|
||||||
type System struct {
|
type System struct {
|
||||||
Port string `mapstructure:"port"`
|
Port string `mapstructure:"port"`
|
||||||
|
SSL string `mapstructure:"ssl"`
|
||||||
DbFile string `mapstructure:"db_file"`
|
DbFile string `mapstructure:"db_file"`
|
||||||
DbPath string `mapstructure:"db_path"`
|
DbPath string `mapstructure:"db_path"`
|
||||||
LogPath string `mapstructure:"log_path"`
|
LogPath string `mapstructure:"log_path"`
|
||||||
@@ -14,5 +15,8 @@ type System struct {
|
|||||||
Mode string `mapstructure:"mode"`
|
Mode string `mapstructure:"mode"`
|
||||||
RepoUrl string `mapstructure:"repo_url"`
|
RepoUrl string `mapstructure:"repo_url"`
|
||||||
Version string `mapstructure:"version"`
|
Version string `mapstructure:"version"`
|
||||||
|
Username string `mapstructure:"username"`
|
||||||
|
Password string `mapstructure:"password"`
|
||||||
|
Entrance string `mapstructure:"entrance"`
|
||||||
IsDemo bool `mapstructure:"is_demo"`
|
IsDemo bool `mapstructure:"is_demo"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ const (
|
|||||||
AppOpenresty = "openresty"
|
AppOpenresty = "openresty"
|
||||||
AppMysql = "mysql"
|
AppMysql = "mysql"
|
||||||
AppRedis = "redis"
|
AppRedis = "redis"
|
||||||
|
|
||||||
|
AppResourceLocal = "local"
|
||||||
|
AppResourceRemote = "remote"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AppOperate string
|
type AppOperate string
|
||||||
|
|||||||
@@ -8,4 +8,6 @@ const (
|
|||||||
OSS = "OSS"
|
OSS = "OSS"
|
||||||
Sftp = "SFTP"
|
Sftp = "SFTP"
|
||||||
MinIo = "MINIO"
|
MinIo = "MINIO"
|
||||||
|
Cos = "COS"
|
||||||
|
Kodo = "KODO"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,8 +7,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
DataDir = global.CONF.System.DataDir
|
DataDir = global.CONF.System.DataDir
|
||||||
ResourceDir = path.Join(DataDir, "resource")
|
ResourceDir = path.Join(DataDir, "resource")
|
||||||
AppResourceDir = path.Join(ResourceDir, "apps")
|
AppResourceDir = path.Join(ResourceDir, "apps")
|
||||||
AppInstallDir = path.Join(DataDir, "apps")
|
AppInstallDir = path.Join(DataDir, "apps")
|
||||||
|
LocalAppResourceDir = path.Join(ResourceDir, "localApps")
|
||||||
|
LocalAppInstallDir = path.Join(DataDir, "localApps")
|
||||||
|
RuntimeDir = path.Join(DataDir, "runtime")
|
||||||
)
|
)
|
||||||
|
|||||||
+29
-10
@@ -46,6 +46,7 @@ var (
|
|||||||
ErrTypeNotSafety = "ErrNotSafety"
|
ErrTypeNotSafety = "ErrNotSafety"
|
||||||
ErrNameIsExist = "ErrNameIsExist"
|
ErrNameIsExist = "ErrNameIsExist"
|
||||||
ErrDemoEnvironment = "ErrDemoEnvironment"
|
ErrDemoEnvironment = "ErrDemoEnvironment"
|
||||||
|
ErrInitUser = "ErrInitUser"
|
||||||
)
|
)
|
||||||
|
|
||||||
// app
|
// app
|
||||||
@@ -60,17 +61,20 @@ var (
|
|||||||
ErrDbUserNotValid = "ErrDbUserNotValid"
|
ErrDbUserNotValid = "ErrDbUserNotValid"
|
||||||
ErrUpdateBuWebsite = "ErrUpdateBuWebsite"
|
ErrUpdateBuWebsite = "ErrUpdateBuWebsite"
|
||||||
Err1PanelNetworkFailed = "Err1PanelNetworkFailed"
|
Err1PanelNetworkFailed = "Err1PanelNetworkFailed"
|
||||||
|
ErrCmdTimeout = "ErrCmdTimeout"
|
||||||
)
|
)
|
||||||
|
|
||||||
//website
|
// website
|
||||||
var (
|
var (
|
||||||
ErrDomainIsExist = "ErrDomainIsExist"
|
ErrDomainIsExist = "ErrDomainIsExist"
|
||||||
ErrAliasIsExist = "ErrAliasIsExist"
|
ErrAliasIsExist = "ErrAliasIsExist"
|
||||||
ErrAppDelete = "ErrAppDelete"
|
ErrAppDelete = "ErrAppDelete"
|
||||||
ErrGroupIsUsed = "ErrGroupIsUsed"
|
ErrGroupIsUsed = "ErrGroupIsUsed"
|
||||||
|
ErrUsernameIsExist = "ErrUsernameIsExist"
|
||||||
|
ErrUsernameIsNotExist = "ErrUsernameIsNotExist"
|
||||||
)
|
)
|
||||||
|
|
||||||
//ssl
|
// ssl
|
||||||
var (
|
var (
|
||||||
ErrSSLCannotDelete = "ErrSSLCannotDelete"
|
ErrSSLCannotDelete = "ErrSSLCannotDelete"
|
||||||
ErrAccountCannotDelete = "ErrAccountCannotDelete"
|
ErrAccountCannotDelete = "ErrAccountCannotDelete"
|
||||||
@@ -78,7 +82,7 @@ var (
|
|||||||
ErrEmailIsExist = "ErrEmailIsExist"
|
ErrEmailIsExist = "ErrEmailIsExist"
|
||||||
)
|
)
|
||||||
|
|
||||||
//file
|
// file
|
||||||
var (
|
var (
|
||||||
ErrPathNotFound = "ErrPathNotFound"
|
ErrPathNotFound = "ErrPathNotFound"
|
||||||
ErrMovePathFailed = "ErrMovePathFailed"
|
ErrMovePathFailed = "ErrMovePathFailed"
|
||||||
@@ -87,19 +91,34 @@ var (
|
|||||||
ErrFileUpload = "ErrFileUpload"
|
ErrFileUpload = "ErrFileUpload"
|
||||||
)
|
)
|
||||||
|
|
||||||
//mysql
|
// mysql
|
||||||
var (
|
var (
|
||||||
ErrUserIsExist = "ErrUserIsExist"
|
ErrUserIsExist = "ErrUserIsExist"
|
||||||
ErrDatabaseIsExist = "ErrDatabaseIsExist"
|
ErrDatabaseIsExist = "ErrDatabaseIsExist"
|
||||||
|
ErrExecTimeOut = "ErrExecTimeOut"
|
||||||
)
|
)
|
||||||
|
|
||||||
//redis
|
// redis
|
||||||
var (
|
var (
|
||||||
ErrTypeOfRedis = "ErrTypeOfRedis"
|
ErrTypeOfRedis = "ErrTypeOfRedis"
|
||||||
)
|
)
|
||||||
|
|
||||||
//container
|
// container
|
||||||
var (
|
var (
|
||||||
ErrInUsed = "ErrInUsed"
|
ErrInUsed = "ErrInUsed"
|
||||||
ErrObjectInUsed = "ErrObjectInUsed"
|
ErrObjectInUsed = "ErrObjectInUsed"
|
||||||
|
ErrPortRules = "ErrPortRules"
|
||||||
|
)
|
||||||
|
|
||||||
|
// runtime
|
||||||
|
var (
|
||||||
|
ErrDirNotFound = "ErrDirNotFound"
|
||||||
|
ErrFileNotExist = "ErrFileNotExist"
|
||||||
|
ErrImageBuildErr = "ErrImageBuildErr"
|
||||||
|
ErrImageExist = "ErrImageExist"
|
||||||
|
ErrDelWithWebsite = "ErrDelWithWebsite"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrBackupInUsed = "ErrBackupInUsed"
|
||||||
)
|
)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user