mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-03-13 17:24:44 +08:00
feat: 增加创建 WORDPRESS 之前创建数据库功能
This commit is contained in:
parent
dc70d7cfc1
commit
ad50907158
@ -39,7 +39,7 @@
|
||||
"author": "Nginx",
|
||||
"type": "internal",
|
||||
"required": [""],
|
||||
"limit": 0,
|
||||
"limit": 1,
|
||||
"crossVersionUpdate": true,
|
||||
"source": "http://nginx.org/"
|
||||
},
|
||||
|
@ -7,14 +7,11 @@ services:
|
||||
restart: always
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
MYSQL_DATABASE: ${DATABASE}
|
||||
MYSQL_USER: ${USER}
|
||||
MYSQL_PASSWORD: ${PASSWORD}
|
||||
MYSQL_ROOT_PASSWORD: ${ROOT_PASSWORD}
|
||||
MYSQL_ROOT_PASSWORD: ${PANEL_DB_ROOT_PASSWORD}
|
||||
networks:
|
||||
- 1panel
|
||||
ports:
|
||||
- ${PORT}:3306
|
||||
- ${PANEL_APP_PORT}:3306
|
||||
volumes:
|
||||
- ./data/:/var/lib/mysql
|
||||
- ./conf/my.cnf:/etc/mysql/my.cnf
|
||||
|
@ -1,44 +1,12 @@
|
||||
{
|
||||
"formFields": [
|
||||
{
|
||||
"type": "text",
|
||||
"labelZh": "时区",
|
||||
"labelEn": "TimeZone",
|
||||
"required": true,
|
||||
"default": "Asia/Shanghai",
|
||||
"envKey": "TZ"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"labelZh": "数据库",
|
||||
"labelEn": "Database",
|
||||
"required": true,
|
||||
"default": "db",
|
||||
"envKey": "DATABASE"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"labelZh": "普通用户",
|
||||
"labelEn": "User",
|
||||
"required": true,
|
||||
"default": "mysql",
|
||||
"envKey": "USER"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"labelZh": "普通用户密码",
|
||||
"labelEn": "Password",
|
||||
"required": true,
|
||||
"default": "1qaz@WSX",
|
||||
"envKey": "PASSWORD"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"labelZh": "Root用户密码",
|
||||
"labelEn": "RootPassword",
|
||||
"required": true,
|
||||
"default": "1panel@mysql",
|
||||
"envKey": "ROOT_PASSWORD"
|
||||
"envKey": "PANEL_DB_ROOT_PASSWORD"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
@ -46,7 +14,7 @@
|
||||
"labelEn": "Port",
|
||||
"required": true,
|
||||
"default": 3306,
|
||||
"envKey": "PORT"
|
||||
"envKey": "PANEL_APP_PORT"
|
||||
}
|
||||
]
|
||||
}
|
@ -7,14 +7,11 @@ services:
|
||||
restart: always
|
||||
environment:
|
||||
TZ: ${TZ}
|
||||
MYSQL_DATABASE: ${DATABASE}
|
||||
MYSQL_USER: ${USER}
|
||||
MYSQL_PASSWORD: ${PASSWORD}
|
||||
MYSQL_ROOT_PASSWORD: ${ROOT_PASSWORD}
|
||||
MYSQL_ROOT_PASSWORD: ${PANEL_DB_ROOT_PASSWORD}
|
||||
networks:
|
||||
- 1panel
|
||||
ports:
|
||||
- ${PORT}:3306
|
||||
- ${PANEL_APP_PORT}:3306
|
||||
volumes:
|
||||
- ./data/:/var/lib/mysql
|
||||
- ./conf/my.cnf:/etc/my.cnf
|
||||
|
@ -1,44 +1,12 @@
|
||||
{
|
||||
"formFields": [
|
||||
{
|
||||
"type": "text",
|
||||
"labelZh": "时区",
|
||||
"labelEn": "TimeZone",
|
||||
"required": true,
|
||||
"default": "Asia/Shanghai",
|
||||
"envKey": "TZ"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"labelZh": "数据库",
|
||||
"labelEn": "Database",
|
||||
"required": true,
|
||||
"default": "db",
|
||||
"envKey": "DATABASE"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"labelZh": "普通用户",
|
||||
"labelEn": "User",
|
||||
"required": true,
|
||||
"default": "mysql",
|
||||
"envKey": "USER"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"labelZh": "普通用户密码",
|
||||
"labelEn": "Password",
|
||||
"required": true,
|
||||
"default": "1qaz@WSX",
|
||||
"envKey": "PASSWORD"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"labelZh": "Root用户密码",
|
||||
"labelEn": "RootPassword",
|
||||
"required": true,
|
||||
"default": "1panel@mysql",
|
||||
"envKey": "ROOT_PASSWORD"
|
||||
"envKey": "PANEL_DB_ROOT_PASSWORD"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
@ -46,7 +14,7 @@
|
||||
"labelEn": "Port",
|
||||
"required": true,
|
||||
"default": 3306,
|
||||
"envKey": "PORT"
|
||||
"envKey": "PANEL_APP_PORT"
|
||||
}
|
||||
]
|
||||
}
|
@ -4,10 +4,10 @@ services:
|
||||
image: nginx:1.23.1
|
||||
restart: always
|
||||
ports:
|
||||
- ${PORT}:80
|
||||
- ${PANEL_APP_PORT}:80
|
||||
volumes:
|
||||
- ./conf/nginx.conf:/etc/nginx/nginx.conf
|
||||
- ./www:/home/www
|
||||
- ./log:/var/log/nginx
|
||||
- ./conf/conf.d/default.conf:/etc/nginx/conf.d/default.conf
|
||||
- ./conf/conf.d:/etc/nginx/conf.d/
|
||||
- ./html:/usr/share/nginx/html
|
@ -6,7 +6,7 @@
|
||||
"labelEn": "Port",
|
||||
"required": true,
|
||||
"default": 80,
|
||||
"envKey": "PORT"
|
||||
"envKey": "PANEL_APP_PORT"
|
||||
}
|
||||
]
|
||||
}
|
@ -2,19 +2,19 @@ version: '3'
|
||||
services:
|
||||
1panel_wordpress:
|
||||
image: wordpress:6.0.1
|
||||
container_name: 1panel_wordpress
|
||||
container_name: ${CONTAINER_NAME}
|
||||
ports:
|
||||
- ${PORT}:80
|
||||
- ${PANEL_APP_PORT}:80
|
||||
restart: always
|
||||
networks:
|
||||
- 1panel
|
||||
volumes:
|
||||
- ./data:/var/www/html
|
||||
environment:
|
||||
WORDPRESS_DB_HOST: ${WORDPRESS_DB_HOST}
|
||||
WORDPRESS_DB_NAME: ${WORDPRESS_DB_NAME}
|
||||
WORDPRESS_DB_USER: ${WORDPRESS_DB_USER}
|
||||
WORDPRESS_DB_PASSWORD: ${WORDPRESS_DB_PASSWORD}
|
||||
WORDPRESS_DB_HOST: ${PANEL_DB_HOST}
|
||||
WORDPRESS_DB_NAME: ${PANEL_DB_NAME}
|
||||
WORDPRESS_DB_USER: ${PANEL_DB_USER}
|
||||
WORDPRESS_DB_PASSWORD: ${PANEL_DB_USER_PASSWORD}
|
||||
WORDPRESS_DEBUG: 1
|
||||
|
||||
networks:
|
||||
|
@ -6,32 +6,32 @@
|
||||
"labelZh": "数据库服务",
|
||||
"labelEn": "Database Service",
|
||||
"required": true,
|
||||
"default": "1Panel-mysql",
|
||||
"envKey": "WORDPRESS_DB_HOST"
|
||||
"default": "",
|
||||
"envKey": "PANEL_DB_HOST"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"labelZh": "数据库名",
|
||||
"labelEn": "Database",
|
||||
"required": true,
|
||||
"default": "db",
|
||||
"envKey": "WORDPRESS_DB_NAME"
|
||||
"default": "random",
|
||||
"envKey": "PANEL_DB_NAME"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"labelZh": "数据库用户",
|
||||
"labelEn": "User",
|
||||
"required": true,
|
||||
"default": "wordpress_user",
|
||||
"envKey": "WORDPRESS_DB_USER"
|
||||
"default": "random",
|
||||
"envKey": "PANEL_DB_USER"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"labelZh": "数据库用户密码",
|
||||
"labelEn": "Password",
|
||||
"required": true,
|
||||
"default": "1qaz@WSX",
|
||||
"envKey": "WORDPRESS_DB_PASSWORD"
|
||||
"default": "random",
|
||||
"envKey": "PANEL_DB_USER_PASSWORD"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
@ -39,7 +39,7 @@
|
||||
"labelEn": "Port",
|
||||
"required": true,
|
||||
"default": 8080,
|
||||
"envKey": "PORT"
|
||||
"envKey": "PANEL_APP_PORT"
|
||||
}
|
||||
]
|
||||
}
|
@ -111,3 +111,20 @@ type AppService struct {
|
||||
Label string `json:"label"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type AppDatabase struct {
|
||||
ServiceName string `json:"PANEL_DB_HOST"`
|
||||
DbName string `json:"PANEL_DB_NAME"`
|
||||
DbUser string `json:"PANEL_DB_USER"`
|
||||
Password string `json:"PANEL_DB_USER_PASSWORD"`
|
||||
}
|
||||
|
||||
type AuthParam struct {
|
||||
RootPassword string `json:"PANEL_DB_ROOT_PASSWORD"`
|
||||
}
|
||||
|
||||
type ContainerExec struct {
|
||||
ContainerName string `json:"containerName"`
|
||||
DbParam AppDatabase `json:"dbParam"`
|
||||
Auth AuthParam `json:"auth"`
|
||||
}
|
||||
|
@ -2,8 +2,10 @@ package model
|
||||
|
||||
type AppContainer struct {
|
||||
BaseModel
|
||||
ServiceName string `json:"serviceName" gorm:"type:varchar(64);not null"`
|
||||
ContainerName string `json:"containerName" gorm:"type:varchar(64);not null"`
|
||||
AppInstallId uint `json:"appInstallId" gorm:"type:integer;not null"`
|
||||
Port int `json:"port" gorm:"type:integer;not null"`
|
||||
ServiceName string `json:"serviceName" gorm:"type:varchar(64);not null"`
|
||||
ContainerName string `json:"containerName" gorm:"type:varchar(64);not null"`
|
||||
AppInstallID uint `json:"appInstallId" gorm:"type:integer;not null"`
|
||||
Port int `json:"port" gorm:"type:integer;not null"`
|
||||
Auth string `json:"auth" gorm:"type:longtext;not null"`
|
||||
AppInstall AppInstall `gorm:"-"`
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ func (i *AppInstall) GetComposePath() string {
|
||||
|
||||
func (i *AppInstall) BeforeDelete(tx *gorm.DB) (err error) {
|
||||
|
||||
if err = tx.Where("app_install_id = ?", i.ID).Delete(&AppContainer{}).Error; err != nil {
|
||||
if err = tx.Model(AppContainer{}).Debug().Where("app_install_id = ?", i.ID).Delete(AppContainer{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
10
backend/app/model/database.go
Normal file
10
backend/app/model/database.go
Normal file
@ -0,0 +1,10 @@
|
||||
package model
|
||||
|
||||
type Database struct {
|
||||
BaseModel
|
||||
AppContainerId uint `json:"appContainerId" gorm:"type:integer;not null"`
|
||||
Key string `json:"key" gorm:"type:varchar(64);not null"`
|
||||
Dbname string `json:"dbname" gorm:"type:varchar(256);not null"`
|
||||
Username string `json:"username" gorm:"type:varchar(256);not null"`
|
||||
Password string `json:"password" gorm:"type:varchar(256);not null"`
|
||||
}
|
@ -35,7 +35,7 @@ func (a AppRepo) GetFirst(opts ...DBOption) (model.App, error) {
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
if err := db.First(&app).Error; err != nil {
|
||||
if err := db.Preload("AppTags").First(&app).Error; err != nil {
|
||||
return app, err
|
||||
}
|
||||
return app, nil
|
||||
|
@ -16,6 +16,12 @@ func (a AppContainerRepo) WithAppId(appId uint) DBOption {
|
||||
}
|
||||
}
|
||||
|
||||
func (a AppContainerRepo) WithServiceName(serviceName string) DBOption {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
return db.Where("service_name = ?", serviceName)
|
||||
}
|
||||
}
|
||||
|
||||
func (a AppContainerRepo) GetBy(opts ...DBOption) ([]model.AppContainer, error) {
|
||||
db := global.DB.Model(&model.AppContainer{})
|
||||
var appContainers []model.AppContainer
|
||||
@ -26,6 +32,16 @@ func (a AppContainerRepo) GetBy(opts ...DBOption) ([]model.AppContainer, error)
|
||||
return appContainers, err
|
||||
}
|
||||
|
||||
func (a AppContainerRepo) GetFirst(opts ...DBOption) (model.AppContainer, error) {
|
||||
db := global.DB.Model(&model.AppContainer{})
|
||||
var appContainer model.AppContainer
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
err := db.Find(&appContainer).Error
|
||||
return appContainer, err
|
||||
}
|
||||
|
||||
func (a AppContainerRepo) Create(container *model.AppContainer) error {
|
||||
db := global.DB.Model(&model.AppContainer{})
|
||||
return db.Create(&container).Error
|
||||
|
@ -1,6 +1,7 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/1Panel-dev/1Panel/app/model"
|
||||
"github.com/1Panel-dev/1Panel/global"
|
||||
"gorm.io/gorm"
|
||||
@ -44,8 +45,8 @@ func (a AppInstallRepo) GetFirst(opts ...DBOption) (model.AppInstall, error) {
|
||||
return install, err
|
||||
}
|
||||
|
||||
func (a AppInstallRepo) Create(install *model.AppInstall) error {
|
||||
db := global.DB.Model(&model.AppInstall{})
|
||||
func (a AppInstallRepo) Create(ctx context.Context, install *model.AppInstall) error {
|
||||
db := ctx.Value("db").(*gorm.DB).Model(&model.AppInstall{})
|
||||
return db.Create(&install).Error
|
||||
}
|
||||
|
||||
@ -54,7 +55,7 @@ func (a AppInstallRepo) Save(install model.AppInstall) error {
|
||||
return db.Save(&install).Error
|
||||
}
|
||||
|
||||
func (a AppInstallRepo) Delete(opts ...DBOption) error {
|
||||
func (a AppInstallRepo) DeleteBy(opts ...DBOption) error {
|
||||
db := global.DB.Model(&model.AppInstall{})
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
@ -62,6 +63,11 @@ func (a AppInstallRepo) Delete(opts ...DBOption) error {
|
||||
return db.Delete(&model.AppInstall{}).Error
|
||||
}
|
||||
|
||||
func (a AppInstallRepo) Delete(install model.AppInstall) error {
|
||||
db := global.DB
|
||||
return db.Delete(&install).Error
|
||||
}
|
||||
|
||||
func (a AppInstallRepo) Page(page, size int, opts ...DBOption) (int64, []model.AppInstall, error) {
|
||||
var apps []model.AppInstall
|
||||
db := global.DB.Model(&model.AppInstall{})
|
||||
|
47
backend/app/repo/database.go
Normal file
47
backend/app/repo/database.go
Normal file
@ -0,0 +1,47 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/1Panel-dev/1Panel/app/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type DatabaseRepo struct {
|
||||
}
|
||||
|
||||
func (d DatabaseRepo) Create(ctx context.Context, database *model.Database) error {
|
||||
db := ctx.Value("db").(*gorm.DB).Model(&model.Database{})
|
||||
return db.Create(&database).Error
|
||||
}
|
||||
|
||||
//func (a DatabaseRepo) BatchCreate(ctx context.Context, tags []*model.AppTag) error {
|
||||
// db := ctx.Value("db").(*gorm.DB)
|
||||
// return db.Create(&tags).Error
|
||||
//}
|
||||
|
||||
//func (d DatabaseRepo) DeleteBy(ctx context.Context, appIds []uint) error {
|
||||
// db := ctx.Value("db").(*gorm.DB)
|
||||
// return db.Where("app_id in (?)", appIds).Delete(&model.AppTag{}).Error
|
||||
//}
|
||||
|
||||
//
|
||||
//func (a AppTagRepo) DeleteAll(ctx context.Context) error {
|
||||
// db := ctx.Value("db").(*gorm.DB)
|
||||
// return db.Where("1 = 1").Delete(&model.AppTag{}).Error
|
||||
//}
|
||||
//
|
||||
//func (a AppTagRepo) GetByAppId(appId uint) ([]model.AppTag, error) {
|
||||
// var appTags []model.AppTag
|
||||
// if err := global.DB.Where("app_id = ?", appId).Find(&appTags).Error; err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// return appTags, nil
|
||||
//}
|
||||
//
|
||||
//func (a AppTagRepo) GetByTagIds(tagIds []uint) ([]model.AppTag, error) {
|
||||
// var appTags []model.AppTag
|
||||
// if err := global.DB.Where("tag_id in (?)", tagIds).Find(&appTags).Error; err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// return appTags, nil
|
||||
//}
|
@ -15,6 +15,7 @@ type RepoGroup struct {
|
||||
AppDetailRepo
|
||||
AppInstallRepo
|
||||
AppContainerRepo
|
||||
DatabaseRepo
|
||||
}
|
||||
|
||||
var RepoGroupApp = new(RepoGroup)
|
||||
|
@ -43,3 +43,11 @@ func (t TagRepo) GetByKeys(keys []string) ([]model.Tag, error) {
|
||||
}
|
||||
return tags, nil
|
||||
}
|
||||
|
||||
func (t TagRepo) GetByAppId(appId uint) ([]model.Tag, error) {
|
||||
var tags []model.Tag
|
||||
if err := global.DB.Where("id in (select tag_id from app_tags where app_id = ?)", appId).Find(&tags).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tags, nil
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/constant"
|
||||
"github.com/1Panel-dev/1Panel/global"
|
||||
"github.com/1Panel-dev/1Panel/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/utils/compose"
|
||||
"github.com/1Panel-dev/1Panel/utils/docker"
|
||||
@ -19,6 +20,7 @@ import (
|
||||
"gopkg.in/yaml.v3"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
@ -179,7 +181,7 @@ func (a AppService) Operate(req dto.AppInstallOperate) error {
|
||||
appDir := install.GetPath()
|
||||
dir, _ := os.Stat(appDir)
|
||||
if dir == nil {
|
||||
return appInstallRepo.Delete(commonRepo.WithByID(install.ID))
|
||||
return appInstallRepo.Delete(install)
|
||||
}
|
||||
out, err := compose.Down(dockerComposePath)
|
||||
if err != nil {
|
||||
@ -188,7 +190,7 @@ func (a AppService) Operate(req dto.AppInstallOperate) error {
|
||||
if err := op.DeleteDir(appDir); err != nil {
|
||||
return err
|
||||
}
|
||||
return appInstallRepo.Delete(commonRepo.WithByID(install.ID))
|
||||
return appInstallRepo.Delete(install)
|
||||
case dto.Sync:
|
||||
if err := a.SyncInstalled(install.ID); err != nil {
|
||||
return err
|
||||
@ -214,7 +216,7 @@ func handleErr(install model.AppInstall, err error, out string) error {
|
||||
|
||||
func (a AppService) Install(name string, appDetailId uint, params map[string]interface{}) error {
|
||||
|
||||
port, ok := params["PORT"]
|
||||
port, ok := params["PANEL_APP_PORT"]
|
||||
if ok {
|
||||
portStr := strconv.FormatFloat(port.(float64), 'f', -1, 32)
|
||||
if common.ScanPort(portStr) {
|
||||
@ -230,6 +232,7 @@ func (a AppService) Install(name string, appDetailId uint, params map[string]int
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if app.Required != "" {
|
||||
var requiredArray []string
|
||||
if err := json.Unmarshal([]byte(app.Required), &requiredArray); err != nil {
|
||||
@ -301,6 +304,41 @@ func (a AppService) Install(name string, appDetailId uint, params map[string]int
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
auth string
|
||||
dbConfig dto.AppDatabase
|
||||
)
|
||||
tags, err := tagRepo.GetByAppId(app.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, tag := range tags {
|
||||
if tag.Key == "Database" {
|
||||
var authParam dto.AuthParam
|
||||
paramByte, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(paramByte, &authParam); err != nil {
|
||||
return err
|
||||
}
|
||||
authByte, err := json.Marshal(authParam)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
auth = string(authByte)
|
||||
}
|
||||
if tag.Key == "WebSite" {
|
||||
paramByte, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(paramByte, &dbConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
composeMap := make(map[string]interface{})
|
||||
if err := yaml.Unmarshal([]byte(appDetail.DockerCompose), &composeMap); err != nil {
|
||||
return err
|
||||
@ -335,6 +373,7 @@ func (a AppService) Install(name string, appDetailId uint, params map[string]int
|
||||
ServiceName: serviceName,
|
||||
ContainerName: containerName,
|
||||
Port: servicePort,
|
||||
Auth: auth,
|
||||
})
|
||||
}
|
||||
for k, v := range changeKeys {
|
||||
@ -349,35 +388,64 @@ func (a AppService) Install(name string, appDetailId uint, params map[string]int
|
||||
return err
|
||||
}
|
||||
|
||||
if err := appInstallRepo.Create(&appInstall); err != nil {
|
||||
tx := global.DB.Begin()
|
||||
ctx := context.WithValue(context.Background(), "db", tx)
|
||||
|
||||
if err := appInstallRepo.Create(ctx, &appInstall); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
for _, c := range appContainers {
|
||||
c.AppInstallId = appInstall.ID
|
||||
c.AppInstallID = appInstall.ID
|
||||
}
|
||||
if err := appContainerRepo.BatchCreate(context.WithValue(context.Background(), "db", global.DB), appContainers); err != nil {
|
||||
if err := appContainerRepo.BatchCreate(ctx, appContainers); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
if !reflect.DeepEqual(dbConfig, dto.AppDatabase{}) {
|
||||
container, err := appContainerRepo.GetFirst(appContainerRepo.WithServiceName(dbConfig.ServiceName))
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(container.AppInstallID))
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
app, err := appRepo.GetFirst(commonRepo.WithByID(install.ID))
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
var database model.Database
|
||||
database.AppContainerId = container.ID
|
||||
database.Dbname = dbConfig.DbName
|
||||
database.Username = dbConfig.DbUser
|
||||
database.Password = dbConfig.Password
|
||||
if err := dataBaseRepo.Create(ctx, &database); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
var auth dto.AuthParam
|
||||
json.Unmarshal([]byte(container.Auth), &auth)
|
||||
execConfig := dto.ContainerExec{
|
||||
ContainerName: container.ContainerName,
|
||||
Auth: auth,
|
||||
DbParam: dbConfig,
|
||||
}
|
||||
_, err = cmd.Exec(getSqlStr(app.Key, execConfig))
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
tx.Commit()
|
||||
go upApp(composeFilePath, appInstall)
|
||||
return nil
|
||||
}
|
||||
|
||||
func upApp(composeFilePath string, appInstall model.AppInstall) {
|
||||
out, err := compose.Up(composeFilePath)
|
||||
if err != nil {
|
||||
if out != "" {
|
||||
appInstall.Message = out
|
||||
} else {
|
||||
appInstall.Message = err.Error()
|
||||
}
|
||||
appInstall.Status = constant.Error
|
||||
_ = appInstallRepo.Save(appInstall)
|
||||
} else {
|
||||
appInstall.Status = constant.Running
|
||||
_ = appInstallRepo.Save(appInstall)
|
||||
}
|
||||
}
|
||||
|
||||
func (a AppService) SyncAllInstalled() error {
|
||||
allList, err := appInstallRepo.GetBy()
|
||||
if err != nil {
|
||||
@ -405,13 +473,9 @@ func (a AppService) GetServices(key string) ([]dto.AppService, error) {
|
||||
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,
|
||||
Value: container.ServiceName,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -505,53 +569,6 @@ func (a AppService) SyncInstalled(installId uint) error {
|
||||
return appInstallRepo.Save(appInstall)
|
||||
}
|
||||
|
||||
func getApps(oldApps []model.App, items []dto.AppDefine) map[string]model.App {
|
||||
apps := make(map[string]model.App, len(oldApps))
|
||||
for _, old := range oldApps {
|
||||
old.Status = constant.AppTakeDown
|
||||
apps[old.Key] = old
|
||||
}
|
||||
for _, item := range items {
|
||||
app, ok := apps[item.Key]
|
||||
if !ok {
|
||||
app = model.App{}
|
||||
}
|
||||
app.Name = item.Name
|
||||
app.Key = item.Key
|
||||
app.ShortDesc = item.ShortDesc
|
||||
app.Author = item.Author
|
||||
app.Source = item.Source
|
||||
app.Type = item.Type
|
||||
app.CrossVersionUpdate = item.CrossVersionUpdate
|
||||
app.Required = item.GetRequired()
|
||||
app.Status = constant.AppNormal
|
||||
apps[item.Key] = app
|
||||
}
|
||||
return apps
|
||||
}
|
||||
|
||||
func getAppDetails(details []model.AppDetail, versions []string) map[string]model.AppDetail {
|
||||
appDetails := make(map[string]model.AppDetail, len(details))
|
||||
for _, old := range details {
|
||||
old.Status = constant.AppTakeDown
|
||||
appDetails[old.Version] = old
|
||||
}
|
||||
|
||||
for _, v := range versions {
|
||||
detail, ok := appDetails[v]
|
||||
if ok {
|
||||
detail.Status = constant.AppNormal
|
||||
appDetails[v] = detail
|
||||
} else {
|
||||
appDetails[v] = model.AppDetail{
|
||||
Version: v,
|
||||
Status: constant.AppNormal,
|
||||
}
|
||||
}
|
||||
}
|
||||
return appDetails
|
||||
}
|
||||
|
||||
func (a AppService) SyncAppList() error {
|
||||
//TODO 从 oss 拉取最新列表
|
||||
|
||||
@ -770,3 +787,78 @@ func syncCanUpdate() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getApps(oldApps []model.App, items []dto.AppDefine) map[string]model.App {
|
||||
apps := make(map[string]model.App, len(oldApps))
|
||||
for _, old := range oldApps {
|
||||
old.Status = constant.AppTakeDown
|
||||
apps[old.Key] = old
|
||||
}
|
||||
for _, item := range items {
|
||||
app, ok := apps[item.Key]
|
||||
if !ok {
|
||||
app = model.App{}
|
||||
}
|
||||
app.Name = item.Name
|
||||
app.Key = item.Key
|
||||
app.ShortDesc = item.ShortDesc
|
||||
app.Author = item.Author
|
||||
app.Source = item.Source
|
||||
app.Type = item.Type
|
||||
app.CrossVersionUpdate = item.CrossVersionUpdate
|
||||
app.Required = item.GetRequired()
|
||||
app.Status = constant.AppNormal
|
||||
apps[item.Key] = app
|
||||
}
|
||||
return apps
|
||||
}
|
||||
|
||||
func getAppDetails(details []model.AppDetail, versions []string) map[string]model.AppDetail {
|
||||
appDetails := make(map[string]model.AppDetail, len(details))
|
||||
for _, old := range details {
|
||||
old.Status = constant.AppTakeDown
|
||||
appDetails[old.Version] = old
|
||||
}
|
||||
|
||||
for _, v := range versions {
|
||||
detail, ok := appDetails[v]
|
||||
if ok {
|
||||
detail.Status = constant.AppNormal
|
||||
appDetails[v] = detail
|
||||
} else {
|
||||
appDetails[v] = model.AppDetail{
|
||||
Version: v,
|
||||
Status: constant.AppNormal,
|
||||
}
|
||||
}
|
||||
}
|
||||
return appDetails
|
||||
}
|
||||
|
||||
func upApp(composeFilePath string, appInstall model.AppInstall) {
|
||||
out, err := compose.Up(composeFilePath)
|
||||
if err != nil {
|
||||
if out != "" {
|
||||
appInstall.Message = out
|
||||
} else {
|
||||
appInstall.Message = err.Error()
|
||||
}
|
||||
appInstall.Status = constant.Error
|
||||
_ = appInstallRepo.Save(appInstall)
|
||||
} else {
|
||||
appInstall.Status = constant.Running
|
||||
_ = appInstallRepo.Save(appInstall)
|
||||
}
|
||||
}
|
||||
|
||||
func getSqlStr(key string, exec dto.ContainerExec) string {
|
||||
var str string
|
||||
param := exec.DbParam
|
||||
switch key {
|
||||
case "mysql":
|
||||
str = fmt.Sprintf("docker exec -i %s mysql -uroot -p%s -e \"CREATE USER '%s'@'%%' IDENTIFIED BY '%s';\" -e \"create database %s;\" -e \"GRANT ALL ON %s.* TO '%s'@'%%';\"",
|
||||
exec.ContainerName, exec.Auth.RootPassword, param.DbUser, param.Password, param.DbName, param.DbName, param.DbUser)
|
||||
}
|
||||
fmt.Println(str)
|
||||
return str
|
||||
}
|
||||
|
@ -18,18 +18,19 @@ type ServiceGroup struct {
|
||||
var ServiceGroupApp = new(ServiceGroup)
|
||||
|
||||
var (
|
||||
hostRepo = repo.RepoGroupApp.HostRepo
|
||||
backupRepo = repo.RepoGroupApp.BackupRepo
|
||||
groupRepo = repo.RepoGroupApp.GroupRepo
|
||||
commandRepo = repo.RepoGroupApp.CommandRepo
|
||||
operationRepo = repo.RepoGroupApp.OperationRepo
|
||||
commonRepo = repo.RepoGroupApp.CommonRepo
|
||||
cronjobRepo = repo.RepoGroupApp.CronjobRepo
|
||||
settingRepo = repo.RepoGroupApp.SettingRepo
|
||||
appRepo = repo.RepoGroupApp.AppRepo
|
||||
appTagRepo = repo.RepoGroupApp.AppTagRepo
|
||||
appDetailRepo = repo.RepoGroupApp.AppDetailRepo
|
||||
tagRepo = repo.RepoGroupApp.TagRepo
|
||||
hostRepo = repo.RepoGroupApp.HostRepo
|
||||
backupRepo = repo.RepoGroupApp.BackupRepo
|
||||
groupRepo = repo.RepoGroupApp.GroupRepo
|
||||
commandRepo = repo.RepoGroupApp.CommandRepo
|
||||
operationRepo = repo.RepoGroupApp.OperationRepo
|
||||
commonRepo = repo.RepoGroupApp.CommonRepo
|
||||
cronjobRepo = repo.RepoGroupApp.CronjobRepo
|
||||
settingRepo = repo.RepoGroupApp.SettingRepo
|
||||
appRepo = repo.RepoGroupApp.AppRepo
|
||||
appTagRepo = repo.RepoGroupApp.AppTagRepo
|
||||
appDetailRepo = repo.RepoGroupApp.AppDetailRepo
|
||||
tagRepo = repo.RepoGroupApp.TagRepo
|
||||
appInstallRepo = repo.RepoGroupApp.AppInstallRepo
|
||||
appContainerRepo = repo.RepoGroupApp.AppContainerRepo
|
||||
dataBaseRepo = repo.RepoGroupApp.DatabaseRepo
|
||||
)
|
||||
|
@ -150,6 +150,6 @@ var AddTableCronjob = &gormigrate.Migration{
|
||||
var AddTableApp = &gormigrate.Migration{
|
||||
ID: "20200921-add-table-app",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
return tx.AutoMigrate(&model.App{}, &model.AppDetail{}, &model.Tag{}, &model.AppTag{}, &model.AppInstall{}, &model.AppContainer{}, &model.AppContainer{})
|
||||
return tx.AutoMigrate(&model.App{}, &model.AppDetail{}, &model.Tag{}, &model.AppTag{}, &model.AppInstall{}, &model.AppContainer{}, &model.Database{})
|
||||
},
|
||||
}
|
||||
|
50
backend/utils/cmd/cmd.go
Normal file
50
backend/utils/cmd/cmd.go
Normal file
@ -0,0 +1,50 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"io"
|
||||
"os/exec"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func Exec(cmdStr string) (out string, err error) {
|
||||
command := exec.CommandContext(context.Background(), "bash", "-c", cmdStr)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
|
||||
stdout, err := command.StdoutPipe()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
readout := bufio.NewReader(stdout)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
out = getOutput(readout)
|
||||
}()
|
||||
|
||||
err = command.Run()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
wg.Wait()
|
||||
return
|
||||
}
|
||||
|
||||
func getOutput(reader *bufio.Reader) string {
|
||||
var sumOutput string
|
||||
outputBytes := make([]byte, 200)
|
||||
for {
|
||||
n, err := reader.Read(outputBytes)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
sumOutput += err.Error()
|
||||
}
|
||||
output := string(outputBytes[:n])
|
||||
sumOutput += output
|
||||
}
|
||||
return sumOutput
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/client"
|
||||
@ -47,3 +49,30 @@ func (c Client) ListContainersByName(names []string) ([]types.Container, error)
|
||||
}
|
||||
return containers, nil
|
||||
}
|
||||
|
||||
func (c Client) ExecCommand(context context.Context, name string, command []string) {
|
||||
execConfig := types.ExecConfig{Tty: true, AttachStdout: true, AttachStderr: false, Cmd: command}
|
||||
respIdExecCreate, err := c.cli.ContainerExecCreate(context, name, execConfig)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
respId, err := c.cli.ContainerExecAttach(context, respIdExecCreate.ID, types.ExecStartCheck{})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
//text, _ := respId.Reader.ReadString('\n')
|
||||
//fmt.Printf("%s\n", text)
|
||||
scanner := bufio.NewScanner(respId.Reader)
|
||||
//text, _ := resp.Reader.ReadString('\n')
|
||||
//log.Print(text)
|
||||
for scanner.Scan() {
|
||||
fmt.Println(scanner.Text())
|
||||
}
|
||||
//
|
||||
//respId, err := c.cli.ContainerExecAttach(context, respIdExecCreate.ID, types.ExecStartCheck{})
|
||||
//if err != nil {
|
||||
// fmt.Println(err)
|
||||
//}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-dialog v-model="open" :title="$t('app.install')" width="40%">
|
||||
<el-dialog v-model="open" :title="$t('app.install')" width="40%" :before-close="handleClose" @opened="opened">
|
||||
<el-form ref="paramForm" label-position="left" :model="form" label-width="150px" :rules="rules">
|
||||
<el-form-item :label="$t('app.name')" prop="NAME">
|
||||
<el-input v-model="form['NAME']"></el-input>
|
||||
@ -40,8 +40,9 @@
|
||||
import { App } from '@/api/interface/app';
|
||||
import { InstallApp, GetAppService } from '@/api/modules/app';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { getRandomStr } from '@/utils/util';
|
||||
import { FormInstance, FormRules } from 'element-plus';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { nextTick, reactive, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
const router = useRouter();
|
||||
|
||||
@ -68,10 +69,22 @@ const req = reactive({
|
||||
let services = ref();
|
||||
|
||||
const handleClose = () => {
|
||||
open.value = false;
|
||||
resetForm();
|
||||
};
|
||||
|
||||
const opened = () => {
|
||||
nextTick(() => {
|
||||
if (paramForm.value) {
|
||||
paramForm.value.clearValidate();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
if (paramForm.value) {
|
||||
paramForm.value.resetFields();
|
||||
}
|
||||
open.value = false;
|
||||
};
|
||||
|
||||
const acceptParams = (props: InstallRrops): void => {
|
||||
@ -79,24 +92,28 @@ const acceptParams = (props: InstallRrops): void => {
|
||||
const params = installData.value.params;
|
||||
if (params?.formFields != undefined) {
|
||||
for (const p of params?.formFields) {
|
||||
form[p.envKey] = p.default;
|
||||
if (p.default == 'random') {
|
||||
form[p.envKey] = getRandomStr(6);
|
||||
} else {
|
||||
form[p.envKey] = p.default;
|
||||
}
|
||||
if (p.required) {
|
||||
rules[p.envKey] = [Rules.requiredInput];
|
||||
}
|
||||
if (p.key) {
|
||||
form[p.envKey] = '';
|
||||
getServices(form[p.envKey], p.key);
|
||||
getServices(p.envKey, p.key);
|
||||
}
|
||||
}
|
||||
}
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
const getServices = (value: any, key: string | undefined) => {
|
||||
GetAppService(key).then((res) => {
|
||||
const getServices = async (envKey: string, key: string | undefined) => {
|
||||
await GetAppService(key).then((res) => {
|
||||
services.value = res.data;
|
||||
if (services.value != null) {
|
||||
value = services.value[0].value;
|
||||
form[envKey] = services.value[0].value;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user