Skip to content

Commit 8614e63

Browse files
feat: PHP runtime add php config (#8922)
1 parent 470d788 commit 8614e63

File tree

20 files changed

+411
-77
lines changed

20 files changed

+411
-77
lines changed

agent/app/api/v2/runtime.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,3 +493,45 @@ func (b *BaseApi) OperateSupervisorProcessFile(c *gin.Context) {
493493
}
494494
helper.SuccessWithData(c, res)
495495
}
496+
497+
// @Tags Runtime
498+
// @Summary Update PHP container config
499+
// @Accept json
500+
// @Param request body request.PHPContainerUpdate true "request"
501+
// @Success 200
502+
// @Security ApiKeyAuth
503+
// @Security Timestamp
504+
// @Router /runtimes/php/container/update [post]
505+
func (b *BaseApi) UpdatePHPContainer(c *gin.Context) {
506+
var req request.PHPContainerConfig
507+
if err := helper.CheckBindAndValidate(&req, c); err != nil {
508+
return
509+
}
510+
if err := runtimeService.UpdatePHPContainer(req); err != nil {
511+
helper.InternalServer(c, err)
512+
return
513+
}
514+
helper.Success(c)
515+
}
516+
517+
// @Tags Runtime
518+
// @Summary Get PHP container config
519+
// @Accept json
520+
// @Param id path integer true "request"
521+
// @Success 200 {object} response.PHPContainerConfig
522+
// @Security ApiKeyAuth
523+
// @Security Timestamp
524+
// @Router /runtimes/php/container/:id [get]
525+
func (b *BaseApi) GetPHPContainerConfig(c *gin.Context) {
526+
id, err := helper.GetParamID(c)
527+
if err != nil {
528+
helper.BadRequest(c, err)
529+
return
530+
}
531+
data, err := runtimeService.GetPHPContainerConfig(id)
532+
if err != nil {
533+
helper.InternalServer(c, err)
534+
return
535+
}
536+
helper.SuccessWithData(c, data)
537+
}

agent/app/dto/request/runtime.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,11 @@ type PHPSupervisorProcessFileReq struct {
123123
ID uint `json:"id" validate:"required"`
124124
SupervisorProcessFileReq
125125
}
126+
127+
type PHPContainerConfig struct {
128+
ID uint `json:"id" validate:"required"`
129+
ContainerName string `json:"containerName"`
130+
ExposedPorts []ExposedPort `json:"exposedPorts"`
131+
Environments []Environment `json:"environments"`
132+
Volumes []Volume `json:"volumes"`
133+
}

agent/app/model/website_acme_account.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ type WebsiteAcmeAccount struct {
66
URL string `gorm:"not null" json:"url"`
77
PrivateKey string `gorm:"not null" json:"-"`
88
Type string `gorm:"not null;default:letsencrypt" json:"type"`
9-
EabKid string `gorm:"default:null;" json:"eabKid"`
10-
EabHmacKey string `gorm:"default:null" json:"eabHmacKey"`
9+
EabKid string `json:"eabKid"`
10+
EabHmacKey string `json:"eabHmacKey"`
1111
KeyType string `gorm:"not null;default:2048" json:"keyType"`
1212
UseProxy bool `gorm:"default:false" json:"useProxy"`
13-
CaDirURL string `gorm:"default:null" json:"caDirURL"`
13+
CaDirURL string `json:"caDirURL"`
1414
}
1515

