Skip to content

Commit 6b81ae1

Browse files
feat: Website Add Composer support (#9997)
Refs #6030
1 parent 5b62a0f commit 6b81ae1

File tree

28 files changed

+351
-33
lines changed

28 files changed

+351
-33
lines changed

agent/app/api/v2/website.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,3 +1121,23 @@ func (b *BaseApi) OperateCrossSiteAccess(c *gin.Context) {
11211121
}
11221122
helper.Success(c)
11231123
}
1124+
1125+
// @Tags Website
1126+
// @Summary Exec Composer
1127+
// @Accept json
1128+
// @Param request body request.ExecComposerReq true "request"
1129+
// @Success 200
1130+
// @Security ApiKeyAuth
1131+
// @Security Timestamp
1132+
// @Router /websites/exec/composer [post]
1133+
func (b *BaseApi) ExecComposer(c *gin.Context) {
1134+
var req request.ExecComposerReq
1135+
if err := helper.CheckBindAndValidate(&req, c); err != nil {
1136+
return
1137+
}
1138+
if err := websiteService.ExecComposer(req); err != nil {
1139+
helper.InternalServer(c, err)
1140+
return
1141+
}
1142+
helper.Success(c)
1143+
}

agent/app/dto/request/website.go

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -152,22 +152,22 @@ type WebsiteDomainDelete struct {
152152
}
153153

154154
type WebsiteHTTPSOp struct {
155-
WebsiteID uint `json:"websiteId" validate:"required"`
156-
Enable bool `json:"enable"`
157-
WebsiteSSLID uint `json:"websiteSSLId"`
158-
Type string `json:"type" validate:"oneof=existed auto manual"`
159-
PrivateKey string `json:"privateKey"`
160-
Certificate string `json:"certificate"`
161-
PrivateKeyPath string `json:"privateKeyPath"`
162-
CertificatePath string `json:"certificatePath"`
163-
ImportType string `json:"importType"`
164-
HttpConfig string `json:"httpConfig" validate:"oneof=HTTPSOnly HTTPAlso HTTPToHTTPS"`
165-
SSLProtocol []string `json:"SSLProtocol"`
166-
Algorithm string `json:"algorithm"`
167-
Hsts bool `json:"hsts"`
168-
HstsIncludeSubDomains bool `json:"hstsIncludeSubDomains"`
169-
HttpsPorts []int `json:"httpsPorts"`
170-
Http3 bool `json:"http3"`
155+
WebsiteID uint `json:"websiteId" validate:"required"`
156+
Enable bool `json:"enable"`
157+
WebsiteSSLID uint `json:"websiteSSLId"`
158+
Type string `json:"type" validate:"oneof=existed auto manual"`
159+
PrivateKey string `json:"privateKey"`
160+
Certificate string `json:"certificate"`
161+
PrivateKeyPath string `json:"privateKeyPath"`
162+
CertificatePath string `json:"certificatePath"`
163+
ImportType string `json:"importType"`
164+
HttpConfig string `json:"httpConfig" validate:"oneof=HTTPSOnly HTTPAlso HTTPToHTTPS"`
165+
SSLProtocol []string `json:"SSLProtocol"`
166+
Algorithm string `json:"algorithm"`
167+
Hsts bool `json:"hsts"`
168+
HstsIncludeSubDomains bool `json:"hstsIncludeSubDomains"`
169+
HttpsPorts []int `json:"httpsPorts"`
170+
Http3 bool `json:"http3"`
171171
}
172172

