2018-05-07 15:10:12 +08:00
|
|
|
// RAINBOND, Application Management Platform
|
|
|
|
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version. For any non-GPL usage of Rainbond,
|
|
|
|
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
|
|
|
|
// must be obtained first.
|
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
package exector
|
2018-05-17 11:27:04 +08:00
|
|
|
|
|
|
|
import (
|
2018-05-23 14:26:27 +08:00
|
|
|
"encoding/json"
|
2018-05-23 11:08:44 +08:00
|
|
|
"errors"
|
2018-05-17 11:27:04 +08:00
|
|
|
"fmt"
|
2022-09-29 23:49:56 +08:00
|
|
|
|
|
|
|
"github.com/goodrain/rainbond/builder/sources"
|
2018-05-28 11:14:56 +08:00
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
2021-02-02 11:22:30 +08:00
|
|
|
"path"
|
2018-05-28 11:14:56 +08:00
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
2021-02-02 11:22:30 +08:00
|
|
|
"sync"
|
2018-05-28 11:14:56 +08:00
|
|
|
"time"
|
|
|
|
|
2021-02-02 11:22:30 +08:00
|
|
|
"github.com/goodrain/rainbond-oam/pkg/localimport"
|
|
|
|
"github.com/goodrain/rainbond-oam/pkg/ram/v1alpha1"
|
2018-05-23 14:26:27 +08:00
|
|
|
"github.com/goodrain/rainbond/api/model"
|
2019-03-29 18:28:01 +08:00
|
|
|
"github.com/goodrain/rainbond/builder"
|
2018-05-17 16:10:44 +08:00
|
|
|
"github.com/goodrain/rainbond/db"
|
2018-05-23 11:08:44 +08:00
|
|
|
"github.com/goodrain/rainbond/event"
|
2020-11-25 16:39:38 +08:00
|
|
|
"github.com/sirupsen/logrus"
|
2018-05-17 11:27:04 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
2018-05-17 16:10:44 +08:00
|
|
|
RegisterWorker("import_app", NewImportApp)
|
|
|
|
}
|
|
|
|
|
2018-05-28 11:14:56 +08:00
|
|
|
//ImportApp Export app to specified format(rainbond-app or dockercompose)
|
2018-05-17 16:10:44 +08:00
|
|
|
type ImportApp struct {
|
2020-06-27 14:06:27 +08:00
|
|
|
EventID string `json:"event_id"`
|
|
|
|
Format string `json:"format"`
|
|
|
|
SourceDir string `json:"source_dir"`
|
|
|
|
Apps []string `json:"apps"`
|
|
|
|
ServiceImage model.ServiceImage `json:"service_image"`
|
2018-09-25 19:22:28 +08:00
|
|
|
Logger event.Logger
|
|
|
|
oldAPPPath map[string]string
|
|
|
|
oldPluginPath map[string]string
|
2022-09-30 00:39:33 +08:00
|
|
|
ImageClient sources.ImageClient
|
2018-05-17 16:10:44 +08:00
|
|
|
}
|
|
|
|
|
2018-05-28 11:14:56 +08:00
|
|
|
//NewImportApp create
|
|
|
|
func NewImportApp(in []byte, m *exectorManager) (TaskWorker, error) {
|
2020-06-27 14:06:27 +08:00
|
|
|
var importApp ImportApp
|
|
|
|
if err := json.Unmarshal(in, &importApp); err != nil {
|
2018-05-23 11:13:19 +08:00
|
|
|
return nil, err
|
2018-05-21 22:10:49 +08:00
|
|
|
}
|
2021-02-02 11:22:30 +08:00
|
|
|
if importApp.ServiceImage.HubURL == "" || importApp.ServiceImage.HubURL == "goodrain.me" {
|
2021-01-05 16:21:23 +08:00
|
|
|
importApp.ServiceImage.HubURL = builder.REGISTRYDOMAIN
|
2020-06-27 14:06:27 +08:00
|
|
|
importApp.ServiceImage.HubUser = builder.REGISTRYUSER
|
|
|
|
importApp.ServiceImage.HubPassword = builder.REGISTRYPASS
|
2018-05-23 14:26:27 +08:00
|
|
|
}
|
2021-02-02 11:22:30 +08:00
|
|
|
logrus.Infof("load app image to hub %s", importApp.ServiceImage.HubURL)
|
2020-06-27 14:06:27 +08:00
|
|
|
importApp.Logger = event.GetManager().GetLogger(importApp.EventID)
|
2022-09-29 23:49:56 +08:00
|
|
|
importApp.ImageClient = m.imageClient
|
2022-09-30 00:39:33 +08:00
|
|
|
|
2020-06-27 14:06:27 +08:00
|
|
|
importApp.oldAPPPath = make(map[string]string)
|
|
|
|
importApp.oldPluginPath = make(map[string]string)
|
|
|
|
return &importApp, nil
|
2018-05-17 16:10:44 +08:00
|
|
|
}
|
|
|
|
|
2018-05-17 19:04:48 +08:00
|
|
|
//Stop stop
|
|
|
|
func (i *ImportApp) Stop() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
//Name return worker name
|
|
|
|
func (i *ImportApp) Name() string {
|
2020-12-09 23:25:32 +08:00
|
|
|
return "import_app"
|
2018-05-17 19:04:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//GetLogger GetLogger
|
|
|
|
func (i *ImportApp) GetLogger() event.Logger {
|
|
|
|
return i.Logger
|
|
|
|
}
|
|
|
|
|
2018-05-23 14:26:27 +08:00
|
|
|
//ErrorCallBack if run error will callback
|
|
|
|
func (i *ImportApp) ErrorCallBack(err error) {
|
2021-02-02 11:22:30 +08:00
|
|
|
i.updateStatus("failed")
|
2018-05-23 14:26:27 +08:00
|
|
|
}
|
|
|
|
|
2018-05-17 16:10:44 +08:00
|
|
|
//Run Run
|
|
|
|
func (i *ImportApp) Run(timeout time.Duration) error {
|
|
|
|
if i.Format == "rainbond-app" {
|
|
|
|
err := i.importApp()
|
|
|
|
if err != nil {
|
2021-02-02 11:22:30 +08:00
|
|
|
logrus.Errorf("load rainbond app failure %s", err.Error())
|
2018-05-24 09:51:09 +08:00
|
|
|
return err
|
2018-05-17 16:10:44 +08:00
|
|
|
}
|
2018-05-24 09:51:09 +08:00
|
|
|
return nil
|
2018-05-17 16:10:44 +08:00
|
|
|
}
|
2018-09-20 13:22:33 +08:00
|
|
|
return errors.New("Unsupported the format: " + i.Format)
|
2018-05-17 11:27:04 +08:00
|
|
|
}
|
|
|
|
|
2018-09-20 13:22:33 +08:00
|
|
|
// importApp import app
|
|
|
|
// support batch import
|
2018-05-17 16:10:44 +08:00
|
|
|
func (i *ImportApp) importApp() error {
|
2018-05-21 18:21:42 +08:00
|
|
|
oldSourceDir := i.SourceDir
|
2021-02-02 11:22:30 +08:00
|
|
|
var datas []v1alpha1.RainbondApplicationConfig
|
|
|
|
var wait sync.WaitGroup
|
2018-05-23 14:26:27 +08:00
|
|
|
for _, app := range i.Apps {
|
2021-02-02 11:22:30 +08:00
|
|
|
wait.Add(1)
|
|
|
|
go func(app string) {
|
|
|
|
defer wait.Done()
|
|
|
|
appFile := filepath.Join(oldSourceDir, app)
|
|
|
|
tmpDir := path.Join(oldSourceDir, app+"-cache")
|
2022-09-29 23:49:56 +08:00
|
|
|
li, err := localimport.New(logrus.StandardLogger(), i.ImageClient.GetContainerdClient(), i.ImageClient.GetDockerClient(), tmpDir)
|
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf("create localimport failure %s", err.Error())
|
|
|
|
return
|
|
|
|
}
|
2021-02-02 11:22:30 +08:00
|
|
|
if err := i.updateStatusForApp(app, "importing"); err != nil {
|
|
|
|
logrus.Errorf("Failed to update status to importing for app %s: %v", app, err)
|
2018-09-10 19:30:00 +08:00
|
|
|
}
|
2021-02-02 11:22:30 +08:00
|
|
|
ram, err := li.Import(appFile, v1alpha1.ImageInfo{
|
|
|
|
HubURL: i.ServiceImage.HubURL,
|
|
|
|
HubUser: i.ServiceImage.HubUser,
|
|
|
|
HubPassword: i.ServiceImage.HubPassword,
|
|
|
|
Namespace: i.ServiceImage.NameSpace,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf("Failed to load app %s: %v", appFile, err)
|
|
|
|
i.updateStatusForApp(app, "failed")
|
|
|
|
return
|
2018-09-10 19:30:00 +08:00
|
|
|
}
|
2021-02-02 11:22:30 +08:00
|
|
|
os.Rename(appFile, appFile+".success")
|
|
|
|
datas = append(datas, *ram)
|
|
|
|
logrus.Infof("Successful import app: %s", appFile)
|
|
|
|
os.Remove(tmpDir)
|
|
|
|
}(app)
|
2018-05-21 18:21:42 +08:00
|
|
|
}
|
2021-02-02 11:22:30 +08:00
|
|
|
wait.Wait()
|
2018-05-28 21:55:58 +08:00
|
|
|
metadatasFile := fmt.Sprintf("%s/metadatas.json", i.SourceDir)
|
2021-02-02 11:22:30 +08:00
|
|
|
dataBytes, _ := json.Marshal(datas)
|
|
|
|
if err := ioutil.WriteFile(metadatasFile, []byte(dataBytes), 0644); err != nil {
|
2018-05-28 21:55:58 +08:00
|
|
|
logrus.Errorf("Failed to load apps %s: %v", i.SourceDir, err)
|
2018-10-10 22:34:08 +08:00
|
|
|
return err
|
2018-05-28 21:55:58 +08:00
|
|
|
}
|
2021-02-02 11:22:30 +08:00
|
|
|
if err := i.updateStatus("success"); err != nil {
|
2018-05-23 14:26:27 +08:00
|
|
|
logrus.Errorf("Failed to load apps %s: %v", i.SourceDir, err)
|
2018-10-10 22:34:08 +08:00
|
|
|
return err
|
2018-05-17 11:27:04 +08:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-02-02 11:22:30 +08:00
|
|
|
func (i *ImportApp) updateStatus(status string) error {
|
2018-05-17 16:10:44 +08:00
|
|
|
logrus.Debug("Update app status in database to: ", status)
|
|
|
|
// 从数据库中获取该应用的状态信息
|
|
|
|
res, err := db.GetManager().AppDao().GetByEventId(i.EventID)
|
|
|
|
if err != nil {
|
2018-09-20 13:22:33 +08:00
|
|
|
err = fmt.Errorf("failed to get app %s from db: %s", i.EventID, err.Error())
|
2018-05-17 16:10:44 +08:00
|
|
|
logrus.Error(err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// 在数据库中更新该应用的状态信息
|
2018-05-21 18:37:35 +08:00
|
|
|
res.Status = status
|
2018-05-17 16:10:44 +08:00
|
|
|
|
2018-05-21 18:37:35 +08:00
|
|
|
if err := db.GetManager().AppDao().UpdateModel(res); err != nil {
|
2018-09-20 13:22:33 +08:00
|
|
|
err = fmt.Errorf("failed to update app %s: %s", i.EventID, err.Error())
|
2018-05-17 16:10:44 +08:00
|
|
|
logrus.Error(err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2018-05-23 14:26:27 +08:00
|
|
|
|
|
|
|
func (i *ImportApp) updateStatusForApp(app, status string) error {
|
2018-05-23 15:53:12 +08:00
|
|
|
logrus.Debugf("Update status in database for app %s to: %s", app, status)
|
2018-05-23 14:26:27 +08:00
|
|
|
// 从数据库中获取该应用的状态信息
|
|
|
|
res, err := db.GetManager().AppDao().GetByEventId(i.EventID)
|
|
|
|
if err != nil {
|
2018-09-20 13:22:33 +08:00
|
|
|
err = fmt.Errorf("Failed to get app %s from db: %s", i.EventID, err.Error())
|
2018-05-23 14:26:27 +08:00
|
|
|
logrus.Error(err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// 在数据库中更新该应用的状态信息
|
2018-05-23 15:53:12 +08:00
|
|
|
appsMap := str2map(res.Apps)
|
|
|
|
appsMap[app] = status
|
|
|
|
res.Apps = map2str(appsMap)
|
2018-05-23 14:26:27 +08:00
|
|
|
|
|
|
|
if err := db.GetManager().AppDao().UpdateModel(res); err != nil {
|
2018-09-20 13:22:33 +08:00
|
|
|
err = fmt.Errorf("Failed to update app %s: %s", i.EventID, err.Error())
|
2018-05-23 14:26:27 +08:00
|
|
|
logrus.Error(err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func str2map(str string) map[string]string {
|
|
|
|
result := make(map[string]string, 10)
|
|
|
|
|
|
|
|
for _, app := range strings.Split(str, ",") {
|
|
|
|
appMap := strings.Split(app, ":")
|
|
|
|
result[appMap[0]] = appMap[1]
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
func map2str(m map[string]string) string {
|
|
|
|
var result string
|
|
|
|
|
|
|
|
for k, v := range m {
|
|
|
|
kv := k + ":" + v
|
|
|
|
|
|
|
|
if result == "" {
|
|
|
|
result += kv
|
|
|
|
} else {
|
|
|
|
result += "," + kv
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
2018-06-10 19:08:01 +08:00
|
|
|
|
|
|
|
// 只保留"/"后面的部分,并去掉不合法字符,一般用于把导出的镜像文件还原为镜像名
|
|
|
|
func buildFromLinuxFileName(fileName string) string {
|
|
|
|
if fileName == "" {
|
|
|
|
return fileName
|
|
|
|
}
|
|
|
|
|
|
|
|
arr := strings.Split(fileName, "/")
|
|
|
|
|
|
|
|
if str := arr[len(arr)-1]; str == "" {
|
|
|
|
fileName = strings.Replace(fileName, "---", "/", -1)
|
|
|
|
} else {
|
|
|
|
fileName = str
|
|
|
|
}
|
|
|
|
|
|
|
|
fileName = strings.Replace(fileName, "--", ":", -1)
|
|
|
|
fileName = strings.TrimSpace(fileName)
|
|
|
|
|
|
|
|
return fileName
|
|
|
|
}
|