1616
func (w WebsiteAcmeAccount) TableName() string {

agent/app/service/runtime.go

Lines changed: 99 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,17 @@ type IRuntimeService interface {
5656
GetPHPExtensions(runtimeID uint) (response.PHPExtensionRes, error)
5757
InstallPHPExtension(req request.PHPExtensionInstallReq) error
5858
UnInstallPHPExtension(req request.PHPExtensionInstallReq) error
59+
5960
GetPHPConfig(id uint) (*response.PHPConfig, error)
6061
UpdatePHPConfig(req request.PHPConfigUpdate) (err error)
6162
UpdatePHPConfigFile(req request.PHPFileUpdate) error
6263
GetPHPConfigFile(req request.PHPFileReq) (*response.FileInfo, error)
6364
UpdateFPMConfig(req request.FPMConfig) error
6465
GetFPMConfig(id uint) (*request.FPMConfig, error)
6566

67+
UpdatePHPContainer(req request.PHPContainerConfig) error
68+
GetPHPContainerConfig(id uint) (*request.PHPContainerConfig, error)
69+
6670
GetSupervisorProcess(id uint) ([]response.SupervisorProcessConfig, error)
6771
OperateSupervisorProcess(req request.PHPSupervisorProcessConfig) error
6872
OperateSupervisorProcessFile(req request.PHPSupervisorProcessFileReq) (string, error)
@@ -383,77 +387,9 @@ func (r *RuntimeService) Get(id uint) (*response.RuntimeDTO, error) {
383387
}
384388
res.AppParams = appParams
385389
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo, constant.RuntimePython, constant.RuntimeDotNet:
386-
res.Params = make(map[string]interface{})
387-
envs, err := gotenv.Unmarshal(runtime.Env)
388-
if err != nil {
390+
if err := handleRuntimeDTO(&res, *runtime); err != nil {
389391
return nil, err
390392
}
391-
for k, v := range envs {
392-
if strings.Contains(k, "CONTAINER_PORT") || strings.Contains(k, "HOST_PORT") {
393-
if strings.Contains(k, "CONTAINER_PORT") {
394-
r := regexp.MustCompile(`_(\d+)$`)
395-
matches := r.FindStringSubmatch(k)
396-
containerPort, err := strconv.Atoi(v)
397-
if err != nil {
398-
return nil, err
399-
}
400-
hostPort, err := strconv.Atoi(envs[fmt.Sprintf("HOST_PORT_%s", matches[1])])
401-
if err != nil {
402-
return nil, err
403-
}
404-
hostIP := envs[fmt.Sprintf("HOST_IP_%s", matches[1])]
405-
if hostIP == "" {
406-
hostIP = "0.0.0.0"
407-
}
408-
res.ExposedPorts = append(res.ExposedPorts, request.ExposedPort{
409-
ContainerPort: containerPort,
410-
HostPort: hostPort,
411-
HostIP: hostIP,
412-
})
413-
}
414-
} else {
415-
res.Params[k] = v
416-
}
417-
}
418-
if v, ok := envs["CONTAINER_PACKAGE_URL"]; ok {
419-
res.Source = v
420-
}
421-
composeByte, err := files.NewFileOp().GetContent(runtime.GetComposePath())
422-
if err != nil {
423-
return nil, err
424-
}
425-
res.Environments, err = getDockerComposeEnvironments(composeByte)
426-
if err != nil {
427-
return nil, err
428-
}
429-
volumes, err := getDockerComposeVolumes(composeByte)
430-
if err != nil {
431-
return nil, err
432-
}
433-
434-
defaultVolumes := make(map[string]string)
435-
switch runtime.Type {
436-
case constant.RuntimeNode:
437-
defaultVolumes = constant.RuntimeDefaultVolumes
438-
case constant.RuntimeJava:
439-
defaultVolumes = constant.RuntimeDefaultVolumes
440-
case constant.RuntimeGo:
441-
defaultVolumes = constant.GoDefaultVolumes
442-
case constant.RuntimePython:
443-
defaultVolumes = constant.RuntimeDefaultVolumes
444-
}
445-
for _, volume := range volumes {
446-
exist := false
447-
for key, value := range defaultVolumes {
448-
if key == volume.Source && value == volume.Target {
449-
exist = true
450-
break
451-
}
452-
}
453-
if !exist {
454-
res.Volumes = append(res.Volumes, volume)
455-
}
456-
}
457393
}
458394

459395
return &res, nil
@@ -1080,6 +1016,100 @@ func (r *RuntimeService) GetFPMConfig(id uint) (*request.FPMConfig, error) {
10801016
return res, nil
10811017
}
10821018

1019+
func (r *RuntimeService) UpdatePHPContainer(req request.PHPContainerConfig) error {
1020+
runtime, err := runtimeRepo.GetFirst(context.Background(), repo.WithByID(req.ID))
1021+
if err != nil {
1022+
return err
1023+
}
1024+
var (
1025+
hostPorts []string
1026+
composeContent []byte
1027+
)
1028+
for _, export := range req.ExposedPorts {
1029+
hostPorts = append(hostPorts, strconv.Itoa(export.HostPort))
1030+
if err = checkRuntimePortExist(export.HostPort, false, runtime.ID); err != nil {
1031+
return err
1032+
}
1033+
}
1034+
if req.ContainerName != "" && req.ContainerName != getRuntimeEnv(runtime.Env, "CONTAINER_NAME") {
1035+
if err := checkContainerName(req.ContainerName); err != nil {
1036+
return err
1037+
}
1038+
runtime.ContainerName = req.ContainerName
1039+
}
1040+
fileOp := files.NewFileOp()
1041+
projectDir := path.Join(global.Dir.RuntimeDir, runtime.Type, runtime.Name)
1042+
composeContent, err = fileOp.GetContent(path.Join(projectDir, "docker-compose.yml"))
1043+
if err != nil {
1044+
return err
1045+
}
1046+
envPath := path.Join(projectDir, ".env")
1047+
if !fileOp.Stat(envPath) {
1048+
_ = fileOp.CreateFile(envPath)
1049+
}
1050+
envs, err := gotenv.Read(envPath)
1051+
if err != nil {
1052+
return err
1053+
}
1054+
for k := range envs {
1055+
if strings.HasPrefix(k, "CONTAINER_PORT_") || strings.HasPrefix(k, "HOST_PORT_") || strings.HasPrefix(k, "HOST_IP_") || strings.Contains(k, "APP_PORT") {
1056+
delete(envs, k)
1057+
}
1058+
}
1059+
create := request.RuntimeCreate{
1060+
Image: runtime.Image,
1061+
Type: runtime.Type,
1062+
Params: make(map[string]interface{}),
1063+
NodeConfig: request.NodeConfig{
1064+
ExposedPorts: req.ExposedPorts,
1065+
Environments: req.Environments,
1066+
Volumes: req.Volumes,
1067+
},
1068+
}
1069+
composeContent, err = handleCompose(envs, composeContent, create, projectDir)
1070+
if err != nil {
1071+
return err
1072+
}
1073+
newMap := make(map[string]string)
1074+
handleMap(create.Params, newMap)
1075+
for k, v := range newMap {
1076+
envs[k] = v
1077+
}
1078+
envStr, err := gotenv.Marshal(envs)
1079+
if err != nil {
1080+
return err
1081+
}
1082+
if err = gotenv.Write(envs, envPath); err != nil {
1083+
return err
1084+
}
1085+
envContent := []byte(envStr)
1086+
runtime.Env = string(envContent)
1087+
runtime.DockerCompose = string(composeContent)
1088+
runtime.Status = constant.StatusReCreating
1089+
_ = runtimeRepo.Save(runtime)
1090+
go reCreateRuntime(runtime)
1091+
return nil
1092+
}
1093+
1094+
func (r *RuntimeService) GetPHPContainerConfig(id uint) (*request.PHPContainerConfig, error) {
1095+
runtime, err := runtimeRepo.GetFirst(context.Background(), repo.WithByID(id))
1096+
if err != nil {
1097+
return nil, err
1098+
}
1099+
runtimeDTO := response.NewRuntimeDTO(*runtime)
1100+
if err := handleRuntimeDTO(&runtimeDTO, *runtime); err != nil {
1101+
return nil, err
1102+
}
1103+
res := &request.PHPContainerConfig{
1104+
ID: runtime.ID,
1105+
ContainerName: runtime.ContainerName,
1106+
ExposedPorts: runtimeDTO.ExposedPorts,
1107+
Environments: runtimeDTO.Environments,
1108+
Volumes: runtimeDTO.Volumes,
1109+
}
1110+
return res, nil
1111+
}
1112+
10831113
func (r *RuntimeService) GetSupervisorProcess(id uint) ([]response.SupervisorProcessConfig, error) {
10841114
runtime, err := runtimeRepo.GetFirst(context.Background(), repo.WithByID(id))
10851115
if err != nil {

agent/app/service/runtime_utils.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import (
1212
"os/exec"
1313
"path"
1414
"path/filepath"
15+
"regexp"
16+
"strconv"
1517
"strings"
1618
"time"
1719

@@ -564,7 +566,14 @@ func handleCompose(env gotenv.Env, composeContent []byte, create request.Runtime
564566
create.Params[hostPortStr] = port.HostPort
565567
create.Params[hostIPStr] = port.HostIP
566568
}
569+
if create.Type == constant.RuntimePHP {
570+
ports = append(ports, fmt.Sprintf("127.0.0.1:${PANEL_APP_PORT_HTTP}:9000"))
571+
}
567572
serviceValue["ports"] = ports
573+
} else {
574+
if create.Type == constant.RuntimePHP {
575+
serviceValue["ports"] = []interface{}{fmt.Sprintf("127.0.0.1:${PANEL_APP_PORT_HTTP}:9000")}
576+
}
568577
}
569578
var environments []interface{}
570579
for _, e := range create.Environments {
@@ -581,6 +590,8 @@ func handleCompose(env gotenv.Env, composeContent []byte, create request.Runtime
581590
defaultVolumes = constant.RuntimeDefaultVolumes
582591
case constant.RuntimeGo:
583592
defaultVolumes = constant.GoDefaultVolumes
593+
case constant.RuntimePHP:
594+
defaultVolumes = constant.PHPDefaultVolumes
584595
}
585596
for k, v := range defaultVolumes {
586597
volumes = append(volumes, fmt.Sprintf("%s:%s", k, v))
@@ -875,3 +886,76 @@ func RestartPHPRuntime() {
875886
}()
876887
}
877888
}
889+
890+
func handleRuntimeDTO(res *response.RuntimeDTO, runtime model.Runtime) error {
891+
res.Params = make(map[string]interface{})
892+
envs, err := gotenv.Unmarshal(runtime.Env)
893+
if err != nil {
894+
return err
895+
}
896+
for k, v := range envs {
897+
if strings.Contains(k, "CONTAINER_PORT") || strings.Contains(k, "HOST_PORT") {
898+
if strings.Contains(k, "CONTAINER_PORT") {
899+
r := regexp.MustCompile(`_(\d+)$`)
900+
matches := r.FindStringSubmatch(k)
901+
containerPort, err := strconv.Atoi(v)
902+
if err != nil {
903+
return err
904+
}
905+
hostPort, err := strconv.Atoi(envs[fmt.Sprintf("HOST_PORT_%s", matches[1])])
906+
if err != nil {
907+
return err
908+
}
909+
hostIP := envs[fmt.Sprintf("HOST_IP_%s", matches[1])]
910+
if hostIP == "" {
911+
hostIP = "0.0.0.0"
912+
}
913+
res.ExposedPorts = append(res.ExposedPorts, request.ExposedPort{
914+
ContainerPort: containerPort,
915+
HostPort: hostPort,
916+
HostIP: hostIP,
917+
})
918+
}
919+
} else {
920+
res.Params[k] = v
921+
}
922+
}
923+
if v, ok := envs["CONTAINER_PACKAGE_URL"]; ok {
924+
res.Source = v
925+
}
926+
composeByte, err := files.NewFileOp().GetContent(runtime.GetComposePath())
927+
if err != nil {
928+
return err
929+
}
930+
res.Environments, err = getDockerComposeEnvironments(composeByte)
931+
if err != nil {
932+
return err
933+
}
934+
volumes, err := getDockerComposeVolumes(composeByte)
935+
if err != nil {
936+
return err
937+
}
938+
939+
defaultVolumes := make(map[string]string)
940+
switch runtime.Type {
941+
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimePython, constant.RuntimeDotNet:
942+
defaultVolumes = constant.RuntimeDefaultVolumes
943+
case constant.RuntimeGo:
944+
defaultVolumes = constant.GoDefaultVolumes
945+
case constant.RuntimePHP:
946+
defaultVolumes = constant.PHPDefaultVolumes
947+
}
948+
for _, volume := range volumes {
949+
exist := false
950+
for key, value := range defaultVolumes {
951+
if key == volume.Source && value == volume.Target {
952+
exist = true
953+
break
954+
}
955+
}
956+
if !exist {
957+
res.Volumes = append(res.Volumes, volume)
958+
}
959+
}
960+
return nil
961+
}

agent/constant/runtime.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,17 @@ var RuntimeDefaultVolumes = map[string]string{
3838
"./run.sh": "/run.sh",
3939
"./.env": "/.env",
4040
}
41+
42+
var PHPDefaultVolumes = map[string]string{
43+
"${PANEL_WEBSITE_DIR}": "/www/",
44+
"./conf": "/usr/local/etc/php",
45+
"./conf/conf.d": "/usr/local/etc/php/conf.d",
46+
"./conf/php-fpm.conf": "/usr/local/etc/php-fpm.d/www.conf",
47+
"./log": "/var/log/php",
48+
"./extensions": "${EXTENSION_DIR}",
49+
"./supervisor/supervisord.conf": "/etc/supervisord.conf",
50+
"./supervisor/supervisor.d/php-fpm.ini": "/etc/supervisor.d/php-fpm.ini",
51+
"./supervisor/supervisor.d": "/etc/supervisor.d",
52+
"./supervisor/log": "/var/log/supervisor",
53+
"./composer": "/tmp/composer",
54+
}

0 commit comments

Comments
 (0)