mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-19 06:32:59 +08:00
feat: PHP 运行环境增加操作 (#6377)
This commit is contained in:
parent
ba9feb0941
commit
44336c2ea2
@ -260,7 +260,7 @@ func (b *BaseApi) GetRuntimeExtension(c *gin.Context) {
|
||||
// @Summary Install php extension
|
||||
// @Description 安装 PHP 扩展
|
||||
// @Accept json
|
||||
// @Param request body request.PHPExtensionsCreate true "request"
|
||||
// @Param request body request.PHPExtensionInstallReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /runtimes/php/extensions/install [post]
|
||||
@ -276,3 +276,24 @@ func (b *BaseApi) InstallPHPExtension(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags Runtime
|
||||
// @Summary UnInstall php extension
|
||||
// @Description 卸载 PHP 扩展
|
||||
// @Accept json
|
||||
// @Param request body request.PHPExtensionInstallReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /runtimes/php/extensions/uninstall [post]
|
||||
func (b *BaseApi) UnInstallPHPExtension(c *gin.Context) {
|
||||
var req request.PHPExtensionInstallReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
err := runtimeService.UnInstallPHPExtension(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
@ -74,5 +74,5 @@ type NodeModuleReq struct {
|
||||
type PHPExtensionInstallReq struct {
|
||||
ID uint `json:"ID" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
TaskID string `json:"taskID" validate:"required"`
|
||||
TaskID string `json:"taskID"`
|
||||
}
|
||||
|
@ -64,6 +64,7 @@ type SupportExtension struct {
|
||||
Installed bool `json:"installed"`
|
||||
Check string `json:"check"`
|
||||
Versions []string `json:"versions"`
|
||||
File string `json:"file"`
|
||||
}
|
||||
|
||||
type PHPExtensionRes struct {
|
||||
|
@ -50,6 +50,7 @@ type IRuntimeService interface {
|
||||
|
||||
GetPHPExtensions(runtimeID uint) (response.PHPExtensionRes, error)
|
||||
InstallPHPExtension(req request.PHPExtensionInstallReq) error
|
||||
UnInstallPHPExtension(req request.PHPExtensionInstallReq) error
|
||||
}
|
||||
|
||||
func NewRuntimeService() IRuntimeService {
|
||||
@ -380,6 +381,7 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
|
||||
return runtimeRepo.Save(runtime)
|
||||
}
|
||||
oldImage := runtime.Image
|
||||
oldEnv := runtime.Env
|
||||
switch runtime.Type {
|
||||
case constant.RuntimePHP:
|
||||
exist, _ := runtimeRepo.GetFirst(runtimeRepo.WithImage(req.Name), runtimeRepo.WithNotId(req.ID))
|
||||
@ -418,17 +420,10 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
|
||||
}
|
||||
}
|
||||
|
||||
if containerName, ok := req.Params["CONTAINER_NAME"]; ok {
|
||||
envs, err := gotenv.Unmarshal(runtime.Env)
|
||||
if err != nil {
|
||||
if containerName, ok := req.Params["CONTAINER_NAME"]; ok && containerName != getRuntimeEnv(runtime.Env, "CONTAINER_NAME") {
|
||||
if err := checkContainerName(containerName.(string)); err != nil {
|
||||
return err
|
||||
}
|
||||
oldContainerName := envs["CONTAINER_NAME"]
|
||||
if containerName != oldContainerName {
|
||||
if err := checkContainerName(containerName.(string)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
projectDir := path.Join(constant.RuntimeDir, runtime.Type, runtime.Name)
|
||||
@ -466,7 +461,7 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go buildRuntime(runtime, imageID, req.Rebuild)
|
||||
go buildRuntime(runtime, imageID, oldEnv, req.Rebuild)
|
||||
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo:
|
||||
runtime.Version = req.Version
|
||||
runtime.CodeDir = req.CodeDir
|
||||
@ -687,7 +682,6 @@ func (r *RuntimeService) InstallPHPExtension(req request.PHPExtensionInstallReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
installTask, err := task.NewTaskWithOps(req.Name, task.TaskInstall, task.TaskScopeRuntime, req.TaskID, runtime.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -739,3 +733,14 @@ func (r *RuntimeService) InstallPHPExtension(req request.PHPExtensionInstallReq)
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *RuntimeService) UnInstallPHPExtension(req request.PHPExtensionInstallReq) error {
|
||||
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(req.ID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := unInstallPHPExtension(runtime, []string{req.Name}); err != nil {
|
||||
return err
|
||||
}
|
||||
return runtimeRepo.Save(runtime)
|
||||
}
|
||||
|
@ -6,10 +6,13 @@ import (
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto/request"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto/response"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||
"github.com/1Panel-dev/1Panel/agent/cmd/server/nginx_conf"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
cmd2 "github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/compose"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/files"
|
||||
@ -24,6 +27,7 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func handleNodeAndJava(create request.RuntimeCreate, runtime *model.Runtime, fileOp files.FileOp, appVersionDir string) (err error) {
|
||||
@ -86,7 +90,7 @@ func handlePHP(create request.RuntimeCreate, runtime *model.Runtime, fileOp file
|
||||
runtime.Params = string(forms)
|
||||
runtime.Status = constant.RuntimeBuildIng
|
||||
|
||||
go buildRuntime(runtime, "", false)
|
||||
go buildRuntime(runtime, "", "", false)
|
||||
return
|
||||
}
|
||||
|
||||
@ -127,9 +131,9 @@ func reCreateRuntime(runtime *model.Runtime) {
|
||||
}
|
||||
|
||||
func runComposeCmdWithLog(operate string, composePath string, logPath string) error {
|
||||
cmd := exec.Command("docker compose", "-f", composePath, operate)
|
||||
cmd := exec.Command("docker", "compose", "-f", composePath, operate)
|
||||
if operate == "up" {
|
||||
cmd = exec.Command("docker compose", "-f", composePath, operate, "-d")
|
||||
cmd = exec.Command("docker", "compose", "-f", composePath, operate, "-d")
|
||||
}
|
||||
logFile, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
|
||||
if err != nil {
|
||||
@ -191,7 +195,33 @@ func SyncRuntimeContainerStatus(runtime *model.Runtime) error {
|
||||
return runtimeRepo.Save(runtime)
|
||||
}
|
||||
|
||||
func buildRuntime(runtime *model.Runtime, oldImageID string, rebuild bool) {
|
||||
func getRuntimeEnv(envStr, key string) string {
|
||||
env, err := gotenv.Unmarshal(envStr)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
if v, ok := env[key]; ok {
|
||||
return v
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getFileEnv(filePath, key string) (string, error) {
|
||||
envContent, err := files.NewFileOp().GetContent(filePath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
env, err := gotenv.Unmarshal(string(envContent))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if v, ok := env[key]; ok {
|
||||
return v, nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func buildRuntime(runtime *model.Runtime, oldImageID string, oldEnv string, rebuild bool) {
|
||||
runtimePath := runtime.GetPath()
|
||||
composePath := runtime.GetComposePath()
|
||||
logPath := path.Join(runtimePath, "build.log")
|
||||
@ -206,10 +236,9 @@ func buildRuntime(runtime *model.Runtime, oldImageID string, rebuild bool) {
|
||||
}()
|
||||
|
||||
cmd := exec.Command("docker", "compose", "-f", composePath, "build")
|
||||
multiWriterStdout := io.MultiWriter(os.Stdout, logFile)
|
||||
cmd.Stdout = multiWriterStdout
|
||||
cmd.Stdout = logFile
|
||||
var stderrBuf bytes.Buffer
|
||||
multiWriterStderr := io.MultiWriter(&stderrBuf, logFile, os.Stderr)
|
||||
multiWriterStderr := io.MultiWriter(&stderrBuf, logFile)
|
||||
cmd.Stderr = multiWriterStderr
|
||||
|
||||
err = cmd.Run()
|
||||
@ -239,34 +268,44 @@ func buildRuntime(runtime *model.Runtime, oldImageID string, rebuild bool) {
|
||||
}
|
||||
}
|
||||
if rebuild && runtime.ID > 0 {
|
||||
websites, _ := websiteRepo.GetBy(websiteRepo.WithRuntimeID(runtime.ID))
|
||||
if len(websites) > 0 {
|
||||
installService := NewIAppInstalledService()
|
||||
installMap := make(map[uint]string)
|
||||
for _, website := range websites {
|
||||
if website.AppInstallID > 0 {
|
||||
installMap[website.AppInstallID] = website.PrimaryDomain
|
||||
extensionsStr := getRuntimeEnv(runtime.Env, "PHP_EXTENSIONS")
|
||||
extensionsArray := strings.Split(extensionsStr, ",")
|
||||
oldExtensionStr := getRuntimeEnv(oldEnv, "PHP_EXTENSIONS")
|
||||
oldExtensionArray := strings.Split(oldExtensionStr, ",")
|
||||
var delExtensions []string
|
||||
for _, oldExt := range oldExtensionArray {
|
||||
exist := false
|
||||
for _, ext := range extensionsArray {
|
||||
if oldExt == ext {
|
||||
exist = true
|
||||
break
|
||||
}
|
||||
}
|
||||
for installID, domain := range installMap {
|
||||
go func(installID uint, domain string) {
|
||||
global.LOG.Infof("rebuild php runtime [%s] domain [%s]", runtime.Name, domain)
|
||||
if err := installService.Operate(request.AppInstalledOperate{
|
||||
InstallId: installID,
|
||||
Operate: constant.Rebuild,
|
||||
}); err != nil {
|
||||
global.LOG.Errorf("rebuild php runtime [%s] domain [%s] error %v", runtime.Name, domain, err)
|
||||
}
|
||||
}(installID, domain)
|
||||
if !exist {
|
||||
delExtensions = append(delExtensions, oldExt)
|
||||
}
|
||||
}
|
||||
|
||||
if err = unInstallPHPExtension(runtime, delExtensions); err != nil {
|
||||
global.LOG.Errorf("unInstallPHPExtension error %v", err)
|
||||
}
|
||||
}
|
||||
runtime.Status = constant.RuntimeStarting
|
||||
_ = runtimeRepo.Save(runtime)
|
||||
|
||||
if out, err := compose.Up(composePath); err != nil {
|
||||
runtime.Status = constant.RuntimeStartErr
|
||||
runtime.Message = out
|
||||
} else {
|
||||
extensions := getRuntimeEnv(runtime.Env, "PHP_EXTENSIONS")
|
||||
if extensions != "" {
|
||||
installCmd := fmt.Sprintf("docker exec -i %s %s %s", runtime.ContainerName, "install-ext", extensions)
|
||||
err = cmd2.ExecWithLogFile(installCmd, 60*time.Minute, logPath)
|
||||
if err != nil {
|
||||
runtime.Status = constant.RuntimeError
|
||||
runtime.Message = buserr.New(constant.ErrImageBuildErr).Error() + ":" + err.Error()
|
||||
_ = runtimeRepo.Save(runtime)
|
||||
return
|
||||
}
|
||||
}
|
||||
runtime.Status = constant.RuntimeRunning
|
||||
}
|
||||
}
|
||||
@ -446,3 +485,49 @@ func checkContainerName(name string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func unInstallPHPExtension(runtime *model.Runtime, delExtensions []string) error {
|
||||
dir := runtime.GetPath()
|
||||
fileOP := files.NewFileOp()
|
||||
var phpExtensions []response.SupportExtension
|
||||
if err := json.Unmarshal(nginx_conf.PHPExtensionsJson, &phpExtensions); err != nil {
|
||||
return err
|
||||
}
|
||||
delMap := make(map[string]struct{})
|
||||
for _, ext := range phpExtensions {
|
||||
for _, del := range delExtensions {
|
||||
if ext.Check == del {
|
||||
delMap[ext.Check] = struct{}{}
|
||||
_ = fileOP.DeleteFile(path.Join(dir, "extensions", ext.File))
|
||||
_ = fileOP.DeleteFile(path.Join(dir, "conf", "conf.d", "docker-php-ext-"+ext.Check+".ini"))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
extensions := getRuntimeEnv(runtime.Env, "PHP_EXTENSIONS")
|
||||
var (
|
||||
oldExts []string
|
||||
newExts []string
|
||||
)
|
||||
oldExts = strings.Split(extensions, ",")
|
||||
for _, ext := range oldExts {
|
||||
if _, ok := delMap[ext]; !ok {
|
||||
newExts = append(newExts, ext)
|
||||
}
|
||||
}
|
||||
newExtensions := strings.Join(newExts, ",")
|
||||
envs, err := gotenv.Unmarshal(runtime.Env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
envs["PHP_EXTENSIONS"] = newExtensions
|
||||
if err = gotenv.Write(envs, runtime.GetEnvPath()); err != nil {
|
||||
return err
|
||||
}
|
||||
envContent, err := gotenv.Marshal(envs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
runtime.Env = envContent
|
||||
return nil
|
||||
}
|
||||
|
@ -1,135 +1,331 @@
|
||||
[
|
||||
{
|
||||
"name": "ZendGuardLoader",
|
||||
"description": "用于解密ZendGuard加密脚本!",
|
||||
"check": "ZendGuardLoader",
|
||||
"versions": ["53", "54", "55", "56"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "ionCube",
|
||||
"description": "用于解密ionCube Encoder加密脚本!",
|
||||
"check": "ionCube",
|
||||
"check": "ioncube_loader",
|
||||
"file": "ioncube_loader.so",
|
||||
"versions": ["56", "70", "71", "72", "73", "74", "81", "82"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "fileinfo",
|
||||
"description": "",
|
||||
"check": "fileinfo",
|
||||
"versions": ["56", "70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "opcache",
|
||||
"description": "用于加速PHP脚本!",
|
||||
"check": "opcache",
|
||||
"file": "opcache.so",
|
||||
"versions": ["56", "70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "xcache",
|
||||
"description": "支持脚本缓存和变量缓存!",
|
||||
"check": "xcache",
|
||||
"versions": ["56"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "memcache",
|
||||
"description": "强大的内容缓存器",
|
||||
"check": "memcache",
|
||||
"file": "memcache.so",
|
||||
"versions": ["56", "70", "71", "72", "73", "74", "80"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "memcached",
|
||||
"description": "比memcache支持更多高级功能",
|
||||
"check": "memcached",
|
||||
"file": "memcached.so",
|
||||
"versions": ["56", "70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "redis",
|
||||
"description": "基于内存亦可持久化的Key-Value数据库",
|
||||
"check": "redis",
|
||||
"file": "redis.so",
|
||||
"versions": [ "56", "70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "mcrypt",
|
||||
"description": "mcrypt加密/解密",
|
||||
"check": "mcrypt",
|
||||
"file": "mcrypt.so",
|
||||
"versions": ["70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "apcu",
|
||||
"description": "脚本缓存器",
|
||||
"check": "apcu",
|
||||
"file": "apcu.so",
|
||||
"versions": ["56", "70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "imagemagick",
|
||||
"description": "Imagick高性能图形库",
|
||||
"name": "imagick",
|
||||
"check": "imagick",
|
||||
"versions": ["56", "70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"file": "imagick.so",
|
||||
"versions": ["56", "70", "71", "72", "73", "74", "80", "81", "82"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "xdebug",
|
||||
"description": "开源的PHP程序调试器",
|
||||
"check": "xdebug",
|
||||
"file": "xdebug.so",
|
||||
"versions": ["56", "70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "imap",
|
||||
"description": "邮件服务器必备",
|
||||
"check": "imap",
|
||||
"file": "imap.so",
|
||||
"versions": ["56", "70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "exif",
|
||||
"description": "用于读取图片EXIF信息",
|
||||
"check": "exif",
|
||||
"file": "exif.so",
|
||||
"versions": [ "56", "70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "intl",
|
||||
"description": "提供国际化支持",
|
||||
"check": "intl",
|
||||
"file": "intl.so",
|
||||
"versions": ["56", "70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "xsl",
|
||||
"description": "xsl解析扩展",
|
||||
"check": "xsl",
|
||||
"file": "xsl.so",
|
||||
"versions": ["56", "70", "71", "72", "73", "74", "80", "81", "82"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "mbstring",
|
||||
"description": "mbstring扩展",
|
||||
"check": "mbstring",
|
||||
"versions": ["83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "Swoole",
|
||||
"description": "异步、协程高性能网络通信引擎",
|
||||
"check": "swoole",
|
||||
"versions": ["70", "71", "72"],
|
||||
"file": "swoole.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "zstd",
|
||||
"description": "使用 Zstandard 库进行压缩和解压缩的 PHP 扩展",
|
||||
"check": "zstd",
|
||||
"versions": ["70", "71", "72"],
|
||||
"file": "zstd.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "xlswriter",
|
||||
"check": "xlswriter",
|
||||
"file": "xlswriter.so",
|
||||
"versions": ["70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "oci8",
|
||||
"check": "oci8",
|
||||
"file": "oci8.so",
|
||||
"versions": ["70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "pdo_oci",
|
||||
"check": "pdo_oci",
|
||||
"file": "pdo_oci.so",
|
||||
"versions": ["70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "pdo_sqlsrv",
|
||||
"check": "pdo_sqlsrv",
|
||||
"file": "pdo_sqlsrv.so",
|
||||
"versions": ["70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "sqlsrv",
|
||||
"check": "sqlsrv",
|
||||
"file": "sqlsrv.so",
|
||||
"versions": ["70", "71", "72", "73", "74","80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "yaf",
|
||||
"check": "yaf",
|
||||
"file": "yaf.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "mongodb",
|
||||
"check": "mongodb",
|
||||
"file": "mongodb.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "yac",
|
||||
"check": "yac",
|
||||
"file": "yac.so",
|
||||
"versions": ["70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "pgsql",
|
||||
"check": "pgsql",
|
||||
"file": "pgsql.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "ssh2",
|
||||
"check": "ssh2",
|
||||
"file": "ssh2.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "grpc",
|
||||
"check": "grpc",
|
||||
"file": "grpc.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "xhprof",
|
||||
"check": "xhprof",
|
||||
"file": "xhprof.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "protobuf",
|
||||
"check": "protobuf",
|
||||
"file": "protobuf.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "pdo_pgsql",
|
||||
"check": "pdo_pgsql",
|
||||
"file": "pdo_pgsql.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "snmp",
|
||||
"check": "snmp",
|
||||
"file": "snmp.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "ldap",
|
||||
"check": "ldap",
|
||||
"file": "ldap.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "recode",
|
||||
"check": "recode",
|
||||
"file": "recode.so",
|
||||
"versions": ["56","70", "71", "72", "73"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "enchant",
|
||||
"check": "enchant",
|
||||
"file": "enchant.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "pspell",
|
||||
"check": "pspell",
|
||||
"file": "pspell.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "bz2",
|
||||
"check": "bz2",
|
||||
"file": "bz2.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "sysvshm",
|
||||
"check": "sysvshm",
|
||||
"file": "sysvshm.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "calendar",
|
||||
"check": "calendar",
|
||||
"file": "calendar.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "gmp",
|
||||
"check": "gmp",
|
||||
"file": "gmp.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "wddx",
|
||||
"check": "wddx",
|
||||
"file": "wddx.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "sysvmsg",
|
||||
"check": "sysvmsg",
|
||||
"file": "sysvmsg.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "igbinary",
|
||||
"check": "igbinary",
|
||||
"file": "igbinary.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "zmq",
|
||||
"check": "zmq",
|
||||
"file": "zmq.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "smbclient",
|
||||
"check": "smbclient",
|
||||
"file": "smbclient.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "event",
|
||||
"check": "event",
|
||||
"file": "event.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "mailparse",
|
||||
"check": "mailparse",
|
||||
"file": "mailparse.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "yaml",
|
||||
"check": "yaml",
|
||||
"file": "yaml.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
},
|
||||
{
|
||||
"name": "sg11",
|
||||
"check": "SourceGuardian",
|
||||
"file": "sourceguardian.so",
|
||||
"versions": ["56","70", "71", "72", "73", "74", "80", "81", "82", "83"],
|
||||
"installed": false
|
||||
}
|
||||
]
|
||||
|
@ -33,6 +33,7 @@ func (r *RuntimeRouter) InitRouter(Router *gin.RouterGroup) {
|
||||
|
||||
groupRouter.GET("/php/:id/extensions", baseApi.GetRuntimeExtension)
|
||||
groupRouter.POST("/php/extensions/install", baseApi.InstallPHPExtension)
|
||||
groupRouter.POST("/php/extensions/uninstall", baseApi.UnInstallPHPExtension)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -139,6 +139,6 @@ export namespace Runtime {
|
||||
export interface PHPExtensionInstall {
|
||||
name: string;
|
||||
id: number;
|
||||
taskID: string;
|
||||
taskID?: string;
|
||||
}
|
||||
}
|
||||
|
@ -75,3 +75,7 @@ export const GetPHPExtensions = (id: number) => {
|
||||
export const InstallPHPExtension = (req: Runtime.PHPExtensionInstall) => {
|
||||
return http.post(`/runtimes/php/extensions/install`, req);
|
||||
};
|
||||
|
||||
export const UnInstallPHPExtension = (req: Runtime.PHPExtensionInstall) => {
|
||||
return http.post(`/runtimes/php/extensions/uninstall`, req);
|
||||
};
|
||||
|
@ -16,7 +16,7 @@
|
||||
</DrawerHeader>
|
||||
</template>
|
||||
<div>
|
||||
<LogFile :config="config"></LogFile>
|
||||
<LogFile :config="config" :height-diff="config.heightDiff"></LogFile>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</template>
|
||||
@ -39,6 +39,7 @@ interface LogProps {
|
||||
style: string;
|
||||
name: string;
|
||||
tail: boolean;
|
||||
heightDiff: number;
|
||||
}
|
||||
|
||||
const open = ref(false);
|
||||
@ -62,6 +63,7 @@ const loadTooltip = () => {
|
||||
|
||||
const acceptParams = (props: LogProps) => {
|
||||
config.value = props;
|
||||
console.log('config', config.value);
|
||||
open.value = true;
|
||||
|
||||
if (!mobile.value) {
|
||||
|
@ -266,6 +266,7 @@ onUnmounted(() => {
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
console.log(props.heightDiff);
|
||||
initCodemirror();
|
||||
init();
|
||||
});
|
||||
|
@ -9,7 +9,13 @@
|
||||
:width="width"
|
||||
>
|
||||
<div>
|
||||
<highlightjs ref="editorRef" language="JavaScript" :autodetect="false" :code="content"></highlightjs>
|
||||
<highlightjs
|
||||
class="editor-main"
|
||||
ref="editorRef"
|
||||
language="JavaScript"
|
||||
:autodetect="false"
|
||||
:code="content"
|
||||
></highlightjs>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@ -115,6 +121,7 @@ const getContent = (pre: boolean) => {
|
||||
}
|
||||
end.value = res.data.end;
|
||||
nextTick(() => {
|
||||
console.log('scrollerElement', scrollerElement.value);
|
||||
if (pre) {
|
||||
if (scrollerElement.value.scrollHeight > 2000) {
|
||||
scrollerElement.value.scrollTop = 2000;
|
||||
@ -122,6 +129,8 @@ const getContent = (pre: boolean) => {
|
||||
} else {
|
||||
scrollerElement.value.scrollTop = scrollerElement.value.scrollHeight;
|
||||
}
|
||||
console.log('scrollHeight', scrollerElement.value.scrollHeight);
|
||||
console.log('scrollTop', scrollerElement.value.scrollTop);
|
||||
});
|
||||
|
||||
if (readReq.latest) {
|
||||
@ -179,6 +188,7 @@ const initCodemirror = () => {
|
||||
nextTick(() => {
|
||||
if (editorRef.value) {
|
||||
scrollerElement.value = editorRef.value.$el as HTMLElement;
|
||||
console.log('scrollerElement', scrollerElement.value);
|
||||
scrollerElement.value.addEventListener('scroll', function () {
|
||||
if (isScrolledToBottom(scrollerElement.value)) {
|
||||
readReq.page = maxPage.value;
|
||||
@ -194,8 +204,7 @@ const initCodemirror = () => {
|
||||
}
|
||||
});
|
||||
let hljsDom = scrollerElement.value.querySelector('.hljs') as HTMLElement;
|
||||
hljsDom.style['min-height'] = '100px';
|
||||
hljsDom.style['max-height'] = '400px';
|
||||
hljsDom.style['min-height'] = '400px';
|
||||
}
|
||||
});
|
||||
};
|
||||
@ -227,8 +236,11 @@ defineExpose({ openWithResourceID, openWithTaskID });
|
||||
height: calc(var(--dialog-max-height) - var(--dialog-header-height) - var(--dialog-padding) * 2);
|
||||
overflow: hidden;
|
||||
}
|
||||
.log-file {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.editor-main {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
height: 420px;
|
||||
}
|
||||
</style>
|
||||
|
@ -153,6 +153,7 @@ const message = {
|
||||
resetSuccess: 'Reset successful',
|
||||
creatingInfo: 'Creating, no need for this operation',
|
||||
installSuccess: 'Install successful',
|
||||
uninstallSuccess: 'Uninstall successful',
|
||||
},
|
||||
login: {
|
||||
username: 'Username',
|
||||
|
@ -153,6 +153,7 @@ const message = {
|
||||
resetSuccess: '重置成功',
|
||||
creatingInfo: '正在創建,無需此操作',
|
||||
installSuccess: '安裝成功',
|
||||
uninstallSuccess: '卸載成功',
|
||||
},
|
||||
login: {
|
||||
username: '用戶名',
|
||||
|
@ -153,6 +153,7 @@ const message = {
|
||||
resetSuccess: '重置成功',
|
||||
creatingInfo: '正在创建,无需此操作',
|
||||
installSuccess: '安装成功',
|
||||
uninstallSuccess: '卸载成功',
|
||||
},
|
||||
login: {
|
||||
username: '用户名',
|
||||
@ -2265,6 +2266,7 @@ const message = {
|
||||
installExtension: '是否确认安装扩展 {0}',
|
||||
loadedExtension: '已加载扩展',
|
||||
popularExtension: '常用扩展',
|
||||
uninstallExtension: '是否确认卸载扩展 {0}',
|
||||
},
|
||||
process: {
|
||||
pid: '进程ID',
|
||||
|
@ -156,20 +156,6 @@
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<div v-if="mode == 'edit'">
|
||||
<el-form-item>
|
||||
<el-checkbox v-model="runtime.rebuild">
|
||||
{{ $t('runtime.rebuild') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-alert type="info" :closable="false">
|
||||
<span>{{ $t('runtime.rebuildHelper') }}</span>
|
||||
<br />
|
||||
</el-alert>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
@ -410,7 +396,9 @@ const getRuntime = async (id: number) => {
|
||||
forms[fileds[index].key] = fileds[index];
|
||||
}
|
||||
formFields.value = forms;
|
||||
runtime.params['PHP_EXTENSIONS'] = runtime.params['PHP_EXTENSIONS'].split(',');
|
||||
if (data.params['PHP_EXTENSIONS'] != '') {
|
||||
runtime.params['PHP_EXTENSIONS'] = runtime.params['PHP_EXTENSIONS'].split(',');
|
||||
}
|
||||
initParam.value = true;
|
||||
} catch (error) {}
|
||||
};
|
||||
|
@ -9,16 +9,15 @@
|
||||
<el-text>{{ $t('runtime.popularExtension') }}</el-text>
|
||||
</div>
|
||||
<ComplexTable :data="supportExtensions" @search="search()" :heightDiff="350" :loading="loading">
|
||||
<el-table-column prop="name" :label="$t('commons.table.name')" width="150" />
|
||||
<el-table-column prop="description" :label="$t('commons.table.description')" />
|
||||
<el-table-column prop="installed" :label="$t('commons.table.status')" width="100">
|
||||
<el-table-column prop="name" :label="$t('commons.table.name')" />
|
||||
<el-table-column prop="installed" :label="$t('commons.table.status')">
|
||||
<template #default="{ row }">
|
||||
<el-icon v-if="row.installed" color="green"><Select /></el-icon>
|
||||
<el-icon v-else><CloseBold /></el-icon>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<fu-table-operations
|
||||
:ellipsis="10"
|
||||
:ellipsis="2"
|
||||
width="100px"
|
||||
:buttons="buttons"
|
||||
:label="$t('commons.table.operate')"
|
||||
@ -27,15 +26,16 @@
|
||||
/>
|
||||
</ComplexTable>
|
||||
</DrawerPro>
|
||||
<TaskLog ref="taskLogRef" />
|
||||
<TaskLog ref="taskLogRef" @clos="search()" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Runtime } from '@/api/interface/runtime';
|
||||
import { GetPHPExtensions, InstallPHPExtension } from '@/api/modules/runtime';
|
||||
import { GetPHPExtensions, InstallPHPExtension, UnInstallPHPExtension } from '@/api/modules/runtime';
|
||||
import i18n from '@/lang';
|
||||
import { ref } from 'vue';
|
||||
import { newUUID } from '@/utils/util';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
|
||||
const open = ref(false);
|
||||
const runtime = ref();
|
||||
@ -58,6 +58,15 @@ const buttons = [
|
||||
return !row.installed;
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.operate.uninstall'),
|
||||
click: function (row: Runtime.SupportExtension) {
|
||||
unInstallPHPExtension(row);
|
||||
},
|
||||
show: function (row: Runtime.SupportExtension) {
|
||||
return row.installed;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const installExtension = async (row: Runtime.SupportExtension) => {
|
||||
@ -80,6 +89,25 @@ const installExtension = async (row: Runtime.SupportExtension) => {
|
||||
});
|
||||
};
|
||||
|
||||
const unInstallPHPExtension = async (row: Runtime.SupportExtension) => {
|
||||
ElMessageBox.confirm(i18n.global.t('runtime.uninstallExtension', [row.name]), i18n.global.t('runtime.extension'), {
|
||||
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||
}).then(async () => {
|
||||
const req = {
|
||||
id: runtime.value.id,
|
||||
name: row.check,
|
||||
};
|
||||
loading.value = true;
|
||||
try {
|
||||
await UnInstallPHPExtension(req);
|
||||
MsgSuccess(i18n.global.t('commons.msg.uninstallSuccess'));
|
||||
loading.value = false;
|
||||
search();
|
||||
} catch (error) {}
|
||||
});
|
||||
};
|
||||
|
||||
const search = async () => {
|
||||
try {
|
||||
const res = await GetPHPExtensions(runtime.value.id);
|
||||
|
@ -94,7 +94,7 @@
|
||||
/>
|
||||
<fu-table-operations
|
||||
:ellipsis="10"
|
||||
width="200px"
|
||||
width="300px"
|
||||
:buttons="buttons"
|
||||
:label="$t('commons.table.operate')"
|
||||
fixed="right"
|
||||
@ -110,13 +110,14 @@
|
||||
<Extensions ref="extensionsRef" @close="search" />
|
||||
<AppResources ref="checkRef" @close="search" />
|
||||
<ExtManagement ref="extManagementRef" @close="search" />
|
||||
<ComposeLogs ref="composeLogRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, reactive, ref } from 'vue';
|
||||
import { Runtime } from '@/api/interface/runtime';
|
||||
import { DeleteRuntime, RuntimeDeleteCheck, SearchRuntimes } from '@/api/modules/runtime';
|
||||
import { DeleteRuntime, OperateRuntime, RuntimeDeleteCheck, SearchRuntimes } from '@/api/modules/runtime';
|
||||
import { dateFormat, toLowerCase } from '@/utils/util';
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
import { containerPrune } from '@/api/modules/container';
|
||||
@ -129,6 +130,7 @@ import CreateRuntime from '@/views/website/runtime/php/create/index.vue';
|
||||
import Status from '@/components/status/index.vue';
|
||||
import RouterMenu from '../index.vue';
|
||||
import Log from '@/components/log-dialog/index.vue';
|
||||
import ComposeLogs from '@/components/compose-log/index.vue';
|
||||
|
||||
const paginationConfig = reactive({
|
||||
cacheSizeKey: 'runtime-page-size',
|
||||
@ -151,6 +153,7 @@ const checkRef = ref();
|
||||
const createRef = ref();
|
||||
const loading = ref(false);
|
||||
const items = ref<Runtime.RuntimeDTO[]>([]);
|
||||
const composeLogRef = ref();
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
@ -162,6 +165,33 @@ const buttons = [
|
||||
return row.status != 'running';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('container.stop'),
|
||||
click: function (row: Runtime.Runtime) {
|
||||
operateRuntime('down', row.id);
|
||||
},
|
||||
disabled: function (row: Runtime.Runtime) {
|
||||
return row.status === 'recreating' || row.status === 'stopped';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('container.start'),
|
||||
click: function (row: Runtime.Runtime) {
|
||||
operateRuntime('up', row.id);
|
||||
},
|
||||
disabled: function (row: Runtime.Runtime) {
|
||||
return row.status === 'starting' || row.status === 'recreating' || row.status === 'running';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('container.restart'),
|
||||
click: function (row: Runtime.Runtime) {
|
||||
operateRuntime('restart', row.id);
|
||||
},
|
||||
disabled: function (row: Runtime.Runtime) {
|
||||
return row.status === 'recreating';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.edit'),
|
||||
click: function (row: Runtime.Runtime) {
|
||||
@ -205,11 +235,15 @@ const openDetail = (row: Runtime.Runtime) => {
|
||||
};
|
||||
|
||||
const openLog = (row: Runtime.RuntimeDTO) => {
|
||||
logRef.value.acceptParams({ id: row.id, type: 'php', tail: row.status == 'building' });
|
||||
if (row.status == 'running') {
|
||||
composeLogRef.value.acceptParams({ compose: row.path + '/docker-compose.yml', resource: row.name });
|
||||
} else {
|
||||
logRef.value.acceptParams({ id: row.id, type: 'php', tail: row.status == 'building', heightDiff: 220 });
|
||||
}
|
||||
};
|
||||
|
||||
const openCreateLog = (id: number) => {
|
||||
logRef.value.acceptParams({ id: id, type: 'php', tail: true });
|
||||
logRef.value.acceptParams({ id: id, type: 'php', tail: true, heightDiff: 220 });
|
||||
};
|
||||
|
||||
const openExtensions = () => {
|
||||
@ -240,6 +274,28 @@ const openDelete = async (row: Runtime.Runtime) => {
|
||||
});
|
||||
};
|
||||
|
||||
const operateRuntime = async (operate: string, ID: number) => {
|
||||
try {
|
||||
const action = await ElMessageBox.confirm(
|
||||
i18n.global.t('runtime.operatorHelper', [i18n.global.t('commons.operate.' + operate)]),
|
||||
i18n.global.t('commons.operate.' + operate),
|
||||
{
|
||||
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||
type: 'info',
|
||||
},
|
||||
);
|
||||
if (action === 'confirm') {
|
||||
loading.value = true;
|
||||
await OperateRuntime({ operate: operate, ID: ID });
|
||||
search();
|
||||
}
|
||||
} catch (error) {
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onOpenBuildCache = () => {
|
||||
ElMessageBox.confirm(i18n.global.t('container.delBuildCacheHelper'), i18n.global.t('container.cleanBuildCache'), {
|
||||
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||
|
Loading…
Reference in New Issue
Block a user