2022-09-22 16:16:04 +08:00
package service
import (
"encoding/base64"
"encoding/json"
2022-09-26 18:20:21 +08:00
"errors"
2022-10-07 15:49:39 +08:00
"fmt"
2022-09-22 16:16:04 +08:00
"github.com/1Panel-dev/1Panel/app/dto"
"github.com/1Panel-dev/1Panel/app/model"
"github.com/1Panel-dev/1Panel/app/repo"
2022-09-26 16:32:40 +08:00
"github.com/1Panel-dev/1Panel/constant"
2022-09-22 16:16:04 +08:00
"github.com/1Panel-dev/1Panel/global"
2022-10-09 23:35:24 +08:00
"github.com/1Panel-dev/1Panel/utils/cmd"
2022-09-23 16:33:55 +08:00
"github.com/1Panel-dev/1Panel/utils/common"
2022-09-26 16:32:40 +08:00
"github.com/1Panel-dev/1Panel/utils/compose"
2022-09-29 18:16:56 +08:00
"github.com/1Panel-dev/1Panel/utils/docker"
2022-09-26 16:32:40 +08:00
"github.com/1Panel-dev/1Panel/utils/files"
"github.com/joho/godotenv"
2022-09-22 16:16:04 +08:00
"golang.org/x/net/context"
2022-09-29 18:16:56 +08:00
"gopkg.in/yaml.v3"
2022-09-22 16:16:04 +08:00
"os"
"path"
2022-10-09 23:35:24 +08:00
"reflect"
2022-09-26 16:32:40 +08:00
"strconv"
2022-09-29 18:16:56 +08:00
"strings"
2022-09-22 16:16:04 +08:00
)
type AppService struct {
}
func ( a AppService ) Page ( req dto . AppRequest ) ( interface { } , error ) {
var opts [ ] repo . DBOption
opts = append ( opts , commonRepo . WithOrderBy ( "name" ) )
if req . Name != "" {
opts = append ( opts , commonRepo . WithLikeName ( req . Name ) )
}
2022-09-23 16:33:55 +08:00
if len ( req . Tags ) != 0 {
tags , err := tagRepo . GetByKeys ( req . Tags )
if err != nil {
return nil , err
}
var tagIds [ ] uint
for _ , t := range tags {
tagIds = append ( tagIds , t . ID )
}
appTags , err := appTagRepo . GetByTagIds ( tagIds )
if err != nil {
return nil , err
}
var appIds [ ] uint
for _ , t := range appTags {
appIds = append ( appIds , t . AppId )
}
opts = append ( opts , commonRepo . WithIdsIn ( appIds ) )
2022-09-22 16:16:04 +08:00
}
var res dto . AppRes
total , apps , err := appRepo . Page ( req . Page , req . PageSize , opts ... )
if err != nil {
return nil , err
}
var appDTOs [ ] * dto . AppDTO
for _ , a := range apps {
appDTO := & dto . AppDTO {
App : a ,
}
appDTOs = append ( appDTOs , appDTO )
appTags , err := appTagRepo . GetByAppId ( a . ID )
if err != nil {
continue
}
var tagIds [ ] uint
for _ , at := range appTags {
tagIds = append ( tagIds , at . TagId )
}
tags , err := tagRepo . GetByIds ( tagIds )
if err != nil {
continue
}
appDTO . Tags = tags
}
res . Items = appDTOs
res . Total = total
tags , err := tagRepo . All ( )
if err != nil {
return nil , err
}
res . Tags = tags
return res , nil
}
2022-09-23 16:33:55 +08:00
func ( a AppService ) GetApp ( id uint ) ( dto . AppDTO , error ) {
var appDTO dto . AppDTO
app , err := appRepo . GetFirst ( commonRepo . WithByID ( id ) )
if err != nil {
return appDTO , err
}
appDTO . App = app
2022-10-03 17:35:39 +08:00
details , err := appDetailRepo . GetBy ( appDetailRepo . WithAppId ( app . ID ) )
2022-09-23 16:33:55 +08:00
if err != nil {
return appDTO , err
}
var versionsRaw [ ] string
for _ , detail := range details {
versionsRaw = append ( versionsRaw , detail . Version )
}
2022-10-03 17:35:39 +08:00
appDTO . Versions = common . GetSortedVersions ( versionsRaw )
2022-09-23 16:33:55 +08:00
return appDTO , nil
}
2022-09-26 16:32:40 +08:00
func ( a AppService ) PageInstalled ( req dto . AppInstalledRequest ) ( int64 , [ ] dto . AppInstalled , error ) {
total , installed , err := appInstallRepo . Page ( req . Page , req . PageSize )
if err != nil {
return 0 , nil , err
}
installDTOs := [ ] dto . AppInstalled { }
for _ , in := range installed {
installDto := dto . AppInstalled {
AppInstall : in ,
AppName : in . App . Name ,
Icon : in . App . Icon ,
}
installDTOs = append ( installDTOs , installDto )
}
return total , installDTOs , nil
}
2022-09-23 16:33:55 +08:00
func ( a AppService ) GetAppDetail ( appId uint , version string ) ( dto . AppDetailDTO , error ) {
var (
appDetailDTO dto . AppDetailDTO
2022-09-30 17:56:06 +08:00
opts [ ] repo . DBOption
2022-09-23 16:33:55 +08:00
)
opts = append ( opts , appDetailRepo . WithAppId ( appId ) , appDetailRepo . WithVersion ( version ) )
2022-10-03 17:35:39 +08:00
detail , err := appDetailRepo . GetFirst ( opts ... )
2022-09-23 16:33:55 +08:00
if err != nil {
return appDetailDTO , err
}
2022-09-26 16:32:40 +08:00
paramMap := make ( map [ string ] interface { } )
json . Unmarshal ( [ ] byte ( detail . Params ) , & paramMap )
2022-09-23 16:33:55 +08:00
appDetailDTO . AppDetail = detail
2022-09-26 16:32:40 +08:00
appDetailDTO . Params = paramMap
2022-09-23 16:33:55 +08:00
return appDetailDTO , nil
}
2022-09-26 18:20:21 +08:00
func ( a AppService ) Operate ( req dto . AppInstallOperate ) error {
2022-09-30 17:56:06 +08:00
install , err := appInstallRepo . GetFirst ( commonRepo . WithByID ( req . InstallId ) )
2022-09-26 18:20:21 +08:00
if err != nil {
return err
}
2022-09-29 18:16:56 +08:00
dockerComposePath := install . GetComposePath ( )
2022-09-26 18:20:21 +08:00
switch req . Operate {
case dto . Up :
out , err := compose . Up ( dockerComposePath )
if err != nil {
return handleErr ( install , err , out )
}
2022-09-27 16:57:23 +08:00
install . Status = constant . Running
2022-09-26 18:20:21 +08:00
case dto . Down :
out , err := compose . Down ( dockerComposePath )
if err != nil {
return handleErr ( install , err , out )
}
2022-09-27 16:57:23 +08:00
install . Status = constant . Stopped
2022-09-26 18:20:21 +08:00
case dto . Restart :
out , err := compose . Restart ( dockerComposePath )
if err != nil {
return handleErr ( install , err , out )
}
2022-09-27 16:57:23 +08:00
install . Status = constant . Running
2022-09-26 22:54:38 +08:00
case dto . Delete :
op := files . NewFileOp ( )
2022-09-29 18:16:56 +08:00
appDir := install . GetPath ( )
2022-09-26 22:54:38 +08:00
dir , _ := os . Stat ( appDir )
if dir == nil {
2022-10-09 23:35:24 +08:00
return appInstallRepo . Delete ( install )
2022-09-26 22:54:38 +08:00
}
2022-09-27 16:57:23 +08:00
out , err := compose . Down ( dockerComposePath )
if err != nil {
return handleErr ( install , err , out )
}
2022-09-30 17:56:06 +08:00
if err := op . DeleteDir ( appDir ) ; err != nil {
return err
2022-09-26 22:54:38 +08:00
}
2022-10-09 23:35:24 +08:00
return appInstallRepo . Delete ( install )
2022-09-29 18:16:56 +08:00
case dto . Sync :
if err := a . SyncInstalled ( install . ID ) ; err != nil {
return err
}
return nil
2022-09-26 18:20:21 +08:00
default :
return errors . New ( "operate not support" )
}
2022-09-27 16:57:23 +08:00
return appInstallRepo . Save ( install )
2022-09-26 18:20:21 +08:00
}
func handleErr ( install model . AppInstall , err error , out string ) error {
reErr := err
install . Message = err . Error ( )
if out != "" {
install . Message = out
reErr = errors . New ( out )
}
_ = appInstallRepo . Save ( install )
return reErr
}
func ( a AppService ) Install ( name string , appDetailId uint , params map [ string ] interface { } ) error {
2022-09-27 16:57:23 +08:00
2022-10-09 23:35:24 +08:00
port , ok := params [ "PANEL_APP_PORT" ]
2022-09-27 16:57:23 +08:00
if ok {
2022-09-27 22:53:24 +08:00
portStr := strconv . FormatFloat ( port . ( float64 ) , 'f' , - 1 , 32 )
if common . ScanPort ( portStr ) {
2022-10-07 15:49:39 +08:00
return errors . New ( "port is in used" )
2022-09-27 16:57:23 +08:00
}
}
2022-10-03 17:35:39 +08:00
appDetail , err := appDetailRepo . GetFirst ( commonRepo . WithByID ( appDetailId ) )
2022-09-26 16:32:40 +08:00
if err != nil {
return err
}
app , err := appRepo . GetFirst ( commonRepo . WithByID ( appDetail . AppId ) )
2022-10-07 15:49:39 +08:00
if err != nil {
return err
}
2022-10-09 23:35:24 +08:00
2022-10-07 15:49:39 +08:00
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 ) )
}
}
}
2022-09-26 16:32:40 +08:00
paramByte , err := json . Marshal ( params )
if err != nil {
return err
}
appInstall := model . AppInstall {
2022-09-29 18:16:56 +08:00
Name : name ,
AppId : appDetail . AppId ,
AppDetailId : appDetail . ID ,
Version : appDetail . Version ,
Status : constant . Installing ,
Params : string ( paramByte ) ,
2022-09-26 16:32:40 +08:00
}
2022-09-29 18:16:56 +08:00
2022-09-26 16:32:40 +08:00
resourceDir := path . Join ( global . CONF . System . ResourceDir , "apps" , app . Key , appDetail . Version )
installDir := path . Join ( global . CONF . System . AppDir , app . Key )
2022-09-29 18:16:56 +08:00
installVersionDir := path . Join ( installDir , appDetail . Version )
fileOp := files . NewFileOp ( )
if err := fileOp . Copy ( resourceDir , installVersionDir ) ; err != nil {
2022-09-26 16:32:40 +08:00
return err
}
2022-09-29 18:16:56 +08:00
appDir := path . Join ( installDir , name )
if err := fileOp . Rename ( installVersionDir , appDir ) ; err != nil {
2022-09-26 16:32:40 +08:00
return err
}
2022-09-29 18:16:56 +08:00
composeFilePath := path . Join ( appDir , "docker-compose.yml" )
envPath := path . Join ( appDir , ".env" )
2022-09-26 16:32:40 +08:00
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 err
}
2022-09-29 18:16:56 +08:00
2022-10-09 23:35:24 +08:00
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
}
}
}
2022-09-29 18:16:56 +08:00
composeMap := make ( map [ string ] interface { } )
2022-10-07 15:49:39 +08:00
if err := yaml . Unmarshal ( [ ] byte ( appDetail . DockerCompose ) , & composeMap ) ; err != nil {
2022-09-29 18:16:56 +08:00
return err
}
servicesMap := composeMap [ "services" ] . ( map [ string ] interface { } )
changeKeys := make ( map [ string ] string , len ( servicesMap ) )
var appContainers [ ] * model . AppContainer
for k , v := range servicesMap {
serviceName := k + "-" + common . RandStr ( 4 )
changeKeys [ k ] = serviceName
value := v . ( map [ string ] interface { } )
containerName := constant . ContainerPrefix + k + "-" + common . RandStr ( 4 )
value [ "container_name" ] = containerName
2022-10-07 15:49:39 +08:00
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
}
}
}
}
}
2022-09-29 18:16:56 +08:00
appContainers = append ( appContainers , & model . AppContainer {
ServiceName : serviceName ,
ContainerName : containerName ,
2022-10-07 15:49:39 +08:00
Port : servicePort ,
2022-10-09 23:35:24 +08:00
Auth : auth ,
2022-09-29 18:16:56 +08:00
} )
}
for k , v := range changeKeys {
servicesMap [ v ] = servicesMap [ k ]
delete ( servicesMap , k )
}
2022-10-07 15:49:39 +08:00
composeByte , err := yaml . Marshal ( composeMap )
2022-09-29 18:16:56 +08:00
if err != nil {
return err
}
2022-10-07 15:49:39 +08:00
if err := fileOp . WriteFile ( composeFilePath , strings . NewReader ( string ( composeByte ) ) , 0775 ) ; err != nil {
2022-09-29 18:16:56 +08:00
return err
}
2022-10-09 23:35:24 +08:00
tx := global . DB . Begin ( )
ctx := context . WithValue ( context . Background ( ) , "db" , tx )
if err := appInstallRepo . Create ( ctx , & appInstall ) ; err != nil {
tx . Rollback ( )
2022-09-26 16:32:40 +08:00
return err
}
2022-09-29 18:16:56 +08:00
for _ , c := range appContainers {
2022-10-09 23:35:24 +08:00
c . AppInstallID = appInstall . ID
2022-09-29 18:16:56 +08:00
}
2022-10-09 23:35:24 +08:00
if err := appContainerRepo . BatchCreate ( ctx , appContainers ) ; err != nil {
tx . Rollback ( )
2022-09-29 18:16:56 +08:00
return err
}
2022-10-09 23:35:24 +08:00
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
2022-09-26 16:32:40 +08:00
}
}
2022-10-09 23:35:24 +08:00
tx . Commit ( )
go upApp ( composeFilePath , appInstall )
return nil
2022-09-26 16:32:40 +08:00
}
2022-09-29 18:16:56 +08:00
func ( a AppService ) SyncAllInstalled ( ) error {
allList , err := appInstallRepo . GetBy ( )
if err != nil {
return err
}
go func ( ) {
for _ , i := range allList {
if err := a . SyncInstalled ( i . ID ) ; err != nil {
global . LOG . Errorf ( "sync install app[%s] error,mgs: %s" , i . Name , err . Error ( ) )
}
}
} ( )
2022-09-27 16:57:23 +08:00
return nil
}
2022-10-07 15:49:39 +08:00
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 {
res = append ( res , dto . AppService {
Label : install . Name ,
2022-10-09 23:35:24 +08:00
Value : container . ServiceName ,
2022-10-07 15:49:39 +08:00
} )
}
}
return res , nil
}
2022-09-29 18:16:56 +08:00
func ( a AppService ) SyncInstalled ( installId uint ) error {
appInstall , err := appInstallRepo . GetFirst ( commonRepo . WithByID ( installId ) )
if err != nil {
return err
}
var containerNames [ ] string
for _ , a := range appInstall . Containers {
containerNames = append ( containerNames , a . ContainerName )
}
cli , err := docker . NewClient ( )
if err != nil {
return err
}
containers , err := cli . ListContainersByName ( containerNames )
if err != nil {
return err
}
2022-09-30 17:56:06 +08:00
var (
errorContainers [ ] string
notFoundContainers [ ] string
runningContainers [ ] string
)
2022-09-29 18:16:56 +08:00
for _ , n := range containers {
if n . State != "running" {
2022-09-30 17:56:06 +08:00
errorContainers = append ( errorContainers , n . Names [ 0 ] )
} else {
runningContainers = append ( runningContainers , n . Names [ 0 ] )
2022-09-29 18:16:56 +08:00
}
}
for _ , old := range containerNames {
exist := false
for _ , new := range containers {
if common . ExistWithStrArray ( old , new . Names ) {
exist = true
break
}
}
if ! exist {
notFoundContainers = append ( notFoundContainers , old )
}
}
2022-09-30 17:56:06 +08:00
containerCount := len ( containers )
errCount := len ( errorContainers )
notFoundCount := len ( notFoundContainers )
normalCount := len ( containerNames )
runningCount := len ( runningContainers )
if containerCount == 0 {
2022-09-29 18:16:56 +08:00
appInstall . Status = constant . Error
appInstall . Message = "container is not found"
return appInstallRepo . Save ( appInstall )
}
2022-09-30 17:56:06 +08:00
if errCount == 0 && notFoundCount == 0 {
2022-09-29 18:16:56 +08:00
appInstall . Status = constant . Running
return appInstallRepo . Save ( appInstall )
}
2022-09-30 17:56:06 +08:00
if errCount == normalCount {
2022-09-29 18:16:56 +08:00
appInstall . Status = constant . Error
}
2022-09-30 17:56:06 +08:00
if notFoundCount == normalCount {
2022-09-29 18:16:56 +08:00
appInstall . Status = constant . Stopped
}
2022-09-30 17:56:06 +08:00
if runningCount < normalCount {
appInstall . Status = constant . UnHealthy
}
2022-09-29 18:16:56 +08:00
var errMsg strings . Builder
2022-09-30 17:56:06 +08:00
if errCount > 0 {
errMsg . Write ( [ ] byte ( string ( rune ( errCount ) ) + " error containers:" ) )
2022-09-29 18:16:56 +08:00
for _ , e := range errorContainers {
errMsg . Write ( [ ] byte ( e ) )
}
errMsg . Write ( [ ] byte ( "\n" ) )
}
2022-09-30 17:56:06 +08:00
if notFoundCount > 0 {
errMsg . Write ( [ ] byte ( string ( rune ( notFoundCount ) ) + " not found containers:" ) )
2022-09-29 18:16:56 +08:00
for _ , e := range notFoundContainers {
errMsg . Write ( [ ] byte ( e ) )
}
errMsg . Write ( [ ] byte ( "\n" ) )
}
appInstall . Message = errMsg . String ( )
return appInstallRepo . Save ( appInstall )
}
func ( a AppService ) SyncAppList ( ) error {
2022-09-22 16:16:04 +08:00
//TODO 从 oss 拉取最新列表
appDir := path . Join ( global . CONF . System . ResourceDir , "apps" )
iconDir := path . Join ( appDir , "icons" )
listFile := path . Join ( appDir , "list.json" )
content , err := os . ReadFile ( listFile )
if err != nil {
return err
}
list := & dto . AppList { }
if err := json . Unmarshal ( content , list ) ; err != nil {
return err
}
var (
2022-09-30 17:56:06 +08:00
tags [ ] * model . Tag
appTags [ ] * model . AppTag
2022-09-22 16:16:04 +08:00
)
for _ , t := range list . Tags {
tags = append ( tags , & model . Tag {
Key : t . Key ,
Name : t . Name ,
} )
}
2022-09-30 17:56:06 +08:00
oldApps , err := appRepo . GetBy ( )
if err != nil {
return err
}
appsMap := getApps ( oldApps , list . Items )
2022-09-22 16:16:04 +08:00
for _ , l := range list . Items {
2022-09-30 17:56:06 +08:00
app := appsMap [ l . Key ]
2022-09-22 16:16:04 +08:00
icon , err := os . ReadFile ( path . Join ( iconDir , l . Icon ) )
if err != nil {
global . LOG . Errorf ( "get [%s] icon error: %s" , l . Name , err . Error ( ) )
continue
}
iconStr := base64 . StdEncoding . EncodeToString ( icon )
2022-09-30 17:56:06 +08:00
app . Icon = iconStr
2022-09-22 16:16:04 +08:00
app . TagsKey = l . Tags
versions := l . Versions
2022-09-30 17:56:06 +08:00
detailsMap := getAppDetails ( app . Details , versions )
2022-09-22 16:16:04 +08:00
for _ , v := range versions {
2022-09-30 17:56:06 +08:00
detail := detailsMap [ v ]
2022-09-22 16:16:04 +08:00
detailPath := path . Join ( appDir , l . Key , v )
if _ , err := os . Stat ( detailPath ) ; err != nil {
global . LOG . Errorf ( "get [%s] folder error: %s" , detailPath , err . Error ( ) )
continue
}
readmeStr , err := os . ReadFile ( path . Join ( detailPath , "README.md" ) )
if err != nil {
global . LOG . Errorf ( "get [%s] README error: %s" , detailPath , err . Error ( ) )
}
detail . Readme = string ( readmeStr )
dockerComposeStr , err := os . ReadFile ( path . Join ( detailPath , "docker-compose.yml" ) )
if err != nil {
global . LOG . Errorf ( "get [%s] docker-compose.yml error: %s" , detailPath , err . Error ( ) )
continue
}
detail . DockerCompose = string ( dockerComposeStr )
2022-09-26 16:32:40 +08:00
paramStr , err := os . ReadFile ( path . Join ( detailPath , "params.json" ) )
2022-09-22 16:16:04 +08:00
if err != nil {
global . LOG . Errorf ( "get [%s] form.json error: %s" , detailPath , err . Error ( ) )
}
2022-09-26 16:32:40 +08:00
detail . Params = string ( paramStr )
2022-09-30 17:56:06 +08:00
detailsMap [ v ] = detail
}
var newDetails [ ] model . AppDetail
for _ , v := range detailsMap {
newDetails = append ( newDetails , v )
2022-09-22 16:16:04 +08:00
}
2022-09-30 17:56:06 +08:00
app . Details = newDetails
appsMap [ l . Key ] = app
2022-09-22 16:16:04 +08:00
}
2022-09-30 17:56:06 +08:00
var (
addAppArray [ ] model . App
updateArray [ ] model . App
)
tagMap := make ( map [ string ] uint , len ( tags ) )
for _ , v := range appsMap {
if v . ID == 0 {
addAppArray = append ( addAppArray , v )
} else {
updateArray = append ( updateArray , v )
}
}
2022-09-22 16:16:04 +08:00
tx := global . DB . Begin ( )
ctx := context . WithValue ( context . Background ( ) , "db" , tx )
2022-09-30 17:56:06 +08:00
if len ( addAppArray ) > 0 {
if err := appRepo . BatchCreate ( ctx , addAppArray ) ; err != nil {
2022-09-22 16:16:04 +08:00
tx . Rollback ( )
return err
}
}
if err := tagRepo . DeleteAll ( ctx ) ; err != nil {
tx . Rollback ( )
return err
}
if len ( tags ) > 0 {
if err := tagRepo . BatchCreate ( ctx , tags ) ; err != nil {
tx . Rollback ( )
return err
}
2022-09-30 17:56:06 +08:00
for _ , t := range tags {
tagMap [ t . Key ] = t . ID
}
2022-09-22 16:16:04 +08:00
}
2022-09-30 17:56:06 +08:00
for _ , update := range updateArray {
if err := appRepo . Save ( ctx , & update ) ; err != nil {
2022-09-22 16:16:04 +08:00
tx . Rollback ( )
return err
}
}
2022-09-30 17:56:06 +08:00
apps := append ( addAppArray , updateArray ... )
2022-09-22 16:16:04 +08:00
var (
2022-09-30 17:56:06 +08:00
addDetails [ ] model . AppDetail
updateDetails [ ] model . AppDetail
2022-09-22 16:16:04 +08:00
)
for _ , a := range apps {
for _ , t := range a . TagsKey {
tagId , ok := tagMap [ t ]
if ok {
appTags = append ( appTags , & model . AppTag {
AppId : a . ID ,
TagId : tagId ,
} )
}
}
for _ , d := range a . Details {
d . AppId = a . ID
2022-09-30 17:56:06 +08:00
if d . ID == 0 {
addDetails = append ( addDetails , d )
} else {
updateDetails = append ( updateDetails , d )
}
2022-09-22 16:16:04 +08:00
}
}
2022-09-30 17:56:06 +08:00
if len ( addDetails ) > 0 {
if err := appDetailRepo . BatchCreate ( ctx , addDetails ) ; err != nil {
tx . Rollback ( )
return err
}
2022-09-22 16:16:04 +08:00
}
2022-09-30 17:56:06 +08:00
for _ , u := range updateDetails {
if err := appDetailRepo . Update ( ctx , u ) ; err != nil {
2022-09-22 16:16:04 +08:00
tx . Rollback ( )
return err
}
}
2022-09-30 17:56:06 +08:00
if err := appTagRepo . DeleteAll ( ctx ) ; err != nil {
2022-09-22 16:16:04 +08:00
tx . Rollback ( )
return err
}
if len ( appTags ) > 0 {
if err := appTagRepo . BatchCreate ( ctx , appTags ) ; err != nil {
tx . Rollback ( )
return err
}
}
tx . Commit ( )
2022-10-03 17:35:39 +08:00
go syncCanUpdate ( )
2022-09-22 16:16:04 +08:00
return nil
}
2022-10-03 17:35:39 +08:00
func syncCanUpdate ( ) {
apps , err := appRepo . GetBy ( )
if err != nil {
global . LOG . Errorf ( "sync update app error: %s" , err . Error ( ) )
}
for _ , app := range apps {
details , err := appDetailRepo . GetBy ( appDetailRepo . WithAppId ( app . ID ) )
if err != nil {
global . LOG . Errorf ( "sync update app error: %s" , err . Error ( ) )
}
var versions [ ] string
for _ , detail := range details {
versions = append ( versions , detail . Version )
}
versions = common . GetSortedVersions ( versions )
lastVersion := versions [ 0 ]
var updateDetailIds [ ] uint
for _ , detail := range details {
if common . CompareVersion ( lastVersion , detail . Version ) {
if app . CrossVersionUpdate || ! common . IsCrossVersion ( detail . Version , lastVersion ) {
updateDetailIds = append ( updateDetailIds , detail . ID )
}
}
}
if len ( updateDetailIds ) > 0 {
if err := appDetailRepo . BatchUpdateBy ( model . AppDetail { LastVersion : lastVersion } , commonRepo . WithIdsIn ( updateDetailIds ) ) ; err != nil {
global . LOG . Errorf ( "sync update app error: %s" , err . Error ( ) )
}
if err := appInstallRepo . BatchUpdateBy ( model . AppInstall { CanUpdate : true } , appInstallRepo . WithDetailIdsIn ( updateDetailIds ) ) ; err != nil {
global . LOG . Errorf ( "sync update app error: %s" , err . Error ( ) )
}
}
}
}
2022-10-09 23:35:24 +08:00
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
}