feat: 增加wordpress应用
This commit is contained in:
committed by
zhengkunwang223
parent
362d2d2616
commit
dc70d7cfc1
4
apps/docker-compose.common.yml
Normal file
4
apps/docker-compose.common.yml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
version: '3'
|
||||||
|
networks:
|
||||||
|
1panel:
|
||||||
|
driver: bridge
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
"type": "internal",
|
"type": "internal",
|
||||||
"required": [""],
|
"required": [""],
|
||||||
"crossVersionUpdate": false,
|
"crossVersionUpdate": false,
|
||||||
|
"limit": 0,
|
||||||
"source": "https://www.mysql.com"
|
"source": "https://www.mysql.com"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -38,8 +39,23 @@
|
|||||||
"author": "Nginx",
|
"author": "Nginx",
|
||||||
"type": "internal",
|
"type": "internal",
|
||||||
"required": [""],
|
"required": [""],
|
||||||
|
"limit": 0,
|
||||||
"crossVersionUpdate": true,
|
"crossVersionUpdate": true,
|
||||||
"source": "http://nginx.org/"
|
"source": "http://nginx.org/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "wordpress",
|
||||||
|
"name": "Wordpress",
|
||||||
|
"tags": ["WebSite"],
|
||||||
|
"versions": ["6.0.1"],
|
||||||
|
"short_desc": "老牌博客网站模版",
|
||||||
|
"icon": "wordpress.png",
|
||||||
|
"author": "Wordpress",
|
||||||
|
"type": "internal",
|
||||||
|
"required": ["mysql"],
|
||||||
|
"limit": 0,
|
||||||
|
"crossVersionUpdate": true,
|
||||||
|
"source": "http://wordpress.org/"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,8 @@ services:
|
|||||||
MYSQL_USER: ${USER}
|
MYSQL_USER: ${USER}
|
||||||
MYSQL_PASSWORD: ${PASSWORD}
|
MYSQL_PASSWORD: ${PASSWORD}
|
||||||
MYSQL_ROOT_PASSWORD: ${ROOT_PASSWORD}
|
MYSQL_ROOT_PASSWORD: ${ROOT_PASSWORD}
|
||||||
|
networks:
|
||||||
|
- 1panel
|
||||||
ports:
|
ports:
|
||||||
- ${PORT}:3306
|
- ${PORT}:3306
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
@@ -1,83 +1,13 @@
|
|||||||
|
|
||||||
[client]
|
|
||||||
port = 3306
|
|
||||||
socket = /var/run/mysqld/mysqld.sock
|
|
||||||
|
|
||||||
[mysqld_safe]
|
|
||||||
socket = /var/run/mysqld/mysqld.sock
|
|
||||||
nice = 0
|
|
||||||
|
|
||||||
[mysqld]
|
[mysqld]
|
||||||
user = mysql
|
skip-host-cache
|
||||||
pid-file = /var/run/mysqld/mysqld.pid
|
skip-name-resolve
|
||||||
socket = /var/run/mysqld/mysqld.sock
|
datadir=/var/lib/mysql
|
||||||
port = 3306
|
socket=/var/run/mysqld/mysqld.sock
|
||||||
basedir = /usr
|
secure-file-priv=/var/lib/mysql-files
|
||||||
datadir = /var/lib/mysql
|
user=mysql
|
||||||
tmpdir = /tmp
|
|
||||||
lc-messages-dir = /usr/share/mysql
|
|
||||||
skip-external-locking
|
|
||||||
skip-character-set-client-handshake
|
|
||||||
default-storage-engine = InnoDB
|
|
||||||
character-set-server = utf8
|
|
||||||
transaction-isolation = READ-COMMITTED
|
|
||||||
|
|
||||||
|
pid-file=/var/run/mysqld/mysqld.pid
|
||||||
|
[client]
|
||||||
|
socket=/var/run/mysqld/mysqld.sock
|
||||||
|
|
||||||
bind-address = 127.0.0.1
|
!includedir /etc/mysql/conf.d/
|
||||||
key_buffer = 16M
|
|
||||||
max_allowed_packet = 16M
|
|
||||||
thread_stack = 192K
|
|
||||||
thread_cache_size = 16
|
|
||||||
myisam-recover = BACKUP
|
|
||||||
max_connections = 300
|
|
||||||
table_open_cache = 64
|
|
||||||
thread_concurrency = 10
|
|
||||||
table_open_cache = 32
|
|
||||||
thread_concurrency = 4
|
|
||||||
|
|
||||||
query_cache_type = 1
|
|
||||||
query_cache_limit = 1M
|
|
||||||
query_cache_size = 8M
|
|
||||||
general_log_file = /var/log/mysql/mysql.log
|
|
||||||
#general_log = 1
|
|
||||||
log_error = /var/log/mysql/error.log
|
|
||||||
|
|
||||||
slow_query_log = 1
|
|
||||||
slow_query_log_file = /var/log/mysql/mysql-slow.log
|
|
||||||
long_query_time = 1
|
|
||||||
#log-queries-not-using-indexes
|
|
||||||
|
|
||||||
|
|
||||||
#server-id = 1
|
|
||||||
#log_bin = /var/log/mysql/mysql-bin.log
|
|
||||||
expire_logs_days = 14
|
|
||||||
max_binlog_size = 1G
|
|
||||||
#binlog_do_db = include_database_name
|
|
||||||
#binlog_ignore_db = include_database_name
|
|
||||||
|
|
||||||
|
|
||||||
# ssl-ca=/etc/mysql/cacert.pem
|
|
||||||
# ssl-cert=/etc/mysql/server-cert.pem
|
|
||||||
# ssl-key=/etc/mysql/server-key.pem
|
|
||||||
innodb_data_file_path = ibdata1:128M:autoextend
|
|
||||||
innodb_file_per_table = 1
|
|
||||||
skip-innodb_doublewrite
|
|
||||||
innodb_additional_mem_pool_size = 12M
|
|
||||||
innodb_buffer_pool_size = 256M
|
|
||||||
innodb_log_buffer_size = 8M
|
|
||||||
innodb_log_file_size = 8M
|
|
||||||
innodb_flush_log_at_trx_commit = 0
|
|
||||||
innodb_flush_method = O_DIRECT
|
|
||||||
innodb_support_xa = OFF
|
|
||||||
|
|
||||||
|
|
||||||
[mysqldump]
|
|
||||||
quick
|
|
||||||
quote-names
|
|
||||||
max_allowed_packet = 16M
|
|
||||||
|
|
||||||
[mysql]
|
|
||||||
#no-auto-rehash # faster start of mysql but no tab completition
|
|
||||||
|
|
||||||
[isamchk]
|
|
||||||
key_buffer = 16M
|
|
||||||
@@ -11,14 +11,15 @@ services:
|
|||||||
MYSQL_USER: ${USER}
|
MYSQL_USER: ${USER}
|
||||||
MYSQL_PASSWORD: ${PASSWORD}
|
MYSQL_PASSWORD: ${PASSWORD}
|
||||||
MYSQL_ROOT_PASSWORD: ${ROOT_PASSWORD}
|
MYSQL_ROOT_PASSWORD: ${ROOT_PASSWORD}
|
||||||
|
networks:
|
||||||
|
- 1panel
|
||||||
ports:
|
ports:
|
||||||
- ${PORT}:3306
|
- ${PORT}:3306
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/:/var/lib/mysql
|
- ./data/:/var/lib/mysql
|
||||||
- ./conf/my.cnf:/etc/mysql/my.cnf
|
- ./conf/my.cnf:/etc/my.cnf
|
||||||
- ./log:/var/log/mysql
|
- ./log:/var/log/mysql
|
||||||
command:
|
|
||||||
--character-set-server=utf8mb4
|
networks:
|
||||||
--collation-server=utf8mb4_general_ci
|
1panel:
|
||||||
--explicit_defaults_for_timestamp=true
|
external: true
|
||||||
--lower_case_table_names=1
|
|
||||||
@@ -4,17 +4,17 @@ services:
|
|||||||
image: wordpress:6.0.1
|
image: wordpress:6.0.1
|
||||||
container_name: 1panel_wordpress
|
container_name: 1panel_wordpress
|
||||||
ports:
|
ports:
|
||||||
- "8080:80"
|
- ${PORT}:80
|
||||||
restart: always
|
restart: always
|
||||||
networks:
|
networks:
|
||||||
- 1panel
|
- 1panel
|
||||||
volumes:
|
volumes:
|
||||||
- ./data:/var/www/html
|
- ./data:/var/www/html
|
||||||
environment:
|
environment:
|
||||||
WORDPRESS_DB_HOST: 1panel_mysql
|
WORDPRESS_DB_HOST: ${WORDPRESS_DB_HOST}
|
||||||
WORDPRESS_DB_NAME: wpdb
|
WORDPRESS_DB_NAME: ${WORDPRESS_DB_NAME}
|
||||||
WORDPRESS_DB_USER: root
|
WORDPRESS_DB_USER: ${WORDPRESS_DB_USER}
|
||||||
WORDPRESS_DB_PASSWORD: Password@123
|
WORDPRESS_DB_PASSWORD: ${WORDPRESS_DB_PASSWORD}
|
||||||
WORDPRESS_DEBUG: 1
|
WORDPRESS_DEBUG: 1
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
45
apps/wordpress/6.0.1/params.json
Normal file
45
apps/wordpress/6.0.1/params.json
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"formFields": [
|
||||||
|
{
|
||||||
|
"type": "service",
|
||||||
|
"key": "mysql",
|
||||||
|
"labelZh": "数据库服务",
|
||||||
|
"labelEn": "Database Service",
|
||||||
|
"required": true,
|
||||||
|
"default": "1Panel-mysql",
|
||||||
|
"envKey": "WORDPRESS_DB_HOST"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"labelZh": "数据库名",
|
||||||
|
"labelEn": "Database",
|
||||||
|
"required": true,
|
||||||
|
"default": "db",
|
||||||
|
"envKey": "WORDPRESS_DB_NAME"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"labelZh": "数据库用户",
|
||||||
|
"labelEn": "User",
|
||||||
|
"required": true,
|
||||||
|
"default": "wordpress_user",
|
||||||
|
"envKey": "WORDPRESS_DB_USER"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"labelZh": "数据库用户密码",
|
||||||
|
"labelEn": "Password",
|
||||||
|
"required": true,
|
||||||
|
"default": "1qaz@WSX",
|
||||||
|
"envKey": "WORDPRESS_DB_PASSWORD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"labelZh": "端口",
|
||||||
|
"labelEn": "Port",
|
||||||
|
"required": true,
|
||||||
|
"default": 8080,
|
||||||
|
"envKey": "PORT"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -114,3 +114,15 @@ func (b *BaseApi) InstalledSync(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
helper.SuccessWithData(c, "")
|
helper.SuccessWithData(c, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *BaseApi) GetServices(c *gin.Context) {
|
||||||
|
|
||||||
|
key := c.Param("key")
|
||||||
|
services, err := appService.GetServices(key)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, services)
|
||||||
|
}
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ type AppInstallRequest struct {
|
|||||||
AppDetailId uint `json:"appDetailId" validate:"required"`
|
AppDetailId uint `json:"appDetailId" validate:"required"`
|
||||||
Params map[string]interface{} `json:"params"`
|
Params map[string]interface{} `json:"params"`
|
||||||
Name string `json:"name" validate:"required"`
|
Name string `json:"name" validate:"required"`
|
||||||
|
Services map[string]string `json:"services"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppInstalled struct {
|
type AppInstalled struct {
|
||||||
@@ -106,10 +107,7 @@ type AppInstallOperate struct {
|
|||||||
Operate AppOperate `json:"operate" validate:"required"`
|
Operate AppOperate `json:"operate" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//type AppContainer struct {
|
type AppService struct {
|
||||||
// Names []string `json:"names"`
|
Label string `json:"label"`
|
||||||
// Image string `json:"image"`
|
Value string `json:"value"`
|
||||||
// Ports string `json:"ports"`
|
}
|
||||||
// Status string `json:"status"`
|
|
||||||
// State string `json:"state"`
|
|
||||||
//}
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ type App struct {
|
|||||||
Status string `json:"status" gorm:"type:varchar(64);not null"`
|
Status string `json:"status" gorm:"type:varchar(64);not null"`
|
||||||
Required string `json:"required" gorm:"type:varchar(64);not null"`
|
Required string `json:"required" gorm:"type:varchar(64);not null"`
|
||||||
CrossVersionUpdate bool `json:"crossVersionUpdate"`
|
CrossVersionUpdate bool `json:"crossVersionUpdate"`
|
||||||
|
Limit int `json:"limit" gorm:"type:Integer;not null"`
|
||||||
Details []AppDetail `json:"-"`
|
Details []AppDetail `json:"-"`
|
||||||
TagsKey []string `json:"-" gorm:"-"`
|
TagsKey []string `json:"-" gorm:"-"`
|
||||||
AppTags []AppTag `json:"-" `
|
AppTags []AppTag `json:"-" `
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ package model
|
|||||||
|
|
||||||
type AppContainer struct {
|
type AppContainer struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
ServiceName string `json:"serviceName"`
|
ServiceName string `json:"serviceName" gorm:"type:varchar(64);not null"`
|
||||||
ContainerName string `json:"containerName"`
|
ContainerName string `json:"containerName" gorm:"type:varchar(64);not null"`
|
||||||
AppInstallId uint `json:"appInstallId"`
|
AppInstallId uint `json:"appInstallId" gorm:"type:integer;not null"`
|
||||||
|
Port int `json:"port" gorm:"type:integer;not null"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package model
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/1Panel-dev/1Panel/global"
|
"github.com/1Panel-dev/1Panel/global"
|
||||||
|
"gorm.io/gorm"
|
||||||
"path"
|
"path"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,10 +21,19 @@ type AppInstall struct {
|
|||||||
Containers []AppContainer `json:"containers"`
|
Containers []AppContainer `json:"containers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i AppInstall) GetPath() string {
|
func (i *AppInstall) GetPath() string {
|
||||||
return path.Join(global.CONF.System.AppDir, i.App.Key, i.Name)
|
return path.Join(global.CONF.System.AppDir, i.App.Key, i.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i AppInstall) GetComposePath() string {
|
func (i *AppInstall) GetComposePath() string {
|
||||||
return path.Join(global.CONF.System.AppDir, i.App.Key, i.Name, "docker-compose.yml")
|
return path.Join(global.CONF.System.AppDir, i.App.Key, i.Name, "docker-compose.yml")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *AppInstall) BeforeDelete(tx *gorm.DB) (err error) {
|
||||||
|
|
||||||
|
if err = tx.Where("app_install_id = ?", i.ID).Delete(&AppContainer{}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,6 +11,12 @@ import (
|
|||||||
type AppRepo struct {
|
type AppRepo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a AppRepo) WithKey(key string) DBOption {
|
||||||
|
return func(db *gorm.DB) *gorm.DB {
|
||||||
|
return db.Where("key = ?", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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 := global.DB.Model(&model.App{})
|
db := global.DB.Model(&model.App{})
|
||||||
|
|||||||
@@ -10,6 +10,22 @@ import (
|
|||||||
type AppContainerRepo struct {
|
type AppContainerRepo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a AppContainerRepo) WithAppId(appId uint) DBOption {
|
||||||
|
return func(db *gorm.DB) *gorm.DB {
|
||||||
|
return db.Where("app_id = ?", appId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a AppContainerRepo) GetBy(opts ...DBOption) ([]model.AppContainer, error) {
|
||||||
|
db := global.DB.Model(&model.AppContainer{})
|
||||||
|
var appContainers []model.AppContainer
|
||||||
|
for _, opt := range opts {
|
||||||
|
db = opt(db)
|
||||||
|
}
|
||||||
|
err := db.Find(&appContainers).Error
|
||||||
|
return appContainers, err
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppContainerRepo) Create(container *model.AppContainer) error {
|
func (a AppContainerRepo) Create(container *model.AppContainer) error {
|
||||||
db := global.DB.Model(&model.AppContainer{})
|
db := global.DB.Model(&model.AppContainer{})
|
||||||
return db.Create(&container).Error
|
return db.Create(&container).Error
|
||||||
|
|||||||
@@ -13,6 +13,16 @@ func (a AppInstallRepo) WithDetailIdsIn(detailIds []uint) DBOption {
|
|||||||
return g.Where("app_detail_id in (?)", detailIds)
|
return g.Where("app_detail_id in (?)", detailIds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func (a AppInstallRepo) WithAppId(appId uint) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("app_id = ?", appId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (a AppInstallRepo) WithStatus(status string) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
return g.Where("status = ?", status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppInstallRepo) GetBy(opts ...DBOption) ([]model.AppInstall, error) {
|
func (a AppInstallRepo) GetBy(opts ...DBOption) ([]model.AppInstall, error) {
|
||||||
db := global.DB.Model(&model.AppInstall{})
|
db := global.DB.Model(&model.AppInstall{})
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"github.com/1Panel-dev/1Panel/app/dto"
|
"github.com/1Panel-dev/1Panel/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/app/model"
|
"github.com/1Panel-dev/1Panel/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/app/repo"
|
"github.com/1Panel-dev/1Panel/app/repo"
|
||||||
@@ -217,7 +218,7 @@ func (a AppService) Install(name string, appDetailId uint, params map[string]int
|
|||||||
if ok {
|
if ok {
|
||||||
portStr := strconv.FormatFloat(port.(float64), 'f', -1, 32)
|
portStr := strconv.FormatFloat(port.(float64), 'f', -1, 32)
|
||||||
if common.ScanPort(portStr) {
|
if common.ScanPort(portStr) {
|
||||||
return errors.New("port is in used")
|
return errors.New("port is in used")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,6 +227,38 @@ func (a AppService) Install(name string, appDetailId uint, params map[string]int
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
app, err := appRepo.GetFirst(commonRepo.WithByID(appDetail.AppId))
|
app, err := appRepo.GetFirst(commonRepo.WithByID(appDetail.AppId))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if app.Required != "" {
|
||||||
|
var requiredArray []string
|
||||||
|
if err := json.Unmarshal([]byte(app.Required), &requiredArray); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, key := range requiredArray {
|
||||||
|
if key == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
requireApp, err := appRepo.GetFirst(appRepo.WithKey(key))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
details, err := appDetailRepo.GetBy(appDetailRepo.WithAppId(requireApp.ID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var detailIds []uint
|
||||||
|
for _, d := range details {
|
||||||
|
detailIds = append(detailIds, d.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = appInstallRepo.GetFirst(appInstallRepo.WithDetailIdsIn(detailIds))
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(fmt.Sprintf("%s is required", requireApp.Key))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
paramByte, err := json.Marshal(params)
|
paramByte, err := json.Marshal(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -268,12 +301,8 @@ func (a AppService) Install(name string, appDetailId uint, params map[string]int
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fileContent, err := os.ReadFile(composeFilePath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
composeMap := make(map[string]interface{})
|
composeMap := make(map[string]interface{})
|
||||||
if err := yaml.Unmarshal(fileContent, &composeMap); err != nil {
|
if err := yaml.Unmarshal([]byte(appDetail.DockerCompose), &composeMap); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
servicesMap := composeMap["services"].(map[string]interface{})
|
servicesMap := composeMap["services"].(map[string]interface{})
|
||||||
@@ -285,20 +314,38 @@ func (a AppService) Install(name string, appDetailId uint, params map[string]int
|
|||||||
value := v.(map[string]interface{})
|
value := v.(map[string]interface{})
|
||||||
containerName := constant.ContainerPrefix + k + "-" + common.RandStr(4)
|
containerName := constant.ContainerPrefix + k + "-" + common.RandStr(4)
|
||||||
value["container_name"] = containerName
|
value["container_name"] = containerName
|
||||||
|
servicePort := 0
|
||||||
|
if portArray, ok := value["ports"].([]interface{}); ok {
|
||||||
|
for _, p := range portArray {
|
||||||
|
if pStr, ok := p.(string); ok {
|
||||||
|
start := strings.Index(pStr, "{")
|
||||||
|
end := strings.Index(pStr, "}")
|
||||||
|
if start > -1 && end > -1 {
|
||||||
|
portS := pStr[start+1 : end]
|
||||||
|
if v, ok := envParams[portS]; ok {
|
||||||
|
portN, _ := strconv.Atoi(v)
|
||||||
|
servicePort = portN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
appContainers = append(appContainers, &model.AppContainer{
|
appContainers = append(appContainers, &model.AppContainer{
|
||||||
ServiceName: serviceName,
|
ServiceName: serviceName,
|
||||||
ContainerName: containerName,
|
ContainerName: containerName,
|
||||||
|
Port: servicePort,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
for k, v := range changeKeys {
|
for k, v := range changeKeys {
|
||||||
servicesMap[v] = servicesMap[k]
|
servicesMap[v] = servicesMap[k]
|
||||||
delete(servicesMap, k)
|
delete(servicesMap, k)
|
||||||
}
|
}
|
||||||
serviceByte, err := yaml.Marshal(servicesMap)
|
composeByte, err := yaml.Marshal(composeMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := fileOp.WriteFile(composeFilePath, strings.NewReader(string(serviceByte)), 0775); err != nil {
|
if err := fileOp.WriteFile(composeFilePath, strings.NewReader(string(composeByte)), 0775); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,6 +393,31 @@ func (a AppService) SyncAllInstalled() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a AppService) GetServices(key string) ([]dto.AppService, error) {
|
||||||
|
app, err := appRepo.GetFirst(appRepo.WithKey(key))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
installs, err := appInstallRepo.GetBy(appInstallRepo.WithAppId(app.ID), appInstallRepo.WithStatus(constant.Running))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var res []dto.AppService
|
||||||
|
for _, install := range installs {
|
||||||
|
for _, container := range install.Containers {
|
||||||
|
value := container.ServiceName
|
||||||
|
if container.Port > 0 {
|
||||||
|
value = value + ":" + string(rune(container.Port))
|
||||||
|
}
|
||||||
|
res = append(res, dto.AppService{
|
||||||
|
Label: install.Name,
|
||||||
|
Value: value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppService) SyncInstalled(installId uint) error {
|
func (a AppService) SyncInstalled(installId uint) error {
|
||||||
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
|
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -23,5 +23,6 @@ func (a *AppRouter) InitAppRouter(Router *gin.RouterGroup) {
|
|||||||
appRouter.POST("/installed", baseApi.PageInstalled)
|
appRouter.POST("/installed", baseApi.PageInstalled)
|
||||||
appRouter.POST("/installed/op", baseApi.InstallOperate)
|
appRouter.POST("/installed/op", baseApi.InstallOperate)
|
||||||
appRouter.POST("/installed/sync", baseApi.InstalledSync)
|
appRouter.POST("/installed/sync", baseApi.InstalledSync)
|
||||||
|
appRouter.GET("/services/:key", baseApi.GetServices)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ export namespace App {
|
|||||||
required: boolean;
|
required: boolean;
|
||||||
default: any;
|
default: any;
|
||||||
envKey: string;
|
envKey: string;
|
||||||
|
key?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AppInstall {
|
export interface AppInstall {
|
||||||
@@ -79,4 +80,9 @@ export namespace App {
|
|||||||
installId: number;
|
installId: number;
|
||||||
operate: string;
|
operate: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AppService {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export const GetApp = (id: number) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const GetAppDetail = (id: number, version: string) => {
|
export const GetAppDetail = (id: number, version: string) => {
|
||||||
return http.get<App.AppDetail>('apps/detail/' + id + '/' + version);
|
return http.get<App.AppDetail>(`apps/detail/${id}/${version}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const InstallApp = (install: App.AppInstall) => {
|
export const InstallApp = (install: App.AppInstall) => {
|
||||||
@@ -33,3 +33,7 @@ export const InstalledOp = (op: App.AppInstalledOp) => {
|
|||||||
export const SyncInstalledApp = () => {
|
export const SyncInstalledApp = () => {
|
||||||
return http.post<any>('apps/installed/sync', {});
|
return http.post<any>('apps/installed/sync', {});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const GetAppService = (key: string | undefined) => {
|
||||||
|
return http.get<any>(`apps/services/${key}`);
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog v-model="open" :title="$t('app.install')" width="30%">
|
<el-dialog v-model="open" :title="$t('app.install')" width="40%">
|
||||||
<el-form ref="paramForm" label-position="left" :model="form" label-width="150px" :rules="rules">
|
<el-form ref="paramForm" label-position="left" :model="form" label-width="150px" :rules="rules">
|
||||||
<el-form-item :label="$t('app.name')" prop="NAME">
|
<el-form-item :label="$t('app.name')" prop="NAME">
|
||||||
<el-input v-model="form['NAME']"></el-input>
|
<el-input v-model="form['NAME']"></el-input>
|
||||||
@@ -14,6 +14,14 @@
|
|||||||
:type="f.type"
|
:type="f.type"
|
||||||
show-password
|
show-password
|
||||||
></el-input>
|
></el-input>
|
||||||
|
<el-select v-model="form[f.envKey]" v-if="f.type == 'service'">
|
||||||
|
<el-option
|
||||||
|
v-for="service in services"
|
||||||
|
:key="service.label"
|
||||||
|
:value="service.value"
|
||||||
|
:label="service.label"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
</el-form>
|
</el-form>
|
||||||
@@ -30,7 +38,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup name="appInstall">
|
<script lang="ts" setup name="appInstall">
|
||||||
import { App } from '@/api/interface/app';
|
import { App } from '@/api/interface/app';
|
||||||
import { InstallApp } from '@/api/modules/app';
|
import { InstallApp, GetAppService } from '@/api/modules/app';
|
||||||
import { Rules } from '@/global/form-rules';
|
import { Rules } from '@/global/form-rules';
|
||||||
import { FormInstance, FormRules } from 'element-plus';
|
import { FormInstance, FormRules } from 'element-plus';
|
||||||
import { reactive, ref } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
@@ -47,7 +55,6 @@ const installData = ref<InstallRrops>({
|
|||||||
});
|
});
|
||||||
let open = ref(false);
|
let open = ref(false);
|
||||||
let form = reactive<{ [key: string]: any }>({});
|
let form = reactive<{ [key: string]: any }>({});
|
||||||
|
|
||||||
let rules = reactive<FormRules>({
|
let rules = reactive<FormRules>({
|
||||||
NAME: [Rules.requiredInput],
|
NAME: [Rules.requiredInput],
|
||||||
});
|
});
|
||||||
@@ -58,6 +65,8 @@ const req = reactive({
|
|||||||
params: {},
|
params: {},
|
||||||
name: '',
|
name: '',
|
||||||
});
|
});
|
||||||
|
let services = ref();
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
if (paramForm.value) {
|
if (paramForm.value) {
|
||||||
paramForm.value.resetFields();
|
paramForm.value.resetFields();
|
||||||
@@ -74,11 +83,24 @@ const acceptParams = (props: InstallRrops): void => {
|
|||||||
if (p.required) {
|
if (p.required) {
|
||||||
rules[p.envKey] = [Rules.requiredInput];
|
rules[p.envKey] = [Rules.requiredInput];
|
||||||
}
|
}
|
||||||
|
if (p.key) {
|
||||||
|
form[p.envKey] = '';
|
||||||
|
getServices(form[p.envKey], p.key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
open.value = true;
|
open.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getServices = (value: any, key: string | undefined) => {
|
||||||
|
GetAppService(key).then((res) => {
|
||||||
|
services.value = res.data;
|
||||||
|
if (services.value != null) {
|
||||||
|
value = services.value[0].value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const submit = async (formEl: FormInstance | undefined) => {
|
const submit = async (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
await formEl.validate((valid) => {
|
await formEl.validate((valid) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user