Rainbond/builder/exector/service_check.go

156 lines
5.6 KiB
Go
Raw Normal View History

2018-03-14 14:12:26 +08:00
// Copyright (C) 2014-2018 Goodrain Co., Ltd.
// RAINBOND, Application Management Platform
2018-03-14 14:33:31 +08:00
// 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.
2018-03-14 14:33:31 +08:00
// 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.
2018-03-14 14:33:31 +08:00
// 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"
2018-03-30 15:37:36 +08:00
"runtime/debug"
"github.com/Sirupsen/logrus"
"github.com/ghodss/yaml"
"github.com/goodrain/rainbond/builder/parser"
"github.com/goodrain/rainbond/event"
"github.com/pquerna/ffjson/ffjson"
"github.com/goodrain/rainbond/mq/api/grpc/pb"
)
//ServiceCheckInput 任务输入数据
type ServiceCheckInput struct {
CheckUUID string `json:"uuid"`
//检测来源类型
SourceType string `json:"source_type"`
// 检测来源定义,
// 代码: https://github.com/shurcooL/githubql.git master
// docker-run: docker run --name xxx nginx:latest nginx
// docker-compose: compose全文
SourceBody string `json:"source_body"`
Username string `json:"username"`
Password string `json:"password"`
TenantID string
EventID string `json:"event_id"`
}
//ServiceCheckResult 应用检测结果
type ServiceCheckResult struct {
//检测状态 Success Failure
CheckStatus string `json:"check_status"`
2018-02-01 18:07:19 +08:00
ErrorInfos parser.ParseErrorList `json:"error_infos"`
ServiceInfo []parser.ServiceInfo `json:"service_info"`
}
//CreateResult 创建检测结果
2018-02-01 18:07:19 +08:00
func CreateResult(ErrorInfos parser.ParseErrorList, ServiceInfo []parser.ServiceInfo) (ServiceCheckResult, error) {
var sr ServiceCheckResult
if ErrorInfos != nil && ErrorInfos.IsFatalError() {
sr = ServiceCheckResult{
CheckStatus: "Failure",
ErrorInfos: ErrorInfos,
ServiceInfo: ServiceInfo,
}
2018-01-17 22:06:58 +08:00
} else {
sr = ServiceCheckResult{
CheckStatus: "Success",
ErrorInfos: ErrorInfos,
ServiceInfo: ServiceInfo,
}
}
//save result
2018-02-01 18:07:19 +08:00
return sr, nil
}
//serviceCheck 应用创建源检测
func (e *exectorManager) serviceCheck(task *pb.TaskMessage) {
//step1 判断应用源类型
//step2 获取应用源介质镜像Or源码
//step3 解析判断应用源规范
//完成
var input ServiceCheckInput
if err := ffjson.Unmarshal(task.TaskBody, &input); err != nil {
logrus.Error("Unmarshal service check input data error.", err.Error())
return
}
logger := event.GetManager().GetLogger(input.EventID)
defer e.removeTask(task)
2018-03-30 15:37:36 +08:00
defer event.GetManager().ReleaseLogger(logger)
defer func() {
if r := recover(); r != nil {
logrus.Errorf("service check error: %v", r)
2018-03-30 15:37:36 +08:00
debug.PrintStack()
logger.Error("后端服务开小差,请重试或联系客服", map[string]string{"step": "callback", "status": "failure"})
}
}()
logger.Info("开始应用构建源检测", map[string]string{"step": "starting"})
2018-01-17 22:06:58 +08:00
logrus.Infof("start check service by type: %s ", input.SourceType)
var pr parser.Parser
switch input.SourceType {
case "docker-run":
2018-08-10 18:23:16 +08:00
pr = parser.CreateDockerRunOrImageParse(input.Username, input.Password, input.SourceBody, e.DockerClient, logger)
case "docker-compose":
2018-02-24 17:19:55 +08:00
logrus.Debugf("source body is \n%v", input.SourceBody)
y, err := yaml.JSONToYAML([]byte(input.SourceBody))
if err != nil {
logrus.Errorf("json bytes format is error, %s", input.SourceBody)
logger.Error("dockercompose文件格式不正确。", map[string]string{"step": "callback", "status": "failure"})
return
}
pr = parser.CreateDockerComposeParse(string(y), e.DockerClient, logger)
case "sourcecode":
2018-01-17 22:06:58 +08:00
pr = parser.CreateSourceCodeParse(input.SourceBody, logger)
}
if pr == nil {
logger.Error("创建应用来源类型不支持。", map[string]string{"step": "callback", "status": "failure"})
return
}
errList := pr.Parse()
if errList != nil {
for i, err := range errList {
2018-02-27 22:31:44 +08:00
if err.SolveAdvice == "" && input.SourceType != "sourcecode" {
2018-01-17 22:06:58 +08:00
errList[i].SolveAdvice = fmt.Sprintf("解析器认为镜像名为:%s,请确认是否正确或镜像是否存在", pr.GetImage())
}
2018-02-27 22:31:44 +08:00
if err.SolveAdvice == "" && input.SourceType == "sourcecode" {
errList[i].SolveAdvice = fmt.Sprintf("源码智能解析失败,请联系客服")
}
2018-01-17 22:06:58 +08:00
}
}
serviceInfos := pr.GetServiceInfo()
2018-02-01 18:07:19 +08:00
sr, err := CreateResult(errList, serviceInfos)
if err != nil {
2018-01-17 22:06:58 +08:00
logrus.Errorf("create check result error,%s", err.Error())
logger.Error("创建检测结果失败。", map[string]string{"step": "callback", "status": "failure"})
}
k := fmt.Sprintf("/servicecheck/%s", input.CheckUUID)
2018-02-01 18:07:19 +08:00
v := sr
vj, err := ffjson.Marshal(&v)
if err != nil {
logrus.Errorf("mashal servicecheck value error, %v", err)
logger.Error("格式化检测结果失败。", map[string]string{"step": "callback", "status": "failure"})
}
ctx, cancel := context.WithCancel(context.Background())
_, err = e.EtcdCli.Put(ctx, k, string(vj))
cancel()
if err != nil {
logrus.Errorf("put servicecheck k %s into etcd error, %v", k, err)
logger.Error("存储检测结果失败。", map[string]string{"step": "callback", "status": "failure"})
}
2018-03-15 19:46:39 +08:00
logrus.Infof("check service by type: %s success", input.SourceType)
2018-03-05 16:55:17 +08:00
logger.Info("创建检测结果成功。", map[string]string{"step": "last", "status": "success"})
}