173173
type WebsiteNginxUpdate struct {
@@ -299,3 +299,13 @@ type CrossSiteAccessOp struct {
299299
WebsiteID uint `json:"websiteID" validate:"required"`
300300
Operation string `json:"operation" validate:"required,oneof=Enable Disable"`
301301
}
302+
303+
type ExecComposerReq struct {
304+
Command string `json:"command" validate:"required"`
305+
ExtCommand string `json:"extCommand"`
306+
Mirror string `json:"mirror" validate:"required"`
307+
Dir string `json:"dir" validate:"required"`
308+
User string `json:"user" validate:"required"`
309+
WebsiteID uint `json:"websiteID" validate:"required"`
310+
TaskID string `json:"taskID" validate:"required"`
311+
}

agent/app/service/website.go

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ type IWebsiteService interface {
126126
ChangeDatabase(req request.ChangeDatabase) error
127127

128128
OperateCrossSiteAccess(req request.CrossSiteAccessOp) error
129+
130+
ExecComposer(req request.ExecComposerReq) error
129131
}
130132

131133
func NewIWebsiteService() IWebsiteService {
@@ -466,15 +468,15 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
466468
website.Protocol = constant.ProtocolHTTPS
467469
website.WebsiteSSLID = create.WebsiteSSLID
468470
appSSLReq := request.WebsiteHTTPSOp{
469-
WebsiteID: website.ID,
470-
Enable: true,
471-
WebsiteSSLID: websiteModel.ID,
472-
Type: "existed",
473-
HttpConfig: "HTTPToHTTPS",
474-
SSLProtocol: []string{"TLSv1.3", "TLSv1.2"},
475-
Algorithm: "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED",
476-
Hsts: true,
477-
HstsIncludeSubDomains: true,
471+
WebsiteID: website.ID,
472+
Enable: true,
473+
WebsiteSSLID: websiteModel.ID,
474+
Type: "existed",
475+
HttpConfig: "HTTPToHTTPS",
476+
SSLProtocol: []string{"TLSv1.3", "TLSv1.2"},
477+
Algorithm: "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED",
478+
Hsts: true,
479+
HstsIncludeSubDomains: true,
478480
}
479481
if err = applySSL(website, *websiteModel, appSSLReq); err != nil {
480482
return err
@@ -960,7 +962,6 @@ func (w WebsiteService) GetWebsiteHTTPS(websiteId uint) (response.WebsiteHTTPS,
960962
if p.Name == "add_header" && len(p.Params) > 0 {
961963
if p.Params[0] == "Strict-Transport-Security" {
962964
res.Hsts = true
963-
//增加HSTS下子域名检查逻辑
964965
if len(p.Params) > 1 {
965966
hstsValue := p.Params[1]
966967
if strings.Contains(hstsValue, "includeSubDomains") {
@@ -3319,3 +3320,50 @@ func (w WebsiteService) OperateCrossSiteAccess(req request.CrossSiteAccessOp) er
33193320
}
33203321
return nil
33213322
}
3323+
3324+
func (w WebsiteService) ExecComposer(req request.ExecComposerReq) error {
3325+
website, err := websiteRepo.GetFirst(repo.WithByID(req.WebsiteID))
3326+
if err != nil {
3327+
return err
3328+
}
3329+
sitePath := GetSitePath(website, SiteDir)
3330+
if !strings.Contains(req.Dir, sitePath) {
3331+
return buserr.New("ErrWebsiteDir")
3332+
}
3333+
if !files.NewFileOp().Stat(path.Join(req.Dir, "composer.json")) {
3334+
return buserr.New("ErrComposerFileNotFound")
3335+
}
3336+
if task.CheckResourceTaskIsExecuting(task.TaskExec, req.Command, website.ID) {
3337+
return buserr.New("ErrInstallExtension")
3338+
}
3339+
runtime, err := runtimeRepo.GetFirst(context.Background(), repo.WithByID(website.RuntimeID))
3340+
if err != nil {
3341+
return err
3342+
}
3343+
var command string
3344+
if req.Command != "custom" {
3345+
command = fmt.Sprintf("%s %s", req.Command, req.ExtCommand)
3346+
} else {
3347+
command = req.ExtCommand
3348+
}
3349+
resourceName := fmt.Sprintf("composer %s", command)
3350+
composerTask, err := task.NewTaskWithOps(resourceName, task.TaskExec, req.Command, req.TaskID, website.ID)
3351+
if err != nil {
3352+
return err
3353+
}
3354+
cmdMgr := cmd.NewCommandMgr(cmd.WithTask(*composerTask), cmd.WithTimeout(20*time.Minute))
3355+
siteDir, _ := settingRepo.Get(settingRepo.WithByKey("WEBSITE_DIR"))
3356+
execDir := strings.ReplaceAll(req.Dir, siteDir.Value, "/www")
3357+
composerTask.AddSubTask("", func(t *task.Task) error {
3358+
cmdStr := fmt.Sprintf("docker exec -u %s %s sh -c 'composer config -g repo.packagist composer %s && composer %s --working-dir=%s'", req.User, runtime.ContainerName, req.Mirror, command, execDir)
3359+
err = cmdMgr.RunBashCf(cmdStr)
3360+
if err != nil {
3361+
return err
3362+
}
3363+
return nil
3364+
}, nil)
3365+
go func() {
3366+
_ = composerTask.Execute()
3367+
}()
3368+
return nil
3369+
}

agent/app/task/task.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ const (
6767
TaskPush = "TaskPush"
6868
TaskClean = "TaskClean"
6969
TaskHandle = "TaskHandle"
70+
TaskExec = "TaskExec"
7071
)
7172

7273
const (

agent/i18n/lang/en.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ ErrBuildDirNotFound: 'The build directory does not exist'
123123
ErrImageNotExist: 'The operating environment {{ .name }} image does not exist, please re-edit the operating environment'
124124
ErrProxyIsUsed: "Load balancing has been used by reverse proxy, cannot be deleted"
125125
ErrSSLValid: 'Certificate file is abnormal, please check the certificate status!'
126+
ErrWebsiteDir: "Please select a directory within the website directory."
127+
ErrComposerFileNotFound: "composer.json file does not exist"
126128

127129
#ssl
128130
ErrSSLCannotDelete: 'The {{ .name }} certificate is being used by a website and cannot be deleted'
@@ -328,6 +330,7 @@ SubTask: 'Subtask'
328330
RuntimeExtension: 'Runtime Environment Extension'
329331
TaskIsExecuting: 'Task is running'
330332
CustomAppstore: 'Custom application warehouse'
333+
TaskExec: 'Execute'
331334

332335
# task - ai
333336
OllamaModelPull: 'Pull Ollama model {{ .name }}'

agent/i18n/lang/ja.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ ErrBuildDirNotFound: 'ビルド ディレクトリが存在しません'
123123
ErrImageNotExist: 'オペレーティング環境 {{ .name }} イメージが存在しません。オペレーティング環境を再編集してください'
124124
ErrProxyIsUsed: "ロードバランシングはリバースプロキシによって使用されているため、削除できません"
125125
ErrSSLValid: '証明書ファイルが異常です、証明書の状態を確認してください!'
126+
ErrWebsiteDir: "ウェブサイトディレクトリ内のディレクトリを選択してください。"
127+
ErrComposerFileNotFound: "composer.json ファイルが存在しません"
126128

127129
#ssl
128130
ErrSSLCannotDelete: '{{ .name }} 証明書は Web サイトで使用されているため、削除できません'
@@ -328,6 +330,7 @@ SubTask: 'サブタスク'
328330
RuntimeExtension: 'ランタイム環境拡張'
329331
TaskIsExecuting: 'タスクは実行中です'
330332
CustomAppstore: 'カスタム アプリケーション ウェアハウス'
333+
TaskExec: '実行'
331334

332335
#task - ai
333336
OllamaModelPull: 'Ollama モデル {{ .name }} をプルします'

agent/i18n/lang/ko.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ ErrBuildDirNotFound: '빌드 디렉토리가 존재하지 않습니다'
123123
ErrImageNotExist: '운영 환경 {{ .name }} 이미지가 존재하지 않습니다. 운영 환경을 다시 편집하세요.'
124124
ErrProxyIsUsed: "로드 밸런싱이 역방향 프록시에 의해 사용되었으므로 삭제할 수 없습니다"
125125
ErrSSLValid: '인증서 파일에 문제가 있습니다. 인증서 상태를 확인하세요!'
126+
ErrWebsiteDir: "웹사이트 디렉토리 내의 디렉토리를 선택하세요."
127+
ErrComposerFileNotFound: "composer.json 파일이 존재하지 않습니다"
126128

127129
#SSL인증
128130
ErrSSLCannotDelete: '{{ .name }} 인증서는 웹사이트에서 사용 중이므로 삭제할 수 없습니다.'
@@ -328,6 +330,7 @@ SubTask: '하위 작업'
328330
RuntimeExtension: '런타임 환경 확장'
329331
TaskIsExecuting: '작업이 실행 중입니다'
330332
CustomAppstore: '사용자 정의 애플리케이션 웨어하우스'
333+
TaskExec": '실행'
331334

332335
# 작업 - ai
333336
OllamaModelPull: 'Ollama 모델 {{ .name }}을(를) 끌어오세요'

agent/i18n/lang/ms.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ ErrBuildDirNotFound: 'Direktori binaan tidak wujud'
122122
ErrImageNotExist: 'Imej persekitaran operasi {{ .name }} tidak wujud, sila edit semula persekitaran pengendalian'
123123
ErrProxyIsUsed: "Pengimbang beban telah digunakan oleh pengganti terbalik, tidak boleh dipadamkan"
124124
ErrSSLValid: 'Fail sijil bermasalah, sila periksa status sijil!'
125+
ErrWebsiteDir: "Sila pilih direktori dalam direktori laman web."
126+
ErrComposerFileNotFound: "Fail composer.json tidak wujud"
125127

126128
#ssl
127129
ErrSSLCannotDelete: 'Sijil {{ .name }} sedang digunakan oleh tapak web dan tidak boleh dipadamkan'
@@ -327,6 +329,7 @@ SubTask: 'Subtugas'
327329
RuntimeExtension: 'Sambungan Persekitaran Runtime'
328330
TaskIsExecuting: 'Tugas sedang berjalan'
329331
CustomAppstore: 'Gudang aplikasi tersuai'
332+
TaskExec: 'Laksanakan'
330333

331334
# tugasan - ai
332335
OllamaModelPull: 'Tarik model Ollama {{ .name }}'

agent/i18n/lang/pt-BR.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ ErrBuildDirNotFound: 'O diretório de compilação não existe'
123123
ErrImageNotExist: 'A imagem do ambiente operacional {{ .name }} não existe, edite novamente o ambiente operacional'
124124
ErrProxyIsUsed: "Balanceamento de carga foi usado por proxy reverso, não pode ser excluído"
125125
ErrSSLValid: 'O arquivo do certificado está anormal, verifique o status do certificado!'
126+
ErrWebsiteDir: "Por favor, selecione um diretório dentro do diretório do site."
127+
ErrComposerFileNotFound: "O arquivo composer.json não existe"
126128

127129
#ssl
128130
ErrSSLCannotDelete: 'O certificado {{ .name }} está sendo usado por um site e não pode ser excluído'
@@ -328,6 +330,7 @@ SubTask: 'Subtarefa'
328330
RuntimeExtension: 'Extensão do ambiente de tempo de execução'
329331
TaskIsExecuting: 'A tarefa está em execução'
330332
CustomAppstore: 'Armazém de aplicativos personalizados'
333+
TaskExec: 'Executar'
331334

332335
# tarefa - ai
333336
OllamaModelPull: 'Puxar modelo Ollama {{ .name }}'

agent/i18n/lang/ru.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ ErrBuildDirNotFound: 'Каталог сборки не существует'
123123
ErrImageNotExist: 'Образ операционной среды {{ .name }} не существует, пожалуйста, отредактируйте операционную среду заново'
124124
ErrProxyIsUsed: "Балансировка нагрузки используется обратным прокси, невозможно удалить"
125125
ErrSSLValid: 'Файл сертификата аномален, проверьте статус сертификата!'
126+
ErrWebsiteDir: "Пожалуйста, выберите директорию внутри директории сайта."
127+
ErrComposerFileNotFound: "Файл composer.json не существует"
126128

127129
#ssl
128130
ErrSSLCannotDelete: 'Сертификат {{ .name }} используется веб-сайтом и не может быть удален'
@@ -328,6 +330,7 @@ SubTask: 'Подзадача'
328330
RuntimeExtension: 'Расширение среды выполнения'
329331
TaskIsExecuting: 'Задача выполняется'
330332
CustomAppstore: 'Хранилище пользовательских приложений'
333+
TaskExec: 'Выполнить'
331334

332335
# задача - ай
333336
OllamaModelPull: 'Вытянуть модель Ollama {{ .name }}'

0 commit comments

Comments
 (0)