Merge branch 'master' into cuib-local-master

This commit is contained in:
pujielan 2018-01-19 17:00:37 +08:00
commit c43f1dd62f
32 changed files with 637 additions and 96 deletions

View File

@ -1,34 +1,38 @@
// 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 main
import (
"github.com/goodrain/rainbond/cmd/api/option"
"github.com/goodrain/rainbond/cmd/api/server"
"fmt"
"os"
"github.com/goodrain/rainbond/cmd"
"github.com/goodrain/rainbond/cmd/api/option"
"github.com/goodrain/rainbond/cmd/api/server"
"github.com/spf13/pflag"
)
func main() {
if len(os.Args) > 1 && os.Args[1] == "version" {
cmd.ShowVersion("api")
}
s := option.NewAPIServer()
s.AddFlags(pflag.CommandLine)
pflag.Parse()

View File

@ -1,19 +1,18 @@
// 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/>.
@ -23,6 +22,7 @@ import (
"fmt"
"os"
"github.com/goodrain/rainbond/cmd"
"github.com/goodrain/rainbond/cmd/builder/option"
"github.com/goodrain/rainbond/cmd/builder/server"
@ -30,6 +30,9 @@ import (
)
func main() {
if len(os.Args) > 1 && os.Args[1] == "version" {
cmd.ShowVersion("chaos")
}
s := option.NewBuilder()
s.AddFlags(pflag.CommandLine)
pflag.Parse()

View File

@ -1,19 +1,18 @@
// 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/>.
@ -23,6 +22,7 @@ import (
"fmt"
"os"
"github.com/goodrain/rainbond/cmd"
"github.com/goodrain/rainbond/cmd/entrance/option"
"github.com/goodrain/rainbond/cmd/entrance/server"
@ -30,6 +30,9 @@ import (
)
func main() {
if len(os.Args) > 1 && os.Args[1] == "version" {
cmd.ShowVersion("entrance")
}
s := option.NewACPLBServer()
s.AddFlags(pflag.CommandLine)
pflag.Parse()

View File

@ -1,19 +1,18 @@
// 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/>.
@ -22,12 +21,16 @@ package main
import (
"os"
"github.com/goodrain/rainbond/cmd"
"github.com/goodrain/rainbond/cmd/eventlog/server"
"github.com/spf13/pflag"
)
func main() {
if len(os.Args) > 1 && os.Args[1] == "version" {
cmd.ShowVersion("eventlog")
}
s := server.NewLogServer()
s.AddFlags(pflag.CommandLine)
pflag.Parse()

View File

@ -21,10 +21,15 @@ package main
import (
"fmt"
"os"
"github.com/goodrain/rainbond/cmd"
"github.com/goodrain/rainbond/cmd/grctl/server"
)
func main() {
if len(os.Args) > 1 && os.Args[1] == "version" {
cmd.ShowVersion("grctl")
}
if err := server.Run(); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)

View File

@ -1,19 +1,18 @@
// 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/>.
@ -23,6 +22,7 @@ import (
"fmt"
"os"
"github.com/goodrain/rainbond/cmd"
"github.com/goodrain/rainbond/cmd/mq/option"
"github.com/goodrain/rainbond/cmd/mq/server"
@ -30,6 +30,9 @@ import (
)
func main() {
if len(os.Args) > 1 && os.Args[1] == "version" {
cmd.ShowVersion("mq")
}
s := option.NewMQServer()
s.AddFlags(pflag.CommandLine)
pflag.Parse()

View File

@ -22,11 +22,15 @@ import (
"fmt"
"os"
"github.com/goodrain/rainbond/cmd"
"github.com/goodrain/rainbond/cmd/node/option"
"github.com/goodrain/rainbond/cmd/node/server"
)
func main() {
if len(os.Args) > 1 && os.Args[1] == "version" {
cmd.ShowVersion("node")
}
option.Init()
if err := server.Run(option.Config); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)

33
cmd/version.go Normal file
View File

@ -0,0 +1,33 @@
// 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 cmd
import (
"fmt"
"os"
)
//CodeVersion 代码版本
const CodeVersion = "0.0.0"
//ShowVersion 显示版本
func ShowVersion(module string) {
fmt.Printf("Rainbond %s %s\n", module, CodeVersion)
os.Exit(0)
}

View File

@ -22,6 +22,7 @@ import (
"fmt"
"os"
"github.com/goodrain/rainbond/cmd"
"github.com/goodrain/rainbond/cmd/webcli/option"
"github.com/goodrain/rainbond/cmd/webcli/server"
@ -29,6 +30,9 @@ import (
)
func main() {
if len(os.Args) > 1 && os.Args[1] == "version" {
cmd.ShowVersion("webcli")
}
s := option.NewWebCliServer()
s.AddFlags(pflag.CommandLine)
pflag.Parse()

View File

@ -1,19 +1,18 @@
// 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/>.
@ -23,6 +22,7 @@ import (
"fmt"
"os"
"github.com/goodrain/rainbond/cmd"
"github.com/goodrain/rainbond/cmd/worker/option"
"github.com/goodrain/rainbond/cmd/worker/server"
@ -30,6 +30,9 @@ import (
)
func main() {
if len(os.Args) > 1 && os.Args[1] == "version" {
cmd.ShowVersion("worker")
}
s := option.NewWorker()
s.AddFlags(pflag.CommandLine)
pflag.Parse()

View File

@ -1884,9 +1884,15 @@
"plugin_cpu",
"plugin_memory",
"build_version",
"info"
"info",
"tenant_id"
],
"properties": {
"build_image": {
"description": "镜像地址\nin: body",
"type": "string",
"x-go-name": "BuildImage"
},
"build_version": {
"description": "部署的版本号\nin: body",
"type": "string",
@ -1918,6 +1924,11 @@
"format": "int64",
"x-go-name": "PluginCPU"
},
"plugin_from": {
"description": "安装来源\nin: body",
"type": "string",
"x-go-name": "PluginFrom"
},
"plugin_memory": {
"description": "插件最大内存, 默认50\nin: body",
"type": "integer",
@ -6344,6 +6355,37 @@
}
}
}
},
"/v2/tenants/{tenant_name}/transplugins": {
"post": {
"description": "trans plugins",
"produces": [
"application/json",
"application/xml"
],
"tags": [
"v2"
],
"summary": "安装云帮默认plugins",
"operationId": "transPlugins",
"parameters": [
{
"type": "string",
"description": "tenant name",
"name": "tenant_name",
"in": "path",
"required": true
}
],
"responses": {
"default": {
"description": "统一返回格式",
"schema": {
"$ref": "#/responses/commandResponse"
}
}
}
}
}
},
"definitions": {

View File

@ -35,6 +35,7 @@ type TenantInterface interface {
SumTenants(w http.ResponseWriter, r *http.Request)
SingleTenantResources(w http.ResponseWriter, r *http.Request)
GetSupportProtocols(w http.ResponseWriter, r *http.Request)
TransPlugins(w http.ResponseWriter, r *http.Request)
}
//ServiceInterface ServiceInterface

View File

@ -61,6 +61,8 @@ func (v2 *V2) tenantNameRouter() chi.Router {
//租户中的日志
r.Post("/event-log", controller.GetManager().TenantLogByAction)
r.Get("/protocols", controller.GetManager().GetSupportProtocols)
//插件预安装
r.Post("/transplugins", controller.GetManager().TransPlugins)
//代码检测
r.Post("/code-check", controller.GetManager().CheckCode)
r.Post("/cloud-share", controller.GetManager().ShareCloud)

View File

@ -105,11 +105,12 @@ func (t *TenantStruct) UpdatePlugin(w http.ResponseWriter, r *http.Request) {
// description: 统一返回格式
pluginID := r.Context().Value(middleware.ContextKey("plugin_id")).(string)
tenantID := r.Context().Value(middleware.ContextKey("tenant_id")).(string)
var ups api_model.UpdatePluginStruct
if ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &ups.Body, nil); !ok {
return
}
if err := handler.GetPluginManager().UpdatePluginAct(pluginID, &ups); err != nil {
if err := handler.GetPluginManager().UpdatePluginAct(pluginID,tenantID, &ups); err != nil {
err.Handle(r, w)
return
}
@ -139,7 +140,8 @@ func (t *TenantStruct) DeletePlugin(w http.ResponseWriter, r *http.Request) {
// "$ref": "#/responses/commandResponse"
// description: 统一返回格式
pluginID := r.Context().Value(middleware.ContextKey("plugin_id")).(string)
if err := handler.GetPluginManager().DeletePluginAct(pluginID); err != nil {
tenantID := r.Context().Value(middleware.ContextKey("tenant_id")).(string)
if err := handler.GetPluginManager().DeletePluginAct(pluginID, tenantID); err != nil {
err.Handle(r, w)
return
}

View File

@ -1716,3 +1716,45 @@ func (t *TenantStruct) GetSupportProtocols(w http.ResponseWriter, r *http.Reques
httputil.ReturnSuccess(r, w, rps)
return
}
//TransPlugins transPlugins
// swagger:operation POST /v2/tenants/{tenant_name}/transplugins v2 transPlugins
//
// 安装云帮默认plugins
//
// trans plugins
//
// ---
// produces:
// - application/json
// - application/xml
// parameters:
// - name: tenant_name
// in: path
// description: tenant name
// required: true
// type: string
//
// responses:
// default:
// schema:
// "$ref": "#/responses/commandResponse"
// description: 统一返回格式
func (t *TenantStruct) TransPlugins(w http.ResponseWriter, r *http.Request) {
var tps api_model.TransPlugins
ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &tps.Body, nil)
if !ok {
return
}
tenantID := r.Context().Value(middleware.ContextKey("tenant_id")).(string)
tenantName := r.Context().Value(middleware.ContextKey("tenant_name")).(string)
rc := make(map[string]string)
err := handler.GetTenantManager().TransPlugins(tenantID, tenantName, tps.Body.FromTenantName, tps.Body.PluginsID)
if err != nil {
err.Handle(r, w)
return
}
rc["result"] = "success"
httputil.ReturnSuccess(r, w, rc)
return
}

View File

@ -28,8 +28,8 @@ import (
//PluginHandler plugin handler
type PluginHandler interface {
CreatePluginAct(cps *api_model.CreatePluginStruct) *util.APIHandleError
UpdatePluginAct(pluginID string, cps *api_model.UpdatePluginStruct) *util.APIHandleError
DeletePluginAct(pluginID string) *util.APIHandleError
UpdatePluginAct(pluginID,tenantID string, cps *api_model.UpdatePluginStruct) *util.APIHandleError
DeletePluginAct(pluginID, tenantID string) *util.APIHandleError
GetPlugins(tenantID string) ([]*dbmodel.TenantPlugin, *util.APIHandleError)
AddDefaultEnv(est *api_model.ENVStruct) *util.APIHandleError
UpdateDefaultEnv(est *api_model.ENVStruct) *util.APIHandleError

View File

@ -39,6 +39,7 @@ type TenantHandler interface {
GetTenantsResources(tr *api_model.TenantResources) ([]map[string]interface{}, error)
TenantsSum() (int, error)
GetProtocols() ([]*dbmodel.RegionProcotols, *util.APIHandleError)
TransPlugins(tenantID, tenantName, fromTenant string, pluginList []string) *util.APIHandleError
}
var defaultTenantHandler TenantHandler

View File

@ -84,8 +84,8 @@ func (p *PluginAction) CreatePluginAct(cps *api_model.CreatePluginStruct) *util.
}
//UpdatePluginAct UpdatePluginAct
func (p *PluginAction) UpdatePluginAct(pluginID string, cps *api_model.UpdatePluginStruct) *util.APIHandleError {
tp, err := db.GetManager().TenantPluginDao().GetPluginByID(pluginID)
func (p *PluginAction) UpdatePluginAct(pluginID, tenantID string, cps *api_model.UpdatePluginStruct) *util.APIHandleError {
tp, err := db.GetManager().TenantPluginDao().GetPluginByID(pluginID, tenantID)
if err != nil {
return util.CreateAPIHandleErrorFromDBError("get old plugin info", err)
}
@ -105,10 +105,10 @@ func (p *PluginAction) UpdatePluginAct(pluginID string, cps *api_model.UpdatePlu
}
//DeletePluginAct DeletePluginAct
func (p *PluginAction) DeletePluginAct(pluginID string) *util.APIHandleError {
func (p *PluginAction) DeletePluginAct(pluginID,tenantID string) *util.APIHandleError {
//TODO: 事务
tx := db.GetManager().Begin()
err := db.GetManager().TenantPluginDaoTransactions(tx).DeletePluginByID(pluginID)
err := db.GetManager().TenantPluginDaoTransactions(tx).DeletePluginByID(pluginID, tenantID)
if err != nil {
tx.Rollback()
return util.CreateAPIHandleErrorFromDBError("delete plugin", err)
@ -213,10 +213,24 @@ func (p *PluginAction) BuildPluginManual(bps *api_model.BuildPluginStruct) (*dbm
eventID := bps.Body.EventID
logger := event.GetManager().GetLogger(eventID)
defer event.CloseManager()
plugin, err := db.GetManager().TenantPluginDao().GetPluginByID(bps.PluginID)
plugin, err := db.GetManager().TenantPluginDao().GetPluginByID(bps.PluginID, bps.Body.TenantID)
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)
@ -244,6 +258,34 @@ func createVersionID(s []byte) string {
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) (
*dbmodel.TenantPluginBuildVersion, error) {

View File

@ -1757,7 +1757,7 @@ func (s *ServiceAction) TenantServiceDeletePluginRelation(serviceID, pluginID st
//SetTenantServicePluginRelation SetTenantServicePluginRelation
func (s *ServiceAction) SetTenantServicePluginRelation(tenantID, serviceID string, pss *api_model.PluginSetStruct) *util.APIHandleError {
tx := db.GetManager().Begin()
plugin, err := db.GetManager().TenantPluginDao().GetPluginByID(pss.Body.PluginID)
plugin, err := db.GetManager().TenantPluginDao().GetPluginByID(pss.Body.PluginID, tenantID)
if err != nil {
tx.Rollback()
return util.CreateAPIHandleErrorFromDBError("get plugin by plugin id", err)

View File

@ -247,3 +247,34 @@ func (t *TenantAction) GetProtocols() ([]*dbmodel.RegionProcotols, *util.APIHand
}
return rps, nil
}
//TransPlugins TransPlugins
func (t *TenantAction) TransPlugins(tenantID, tenantName, fromTenant string, pluginList []string) *util.APIHandleError {
tenantInfo, err := db.GetManager().TenantDao().GetTenantIDByName(fromTenant)
if err != nil {
return util.CreateAPIHandleErrorFromDBError("get tenant infos", err)
}
goodrainID := tenantInfo.UUID
tx := db.GetManager().Begin()
for _, p := range pluginList {
pluginInfo, err := db.GetManager().TenantPluginDao().GetPluginByID(p, goodrainID)
if err != nil {
tx.Rollback()
return util.CreateAPIHandleErrorFromDBError("get plugin infos", err)
}
pluginInfo.TenantID = tenantID
pluginInfo.Domain = tenantName
pluginInfo.ID = 0
err = db.GetManager().TenantPluginDaoTransactions(tx).AddModel(pluginInfo)
if err != nil {
if !strings.Contains(err.Error(), "is exist") {
tx.Rollback()
return util.CreateAPIHandleErrorFromDBError("add plugin Info", err)
}
}
}
if err := tx.Commit().Error; err != nil {
return util.CreateAPIHandleErrorFromDBError("trans plugins infos", err)
}
return nil
}

View File

@ -93,11 +93,12 @@ func InitService(next http.Handler) http.Handler {
func InitPlugin(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
pluginID := chi.URLParam(r, "plugin_id")
tenantID := r.Context().Value(ContextKey("tenant_id")).(string)
if pluginID == "" {
httputil.ReturnError(r, w, 404, "need plugin id")
return
}
_, err := db.GetManager().TenantPluginDao().GetPluginByID(pluginID)
_, err := db.GetManager().TenantPluginDao().GetPluginByID(pluginID,tenantID)
if err != nil {
if err.Error() == gorm.ErrRecordNotFound.Error() {
httputil.ReturnError(r, w, 404, "cant find plugin")

View File

@ -44,7 +44,7 @@ func InitProxy(conf option.Config) {
func GetNodeProxy() proxy.Proxy {
return nodeProxy
}
//GetNodeProxy GetNodeProxy
//GetBuilderProxy GetNodeProxy
func GetBuilderProxy() proxy.Proxy {
return builderProxy
}

View File

@ -224,8 +224,16 @@ type BuildPluginStruct struct {
Operator string `json:"operator" validate:"operator"`
//租户id
// in: body
// required: false
// 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"`
}
}
@ -387,3 +395,21 @@ type VersionEnv struct {
//required: true
EnvValue string `json:"env_value" validate:"env_value"`
}
//TransPlugins TransPlugins
type TransPlugins struct {
// in: path
// required: true
TenantName string `json:"tenant_name"`
//in: body
Body struct {
// 从该租户安装
// in: body
// required: true
FromTenantName string `json:"from_tenant_name" validate:"from_tenant_name"`
// 插件id
// in: body
// required: true
PluginsID []string `json:"plugins_id" validate:"plugins_id"`
}
}

View File

@ -88,8 +88,8 @@ type TenantServicesPortDao interface {
//TenantPluginDao TenantPluginDao
type TenantPluginDao interface {
Dao
GetPluginByID(pluginID string) (*model.TenantPlugin, error)
DeletePluginByID(pluginID string) error
GetPluginByID(pluginID, tenantID string) (*model.TenantPlugin, error)
DeletePluginByID(pluginID, tenantID string) error
GetPluginsByTenantID(tenantID string) ([]*model.TenantPlugin, error)
}

View File

@ -34,12 +34,12 @@ type PluginDaoImpl struct {
func (t *PluginDaoImpl) AddModel(mo model.Interface) error {
plugin := mo.(*model.TenantPlugin)
var oldPlugin model.TenantPlugin
if ok := t.DB.Where("plugin_id = ?", plugin.PluginID).Find(&oldPlugin).RecordNotFound(); ok {
if ok := t.DB.Where("plugin_id = ? and tenant_id = ?", plugin.PluginID, plugin.TenantID).Find(&oldPlugin).RecordNotFound(); ok {
if err := t.DB.Create(plugin).Error; err != nil {
return err
}
} else {
return fmt.Errorf("plugin %s is exist", plugin.PluginName)
return fmt.Errorf("plugin %s in tenant %s is exist", plugin.PluginName, plugin.TenantID)
}
return nil
}
@ -54,20 +54,20 @@ func (t *PluginDaoImpl) UpdateModel(mo model.Interface) error {
}
//GetPluginByID GetPluginByID
func (t *PluginDaoImpl) GetPluginByID(id string) (*model.TenantPlugin, error) {
func (t *PluginDaoImpl) GetPluginByID(id, tenantID string) (*model.TenantPlugin, error) {
var plugin model.TenantPlugin
if err := t.DB.Where("plugin_id = ? ", id).Find(&plugin).Error; err != nil {
if err := t.DB.Where("plugin_id = ? and tenant_id = ?", id, tenantID).Find(&plugin).Error; err != nil {
return nil, err
}
return &plugin, nil
}
//DeletePluginByID DeletePluginByID
func (t *PluginDaoImpl) DeletePluginByID(id string) error {
func (t *PluginDaoImpl) DeletePluginByID(id, tenantID string) error {
relation := &model.TenantPlugin{
PluginID: id,
}
if err := t.DB.Where("plugin_id=?", id).Delete(relation).Error; err != nil {
if err := t.DB.Where("plugin_id=? and tenant_id=?", id, tenantID).Delete(relation).Error; err != nil {
return err
}
return nil

View File

@ -20,6 +20,8 @@ package store
import (
"context"
"math"
"sort"
"sync"
"time"
@ -174,7 +176,7 @@ type MonitorMessage struct {
type cacheMonitorMessage struct {
updateTime time.Time
hostName string
mms []MonitorMessage
mms MonitorMessageList
}
//CacheMonitorMessageList 某个应用性能分析数据
@ -258,7 +260,9 @@ func (c *CacheMonitorMessageList) pushMessage() {
addSource := c.list[i].mms
source = merge(source, addSource)
}
mdata = getByte(source)
//重新排序
sort.Sort(&source)
mdata = getByte(*source.Pop(20))
c.message.MonitorData = mdata
for _, ch := range c.subSocketChan {
select {
@ -306,29 +310,76 @@ func fromByte(source []byte) []MonitorMessage {
return mm
}
func merge(source, addsource []MonitorMessage) (result []MonitorMessage) {
var cache = make(map[string]*MonitorMessage)
func merge(source, addsource MonitorMessageList) (result MonitorMessageList) {
var cache = make(map[string]MonitorMessage)
for _, mm := range source {
cache[mm.Key] = &mm
cache[mm.Key] = mm
}
for _, mm := range addsource {
if oldmm, ok := cache[mm.Key]; ok {
oldmm.Count += mm.Count
oldmm.AbnormalCount += mm.AbnormalCount
//平均时间
oldmm.AverageTime = (oldmm.AverageTime + mm.AverageTime) / 2
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
oldmm.CumulativeTime = oldmm.CumulativeTime + mm.CumulativeTime
oldmm.AverageTime = Round((oldmm.AverageTime+mm.AverageTime)/2, 2)
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
oldmm.CumulativeTime = Round(oldmm.CumulativeTime+mm.CumulativeTime, 2)
//最大时间
if mm.MaxTime > oldmm.MaxTime {
oldmm.MaxTime = mm.MaxTime
}
cache[mm.Key] = oldmm
continue
}
cache[mm.Key] = &mm
cache[mm.Key] = mm
}
for _, c := range cache {
result = append(result, *c)
result.Add(&c)
}
return
}
//Round Round
func Round(f float64, n int) float64 {
pow10n := math.Pow10(n)
return math.Trunc((f+0.5/pow10n)*pow10n) / pow10n
}
//MonitorMessageList 消息列表
type MonitorMessageList []MonitorMessage
//Add 添加
func (m *MonitorMessageList) Add(mm *MonitorMessage) {
*m = append(*m, *mm)
}
// Len 为集合内元素的总数
func (m *MonitorMessageList) Len() int {
return len(*m)
}
//Less 如果index为i的元素小于index为j的元素则返回true否则返回false
func (m *MonitorMessageList) Less(i, j int) bool {
return (*m)[i].CumulativeTime < (*m)[j].CumulativeTime
}
// Swap 交换索引为 i 和 j 的元素
func (m *MonitorMessageList) Swap(i, j int) {
tmp := (*m)[i]
(*m)[i] = (*m)[j]
(*m)[j] = tmp
}
//Pop Pop
func (m *MonitorMessageList) Pop(i int) *MonitorMessageList {
if len(*m) <= i {
return m
}
cache := (*m)[:i]
return &cache
}
//String json string
func (m *MonitorMessageList) String() string {
body, _ := ffjson.Marshal(m)
return string(body)
}

View File

@ -0,0 +1,38 @@
// 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 store
import "testing"
func TestMerge(t *testing.T) {
s1 := MonitorMessageList{
MonitorMessage{
Key: "/asdadasd",
},
}
s2 := MonitorMessageList{
MonitorMessage{
Key: "/asdadasd",
},
MonitorMessage{
Key: "/asda12dasd",
},
}
re := merge(s1, s2)
t.Log(re)
}

View File

@ -127,7 +127,13 @@ type RouteConfig struct {
type PieceHTTPVirtualHost struct {
Name string `json:"name"`
Domains []string `json:"domains"`
Routes []*PieceHTTPRoutes `json:"routes"`
//Routes []*PieceHTTPRoutes `json:"routes"`
Routes interface{} `json:"routes"`
}
//WeightedClusters WeightedClusters
type WeightedClusters struct {
Clusters []map[string]interface{} `json:"clusters"`
}
//PieceHTTPRoutes PieceHTTPRoutes
@ -135,7 +141,8 @@ type PieceHTTPRoutes struct {
TimeoutMS int `json:"timeout_ms"`
Prefix string `json:"prefix"`
Cluster string `json:"cluster"`
//Headers []*PieceHeader `json:"headers"`
//Headers []PieceHeader `json:"headers"`
Headers interface{} `json:"headers"`
}
//PieceHeader PieceHeader
@ -170,4 +177,10 @@ const (
UPSTREAM string = "upStream"
//DOWNSTREAM downStream
DOWNSTREAM string = "downStream"
//WEIGHT WEIGHT
WEIGHT string = "WEIGHT"
//MODELWEIGHT MODEL_WEIGHT
MODELWEIGHT string = "weight_model"
//MODELPREFIX MODEL_PREFIX
MODELPREFIX string = "prefix_model"
)

View File

@ -140,12 +140,48 @@ func (d *DataCenterConfig) GetConfig(name string) *model.ConfigUnit {
return d.config.Get(name)
}
//CacheConfig 更新配置缓存
func (d *DataCenterConfig) CacheConfig(c *model.ConfigUnit) error {
if c.Name == "" {
return fmt.Errorf("config name can not be empty")
}
logrus.Debugf("add config %v", c)
//将值类型由[]interface{} 转 []string
if c.ValueType == "array" {
switch c.Value.(type) {
case []interface{}:
var data []string
for _, v := range c.Value.([]interface{}) {
data = append(data, v.(string))
}
c.Value = data
}
oldC := d.config.Get(c.Name)
if oldC != nil {
switch oldC.Value.(type) {
case string:
value := append(c.Value.([]string), oldC.Value.(string))
util.Deweight(&value)
c.Value = value
case []string:
value := append(c.Value.([]string), oldC.Value.([]string)...)
util.Deweight(&value)
c.Value = value
default:
}
}
}
d.config.Add(*c)
return nil
}
//PutConfig 增加or更新配置
func (d *DataCenterConfig) PutConfig(c *model.ConfigUnit) error {
if c.Name == "" {
return fmt.Errorf("config name can not be empty")
}
logrus.Debugf("add config %v",c)
logrus.Debugf("add config %v", c)
//将值类型由[]interface{} 转 []string
if c.ValueType == "array" {
switch c.Value.(type) {
@ -186,7 +222,7 @@ func (d *DataCenterConfig) PutConfig(c *model.ConfigUnit) error {
func (d *DataCenterConfig) PutConfigKV(kv *mvccpb.KeyValue) {
var cn model.ConfigUnit
if err := ffjson.Unmarshal(kv.Value, &cn); err == nil {
d.PutConfig(&cn)
d.CacheConfig(&cn)
} else {
logrus.Errorf("parse config error,%s", err.Error())
}

View File

@ -22,6 +22,7 @@ import (
"fmt"
"strconv"
"strings"
"reflect"
"github.com/Sirupsen/logrus"
"github.com/goodrain/rainbond/cmd/node/option"
@ -145,6 +146,7 @@ func (d *DiscoverAction) DiscoverListeners(
return nil, util.CreateAPIHandleError(500, fmt.Errorf(
"get env %s error: %v", namespace+serviceAlias+pluginID, err))
}
logrus.Debugf("process go on")
//TODO: console控制尽量不把小于1000的端口给用户使用
var vhL []*node_model.PieceHTTPVirtualHost
@ -283,17 +285,25 @@ func (d *DiscoverAction) DiscoverListeners(
}
}
}
prs := &node_model.PieceHTTPRoutes{
TimeoutMS: 0,
Prefix: d.ToolsGetRouterItem(destServiceAlias, node_model.PREFIX, options).(string),
Cluster: fmt.Sprintf("%s_%s_%s_%d", namespace, serviceAlias, destServiceAlias, port),
//Headers: d.ToolsGetRouterItem(destServiceAlias,
// node_model.HEADERS, &sr).([]*node_model.PieceHeader),
headers := d.ToolsGetRouterItem(
destServiceAlias,
node_model.HEADERS, options)
prs := make(map[string]interface{})
prs["timeout_ms"] = 0
prs["prefix"] = d.ToolsGetRouterItem(destServiceAlias, node_model.PREFIX, options).(string)
c := make(map[string]interface{})
c["name"] = fmt.Sprintf("%s_%s_%s_%d", namespace, serviceAlias, destServiceAlias, port)
c["weight"] = d.ToolsGetRouterItem(destServiceAlias, node_model.WEIGHT, options).(int)
var wc node_model.WeightedClusters
wc.Clusters = []map[string]interface{}{c}
prs["weighted_clusters"] = wc
if len(headers.([]node_model.PieceHeader)) != 0 {
prs["headers"] = headers
}
pvh := &node_model.PieceHTTPVirtualHost{
Name: fmt.Sprintf("%s_%s_%s_%d", namespace, serviceAlias, destServiceAlias, port),
Domains: d.ToolsGetRouterItem(destServiceAlias, node_model.DOMAINS, options).([]string),
Routes: []*node_model.PieceHTTPRoutes{prs},
Routes: []map[string]interface{}{prs},
}
vhL = append(vhL, pvh)
}
@ -312,8 +322,62 @@ func (d *DiscoverAction) DiscoverListeners(
Name: "router",
Config: make(map[string]string),
}
var newVHL []*node_model.PieceHTTPVirtualHost
if len(vhL) > 1 {
domainL := d.CheckSameDomainAndPrefix(resources)
logrus.Debugf("domainL is %v", domainL)
if len(domainL) > 0 {
//存在相同的domain设置
for d := range domainL {
var c []map[string]interface{}
var r []interface{}
var pvh node_model.PieceHTTPVirtualHost
prs := make(map[string]interface{})
prs["timeout_ms"] = 0
for _, v := range vhL {
if pvh.Name == "" {
pvh.Name = v.Name
pvh.Domains = v.Domains
pvh.Routes = []map[string]interface{}{prs}
}
if v.Domains[0] == d {
switch domainL[d]{
case node_model.MODELWEIGHT:
prs["prefix"] = v.Routes.([]map[string]interface{})[0]["prefix"].(string)
if hasHeader, ok := v.Routes.([]map[string]interface{})[0]["headers"].([]node_model.PieceHeader); ok {
prs["headers"] = hasHeader
}
//pieceCluster := v.Routes.([]map[string]interface{})[0]["weighted_clusters"].(node_model.WeightedClusters).Clusters[0]
c = append(c, v.Routes.([]map[string]interface{})[0]["weighted_clusters"].(node_model.WeightedClusters).Clusters[0])
case node_model.MODELPREFIX:
r = append(r, v.Routes.([]map[string]interface{})[0])
}
}else {
newVHL = append(newVHL, v)
}
}
if len(r) != 0 {
pvh.Routes = r
newVHL = append(newVHL, &pvh)
}
if len(c) != 0 {
var wc node_model.WeightedClusters
wc.Clusters = c
prs["weighted_clusters"] = wc
logrus.Debugf("prs is %v", prs)
pvh.Routes = []map[string]interface{}{prs}
newVHL = append(newVHL, &pvh)
}
}
}else {
newVHL = vhL
}
}else {
newVHL = vhL
}
logrus.Debugf("newVHL is %v", newVHL)
rcg := &node_model.RouteConfig{
VirtualHosts: vhL,
VirtualHosts: newVHL,
}
lhc := &node_model.LDSHTTPConfig{
CodecType: "auto",
@ -339,6 +403,64 @@ func (d *DiscoverAction) DiscoverListeners(
return lds, nil
}
//Duplicate Duplicate
func Duplicate(a interface{}) (ret []interface{}) {
va := reflect.ValueOf(a)
for i := 0; i < va.Len(); i++ {
if i > 0 && reflect.DeepEqual(va.Index(i-1).Interface(), va.Index(i).Interface()) {
continue
}
ret = append(ret, va.Index(i).Interface())
}
return ret
}
//CheckSameDomainAndPrefix 检查是否存在相同domain以及prefix
func (d *DiscoverAction)CheckSameDomainAndPrefix(resources *api_model.ResourceSpec) (map[string]string){
baseServices := resources.BaseServices
domainL := make(map[string]string)
if len(baseServices) == 0 {
logrus.Debugf("has no base services resources")
return domainL
}
filterL := make(map[string]int)
for _, bs := range baseServices {
l := len(filterL)
domainName, _:= bs.Options[node_model.DOMAINS].(string)
filterL[domainName] = 0
if len(filterL) == l {
domainL[domainName] = "use"
}
}
for d := range domainL {
prefixM := make(map[string]int)
for _, bs := range baseServices {
domainName, _ := bs.Options[node_model.DOMAINS].(string)
if domainName == d {
prefix, _ := bs.Options[node_model.PREFIX].(string)
prefixM[prefix] = 0
}
// if strings.Contains(domainName, ","){
// mm := strings.Split(domainName, ",")
// for _, n := range mm {
// if n == d {
// prefix, _ := bs.Options[node_model.PREFIX].(string)
// prefixM[prefix] = 0
// continue
// }
// }
// }
}
logrus.Debugf("prefixM is %v", prefixM)
if len(prefixM) == 1 {
domainL[d] = node_model.MODELWEIGHT
}else{
domainL[d] = node_model.MODELPREFIX
}
}
return domainL
}
//DiscoverClusters cds
func (d *DiscoverAction) DiscoverClusters(
tenantService,
@ -499,8 +621,7 @@ func (d *DiscoverAction) ToolsBuildPieceLDS() {}
//ToolsGetRouterItem ToolsGetRouterItem
func (d *DiscoverAction) ToolsGetRouterItem(
destAlias, kind string,
sr map[string]interface{}) interface{} {
destAlias, kind string, sr map[string]interface{}) interface{} {
switch kind {
case node_model.PREFIX:
if prefix, ok := sr[node_model.PREFIX]; ok {
@ -553,26 +674,52 @@ func (d *DiscoverAction) ToolsGetRouterItem(
logrus.Errorf("strcon max retry error")
return 3
}
if mxr > 0 && mxr < 10 {
return mxr
}
if mxr == 11 {
return 0
}
return mxr
}
return 3
case node_model.HEADERS:
return ""
if headers, ok := sr[node_model.HEADERS]; ok {
var np []node_model.PieceHeader
parents := strings.Split(headers.(string), ";")
for _, h := range parents {
headers := strings.Split(h, ":")
//has_header:no 默认
if len(headers) == 2 {
if headers[0] == "has_header" && headers[1] == "no" {
continue
}
ph := node_model.PieceHeader{
Name: headers[0],
Value: headers[1],
}
np = append(np, ph)
}
}
return np
}
var rc []node_model.PieceHeader
return rc
case node_model.DOMAINS:
if domain, ok := sr[node_model.DOMAINS]; ok {
if destAlias != "" {
return []string{destAlias, domain.(string)}
if strings.Contains(domain.(string), ","){
mm := strings.Split(domain.(string), ",")
return mm
}
return []string{domain.(string)}
}
return []string{destAlias}
case node_model.WEIGHT:
if weight, ok := sr[node_model.WEIGHT]; ok {
w, err := strconv.Atoi(weight.(string))
if err != nil {
return 100
}
return w
}
return 100
default:
return nil
}
return ""
}
//ToolsGetRainbondResources 获取rainbond自定义resources

View File

@ -87,9 +87,15 @@ func (t *TaskEngine) Start() error {
t.LoadStaticTask()
//以下工作器只能由一个节点完成
//step1 获取调度权限如果master节点多点部署只能有一个节点具有调度权
var timer = time.NewTimer(time.Second * 4)
go func() {
defer close(t.down)
for {
select {
case <-t.ctx.Done():
return
case <-timer.C:
}
if ok, err := t.haveMaster(); ok {
logrus.Infof("Current node(%s) have task scheduler authority", t.currentNode.HostName)
keepchan := make(chan struct{}, 1)
@ -111,12 +117,7 @@ func (t *TaskEngine) Start() error {
} else if err != nil {
logrus.Error("check current node Whether has a scheduling authority error,", err.Error())
}
select {
case <-t.ctx.Done():
return
default:
}
time.Sleep(time.Second * 3)
timer.Reset(time.Second * 4)
}
}()
return nil
@ -142,18 +143,18 @@ func (t *TaskEngine) haveMaster() (bool, error) {
return false, err
}
if !resp.Succeeded {
ctx, cancel := context.WithTimeout(t.ctx, time.Second*3)
ch := store.DefalutClient.WatchByCtx(ctx, "/rainbond/task/scheduler/authority")
ctx, cancel := context.WithCancel(t.ctx)
defer cancel()
ch := store.DefalutClient.WatchByCtx(ctx, key)
for {
select {
case <-t.ctx.Done():
cancel()
return false, nil
case events := <-ch:
for _, event := range events.Events {
//watch 到删除操作,返回去获取权限
if event.Type == client.EventTypeDelete {
cancel()
logrus.Infof("get event that master offline,will strive for master node permissions.")
return false, nil
}
}
@ -165,7 +166,7 @@ func (t *TaskEngine) haveMaster() (bool, error) {
}
func (t *TaskEngine) keepMaster(errchan chan struct{}) {
duration := time.Second * 5
duration := time.Second * 3
timer := time.NewTimer(duration)
keep:
for {

View File

@ -46,13 +46,13 @@ function prepare() {
function build() {
echo "---> Build Binary For ACP"
echo "acp plugins version:$release_desc"
sed -i "s/0.0.0/$release_desc/g" ./cmd/version.go
echo "build rainbond-node"
docker run --rm -v `pwd`:${WORK_DIR} -w ${WORK_DIR} -it golang:1.8.3 go build -ldflags '-w -s' -o $releasedir/dist/usr/local/bin/${BASE_NAME}-node ./cmd/node
echo "grctl version:$release_desc"
sed -i "s/0.0.0/$release_desc/g" ./cmd/grctl/option/version.go
echo "build rainbond-grctl"
docker run --rm -v `pwd`:${WORK_DIR} -w ${WORK_DIR} -it golang:1.8.3 go build -ldflags '-w -s' -o $releasedir/dist/usr/local/bin/${BASE_NAME}-grctl ./cmd/grctl
sed -i "s/$release_desc/0.0.0/g" ./cmd/grctl/option/version.go
sed -i "s/$release_desc/0.0.0/g" ./cmd/version.go
}
function build::rpm() {