2022-10-10 15:10:53 +08:00
package service
import (
"encoding/json"
"fmt"
"github.com/1Panel-dev/1Panel/app/dto"
"github.com/1Panel-dev/1Panel/app/model"
"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/compose"
"github.com/1Panel-dev/1Panel/utils/files"
"github.com/joho/godotenv"
2022-10-10 22:56:42 +08:00
"github.com/pkg/errors"
2022-10-10 15:10:53 +08:00
"path"
"strconv"
)
type DatabaseOp string
var (
Add DatabaseOp = "add"
Delete DatabaseOp = "delete"
)
func execDockerCommand ( database model . Database , container model . AppContainer , op DatabaseOp ) error {
var auth dto . AuthParam
var dbConfig dto . AppDatabase
dbConfig . Password = database . Password
dbConfig . DbUser = database . Username
dbConfig . DbName = database . Dbname
json . Unmarshal ( [ ] byte ( container . Auth ) , & auth )
execConfig := dto . ContainerExec {
ContainerName : container . ContainerName ,
Auth : auth ,
DbParam : dbConfig ,
}
_ , err := cmd . Exec ( getSqlStr ( database . Key , op , execConfig ) )
if err != nil {
return err
}
return nil
}
func getSqlStr ( key string , operate DatabaseOp , exec dto . ContainerExec ) string {
var str string
param := exec . DbParam
switch key {
case "mysql" :
if operate == Add {
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 )
}
if operate == Delete {
str = fmt . Sprintf ( "docker exec -i %s mysql -uroot -p%s -e \"drop database %s;\" -e \"drop user %s;\" " ,
exec . ContainerName , exec . Auth . RootPassword , param . DbName , param . DbUser )
}
}
return str
}
2022-10-10 22:56:42 +08:00
func checkRequiredAndLimit ( app model . App ) error {
if app . Limit > 0 {
installs , err := appInstallRepo . GetBy ( appInstallRepo . WithAppId ( app . ID ) )
if err != nil {
return err
}
if len ( installs ) >= app . Limit {
return errors . New ( fmt . Sprintf ( "app install limit %d" , app . Limit ) )
}
}
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 ) )
}
}
}
return nil
}
2022-10-10 15:10:53 +08:00
func copyAppData ( key , version , installName string , params map [ string ] interface { } ) ( composeFilePath string , err error ) {
resourceDir := path . Join ( global . CONF . System . ResourceDir , "apps" , key , version )
installDir := path . Join ( global . CONF . System . AppDir , key )
installVersionDir := path . Join ( installDir , version )
fileOp := files . NewFileOp ( )
if err = fileOp . Copy ( resourceDir , installVersionDir ) ; err != nil {
return
}
appDir := path . Join ( installDir , installName )
if err = fileOp . Rename ( installVersionDir , appDir ) ; err != nil {
return
}
composeFilePath = path . Join ( appDir , "docker-compose.yml" )
envPath := path . Join ( appDir , ".env" )
envParams := make ( map [ string ] string , len ( params ) )
for k , v := range params {
switch t := v . ( type ) {
case string :
envParams [ k ] = t
case float64 :
envParams [ k ] = strconv . FormatFloat ( t , 'f' , - 1 , 32 )
default :
envParams [ k ] = t . ( string )
}
}
if err = godotenv . Write ( envParams , envPath ) ; err != nil {
return
}
return
}
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 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 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
}