mirror of
https://gitee.com/rainbond/Rainbond.git
synced 2024-12-05 13:17:42 +08:00
327 lines
7.8 KiB
Go
327 lines
7.8 KiB
Go
// 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 parser
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
dbmodel "github.com/goodrain/rainbond/db/model"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/docker/distribution/reference"
|
|
"github.com/goodrain/rainbond/builder/parser/code"
|
|
"github.com/goodrain/rainbond/builder/parser/discovery"
|
|
"github.com/goodrain/rainbond/builder/parser/types"
|
|
"github.com/goodrain/rainbond/builder/sources"
|
|
"k8s.io/apimachinery/pkg/api/resource"
|
|
)
|
|
|
|
//ParseError 错误信息
|
|
type ParseError struct {
|
|
ErrorType ParseErrorType `json:"error_type"`
|
|
ErrorInfo string `json:"error_info"`
|
|
SolveAdvice string `json:"solve_advice"`
|
|
}
|
|
|
|
//ParseErrorList 错误列表
|
|
type ParseErrorList []ParseError
|
|
|
|
//ParseErrorType 错误类型
|
|
type ParseErrorType string
|
|
|
|
//FatalError 致命错误
|
|
var FatalError ParseErrorType = "FatalError"
|
|
|
|
//NegligibleError 可忽略错误
|
|
var NegligibleError ParseErrorType = "NegligibleError"
|
|
|
|
//Errorf error create
|
|
func Errorf(errtype ParseErrorType, format string, a ...interface{}) ParseError {
|
|
parseError := ParseError{
|
|
ErrorType: errtype,
|
|
ErrorInfo: fmt.Sprintf(format, a...),
|
|
}
|
|
return parseError
|
|
}
|
|
|
|
//ErrorAndSolve error create
|
|
func ErrorAndSolve(errtype ParseErrorType, errorInfo, SolveAdvice string) ParseError {
|
|
parseError := ParseError{
|
|
ErrorType: errtype,
|
|
ErrorInfo: errorInfo,
|
|
SolveAdvice: SolveAdvice,
|
|
}
|
|
return parseError
|
|
}
|
|
|
|
//SolveAdvice 构建a标签建议
|
|
func SolveAdvice(actionType, message string) string {
|
|
return fmt.Sprintf("<a action_type=\"%s\">%s</a>", actionType, message)
|
|
}
|
|
|
|
func (p ParseError) Error() string {
|
|
return fmt.Sprintf("Type:%s Message:%s", p.ErrorType, p.ErrorInfo)
|
|
}
|
|
func (ps ParseErrorList) Error() string {
|
|
var re string
|
|
for _, p := range ps {
|
|
re += fmt.Sprintf("Type:%s Message:%s\n", p.ErrorType, p.ErrorInfo)
|
|
}
|
|
return re
|
|
}
|
|
|
|
//IsFatalError 是否具有致命错误
|
|
func (ps ParseErrorList) IsFatalError() bool {
|
|
for _, p := range ps {
|
|
if p.ErrorType == FatalError {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
//Image 镜像
|
|
type Image struct {
|
|
name reference.Named
|
|
source string
|
|
Name string `json:"name"`
|
|
Tag string `json:"tag"`
|
|
}
|
|
|
|
//String -
|
|
func (i Image) String() string {
|
|
if i.name == nil {
|
|
return ""
|
|
}
|
|
return i.name.String()
|
|
}
|
|
|
|
//Source return the name before resolution
|
|
func (i Image) Source() string {
|
|
return i.source
|
|
}
|
|
|
|
//GetTag get tag
|
|
func (i Image) GetTag() string {
|
|
return i.Tag
|
|
}
|
|
|
|
//GetRepostory get repostory
|
|
func (i Image) GetRepostory() string {
|
|
if i.name == nil {
|
|
return ""
|
|
}
|
|
return reference.Path(i.name)
|
|
}
|
|
|
|
//GetDomain get image registry domain
|
|
func (i Image) GetDomain() string {
|
|
if i.name == nil {
|
|
return ""
|
|
}
|
|
domain := reference.Domain(i.name)
|
|
if domain == "docker.io" {
|
|
domain = "registry-1.docker.io"
|
|
}
|
|
return domain
|
|
}
|
|
|
|
//IsOfficial is official image
|
|
func (i Image) IsOfficial() bool {
|
|
domain := reference.Domain(i.name)
|
|
if domain == "docker.io" {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
//GetSimpleName get image name without tag and organizations
|
|
func (i Image) GetSimpleName() string {
|
|
if strings.Contains(i.GetRepostory(), "/") {
|
|
return strings.Split(i.GetRepostory(), "/")[1]
|
|
}
|
|
return i.GetRepostory()
|
|
}
|
|
|
|
//Parser 解析器
|
|
type Parser interface {
|
|
Parse() ParseErrorList
|
|
GetServiceInfo() []ServiceInfo
|
|
GetImage() Image
|
|
}
|
|
|
|
//Lang 语言类型
|
|
type Lang string
|
|
|
|
//ServiceInfo 智能获取的应用信息
|
|
type ServiceInfo struct {
|
|
ID string `json:"id,omitempty"`
|
|
Ports []types.Port `json:"ports,omitempty"`
|
|
Envs []types.Env `json:"envs,omitempty"`
|
|
Volumes []types.Volume `json:"volumes,omitempty"`
|
|
Image Image `json:"image,omitempty"`
|
|
Args []string `json:"args,omitempty"`
|
|
DependServices []string `json:"depends,omitempty"`
|
|
ServiceType string `json:"service_type,omitempty"`
|
|
Branchs []string `json:"branchs,omitempty"`
|
|
Memory int `json:"memory,omitempty"`
|
|
Lang code.Lang `json:"language,omitempty"`
|
|
ImageAlias string `json:"image_alias,omitempty"`
|
|
//For third party services
|
|
Endpoints []*discovery.Endpoint `json:"endpoints,omitempty"`
|
|
//os type,default linux
|
|
OS string `json:"os"`
|
|
Name string `json:"name,omitempty"` // module name
|
|
Cname string `json:"cname,omitempty"` // service cname
|
|
Packaging string `json:"packaging,omitempty"`
|
|
}
|
|
|
|
//GetServiceInfo GetServiceInfo
|
|
type GetServiceInfo struct {
|
|
UUID string `json:"uuid"`
|
|
Source string `json:"source"`
|
|
}
|
|
|
|
//GetPortProtocol 获取端口协议
|
|
func GetPortProtocol(port int) string {
|
|
if port == 80 {
|
|
return "http"
|
|
}
|
|
if port == 8080 {
|
|
return "http"
|
|
}
|
|
if port == 22 {
|
|
return "tcp"
|
|
}
|
|
if port == 3306 {
|
|
return "mysql"
|
|
}
|
|
if port == 443 {
|
|
return "https"
|
|
}
|
|
if port == 3128 {
|
|
return "http"
|
|
}
|
|
if port == 1080 {
|
|
return "udp"
|
|
}
|
|
if port == 6379 {
|
|
return "tcp"
|
|
}
|
|
if port > 1 && port < 5000 {
|
|
return "tcp"
|
|
}
|
|
return "http"
|
|
}
|
|
|
|
var dbImageKey = []string{
|
|
"mysql", "mariadb", "mongo", "redis", "tidb",
|
|
"zookeeper", "kafka", "mysqldb", "mongodb",
|
|
"memcached", "cockroachdb", "cockroach", "etcd",
|
|
"postgres", "postgresql", "elasticsearch", "consul",
|
|
"percona", "mysql-server", "mysql-cluster",
|
|
}
|
|
|
|
//DetermineDeployType Determine the deployment type
|
|
// if image like db image,return stateful type
|
|
func DetermineDeployType(imageName Image) string {
|
|
for _, key := range dbImageKey {
|
|
if strings.ToLower(imageName.GetSimpleName()) == key {
|
|
return dbmodel.ServiceTypeStateSingleton.String()
|
|
}
|
|
}
|
|
return dbmodel.ServiceTypeStatelessMultiple.String()
|
|
}
|
|
|
|
//readmemory
|
|
//10m 10
|
|
//10g 10*1024
|
|
//10k 128
|
|
//10b 128
|
|
func readmemory(s string) int {
|
|
def := 512
|
|
s = strings.ToLower(s)
|
|
// <binarySI> ::= Ki | Mi | Gi | Ti | Pi | Ei
|
|
isValid := false
|
|
validUnits := map[string]string{
|
|
"gi": "Gi", "mi": "Mi", "ki": "Ki",
|
|
}
|
|
for k, v := range validUnits {
|
|
if strings.Contains(s, k) {
|
|
isValid = true
|
|
s = strings.Replace(s, k, v, 1)
|
|
break
|
|
}
|
|
}
|
|
if !isValid {
|
|
validUnits := map[string]string{
|
|
"g": "Gi", "m": "Mi", "k": "Ki",
|
|
}
|
|
for k, v := range validUnits {
|
|
if strings.Contains(s, k) {
|
|
isValid = true
|
|
s = strings.Replace(s, k, v, 1)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if !isValid {
|
|
logrus.Warningf("s: %s; invalid unit", s)
|
|
return def
|
|
}
|
|
q, err := resource.ParseQuantity(s)
|
|
if err != nil {
|
|
logrus.Warningf("s: %s; failed to parse quantity: %v", s, err)
|
|
return def
|
|
}
|
|
re, ok := q.AsInt64()
|
|
if !ok {
|
|
logrus.Warningf("failed to int64: %d", re)
|
|
return def
|
|
}
|
|
if re != 0 {
|
|
return int(re) / (1024 * 1024)
|
|
}
|
|
return def
|
|
}
|
|
|
|
//ParseImageName parse image name
|
|
func ParseImageName(s string) (i Image) {
|
|
ref, err := reference.ParseAnyReference(s)
|
|
if err != nil {
|
|
logrus.Errorf("image name: %s; parse image failure %s", s, err.Error())
|
|
return i
|
|
}
|
|
name, err := reference.ParseNamed(ref.String())
|
|
if err != nil {
|
|
logrus.Errorf("parse image failure %s", err.Error())
|
|
return i
|
|
}
|
|
i.name = name
|
|
i.Tag = sources.GetTagFromNamedRef(name)
|
|
if strings.Contains(s, ":") {
|
|
i.Name = s[:len(s)-(len(i.Tag)+1)]
|
|
} else {
|
|
i.Name = s
|
|
}
|
|
i.source = s
|
|
return
|
|
}
|