[ADD] add plugin share code (#74)

This commit is contained in:
barnettZQG 2018-05-29 12:51:10 +08:00
parent 1e5f063f98
commit 6d810cd810
17 changed files with 435 additions and 259 deletions

View File

@ -114,6 +114,8 @@ type PluginInterface interface {
GePluginEnvWhichCanBeSet(w http.ResponseWriter, r *http.Request)
UpdateVersionEnv(w http.ResponseWriter, r *http.Request)
GetPluginDefaultEnvs(w http.ResponseWriter, r *http.Request)
SharePlugin(w http.ResponseWriter, r *http.Request)
SharePluginResult(w http.ResponseWriter, r *http.Request)
}
//RulesInterface RulesInterface

View File

@ -78,6 +78,8 @@ func (v2 *V2) tenantNameRouter() chi.Router {
//创建应用
r.Post("/services", controller.GetManager().CreateService)
r.Post("/plugin", controller.GetManager().PluginAction)
r.Post("/plugins/{plugin_id}/share", controller.GetManager().SharePlugin)
r.Post("/plugins/{plugin_id}/share/{share_id}", controller.GetManager().SharePluginResult)
r.Get("/plugin", controller.GetManager().PluginAction)
r.Post("/services_status", controller.GetManager().StatusServiceList)
r.Mount("/services/{service_alias}", v2.serviceRouter())

View File

@ -21,10 +21,12 @@ package controller
import (
"net/http"
"github.com/goodrain/rainbond/api/handler"
"github.com/goodrain/rainbond/api/middleware"
"github.com/goodrain/rainbond/api/handler/share"
"github.com/go-chi/chi"
"github.com/goodrain/rainbond/api/handler"
"github.com/goodrain/rainbond/api/middleware"
"github.com/goodrain/rainbond/util"
api_model "github.com/goodrain/rainbond/api/model"
httputil "github.com/goodrain/rainbond/util/http"
@ -611,3 +613,35 @@ func (t *TenantStruct) UpdateVersionEnv(w http.ResponseWriter, r *http.Request)
}
httputil.ReturnSuccess(r, w, nil)
}
//SharePlugin share tenants plugin
func (t *TenantStruct) SharePlugin(w http.ResponseWriter, r *http.Request) {
var sp share.PluginShare
ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &sp.Body, nil)
if !ok {
return
}
tenantID := r.Context().Value(middleware.ContextKey("tenant_id")).(string)
sp.TenantID = tenantID
sp.PluginID = chi.URLParam(r, "plugin_id")
if sp.Body.EventID == "" {
sp.Body.EventID = util.NewUUID()
}
res, errS := handler.GetPluginShareHandle().Share(sp)
if errS != nil {
errS.Handle(r, w)
return
}
httputil.ReturnSuccess(r, w, res)
}
//SharePluginResult SharePluginResult
func (t *TenantStruct) SharePluginResult(w http.ResponseWriter, r *http.Request) {
shareID := chi.URLParam(r, "share_id")
res, errS := handler.GetPluginShareHandle().ShareResult(shareID)
if errS != nil {
errS.Handle(r, w)
return
}
httputil.ReturnSuccess(r, w, res)
}

View File

@ -70,6 +70,7 @@ func InitHandle(conf option.Config, statusCli *client.AppRuntimeSyncClient) erro
//需要使用etcd v2 API
defaultEventHandler = CreateLogManager(conf.EtcdEndpoint)
shareHandler = &share.ServiceShareHandle{MQClient: mqClient, EtcdCli: etcdCli}
pluginShareHandler = &share.PluginShareHandle{MQClient: mqClient, EtcdCli: etcdCli}
if err := CreateTokenIdenHandler(conf); err != nil {
logrus.Errorf("create token identification mannager error, %v", err)
return err
@ -79,12 +80,18 @@ func InitHandle(conf option.Config, statusCli *client.AppRuntimeSyncClient) erro
var defaultServieHandler ServiceHandler
var shareHandler *share.ServiceShareHandle
var pluginShareHandler *share.PluginShareHandle
//GetShareHandle get share handle
func GetShareHandle() *share.ServiceShareHandle {
return shareHandler
}
//GetPluginShareHandle get plugin share handle
func GetPluginShareHandle() *share.PluginShareHandle {
return pluginShareHandler
}
//GetServiceManager get manager
func GetServiceManager() ServiceHandler {
return defaultServieHandler

View File

@ -20,14 +20,10 @@ package handler
import (
"context"
"crypto/md5"
"encoding/hex"
"fmt"
"strings"
"time"
"github.com/jinzhu/gorm"
api_db "github.com/goodrain/rainbond/api/db"
api_model "github.com/goodrain/rainbond/api/model"
"github.com/goodrain/rainbond/api/util"
@ -35,6 +31,7 @@ import (
dbmodel "github.com/goodrain/rainbond/db/model"
"github.com/goodrain/rainbond/event"
"github.com/goodrain/rainbond/mq/api/grpc/pb"
core_util "github.com/goodrain/rainbond/util"
"github.com/pquerna/ffjson/ffjson"
@ -217,23 +214,9 @@ func (p *PluginAction) BuildPluginManual(bps *api_model.BuildPluginStruct) (*dbm
if err != nil {
return nil, util.CreateAPIHandleErrorFromDBError(fmt.Sprintf("get plugin by %v", bps.PluginID), err)
}
if bps.Body.PluginFrom != "" {
switch bps.Body.PluginFrom {
case "yb":
pbv, err := p.InstallPluginFromYB(bps, plugin)
if err != nil {
logrus.Debugf("install plugin from yb error %s", err.Error())
return nil, util.CreateAPIHandleError(500, fmt.Errorf("install plugin from yb error"))
}
return pbv, nil
case "ys":
default:
return nil, util.CreateAPIHandleError(400, fmt.Errorf("unexpect plugin from"))
}
}
switch plugin.BuildModel {
case "image":
pbv, err := p.ImageBuildPlugin(bps, plugin)
pbv, err := p.buildPlugin(bps, plugin)
if err != nil {
logrus.Error("build plugin from image error ", err.Error())
logger.Error("从镜像构建插件任务发送失败 "+err.Error(), map[string]string{"step": "callback", "status": "failure"})
@ -242,7 +225,7 @@ func (p *PluginAction) BuildPluginManual(bps *api_model.BuildPluginStruct) (*dbm
logger.Info("从镜像构建插件任务发送成功 ", map[string]string{"step": "image-plugin", "status": "starting"})
return pbv, nil
case "dockerfile":
pbv, err := p.DockerfileBuildPlugin(bps, plugin)
pbv, err := p.buildPlugin(bps, plugin)
if err != nil {
logrus.Error("build plugin from image error ", err.Error())
logger.Error("从dockerfile构建插件任务发送失败 "+err.Error(), map[string]string{"step": "callback", "status": "failure"})
@ -255,42 +238,8 @@ func (p *PluginAction) BuildPluginManual(bps *api_model.BuildPluginStruct) (*dbm
}
}
func createVersionID(s []byte) string {
h := md5.New()
h.Write(s)
return hex.EncodeToString(h.Sum(nil))
}
//InstallPluginFromYB InstallPluginFromYB
func (p *PluginAction) InstallPluginFromYB(b *api_model.BuildPluginStruct, plugin *dbmodel.TenantPlugin) (
*dbmodel.TenantPluginBuildVersion, error) {
if b.Body.Operator == "" {
b.Body.Operator = "define"
}
pbv := &dbmodel.TenantPluginBuildVersion{
VersionID: b.Body.BuildVersion,
PluginID: b.PluginID,
Kind: plugin.BuildModel,
BaseImage: plugin.ImageURL,
BuildLocalImage: b.Body.BuildImage,
ContainerCPU: b.Body.PluginCPU,
ContainerMemory: b.Body.PluginMemory,
ContainerCMD: b.Body.PluginCMD,
BuildTime: time.Now().Format(time.RFC3339),
Info: b.Body.Info,
Status: "complete",
}
if err := db.GetManager().TenantPluginBuildVersionDao().AddModel(pbv); err != nil {
if !strings.Contains(err.Error(), "exist") {
logrus.Errorf("build plugin error: %s", err.Error())
return nil, err
}
}
return pbv, nil
}
//ImageBuildPlugin ImageBuildPlugin
func (p *PluginAction) ImageBuildPlugin(b *api_model.BuildPluginStruct, plugin *dbmodel.TenantPlugin) (
//buildPlugin buildPlugin
func (p *PluginAction) buildPlugin(b *api_model.BuildPluginStruct, plugin *dbmodel.TenantPlugin) (
*dbmodel.TenantPluginBuildVersion, error) {
if plugin.ImageURL == "" {
return nil, fmt.Errorf("need image url")
@ -298,66 +247,42 @@ func (p *PluginAction) ImageBuildPlugin(b *api_model.BuildPluginStruct, plugin *
if b.Body.Operator == "" {
b.Body.Operator = "define"
}
//TODO: build_version create in console
//diffStr := fmt.Sprintf("%s%s%s%s", b.TenantName, plugin.ImageURL, b.PluginID, time.Now().Format(time.RFC3339))
//buildVersion := createVersionID([]byte(diffStr))
rebuild := false
tpbv, err := db.GetManager().TenantPluginBuildVersionDao().GetBuildVersionByVersionID(
b.PluginID, b.Body.BuildVersion)
if err != nil {
if err.Error() == gorm.ErrRecordNotFound.Error() {
rebuild = false
} else {
if b.Body.BuildVersion == "" {
return nil, fmt.Errorf("build version can not be empty")
}
if b.Body.DeployVersion == "" {
b.Body.DeployVersion = core_util.CreateVersionByTime()
}
pbv := &dbmodel.TenantPluginBuildVersion{
VersionID: b.Body.BuildVersion,
DeployVersion: b.Body.DeployVersion,
PluginID: b.PluginID,
Kind: plugin.BuildModel,
Repo: b.Body.RepoURL,
GitURL: plugin.GitURL,
BaseImage: plugin.ImageURL,
ContainerCPU: b.Body.PluginCPU,
ContainerMemory: b.Body.PluginMemory,
ContainerCMD: b.Body.PluginCMD,
BuildTime: time.Now().Format(time.RFC3339),
Info: b.Body.Info,
Status: "building",
}
if b.Body.PluginCPU == 0 {
pbv.ContainerCPU = 125
}
if b.Body.PluginMemory == 0 {
pbv.ContainerMemory = 50
}
if err := db.GetManager().TenantPluginBuildVersionDao().AddModel(pbv); err != nil {
if !strings.Contains(err.Error(), "exist") {
logrus.Errorf("build plugin error: %s", err.Error())
return nil, err
}
} else {
rebuild = true
}
tx := db.GetManager().Begin()
if rebuild {
tpbv.Info = b.Body.Info
tpbv.Status = "building"
tpbv.BuildTime = time.Now().Format(time.RFC3339)
if b.Body.PluginCPU == 0 {
tpbv.ContainerCPU = 125
}
if b.Body.PluginMemory == 0 {
tpbv.ContainerMemory = 50
}
if err := db.GetManager().TenantPluginBuildVersionDaoTransactions(tx).UpdateModel(tpbv); err != nil {
if err != nil {
tx.Rollback()
logrus.Errorf("build plugin error: %s", err.Error())
return nil, err
}
}
} else {
pbv := &dbmodel.TenantPluginBuildVersion{
VersionID: b.Body.BuildVersion,
PluginID: b.PluginID,
Kind: plugin.BuildModel,
BaseImage: plugin.ImageURL,
ContainerCPU: b.Body.PluginCPU,
ContainerMemory: b.Body.PluginMemory,
ContainerCMD: b.Body.PluginCMD,
BuildTime: time.Now().Format(time.RFC3339),
Info: b.Body.Info,
Status: "building",
}
if b.Body.PluginCPU == 0 {
pbv.ContainerCPU = 125
}
if b.Body.PluginMemory == 0 {
pbv.ContainerMemory = 50
}
if err := db.GetManager().TenantPluginBuildVersionDaoTransactions(tx).AddModel(pbv); err != nil {
if !strings.Contains(err.Error(), "exist") {
tx.Rollback()
logrus.Errorf("build plugin error: %s", err.Error())
return nil, err
}
}
tpbv = pbv
var updateVersion = func() {
pbv.Status = "failure"
db.GetManager().TenantPluginBuildVersionDao().UpdateModel(pbv)
}
taskBody := &builder_model.BuildPluginTaskBody{
TenantID: b.Body.TenantID,
@ -371,161 +296,41 @@ func (p *PluginAction) ImageBuildPlugin(b *api_model.BuildPluginStruct, plugin *
PluginCPU: b.Body.PluginCPU,
PluginMemory: b.Body.PluginMemory,
VersionID: b.Body.BuildVersion,
ImageInfo: b.Body.ImageInfo,
Repo: b.Body.RepoURL,
GitURL: plugin.GitURL,
}
jtask, errJ := ffjson.Marshal(taskBody)
if errJ != nil {
tx.Rollback()
logrus.Debugf("unmarshall jtask error, %v", errJ)
updateVersion()
return nil, errJ
}
taskType := "plugin_image_build"
if plugin.BuildModel == "dockerfile" {
taskType = "plugin_dockerfile_build"
}
ts := &api_db.BuildTaskStruct{
TaskType: "plugin_image_build",
TaskType: taskType,
TaskBody: jtask,
User: b.Body.Operator,
}
eq, err := api_db.BuildTaskBuild(ts)
if err != nil {
logrus.Errorf("build equeue build plugin from image error, %v", err)
tx.Rollback()
updateVersion()
return nil, err
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
_, err = p.MQClient.Enqueue(ctx, eq)
cancel()
if err != nil {
updateVersion()
logrus.Errorf("equque mq error, %v", err)
tx.Rollback()
return nil, err
}
if err := tx.Commit().Error; err != nil {
tx.Rollback()
logrus.Debugf("commit mysql error, %v", err)
return nil, nil
}
logrus.Debugf("equeue mq build plugin from image success")
return tpbv, nil
}
//DockerfileBuildPlugin DockerfileBuildPlugin
func (p *PluginAction) DockerfileBuildPlugin(b *api_model.BuildPluginStruct, plugin *dbmodel.TenantPlugin) (
*dbmodel.TenantPluginBuildVersion, error) {
if plugin.GitURL == "" {
return nil, fmt.Errorf("need git url")
}
if b.Body.RepoURL == "" {
b.Body.RepoURL = "master"
}
if b.Body.Operator == "" {
b.Body.Operator = "define"
}
// TODO: build_version create in console
// diffStr := fmt.Sprintf("%s%s%s%s", b.TenantName, b.Body.RepoURL, b.PluginID, time.Now().Format(time.RFC3339))
// buildVersion := createVersionID([]byte(diffStr))
rebuild := false
tpbv, err := db.GetManager().TenantPluginBuildVersionDao().GetBuildVersionByVersionID(
b.PluginID, b.Body.BuildVersion)
if err != nil {
if err.Error() == gorm.ErrRecordNotFound.Error() {
rebuild = false
} else {
return nil, err
}
} else {
rebuild = true
}
tx := db.GetManager().Begin()
if rebuild {
tpbv.Info = b.Body.Info
tpbv.Status = "building"
tpbv.BuildTime = time.Now().Format(time.RFC3339)
if b.Body.PluginCPU == 0 {
tpbv.ContainerCPU = 125
}
if b.Body.PluginMemory == 0 {
tpbv.ContainerMemory = 50
}
if err := db.GetManager().TenantPluginBuildVersionDaoTransactions(tx).UpdateModel(tpbv); err != nil {
if err != nil {
tx.Rollback()
logrus.Errorf("build plugin error: %s", err.Error())
return nil, err
}
}
} else {
pbv := &dbmodel.TenantPluginBuildVersion{
VersionID: b.Body.BuildVersion,
PluginID: b.PluginID,
Kind: plugin.BuildModel,
Repo: b.Body.RepoURL,
GitURL: plugin.GitURL,
Info: b.Body.Info,
ContainerCPU: b.Body.PluginCPU,
ContainerMemory: b.Body.PluginMemory,
ContainerCMD: b.Body.PluginCMD,
BuildTime: time.Now().Format(time.RFC3339),
Status: "building",
}
if b.Body.PluginCPU == 0 {
pbv.ContainerCPU = 125
}
if b.Body.PluginMemory == 0 {
pbv.ContainerMemory = 50
}
if err := db.GetManager().TenantPluginBuildVersionDaoTransactions(tx).AddModel(pbv); err != nil {
if !strings.Contains(err.Error(), "exist") {
tx.Rollback()
logrus.Errorf("build plugin error: %s", err.Error())
return nil, err
}
}
tpbv = pbv
}
taskBody := &builder_model.BuildPluginTaskBody{
TenantID: b.Body.TenantID,
PluginID: b.PluginID,
Operator: b.Body.Operator,
EventID: b.Body.EventID,
Repo: b.Body.RepoURL,
GitURL: plugin.GitURL,
Kind: plugin.BuildModel,
VersionID: b.Body.BuildVersion,
DeployVersion: b.Body.BuildVersion,
PluginCMD: b.Body.PluginCMD,
PluginCPU: b.Body.PluginCPU,
PluginMemory: b.Body.PluginMemory,
}
jtask, errJ := ffjson.Marshal(taskBody)
if errJ != nil {
tx.Rollback()
logrus.Debugf("unmarshall jtask error, %v", errJ)
return nil, errJ
}
ts := &api_db.BuildTaskStruct{
TaskType: "plugin_dockerfile_build",
TaskBody: jtask,
User: b.Body.Operator,
}
eq, err := api_db.BuildTaskBuild(ts)
if err != nil {
logrus.Errorf("build equeue build plugin from dockerfile error, %v", err)
tx.Rollback()
return nil, err
}
ctx, cancel := context.WithCancel(context.Background())
_, errE := p.MQClient.Enqueue(ctx, eq)
cancel()
if errE != nil {
logrus.Errorf("equque mq error, %v", err)
tx.Rollback()
return nil, err
}
if err := tx.Commit().Error; err != nil {
tx.Rollback()
logrus.Debugf("commit mysql error, %v", err)
return nil, nil
}
logrus.Debugf("equeue mq build plugin from dockerfile success")
return tpbv, nil
return pbv, nil
}
//GetAllPluginBuildVersions GetAllPluginBuildVersions

View File

@ -17,3 +17,118 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package share
import (
"context"
"fmt"
"github.com/Sirupsen/logrus"
"github.com/coreos/etcd/clientv3"
api_db "github.com/goodrain/rainbond/api/db"
"github.com/goodrain/rainbond/api/util"
"github.com/goodrain/rainbond/builder/exector"
"github.com/goodrain/rainbond/db"
"github.com/goodrain/rainbond/mq/api/grpc/pb"
"github.com/pquerna/ffjson/ffjson"
"github.com/twinj/uuid"
)
//PluginShareHandle plugin share
type PluginShareHandle struct {
MQClient pb.TaskQueueClient
EtcdCli *clientv3.Client
}
//PluginResult share plugin api return
type PluginResult struct {
EventID string `json:"event_id"`
ShareID string `json:"share_id"`
ImageName string `json:"image_name,omitempty"`
}
//PluginShare PluginShare
type PluginShare struct {
// in: path
// required: true
TenantName string `json:"tenant_name"`
TenantID string
// in: path
// required: true
PluginID string `json:"plugin_id"`
//in: body
Body struct {
//in: body
//应用分享Key
PluginKey string `json:"plugin_key" validate:"plugin_key|required"`
PluginVersion string `json:"plugin_version" validate:"plugin_version|required"`
EventID string `json:"event_id"`
ShareUser string `json:"share_user"`
ShareScope string `json:"share_scope"`
ImageInfo struct {
HubURL string `json:"hub_url"`
HubUser string `json:"hub_user"`
HubPassword string `json:"hub_password"`
Namespace string `json:"namespace"`
} `json:"image_info,omitempty"`
}
}
//Share 分享应用
func (s *PluginShareHandle) Share(ss PluginShare) (*PluginResult, *util.APIHandleError) {
_, err := db.GetManager().TenantPluginDao().GetPluginByID(ss.PluginID, ss.TenantID)
if err != nil {
return nil, util.CreateAPIHandleErrorFromDBError("query plugin error", err)
}
//query new build version
version, err := db.GetManager().TenantPluginBuildVersionDao().GetLastBuildVersionByVersionID(ss.PluginID, ss.Body.PluginVersion)
if err != nil {
logrus.Error("query service deploy version error", err.Error())
return nil, util.CreateAPIHandleErrorFromDBError("query plugin version error", err)
}
shareID := uuid.NewV4().String()
var bs api_db.BuildTaskStruct
shareImageName, err := version.CreateShareImage(ss.Body.ImageInfo.HubURL, ss.Body.ImageInfo.Namespace)
if err != nil {
return nil, util.CreateAPIHandleErrorf(500, "create share image name error", err)
}
info := map[string]interface{}{
"image_info": ss.Body.ImageInfo,
"event_id": ss.Body.EventID,
"tenant_name": ss.TenantName,
"image_name": shareImageName,
"share_id": shareID,
"local_image_name": version.BuildLocalImage,
}
body, _ := ffjson.Marshal(info)
bs.TaskType = "share-plugin"
bs.TaskBody = body
bs.User = ss.Body.ShareUser
eq, _ := api_db.BuildTaskBuild(&bs)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
_, err = s.MQClient.Enqueue(ctx, eq)
if err != nil {
logrus.Errorf("equque mq error, %v", err)
return nil, util.CreateAPIHandleError(502, err)
}
return &PluginResult{EventID: ss.Body.EventID, ShareID: shareID, ImageName: shareImageName}, nil
}
//ShareResult 分享应用结果查询
func (s *PluginShareHandle) ShareResult(shareID string) (i exector.ShareStatus, e *util.APIHandleError) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
res, err := s.EtcdCli.Get(ctx, fmt.Sprintf("/rainbond/shareresult/%s", shareID))
if err != nil {
e = util.CreateAPIHandleError(500, err)
} else {
if res.Count == 0 {
i.ShareID = "shareID"
} else {
if err := ffjson.Unmarshal(res.Kvs[0].Value, &i); err != nil {
return i, util.CreateAPIHandleError(500, err)
}
}
}
return
}

View File

@ -206,10 +206,14 @@ type BuildPluginStruct struct {
// in: body
// required: false
PluginCMD string `json:"plugin_cmd" validate:"plugin_cmd"`
// 部署的版本号
// 插件的版本号
// in: body
// required: true
BuildVersion string `json:"build_version" validate:"build_version|required"`
// 插件构建版本号
// in: body
// required: true
DeployVersion string `json:"deploy_version" validate:"deploy_version"`
// git地址分支信息默认为master
// in: body
// required: false
@ -226,14 +230,18 @@ type BuildPluginStruct struct {
// in: body
// required: true
TenantID string `json:"tenant_id" validate:"tenant_id"`
//安装来源
// in: body
// required: false
PluginFrom string `json:"plugin_from" validate:"plugin_from"`
// 镜像地址
// in: body
// required: false
BuildImage string `json:"build_image" validate:"build_image"`
//ImageInfo
ImageInfo struct {
HubURL string `json:"hub_url"`
HubUser string `json:"hub_user"`
HubPassword string `json:"hub_password"`
Namespace string `json:"namespace"`
IsTrust bool `json:"is_trust,omitempty"`
}
}
}

View File

@ -64,7 +64,7 @@ func (e *exectorManager) pluginDockerfileBuild(in []byte) {
return
}
}
version, err := db.GetManager().TenantPluginBuildVersionDao().GetBuildVersionByVersionID(tb.PluginID, tb.VersionID)
version, err := db.GetManager().TenantPluginBuildVersionDao().GetBuildVersionByDeployVersion(tb.PluginID, tb.VersionID, tb.DeployVersion)
if err != nil {
logrus.Errorf("get version error, %v", err)
}
@ -127,7 +127,7 @@ func (e *exectorManager) runD(t *model.BuildPluginTaskBody, logger event.Logger)
return err
}
logger.Info("推送镜像完成", map[string]string{"step": "build-exector"})
version, err := db.GetManager().TenantPluginBuildVersionDao().GetBuildVersionByVersionID(t.PluginID, t.VersionID)
version, err := db.GetManager().TenantPluginBuildVersionDao().GetBuildVersionByDeployVersion(t.PluginID, t.VersionID, t.DeployVersion)
if err != nil {
logrus.Errorf("get version error, %v", err)
return err

View File

@ -55,7 +55,7 @@ func (e *exectorManager) pluginImageBuild(in []byte) {
return
}
}
version, err := db.GetManager().TenantPluginBuildVersionDao().GetBuildVersionByVersionID(tb.PluginID, tb.VersionID)
version, err := db.GetManager().TenantPluginBuildVersionDao().GetBuildVersionByDeployVersion(tb.PluginID, tb.VersionID, tb.DeployVersion)
if err != nil {
logrus.Errorf("get version error, %v", err)
}
@ -74,7 +74,6 @@ func (e *exectorManager) run(t *model.BuildPluginTaskBody, logger event.Logger)
logger.Error("拉取镜像失败", map[string]string{"step": "builder-exector", "status": "failure"})
return err
}
logger.Info("拉取镜像完成", map[string]string{"step": "build-exector", "status": "complete"})
newTag := createPluginImageTag(t.ImageURL, t.PluginID, t.DeployVersion)
err := sources.ImageTag(e.DockerClient, t.ImageURL, newTag, logger, 1)
@ -89,7 +88,7 @@ func (e *exectorManager) run(t *model.BuildPluginTaskBody, logger event.Logger)
logger.Error("推送镜像失败", map[string]string{"step": "builder-exector", "status": "failure"})
return err
}
version, err := db.GetManager().TenantPluginBuildVersionDao().GetBuildVersionByVersionID(t.PluginID, t.VersionID)
version, err := db.GetManager().TenantPluginBuildVersionDao().GetBuildVersionByDeployVersion(t.PluginID, t.VersionID, t.DeployVersion)
if err != nil {
logger.Error("更新插件版本信息错误", map[string]string{"step": "builder-exector", "status": "failure"})
return err

View File

@ -0,0 +1,141 @@
// Copyright (C) 2014-2018 Goodrain Co., Ltd.
// RAINBOND, Application Management Platform
// 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
import (
"context"
"fmt"
"time"
"github.com/Sirupsen/logrus"
"github.com/coreos/etcd/clientv3"
"github.com/docker/engine-api/client"
"github.com/goodrain/rainbond/builder/sources"
"github.com/goodrain/rainbond/event"
"github.com/pquerna/ffjson/ffjson"
"github.com/tidwall/gjson"
)
//PluginShareItem PluginShareItem
type PluginShareItem struct {
EventID string `json:"event_id"`
ImageName string `json:"image_name"`
LocalImageName string `json:"local_image_name"`
ShareID string `json:"share_id"`
Logger event.Logger
ImageInfo struct {
HubURL string `json:"hub_url"`
HubUser string `json:"hub_user"`
HubPassword string `json:"hub_password"`
Namespace string `json:"namespace"`
IsTrust bool `json:"is_trust,omitempty"`
} `json:"image_info,omitempty"`
DockerClient *client.Client
EtcdCli *clientv3.Client
}
func init() {
RegisterWorker("share-plugin", SharePluginItemCreater)
}
//SharePluginItemCreater create
func SharePluginItemCreater(in []byte, m *exectorManager) (TaskWorker, error) {
eventID := gjson.GetBytes(in, "event_id").String()
logger := event.GetManager().GetLogger(eventID)
pluginShare := &PluginShareItem{
Logger: logger,
EventID: eventID,
DockerClient: m.DockerClient,
}
if err := ffjson.Unmarshal(in, &pluginShare); err != nil {
return nil, err
}
return pluginShare, nil
}
//Run Run
func (i *PluginShareItem) Run(timeout time.Duration) error {
_, err := sources.ImagePull(i.DockerClient, i.LocalImageName, "", "", i.Logger, 10)
if err != nil {
logrus.Errorf("pull image %s error: %s", i.LocalImageName, err.Error())
i.Logger.Error(fmt.Sprintf("拉取应用镜像: %s失败", i.LocalImageName), map[string]string{"step": "builder-exector", "status": "failure"})
return err
}
if err := sources.ImageTag(i.DockerClient, i.LocalImageName, i.ImageName, i.Logger, 1); err != nil {
logrus.Errorf("change image tag error: %s", err.Error())
i.Logger.Error(fmt.Sprintf("修改镜像tag: %s -> %s 失败", i.LocalImageName, i.ImageName), map[string]string{"step": "builder-exector", "status": "failure"})
return err
}
if i.ImageInfo.IsTrust {
err = sources.TrustedImagePush(i.DockerClient, i.ImageName, i.ImageInfo.HubUser, i.ImageInfo.HubPassword, i.Logger, 10)
} else {
err = sources.ImagePush(i.DockerClient, i.ImageName, i.ImageInfo.HubUser, i.ImageInfo.HubPassword, i.Logger, 10)
}
if err != nil {
if err.Error() == "authentication required" {
i.Logger.Error("镜像仓库授权失败", map[string]string{"step": "builder-exector", "status": "failure"})
return err
}
logrus.Errorf("push image into registry error: %s", err.Error())
i.Logger.Error("推送镜像至镜像仓库失败", map[string]string{"step": "builder-exector", "status": "failure"})
return err
}
return nil
}
//Stop stop
func (i *PluginShareItem) Stop() error {
return nil
}
//Name return worker name
func (i *PluginShareItem) Name() string {
return "share-plugin"
}
//GetLogger GetLogger
func (i *PluginShareItem) GetLogger() event.Logger {
return i.Logger
}
//ErrorCallBack if run error will callback
func (i *PluginShareItem) ErrorCallBack(err error) {
i.updateShareStatus("failure")
}
//updateShareStatus update share task result
func (i *PluginShareItem) updateShareStatus(status string) error {
var ss = ShareStatus{
ShareID: i.ShareID,
Status: status,
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
_, err := i.EtcdCli.Put(ctx, fmt.Sprintf("/rainbond/shareresult/%s", i.ShareID), ss.String())
if err != nil {
logrus.Errorf("put shareresult %s into etcd error, %v", i.ShareID, err)
i.Logger.Error("存储分享结果失败。", map[string]string{"step": "callback", "status": "failure"})
}
if status == "success" {
i.Logger.Info("创建分享结果成功,分享成功", map[string]string{"step": "last", "status": "success"})
} else {
i.Logger.Info("创建分享结果成功,分享失败", map[string]string{"step": "callback", "status": "failure"})
}
return nil
}

View File

@ -33,6 +33,13 @@ type BuildPluginTaskBody struct {
PluginCMD string `json:"plugin_cmd"`
PluginCPU int `json:"plugin_cpu"`
PluginMemory int `json:"plugin_memory"`
ImageInfo struct {
HubURL string `json:"hub_url"`
HubUser string `json:"hub_user"`
HubPassword string `json:"hub_password"`
Namespace string `json:"namespace"`
IsTrust bool `json:"is_trust,omitempty"`
} `json:"image_info,omitempty"`
}
//BuildPluginVersion BuildPluginVersion

View File

@ -128,6 +128,8 @@ type TenantPluginBuildVersionDao interface {
DeleteBuildVersionByPluginID(pluginID string) error
GetBuildVersionByPluginID(pluginID string) ([]*model.TenantPluginBuildVersion, error)
GetBuildVersionByVersionID(pluginID, versionID string) (*model.TenantPluginBuildVersion, error)
GetLastBuildVersionByVersionID(pluginID, versionID string) (*model.TenantPluginBuildVersion, error)
GetBuildVersionByDeployVersion(pluginID, versionID, deployVersion string) (*model.TenantPluginBuildVersion, error)
}
//TenantPluginVersionEnvDao TenantPluginVersionEnvDao

View File

@ -18,6 +18,11 @@
package model
import (
"github.com/Sirupsen/logrus"
"github.com/docker/distribution/reference"
)
//TenantPlugin plugin model
type TenantPlugin struct {
Model
@ -96,6 +101,24 @@ func (t *TenantPluginBuildVersion) TableName() string {
return "tenant_plugin_build_version"
}
//CreateShareImage CreateShareImage
func (t *TenantPluginBuildVersion) CreateShareImage(hubURL, namespace string) (string, error) {
_, err := reference.ParseAnyReference(t.BuildLocalImage)
if err != nil {
logrus.Errorf("reference image error: %s", err.Error())
return "", err
}
image := ParseImage(t.BuildLocalImage)
if hubURL != "" {
image.Host = hubURL
}
if namespace != "" {
image.Namespace = namespace
}
image.Name = image.Name + "_" + t.VersionID + ":" + t.DeployVersion
return image.String(), nil
}
//TenantPluginVersionEnv TenantPluginVersionEnv
type TenantPluginVersionEnv struct {
Model

View File

@ -256,6 +256,24 @@ func (t *PluginBuildVersionDaoImpl) GetBuildVersionByVersionID(pluginID, version
return &version, nil
}
//GetBuildVersionByDeployVersion GetBuildVersionByDeployVersion
func (t *PluginBuildVersionDaoImpl) GetBuildVersionByDeployVersion(pluginID, versionID, deployVersion string) (*model.TenantPluginBuildVersion, error) {
var version model.TenantPluginBuildVersion
if err := t.DB.Where("plugin_id=? and version_id = ? and deploy_version=?", pluginID, versionID, deployVersion).Find(&version).Error; err != nil {
return nil, err
}
return &version, nil
}
//GetLastBuildVersionByVersionID get last success build version
func (t *PluginBuildVersionDaoImpl) GetLastBuildVersionByVersionID(pluginID, versionID string) (*model.TenantPluginBuildVersion, error) {
var version model.TenantPluginBuildVersion
if err := t.DB.Where("plugin_id=? and version_id = ? and status=?", pluginID, versionID, "complete").Order("ID desc").Limit("1").Find(&version).Error; err != nil {
return nil, err
}
return &version, nil
}
//PluginVersionEnvDaoImpl PluginVersionEnvDaoImpl
type PluginVersionEnvDaoImpl struct {
DB *gorm.DB

View File

@ -512,3 +512,10 @@ func Rename(old, new string) error {
}
return os.Rename(old, new)
}
//CreateVersionByTime create version number
func CreateVersionByTime() string {
now := time.Now()
re := fmt.Sprintf("%d%d%d%d%d%d%d", now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), now.Nanosecond())
return re
}

View File

@ -60,3 +60,9 @@ func TestUnzip(t *testing.T) {
t.Fatal(err)
}
}
func TestCreateVersionByTime(t *testing.T) {
if re := CreateVersionByTime(); re != "" {
t.Log(re)
}
}

View File

@ -784,7 +784,7 @@ func (p *PodTemplateSpecBuild) createPluginsContainer(volumeMounts []v1.VolumeMo
if pluginR.Switch == false {
continue
}
versionInfo, err := p.dbmanager.TenantPluginBuildVersionDao().GetBuildVersionByVersionID(pluginR.PluginID, pluginR.VersionID)
versionInfo, err := p.dbmanager.TenantPluginBuildVersionDao().GetLastBuildVersionByVersionID(pluginR.PluginID, pluginR.VersionID)
if err != nil {
return nil, nil, err
}